Ruby: compile.c Source File

Ruby 3.4.9p82 (2026-03-11 revision 76cca827ab52ab1d346a728f068d5b8da3e2952b)

compile.c
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
53
54 typedef 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;
64} LINK_ELEMENT;
65
66 typedef struct iseq_link_anchor {
67 LINK_ELEMENT anchor;
68 LINK_ELEMENT *last;
69} LINK_ANCHOR;
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
78 typedef 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
90 typedef 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
103 typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109 typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
115 struct ensure_range {
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
121 struct iseq_compile_data_ensure_node_stack {
122 const void *ensure_node;
123 struct iseq_compile_data_ensure_node_stack *prev;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
141
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/* add instructions */
218#define ADD_SEQ(seq1, seq2) \
219 APPEND_LIST((seq1), (seq2))
220
221/* add an instruction */
222#define ADD_INSN(seq, line_node, insn) \
223 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
224
225/* add an instruction with the given line number and node id */
226#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
227 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
228
229/* insert an instruction before next */
230#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
231 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
232
233/* insert an instruction after prev */
234#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
235 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
236
237/* add an instruction with some operands (1, 2, 3, 5) */
238#define ADD_INSN1(seq, line_node, insn, op1) \
239 ADD_ELEM((seq), (LINK_ELEMENT *) \
240 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
241
242/* insert an instruction with some operands (1, 2, 3, 5) before next */
243#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
244 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
245 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
246
247/* insert an instruction with some operands (1, 2, 3, 5) after prev */
248#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
249 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
250 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
251
252#define LABEL_REF(label) ((label)->refcnt++)
253
254/* add an instruction with label operand (alias of ADD_INSN1) */
255#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
256
257#define ADD_INSN2(seq, line_node, insn, op1, op2) \
258 ADD_ELEM((seq), (LINK_ELEMENT *) \
259 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
260
261#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
262 ADD_ELEM((seq), (LINK_ELEMENT *) \
263 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
264
265/* Specific Insn factory */
266#define ADD_SEND(seq, line_node, id, argc) \
267 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
268
269#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
270 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
271
272#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
273 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
274
275#define ADD_CALL_RECEIVER(seq, line_node) \
276 ADD_INSN((seq), (line_node), putself)
277
278#define ADD_CALL(seq, line_node, id, argc) \
279 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
280
281#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
282 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
283
284#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
285 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)))
286
287#define ADD_TRACE(seq, event) \
288 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
289#define ADD_TRACE_WITH_DATA(seq, event, data) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
291
292static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
293static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
294
295#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
296#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
297
298/* add label */
299#define ADD_LABEL(seq, label) \
300 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
301
302#define APPEND_LABEL(seq, before, label) \
303 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
304
305#define ADD_ADJUST(seq, line_node, label) \
306 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
307
308#define ADD_ADJUST_RESTORE(seq, label) \
309 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
310
311#define LABEL_UNREMOVABLE(label) \
312 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
313#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
314 VALUE _e = rb_ary_new3(5, (type), \
315 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
316 (VALUE)(iseqv), (VALUE)(lc) | 1); \
317 LABEL_UNREMOVABLE(ls); \
318 LABEL_REF(le); \
319 LABEL_REF(lc); \
320 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
321 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
322 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
323} while (0)
324
325/* compile node */
326#define COMPILE(anchor, desc, node) \
327 (debug_compile("== " desc "\n", \
328 iseq_compile_each(iseq, (anchor), (node), 0)))
329
330/* compile node, this node's value will be popped */
331#define COMPILE_POPPED(anchor, desc, node) \
332 (debug_compile("== " desc "\n", \
333 iseq_compile_each(iseq, (anchor), (node), 1)))
334
335/* compile node, which is popped when 'popped' is true */
336#define COMPILE_(anchor, desc, node, popped) \
337 (debug_compile("== " desc "\n", \
338 iseq_compile_each(iseq, (anchor), (node), (popped))))
339
340#define COMPILE_RECV(anchor, desc, node, recv) \
341 (private_recv_p(node) ? \
342 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
343 COMPILE(anchor, desc, recv) ? 0 : -1)
344
345#define OPERAND_AT(insn, idx) \
346 (((INSN*)(insn))->operands[(idx)])
347
348#define INSN_OF(insn) \
349 (((INSN*)(insn))->insn_id)
350
351#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
352#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
353#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
354#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
355#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
356#define IS_NEXT_INSN_ID(link, insn) \
357 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
358
359/* error */
360#if CPDEBUG > 0
361 RBIMPL_ATTR_NORETURN()
362#endif
363 RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
364static void
365append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
366{
367 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
368 VALUE file = rb_iseq_path(iseq);
369 VALUE err = err_info == Qtrue ? Qfalse : err_info;
370 va_list args;
371
372 va_start(args, fmt);
373 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
374 va_end(args);
375 if (NIL_P(err_info)) {
376 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
377 rb_set_errinfo(err);
378 }
379 else if (!err_info) {
380 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
381 }
382 if (compile_debug) {
383 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
384 rb_exc_fatal(err);
385 }
386}
387
388#if 0
389static void
390compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
391{
392 va_list args;
393 va_start(args, fmt);
394 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
395 va_end(args);
396 abort();
397}
398#endif
399
400#define COMPILE_ERROR append_compile_error
401
402#define ERROR_ARGS_AT(n) iseq, nd_line(n),
403#define ERROR_ARGS ERROR_ARGS_AT(node)
404
405#define EXPECT_NODE(prefix, node, ndtype, errval) \
406do { \
407 const NODE *error_node = (node); \
408 enum node_type error_type = nd_type(error_node); \
409 if (error_type != (ndtype)) { \
410 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
411 prefix ": " #ndtype " is expected, but %s", \
412 ruby_node_name(error_type)); \
413 return errval; \
414 } \
415} while (0)
416
417#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
418do { \
419 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
420 prefix ": must be " #ndtype ", but 0"); \
421 return errval; \
422} while (0)
423
424#define UNKNOWN_NODE(prefix, node, errval) \
425do { \
426 const NODE *error_node = (node); \
427 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
428 ruby_node_name(nd_type(error_node))); \
429 return errval; \
430} while (0)
431
432#define COMPILE_OK 1
433#define COMPILE_NG 0
434
435#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
436#define NO_CHECK(sub) (void)(sub)
437#define BEFORE_RETURN
438
439#define DECL_ANCHOR(name) \
440 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
441#define INIT_ANCHOR(name) \
442 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
443
444static inline VALUE
445freeze_hide_obj(VALUE obj)
446{
447 OBJ_FREEZE(obj);
448 RBASIC_CLEAR_CLASS(obj);
449 return obj;
450}
451
452#include "optinsn.inc"
453#if OPT_INSTRUCTIONS_UNIFICATION
454#include "optunifs.inc"
455#endif
456
457/* for debug */
458#if CPDEBUG < 0
459#define ISEQ_ARG iseq,
460#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
461#else
462#define ISEQ_ARG
463#define ISEQ_ARG_DECLARE
464#endif
465
466#if CPDEBUG
467#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
468#endif
469
470static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
471static void dump_disasm_list(const LINK_ELEMENT *elem);
472
473static int insn_data_length(INSN *iobj);
474static int calc_sp_depth(int depth, INSN *iobj);
475
476static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
477static LABEL *new_label_body(rb_iseq_t *iseq, long line);
478static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
479static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
480
481
482static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
483static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
484static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
485static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487
488static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
489static int iseq_set_exception_local_table(rb_iseq_t *iseq);
490static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
491
492static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
493static int iseq_set_exception_table(rb_iseq_t *iseq);
494static int iseq_set_optargs_table(rb_iseq_t *iseq);
495
496static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
497static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
498
499/*
500 * To make Array to LinkedList, use link_anchor
501 */
502
503static void
504verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
505{
506#if CPDEBUG
507 int flag = 0;
508 LINK_ELEMENT *list, *plist;
509
510 if (!compile_debug) return;
511
512 list = anchor->anchor.next;
513 plist = &anchor->anchor;
514 while (list) {
515 if (plist != list->prev) {
516 flag += 1;
517 }
518 plist = list;
519 list = list->next;
520 }
521
522 if (anchor->last != plist && anchor->last != 0) {
523 flag |= 0x70000;
524 }
525
526 if (flag != 0) {
527 rb_bug("list verify error: %08x (%s)", flag, info);
528 }
529#endif
530}
531#if CPDEBUG < 0
532#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
533#endif
534
535static void
536verify_call_cache(rb_iseq_t *iseq)
537{
538#if CPDEBUG
539 VALUE *original = rb_iseq_original_iseq(iseq);
540 size_t i = 0;
541 while (i < ISEQ_BODY(iseq)->iseq_size) {
542 VALUE insn = original[i];
543 const char *types = insn_op_types(insn);
544
545 for (int j=0; types[j]; j++) {
546 if (types[j] == TS_CALLDATA) {
547 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
548 const struct rb_callinfo *ci = cd->ci;
549 const struct rb_callcache *cc = cd->cc;
550 if (cc != vm_cc_empty()) {
551 vm_ci_dump(ci);
552 rb_bug("call cache is not initialized by vm_cc_empty()");
553 }
554 }
555 }
556 i += insn_len(insn);
557 }
558
559 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
560 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
561 const struct rb_callinfo *ci = cd->ci;
562 const struct rb_callcache *cc = cd->cc;
563 if (cc != NULL && cc != vm_cc_empty()) {
564 vm_ci_dump(ci);
565 rb_bug("call cache is not initialized by vm_cc_empty()");
566 }
567 }
568#endif
569}
570
571/*
572 * elem1, elem2 => elem1, elem2, elem
573 */
574static void
575ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
576{
577 elem->prev = anchor->last;
578 anchor->last->next = elem;
579 anchor->last = elem;
580 verify_list("add", anchor);
581}
582
583/*
584 * elem1, before, elem2 => elem1, before, elem, elem2
585 */
586static void
587APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
588{
589 elem->prev = before;
590 elem->next = before->next;
591 elem->next->prev = elem;
592 before->next = elem;
593 if (before == anchor->last) anchor->last = elem;
594 verify_list("add", anchor);
595}
596#if CPDEBUG < 0
597#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
598#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
599#endif
600
601static int
602branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
603{
604 if (!ISEQ_COVERAGE(iseq)) return 0;
605 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
606 if (first_line <= 0) return 0;
607 return 1;
608}
609
610#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
611
612static VALUE
613setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
614{
615 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
616 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
617 VALUE branch = rb_ary_hidden_new(6);
618
619 rb_hash_aset(structure, key, branch);
620 rb_ary_push(branch, ID2SYM(rb_intern(type)));
621 rb_ary_push(branch, INT2FIX(first_lineno));
622 rb_ary_push(branch, INT2FIX(first_column));
623 rb_ary_push(branch, INT2FIX(last_lineno));
624 rb_ary_push(branch, INT2FIX(last_column));
625 return branch;
626}
627
628static VALUE
629decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
630{
631 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
632
633 /*
634 * if !structure[node]
635 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
636 * else
637 * branches = structure[node][5]
638 * end
639 */
640
641 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
642 VALUE branch_base = rb_hash_aref(structure, key);
643 VALUE branches;
644
645 if (NIL_P(branch_base)) {
646 branch_base = setup_branch(loc, type, structure, key);
647 branches = rb_hash_new();
648 rb_obj_hide(branches);
649 rb_ary_push(branch_base, branches);
650 }
651 else {
652 branches = RARRAY_AREF(branch_base, 5);
653 }
654
655 return branches;
656}
657
658static NODE
659generate_dummy_line_node(int lineno, int node_id)
660{
661 NODE dummy = { 0 };
662 nd_set_line(&dummy, lineno);
663 nd_set_node_id(&dummy, node_id);
664 return dummy;
665}
666
667static void
668add_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)
669{
670 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
671
672 /*
673 * if !branches[branch_id]
674 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
675 * else
676 * counter_idx= branches[branch_id][5]
677 * end
678 */
679
680 VALUE key = INT2FIX(branch_id);
681 VALUE branch = rb_hash_aref(branches, key);
682 long counter_idx;
683
684 if (NIL_P(branch)) {
685 branch = setup_branch(loc, type, branches, key);
686 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
687 counter_idx = RARRAY_LEN(counters);
688 rb_ary_push(branch, LONG2FIX(counter_idx));
689 rb_ary_push(counters, INT2FIX(0));
690 }
691 else {
692 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
693 }
694
695 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
696 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
697}
698
699#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
700
701static int
702validate_label(st_data_t name, st_data_t label, st_data_t arg)
703{
704 rb_iseq_t *iseq = (rb_iseq_t *)arg;
705 LABEL *lobj = (LABEL *)label;
706 if (!lobj->link.next) {
707 do {
708 COMPILE_ERROR(iseq, lobj->position,
709 "%"PRIsVALUE": undefined label",
710 rb_sym2str((VALUE)name));
711 } while (0);
712 }
713 return ST_CONTINUE;
714}
715
716static void
717validate_labels(rb_iseq_t *iseq, st_table *labels_table)
718{
719 st_foreach(labels_table, validate_label, (st_data_t)iseq);
720 st_free_table(labels_table);
721}
722
723static NODE *
724get_nd_recv(const NODE *node)
725{
726 switch (nd_type(node)) {
727 case NODE_CALL:
728 return RNODE_CALL(node)->nd_recv;
729 case NODE_OPCALL:
730 return RNODE_OPCALL(node)->nd_recv;
731 case NODE_FCALL:
732 return 0;
733 case NODE_QCALL:
734 return RNODE_QCALL(node)->nd_recv;
735 case NODE_VCALL:
736 return 0;
737 case NODE_ATTRASGN:
738 return RNODE_ATTRASGN(node)->nd_recv;
739 case NODE_OP_ASGN1:
740 return RNODE_OP_ASGN1(node)->nd_recv;
741 case NODE_OP_ASGN2:
742 return RNODE_OP_ASGN2(node)->nd_recv;
743 default:
744 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
745 }
746}
747
748static ID
749get_node_call_nd_mid(const NODE *node)
750{
751 switch (nd_type(node)) {
752 case NODE_CALL:
753 return RNODE_CALL(node)->nd_mid;
754 case NODE_OPCALL:
755 return RNODE_OPCALL(node)->nd_mid;
756 case NODE_FCALL:
757 return RNODE_FCALL(node)->nd_mid;
758 case NODE_QCALL:
759 return RNODE_QCALL(node)->nd_mid;
760 case NODE_VCALL:
761 return RNODE_VCALL(node)->nd_mid;
762 case NODE_ATTRASGN:
763 return RNODE_ATTRASGN(node)->nd_mid;
764 default:
765 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
766 }
767}
768
769static NODE *
770get_nd_args(const NODE *node)
771{
772 switch (nd_type(node)) {
773 case NODE_CALL:
774 return RNODE_CALL(node)->nd_args;
775 case NODE_OPCALL:
776 return RNODE_OPCALL(node)->nd_args;
777 case NODE_FCALL:
778 return RNODE_FCALL(node)->nd_args;
779 case NODE_QCALL:
780 return RNODE_QCALL(node)->nd_args;
781 case NODE_VCALL:
782 return 0;
783 case NODE_ATTRASGN:
784 return RNODE_ATTRASGN(node)->nd_args;
785 default:
786 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
787 }
788}
789
790static ID
791get_node_colon_nd_mid(const NODE *node)
792{
793 switch (nd_type(node)) {
794 case NODE_COLON2:
795 return RNODE_COLON2(node)->nd_mid;
796 case NODE_COLON3:
797 return RNODE_COLON3(node)->nd_mid;
798 default:
799 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
800 }
801}
802
803static ID
804get_nd_vid(const NODE *node)
805{
806 switch (nd_type(node)) {
807 case NODE_LASGN:
808 return RNODE_LASGN(node)->nd_vid;
809 case NODE_DASGN:
810 return RNODE_DASGN(node)->nd_vid;
811 case NODE_IASGN:
812 return RNODE_IASGN(node)->nd_vid;
813 case NODE_CVASGN:
814 return RNODE_CVASGN(node)->nd_vid;
815 default:
816 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
817 }
818}
819
820static NODE *
821get_nd_value(const NODE *node)
822{
823 switch (nd_type(node)) {
824 case NODE_LASGN:
825 return RNODE_LASGN(node)->nd_value;
826 case NODE_DASGN:
827 return RNODE_DASGN(node)->nd_value;
828 default:
829 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
830 }
831}
832
833static VALUE
834get_string_value(const NODE *node)
835{
836 switch (nd_type(node)) {
837 case NODE_STR:
838 return rb_node_str_string_val(node);
839 case NODE_FILE:
840 return rb_node_file_path_val(node);
841 default:
842 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
843 }
844}
845
846 VALUE
847rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
848{
849 DECL_ANCHOR(ret);
850 INIT_ANCHOR(ret);
851
852 (*ifunc->func)(iseq, ret, ifunc->data);
853
854 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
855
856 CHECK(iseq_setup_insn(iseq, ret));
857 return iseq_setup(iseq, ret);
858}
859
860static bool drop_unreachable_return(LINK_ANCHOR *ret);
861
862 VALUE
863rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
864{
865 DECL_ANCHOR(ret);
866 INIT_ANCHOR(ret);
867
868 if (node == 0) {
869 NO_CHECK(COMPILE(ret, "nil", node));
870 iseq_set_local_table(iseq, 0, 0);
871 }
872 /* assume node is T_NODE */
873 else if (nd_type_p(node, NODE_SCOPE)) {
874 /* iseq type of top, method, class, block */
875 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
876 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
877
878 switch (ISEQ_BODY(iseq)->type) {
879 case ISEQ_TYPE_BLOCK:
880 {
881 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
882 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
883
884 start->rescued = LABEL_RESCUE_BEG;
885 end->rescued = LABEL_RESCUE_END;
886
887 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
888 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
889 ADD_LABEL(ret, start);
890 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
891 ADD_LABEL(ret, end);
892 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
893 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
894
895 /* wide range catch handler must put at last */
896 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
897 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
898 break;
899 }
900 case ISEQ_TYPE_CLASS:
901 {
902 ADD_TRACE(ret, RUBY_EVENT_CLASS);
903 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
904 ADD_TRACE(ret, RUBY_EVENT_END);
905 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
906 break;
907 }
908 case ISEQ_TYPE_METHOD:
909 {
910 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
911 ADD_TRACE(ret, RUBY_EVENT_CALL);
912 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
913 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
914 ADD_TRACE(ret, RUBY_EVENT_RETURN);
915 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
916 break;
917 }
918 default: {
919 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
920 break;
921 }
922 }
923 }
924 else {
925 const char *m;
926#define INVALID_ISEQ_TYPE(type) \
927 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
928 switch (ISEQ_BODY(iseq)->type) {
929 case INVALID_ISEQ_TYPE(METHOD);
930 case INVALID_ISEQ_TYPE(CLASS);
931 case INVALID_ISEQ_TYPE(BLOCK);
932 case INVALID_ISEQ_TYPE(EVAL);
933 case INVALID_ISEQ_TYPE(MAIN);
934 case INVALID_ISEQ_TYPE(TOP);
935#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
936 case ISEQ_TYPE_RESCUE:
937 iseq_set_exception_local_table(iseq);
938 CHECK(COMPILE(ret, "rescue", node));
939 break;
940 case ISEQ_TYPE_ENSURE:
941 iseq_set_exception_local_table(iseq);
942 CHECK(COMPILE_POPPED(ret, "ensure", node));
943 break;
944 case ISEQ_TYPE_PLAIN:
945 CHECK(COMPILE(ret, "ensure", node));
946 break;
947 default:
948 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
949 return COMPILE_NG;
950 invalid_iseq_type:
951 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
952 return COMPILE_NG;
953 }
954 }
955
956 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
957 NODE dummy_line_node = generate_dummy_line_node(0, -1);
958 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
959 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
960 }
961 else if (!drop_unreachable_return(ret)) {
962 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
963 }
964
965#if OPT_SUPPORT_JOKE
966 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
967 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
968 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
969 validate_labels(iseq, labels_table);
970 }
971#endif
972 CHECK(iseq_setup_insn(iseq, ret));
973 return iseq_setup(iseq, ret);
974}
975
976static int
977rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
978{
979#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
980 const void * const *table = rb_vm_get_insns_address_table();
981 unsigned int i;
982 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
983
984 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
985 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
986 int len = insn_len(insn);
987 encoded[i] = (VALUE)table[insn];
988 i += len;
989 }
990 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
991#endif
992
993#if USE_YJIT
994 rb_yjit_live_iseq_count++;
995 rb_yjit_iseq_alloc_count++;
996#endif
997
998 return COMPILE_OK;
999}
1000
1001 VALUE *
1002rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1003{
1004 VALUE *original_code;
1005
1006 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1007 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1008 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1009
1010#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1011 {
1012 unsigned int i;
1013
1014 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1015 const void *addr = (const void *)original_code[i];
1016 const int insn = rb_vm_insn_addr2insn(addr);
1017
1018 original_code[i] = insn;
1019 i += insn_len(insn);
1020 }
1021 }
1022#endif
1023 return original_code;
1024}
1025
1026/*********************************************/
1027/* definition of data structure for compiler */
1028/*********************************************/
1029
1030/*
1031 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1032 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1033 * generate SPARCV8PLUS code with unaligned memory access instructions.
1034 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1035 */
1036#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1037 #define STRICT_ALIGNMENT
1038#endif
1039
1040/*
1041 * Some OpenBSD platforms (including sparc64) require strict alignment.
1042 */
1043#if defined(__OpenBSD__)
1044 #include <sys/endian.h>
1045 #ifdef __STRICT_ALIGNMENT
1046 #define STRICT_ALIGNMENT
1047 #endif
1048#endif
1049
1050#ifdef STRICT_ALIGNMENT
1051 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1052 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1053 #else
1054 #define ALIGNMENT_SIZE SIZEOF_VALUE
1055 #endif
1056 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1057 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1058 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1059#else
1060 #define PADDING_SIZE_MAX 0
1061#endif /* STRICT_ALIGNMENT */
1062
1063#ifdef STRICT_ALIGNMENT
1064/* calculate padding size for aligned memory access */
1065static size_t
1066calc_padding(void *ptr, size_t size)
1067{
1068 size_t mis;
1069 size_t padding = 0;
1070
1071 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1072 if (mis > 0) {
1073 padding = ALIGNMENT_SIZE - mis;
1074 }
1075/*
1076 * On 32-bit sparc or equivalents, when a single VALUE is requested
1077 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1078 */
1079#if ALIGNMENT_SIZE > SIZEOF_VALUE
1080 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1081 padding = 0;
1082 }
1083#endif
1084
1085 return padding;
1086}
1087#endif /* STRICT_ALIGNMENT */
1088
1089static void *
1090compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1091{
1092 void *ptr = 0;
1093 struct iseq_compile_data_storage *storage = *arena;
1094#ifdef STRICT_ALIGNMENT
1095 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1096#else
1097 const size_t padding = 0; /* expected to be optimized by compiler */
1098#endif /* STRICT_ALIGNMENT */
1099
1100 if (size >= INT_MAX - padding) rb_memerror();
1101 if (storage->pos + size + padding > storage->size) {
1102 unsigned int alloc_size = storage->size;
1103
1104 while (alloc_size < size + PADDING_SIZE_MAX) {
1105 if (alloc_size >= INT_MAX / 2) rb_memerror();
1106 alloc_size *= 2;
1107 }
1108 storage->next = (void *)ALLOC_N(char, alloc_size +
1109 offsetof(struct iseq_compile_data_storage, buff));
1110 storage = *arena = storage->next;
1111 storage->next = 0;
1112 storage->pos = 0;
1113 storage->size = alloc_size;
1114#ifdef STRICT_ALIGNMENT
1115 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1116#endif /* STRICT_ALIGNMENT */
1117 }
1118
1119#ifdef STRICT_ALIGNMENT
1120 storage->pos += (int)padding;
1121#endif /* STRICT_ALIGNMENT */
1122
1123 ptr = (void *)&storage->buff[storage->pos];
1124 storage->pos += (int)size;
1125 return ptr;
1126}
1127
1128static void *
1129compile_data_alloc(rb_iseq_t *iseq, size_t size)
1130{
1131 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1132 return compile_data_alloc_with_arena(arena, size);
1133}
1134
1135static inline void *
1136compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1137{
1138 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1139 return compile_data_alloc(iseq, size);
1140}
1141
1142static inline void *
1143compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1144{
1145 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1146 void *p = compile_data_alloc(iseq, size);
1147 memset(p, 0, size);
1148 return p;
1149}
1150
1151static INSN *
1152compile_data_alloc_insn(rb_iseq_t *iseq)
1153{
1154 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1155 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1156}
1157
1158static LABEL *
1159compile_data_alloc_label(rb_iseq_t *iseq)
1160{
1161 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1162}
1163
1164static ADJUST *
1165compile_data_alloc_adjust(rb_iseq_t *iseq)
1166{
1167 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1168}
1169
1170static TRACE *
1171compile_data_alloc_trace(rb_iseq_t *iseq)
1172{
1173 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1174}
1175
1176/*
1177 * elem1, elemX => elem1, elem2, elemX
1178 */
1179static void
1180ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1181{
1182 elem2->next = elem1->next;
1183 elem2->prev = elem1;
1184 elem1->next = elem2;
1185 if (elem2->next) {
1186 elem2->next->prev = elem2;
1187 }
1188}
1189
1190/*
1191 * elem1, elemX => elemX, elem2, elem1
1192 */
1193static void
1194ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1195{
1196 elem2->prev = elem1->prev;
1197 elem2->next = elem1;
1198 elem1->prev = elem2;
1199 if (elem2->prev) {
1200 elem2->prev->next = elem2;
1201 }
1202}
1203
1204/*
1205 * elemX, elem1, elemY => elemX, elem2, elemY
1206 */
1207static void
1208ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1209{
1210 elem2->prev = elem1->prev;
1211 elem2->next = elem1->next;
1212 if (elem1->prev) {
1213 elem1->prev->next = elem2;
1214 }
1215 if (elem1->next) {
1216 elem1->next->prev = elem2;
1217 }
1218}
1219
1220static void
1221ELEM_REMOVE(LINK_ELEMENT *elem)
1222{
1223 elem->prev->next = elem->next;
1224 if (elem->next) {
1225 elem->next->prev = elem->prev;
1226 }
1227}
1228
1229static LINK_ELEMENT *
1230FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1231{
1232 return anchor->anchor.next;
1233}
1234
1235static LINK_ELEMENT *
1236LAST_ELEMENT(LINK_ANCHOR *const anchor)
1237{
1238 return anchor->last;
1239}
1240
1241static LINK_ELEMENT *
1242ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1243{
1244 while (elem) {
1245 switch (elem->type) {
1246 case ISEQ_ELEMENT_INSN:
1247 case ISEQ_ELEMENT_ADJUST:
1248 return elem;
1249 default:
1250 elem = elem->next;
1251 }
1252 }
1253 return NULL;
1254}
1255
1256static int
1257LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1258{
1259 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1260 if (first_insn != NULL &&
1261 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1262 return TRUE;
1263 }
1264 else {
1265 return FALSE;
1266 }
1267}
1268
1269static int
1270LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1271{
1272 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1273 return TRUE;
1274 }
1275 else {
1276 return FALSE;
1277 }
1278}
1279
1280/*
1281 * anc1: e1, e2, e3
1282 * anc2: e4, e5
1283 *#=>
1284 * anc1: e1, e2, e3, e4, e5
1285 * anc2: e4, e5 (broken)
1286 */
1287static void
1288APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1289{
1290 if (anc2->anchor.next) {
1291 /* LINK_ANCHOR must not loop */
1292 RUBY_ASSERT(anc2->last != &anc2->anchor);
1293 anc1->last->next = anc2->anchor.next;
1294 anc2->anchor.next->prev = anc1->last;
1295 anc1->last = anc2->last;
1296 }
1297 else {
1298 RUBY_ASSERT(anc2->last == &anc2->anchor);
1299 }
1300 verify_list("append", anc1);
1301}
1302#if CPDEBUG < 0
1303#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1304#endif
1305
1306#if CPDEBUG && 0
1307static void
1308debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1309{
1310 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1311 printf("----\n");
1312 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1313 (void *)anchor->anchor.next, (void *)anchor->last);
1314 while (list) {
1315 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1316 (void *)list->prev, (int)list->type);
1317 list = list->next;
1318 }
1319 printf("----\n");
1320
1321 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1322 verify_list("debug list", anchor);
1323}
1324#if CPDEBUG < 0
1325#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1326#endif
1327#else
1328#define debug_list(anc, cur) ((void)0)
1329#endif
1330
1331static TRACE *
1332new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1333{
1334 TRACE *trace = compile_data_alloc_trace(iseq);
1335
1336 trace->link.type = ISEQ_ELEMENT_TRACE;
1337 trace->link.next = NULL;
1338 trace->event = event;
1339 trace->data = data;
1340
1341 return trace;
1342}
1343
1344static LABEL *
1345new_label_body(rb_iseq_t *iseq, long line)
1346{
1347 LABEL *labelobj = compile_data_alloc_label(iseq);
1348
1349 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1350 labelobj->link.next = 0;
1351
1352 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1353 labelobj->sc_state = 0;
1354 labelobj->sp = -1;
1355 labelobj->refcnt = 0;
1356 labelobj->set = 0;
1357 labelobj->rescued = LABEL_RESCUE_NONE;
1358 labelobj->unremovable = 0;
1359 labelobj->position = -1;
1360 return labelobj;
1361}
1362
1363static ADJUST *
1364new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1365{
1366 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1367 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1368 adjust->link.next = 0;
1369 adjust->label = label;
1370 adjust->line_no = line;
1371 LABEL_UNREMOVABLE(label);
1372 return adjust;
1373}
1374
1375static void
1376iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
1377{
1378 const char *types = insn_op_types(insn->insn_id);
1379 for (int j = 0; types[j]; j++) {
1380 char type = types[j];
1381 switch (type) {
1382 case TS_CDHASH:
1383 case TS_ISEQ:
1384 case TS_VALUE:
1385 case TS_IC: // constant path array
1386 case TS_CALLDATA: // ci is stored.
1387 func(OPERAND_AT(insn, j), data);
1388 break;
1389 default:
1390 break;
1391 }
1392 }
1393}
1394
1395static void
1396iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
1397{
1398 RB_OBJ_WRITTEN(iseq, Qundef, obj);
1399}
1400
1401static INSN *
1402new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1403{
1404 INSN *iobj = compile_data_alloc_insn(iseq);
1405
1406 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1407
1408 iobj->link.type = ISEQ_ELEMENT_INSN;
1409 iobj->link.next = 0;
1410 iobj->insn_id = insn_id;
1411 iobj->insn_info.line_no = line_no;
1412 iobj->insn_info.node_id = node_id;
1413 iobj->insn_info.events = 0;
1414 iobj->operands = argv;
1415 iobj->operand_size = argc;
1416 iobj->sc_state = 0;
1417
1418 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1419
1420 return iobj;
1421}
1422
1423static INSN *
1424new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1425{
1426 VALUE *operands = 0;
1427 va_list argv;
1428 if (argc > 0) {
1429 int i;
1430 va_start(argv, argc);
1431 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1432 for (i = 0; i < argc; i++) {
1433 VALUE v = va_arg(argv, VALUE);
1434 operands[i] = v;
1435 }
1436 va_end(argv);
1437 }
1438 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1439}
1440
1441static const struct rb_callinfo *
1442new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1443{
1444 VM_ASSERT(argc >= 0);
1445
1446 if (kw_arg) {
1447 flag |= VM_CALL_KWARG;
1448 argc += kw_arg->keyword_len;
1449 }
1450
1451 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1452 && !has_blockiseq) {
1453 flag |= VM_CALL_ARGS_SIMPLE;
1454 }
1455
1456 ISEQ_BODY(iseq)->ci_size++;
1457 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1458 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1459 return ci;
1460}
1461
1462static INSN *
1463new_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)
1464{
1465 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1466 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1467 operands[0] = ci;
1468 operands[1] = (VALUE)blockiseq;
1469 if (blockiseq) {
1470 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1471 }
1472
1473 INSN *insn;
1474
1475 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1476 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1477 }
1478 else {
1479 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1480 }
1481
1482 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1483 RB_GC_GUARD(ci);
1484 return insn;
1485}
1486
1487static rb_iseq_t *
1488new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1489 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1490{
1491 rb_iseq_t *ret_iseq;
1492 VALUE ast_value = rb_ruby_ast_new(node);
1493
1494 debugs("[new_child_iseq]> ---------------------------------------\n");
1495 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1496 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1497 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1498 line_no, parent,
1499 isolated_depth ? isolated_depth + 1 : 0,
1500 type, ISEQ_COMPILE_DATA(iseq)->option,
1501 ISEQ_BODY(iseq)->variable.script_lines);
1502 debugs("[new_child_iseq]< ---------------------------------------\n");
1503 return ret_iseq;
1504}
1505
1506static rb_iseq_t *
1507new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1508 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1509{
1510 rb_iseq_t *ret_iseq;
1511
1512 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1513 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1514 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1515 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1516 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1517 return ret_iseq;
1518}
1519
1520static void
1521set_catch_except_p(rb_iseq_t *iseq)
1522{
1523 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1524 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1525 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1526 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1527 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1528 }
1529 }
1530}
1531
1532/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1533 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1534 if catch table exists. But we want to optimize while loop, which always has catch
1535 table entries for break/next/redo.
1536
1537 So this function sets true for limited ISeqs with break/next/redo catch table entries
1538 whose child ISeq would really raise an exception. */
1539static void
1540update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1541{
1542 unsigned int pos;
1543 size_t i;
1544 int insn;
1545 const struct iseq_catch_table *ct = body->catch_table;
1546
1547 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1548 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1549 pos = 0;
1550 while (pos < body->iseq_size) {
1551 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1552 if (insn == BIN(throw)) {
1553 set_catch_except_p(iseq);
1554 break;
1555 }
1556 pos += insn_len(insn);
1557 }
1558
1559 if (ct == NULL)
1560 return;
1561
1562 for (i = 0; i < ct->size; i++) {
1563 const struct iseq_catch_table_entry *entry =
1564 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1565 if (entry->type != CATCH_TYPE_BREAK
1566 && entry->type != CATCH_TYPE_NEXT
1567 && entry->type != CATCH_TYPE_REDO) {
1568 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1569 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1570 break;
1571 }
1572 }
1573}
1574
1575static void
1576iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1577{
1578 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1579 if (NIL_P(catch_table_ary)) return;
1580 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1581 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1582 for (i = 0; i < tlen; i++) {
1583 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1584 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1585 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1586 LINK_ELEMENT *e;
1587
1588 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1589
1590 if (ct != CATCH_TYPE_BREAK
1591 && ct != CATCH_TYPE_NEXT
1592 && ct != CATCH_TYPE_REDO) {
1593
1594 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1595 if (e == cont) {
1596 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1597 ELEM_INSERT_NEXT(end, &nop->link);
1598 break;
1599 }
1600 }
1601 }
1602 }
1603
1604 RB_GC_GUARD(catch_table_ary);
1605}
1606
1607static int
1608iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1609{
1610 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1611 return COMPILE_NG;
1612
1613 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1614
1615 if (compile_debug > 5)
1616 dump_disasm_list(FIRST_ELEMENT(anchor));
1617
1618 debugs("[compile step 3.1 (iseq_optimize)]\n");
1619 iseq_optimize(iseq, anchor);
1620
1621 if (compile_debug > 5)
1622 dump_disasm_list(FIRST_ELEMENT(anchor));
1623
1624 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1625 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1626 iseq_insns_unification(iseq, anchor);
1627 if (compile_debug > 5)
1628 dump_disasm_list(FIRST_ELEMENT(anchor));
1629 }
1630
1631 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1632 iseq_insert_nop_between_end_and_cont(iseq);
1633 if (compile_debug > 5)
1634 dump_disasm_list(FIRST_ELEMENT(anchor));
1635
1636 return COMPILE_OK;
1637}
1638
1639static int
1640iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1641{
1642 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1643 return COMPILE_NG;
1644
1645 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1646 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1647 if (compile_debug > 5)
1648 dump_disasm_list(FIRST_ELEMENT(anchor));
1649
1650 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1651 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1652
1653 debugs("[compile step 4.3 (set_optargs_table)] \n");
1654 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1655
1656 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1657 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1658
1659 debugs("[compile step 6 (update_catch_except_flags)] \n");
1660 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1661 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1662
1663 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1664 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1665 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1666 xfree(ISEQ_BODY(iseq)->catch_table);
1667 ISEQ_BODY(iseq)->catch_table = NULL;
1668 }
1669
1670#if VM_INSN_INFO_TABLE_IMPL == 2
1671 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1672 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1673 rb_iseq_insns_info_encode_positions(iseq);
1674 }
1675#endif
1676
1677 if (compile_debug > 1) {
1678 VALUE str = rb_iseq_disasm(iseq);
1679 printf("%s\n", StringValueCStr(str));
1680 }
1681 verify_call_cache(iseq);
1682 debugs("[compile step: finish]\n");
1683
1684 return COMPILE_OK;
1685}
1686
1687static int
1688iseq_set_exception_local_table(rb_iseq_t *iseq)
1689{
1690 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1691 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1692 return COMPILE_OK;
1693}
1694
1695static int
1696get_lvar_level(const rb_iseq_t *iseq)
1697{
1698 int lev = 0;
1699 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1700 lev++;
1701 iseq = ISEQ_BODY(iseq)->parent_iseq;
1702 }
1703 return lev;
1704}
1705
1706static int
1707get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1708{
1709 unsigned int i;
1710
1711 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1712 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1713 return (int)i;
1714 }
1715 }
1716 return -1;
1717}
1718
1719static int
1720get_local_var_idx(const rb_iseq_t *iseq, ID id)
1721{
1722 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1723
1724 if (idx < 0) {
1725 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1726 "get_local_var_idx: %d", idx);
1727 }
1728
1729 return idx;
1730}
1731
1732static int
1733get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1734{
1735 int lv = 0, idx = -1;
1736 const rb_iseq_t *const topmost_iseq = iseq;
1737
1738 while (iseq) {
1739 idx = get_dyna_var_idx_at_raw(iseq, id);
1740 if (idx >= 0) {
1741 break;
1742 }
1743 iseq = ISEQ_BODY(iseq)->parent_iseq;
1744 lv++;
1745 }
1746
1747 if (idx < 0) {
1748 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1749 "get_dyna_var_idx: -1");
1750 }
1751
1752 *level = lv;
1753 *ls = ISEQ_BODY(iseq)->local_table_size;
1754 return idx;
1755}
1756
1757static int
1758iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1759{
1760 const struct rb_iseq_constant_body *body;
1761 while (level > 0) {
1762 iseq = ISEQ_BODY(iseq)->parent_iseq;
1763 level--;
1764 }
1765 body = ISEQ_BODY(iseq);
1766 if (body->local_iseq == iseq && /* local variables */
1767 body->param.flags.has_block &&
1768 body->local_table_size - body->param.block_start == idx) {
1769 return TRUE;
1770 }
1771 else {
1772 return FALSE;
1773 }
1774}
1775
1776static int
1777iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1778{
1779 int level, ls;
1780 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1781 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1782 *pidx = ls - idx;
1783 *plevel = level;
1784 return TRUE;
1785 }
1786 else {
1787 return FALSE;
1788 }
1789}
1790
1791static void
1792access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1793{
1794 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1795
1796 if (isolated_depth && level >= isolated_depth) {
1797 if (id == rb_intern("yield")) {
1798 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1799 }
1800 else {
1801 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1802 }
1803 }
1804
1805 for (int i=0; i<level; i++) {
1806 VALUE val;
1807 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1808
1809 if (!ovs) {
1810 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1811 }
1812
1813 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1814 if (write && !val) {
1815 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1816 }
1817 }
1818 else {
1819 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1820 }
1821
1822 iseq = ISEQ_BODY(iseq)->parent_iseq;
1823 }
1824}
1825
1826static ID
1827iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1828{
1829 for (int i=0; i<level; i++) {
1830 iseq = ISEQ_BODY(iseq)->parent_iseq;
1831 }
1832
1833 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1834 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1835 return id;
1836}
1837
1838static void
1839iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1840{
1841 if (iseq_local_block_param_p(iseq, idx, level)) {
1842 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1843 }
1844 else {
1845 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1846 }
1847 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1848}
1849
1850static void
1851iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1852{
1853 if (iseq_local_block_param_p(iseq, idx, level)) {
1854 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1855 }
1856 else {
1857 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1858 }
1859 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1860}
1861
1862
1863
1864static void
1865iseq_calc_param_size(rb_iseq_t *iseq)
1866{
1867 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1868 if (body->param.flags.has_opt ||
1869 body->param.flags.has_post ||
1870 body->param.flags.has_rest ||
1871 body->param.flags.has_block ||
1872 body->param.flags.has_kw ||
1873 body->param.flags.has_kwrest) {
1874
1875 if (body->param.flags.has_block) {
1876 body->param.size = body->param.block_start + 1;
1877 }
1878 else if (body->param.flags.has_kwrest) {
1879 body->param.size = body->param.keyword->rest_start + 1;
1880 }
1881 else if (body->param.flags.has_kw) {
1882 body->param.size = body->param.keyword->bits_start + 1;
1883 }
1884 else if (body->param.flags.has_post) {
1885 body->param.size = body->param.post_start + body->param.post_num;
1886 }
1887 else if (body->param.flags.has_rest) {
1888 body->param.size = body->param.rest_start + 1;
1889 }
1890 else if (body->param.flags.has_opt) {
1891 body->param.size = body->param.lead_num + body->param.opt_num;
1892 }
1893 else {
1894 UNREACHABLE;
1895 }
1896 }
1897 else {
1898 body->param.size = body->param.lead_num;
1899 }
1900}
1901
1902static int
1903iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1904 const struct rb_args_info *args, int arg_size)
1905{
1906 const rb_node_kw_arg_t *node = args->kw_args;
1907 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1908 struct rb_iseq_param_keyword *keyword;
1909 const VALUE default_values = rb_ary_hidden_new(1);
1910 const VALUE complex_mark = rb_str_tmp_new(0);
1911 int kw = 0, rkw = 0, di = 0, i;
1912
1913 body->param.flags.has_kw = TRUE;
1914 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1915
1916 while (node) {
1917 kw++;
1918 node = node->nd_next;
1919 }
1920 arg_size += kw;
1921 keyword->bits_start = arg_size++;
1922
1923 node = args->kw_args;
1924 while (node) {
1925 const NODE *val_node = get_nd_value(node->nd_body);
1926 VALUE dv;
1927
1928 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1929 ++rkw;
1930 }
1931 else {
1932 switch (nd_type(val_node)) {
1933 case NODE_SYM:
1934 dv = rb_node_sym_string_val(val_node);
1935 break;
1936 case NODE_REGX:
1937 dv = rb_node_regx_string_val(val_node);
1938 break;
1939 case NODE_LINE:
1940 dv = rb_node_line_lineno_val(val_node);
1941 break;
1942 case NODE_INTEGER:
1943 dv = rb_node_integer_literal_val(val_node);
1944 break;
1945 case NODE_FLOAT:
1946 dv = rb_node_float_literal_val(val_node);
1947 break;
1948 case NODE_RATIONAL:
1949 dv = rb_node_rational_literal_val(val_node);
1950 break;
1951 case NODE_IMAGINARY:
1952 dv = rb_node_imaginary_literal_val(val_node);
1953 break;
1954 case NODE_ENCODING:
1955 dv = rb_node_encoding_val(val_node);
1956 break;
1957 case NODE_NIL:
1958 dv = Qnil;
1959 break;
1960 case NODE_TRUE:
1961 dv = Qtrue;
1962 break;
1963 case NODE_FALSE:
1964 dv = Qfalse;
1965 break;
1966 default:
1967 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1968 dv = complex_mark;
1969 }
1970
1971 keyword->num = ++di;
1972 rb_ary_push(default_values, dv);
1973 }
1974
1975 node = node->nd_next;
1976 }
1977
1978 keyword->num = kw;
1979
1980 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1981 ID kw_id = iseq->body->local_table[arg_size];
1982 keyword->rest_start = arg_size++;
1983 body->param.flags.has_kwrest = TRUE;
1984
1985 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
1986 }
1987 keyword->required_num = rkw;
1988 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1989
1990 if (RARRAY_LEN(default_values)) {
1991 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1992
1993 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1994 VALUE dv = RARRAY_AREF(default_values, i);
1995 if (dv == complex_mark) dv = Qundef;
1996 RB_OBJ_WRITE(iseq, &dvs[i], dv);
1997 }
1998
1999 keyword->default_values = dvs;
2000 }
2001 return arg_size;
2002}
2003
2004static void
2005iseq_set_use_block(rb_iseq_t *iseq)
2006{
2007 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2008 if (!body->param.flags.use_block) {
2009 body->param.flags.use_block = 1;
2010
2011 rb_vm_t *vm = GET_VM();
2012
2013 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2014 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2015 st_insert(vm->unused_block_warning_table, key, 1);
2016 }
2017 }
2018}
2019
2020static int
2021iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2022{
2023 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2024
2025 if (node_args) {
2026 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2027 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2028 ID rest_id = 0;
2029 int last_comma = 0;
2030 ID block_id = 0;
2031 int arg_size;
2032
2033 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2034
2035 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2036 body->param.lead_num = arg_size = (int)args->pre_args_num;
2037 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2038 debugs(" - argc: %d\n", body->param.lead_num);
2039
2040 rest_id = args->rest_arg;
2041 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2042 last_comma = 1;
2043 rest_id = 0;
2044 }
2045 block_id = args->block_arg;
2046
2047 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2048
2049 if (optimized_forward) {
2050 rest_id = 0;
2051 block_id = 0;
2052 }
2053
2054 if (args->opt_args) {
2055 const rb_node_opt_arg_t *node = args->opt_args;
2056 LABEL *label;
2057 VALUE labels = rb_ary_hidden_new(1);
2058 VALUE *opt_table;
2059 int i = 0, j;
2060
2061 while (node) {
2062 label = NEW_LABEL(nd_line(RNODE(node)));
2063 rb_ary_push(labels, (VALUE)label | 1);
2064 ADD_LABEL(optargs, label);
2065 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2066 node = node->nd_next;
2067 i += 1;
2068 }
2069
2070 /* last label */
2071 label = NEW_LABEL(nd_line(node_args));
2072 rb_ary_push(labels, (VALUE)label | 1);
2073 ADD_LABEL(optargs, label);
2074
2075 opt_table = ALLOC_N(VALUE, i+1);
2076
2077 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2078 for (j = 0; j < i+1; j++) {
2079 opt_table[j] &= ~1;
2080 }
2081 rb_ary_clear(labels);
2082
2083 body->param.flags.has_opt = TRUE;
2084 body->param.opt_num = i;
2085 body->param.opt_table = opt_table;
2086 arg_size += i;
2087 }
2088
2089 if (rest_id) {
2090 body->param.rest_start = arg_size++;
2091 body->param.flags.has_rest = TRUE;
2092 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2093 RUBY_ASSERT(body->param.rest_start != -1);
2094 }
2095
2096 if (args->first_post_arg) {
2097 body->param.post_start = arg_size;
2098 body->param.post_num = args->post_args_num;
2099 body->param.flags.has_post = TRUE;
2100 arg_size += args->post_args_num;
2101
2102 if (body->param.flags.has_rest) { /* TODO: why that? */
2103 body->param.post_start = body->param.rest_start + 1;
2104 }
2105 }
2106
2107 if (args->kw_args) {
2108 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2109 }
2110 else if (args->kw_rest_arg && !optimized_forward) {
2111 ID kw_id = iseq->body->local_table[arg_size];
2112 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2113 keyword->rest_start = arg_size++;
2114 body->param.keyword = keyword;
2115 body->param.flags.has_kwrest = TRUE;
2116
2117 static ID anon_kwrest = 0;
2118 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2119 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2120 }
2121 else if (args->no_kwarg) {
2122 body->param.flags.accepts_no_kwarg = TRUE;
2123 }
2124
2125 if (block_id) {
2126 body->param.block_start = arg_size++;
2127 body->param.flags.has_block = TRUE;
2128 iseq_set_use_block(iseq);
2129 }
2130
2131 // Only optimize specifically methods like this: `foo(...)`
2132 if (optimized_forward) {
2133 body->param.flags.use_block = 1;
2134 body->param.flags.forwardable = TRUE;
2135 arg_size = 1;
2136 }
2137
2138 iseq_calc_param_size(iseq);
2139 body->param.size = arg_size;
2140
2141 if (args->pre_init) { /* m_init */
2142 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2143 }
2144 if (args->post_init) { /* p_init */
2145 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2146 }
2147
2148 if (body->type == ISEQ_TYPE_BLOCK) {
2149 if (body->param.flags.has_opt == FALSE &&
2150 body->param.flags.has_post == FALSE &&
2151 body->param.flags.has_rest == FALSE &&
2152 body->param.flags.has_kw == FALSE &&
2153 body->param.flags.has_kwrest == FALSE) {
2154
2155 if (body->param.lead_num == 1 && last_comma == 0) {
2156 /* {|a|} */
2157 body->param.flags.ambiguous_param0 = TRUE;
2158 }
2159 }
2160 }
2161 }
2162
2163 return COMPILE_OK;
2164}
2165
2166static int
2167iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2168{
2169 unsigned int size = tbl ? tbl->size : 0;
2170 unsigned int offset = 0;
2171
2172 if (node_args) {
2173 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2174
2175 // If we have a function that only has `...` as the parameter,
2176 // then its local table should only be `...`
2177 // FIXME: I think this should be fixed in the AST rather than special case here.
2178 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2179 size -= 3;
2180 offset += 3;
2181 }
2182 }
2183
2184 if (size > 0) {
2185 ID *ids = (ID *)ALLOC_N(ID, size);
2186 MEMCPY(ids, tbl->ids + offset, ID, size);
2187 ISEQ_BODY(iseq)->local_table = ids;
2188 }
2189 ISEQ_BODY(iseq)->local_table_size = size;
2190
2191 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2192 return COMPILE_OK;
2193}
2194
2195int
2196rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2197{
2198 int tval, tlit;
2199
2200 if (val == lit) {
2201 return 0;
2202 }
2203 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2204 return val != lit;
2205 }
2206 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2207 return -1;
2208 }
2209 else if (tlit != tval) {
2210 return -1;
2211 }
2212 else if (tlit == T_SYMBOL) {
2213 return val != lit;
2214 }
2215 else if (tlit == T_STRING) {
2216 return rb_str_hash_cmp(lit, val);
2217 }
2218 else if (tlit == T_BIGNUM) {
2219 long x = FIX2LONG(rb_big_cmp(lit, val));
2220
2221 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2222 * There is no need to call rb_fix2int here. */
2223 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2224 return (int)x;
2225 }
2226 else if (tlit == T_FLOAT) {
2227 return rb_float_cmp(lit, val);
2228 }
2229 else if (tlit == T_RATIONAL) {
2230 const struct RRational *rat1 = RRATIONAL(val);
2231 const struct RRational *rat2 = RRATIONAL(lit);
2232 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2233 }
2234 else if (tlit == T_COMPLEX) {
2235 const struct RComplex *comp1 = RCOMPLEX(val);
2236 const struct RComplex *comp2 = RCOMPLEX(lit);
2237 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2238 }
2239 else if (tlit == T_REGEXP) {
2240 return rb_reg_equal(val, lit) ? 0 : -1;
2241 }
2242 else {
2243 UNREACHABLE_RETURN(-1);
2244 }
2245}
2246
2247st_index_t
2248rb_iseq_cdhash_hash(VALUE a)
2249{
2250 switch (OBJ_BUILTIN_TYPE(a)) {
2251 case -1:
2252 case T_SYMBOL:
2253 return (st_index_t)a;
2254 case T_STRING:
2255 return rb_str_hash(a);
2256 case T_BIGNUM:
2257 return FIX2LONG(rb_big_hash(a));
2258 case T_FLOAT:
2259 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2260 case T_RATIONAL:
2261 return rb_rational_hash(a);
2262 case T_COMPLEX:
2263 return rb_complex_hash(a);
2264 case T_REGEXP:
2265 return NUM2LONG(rb_reg_hash(a));
2266 default:
2267 UNREACHABLE_RETURN(0);
2268 }
2269}
2270
2271static const struct st_hash_type cdhash_type = {
2272 rb_iseq_cdhash_cmp,
2273 rb_iseq_cdhash_hash,
2274};
2275
2276 struct cdhash_set_label_struct {
2277 VALUE hash;
2278 int pos;
2279 int len;
2280};
2281
2282static int
2283cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2284{
2285 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2286 LABEL *lobj = (LABEL *)(val & ~1);
2287 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2288 return ST_CONTINUE;
2289}
2290
2291
2292static inline VALUE
2293get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2294{
2295 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2296}
2297
2298static inline VALUE
2299get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2300{
2301 VALUE val;
2302 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2303 if (tbl) {
2304 if (rb_id_table_lookup(tbl,id,&val)) {
2305 return val;
2306 }
2307 }
2308 else {
2309 tbl = rb_id_table_create(1);
2310 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2311 }
2312 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2313 rb_id_table_insert(tbl,id,val);
2314 return val;
2315}
2316
2317#define BADINSN_DUMP(anchor, list, dest) \
2318 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2319
2320#define BADINSN_ERROR \
2321 (xfree(generated_iseq), \
2322 xfree(insns_info), \
2323 BADINSN_DUMP(anchor, list, NULL), \
2324 COMPILE_ERROR)
2325
2326static int
2327fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2328{
2329 int stack_max = 0, sp = 0, line = 0;
2330 LINK_ELEMENT *list;
2331
2332 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2333 if (IS_LABEL(list)) {
2334 LABEL *lobj = (LABEL *)list;
2335 lobj->set = TRUE;
2336 }
2337 }
2338
2339 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2340 switch (list->type) {
2341 case ISEQ_ELEMENT_INSN:
2342 {
2343 int j, len, insn;
2344 const char *types;
2345 VALUE *operands;
2346 INSN *iobj = (INSN *)list;
2347
2348 /* update sp */
2349 sp = calc_sp_depth(sp, iobj);
2350 if (sp < 0) {
2351 BADINSN_DUMP(anchor, list, NULL);
2352 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2353 "argument stack underflow (%d)", sp);
2354 return -1;
2355 }
2356 if (sp > stack_max) {
2357 stack_max = sp;
2358 }
2359
2360 line = iobj->insn_info.line_no;
2361 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2362 operands = iobj->operands;
2363 insn = iobj->insn_id;
2364 types = insn_op_types(insn);
2365 len = insn_len(insn);
2366
2367 /* operand check */
2368 if (iobj->operand_size != len - 1) {
2369 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2370 BADINSN_DUMP(anchor, list, NULL);
2371 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2372 "operand size miss! (%d for %d)",
2373 iobj->operand_size, len - 1);
2374 return -1;
2375 }
2376
2377 for (j = 0; types[j]; j++) {
2378 if (types[j] == TS_OFFSET) {
2379 /* label(destination position) */
2380 LABEL *lobj = (LABEL *)operands[j];
2381 if (!lobj->set) {
2382 BADINSN_DUMP(anchor, list, NULL);
2383 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2384 "unknown label: "LABEL_FORMAT, lobj->label_no);
2385 return -1;
2386 }
2387 if (lobj->sp == -1) {
2388 lobj->sp = sp;
2389 }
2390 else if (lobj->sp != sp) {
2391 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2392 RSTRING_PTR(rb_iseq_path(iseq)), line,
2393 lobj->label_no, lobj->sp, sp);
2394 }
2395 }
2396 }
2397 break;
2398 }
2399 case ISEQ_ELEMENT_LABEL:
2400 {
2401 LABEL *lobj = (LABEL *)list;
2402 if (lobj->sp == -1) {
2403 lobj->sp = sp;
2404 }
2405 else {
2406 if (lobj->sp != sp) {
2407 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2408 RSTRING_PTR(rb_iseq_path(iseq)), line,
2409 lobj->label_no, lobj->sp, sp);
2410 }
2411 sp = lobj->sp;
2412 }
2413 break;
2414 }
2415 case ISEQ_ELEMENT_TRACE:
2416 {
2417 /* ignore */
2418 break;
2419 }
2420 case ISEQ_ELEMENT_ADJUST:
2421 {
2422 ADJUST *adjust = (ADJUST *)list;
2423 int orig_sp = sp;
2424
2425 sp = adjust->label ? adjust->label->sp : 0;
2426 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2427 BADINSN_DUMP(anchor, list, NULL);
2428 COMPILE_ERROR(iseq, adjust->line_no,
2429 "iseq_set_sequence: adjust bug %d < %d",
2430 orig_sp, sp);
2431 return -1;
2432 }
2433 break;
2434 }
2435 default:
2436 BADINSN_DUMP(anchor, list, NULL);
2437 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2438 return -1;
2439 }
2440 }
2441 return stack_max;
2442}
2443
2444static int
2445add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2446 int insns_info_index, int code_index, const INSN *iobj)
2447{
2448 if (insns_info_index == 0 ||
2449 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2450#ifdef USE_ISEQ_NODE_ID
2451 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2452#endif
2453 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2454 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2455#ifdef USE_ISEQ_NODE_ID
2456 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2457#endif
2458 insns_info[insns_info_index].events = iobj->insn_info.events;
2459 positions[insns_info_index] = code_index;
2460 return TRUE;
2461 }
2462 return FALSE;
2463}
2464
2465static int
2466add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2467 int insns_info_index, int code_index, const ADJUST *adjust)
2468{
2469 insns_info[insns_info_index].line_no = adjust->line_no;
2470 insns_info[insns_info_index].node_id = -1;
2471 insns_info[insns_info_index].events = 0;
2472 positions[insns_info_index] = code_index;
2473 return TRUE;
2474}
2475
2476static ID *
2477array_to_idlist(VALUE arr)
2478{
2479 RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2480 long size = RARRAY_LEN(arr);
2481 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2482 for (int i = 0; i < size; i++) {
2483 VALUE sym = RARRAY_AREF(arr, i);
2484 ids[i] = SYM2ID(sym);
2485 }
2486 ids[size] = 0;
2487 return ids;
2488}
2489
2490static VALUE
2491idlist_to_array(const ID *ids)
2492{
2493 VALUE arr = rb_ary_new();
2494 while (*ids) {
2495 rb_ary_push(arr, ID2SYM(*ids++));
2496 }
2497 return arr;
2498}
2499
2503static int
2504iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2505{
2506 struct iseq_insn_info_entry *insns_info;
2507 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2508 unsigned int *positions;
2509 LINK_ELEMENT *list;
2510 VALUE *generated_iseq;
2511 rb_event_flag_t events = 0;
2512 long data = 0;
2513
2514 int insn_num, code_index, insns_info_index, sp = 0;
2515 int stack_max = fix_sp_depth(iseq, anchor);
2516
2517 if (stack_max < 0) return COMPILE_NG;
2518
2519 /* fix label position */
2520 insn_num = code_index = 0;
2521 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2522 switch (list->type) {
2523 case ISEQ_ELEMENT_INSN:
2524 {
2525 INSN *iobj = (INSN *)list;
2526 /* update sp */
2527 sp = calc_sp_depth(sp, iobj);
2528 insn_num++;
2529 events = iobj->insn_info.events |= events;
2530 if (ISEQ_COVERAGE(iseq)) {
2531 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2532 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2533 int line = iobj->insn_info.line_no - 1;
2534 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2535 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2536 }
2537 }
2538 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2539 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2540 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2541 }
2542 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2543 }
2544 }
2545 code_index += insn_data_length(iobj);
2546 events = 0;
2547 data = 0;
2548 break;
2549 }
2550 case ISEQ_ELEMENT_LABEL:
2551 {
2552 LABEL *lobj = (LABEL *)list;
2553 lobj->position = code_index;
2554 if (lobj->sp != sp) {
2555 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2556 RSTRING_PTR(rb_iseq_path(iseq)),
2557 lobj->label_no, lobj->sp, sp);
2558 }
2559 sp = lobj->sp;
2560 break;
2561 }
2562 case ISEQ_ELEMENT_TRACE:
2563 {
2564 TRACE *trace = (TRACE *)list;
2565 events |= trace->event;
2566 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2567 break;
2568 }
2569 case ISEQ_ELEMENT_ADJUST:
2570 {
2571 ADJUST *adjust = (ADJUST *)list;
2572 if (adjust->line_no != -1) {
2573 int orig_sp = sp;
2574 sp = adjust->label ? adjust->label->sp : 0;
2575 if (orig_sp - sp > 0) {
2576 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2577 code_index++; /* insn */
2578 insn_num++;
2579 }
2580 }
2581 break;
2582 }
2583 default: break;
2584 }
2585 }
2586
2587 /* make instruction sequence */
2588 generated_iseq = ALLOC_N(VALUE, code_index);
2589 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2590 positions = ALLOC_N(unsigned int, insn_num);
2591 if (ISEQ_IS_SIZE(body)) {
2592 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2593 }
2594 else {
2595 body->is_entries = NULL;
2596 }
2597 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2598 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2599
2600 // Calculate the bitmask buffer size.
2601 // Round the generated_iseq size up to the nearest multiple
2602 // of the number of bits in an unsigned long.
2603
2604 // Allocate enough room for the bitmask list
2605 iseq_bits_t * mark_offset_bits;
2606 int code_size = code_index;
2607
2608 iseq_bits_t tmp[1] = {0};
2609 bool needs_bitmap = false;
2610
2611 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2612 mark_offset_bits = tmp;
2613 }
2614 else {
2615 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2616 }
2617
2618 list = FIRST_ELEMENT(anchor);
2619 insns_info_index = code_index = sp = 0;
2620
2621 while (list) {
2622 switch (list->type) {
2623 case ISEQ_ELEMENT_INSN:
2624 {
2625 int j, len, insn;
2626 const char *types;
2627 VALUE *operands;
2628 INSN *iobj = (INSN *)list;
2629
2630 /* update sp */
2631 sp = calc_sp_depth(sp, iobj);
2632 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2633 operands = iobj->operands;
2634 insn = iobj->insn_id;
2635 generated_iseq[code_index] = insn;
2636 types = insn_op_types(insn);
2637 len = insn_len(insn);
2638
2639 for (j = 0; types[j]; j++) {
2640 char type = types[j];
2641
2642 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2643 switch (type) {
2644 case TS_OFFSET:
2645 {
2646 /* label(destination position) */
2647 LABEL *lobj = (LABEL *)operands[j];
2648 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2649 break;
2650 }
2651 case TS_CDHASH:
2652 {
2653 VALUE map = operands[j];
2654 struct cdhash_set_label_struct data;
2655 data.hash = map;
2656 data.pos = code_index;
2657 data.len = len;
2658 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2659
2660 rb_hash_rehash(map);
2661 freeze_hide_obj(map);
2662 generated_iseq[code_index + 1 + j] = map;
2663 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2664 RB_OBJ_WRITTEN(iseq, Qundef, map);
2665 needs_bitmap = true;
2666 break;
2667 }
2668 case TS_LINDEX:
2669 case TS_NUM: /* ulong */
2670 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2671 break;
2672 case TS_ISEQ: /* iseq */
2673 case TS_VALUE: /* VALUE */
2674 {
2675 VALUE v = operands[j];
2676 generated_iseq[code_index + 1 + j] = v;
2677 /* to mark ruby object */
2678 if (!SPECIAL_CONST_P(v)) {
2679 RB_OBJ_WRITTEN(iseq, Qundef, v);
2680 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2681 needs_bitmap = true;
2682 }
2683 break;
2684 }
2685 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2686 case TS_IC: /* inline cache: constants */
2687 {
2688 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2689 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2690 if (UNLIKELY(ic_index >= body->ic_size)) {
2691 BADINSN_DUMP(anchor, &iobj->link, 0);
2692 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2693 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2694 ic_index, ISEQ_IS_SIZE(body));
2695 }
2696
2697 ic->segments = array_to_idlist(operands[j]);
2698
2699 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2700 }
2701 break;
2702 case TS_IVC: /* inline ivar cache */
2703 {
2704 unsigned int ic_index = FIX2UINT(operands[j]);
2705
2706 IVC cache = ((IVC)&body->is_entries[ic_index]);
2707
2708 if (insn == BIN(setinstancevariable)) {
2709 cache->iv_set_name = SYM2ID(operands[j - 1]);
2710 }
2711 else {
2712 cache->iv_set_name = 0;
2713 }
2714
2715 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2716 }
2717 case TS_ISE: /* inline storage entry: `once` insn */
2718 case TS_ICVARC: /* inline cvar cache */
2719 {
2720 unsigned int ic_index = FIX2UINT(operands[j]);
2721 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2722 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2723 BADINSN_DUMP(anchor, &iobj->link, 0);
2724 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2725 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2726 ic_index, ISEQ_IS_SIZE(body));
2727 }
2728 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2729
2730 break;
2731 }
2732 case TS_CALLDATA:
2733 {
2734 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2735 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2736 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2737 cd->ci = source_ci;
2738 cd->cc = vm_cc_empty();
2739 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2740 break;
2741 }
2742 case TS_ID: /* ID */
2743 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2744 break;
2745 case TS_FUNCPTR:
2746 generated_iseq[code_index + 1 + j] = operands[j];
2747 break;
2748 case TS_BUILTIN:
2749 generated_iseq[code_index + 1 + j] = operands[j];
2750 break;
2751 default:
2752 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2753 "unknown operand type: %c", type);
2754 return COMPILE_NG;
2755 }
2756 }
2757 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2758 code_index += len;
2759 break;
2760 }
2761 case ISEQ_ELEMENT_LABEL:
2762 {
2763 LABEL *lobj = (LABEL *)list;
2764 if (lobj->sp != sp) {
2765 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2766 RSTRING_PTR(rb_iseq_path(iseq)),
2767 lobj->label_no, lobj->sp, sp);
2768 }
2769 sp = lobj->sp;
2770 break;
2771 }
2772 case ISEQ_ELEMENT_ADJUST:
2773 {
2774 ADJUST *adjust = (ADJUST *)list;
2775 int orig_sp = sp;
2776
2777 if (adjust->label) {
2778 sp = adjust->label->sp;
2779 }
2780 else {
2781 sp = 0;
2782 }
2783
2784 if (adjust->line_no != -1) {
2785 const int diff = orig_sp - sp;
2786 if (diff > 0) {
2787 if (insns_info_index == 0) {
2788 COMPILE_ERROR(iseq, adjust->line_no,
2789 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2790 }
2791 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2792 }
2793 if (diff > 1) {
2794 generated_iseq[code_index++] = BIN(adjuststack);
2795 generated_iseq[code_index++] = orig_sp - sp;
2796 }
2797 else if (diff == 1) {
2798 generated_iseq[code_index++] = BIN(pop);
2799 }
2800 else if (diff < 0) {
2801 int label_no = adjust->label ? adjust->label->label_no : -1;
2802 xfree(generated_iseq);
2803 xfree(insns_info);
2804 xfree(positions);
2805 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2806 xfree(mark_offset_bits);
2807 }
2808 debug_list(anchor, list);
2809 COMPILE_ERROR(iseq, adjust->line_no,
2810 "iseq_set_sequence: adjust bug to %d %d < %d",
2811 label_no, orig_sp, sp);
2812 return COMPILE_NG;
2813 }
2814 }
2815 break;
2816 }
2817 default:
2818 /* ignore */
2819 break;
2820 }
2821 list = list->next;
2822 }
2823
2824 body->iseq_encoded = (void *)generated_iseq;
2825 body->iseq_size = code_index;
2826 body->stack_max = stack_max;
2827
2828 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2829 body->mark_bits.single = mark_offset_bits[0];
2830 }
2831 else {
2832 if (needs_bitmap) {
2833 body->mark_bits.list = mark_offset_bits;
2834 }
2835 else {
2836 body->mark_bits.list = 0;
2837 ruby_xfree(mark_offset_bits);
2838 }
2839 }
2840
2841 /* get rid of memory leak when REALLOC failed */
2842 body->insns_info.body = insns_info;
2843 body->insns_info.positions = positions;
2844
2845 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2846 body->insns_info.body = insns_info;
2847 REALLOC_N(positions, unsigned int, insns_info_index);
2848 body->insns_info.positions = positions;
2849 body->insns_info.size = insns_info_index;
2850
2851 return COMPILE_OK;
2852}
2853
2854static int
2855label_get_position(LABEL *lobj)
2856{
2857 return lobj->position;
2858}
2859
2860static int
2861label_get_sp(LABEL *lobj)
2862{
2863 return lobj->sp;
2864}
2865
2866static int
2867iseq_set_exception_table(rb_iseq_t *iseq)
2868{
2869 const VALUE *tptr, *ptr;
2870 unsigned int tlen, i;
2871 struct iseq_catch_table_entry *entry;
2872
2873 ISEQ_BODY(iseq)->catch_table = NULL;
2874
2875 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2876 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2877 tlen = (int)RARRAY_LEN(catch_table_ary);
2878 tptr = RARRAY_CONST_PTR(catch_table_ary);
2879
2880 if (tlen > 0) {
2881 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2882 table->size = tlen;
2883
2884 for (i = 0; i < table->size; i++) {
2885 int pos;
2886 ptr = RARRAY_CONST_PTR(tptr[i]);
2887 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2888 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2889 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2890 RUBY_ASSERT(pos >= 0);
2891 entry->start = (unsigned int)pos;
2892 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2893 RUBY_ASSERT(pos >= 0);
2894 entry->end = (unsigned int)pos;
2895 entry->iseq = (rb_iseq_t *)ptr[3];
2896 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2897
2898 /* stack depth */
2899 if (ptr[4]) {
2900 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2901 entry->cont = label_get_position(lobj);
2902 entry->sp = label_get_sp(lobj);
2903
2904 /* TODO: Dirty Hack! Fix me */
2905 if (entry->type == CATCH_TYPE_RESCUE ||
2906 entry->type == CATCH_TYPE_BREAK ||
2907 entry->type == CATCH_TYPE_NEXT) {
2908 RUBY_ASSERT(entry->sp > 0);
2909 entry->sp--;
2910 }
2911 }
2912 else {
2913 entry->cont = 0;
2914 }
2915 }
2916 ISEQ_BODY(iseq)->catch_table = table;
2917 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2918 }
2919
2920 RB_GC_GUARD(catch_table_ary);
2921
2922 return COMPILE_OK;
2923}
2924
2925/*
2926 * set optional argument table
2927 * def foo(a, b=expr1, c=expr2)
2928 * =>
2929 * b:
2930 * expr1
2931 * c:
2932 * expr2
2933 */
2934static int
2935iseq_set_optargs_table(rb_iseq_t *iseq)
2936{
2937 int i;
2938 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2939
2940 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2941 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2942 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2943 }
2944 }
2945 return COMPILE_OK;
2946}
2947
2948static LINK_ELEMENT *
2949get_destination_insn(INSN *iobj)
2950{
2951 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2952 LINK_ELEMENT *list;
2953 rb_event_flag_t events = 0;
2954
2955 list = lobj->link.next;
2956 while (list) {
2957 switch (list->type) {
2958 case ISEQ_ELEMENT_INSN:
2959 case ISEQ_ELEMENT_ADJUST:
2960 goto found;
2961 case ISEQ_ELEMENT_LABEL:
2962 /* ignore */
2963 break;
2964 case ISEQ_ELEMENT_TRACE:
2965 {
2966 TRACE *trace = (TRACE *)list;
2967 events |= trace->event;
2968 }
2969 break;
2970 default: break;
2971 }
2972 list = list->next;
2973 }
2974 found:
2975 if (list && IS_INSN(list)) {
2976 INSN *iobj = (INSN *)list;
2977 iobj->insn_info.events |= events;
2978 }
2979 return list;
2980}
2981
2982static LINK_ELEMENT *
2983get_next_insn(INSN *iobj)
2984{
2985 LINK_ELEMENT *list = iobj->link.next;
2986
2987 while (list) {
2988 if (IS_INSN(list) || IS_ADJUST(list)) {
2989 return list;
2990 }
2991 list = list->next;
2992 }
2993 return 0;
2994}
2995
2996static LINK_ELEMENT *
2997get_prev_insn(INSN *iobj)
2998{
2999 LINK_ELEMENT *list = iobj->link.prev;
3000
3001 while (list) {
3002 if (IS_INSN(list) || IS_ADJUST(list)) {
3003 return list;
3004 }
3005 list = list->prev;
3006 }
3007 return 0;
3008}
3009
3010static void
3011unref_destination(INSN *iobj, int pos)
3012{
3013 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3014 --lobj->refcnt;
3015 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3016}
3017
3018static bool
3019replace_destination(INSN *dobj, INSN *nobj)
3020{
3021 VALUE n = OPERAND_AT(nobj, 0);
3022 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3023 LABEL *nl = (LABEL *)n;
3024 if (dl == nl) return false;
3025 --dl->refcnt;
3026 ++nl->refcnt;
3027 OPERAND_AT(dobj, 0) = n;
3028 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3029 return true;
3030}
3031
3032static LABEL*
3033find_destination(INSN *i)
3034{
3035 int pos, len = insn_len(i->insn_id);
3036 for (pos = 0; pos < len; ++pos) {
3037 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3038 return (LABEL *)OPERAND_AT(i, pos);
3039 }
3040 }
3041 return 0;
3042}
3043
3044static int
3045remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3046{
3047 LINK_ELEMENT *first = i, *end;
3048 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3049
3050 if (!i) return 0;
3051 unref_counts = ALLOCA_N(int, nlabels);
3052 MEMZERO(unref_counts, int, nlabels);
3053 end = i;
3054 do {
3055 LABEL *lab;
3056 if (IS_INSN(i)) {
3057 if (IS_INSN_ID(i, leave)) {
3058 end = i;
3059 break;
3060 }
3061 else if ((lab = find_destination((INSN *)i)) != 0) {
3062 unref_counts[lab->label_no]++;
3063 }
3064 }
3065 else if (IS_LABEL(i)) {
3066 lab = (LABEL *)i;
3067 if (lab->unremovable) return 0;
3068 if (lab->refcnt > unref_counts[lab->label_no]) {
3069 if (i == first) return 0;
3070 break;
3071 }
3072 continue;
3073 }
3074 else if (IS_TRACE(i)) {
3075 /* do nothing */
3076 }
3077 else if (IS_ADJUST(i)) {
3078 return 0;
3079 }
3080 end = i;
3081 } while ((i = i->next) != 0);
3082 i = first;
3083 do {
3084 if (IS_INSN(i)) {
3085 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3086 VALUE insn = INSN_OF(i);
3087 int pos, len = insn_len(insn);
3088 for (pos = 0; pos < len; ++pos) {
3089 switch (insn_op_types(insn)[pos]) {
3090 case TS_OFFSET:
3091 unref_destination((INSN *)i, pos);
3092 break;
3093 case TS_CALLDATA:
3094 --(body->ci_size);
3095 break;
3096 }
3097 }
3098 }
3099 ELEM_REMOVE(i);
3100 } while ((i != end) && (i = i->next) != 0);
3101 return 1;
3102}
3103
3104static int
3105iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3106{
3107 switch (OPERAND_AT(iobj, 0)) {
3108 case INT2FIX(0): /* empty array */
3109 ELEM_REMOVE(&iobj->link);
3110 return TRUE;
3111 case INT2FIX(1): /* single element array */
3112 ELEM_REMOVE(&iobj->link);
3113 return FALSE;
3114 default:
3115 iobj->insn_id = BIN(adjuststack);
3116 return TRUE;
3117 }
3118}
3119
3120static int
3121is_frozen_putstring(INSN *insn, VALUE *op)
3122{
3123 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3124 *op = OPERAND_AT(insn, 0);
3125 return 1;
3126 }
3127 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3128 *op = OPERAND_AT(insn, 0);
3129 return RB_TYPE_P(*op, T_STRING);
3130 }
3131 return 0;
3132}
3133
3134static int
3135insn_has_label_before(LINK_ELEMENT *elem)
3136{
3137 LINK_ELEMENT *prev = elem->prev;
3138 while (prev) {
3139 if (prev->type == ISEQ_ELEMENT_LABEL) {
3140 LABEL *label = (LABEL *)prev;
3141 if (label->refcnt > 0) {
3142 return 1;
3143 }
3144 }
3145 else if (prev->type == ISEQ_ELEMENT_INSN) {
3146 break;
3147 }
3148 prev = prev->prev;
3149 }
3150 return 0;
3151}
3152
3153static int
3154optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3155{
3156 /*
3157 * putobject obj
3158 * dup
3159 * checktype T_XXX
3160 * branchif l1
3161 * l2:
3162 * ...
3163 * l1:
3164 *
3165 * => obj is a T_XXX
3166 *
3167 * putobject obj (T_XXX)
3168 * jump L1
3169 * L1:
3170 *
3171 * => obj is not a T_XXX
3172 *
3173 * putobject obj (T_XXX)
3174 * jump L2
3175 * L2:
3176 */
3177 int line, node_id;
3178 INSN *niobj, *ciobj, *dup = 0;
3179 LABEL *dest = 0;
3180 VALUE type;
3181
3182 switch (INSN_OF(iobj)) {
3183 case BIN(putstring):
3184 case BIN(putchilledstring):
3185 type = INT2FIX(T_STRING);
3186 break;
3187 case BIN(putnil):
3188 type = INT2FIX(T_NIL);
3189 break;
3190 case BIN(putobject):
3191 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3192 break;
3193 default: return FALSE;
3194 }
3195
3196 ciobj = (INSN *)get_next_insn(iobj);
3197 if (IS_INSN_ID(ciobj, jump)) {
3198 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3199 }
3200 if (IS_INSN_ID(ciobj, dup)) {
3201 ciobj = (INSN *)get_next_insn(dup = ciobj);
3202 }
3203 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3204 niobj = (INSN *)get_next_insn(ciobj);
3205 if (!niobj) {
3206 /* TODO: putobject true/false */
3207 return FALSE;
3208 }
3209 switch (INSN_OF(niobj)) {
3210 case BIN(branchif):
3211 if (OPERAND_AT(ciobj, 0) == type) {
3212 dest = (LABEL *)OPERAND_AT(niobj, 0);
3213 }
3214 break;
3215 case BIN(branchunless):
3216 if (OPERAND_AT(ciobj, 0) != type) {
3217 dest = (LABEL *)OPERAND_AT(niobj, 0);
3218 }
3219 break;
3220 default:
3221 return FALSE;
3222 }
3223 line = ciobj->insn_info.line_no;
3224 node_id = ciobj->insn_info.node_id;
3225 if (!dest) {
3226 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3227 dest = (LABEL *)niobj->link.next; /* reuse label */
3228 }
3229 else {
3230 dest = NEW_LABEL(line);
3231 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3232 }
3233 }
3234 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3235 LABEL_REF(dest);
3236 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3237 return TRUE;
3238}
3239
3240static const struct rb_callinfo *
3241ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3242{
3243 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3244 vm_ci_flag(ci) | add,
3245 vm_ci_argc(ci),
3246 vm_ci_kwarg(ci));
3247 RB_OBJ_WRITTEN(iseq, ci, nci);
3248 return nci;
3249}
3250
3251static const struct rb_callinfo *
3252ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3253{
3254 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3255 vm_ci_flag(ci),
3256 argc,
3257 vm_ci_kwarg(ci));
3258 RB_OBJ_WRITTEN(iseq, ci, nci);
3259 return nci;
3260}
3261
3262#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3263
3264static int
3265iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3266{
3267 INSN *const iobj = (INSN *)list;
3268
3269 again:
3270 optimize_checktype(iseq, iobj);
3271
3272 if (IS_INSN_ID(iobj, jump)) {
3273 INSN *niobj, *diobj, *piobj;
3274 diobj = (INSN *)get_destination_insn(iobj);
3275 niobj = (INSN *)get_next_insn(iobj);
3276
3277 if (diobj == niobj) {
3278 /*
3279 * jump LABEL
3280 * LABEL:
3281 * =>
3282 * LABEL:
3283 */
3284 unref_destination(iobj, 0);
3285 ELEM_REMOVE(&iobj->link);
3286 return COMPILE_OK;
3287 }
3288 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3289 IS_INSN_ID(diobj, jump) &&
3290 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3291 diobj->insn_info.events == 0) {
3292 /*
3293 * useless jump elimination:
3294 * jump LABEL1
3295 * ...
3296 * LABEL1:
3297 * jump LABEL2
3298 *
3299 * => in this case, first jump instruction should jump to
3300 * LABEL2 directly
3301 */
3302 if (replace_destination(iobj, diobj)) {
3303 remove_unreachable_chunk(iseq, iobj->link.next);
3304 goto again;
3305 }
3306 }
3307 else if (IS_INSN_ID(diobj, leave)) {
3308 /*
3309 * jump LABEL
3310 * ...
3311 * LABEL:
3312 * leave
3313 * =>
3314 * leave
3315 * ...
3316 * LABEL:
3317 * leave
3318 */
3319 /* replace */
3320 unref_destination(iobj, 0);
3321 iobj->insn_id = BIN(leave);
3322 iobj->operand_size = 0;
3323 iobj->insn_info = diobj->insn_info;
3324 goto again;
3325 }
3326 else if (IS_INSN(iobj->link.prev) &&
3327 (piobj = (INSN *)iobj->link.prev) &&
3328 (IS_INSN_ID(piobj, branchif) ||
3329 IS_INSN_ID(piobj, branchunless))) {
3330 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3331 if (niobj == pdiobj) {
3332 int refcnt = IS_LABEL(piobj->link.next) ?
3333 ((LABEL *)piobj->link.next)->refcnt : 0;
3334 /*
3335 * useless jump elimination (if/unless destination):
3336 * if L1
3337 * jump L2
3338 * L1:
3339 * ...
3340 * L2:
3341 *
3342 * ==>
3343 * unless L2
3344 * L1:
3345 * ...
3346 * L2:
3347 */
3348 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3349 ? BIN(branchunless) : BIN(branchif);
3350 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3351 ELEM_REMOVE(&iobj->link);
3352 }
3353 else {
3354 /* TODO: replace other branch destinations too */
3355 }
3356 return COMPILE_OK;
3357 }
3358 else if (diobj == pdiobj) {
3359 /*
3360 * useless jump elimination (if/unless before jump):
3361 * L1:
3362 * ...
3363 * if L1
3364 * jump L1
3365 *
3366 * ==>
3367 * L1:
3368 * ...
3369 * pop
3370 * jump L1
3371 */
3372 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3373 ELEM_REPLACE(&piobj->link, &popiobj->link);
3374 }
3375 }
3376 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3377 goto again;
3378 }
3379 }
3380
3381 /*
3382 * putstring "beg"
3383 * putstring "end"
3384 * newrange excl
3385 *
3386 * ==>
3387 *
3388 * putobject "beg".."end"
3389 */
3390 if (IS_INSN_ID(iobj, newrange)) {
3391 INSN *const range = iobj;
3392 INSN *beg, *end;
3393 VALUE str_beg, str_end;
3394
3395 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3396 is_frozen_putstring(end, &str_end) &&
3397 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3398 is_frozen_putstring(beg, &str_beg) &&
3399 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3400 int excl = FIX2INT(OPERAND_AT(range, 0));
3401 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3402
3403 ELEM_REMOVE(&beg->link);
3404 ELEM_REMOVE(&end->link);
3405 range->insn_id = BIN(putobject);
3406 OPERAND_AT(range, 0) = lit_range;
3407 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3408 }
3409 }
3410
3411 if (IS_INSN_ID(iobj, leave)) {
3412 remove_unreachable_chunk(iseq, iobj->link.next);
3413 }
3414
3415 /*
3416 * ...
3417 * duparray [...]
3418 * concatarray | concattoarray
3419 * =>
3420 * ...
3421 * putobject [...]
3422 * concatarray | concattoarray
3423 */
3424 if (IS_INSN_ID(iobj, duparray)) {
3425 LINK_ELEMENT *next = iobj->link.next;
3426 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3427 iobj->insn_id = BIN(putobject);
3428 }
3429 }
3430
3431 /*
3432 * duparray [...]
3433 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3434 * =>
3435 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3436 */
3437 if (IS_INSN_ID(iobj, duparray)) {
3438 LINK_ELEMENT *next = iobj->link.next;
3439 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3440 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3441 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3442
3443 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3444 VALUE ary = iobj->operands[0];
3445 rb_obj_reveal(ary, rb_cArray);
3446
3447 iobj->insn_id = BIN(opt_ary_freeze);
3448 iobj->operand_size = 2;
3449 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3450 iobj->operands[0] = ary;
3451 iobj->operands[1] = (VALUE)ci;
3452 ELEM_REMOVE(next);
3453 }
3454 }
3455 }
3456
3457 /*
3458 * duphash {...}
3459 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3460 * =>
3461 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3462 */
3463 if (IS_INSN_ID(iobj, duphash)) {
3464 LINK_ELEMENT *next = iobj->link.next;
3465 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3466 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3467 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3468
3469 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3470 VALUE hash = iobj->operands[0];
3471 rb_obj_reveal(hash, rb_cHash);
3472
3473 iobj->insn_id = BIN(opt_hash_freeze);
3474 iobj->operand_size = 2;
3475 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3476 iobj->operands[0] = hash;
3477 iobj->operands[1] = (VALUE)ci;
3478 ELEM_REMOVE(next);
3479 }
3480 }
3481 }
3482
3483 /*
3484 * newarray 0
3485 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3486 * =>
3487 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3488 */
3489 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3490 LINK_ELEMENT *next = iobj->link.next;
3491 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3492 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3493 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3494
3495 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3496 iobj->insn_id = BIN(opt_ary_freeze);
3497 iobj->operand_size = 2;
3498 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3499 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cArray_empty_frozen);
3500 iobj->operands[1] = (VALUE)ci;
3501 ELEM_REMOVE(next);
3502 }
3503 }
3504 }
3505
3506 /*
3507 * newhash 0
3508 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3509 * =>
3510 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3511 */
3512 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3513 LINK_ELEMENT *next = iobj->link.next;
3514 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3515 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3516 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3517
3518 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3519 iobj->insn_id = BIN(opt_hash_freeze);
3520 iobj->operand_size = 2;
3521 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3522 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cHash_empty_frozen);
3523 iobj->operands[1] = (VALUE)ci;
3524 ELEM_REMOVE(next);
3525 }
3526 }
3527 }
3528
3529 if (IS_INSN_ID(iobj, branchif) ||
3530 IS_INSN_ID(iobj, branchnil) ||
3531 IS_INSN_ID(iobj, branchunless)) {
3532 /*
3533 * if L1
3534 * ...
3535 * L1:
3536 * jump L2
3537 * =>
3538 * if L2
3539 */
3540 INSN *nobj = (INSN *)get_destination_insn(iobj);
3541
3542 /* This is super nasty hack!!!
3543 *
3544 * This jump-jump optimization may ignore event flags of the jump
3545 * instruction being skipped. Actually, Line 2 TracePoint event
3546 * is never fired in the following code:
3547 *
3548 * 1: raise if 1 == 2
3549 * 2: while true
3550 * 3: break
3551 * 4: end
3552 *
3553 * This is critical for coverage measurement. [Bug #15980]
3554 *
3555 * This is a stopgap measure: stop the jump-jump optimization if
3556 * coverage measurement is enabled and if the skipped instruction
3557 * has any event flag.
3558 *
3559 * Note that, still, TracePoint Line event does not occur on Line 2.
3560 * This should be fixed in future.
3561 */
3562 int stop_optimization =
3563 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3564 nobj->link.type == ISEQ_ELEMENT_INSN &&
3565 nobj->insn_info.events;
3566 if (!stop_optimization) {
3567 INSN *pobj = (INSN *)iobj->link.prev;
3568 int prev_dup = 0;
3569 if (pobj) {
3570 if (!IS_INSN(&pobj->link))
3571 pobj = 0;
3572 else if (IS_INSN_ID(pobj, dup))
3573 prev_dup = 1;
3574 }
3575
3576 for (;;) {
3577 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3578 if (!replace_destination(iobj, nobj)) break;
3579 }
3580 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3581 !!(nobj = (INSN *)nobj->link.next) &&
3582 /* basic blocks, with no labels in the middle */
3583 nobj->insn_id == iobj->insn_id) {
3584 /*
3585 * dup
3586 * if L1
3587 * ...
3588 * L1:
3589 * dup
3590 * if L2
3591 * =>
3592 * dup
3593 * if L2
3594 * ...
3595 * L1:
3596 * dup
3597 * if L2
3598 */
3599 if (!replace_destination(iobj, nobj)) break;
3600 }
3601 else if (pobj) {
3602 /*
3603 * putnil
3604 * if L1
3605 * =>
3606 * # nothing
3607 *
3608 * putobject true
3609 * if L1
3610 * =>
3611 * jump L1
3612 *
3613 * putstring ".."
3614 * if L1
3615 * =>
3616 * jump L1
3617 *
3618 * putstring ".."
3619 * dup
3620 * if L1
3621 * =>
3622 * putstring ".."
3623 * jump L1
3624 *
3625 */
3626 int cond;
3627 if (prev_dup && IS_INSN(pobj->link.prev)) {
3628 pobj = (INSN *)pobj->link.prev;
3629 }
3630 if (IS_INSN_ID(pobj, putobject)) {
3631 cond = (IS_INSN_ID(iobj, branchif) ?
3632 OPERAND_AT(pobj, 0) != Qfalse :
3633 IS_INSN_ID(iobj, branchunless) ?
3634 OPERAND_AT(pobj, 0) == Qfalse :
3635 FALSE);
3636 }
3637 else if (IS_INSN_ID(pobj, putstring) ||
3638 IS_INSN_ID(pobj, duparray) ||
3639 IS_INSN_ID(pobj, newarray)) {
3640 cond = IS_INSN_ID(iobj, branchif);
3641 }
3642 else if (IS_INSN_ID(pobj, putnil)) {
3643 cond = !IS_INSN_ID(iobj, branchif);
3644 }
3645 else break;
3646 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3647 ELEM_REMOVE(iobj->link.prev);
3648 }
3649 else if (!iseq_pop_newarray(iseq, pobj)) {
3650 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3651 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3652 }
3653 if (cond) {
3654 if (prev_dup) {
3655 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3656 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3657 }
3658 iobj->insn_id = BIN(jump);
3659 goto again;
3660 }
3661 else {
3662 unref_destination(iobj, 0);
3663 ELEM_REMOVE(&iobj->link);
3664 }
3665 break;
3666 }
3667 else break;
3668 nobj = (INSN *)get_destination_insn(nobj);
3669 }
3670 }
3671 }
3672
3673 if (IS_INSN_ID(iobj, pop)) {
3674 /*
3675 * putself / putnil / putobject obj / putstring "..."
3676 * pop
3677 * =>
3678 * # do nothing
3679 */
3680 LINK_ELEMENT *prev = iobj->link.prev;
3681 if (IS_INSN(prev)) {
3682 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3683 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3684 previ == BIN(putself) || previ == BIN(putstring) ||
3685 previ == BIN(putchilledstring) ||
3686 previ == BIN(dup) ||
3687 previ == BIN(getlocal) ||
3688 previ == BIN(getblockparam) ||
3689 previ == BIN(getblockparamproxy) ||
3690 previ == BIN(getinstancevariable) ||
3691 previ == BIN(duparray)) {
3692 /* just push operand or static value and pop soon, no
3693 * side effects */
3694 ELEM_REMOVE(prev);
3695 ELEM_REMOVE(&iobj->link);
3696 }
3697 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3698 ELEM_REMOVE(&iobj->link);
3699 }
3700 else if (previ == BIN(concatarray)) {
3701 INSN *piobj = (INSN *)prev;
3702 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3703 INSN_OF(piobj) = BIN(pop);
3704 }
3705 else if (previ == BIN(concatstrings)) {
3706 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3707 ELEM_REMOVE(prev);
3708 }
3709 else {
3710 ELEM_REMOVE(&iobj->link);
3711 INSN_OF(prev) = BIN(adjuststack);
3712 }
3713 }
3714 }
3715 }
3716
3717 if (IS_INSN_ID(iobj, newarray) ||
3718 IS_INSN_ID(iobj, duparray) ||
3719 IS_INSN_ID(iobj, concatarray) ||
3720 IS_INSN_ID(iobj, splatarray) ||
3721 0) {
3722 /*
3723 * newarray N
3724 * splatarray
3725 * =>
3726 * newarray N
3727 * newarray always puts an array
3728 */
3729 LINK_ELEMENT *next = iobj->link.next;
3730 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3731 /* remove splatarray following always-array insn */
3732 ELEM_REMOVE(next);
3733 }
3734 }
3735
3736 if (IS_INSN_ID(iobj, newarray)) {
3737 LINK_ELEMENT *next = iobj->link.next;
3738 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3739 OPERAND_AT(next, 1) == INT2FIX(0)) {
3740 VALUE op1, op2;
3741 op1 = OPERAND_AT(iobj, 0);
3742 op2 = OPERAND_AT(next, 0);
3743 ELEM_REMOVE(next);
3744
3745 if (op1 == op2) {
3746 /*
3747 * newarray 2
3748 * expandarray 2, 0
3749 * =>
3750 * swap
3751 */
3752 if (op1 == INT2FIX(2)) {
3753 INSN_OF(iobj) = BIN(swap);
3754 iobj->operand_size = 0;
3755 }
3756 /*
3757 * newarray X
3758 * expandarray X, 0
3759 * =>
3760 * opt_reverse X
3761 */
3762 else {
3763 INSN_OF(iobj) = BIN(opt_reverse);
3764 }
3765 }
3766 else {
3767 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3768 INSN_OF(iobj) = BIN(opt_reverse);
3769 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3770
3771 if (op1 > op2) {
3772 /* X > Y
3773 * newarray X
3774 * expandarray Y, 0
3775 * =>
3776 * pop * (Y-X)
3777 * opt_reverse Y
3778 */
3779 for (; diff > 0; diff--) {
3780 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3781 }
3782 }
3783 else { /* (op1 < op2) */
3784 /* X < Y
3785 * newarray X
3786 * expandarray Y, 0
3787 * =>
3788 * putnil * (Y-X)
3789 * opt_reverse Y
3790 */
3791 for (; diff < 0; diff++) {
3792 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3793 }
3794 }
3795 }
3796 }
3797 }
3798
3799 if (IS_INSN_ID(iobj, duparray)) {
3800 LINK_ELEMENT *next = iobj->link.next;
3801 /*
3802 * duparray obj
3803 * expandarray X, 0
3804 * =>
3805 * putobject obj
3806 * expandarray X, 0
3807 */
3808 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3809 INSN_OF(iobj) = BIN(putobject);
3810 }
3811 }
3812
3813 if (IS_INSN_ID(iobj, anytostring)) {
3814 LINK_ELEMENT *next = iobj->link.next;
3815 /*
3816 * anytostring
3817 * concatstrings 1
3818 * =>
3819 * anytostring
3820 */
3821 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3822 OPERAND_AT(next, 0) == INT2FIX(1)) {
3823 ELEM_REMOVE(next);
3824 }
3825 }
3826
3827 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3828 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3829 /*
3830 * putstring ""
3831 * concatstrings N
3832 * =>
3833 * concatstrings N-1
3834 */
3835 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3836 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3837 INSN *next = (INSN *)iobj->link.next;
3838 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3839 ELEM_REMOVE(&next->link);
3840 }
3841 ELEM_REMOVE(&iobj->link);
3842 }
3843 }
3844
3845 if (IS_INSN_ID(iobj, concatstrings)) {
3846 /*
3847 * concatstrings N
3848 * concatstrings M
3849 * =>
3850 * concatstrings N+M-1
3851 */
3852 LINK_ELEMENT *next = iobj->link.next;
3853 INSN *jump = 0;
3854 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3855 next = get_destination_insn(jump = (INSN *)next);
3856 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3857 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3858 OPERAND_AT(iobj, 0) = INT2FIX(n);
3859 if (jump) {
3860 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3861 if (!--label->refcnt) {
3862 ELEM_REMOVE(&label->link);
3863 }
3864 else {
3865 label = NEW_LABEL(0);
3866 OPERAND_AT(jump, 0) = (VALUE)label;
3867 }
3868 label->refcnt++;
3869 ELEM_INSERT_NEXT(next, &label->link);
3870 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3871 }
3872 else {
3873 ELEM_REMOVE(next);
3874 }
3875 }
3876 }
3877
3878 if (do_tailcallopt &&
3879 (IS_INSN_ID(iobj, send) ||
3880 IS_INSN_ID(iobj, opt_aref_with) ||
3881 IS_INSN_ID(iobj, opt_aset_with) ||
3882 IS_INSN_ID(iobj, invokesuper))) {
3883 /*
3884 * send ...
3885 * leave
3886 * =>
3887 * send ..., ... | VM_CALL_TAILCALL, ...
3888 * leave # unreachable
3889 */
3890 INSN *piobj = NULL;
3891 if (iobj->link.next) {
3892 LINK_ELEMENT *next = iobj->link.next;
3893 do {
3894 if (!IS_INSN(next)) {
3895 next = next->next;
3896 continue;
3897 }
3898 switch (INSN_OF(next)) {
3899 case BIN(nop):
3900 next = next->next;
3901 break;
3902 case BIN(jump):
3903 /* if cond
3904 * return tailcall
3905 * end
3906 */
3907 next = get_destination_insn((INSN *)next);
3908 break;
3909 case BIN(leave):
3910 piobj = iobj;
3911 /* fall through */
3912 default:
3913 next = NULL;
3914 break;
3915 }
3916 } while (next);
3917 }
3918
3919 if (piobj) {
3920 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3921 if (IS_INSN_ID(piobj, send) ||
3922 IS_INSN_ID(piobj, invokesuper)) {
3923 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3924 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3925 OPERAND_AT(piobj, 0) = (VALUE)ci;
3926 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3927 }
3928 }
3929 else {
3930 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3931 OPERAND_AT(piobj, 0) = (VALUE)ci;
3932 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3933 }
3934 }
3935 }
3936
3937 if (IS_INSN_ID(iobj, dup)) {
3938 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3939 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3940
3941 /*
3942 * dup
3943 * setlocal x, y
3944 * setlocal x, y
3945 * =>
3946 * dup
3947 * setlocal x, y
3948 */
3949 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3950 set2 = set1->next;
3951 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3952 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3953 ELEM_REMOVE(set1);
3954 ELEM_REMOVE(&iobj->link);
3955 }
3956 }
3957
3958 /*
3959 * dup
3960 * setlocal x, y
3961 * dup
3962 * setlocal x, y
3963 * =>
3964 * dup
3965 * setlocal x, y
3966 */
3967 else if (IS_NEXT_INSN_ID(set1, dup) &&
3968 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3969 set2 = set1->next->next;
3970 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3971 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3972 ELEM_REMOVE(set1->next);
3973 ELEM_REMOVE(set2);
3974 }
3975 }
3976 }
3977 }
3978
3979 /*
3980 * getlocal x, y
3981 * dup
3982 * setlocal x, y
3983 * =>
3984 * dup
3985 */
3986 if (IS_INSN_ID(iobj, getlocal)) {
3987 LINK_ELEMENT *niobj = &iobj->link;
3988 if (IS_NEXT_INSN_ID(niobj, dup)) {
3989 niobj = niobj->next;
3990 }
3991 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3992 LINK_ELEMENT *set1 = niobj->next;
3993 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3994 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3995 ELEM_REMOVE(set1);
3996 ELEM_REMOVE(niobj);
3997 }
3998 }
3999 }
4000
4001 /*
4002 * opt_invokebuiltin_delegate
4003 * trace
4004 * leave
4005 * =>
4006 * opt_invokebuiltin_delegate_leave
4007 * trace
4008 * leave
4009 */
4010 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4011 if (IS_TRACE(iobj->link.next)) {
4012 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4013 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4014 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4015 if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4016 iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4017 }
4018 }
4019 }
4020 }
4021
4022 /*
4023 * getblockparam
4024 * branchif / branchunless
4025 * =>
4026 * getblockparamproxy
4027 * branchif / branchunless
4028 */
4029 if (IS_INSN_ID(iobj, getblockparam)) {
4030 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4031 iobj->insn_id = BIN(getblockparamproxy);
4032 }
4033 }
4034
4035 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4036 LINK_ELEMENT *niobj = &iobj->link;
4037 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4038 niobj = niobj->next;
4039 LINK_ELEMENT *siobj;
4040 unsigned int set_flags = 0, unset_flags = 0;
4041
4042 /*
4043 * Eliminate hash allocation for f(*a, kw: 1)
4044 *
4045 * splatarray false
4046 * duphash
4047 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4048 * =>
4049 * splatarray false
4050 * putobject
4051 * send ARGS_SPLAT|KW_SPLAT
4052 */
4053 if (IS_NEXT_INSN_ID(niobj, send)) {
4054 siobj = niobj->next;
4055 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4056 unset_flags = VM_CALL_ARGS_BLOCKARG;
4057 }
4058 /*
4059 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4060 *
4061 * splatarray false
4062 * duphash
4063 * getlocal / getinstancevariable / getblockparamproxy
4064 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4065 * =>
4066 * splatarray false
4067 * putobject
4068 * getlocal / getinstancevariable / getblockparamproxy
4069 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4070 */
4071 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4072 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4073 siobj = niobj->next->next;
4074 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4075 }
4076
4077 if (set_flags) {
4078 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4079 unsigned int flags = vm_ci_flag(ci);
4080 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4081 ((INSN*)niobj)->insn_id = BIN(putobject);
4082 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4083
4084 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4085 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4086 RB_OBJ_WRITTEN(iseq, ci, nci);
4087 OPERAND_AT(siobj, 0) = (VALUE)nci;
4088 }
4089 }
4090 }
4091 }
4092
4093 return COMPILE_OK;
4094}
4095
4096static int
4097insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4098{
4099 iobj->insn_id = insn_id;
4100 iobj->operand_size = insn_len(insn_id) - 1;
4101 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4102
4103 if (insn_id == BIN(opt_neq)) {
4104 VALUE original_ci = iobj->operands[0];
4105 iobj->operand_size = 2;
4106 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4107 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4108 iobj->operands[1] = original_ci;
4109 }
4110
4111 return COMPILE_OK;
4112}
4113
4114static int
4115iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4116{
4117 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4118 IS_INSN(iobj->link.next)) {
4119 /*
4120 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4121 */
4122 INSN *niobj = (INSN *)iobj->link.next;
4123 if (IS_INSN_ID(niobj, send)) {
4124 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4125 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4126 VALUE method = INT2FIX(0);
4127 switch (vm_ci_mid(ci)) {
4128 case idMax:
4129 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4130 break;
4131 case idMin:
4132 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4133 break;
4134 case idHash:
4135 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4136 break;
4137 }
4138
4139 if (method != INT2FIX(0)) {
4140 VALUE num = iobj->operands[0];
4141 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4142 iobj->insn_id = BIN(opt_newarray_send);
4143 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4144 iobj->operands[0] = num;
4145 iobj->operands[1] = method;
4146 iobj->operand_size = operand_len;
4147 ELEM_REMOVE(&niobj->link);
4148 return COMPILE_OK;
4149 }
4150 }
4151 }
4152 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4153 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4154 IS_NEXT_INSN_ID(&niobj->link, send)) {
4155 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4156 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4157 VALUE num = iobj->operands[0];
4158 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4159 iobj->insn_id = BIN(opt_newarray_send);
4160 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4161 iobj->operands[0] = FIXNUM_INC(num, 1);
4162 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4163 iobj->operand_size = operand_len;
4164 ELEM_REMOVE(&iobj->link);
4165 ELEM_REMOVE(niobj->link.next);
4166 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4167 return COMPILE_OK;
4168 }
4169 }
4170 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4171 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4172 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4173 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4174 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4175 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4176 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4177 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4178 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4179 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4180 VALUE num = iobj->operands[0];
4181 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4182 iobj->insn_id = BIN(opt_newarray_send);
4183 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4184 iobj->operands[0] = FIXNUM_INC(num, 2);
4185 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4186 iobj->operand_size = operand_len;
4187 // Remove the "send" insn.
4188 ELEM_REMOVE((niobj->link.next)->next);
4189 // Remove the modified insn from its original "newarray" position...
4190 ELEM_REMOVE(&iobj->link);
4191 // and insert it after the buffer insn.
4192 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4193 return COMPILE_OK;
4194 }
4195 }
4196
4197 // Break the "else if" chain since some prior checks abort after sub-ifs.
4198 // We already found "newarray". To match `[...].include?(arg)` we look for
4199 // the instruction(s) representing the argument followed by a "send".
4200 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4201 IS_INSN_ID(niobj, putobject) ||
4202 IS_INSN_ID(niobj, putself) ||
4203 IS_INSN_ID(niobj, getlocal) ||
4204 IS_INSN_ID(niobj, getinstancevariable)) &&
4205 IS_NEXT_INSN_ID(&niobj->link, send)) {
4206
4207 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4208 const struct rb_callinfo *ci;
4209 // Allow any number (0 or more) of simple method calls on the argument
4210 // (as in `[...].include?(arg.method1.method2)`.
4211 do {
4212 sendobj = sendobj->next;
4213 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4214 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4215
4216 // If this send is for .include? with one arg we can do our opt.
4217 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4218 VALUE num = iobj->operands[0];
4219 INSN *sendins = (INSN *)sendobj;
4220 sendins->insn_id = BIN(opt_newarray_send);
4221 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4222 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4223 sendins->operands[0] = FIXNUM_INC(num, 1);
4224 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4225 // Remove the original "newarray" insn.
4226 ELEM_REMOVE(&iobj->link);
4227 return COMPILE_OK;
4228 }
4229 }
4230 }
4231
4232 /*
4233 * duparray [...]
4234 * some insn for the arg...
4235 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4236 * =>
4237 * arg insn...
4238 * opt_duparray_send [...], :include?, 1
4239 */
4240 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4241 INSN *niobj = (INSN *)iobj->link.next;
4242 if ((IS_INSN_ID(niobj, getlocal) ||
4243 IS_INSN_ID(niobj, getinstancevariable) ||
4244 IS_INSN_ID(niobj, putself)) &&
4245 IS_NEXT_INSN_ID(&niobj->link, send)) {
4246
4247 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4248 const struct rb_callinfo *ci;
4249 // Allow any number (0 or more) of simple method calls on the argument
4250 // (as in `[...].include?(arg.method1.method2)`.
4251 do {
4252 sendobj = sendobj->next;
4253 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4254 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4255
4256 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4257 // Move the array arg from duparray to opt_duparray_send.
4258 VALUE ary = iobj->operands[0];
4259 rb_obj_reveal(ary, rb_cArray);
4260
4261 INSN *sendins = (INSN *)sendobj;
4262 sendins->insn_id = BIN(opt_duparray_send);
4263 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4264 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4265 sendins->operands[0] = ary;
4266 sendins->operands[1] = rb_id2sym(idIncludeP);
4267 sendins->operands[2] = INT2FIX(1);
4268
4269 // Remove the duparray insn.
4270 ELEM_REMOVE(&iobj->link);
4271 return COMPILE_OK;
4272 }
4273 }
4274 }
4275
4276
4277 if (IS_INSN_ID(iobj, send)) {
4278 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4279 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4280
4281#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4282 if (vm_ci_simple(ci)) {
4283 switch (vm_ci_argc(ci)) {
4284 case 0:
4285 switch (vm_ci_mid(ci)) {
4286 case idLength: SP_INSN(length); return COMPILE_OK;
4287 case idSize: SP_INSN(size); return COMPILE_OK;
4288 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4289 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4290 case idSucc: SP_INSN(succ); return COMPILE_OK;
4291 case idNot: SP_INSN(not); return COMPILE_OK;
4292 }
4293 break;
4294 case 1:
4295 switch (vm_ci_mid(ci)) {
4296 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4297 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4298 case idMULT: SP_INSN(mult); return COMPILE_OK;
4299 case idDIV: SP_INSN(div); return COMPILE_OK;
4300 case idMOD: SP_INSN(mod); return COMPILE_OK;
4301 case idEq: SP_INSN(eq); return COMPILE_OK;
4302 case idNeq: SP_INSN(neq); return COMPILE_OK;
4303 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4304 case idLT: SP_INSN(lt); return COMPILE_OK;
4305 case idLE: SP_INSN(le); return COMPILE_OK;
4306 case idGT: SP_INSN(gt); return COMPILE_OK;
4307 case idGE: SP_INSN(ge); return COMPILE_OK;
4308 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4309 case idAREF: SP_INSN(aref); return COMPILE_OK;
4310 case idAnd: SP_INSN(and); return COMPILE_OK;
4311 case idOr: SP_INSN(or); return COMPILE_OK;
4312 }
4313 break;
4314 case 2:
4315 switch (vm_ci_mid(ci)) {
4316 case idASET: SP_INSN(aset); return COMPILE_OK;
4317 }
4318 break;
4319 }
4320 }
4321
4322 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4323 iobj->insn_id = BIN(opt_send_without_block);
4324 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4325 }
4326 }
4327#undef SP_INSN
4328
4329 return COMPILE_OK;
4330}
4331
4332static inline int
4333tailcallable_p(rb_iseq_t *iseq)
4334{
4335 switch (ISEQ_BODY(iseq)->type) {
4336 case ISEQ_TYPE_TOP:
4337 case ISEQ_TYPE_EVAL:
4338 case ISEQ_TYPE_MAIN:
4339 /* not tail callable because cfp will be over popped */
4340 case ISEQ_TYPE_RESCUE:
4341 case ISEQ_TYPE_ENSURE:
4342 /* rescue block can't tail call because of errinfo */
4343 return FALSE;
4344 default:
4345 return TRUE;
4346 }
4347}
4348
4349static int
4350iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4351{
4352 LINK_ELEMENT *list;
4353 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4354 const int do_tailcallopt = tailcallable_p(iseq) &&
4355 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4356 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4357 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4358 int rescue_level = 0;
4359 int tailcallopt = do_tailcallopt;
4360
4361 list = FIRST_ELEMENT(anchor);
4362
4363 int do_block_optimization = 0;
4364
4365 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4366 do_block_optimization = 1;
4367 }
4368
4369 while (list) {
4370 if (IS_INSN(list)) {
4371 if (do_peepholeopt) {
4372 iseq_peephole_optimize(iseq, list, tailcallopt);
4373 }
4374 if (do_si) {
4375 iseq_specialized_instruction(iseq, (INSN *)list);
4376 }
4377 if (do_ou) {
4378 insn_operands_unification((INSN *)list);
4379 }
4380
4381 if (do_block_optimization) {
4382 INSN * item = (INSN *)list;
4383 if (IS_INSN_ID(item, jump)) {
4384 do_block_optimization = 0;
4385 }
4386 }
4387 }
4388 if (IS_LABEL(list)) {
4389 switch (((LABEL *)list)->rescued) {
4390 case LABEL_RESCUE_BEG:
4391 rescue_level++;
4392 tailcallopt = FALSE;
4393 break;
4394 case LABEL_RESCUE_END:
4395 if (!--rescue_level) tailcallopt = do_tailcallopt;
4396 break;
4397 }
4398 }
4399 list = list->next;
4400 }
4401
4402 if (do_block_optimization) {
4403 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4404 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4405 ELEM_REMOVE(le);
4406 }
4407 }
4408 return COMPILE_OK;
4409}
4410
4411#if OPT_INSTRUCTIONS_UNIFICATION
4412static INSN *
4413new_unified_insn(rb_iseq_t *iseq,
4414 int insn_id, int size, LINK_ELEMENT *seq_list)
4415{
4416 INSN *iobj = 0;
4417 LINK_ELEMENT *list = seq_list;
4418 int i, argc = 0;
4419 VALUE *operands = 0, *ptr = 0;
4420
4421
4422 /* count argc */
4423 for (i = 0; i < size; i++) {
4424 iobj = (INSN *)list;
4425 argc += iobj->operand_size;
4426 list = list->next;
4427 }
4428
4429 if (argc > 0) {
4430 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4431 }
4432
4433 /* copy operands */
4434 list = seq_list;
4435 for (i = 0; i < size; i++) {
4436 iobj = (INSN *)list;
4437 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4438 ptr += iobj->operand_size;
4439 list = list->next;
4440 }
4441
4442 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4443}
4444#endif
4445
4446/*
4447 * This scheme can get more performance if do this optimize with
4448 * label address resolving.
4449 * It's future work (if compile time was bottle neck).
4450 */
4451static int
4452iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4453{
4454#if OPT_INSTRUCTIONS_UNIFICATION
4455 LINK_ELEMENT *list;
4456 INSN *iobj, *niobj;
4457 int id, k;
4458 intptr_t j;
4459
4460 list = FIRST_ELEMENT(anchor);
4461 while (list) {
4462 if (IS_INSN(list)) {
4463 iobj = (INSN *)list;
4464 id = iobj->insn_id;
4465 if (unified_insns_data[id] != 0) {
4466 const int *const *entry = unified_insns_data[id];
4467 for (j = 1; j < (intptr_t)entry[0]; j++) {
4468 const int *unified = entry[j];
4469 LINK_ELEMENT *li = list->next;
4470 for (k = 2; k < unified[1]; k++) {
4471 if (!IS_INSN(li) ||
4472 ((INSN *)li)->insn_id != unified[k]) {
4473 goto miss;
4474 }
4475 li = li->next;
4476 }
4477 /* matched */
4478 niobj =
4479 new_unified_insn(iseq, unified[0], unified[1] - 1,
4480 list);
4481
4482 /* insert to list */
4483 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4484 niobj->link.next = li;
4485 if (li) {
4486 li->prev = (LINK_ELEMENT *)niobj;
4487 }
4488
4489 list->prev->next = (LINK_ELEMENT *)niobj;
4490 list = (LINK_ELEMENT *)niobj;
4491 break;
4492 miss:;
4493 }
4494 }
4495 }
4496 list = list->next;
4497 }
4498#endif
4499 return COMPILE_OK;
4500}
4501
4502static int
4503all_string_result_p(const NODE *node)
4504{
4505 if (!node) return FALSE;
4506 switch (nd_type(node)) {
4507 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4508 return TRUE;
4509 case NODE_IF: case NODE_UNLESS:
4510 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4511 if (all_string_result_p(RNODE_IF(node)->nd_body))
4512 return all_string_result_p(RNODE_IF(node)->nd_else);
4513 return FALSE;
4514 case NODE_AND: case NODE_OR:
4515 if (!RNODE_AND(node)->nd_2nd)
4516 return all_string_result_p(RNODE_AND(node)->nd_1st);
4517 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4518 return FALSE;
4519 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4520 default:
4521 return FALSE;
4522 }
4523}
4524
4525static int
4526compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4527{
4528 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4529 VALUE lit = rb_node_dstr_string_val(node);
4530 LINK_ELEMENT *first_lit = 0;
4531 int cnt = 0;
4532
4533 debugp_param("nd_lit", lit);
4534 if (!NIL_P(lit)) {
4535 cnt++;
4536 if (!RB_TYPE_P(lit, T_STRING)) {
4537 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4538 rb_builtin_type_name(TYPE(lit)));
4539 return COMPILE_NG;
4540 }
4541 lit = rb_fstring(lit);
4542 ADD_INSN1(ret, node, putobject, lit);
4543 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4544 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4545 }
4546
4547 while (list) {
4548 const NODE *const head = list->nd_head;
4549 if (nd_type_p(head, NODE_STR)) {
4550 lit = rb_node_str_string_val(head);
4551 ADD_INSN1(ret, head, putobject, lit);
4552 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4553 lit = Qnil;
4554 }
4555 else {
4556 CHECK(COMPILE(ret, "each string", head));
4557 }
4558 cnt++;
4559 list = (struct RNode_LIST *)list->nd_next;
4560 }
4561 if (NIL_P(lit) && first_lit) {
4562 ELEM_REMOVE(first_lit);
4563 --cnt;
4564 }
4565 *cntp = cnt;
4566
4567 return COMPILE_OK;
4568}
4569
4570static int
4571compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4572{
4573 while (node && nd_type_p(node, NODE_BLOCK)) {
4574 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4575 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4576 node = RNODE_BLOCK(node)->nd_next;
4577 }
4578 if (node) {
4579 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4580 }
4581 return COMPILE_OK;
4582}
4583
4584static int
4585compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4586{
4587 int cnt;
4588 if (!RNODE_DSTR(node)->nd_next) {
4589 VALUE lit = rb_node_dstr_string_val(node);
4590 ADD_INSN1(ret, node, putstring, lit);
4591 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4592 }
4593 else {
4594 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4595 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4596 }
4597 return COMPILE_OK;
4598}
4599
4600static int
4601compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4602{
4603 int cnt;
4604 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4605
4606 if (!RNODE_DREGX(node)->nd_next) {
4607 if (!popped) {
4608 VALUE src = rb_node_dregx_string_val(node);
4609 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4610 ADD_INSN1(ret, node, putobject, match);
4611 RB_OBJ_WRITTEN(iseq, Qundef, match);
4612 }
4613 return COMPILE_OK;
4614 }
4615
4616 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4617 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4618
4619 if (popped) {
4620 ADD_INSN(ret, node, pop);
4621 }
4622
4623 return COMPILE_OK;
4624}
4625
4626static int
4627compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4628 LABEL *then_label, LABEL *else_label)
4629{
4630 const int line = nd_line(node);
4631 LABEL *lend = NEW_LABEL(line);
4632 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4633 + VM_SVAR_FLIPFLOP_START;
4634 VALUE key = INT2FIX(cnt);
4635
4636 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4637 ADD_INSNL(ret, node, branchif, lend);
4638
4639 /* *flip == 0 */
4640 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4641 ADD_INSNL(ret, node, branchunless, else_label);
4642 ADD_INSN1(ret, node, putobject, Qtrue);
4643 ADD_INSN1(ret, node, setspecial, key);
4644 if (!again) {
4645 ADD_INSNL(ret, node, jump, then_label);
4646 }
4647
4648 /* *flip == 1 */
4649 ADD_LABEL(ret, lend);
4650 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4651 ADD_INSNL(ret, node, branchunless, then_label);
4652 ADD_INSN1(ret, node, putobject, Qfalse);
4653 ADD_INSN1(ret, node, setspecial, key);
4654 ADD_INSNL(ret, node, jump, then_label);
4655
4656 return COMPILE_OK;
4657}
4658
4659static int
4660compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4661 LABEL *then_label, LABEL *else_label);
4662
4663#define COMPILE_SINGLE 2
4664static int
4665compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4666 LABEL *then_label, LABEL *else_label)
4667{
4668 DECL_ANCHOR(seq);
4669 INIT_ANCHOR(seq);
4670 LABEL *label = NEW_LABEL(nd_line(cond));
4671 if (!then_label) then_label = label;
4672 else if (!else_label) else_label = label;
4673
4674 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4675
4676 if (LIST_INSN_SIZE_ONE(seq)) {
4677 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4678 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4679 return COMPILE_OK;
4680 }
4681 if (!label->refcnt) {
4682 return COMPILE_SINGLE;
4683 }
4684 ADD_LABEL(seq, label);
4685 ADD_SEQ(ret, seq);
4686 return COMPILE_OK;
4687}
4688
4689static int
4690compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4691 LABEL *then_label, LABEL *else_label)
4692{
4693 int ok;
4694 DECL_ANCHOR(ignore);
4695
4696 again:
4697 switch (nd_type(cond)) {
4698 case NODE_AND:
4699 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4700 cond = RNODE_AND(cond)->nd_2nd;
4701 if (ok == COMPILE_SINGLE) {
4702 INIT_ANCHOR(ignore);
4703 ret = ignore;
4704 then_label = NEW_LABEL(nd_line(cond));
4705 }
4706 goto again;
4707 case NODE_OR:
4708 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4709 cond = RNODE_OR(cond)->nd_2nd;
4710 if (ok == COMPILE_SINGLE) {
4711 INIT_ANCHOR(ignore);
4712 ret = ignore;
4713 else_label = NEW_LABEL(nd_line(cond));
4714 }
4715 goto again;
4716 case NODE_SYM:
4717 case NODE_LINE:
4718 case NODE_FILE:
4719 case NODE_ENCODING:
4720 case NODE_INTEGER: /* NODE_INTEGER is always true */
4721 case NODE_FLOAT: /* NODE_FLOAT is always true */
4722 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4723 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4724 case NODE_TRUE:
4725 case NODE_STR:
4726 case NODE_REGX:
4727 case NODE_ZLIST:
4728 case NODE_LAMBDA:
4729 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4730 ADD_INSNL(ret, cond, jump, then_label);
4731 return COMPILE_OK;
4732 case NODE_FALSE:
4733 case NODE_NIL:
4734 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4735 ADD_INSNL(ret, cond, jump, else_label);
4736 return COMPILE_OK;
4737 case NODE_LIST:
4738 case NODE_ARGSCAT:
4739 case NODE_DREGX:
4740 case NODE_DSTR:
4741 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4742 ADD_INSNL(ret, cond, jump, then_label);
4743 return COMPILE_OK;
4744 case NODE_FLIP2:
4745 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4746 return COMPILE_OK;
4747 case NODE_FLIP3:
4748 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4749 return COMPILE_OK;
4750 case NODE_DEFINED:
4751 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4752 break;
4753 default:
4754 {
4755 DECL_ANCHOR(cond_seq);
4756 INIT_ANCHOR(cond_seq);
4757
4758 CHECK(COMPILE(cond_seq, "branch condition", cond));
4759
4760 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4761 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4762 if (insn->insn_id == BIN(putobject)) {
4763 if (RTEST(insn->operands[0])) {
4764 ADD_INSNL(ret, cond, jump, then_label);
4765 // maybe unreachable
4766 return COMPILE_OK;
4767 }
4768 else {
4769 ADD_INSNL(ret, cond, jump, else_label);
4770 return COMPILE_OK;
4771 }
4772 }
4773 }
4774 ADD_SEQ(ret, cond_seq);
4775 }
4776 break;
4777 }
4778
4779 ADD_INSNL(ret, cond, branchunless, else_label);
4780 ADD_INSNL(ret, cond, jump, then_label);
4781 return COMPILE_OK;
4782}
4783
4784#define HASH_BRACE 1
4785
4786static int
4787keyword_node_p(const NODE *const node)
4788{
4789 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4790}
4791
4792static VALUE
4793get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4794{
4795 switch (nd_type(node)) {
4796 case NODE_SYM:
4797 return rb_node_sym_string_val(node);
4798 default:
4799 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4800 }
4801}
4802
4803static VALUE
4804node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4805{
4806 NODE *node = node_hash->nd_head;
4807 VALUE hash = rb_hash_new();
4808 VALUE ary = rb_ary_new();
4809
4810 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4811 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4812 VALUE idx = rb_hash_aref(hash, key);
4813 if (!NIL_P(idx)) {
4814 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4815 (*count_ptr)--;
4816 }
4817 rb_hash_aset(hash, key, INT2FIX(i));
4818 rb_ary_store(ary, i, Qtrue);
4819 (*count_ptr)++;
4820 }
4821
4822 return ary;
4823}
4824
4825static int
4826compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4827 const NODE *const root_node,
4828 struct rb_callinfo_kwarg **const kw_arg_ptr,
4829 unsigned int *flag)
4830{
4831 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4832 RUBY_ASSERT(kw_arg_ptr != NULL);
4833 RUBY_ASSERT(flag != NULL);
4834
4835 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4836 const NODE *node = RNODE_HASH(root_node)->nd_head;
4837 int seen_nodes = 0;
4838
4839 while (node) {
4840 const NODE *key_node = RNODE_LIST(node)->nd_head;
4841 seen_nodes++;
4842
4843 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4844 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4845 /* can be keywords */
4846 }
4847 else {
4848 if (flag) {
4849 *flag |= VM_CALL_KW_SPLAT;
4850 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4851 /* A new hash will be created for the keyword arguments
4852 * in this case, so mark the method as passing mutable
4853 * keyword splat.
4854 */
4855 *flag |= VM_CALL_KW_SPLAT_MUT;
4856 }
4857 }
4858 return FALSE;
4859 }
4860 node = RNODE_LIST(node)->nd_next; /* skip value node */
4861 node = RNODE_LIST(node)->nd_next;
4862 }
4863
4864 /* may be keywords */
4865 node = RNODE_HASH(root_node)->nd_head;
4866 {
4867 int len = 0;
4868 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4869 struct rb_callinfo_kwarg *kw_arg =
4870 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4871 VALUE *keywords = kw_arg->keywords;
4872 int i = 0;
4873 int j = 0;
4874 kw_arg->references = 0;
4875 kw_arg->keyword_len = len;
4876
4877 *kw_arg_ptr = kw_arg;
4878
4879 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4880 const NODE *key_node = RNODE_LIST(node)->nd_head;
4881 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4882 int popped = TRUE;
4883 if (rb_ary_entry(key_index, i)) {
4884 keywords[j] = get_symbol_value(iseq, key_node);
4885 j++;
4886 popped = FALSE;
4887 }
4888 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4889 }
4890 RUBY_ASSERT(j == len);
4891 return TRUE;
4892 }
4893 }
4894 return FALSE;
4895}
4896
4897static int
4898compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4899{
4900 int len = 0;
4901
4902 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4903 if (CPDEBUG > 0) {
4904 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4905 }
4906
4907 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4908 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4909 }
4910 else {
4911 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4912 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4913 }
4914 }
4915
4916 return len;
4917}
4918
4919static inline bool
4920frozen_string_literal_p(const rb_iseq_t *iseq)
4921{
4922 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4923}
4924
4925static inline bool
4926static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
4927{
4928 switch (nd_type(node)) {
4929 case NODE_SYM:
4930 case NODE_REGX:
4931 case NODE_LINE:
4932 case NODE_ENCODING:
4933 case NODE_INTEGER:
4934 case NODE_FLOAT:
4935 case NODE_RATIONAL:
4936 case NODE_IMAGINARY:
4937 case NODE_NIL:
4938 case NODE_TRUE:
4939 case NODE_FALSE:
4940 return TRUE;
4941 case NODE_STR:
4942 case NODE_FILE:
4943 return hash_key || frozen_string_literal_p(iseq);
4944 default:
4945 return FALSE;
4946 }
4947}
4948
4949static inline VALUE
4950static_literal_value(const NODE *node, rb_iseq_t *iseq)
4951{
4952 switch (nd_type(node)) {
4953 case NODE_INTEGER:
4954 return rb_node_integer_literal_val(node);
4955 case NODE_FLOAT:
4956 return rb_node_float_literal_val(node);
4957 case NODE_RATIONAL:
4958 return rb_node_rational_literal_val(node);
4959 case NODE_IMAGINARY:
4960 return rb_node_imaginary_literal_val(node);
4961 case NODE_NIL:
4962 return Qnil;
4963 case NODE_TRUE:
4964 return Qtrue;
4965 case NODE_FALSE:
4966 return Qfalse;
4967 case NODE_SYM:
4968 return rb_node_sym_string_val(node);
4969 case NODE_REGX:
4970 return rb_node_regx_string_val(node);
4971 case NODE_LINE:
4972 return rb_node_line_lineno_val(node);
4973 case NODE_ENCODING:
4974 return rb_node_encoding_val(node);
4975 case NODE_FILE:
4976 case NODE_STR:
4977 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4978 VALUE lit = get_string_value(node);
4979 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
4980 }
4981 else {
4982 return get_string_value(node);
4983 }
4984 default:
4985 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
4986 }
4987}
4988
4989static int
4990compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
4991{
4992 const NODE *line_node = node;
4993
4994 if (nd_type_p(node, NODE_ZLIST)) {
4995 if (!popped) {
4996 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4997 }
4998 return 0;
4999 }
5000
5001 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5002
5003 if (popped) {
5004 for (; node; node = RNODE_LIST(node)->nd_next) {
5005 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5006 }
5007 return 1;
5008 }
5009
5010 /* Compilation of an array literal.
5011 * The following code is essentially the same as:
5012 *
5013 * for (int count = 0; node; count++; node->nd_next) {
5014 * compile(node->nd_head);
5015 * }
5016 * ADD_INSN(newarray, count);
5017 *
5018 * However, there are three points.
5019 *
5020 * - The code above causes stack overflow for a big string literal.
5021 * The following limits the stack length up to max_stack_len.
5022 *
5023 * [x1,x2,...,x10000] =>
5024 * push x1 ; push x2 ; ...; push x256; newarray 256;
5025 * push x257; push x258; ...; push x512; pushtoarray 256;
5026 * push x513; push x514; ...; push x768; pushtoarray 256;
5027 * ...
5028 *
5029 * - Long subarray can be optimized by pre-allocating a hidden array.
5030 *
5031 * [1,2,3,...,100] =>
5032 * duparray [1,2,3,...,100]
5033 *
5034 * [x, 1,2,3,...,100, z] =>
5035 * push x; newarray 1;
5036 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5037 * push z; pushtoarray 1;
5038 *
5039 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5040 * to only push it onto the array if it is not empty
5041 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5042 *
5043 * [1,2,3,**kw] =>
5044 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5045 */
5046
5047 const int max_stack_len = 0x100;
5048 const int min_tmp_ary_len = 0x40;
5049 int stack_len = 0;
5050
5051 /* Either create a new array, or push to the existing array */
5052#define FLUSH_CHUNK \
5053 if (stack_len) { \
5054 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5055 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5056 first_chunk = FALSE; \
5057 stack_len = 0; \
5058 }
5059
5060 while (node) {
5061 int count = 1;
5062
5063 /* pre-allocation check (this branch can be omittable) */
5064 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5065 /* count the elements that are optimizable */
5066 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5067 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5068 count++;
5069
5070 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5071 /* The literal contains only optimizable elements, or the subarray is long enough */
5072 VALUE ary = rb_ary_hidden_new(count);
5073
5074 /* Create a hidden array */
5075 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5076 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5077 OBJ_FREEZE(ary);
5078
5079 /* Emit optimized code */
5080 FLUSH_CHUNK;
5081 if (first_chunk) {
5082 ADD_INSN1(ret, line_node, duparray, ary);
5083 first_chunk = FALSE;
5084 }
5085 else {
5086 ADD_INSN1(ret, line_node, putobject, ary);
5087 ADD_INSN(ret, line_node, concattoarray);
5088 }
5089 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5090 }
5091 }
5092
5093 /* Base case: Compile "count" elements */
5094 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5095 if (CPDEBUG > 0) {
5096 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5097 }
5098
5099 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5100 /* Create array or push existing non-keyword elements onto array */
5101 if (stack_len == 0 && first_chunk) {
5102 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5103 }
5104 else {
5105 FLUSH_CHUNK;
5106 }
5107 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5108 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5109 return 1;
5110 }
5111 else {
5112 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5113 stack_len++;
5114 }
5115
5116 /* If there are many pushed elements, flush them to avoid stack overflow */
5117 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5118 }
5119 }
5120
5121 FLUSH_CHUNK;
5122#undef FLUSH_CHUNK
5123 return 1;
5124}
5125
5126static inline int
5127static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5128{
5129 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);
5130}
5131
5132static int
5133compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5134{
5135 const NODE *line_node = node;
5136
5137 node = RNODE_HASH(node)->nd_head;
5138
5139 if (!node || nd_type_p(node, NODE_ZLIST)) {
5140 if (!popped) {
5141 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5142 }
5143 return 0;
5144 }
5145
5146 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5147
5148 if (popped) {
5149 for (; node; node = RNODE_LIST(node)->nd_next) {
5150 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5151 }
5152 return 1;
5153 }
5154
5155 /* Compilation of a hash literal (or keyword arguments).
5156 * This is very similar to compile_array, but there are some differences:
5157 *
5158 * - It contains key-value pairs. So we need to take every two elements.
5159 * We can assume that the length is always even.
5160 *
5161 * - Merging is done by a method call (id_core_hash_merge_ptr).
5162 * Sometimes we need to insert the receiver, so "anchor" is needed.
5163 * In addition, a method call is much slower than concatarray.
5164 * So it pays only when the subsequence is really long.
5165 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5166 *
5167 * - We need to handle keyword splat: **kw.
5168 * For **kw, the key part (node->nd_head) is NULL, and the value part
5169 * (node->nd_next->nd_head) is "kw".
5170 * The code is a bit difficult to avoid hash allocation for **{}.
5171 */
5172
5173 const int max_stack_len = 0x100;
5174 const int min_tmp_hash_len = 0x800;
5175 int stack_len = 0;
5176 int first_chunk = 1;
5177 DECL_ANCHOR(anchor);
5178 INIT_ANCHOR(anchor);
5179
5180 /* Convert pushed elements to a hash, and merge if needed */
5181#define FLUSH_CHUNK() \
5182 if (stack_len) { \
5183 if (first_chunk) { \
5184 APPEND_LIST(ret, anchor); \
5185 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5186 } \
5187 else { \
5188 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5189 ADD_INSN(ret, line_node, swap); \
5190 APPEND_LIST(ret, anchor); \
5191 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5192 } \
5193 INIT_ANCHOR(anchor); \
5194 first_chunk = stack_len = 0; \
5195 }
5196
5197 while (node) {
5198 int count = 1;
5199
5200 /* pre-allocation check (this branch can be omittable) */
5201 if (static_literal_node_pair_p(node, iseq)) {
5202 /* count the elements that are optimizable */
5203 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5204 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5205 count++;
5206
5207 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5208 /* The literal contains only optimizable elements, or the subsequence is long enough */
5209 VALUE ary = rb_ary_hidden_new(count);
5210
5211 /* Create a hidden hash */
5212 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5213 VALUE elem[2];
5214 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5215 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5216 rb_ary_cat(ary, elem, 2);
5217 }
5218 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5219 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5220 hash = rb_obj_hide(hash);
5221 OBJ_FREEZE(hash);
5222
5223 /* Emit optimized code */
5224 FLUSH_CHUNK();
5225 if (first_chunk) {
5226 ADD_INSN1(ret, line_node, duphash, hash);
5227 first_chunk = 0;
5228 }
5229 else {
5230 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5231 ADD_INSN(ret, line_node, swap);
5232
5233 ADD_INSN1(ret, line_node, putobject, hash);
5234
5235 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5236 }
5237 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5238 }
5239 }
5240
5241 /* Base case: Compile "count" elements */
5242 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5243
5244 if (CPDEBUG > 0) {
5245 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5246 }
5247
5248 if (RNODE_LIST(node)->nd_head) {
5249 /* Normal key-value pair */
5250 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5251 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5252 stack_len += 2;
5253
5254 /* If there are many pushed elements, flush them to avoid stack overflow */
5255 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5256 }
5257 else {
5258 /* kwsplat case: foo(..., **kw, ...) */
5259 FLUSH_CHUNK();
5260
5261 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5262 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5263 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5264 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5265 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5266
5267 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5268 if (empty_kw) {
5269 if (only_kw && method_call_keywords) {
5270 /* **{} appears at the only keyword argument in method call,
5271 * so it won't be modified.
5272 * kw is a special NODE_LIT that contains a special empty hash,
5273 * so this emits: putobject {}.
5274 * This is only done for method calls and not for literal hashes,
5275 * because literal hashes should always result in a new hash.
5276 */
5277 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5278 }
5279 else if (first_kw) {
5280 /* **{} appears as the first keyword argument, so it may be modified.
5281 * We need to create a fresh hash object.
5282 */
5283 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5284 }
5285 /* Any empty keyword splats that are not the first can be ignored.
5286 * since merging an empty hash into the existing hash is the same
5287 * as not merging it. */
5288 }
5289 else {
5290 if (only_kw && method_call_keywords) {
5291 /* **kw is only keyword argument in method call.
5292 * Use directly. This will be not be flagged as mutable.
5293 * This is only done for method calls and not for literal hashes,
5294 * because literal hashes should always result in a new hash.
5295 */
5296 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5297 }
5298 else {
5299 /* There is more than one keyword argument, or this is not a method
5300 * call. In that case, we need to add an empty hash (if first keyword),
5301 * or merge the hash to the accumulated hash (if not the first keyword).
5302 */
5303 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5304 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5305 else ADD_INSN(ret, line_node, swap);
5306
5307 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5308
5309 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5310 }
5311 }
5312
5313 first_chunk = 0;
5314 }
5315 }
5316 }
5317
5318 FLUSH_CHUNK();
5319#undef FLUSH_CHUNK
5320 return 1;
5321}
5322
5323 VALUE
5324rb_node_case_when_optimizable_literal(const NODE *const node)
5325{
5326 switch (nd_type(node)) {
5327 case NODE_INTEGER:
5328 return rb_node_integer_literal_val(node);
5329 case NODE_FLOAT: {
5330 VALUE v = rb_node_float_literal_val(node);
5331 double ival;
5332
5333 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5334 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5335 }
5336 return v;
5337 }
5338 case NODE_RATIONAL:
5339 case NODE_IMAGINARY:
5340 return Qundef;
5341 case NODE_NIL:
5342 return Qnil;
5343 case NODE_TRUE:
5344 return Qtrue;
5345 case NODE_FALSE:
5346 return Qfalse;
5347 case NODE_SYM:
5348 return rb_node_sym_string_val(node);
5349 case NODE_LINE:
5350 return rb_node_line_lineno_val(node);
5351 case NODE_STR:
5352 return rb_node_str_string_val(node);
5353 case NODE_FILE:
5354 return rb_node_file_path_val(node);
5355 }
5356 return Qundef;
5357}
5358
5359static int
5360when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5361 LABEL *l1, int only_special_literals, VALUE literals)
5362{
5363 while (vals) {
5364 const NODE *val = RNODE_LIST(vals)->nd_head;
5365 VALUE lit = rb_node_case_when_optimizable_literal(val);
5366
5367 if (UNDEF_P(lit)) {
5368 only_special_literals = 0;
5369 }
5370 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5371 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5372 }
5373
5374 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5375 debugp_param("nd_lit", get_string_value(val));
5376 lit = get_string_value(val);
5377 ADD_INSN1(cond_seq, val, putobject, lit);
5378 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5379 }
5380 else {
5381 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5382 }
5383
5384 // Emit pattern === target
5385 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5386 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5387 ADD_INSNL(cond_seq, val, branchif, l1);
5388 vals = RNODE_LIST(vals)->nd_next;
5389 }
5390 return only_special_literals;
5391}
5392
5393static int
5394when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5395 LABEL *l1, int only_special_literals, VALUE literals)
5396{
5397 const NODE *line_node = vals;
5398
5399 switch (nd_type(vals)) {
5400 case NODE_LIST:
5401 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5402 return COMPILE_NG;
5403 break;
5404 case NODE_SPLAT:
5405 ADD_INSN (cond_seq, line_node, dup);
5406 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5407 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5408 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5409 ADD_INSNL(cond_seq, line_node, branchif, l1);
5410 break;
5411 case NODE_ARGSCAT:
5412 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5413 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5414 break;
5415 case NODE_ARGSPUSH:
5416 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5417 ADD_INSN (cond_seq, line_node, dup);
5418 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5419 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5420 ADD_INSNL(cond_seq, line_node, branchif, l1);
5421 break;
5422 default:
5423 ADD_INSN (cond_seq, line_node, dup);
5424 CHECK(COMPILE(cond_seq, "when val", vals));
5425 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5426 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5427 ADD_INSNL(cond_seq, line_node, branchif, l1);
5428 break;
5429 }
5430 return COMPILE_OK;
5431}
5432
5433/* Multiple Assignment Handling
5434 *
5435 * In order to handle evaluation of multiple assignment such that the left hand side
5436 * is evaluated before the right hand side, we need to process the left hand side
5437 * and see if there are any attributes that need to be assigned, or constants set
5438 * on explicit objects. If so, we add instructions to evaluate the receiver of
5439 * any assigned attributes or constants before we process the right hand side.
5440 *
5441 * For a multiple assignment such as:
5442 *
5443 * l1.m1, l2[0] = r3, r4
5444 *
5445 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5446 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5447 * On the VM stack, this looks like:
5448 *
5449 * self # putself
5450 * l1 # send
5451 * l1, self # putself
5452 * l1, l2 # send
5453 * l1, l2, 0 # putobject 0
5454 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5455 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5456 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5457 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5458 * l1, l2, 0, [r3, r4], r4, m1= # send
5459 * l1, l2, 0, [r3, r4], r4 # pop
5460 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5461 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5462 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5463 * l1, l2, 0, [r3, r4], r4, []= # send
5464 * l1, l2, 0, [r3, r4], r4 # pop
5465 * l1, l2, 0, [r3, r4] # pop
5466 * [r3, r4], l2, 0, [r3, r4] # setn 3
5467 * [r3, r4], l2, 0 # pop
5468 * [r3, r4], l2 # pop
5469 * [r3, r4] # pop
5470 *
5471 * This is made more complex when you have to handle splats, post args,
5472 * and arbitrary levels of nesting. You need to keep track of the total
5473 * number of attributes to set, and for each attribute, how many entries
5474 * are on the stack before the final attribute, in order to correctly
5475 * calculate the topn value to use to get the receiver of the attribute
5476 * setter method.
5477 *
5478 * A brief description of the VM stack for simple multiple assignment
5479 * with no splat (rhs_array will not be present if the return value of
5480 * the multiple assignment is not needed):
5481 *
5482 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5483 *
5484 * For multiple assignment with splats, while processing the part before
5485 * the splat (splat+post here is an array of the splat and the post arguments):
5486 *
5487 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5488 *
5489 * When processing the splat and post arguments:
5490 *
5491 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5492 *
5493 * When processing nested multiple assignment, existing values on the stack
5494 * are kept. So for:
5495 *
5496 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5497 *
5498 * The stack layout would be the following before processing the nested
5499 * multiple assignment:
5500 *
5501 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5502 *
5503 * In order to handle this correctly, we need to keep track of the nesting
5504 * level for each attribute assignment, as well as the attribute number
5505 * (left hand side attributes are processed left to right) and number of
5506 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5507 * this information.
5508 *
5509 * We also need to track information for the entire multiple assignment, such
5510 * as the total number of arguments, and the current nesting level, to
5511 * handle both nested multiple assignment as well as cases where the
5512 * rhs is not needed. We also need to keep track of all attribute
5513 * assignments in this, which we do using a linked listed. struct masgn_state
5514 * tracks this information.
5515 */
5516
5517 struct masgn_lhs_node {
5518 INSN *before_insn;
5519 struct masgn_lhs_node *next;
5520 const NODE *line_node;
5521 int argn;
5522 int num_args;
5523 int lhs_pos;
5524};
5525
5526 struct masgn_state {
5527 struct masgn_lhs_node *first_memo;
5528 struct masgn_lhs_node *last_memo;
5529 int lhs_level;
5530 int num_args;
5531 bool nested;
5532};
5533
5534static int
5535add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5536{
5537 if (!state) {
5538 rb_bug("no masgn_state");
5539 }
5540
5541 struct masgn_lhs_node *memo;
5542 memo = malloc(sizeof(struct masgn_lhs_node));
5543 if (!memo) {
5544 return COMPILE_NG;
5545 }
5546
5547 memo->before_insn = before_insn;
5548 memo->line_node = line_node;
5549 memo->argn = state->num_args + 1;
5550 memo->num_args = argc;
5551 state->num_args += argc;
5552 memo->lhs_pos = lhs_pos;
5553 memo->next = NULL;
5554 if (!state->first_memo) {
5555 state->first_memo = memo;
5556 }
5557 else {
5558 state->last_memo->next = memo;
5559 }
5560 state->last_memo = memo;
5561
5562 return COMPILE_OK;
5563}
5564
5565static 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);
5566
5567static int
5568compile_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)
5569{
5570 switch (nd_type(node)) {
5571 case NODE_ATTRASGN: {
5572 INSN *iobj;
5573 const NODE *line_node = node;
5574
5575 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5576
5577 bool safenav_call = false;
5578 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5579 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5580 ASSUME(iobj);
5581 ELEM_REMOVE(insn_element);
5582 if (!IS_INSN_ID(iobj, send)) {
5583 safenav_call = true;
5584 iobj = (INSN *)get_prev_insn(iobj);
5585 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5586 }
5587 (pre->last = iobj->link.prev)->next = 0;
5588
5589 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5590 int argc = vm_ci_argc(ci) + 1;
5591 ci = ci_argc_set(iseq, ci, argc);
5592 OPERAND_AT(iobj, 0) = (VALUE)ci;
5593 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5594
5595 if (argc == 1) {
5596 ADD_INSN(lhs, line_node, swap);
5597 }
5598 else {
5599 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5600 }
5601
5602 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5603 return COMPILE_NG;
5604 }
5605
5606 iobj->link.prev = lhs->last;
5607 lhs->last->next = &iobj->link;
5608 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5609 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5610 int argc = vm_ci_argc(ci);
5611 bool dupsplat = false;
5612 ci = ci_argc_set(iseq, ci, argc - 1);
5613 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5614 /* Given h[*a], _ = ary
5615 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5616 * `a` must be dupped, because it will be appended with ary[0]
5617 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5618 */
5619 dupsplat = true;
5620 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5621 }
5622 OPERAND_AT(iobj, 0) = (VALUE)ci;
5623 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5624
5625 /* Given: h[*a], h[*b, 1] = ary
5626 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5627 * so this uses splatarray true on a to dup it before using pushtoarray
5628 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5629 * so you can use pushtoarray directly
5630 */
5631 int line_no = nd_line(line_node);
5632 int node_id = nd_node_id(line_node);
5633
5634 if (dupsplat) {
5635 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5636 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5637 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5638 }
5639 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5640 }
5641 if (!safenav_call) {
5642 ADD_INSN(lhs, line_node, pop);
5643 if (argc != 1) {
5644 ADD_INSN(lhs, line_node, pop);
5645 }
5646 }
5647 for (int i=0; i < argc; i++) {
5648 ADD_INSN(post, line_node, pop);
5649 }
5650 break;
5651 }
5652 case NODE_MASGN: {
5653 DECL_ANCHOR(nest_rhs);
5654 INIT_ANCHOR(nest_rhs);
5655 DECL_ANCHOR(nest_lhs);
5656 INIT_ANCHOR(nest_lhs);
5657
5658 int prev_level = state->lhs_level;
5659 bool prev_nested = state->nested;
5660 state->nested = 1;
5661 state->lhs_level = lhs_pos - 1;
5662 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5663 state->lhs_level = prev_level;
5664 state->nested = prev_nested;
5665
5666 ADD_SEQ(lhs, nest_rhs);
5667 ADD_SEQ(lhs, nest_lhs);
5668 break;
5669 }
5670 case NODE_CDECL:
5671 if (!RNODE_CDECL(node)->nd_vid) {
5672 /* Special handling only needed for expr::C, not for C */
5673 INSN *iobj;
5674
5675 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5676
5677 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5678 iobj = (INSN *)insn_element; /* setconstant insn */
5679 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5680 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5681 ELEM_REMOVE(insn_element);
5682 pre->last = iobj->link.prev;
5683 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5684
5685 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5686 return COMPILE_NG;
5687 }
5688
5689 ADD_INSN(post, node, pop);
5690 break;
5691 }
5692 /* Fallthrough */
5693 default: {
5694 DECL_ANCHOR(anchor);
5695 INIT_ANCHOR(anchor);
5696 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5697 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5698 ADD_SEQ(lhs, anchor);
5699 }
5700 }
5701
5702 return COMPILE_OK;
5703}
5704
5705static int
5706compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5707{
5708 if (lhsn) {
5709 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5710 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5711 }
5712 return COMPILE_OK;
5713}
5714
5715static int
5716compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5717 const NODE *rhsn, const NODE *orig_lhsn)
5718{
5719 VALUE mem[64];
5720 const int memsize = numberof(mem);
5721 int memindex = 0;
5722 int llen = 0, rlen = 0;
5723 int i;
5724 const NODE *lhsn = orig_lhsn;
5725
5726#define MEMORY(v) { \
5727 int i; \
5728 if (memindex == memsize) return 0; \
5729 for (i=0; i<memindex; i++) { \
5730 if (mem[i] == (v)) return 0; \
5731 } \
5732 mem[memindex++] = (v); \
5733}
5734
5735 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5736 return 0;
5737 }
5738
5739 while (lhsn) {
5740 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5741 switch (nd_type(ln)) {
5742 case NODE_LASGN:
5743 case NODE_DASGN:
5744 case NODE_IASGN:
5745 case NODE_CVASGN:
5746 MEMORY(get_nd_vid(ln));
5747 break;
5748 default:
5749 return 0;
5750 }
5751 lhsn = RNODE_LIST(lhsn)->nd_next;
5752 llen++;
5753 }
5754
5755 while (rhsn) {
5756 if (llen <= rlen) {
5757 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5758 }
5759 else {
5760 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5761 }
5762 rhsn = RNODE_LIST(rhsn)->nd_next;
5763 rlen++;
5764 }
5765
5766 if (llen > rlen) {
5767 for (i=0; i<llen-rlen; i++) {
5768 ADD_INSN(ret, orig_lhsn, putnil);
5769 }
5770 }
5771
5772 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5773 return 1;
5774}
5775
5776static int
5777compile_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)
5778{
5779 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5780 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5781 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5782 const NODE *lhsn_count = lhsn;
5783 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5784
5785 int llen = 0;
5786 int lpos = 0;
5787
5788 while (lhsn_count) {
5789 llen++;
5790 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5791 }
5792 while (lhsn) {
5793 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5794 lpos++;
5795 lhsn = RNODE_LIST(lhsn)->nd_next;
5796 }
5797
5798 if (lhs_splat) {
5799 if (nd_type_p(splatn, NODE_POSTARG)) {
5800 /*a, b, *r, p1, p2 */
5801 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5802 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5803 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5804 int ppos = 0;
5805 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5806
5807 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5808
5809 if (NODE_NAMED_REST_P(restn)) {
5810 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5811 }
5812 while (postn) {
5813 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5814 ppos++;
5815 postn = RNODE_LIST(postn)->nd_next;
5816 }
5817 }
5818 else {
5819 /* a, b, *r */
5820 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5821 }
5822 }
5823
5824 if (!state->nested) {
5825 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5826 }
5827
5828 if (!popped) {
5829 ADD_INSN(rhs, node, dup);
5830 }
5831 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5832 return COMPILE_OK;
5833}
5834
5835static int
5836compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5837{
5838 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5839 struct masgn_state state;
5840 state.lhs_level = popped ? 0 : 1;
5841 state.nested = 0;
5842 state.num_args = 0;
5843 state.first_memo = NULL;
5844 state.last_memo = NULL;
5845
5846 DECL_ANCHOR(pre);
5847 INIT_ANCHOR(pre);
5848 DECL_ANCHOR(rhs);
5849 INIT_ANCHOR(rhs);
5850 DECL_ANCHOR(lhs);
5851 INIT_ANCHOR(lhs);
5852 DECL_ANCHOR(post);
5853 INIT_ANCHOR(post);
5854 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5855
5856 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5857 while (memo) {
5858 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5859 for (int i = 0; i < memo->num_args; i++) {
5860 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5861 }
5862 tmp_memo = memo->next;
5863 free(memo);
5864 memo = tmp_memo;
5865 }
5866 CHECK(ok);
5867
5868 ADD_SEQ(ret, pre);
5869 ADD_SEQ(ret, rhs);
5870 ADD_SEQ(ret, lhs);
5871 if (!popped && state.num_args >= 1) {
5872 /* make sure rhs array is returned before popping */
5873 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5874 }
5875 ADD_SEQ(ret, post);
5876 }
5877 return COMPILE_OK;
5878}
5879
5880static VALUE
5881collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5882{
5883 VALUE arr = rb_ary_new();
5884 for (;;) {
5885 switch (nd_type(node)) {
5886 case NODE_CONST:
5887 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5888 return arr;
5889 case NODE_COLON3:
5890 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5891 rb_ary_unshift(arr, ID2SYM(idNULL));
5892 return arr;
5893 case NODE_COLON2:
5894 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5895 node = RNODE_COLON2(node)->nd_head;
5896 break;
5897 default:
5898 return Qfalse;
5899 }
5900 }
5901}
5902
5903static int
5904compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5905 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5906{
5907 switch (nd_type(node)) {
5908 case NODE_CONST:
5909 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5910 ADD_INSN1(body, node, putobject, Qtrue);
5911 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5912 break;
5913 case NODE_COLON3:
5914 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5915 ADD_INSN(body, node, pop);
5916 ADD_INSN1(body, node, putobject, rb_cObject);
5917 ADD_INSN1(body, node, putobject, Qtrue);
5918 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5919 break;
5920 case NODE_COLON2:
5921 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5922 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5923 ADD_INSN1(body, node, putobject, Qfalse);
5924 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5925 break;
5926 default:
5927 CHECK(COMPILE(pref, "const colon2 prefix", node));
5928 break;
5929 }
5930 return COMPILE_OK;
5931}
5932
5933static int
5934compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5935{
5936 if (nd_type_p(cpath, NODE_COLON3)) {
5937 /* toplevel class ::Foo */
5938 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5939 return VM_DEFINECLASS_FLAG_SCOPED;
5940 }
5941 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5942 /* Bar::Foo */
5943 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5944 return VM_DEFINECLASS_FLAG_SCOPED;
5945 }
5946 else {
5947 /* class at cbase Foo */
5948 ADD_INSN1(ret, cpath, putspecialobject,
5949 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5950 return 0;
5951 }
5952}
5953
5954static inline int
5955private_recv_p(const NODE *node)
5956{
5957 NODE *recv = get_nd_recv(node);
5958 if (recv && nd_type_p(recv, NODE_SELF)) {
5959 return RNODE_SELF(recv)->nd_state != 0;
5960 }
5961 return 0;
5962}
5963
5964static void
5965defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5966 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
5967
5968static int
5969compile_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);
5970
5971static void
5972defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5973 const NODE *const node, LABEL **lfinish, VALUE needstr,
5974 bool keep_result)
5975{
5976 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5977 enum node_type type;
5978 const int line = nd_line(node);
5979 const NODE *line_node = node;
5980
5981 switch (type = nd_type(node)) {
5982
5983 /* easy literals */
5984 case NODE_NIL:
5985 expr_type = DEFINED_NIL;
5986 break;
5987 case NODE_SELF:
5988 expr_type = DEFINED_SELF;
5989 break;
5990 case NODE_TRUE:
5991 expr_type = DEFINED_TRUE;
5992 break;
5993 case NODE_FALSE:
5994 expr_type = DEFINED_FALSE;
5995 break;
5996
5997 case NODE_HASH:
5998 case NODE_LIST:{
5999 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6000
6001 if (vals) {
6002 do {
6003 if (RNODE_LIST(vals)->nd_head) {
6004 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6005
6006 if (!lfinish[1]) {
6007 lfinish[1] = NEW_LABEL(line);
6008 }
6009 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6010 }
6011 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6012 }
6013 }
6014 /* fall through */
6015 case NODE_STR:
6016 case NODE_SYM:
6017 case NODE_REGX:
6018 case NODE_LINE:
6019 case NODE_FILE:
6020 case NODE_ENCODING:
6021 case NODE_INTEGER:
6022 case NODE_FLOAT:
6023 case NODE_RATIONAL:
6024 case NODE_IMAGINARY:
6025 case NODE_ZLIST:
6026 case NODE_AND:
6027 case NODE_OR:
6028 default:
6029 expr_type = DEFINED_EXPR;
6030 break;
6031
6032 case NODE_SPLAT:
6033 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6034 if (!lfinish[1]) {
6035 lfinish[1] = NEW_LABEL(line);
6036 }
6037 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6038 expr_type = DEFINED_EXPR;
6039 break;
6040
6041 /* variables */
6042 case NODE_LVAR:
6043 case NODE_DVAR:
6044 expr_type = DEFINED_LVAR;
6045 break;
6046
6047#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6048 case NODE_IVAR:
6049 ADD_INSN3(ret, line_node, definedivar,
6050 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6051 return;
6052
6053 case NODE_GVAR:
6054 ADD_INSN(ret, line_node, putnil);
6055 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6056 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6057 return;
6058
6059 case NODE_CVAR:
6060 ADD_INSN(ret, line_node, putnil);
6061 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6062 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6063 return;
6064
6065 case NODE_CONST:
6066 ADD_INSN(ret, line_node, putnil);
6067 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6068 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6069 return;
6070 case NODE_COLON2:
6071 if (!lfinish[1]) {
6072 lfinish[1] = NEW_LABEL(line);
6073 }
6074 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6075 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6076 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6077
6078 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6079 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6080 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6081 }
6082 else {
6083 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6084 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6085 }
6086 return;
6087 case NODE_COLON3:
6088 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6089 ADD_INSN3(ret, line_node, defined,
6090 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6091 return;
6092
6093 /* method dispatch */
6094 case NODE_CALL:
6095 case NODE_OPCALL:
6096 case NODE_VCALL:
6097 case NODE_FCALL:
6098 case NODE_ATTRASGN:{
6099 const int explicit_receiver =
6100 (type == NODE_CALL || type == NODE_OPCALL ||
6101 (type == NODE_ATTRASGN && !private_recv_p(node)));
6102
6103 if (get_nd_args(node) || explicit_receiver) {
6104 if (!lfinish[1]) {
6105 lfinish[1] = NEW_LABEL(line);
6106 }
6107 if (!lfinish[2]) {
6108 lfinish[2] = NEW_LABEL(line);
6109 }
6110 }
6111 if (get_nd_args(node)) {
6112 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6113 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6114 }
6115 if (explicit_receiver) {
6116 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6117 switch (nd_type(get_nd_recv(node))) {
6118 case NODE_CALL:
6119 case NODE_OPCALL:
6120 case NODE_VCALL:
6121 case NODE_FCALL:
6122 case NODE_ATTRASGN:
6123 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6124 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6125 break;
6126 default:
6127 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6128 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6129 break;
6130 }
6131 if (keep_result) {
6132 ADD_INSN(ret, line_node, dup);
6133 }
6134 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6135 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6136 }
6137 else {
6138 ADD_INSN(ret, line_node, putself);
6139 if (keep_result) {
6140 ADD_INSN(ret, line_node, dup);
6141 }
6142 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6143 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6144 }
6145 return;
6146 }
6147
6148 case NODE_YIELD:
6149 ADD_INSN(ret, line_node, putnil);
6150 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6151 PUSH_VAL(DEFINED_YIELD));
6152 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6153 return;
6154
6155 case NODE_BACK_REF:
6156 case NODE_NTH_REF:
6157 ADD_INSN(ret, line_node, putnil);
6158 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6159 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6160 PUSH_VAL(DEFINED_GVAR));
6161 return;
6162
6163 case NODE_SUPER:
6164 case NODE_ZSUPER:
6165 ADD_INSN(ret, line_node, putnil);
6166 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6167 PUSH_VAL(DEFINED_ZSUPER));
6168 return;
6169
6170#undef PUSH_VAL
6171 case NODE_OP_ASGN1:
6172 case NODE_OP_ASGN2:
6173 case NODE_OP_ASGN_OR:
6174 case NODE_OP_ASGN_AND:
6175 case NODE_MASGN:
6176 case NODE_LASGN:
6177 case NODE_DASGN:
6178 case NODE_GASGN:
6179 case NODE_IASGN:
6180 case NODE_CDECL:
6181 case NODE_CVASGN:
6182 case NODE_OP_CDECL:
6183 expr_type = DEFINED_ASGN;
6184 break;
6185 }
6186
6187 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6188
6189 if (needstr != Qfalse) {
6190 VALUE str = rb_iseq_defined_string(expr_type);
6191 ADD_INSN1(ret, line_node, putobject, str);
6192 }
6193 else {
6194 ADD_INSN1(ret, line_node, putobject, Qtrue);
6195 }
6196}
6197
6198static void
6199build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6200{
6201 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6202 iseq_set_exception_local_table(iseq);
6203}
6204
6205static void
6206defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6207 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6208{
6209 LINK_ELEMENT *lcur = ret->last;
6210 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6211 if (lfinish[1]) {
6212 int line = nd_line(node);
6213 LABEL *lstart = NEW_LABEL(line);
6214 LABEL *lend = NEW_LABEL(line);
6215 const rb_iseq_t *rescue;
6216 struct rb_iseq_new_with_callback_callback_func *ifunc =
6217 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6218 rescue = new_child_iseq_with_callback(iseq, ifunc,
6219 rb_str_concat(rb_str_new2("defined guard in "),
6220 ISEQ_BODY(iseq)->location.label),
6221 iseq, ISEQ_TYPE_RESCUE, 0);
6222 lstart->rescued = LABEL_RESCUE_BEG;
6223 lend->rescued = LABEL_RESCUE_END;
6224 APPEND_LABEL(ret, lcur, lstart);
6225 ADD_LABEL(ret, lend);
6226 if (!ignore) {
6227 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6228 }
6229 }
6230}
6231
6232static int
6233compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6234{
6235 const int line = nd_line(node);
6236 const NODE *line_node = node;
6237 if (!RNODE_DEFINED(node)->nd_head) {
6238 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6239 ADD_INSN1(ret, line_node, putobject, str);
6240 }
6241 else {
6242 LABEL *lfinish[3];
6243 LINK_ELEMENT *last = ret->last;
6244 lfinish[0] = NEW_LABEL(line);
6245 lfinish[1] = 0;
6246 lfinish[2] = 0;
6247 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6248 if (lfinish[1]) {
6249 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6250 ADD_INSN(ret, line_node, swap);
6251 if (lfinish[2]) {
6252 ADD_LABEL(ret, lfinish[2]);
6253 }
6254 ADD_INSN(ret, line_node, pop);
6255 ADD_LABEL(ret, lfinish[1]);
6256 }
6257 ADD_LABEL(ret, lfinish[0]);
6258 }
6259 return COMPILE_OK;
6260}
6261
6262static VALUE
6263make_name_for_block(const rb_iseq_t *orig_iseq)
6264{
6265 int level = 1;
6266 const rb_iseq_t *iseq = orig_iseq;
6267
6268 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6269 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6270 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6271 level++;
6272 }
6273 iseq = ISEQ_BODY(iseq)->parent_iseq;
6274 }
6275 }
6276
6277 if (level == 1) {
6278 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6279 }
6280 else {
6281 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6282 }
6283}
6284
6285static void
6286push_ensure_entry(rb_iseq_t *iseq,
6287 struct iseq_compile_data_ensure_node_stack *enl,
6288 struct ensure_range *er, const void *const node)
6289{
6290 enl->ensure_node = node;
6291 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6292 enl->erange = er;
6293 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6294}
6295
6296static void
6297add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6298 LABEL *lstart, LABEL *lend)
6299{
6300 struct ensure_range *ne =
6301 compile_data_alloc(iseq, sizeof(struct ensure_range));
6302
6303 while (erange->next != 0) {
6304 erange = erange->next;
6305 }
6306 ne->next = 0;
6307 ne->begin = lend;
6308 ne->end = erange->end;
6309 erange->end = lstart;
6310
6311 erange->next = ne;
6312}
6313
6314static bool
6315can_add_ensure_iseq(const rb_iseq_t *iseq)
6316{
6317 struct iseq_compile_data_ensure_node_stack *e;
6318 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6319 while (e) {
6320 if (e->ensure_node) return false;
6321 e = e->prev;
6322 }
6323 }
6324 return true;
6325}
6326
6327static void
6328add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6329{
6330 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6331
6332 struct iseq_compile_data_ensure_node_stack *enlp =
6333 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6334 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6335 DECL_ANCHOR(ensure);
6336
6337 INIT_ANCHOR(ensure);
6338 while (enlp) {
6339 if (enlp->erange != NULL) {
6340 DECL_ANCHOR(ensure_part);
6341 LABEL *lstart = NEW_LABEL(0);
6342 LABEL *lend = NEW_LABEL(0);
6343 INIT_ANCHOR(ensure_part);
6344
6345 add_ensure_range(iseq, enlp->erange, lstart, lend);
6346
6347 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6348 ADD_LABEL(ensure_part, lstart);
6349 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6350 ADD_LABEL(ensure_part, lend);
6351 ADD_SEQ(ensure, ensure_part);
6352 }
6353 else {
6354 if (!is_return) {
6355 break;
6356 }
6357 }
6358 enlp = enlp->prev;
6359 }
6360 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6361 ADD_SEQ(ret, ensure);
6362}
6363
6364#if RUBY_DEBUG
6365static int
6366check_keyword(const NODE *node)
6367{
6368 /* This check is essentially a code clone of compile_keyword_arg. */
6369
6370 if (nd_type_p(node, NODE_LIST)) {
6371 while (RNODE_LIST(node)->nd_next) {
6372 node = RNODE_LIST(node)->nd_next;
6373 }
6374 node = RNODE_LIST(node)->nd_head;
6375 }
6376
6377 return keyword_node_p(node);
6378}
6379#endif
6380
6381static bool
6382keyword_node_single_splat_p(NODE *kwnode)
6383{
6384 RUBY_ASSERT(keyword_node_p(kwnode));
6385
6386 NODE *node = RNODE_HASH(kwnode)->nd_head;
6387 return RNODE_LIST(node)->nd_head == NULL &&
6388 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6389}
6390
6391static void
6392compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6393 NODE *kwnode, unsigned int *flag_ptr)
6394{
6395 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6396 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6397 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6398 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6399 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6400}
6401
6402#define SPLATARRAY_FALSE 0
6403#define SPLATARRAY_TRUE 1
6404#define DUP_SINGLE_KW_SPLAT 2
6405
6406static int
6407setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6408 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6409{
6410 if (!argn) return 0;
6411
6412 NODE *kwnode = NULL;
6413
6414 switch (nd_type(argn)) {
6415 case NODE_LIST: {
6416 // f(x, y, z)
6417 int len = compile_args(iseq, args, argn, &kwnode);
6418 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6419
6420 if (kwnode) {
6421 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6422 len -= 1;
6423 }
6424 else {
6425 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6426 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6427 }
6428 else {
6429 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6430 }
6431 }
6432 }
6433
6434 return len;
6435 }
6436 case NODE_SPLAT: {
6437 // f(*a)
6438 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6439 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6440 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6441 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6442 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6443 return 1;
6444 }
6445 case NODE_ARGSCAT: {
6446 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6447 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6448 bool args_pushed = false;
6449
6450 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6451 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6452 if (kwnode) rest_len--;
6453 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6454 args_pushed = true;
6455 }
6456 else {
6457 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6458 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6459 }
6460
6461 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6462 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6463 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6464 argc += 1;
6465 }
6466 else if (!args_pushed) {
6467 ADD_INSN(args, argn, concattoarray);
6468 }
6469
6470 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6471 if (kwnode) {
6472 // kwsplat
6473 *flag_ptr |= VM_CALL_KW_SPLAT;
6474 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6475 argc += 1;
6476 }
6477
6478 return argc;
6479 }
6480 case NODE_ARGSPUSH: {
6481 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6482 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6483
6484 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6485 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6486 if (kwnode) rest_len--;
6487 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6488 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6489 }
6490 else {
6491 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6492 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6493 }
6494 else {
6495 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6496 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6497 }
6498 }
6499
6500 if (kwnode) {
6501 // f(*a, k:1)
6502 *flag_ptr |= VM_CALL_KW_SPLAT;
6503 if (!keyword_node_single_splat_p(kwnode)) {
6504 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6505 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6506 }
6507 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6508 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6509 }
6510 else {
6511 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6512 }
6513 argc += 1;
6514 }
6515
6516 return argc;
6517 }
6518 default: {
6519 UNKNOWN_NODE("setup_arg", argn, Qnil);
6520 }
6521 }
6522}
6523
6524static void
6525setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6526{
6527 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6528 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6529 }
6530}
6531
6532static bool
6533setup_args_dup_rest_p(const NODE *argn)
6534{
6535 switch(nd_type(argn)) {
6536 case NODE_LVAR:
6537 case NODE_DVAR:
6538 case NODE_GVAR:
6539 case NODE_IVAR:
6540 case NODE_CVAR:
6541 case NODE_CONST:
6542 case NODE_COLON3:
6543 case NODE_INTEGER:
6544 case NODE_FLOAT:
6545 case NODE_RATIONAL:
6546 case NODE_IMAGINARY:
6547 case NODE_STR:
6548 case NODE_SYM:
6549 case NODE_REGX:
6550 case NODE_SELF:
6551 case NODE_NIL:
6552 case NODE_TRUE:
6553 case NODE_FALSE:
6554 case NODE_LAMBDA:
6555 case NODE_NTH_REF:
6556 case NODE_BACK_REF:
6557 return false;
6558 case NODE_COLON2:
6559 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6560 default:
6561 return true;
6562 }
6563}
6564
6565static VALUE
6566setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6567 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6568{
6569 VALUE ret;
6570 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6571
6572 if (argn) {
6573 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6574 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6575
6576 if (check_arg) {
6577 switch(nd_type(check_arg)) {
6578 case(NODE_SPLAT):
6579 // avoid caller side array allocation for f(*arg)
6580 dup_rest = SPLATARRAY_FALSE;
6581 break;
6582 case(NODE_ARGSCAT):
6583 // avoid caller side array allocation for f(1, *arg)
6584 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6585 break;
6586 case(NODE_ARGSPUSH):
6587 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6588 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6589 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6590 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6591 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6592 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6593
6594 if (dup_rest == SPLATARRAY_FALSE) {
6595 // require allocation for keyword key/value/splat that may modify splatted argument
6596 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6597 while (node) {
6598 NODE *key_node = RNODE_LIST(node)->nd_head;
6599 if (key_node && setup_args_dup_rest_p(key_node)) {
6600 dup_rest = SPLATARRAY_TRUE;
6601 break;
6602 }
6603
6604 node = RNODE_LIST(node)->nd_next;
6605 NODE *value_node = RNODE_LIST(node)->nd_head;
6606 if (setup_args_dup_rest_p(value_node)) {
6607 dup_rest = SPLATARRAY_TRUE;
6608 break;
6609 }
6610
6611 node = RNODE_LIST(node)->nd_next;
6612 }
6613 }
6614 break;
6615 default:
6616 break;
6617 }
6618 }
6619
6620 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6621 // for block pass that may modify splatted argument, dup rest and kwrest if given
6622 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6623 }
6624 }
6625 initial_dup_rest = dup_rest;
6626
6627 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6628 DECL_ANCHOR(arg_block);
6629 INIT_ANCHOR(arg_block);
6630
6631 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6632 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6633
6634 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6635 const NODE * arg_node =
6636 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6637
6638 int argc = 0;
6639
6640 // Only compile leading args:
6641 // foo(x, y, ...)
6642 // ^^^^
6643 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6644 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6645 }
6646
6647 *flag |= VM_CALL_FORWARDING;
6648
6649 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6650 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6651 return INT2FIX(argc);
6652 }
6653 else {
6654 *flag |= VM_CALL_ARGS_BLOCKARG;
6655
6656 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6657 }
6658
6659 if (LIST_INSN_SIZE_ONE(arg_block)) {
6660 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6661 if (IS_INSN(elem)) {
6662 INSN *iobj = (INSN *)elem;
6663 if (iobj->insn_id == BIN(getblockparam)) {
6664 iobj->insn_id = BIN(getblockparamproxy);
6665 }
6666 }
6667 }
6668 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6669 ADD_SEQ(args, arg_block);
6670 }
6671 else {
6672 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6673 }
6674 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6675 return ret;
6676}
6677
6678static void
6679build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6680{
6681 const NODE *body = ptr;
6682 int line = nd_line(body);
6683 VALUE argc = INT2FIX(0);
6684 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6685
6686 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6687 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6688 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6689 iseq_set_local_table(iseq, 0, 0);
6690}
6691
6692static void
6693compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6694{
6695 const NODE *vars;
6696 LINK_ELEMENT *last;
6697 int line = nd_line(node);
6698 const NODE *line_node = node;
6699 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6700
6701#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6702 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6703#else
6704 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6705#endif
6706 ADD_INSN(ret, line_node, dup);
6707 ADD_INSNL(ret, line_node, branchunless, fail_label);
6708
6709 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6710 INSN *cap;
6711 if (RNODE_BLOCK(vars)->nd_next) {
6712 ADD_INSN(ret, line_node, dup);
6713 }
6714 last = ret->last;
6715 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6716 last = last->next; /* putobject :var */
6717 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6718 NULL, INT2FIX(0), NULL);
6719 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6720#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6721 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6722 /* only one name */
6723 DECL_ANCHOR(nom);
6724
6725 INIT_ANCHOR(nom);
6726 ADD_INSNL(nom, line_node, jump, end_label);
6727 ADD_LABEL(nom, fail_label);
6728# if 0 /* $~ must be MatchData or nil */
6729 ADD_INSN(nom, line_node, pop);
6730 ADD_INSN(nom, line_node, putnil);
6731# endif
6732 ADD_LABEL(nom, end_label);
6733 (nom->last->next = cap->link.next)->prev = nom->last;
6734 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6735 return;
6736 }
6737#endif
6738 }
6739 ADD_INSNL(ret, line_node, jump, end_label);
6740 ADD_LABEL(ret, fail_label);
6741 ADD_INSN(ret, line_node, pop);
6742 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6743 last = ret->last;
6744 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6745 last = last->next; /* putobject :var */
6746 ((INSN*)last)->insn_id = BIN(putnil);
6747 ((INSN*)last)->operand_size = 0;
6748 }
6749 ADD_LABEL(ret, end_label);
6750}
6751
6752static int
6753optimizable_range_item_p(const NODE *n)
6754{
6755 if (!n) return FALSE;
6756 switch (nd_type(n)) {
6757 case NODE_LINE:
6758 return TRUE;
6759 case NODE_INTEGER:
6760 return TRUE;
6761 case NODE_NIL:
6762 return TRUE;
6763 default:
6764 return FALSE;
6765 }
6766}
6767
6768static VALUE
6769optimized_range_item(const NODE *n)
6770{
6771 switch (nd_type(n)) {
6772 case NODE_LINE:
6773 return rb_node_line_lineno_val(n);
6774 case NODE_INTEGER:
6775 return rb_node_integer_literal_val(n);
6776 case NODE_FLOAT:
6777 return rb_node_float_literal_val(n);
6778 case NODE_RATIONAL:
6779 return rb_node_rational_literal_val(n);
6780 case NODE_IMAGINARY:
6781 return rb_node_imaginary_literal_val(n);
6782 case NODE_NIL:
6783 return Qnil;
6784 default:
6785 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6786 }
6787}
6788
6789static int
6790compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6791{
6792 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6793 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6794
6795 const int line = nd_line(node);
6796 const NODE *line_node = node;
6797 DECL_ANCHOR(cond_seq);
6798 LABEL *then_label, *else_label, *end_label;
6799 VALUE branches = Qfalse;
6800
6801 INIT_ANCHOR(cond_seq);
6802 then_label = NEW_LABEL(line);
6803 else_label = NEW_LABEL(line);
6804 end_label = 0;
6805
6806 NODE *cond = RNODE_IF(node)->nd_cond;
6807 if (nd_type(cond) == NODE_BLOCK) {
6808 cond = RNODE_BLOCK(cond)->nd_head;
6809 }
6810
6811 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6812 ADD_SEQ(ret, cond_seq);
6813
6814 if (then_label->refcnt && else_label->refcnt) {
6815 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6816 }
6817
6818 if (then_label->refcnt) {
6819 ADD_LABEL(ret, then_label);
6820
6821 DECL_ANCHOR(then_seq);
6822 INIT_ANCHOR(then_seq);
6823 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6824
6825 if (else_label->refcnt) {
6826 const NODE *const coverage_node = node_body ? node_body : node;
6827 add_trace_branch_coverage(
6828 iseq,
6829 ret,
6830 nd_code_loc(coverage_node),
6831 nd_node_id(coverage_node),
6832 0,
6833 type == NODE_IF ? "then" : "else",
6834 branches);
6835 end_label = NEW_LABEL(line);
6836 ADD_INSNL(then_seq, line_node, jump, end_label);
6837 if (!popped) {
6838 ADD_INSN(then_seq, line_node, pop);
6839 }
6840 }
6841 ADD_SEQ(ret, then_seq);
6842 }
6843
6844 if (else_label->refcnt) {
6845 ADD_LABEL(ret, else_label);
6846
6847 DECL_ANCHOR(else_seq);
6848 INIT_ANCHOR(else_seq);
6849 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6850
6851 if (then_label->refcnt) {
6852 const NODE *const coverage_node = node_else ? node_else : node;
6853 add_trace_branch_coverage(
6854 iseq,
6855 ret,
6856 nd_code_loc(coverage_node),
6857 nd_node_id(coverage_node),
6858 1,
6859 type == NODE_IF ? "else" : "then",
6860 branches);
6861 }
6862 ADD_SEQ(ret, else_seq);
6863 }
6864
6865 if (end_label) {
6866 ADD_LABEL(ret, end_label);
6867 }
6868
6869 return COMPILE_OK;
6870}
6871
6872static int
6873compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6874{
6875 const NODE *vals;
6876 const NODE *node = orig_node;
6877 LABEL *endlabel, *elselabel;
6878 DECL_ANCHOR(head);
6879 DECL_ANCHOR(body_seq);
6880 DECL_ANCHOR(cond_seq);
6881 int only_special_literals = 1;
6882 VALUE literals = rb_hash_new();
6883 int line;
6884 enum node_type type;
6885 const NODE *line_node;
6886 VALUE branches = Qfalse;
6887 int branch_id = 0;
6888
6889 INIT_ANCHOR(head);
6890 INIT_ANCHOR(body_seq);
6891 INIT_ANCHOR(cond_seq);
6892
6893 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6894
6895 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6896
6897 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6898
6899 node = RNODE_CASE(node)->nd_body;
6900 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6901 type = nd_type(node);
6902 line = nd_line(node);
6903 line_node = node;
6904
6905 endlabel = NEW_LABEL(line);
6906 elselabel = NEW_LABEL(line);
6907
6908 ADD_SEQ(ret, head); /* case VAL */
6909
6910 while (type == NODE_WHEN) {
6911 LABEL *l1;
6912
6913 l1 = NEW_LABEL(line);
6914 ADD_LABEL(body_seq, l1);
6915 ADD_INSN(body_seq, line_node, pop);
6916
6917 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6918 add_trace_branch_coverage(
6919 iseq,
6920 body_seq,
6921 nd_code_loc(coverage_node),
6922 nd_node_id(coverage_node),
6923 branch_id++,
6924 "when",
6925 branches);
6926
6927 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6928 ADD_INSNL(body_seq, line_node, jump, endlabel);
6929
6930 vals = RNODE_WHEN(node)->nd_head;
6931 if (vals) {
6932 switch (nd_type(vals)) {
6933 case NODE_LIST:
6934 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6935 if (only_special_literals < 0) return COMPILE_NG;
6936 break;
6937 case NODE_SPLAT:
6938 case NODE_ARGSCAT:
6939 case NODE_ARGSPUSH:
6940 only_special_literals = 0;
6941 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6942 break;
6943 default:
6944 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6945 }
6946 }
6947 else {
6948 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6949 }
6950
6951 node = RNODE_WHEN(node)->nd_next;
6952 if (!node) {
6953 break;
6954 }
6955 type = nd_type(node);
6956 line = nd_line(node);
6957 line_node = node;
6958 }
6959 /* else */
6960 if (node) {
6961 ADD_LABEL(cond_seq, elselabel);
6962 ADD_INSN(cond_seq, line_node, pop);
6963 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
6964 CHECK(COMPILE_(cond_seq, "else", node, popped));
6965 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6966 }
6967 else {
6968 debugs("== else (implicit)\n");
6969 ADD_LABEL(cond_seq, elselabel);
6970 ADD_INSN(cond_seq, orig_node, pop);
6971 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
6972 if (!popped) {
6973 ADD_INSN(cond_seq, orig_node, putnil);
6974 }
6975 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6976 }
6977
6978 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6979 ADD_INSN(ret, orig_node, dup);
6980 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6981 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6982 LABEL_REF(elselabel);
6983 }
6984
6985 ADD_SEQ(ret, cond_seq);
6986 ADD_SEQ(ret, body_seq);
6987 ADD_LABEL(ret, endlabel);
6988 return COMPILE_OK;
6989}
6990
6991static int
6992compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6993{
6994 const NODE *vals;
6995 const NODE *val;
6996 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6997 LABEL *endlabel;
6998 DECL_ANCHOR(body_seq);
6999 VALUE branches = Qfalse;
7000 int branch_id = 0;
7001
7002 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7003
7004 INIT_ANCHOR(body_seq);
7005 endlabel = NEW_LABEL(nd_line(node));
7006
7007 while (node && nd_type_p(node, NODE_WHEN)) {
7008 const int line = nd_line(node);
7009 LABEL *l1 = NEW_LABEL(line);
7010 ADD_LABEL(body_seq, l1);
7011
7012 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7013 add_trace_branch_coverage(
7014 iseq,
7015 body_seq,
7016 nd_code_loc(coverage_node),
7017 nd_node_id(coverage_node),
7018 branch_id++,
7019 "when",
7020 branches);
7021
7022 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7023 ADD_INSNL(body_seq, node, jump, endlabel);
7024
7025 vals = RNODE_WHEN(node)->nd_head;
7026 if (!vals) {
7027 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7028 }
7029 switch (nd_type(vals)) {
7030 case NODE_LIST:
7031 while (vals) {
7032 LABEL *lnext;
7033 val = RNODE_LIST(vals)->nd_head;
7034 lnext = NEW_LABEL(nd_line(val));
7035 debug_compile("== when2\n", (void)0);
7036 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7037 ADD_LABEL(ret, lnext);
7038 vals = RNODE_LIST(vals)->nd_next;
7039 }
7040 break;
7041 case NODE_SPLAT:
7042 case NODE_ARGSCAT:
7043 case NODE_ARGSPUSH:
7044 ADD_INSN(ret, vals, putnil);
7045 CHECK(COMPILE(ret, "when2/cond splat", vals));
7046 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7047 ADD_INSNL(ret, vals, branchif, l1);
7048 break;
7049 default:
7050 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7051 }
7052 node = RNODE_WHEN(node)->nd_next;
7053 }
7054 /* else */
7055 const NODE *const coverage_node = node ? node : orig_node;
7056 add_trace_branch_coverage(
7057 iseq,
7058 ret,
7059 nd_code_loc(coverage_node),
7060 nd_node_id(coverage_node),
7061 branch_id,
7062 "else",
7063 branches);
7064 CHECK(COMPILE_(ret, "else", node, popped));
7065 ADD_INSNL(ret, orig_node, jump, endlabel);
7066
7067 ADD_SEQ(ret, body_seq);
7068 ADD_LABEL(ret, endlabel);
7069 return COMPILE_OK;
7070}
7071
7072static 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);
7073
7074static 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);
7075static 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);
7076static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7077static 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);
7078static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7079
7080#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7081#define CASE3_BI_OFFSET_ERROR_STRING 1
7082#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7083#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7084#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7085
7086static int
7087iseq_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)
7088{
7089 const int line = nd_line(node);
7090 const NODE *line_node = node;
7091
7092 switch (nd_type(node)) {
7093 case NODE_ARYPTN: {
7094 /*
7095 * if pattern.use_rest_num?
7096 * rest_num = 0
7097 * end
7098 * if pattern.has_constant_node?
7099 * unless pattern.constant === obj
7100 * goto match_failed
7101 * end
7102 * end
7103 * unless obj.respond_to?(:deconstruct)
7104 * goto match_failed
7105 * end
7106 * d = obj.deconstruct
7107 * unless Array === d
7108 * goto type_error
7109 * end
7110 * min_argc = pattern.pre_args_num + pattern.post_args_num
7111 * if pattern.has_rest_arg?
7112 * unless d.length >= min_argc
7113 * goto match_failed
7114 * end
7115 * else
7116 * unless d.length == min_argc
7117 * goto match_failed
7118 * end
7119 * end
7120 * pattern.pre_args_num.each do |i|
7121 * unless pattern.pre_args[i].match?(d[i])
7122 * goto match_failed
7123 * end
7124 * end
7125 * if pattern.use_rest_num?
7126 * rest_num = d.length - min_argc
7127 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7128 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7129 * goto match_failed
7130 * end
7131 * end
7132 * end
7133 * pattern.post_args_num.each do |i|
7134 * j = pattern.pre_args_num + i
7135 * j += rest_num
7136 * unless pattern.post_args[i].match?(d[j])
7137 * goto match_failed
7138 * end
7139 * end
7140 * goto matched
7141 * type_error:
7142 * FrozenCore.raise TypeError
7143 * match_failed:
7144 * goto unmatched
7145 */
7146 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7147 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7148 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7149
7150 const int min_argc = pre_args_num + post_args_num;
7151 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7152 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7153
7154 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7155 int i;
7156 match_failed = NEW_LABEL(line);
7157 type_error = NEW_LABEL(line);
7158 deconstruct = NEW_LABEL(line);
7159 deconstructed = NEW_LABEL(line);
7160
7161 if (use_rest_num) {
7162 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7163 ADD_INSN(ret, line_node, swap);
7164 if (base_index) {
7165 base_index++;
7166 }
7167 }
7168
7169 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7170
7171 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7172
7173 ADD_INSN(ret, line_node, dup);
7174 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7175 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7176 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7177 if (in_single_pattern) {
7178 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7179 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7180 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7181 INT2FIX(min_argc), base_index + 1 /* (1) */));
7182 }
7183 ADD_INSNL(ret, line_node, branchunless, match_failed);
7184
7185 for (i = 0; i < pre_args_num; i++) {
7186 ADD_INSN(ret, line_node, dup);
7187 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7188 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7189 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));
7190 args = RNODE_LIST(args)->nd_next;
7191 }
7192
7193 if (RNODE_ARYPTN(node)->rest_arg) {
7194 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7195 ADD_INSN(ret, line_node, dup);
7196 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7197 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7198 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7199 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7200 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7201 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7202 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7203
7204 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));
7205 }
7206 else {
7207 if (post_args_num > 0) {
7208 ADD_INSN(ret, line_node, dup);
7209 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7210 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7211 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7212 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7213 ADD_INSN(ret, line_node, pop);
7214 }
7215 }
7216 }
7217
7218 args = RNODE_ARYPTN(node)->post_args;
7219 for (i = 0; i < post_args_num; i++) {
7220 ADD_INSN(ret, line_node, dup);
7221
7222 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7223 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7224 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7225
7226 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7227 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));
7228 args = RNODE_LIST(args)->nd_next;
7229 }
7230
7231 ADD_INSN(ret, line_node, pop);
7232 if (use_rest_num) {
7233 ADD_INSN(ret, line_node, pop);
7234 }
7235 ADD_INSNL(ret, line_node, jump, matched);
7236 ADD_INSN(ret, line_node, putnil);
7237 if (use_rest_num) {
7238 ADD_INSN(ret, line_node, putnil);
7239 }
7240
7241 ADD_LABEL(ret, type_error);
7242 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7243 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7244 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7245 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7246 ADD_INSN(ret, line_node, pop);
7247
7248 ADD_LABEL(ret, match_failed);
7249 ADD_INSN(ret, line_node, pop);
7250 if (use_rest_num) {
7251 ADD_INSN(ret, line_node, pop);
7252 }
7253 ADD_INSNL(ret, line_node, jump, unmatched);
7254
7255 break;
7256 }
7257 case NODE_FNDPTN: {
7258 /*
7259 * if pattern.has_constant_node?
7260 * unless pattern.constant === obj
7261 * goto match_failed
7262 * end
7263 * end
7264 * unless obj.respond_to?(:deconstruct)
7265 * goto match_failed
7266 * end
7267 * d = obj.deconstruct
7268 * unless Array === d
7269 * goto type_error
7270 * end
7271 * unless d.length >= pattern.args_num
7272 * goto match_failed
7273 * end
7274 *
7275 * begin
7276 * len = d.length
7277 * limit = d.length - pattern.args_num
7278 * i = 0
7279 * while i <= limit
7280 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7281 * if pattern.has_pre_rest_arg_id
7282 * unless pattern.pre_rest_arg.match?(d[0, i])
7283 * goto find_failed
7284 * end
7285 * end
7286 * if pattern.has_post_rest_arg_id
7287 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7288 * goto find_failed
7289 * end
7290 * end
7291 * goto find_succeeded
7292 * end
7293 * i+=1
7294 * end
7295 * find_failed:
7296 * goto match_failed
7297 * find_succeeded:
7298 * end
7299 *
7300 * goto matched
7301 * type_error:
7302 * FrozenCore.raise TypeError
7303 * match_failed:
7304 * goto unmatched
7305 */
7306 const NODE *args = RNODE_FNDPTN(node)->args;
7307 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7308
7309 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7310 match_failed = NEW_LABEL(line);
7311 type_error = NEW_LABEL(line);
7312 deconstruct = NEW_LABEL(line);
7313 deconstructed = NEW_LABEL(line);
7314
7315 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7316
7317 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7318
7319 ADD_INSN(ret, line_node, dup);
7320 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7321 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7322 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7323 if (in_single_pattern) {
7324 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) */));
7325 }
7326 ADD_INSNL(ret, line_node, branchunless, match_failed);
7327
7328 {
7329 LABEL *while_begin = NEW_LABEL(nd_line(node));
7330 LABEL *next_loop = NEW_LABEL(nd_line(node));
7331 LABEL *find_succeeded = NEW_LABEL(line);
7332 LABEL *find_failed = NEW_LABEL(nd_line(node));
7333 int j;
7334
7335 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7336 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7337
7338 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7339 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7340 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7341
7342 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7343
7344 ADD_LABEL(ret, while_begin);
7345
7346 ADD_INSN(ret, line_node, dup);
7347 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7348 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7349 ADD_INSNL(ret, line_node, branchunless, find_failed);
7350
7351 for (j = 0; j < args_num; j++) {
7352 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7353 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7354 if (j != 0) {
7355 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7356 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7357 }
7358 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7359
7360 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));
7361 args = RNODE_LIST(args)->nd_next;
7362 }
7363
7364 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7365 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7366 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7367 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7368 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7369 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));
7370 }
7371 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7372 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7373 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7374 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7375 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7376 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7377 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7378 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));
7379 }
7380 ADD_INSNL(ret, line_node, jump, find_succeeded);
7381
7382 ADD_LABEL(ret, next_loop);
7383 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7384 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7385 ADD_INSNL(ret, line_node, jump, while_begin);
7386
7387 ADD_LABEL(ret, find_failed);
7388 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7389 if (in_single_pattern) {
7390 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7391 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7392 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7393 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7394 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7395
7396 ADD_INSN1(ret, line_node, putobject, Qfalse);
7397 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7398
7399 ADD_INSN(ret, line_node, pop);
7400 ADD_INSN(ret, line_node, pop);
7401 }
7402 ADD_INSNL(ret, line_node, jump, match_failed);
7403 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7404
7405 ADD_LABEL(ret, find_succeeded);
7406 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7407 }
7408
7409 ADD_INSN(ret, line_node, pop);
7410 ADD_INSNL(ret, line_node, jump, matched);
7411 ADD_INSN(ret, line_node, putnil);
7412
7413 ADD_LABEL(ret, type_error);
7414 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7415 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7416 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7417 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7418 ADD_INSN(ret, line_node, pop);
7419
7420 ADD_LABEL(ret, match_failed);
7421 ADD_INSN(ret, line_node, pop);
7422 ADD_INSNL(ret, line_node, jump, unmatched);
7423
7424 break;
7425 }
7426 case NODE_HSHPTN: {
7427 /*
7428 * keys = nil
7429 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7430 * keys = pattern.kw_args_node.keys
7431 * end
7432 * if pattern.has_constant_node?
7433 * unless pattern.constant === obj
7434 * goto match_failed
7435 * end
7436 * end
7437 * unless obj.respond_to?(:deconstruct_keys)
7438 * goto match_failed
7439 * end
7440 * d = obj.deconstruct_keys(keys)
7441 * unless Hash === d
7442 * goto type_error
7443 * end
7444 * if pattern.has_kw_rest_arg_node?
7445 * d = d.dup
7446 * end
7447 * if pattern.has_kw_args_node?
7448 * pattern.kw_args_node.each |k,|
7449 * unless d.key?(k)
7450 * goto match_failed
7451 * end
7452 * end
7453 * pattern.kw_args_node.each |k, pat|
7454 * if pattern.has_kw_rest_arg_node?
7455 * unless pat.match?(d.delete(k))
7456 * goto match_failed
7457 * end
7458 * else
7459 * unless pat.match?(d[k])
7460 * goto match_failed
7461 * end
7462 * end
7463 * end
7464 * else
7465 * unless d.empty?
7466 * goto match_failed
7467 * end
7468 * end
7469 * if pattern.has_kw_rest_arg_node?
7470 * if pattern.no_rest_keyword?
7471 * unless d.empty?
7472 * goto match_failed
7473 * end
7474 * else
7475 * unless pattern.kw_rest_arg_node.match?(d)
7476 * goto match_failed
7477 * end
7478 * end
7479 * end
7480 * goto matched
7481 * type_error:
7482 * FrozenCore.raise TypeError
7483 * match_failed:
7484 * goto unmatched
7485 */
7486 LABEL *match_failed, *type_error;
7487 VALUE keys = Qnil;
7488
7489 match_failed = NEW_LABEL(line);
7490 type_error = NEW_LABEL(line);
7491
7492 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7493 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7494 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7495 while (kw_args) {
7496 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7497 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7498 }
7499 }
7500
7501 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7502
7503 ADD_INSN(ret, line_node, dup);
7504 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7505 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7506 if (in_single_pattern) {
7507 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7508 }
7509 ADD_INSNL(ret, line_node, branchunless, match_failed);
7510
7511 if (NIL_P(keys)) {
7512 ADD_INSN(ret, line_node, putnil);
7513 }
7514 else {
7515 ADD_INSN1(ret, line_node, duparray, keys);
7516 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7517 }
7518 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7519
7520 ADD_INSN(ret, line_node, dup);
7521 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7522 ADD_INSNL(ret, line_node, branchunless, type_error);
7523
7524 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7525 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7526 }
7527
7528 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7529 int i;
7530 int keys_num;
7531 const NODE *args;
7532 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7533 if (args) {
7534 DECL_ANCHOR(match_values);
7535 INIT_ANCHOR(match_values);
7536 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7537 for (i = 0; i < keys_num; i++) {
7538 NODE *key_node = RNODE_LIST(args)->nd_head;
7539 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7540 VALUE key = get_symbol_value(iseq, key_node);
7541
7542 ADD_INSN(ret, line_node, dup);
7543 ADD_INSN1(ret, line_node, putobject, key);
7544 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7545 if (in_single_pattern) {
7546 LABEL *match_succeeded;
7547 match_succeeded = NEW_LABEL(line);
7548
7549 ADD_INSN(ret, line_node, dup);
7550 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7551
7552 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7553 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7554 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7555 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7556 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7557 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7558 ADD_INSN1(ret, line_node, putobject, key); // (7)
7559 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7560
7561 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7562
7563 ADD_LABEL(ret, match_succeeded);
7564 }
7565 ADD_INSNL(ret, line_node, branchunless, match_failed);
7566
7567 ADD_INSN(match_values, line_node, dup);
7568 ADD_INSN1(match_values, line_node, putobject, key);
7569 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7570 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7571 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7572 }
7573 ADD_SEQ(ret, match_values);
7574 }
7575 }
7576 else {
7577 ADD_INSN(ret, line_node, dup);
7578 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7579 if (in_single_pattern) {
7580 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7581 }
7582 ADD_INSNL(ret, line_node, branchunless, match_failed);
7583 }
7584
7585 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7586 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7587 ADD_INSN(ret, line_node, dup);
7588 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7589 if (in_single_pattern) {
7590 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7591 }
7592 ADD_INSNL(ret, line_node, branchunless, match_failed);
7593 }
7594 else {
7595 ADD_INSN(ret, line_node, dup); // (11)
7596 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));
7597 }
7598 }
7599
7600 ADD_INSN(ret, line_node, pop);
7601 ADD_INSNL(ret, line_node, jump, matched);
7602 ADD_INSN(ret, line_node, putnil);
7603
7604 ADD_LABEL(ret, type_error);
7605 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7606 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7607 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7608 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7609 ADD_INSN(ret, line_node, pop);
7610
7611 ADD_LABEL(ret, match_failed);
7612 ADD_INSN(ret, line_node, pop);
7613 ADD_INSNL(ret, line_node, jump, unmatched);
7614 break;
7615 }
7616 case NODE_SYM:
7617 case NODE_REGX:
7618 case NODE_LINE:
7619 case NODE_INTEGER:
7620 case NODE_FLOAT:
7621 case NODE_RATIONAL:
7622 case NODE_IMAGINARY:
7623 case NODE_FILE:
7624 case NODE_ENCODING:
7625 case NODE_STR:
7626 case NODE_XSTR:
7627 case NODE_DSTR:
7628 case NODE_DSYM:
7629 case NODE_DREGX:
7630 case NODE_LIST:
7631 case NODE_ZLIST:
7632 case NODE_LAMBDA:
7633 case NODE_DOT2:
7634 case NODE_DOT3:
7635 case NODE_CONST:
7636 case NODE_LVAR:
7637 case NODE_DVAR:
7638 case NODE_IVAR:
7639 case NODE_CVAR:
7640 case NODE_GVAR:
7641 case NODE_TRUE:
7642 case NODE_FALSE:
7643 case NODE_SELF:
7644 case NODE_NIL:
7645 case NODE_COLON2:
7646 case NODE_COLON3:
7647 case NODE_BEGIN:
7648 case NODE_BLOCK:
7649 case NODE_ONCE:
7650 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7651 if (in_single_pattern) {
7652 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7653 }
7654 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7655 if (in_single_pattern) {
7656 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7657 }
7658 ADD_INSNL(ret, line_node, branchif, matched);
7659 ADD_INSNL(ret, line_node, jump, unmatched);
7660 break;
7661 case NODE_LASGN: {
7662 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7663 ID id = RNODE_LASGN(node)->nd_vid;
7664 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7665
7666 if (in_alt_pattern) {
7667 const char *name = rb_id2name(id);
7668 if (name && strlen(name) > 0 && name[0] != '_') {
7669 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7670 rb_id2str(id));
7671 return COMPILE_NG;
7672 }
7673 }
7674
7675 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7676 ADD_INSNL(ret, line_node, jump, matched);
7677 break;
7678 }
7679 case NODE_DASGN: {
7680 int idx, lv, ls;
7681 ID id = RNODE_DASGN(node)->nd_vid;
7682
7683 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7684
7685 if (in_alt_pattern) {
7686 const char *name = rb_id2name(id);
7687 if (name && strlen(name) > 0 && name[0] != '_') {
7688 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7689 rb_id2str(id));
7690 return COMPILE_NG;
7691 }
7692 }
7693
7694 if (idx < 0) {
7695 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7696 rb_id2str(id));
7697 return COMPILE_NG;
7698 }
7699 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7700 ADD_INSNL(ret, line_node, jump, matched);
7701 break;
7702 }
7703 case NODE_IF:
7704 case NODE_UNLESS: {
7705 LABEL *match_failed;
7706 match_failed = unmatched;
7707 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7708 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7709 if (in_single_pattern) {
7710 LABEL *match_succeeded;
7711 match_succeeded = NEW_LABEL(line);
7712
7713 ADD_INSN(ret, line_node, dup);
7714 if (nd_type_p(node, NODE_IF)) {
7715 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7716 }
7717 else {
7718 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7719 }
7720
7721 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7722 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7723 ADD_INSN1(ret, line_node, putobject, Qfalse);
7724 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7725
7726 ADD_INSN(ret, line_node, pop);
7727 ADD_INSN(ret, line_node, pop);
7728
7729 ADD_LABEL(ret, match_succeeded);
7730 }
7731 if (nd_type_p(node, NODE_IF)) {
7732 ADD_INSNL(ret, line_node, branchunless, match_failed);
7733 }
7734 else {
7735 ADD_INSNL(ret, line_node, branchif, match_failed);
7736 }
7737 ADD_INSNL(ret, line_node, jump, matched);
7738 break;
7739 }
7740 case NODE_HASH: {
7741 NODE *n;
7742 LABEL *match_failed;
7743 match_failed = NEW_LABEL(line);
7744
7745 n = RNODE_HASH(node)->nd_head;
7746 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7747 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7748 return COMPILE_NG;
7749 }
7750
7751 ADD_INSN(ret, line_node, dup); // (1)
7752 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));
7753 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));
7754 ADD_INSN(ret, line_node, putnil);
7755
7756 ADD_LABEL(ret, match_failed);
7757 ADD_INSN(ret, line_node, pop);
7758 ADD_INSNL(ret, line_node, jump, unmatched);
7759 break;
7760 }
7761 case NODE_OR: {
7762 LABEL *match_succeeded, *fin;
7763 match_succeeded = NEW_LABEL(line);
7764 fin = NEW_LABEL(line);
7765
7766 ADD_INSN(ret, line_node, dup); // (1)
7767 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));
7768 ADD_LABEL(ret, match_succeeded);
7769 ADD_INSN(ret, line_node, pop);
7770 ADD_INSNL(ret, line_node, jump, matched);
7771 ADD_INSN(ret, line_node, putnil);
7772 ADD_LABEL(ret, fin);
7773 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7774 break;
7775 }
7776 default:
7777 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7778 }
7779 return COMPILE_OK;
7780}
7781
7782static int
7783iseq_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)
7784{
7785 LABEL *fin = NEW_LABEL(nd_line(node));
7786 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7787 ADD_LABEL(ret, fin);
7788 return COMPILE_OK;
7789}
7790
7791static int
7792iseq_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)
7793{
7794 const NODE *line_node = node;
7795
7796 if (RNODE_ARYPTN(node)->nd_pconst) {
7797 ADD_INSN(ret, line_node, dup); // (1)
7798 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7799 if (in_single_pattern) {
7800 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7801 }
7802 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7803 if (in_single_pattern) {
7804 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7805 }
7806 ADD_INSNL(ret, line_node, branchunless, match_failed);
7807 }
7808 return COMPILE_OK;
7809}
7810
7811
7812static int
7813iseq_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)
7814{
7815 const NODE *line_node = node;
7816
7817 // NOTE: this optimization allows us to re-use the #deconstruct value
7818 // (or its absence).
7819 if (use_deconstructed_cache) {
7820 // If value is nil then we haven't tried to deconstruct
7821 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7822 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7823
7824 // If false then the value is not deconstructable
7825 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7826 ADD_INSNL(ret, line_node, branchunless, match_failed);
7827
7828 // Drop value, add deconstructed to the stack and jump
7829 ADD_INSN(ret, line_node, pop); // (1)
7830 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7831 ADD_INSNL(ret, line_node, jump, deconstructed);
7832 }
7833 else {
7834 ADD_INSNL(ret, line_node, jump, deconstruct);
7835 }
7836
7837 ADD_LABEL(ret, deconstruct);
7838 ADD_INSN(ret, line_node, dup);
7839 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7840 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7841
7842 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7843 if (use_deconstructed_cache) {
7844 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7845 }
7846
7847 if (in_single_pattern) {
7848 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7849 }
7850
7851 ADD_INSNL(ret, line_node, branchunless, match_failed);
7852
7853 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7854
7855 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7856 if (use_deconstructed_cache) {
7857 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7858 }
7859
7860 ADD_INSN(ret, line_node, dup);
7861 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7862 ADD_INSNL(ret, line_node, branchunless, type_error);
7863
7864 ADD_LABEL(ret, deconstructed);
7865
7866 return COMPILE_OK;
7867}
7868
7869static int
7870iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7871{
7872 /*
7873 * if match_succeeded?
7874 * goto match_succeeded
7875 * end
7876 * error_string = FrozenCore.sprintf(errmsg, matchee)
7877 * key_error_p = false
7878 * match_succeeded:
7879 */
7880 const int line = nd_line(node);
7881 const NODE *line_node = node;
7882 LABEL *match_succeeded = NEW_LABEL(line);
7883
7884 ADD_INSN(ret, line_node, dup);
7885 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7886
7887 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7888 ADD_INSN1(ret, line_node, putobject, errmsg);
7889 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7890 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7891 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7892
7893 ADD_INSN1(ret, line_node, putobject, Qfalse);
7894 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7895
7896 ADD_INSN(ret, line_node, pop);
7897 ADD_INSN(ret, line_node, pop);
7898 ADD_LABEL(ret, match_succeeded);
7899
7900 return COMPILE_OK;
7901}
7902
7903static int
7904iseq_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)
7905{
7906 /*
7907 * if match_succeeded?
7908 * goto match_succeeded
7909 * end
7910 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7911 * key_error_p = false
7912 * match_succeeded:
7913 */
7914 const int line = nd_line(node);
7915 const NODE *line_node = node;
7916 LABEL *match_succeeded = NEW_LABEL(line);
7917
7918 ADD_INSN(ret, line_node, dup);
7919 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7920
7921 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7922 ADD_INSN1(ret, line_node, putobject, errmsg);
7923 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7924 ADD_INSN(ret, line_node, dup);
7925 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7926 ADD_INSN1(ret, line_node, putobject, pattern_length);
7927 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7928 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7929
7930 ADD_INSN1(ret, line_node, putobject, Qfalse);
7931 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7932
7933 ADD_INSN(ret, line_node, pop);
7934 ADD_INSN(ret, line_node, pop);
7935 ADD_LABEL(ret, match_succeeded);
7936
7937 return COMPILE_OK;
7938}
7939
7940static int
7941iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7942{
7943 /*
7944 * if match_succeeded?
7945 * goto match_succeeded
7946 * end
7947 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7948 * key_error_p = false
7949 * match_succeeded:
7950 */
7951 const int line = nd_line(node);
7952 const NODE *line_node = node;
7953 LABEL *match_succeeded = NEW_LABEL(line);
7954
7955 ADD_INSN(ret, line_node, dup);
7956 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7957
7958 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7959 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7960 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7961 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7962 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7963 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7964
7965 ADD_INSN1(ret, line_node, putobject, Qfalse);
7966 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7967
7968 ADD_INSN(ret, line_node, pop);
7969 ADD_INSN(ret, line_node, pop);
7970
7971 ADD_LABEL(ret, match_succeeded);
7972 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7973 ADD_INSN(ret, line_node, pop);
7974 ADD_INSN(ret, line_node, pop);
7975
7976 return COMPILE_OK;
7977}
7978
7979static int
7980compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7981{
7982 const NODE *pattern;
7983 const NODE *node = orig_node;
7984 LABEL *endlabel, *elselabel;
7985 DECL_ANCHOR(head);
7986 DECL_ANCHOR(body_seq);
7987 DECL_ANCHOR(cond_seq);
7988 int line;
7989 enum node_type type;
7990 const NODE *line_node;
7991 VALUE branches = 0;
7992 int branch_id = 0;
7993 bool single_pattern;
7994
7995 INIT_ANCHOR(head);
7996 INIT_ANCHOR(body_seq);
7997 INIT_ANCHOR(cond_seq);
7998
7999 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8000
8001 node = RNODE_CASE3(node)->nd_body;
8002 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8003 type = nd_type(node);
8004 line = nd_line(node);
8005 line_node = node;
8006 single_pattern = !RNODE_IN(node)->nd_next;
8007
8008 endlabel = NEW_LABEL(line);
8009 elselabel = NEW_LABEL(line);
8010
8011 if (single_pattern) {
8012 /* allocate stack for ... */
8013 ADD_INSN(head, line_node, putnil); /* key_error_key */
8014 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8015 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8016 ADD_INSN(head, line_node, putnil); /* error_string */
8017 }
8018 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8019
8020 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8021
8022 ADD_SEQ(ret, head); /* case VAL */
8023
8024 while (type == NODE_IN) {
8025 LABEL *l1;
8026
8027 if (branch_id) {
8028 ADD_INSN(body_seq, line_node, putnil);
8029 }
8030 l1 = NEW_LABEL(line);
8031 ADD_LABEL(body_seq, l1);
8032 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8033
8034 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8035 add_trace_branch_coverage(
8036 iseq,
8037 body_seq,
8038 nd_code_loc(coverage_node),
8039 nd_node_id(coverage_node),
8040 branch_id++,
8041 "in",
8042 branches);
8043
8044 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8045 ADD_INSNL(body_seq, line_node, jump, endlabel);
8046
8047 pattern = RNODE_IN(node)->nd_head;
8048 if (pattern) {
8049 int pat_line = nd_line(pattern);
8050 LABEL *next_pat = NEW_LABEL(pat_line);
8051 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8052 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8053 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8054 ADD_LABEL(cond_seq, next_pat);
8055 LABEL_UNREMOVABLE(next_pat);
8056 }
8057 else {
8058 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8059 return COMPILE_NG;
8060 }
8061
8062 node = RNODE_IN(node)->nd_next;
8063 if (!node) {
8064 break;
8065 }
8066 type = nd_type(node);
8067 line = nd_line(node);
8068 line_node = node;
8069 }
8070 /* else */
8071 if (node) {
8072 ADD_LABEL(cond_seq, elselabel);
8073 ADD_INSN(cond_seq, line_node, pop);
8074 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8075 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8076 CHECK(COMPILE_(cond_seq, "else", node, popped));
8077 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8078 ADD_INSN(cond_seq, line_node, putnil);
8079 if (popped) {
8080 ADD_INSN(cond_seq, line_node, putnil);
8081 }
8082 }
8083 else {
8084 debugs("== else (implicit)\n");
8085 ADD_LABEL(cond_seq, elselabel);
8086 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8087 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8088
8089 if (single_pattern) {
8090 /*
8091 * if key_error_p
8092 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8093 * else
8094 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8095 * end
8096 */
8097 LABEL *key_error, *fin;
8098 struct rb_callinfo_kwarg *kw_arg;
8099
8100 key_error = NEW_LABEL(line);
8101 fin = NEW_LABEL(line);
8102
8103 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8104 kw_arg->references = 0;
8105 kw_arg->keyword_len = 2;
8106 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8107 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8108
8109 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8110 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8111 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8112 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8113 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8114 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8115 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8116 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8117 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8118 ADD_INSNL(cond_seq, orig_node, jump, fin);
8119
8120 ADD_LABEL(cond_seq, key_error);
8121 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8122 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8123 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8124 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8125 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8126 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8127 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8128 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8129 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8130 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8131
8132 ADD_LABEL(cond_seq, fin);
8133 }
8134 else {
8135 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8136 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8137 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8138 }
8139 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8140 if (!popped) {
8141 ADD_INSN(cond_seq, orig_node, putnil);
8142 }
8143 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8144 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8145 if (popped) {
8146 ADD_INSN(cond_seq, line_node, putnil);
8147 }
8148 }
8149
8150 ADD_SEQ(ret, cond_seq);
8151 ADD_SEQ(ret, body_seq);
8152 ADD_LABEL(ret, endlabel);
8153 return COMPILE_OK;
8154}
8155
8156#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8157#undef CASE3_BI_OFFSET_ERROR_STRING
8158#undef CASE3_BI_OFFSET_KEY_ERROR_P
8159#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8160#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8161
8162static int
8163compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8164{
8165 const int line = (int)nd_line(node);
8166 const NODE *line_node = node;
8167
8168 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8169 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8170 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8171 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8172 VALUE branches = Qfalse;
8173
8174 struct iseq_compile_data_ensure_node_stack enl;
8175
8176 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8177 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8178 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8179 LABEL *end_label = NEW_LABEL(line);
8180 LABEL *adjust_label = NEW_LABEL(line);
8181
8182 LABEL *next_catch_label = NEW_LABEL(line);
8183 LABEL *tmp_label = NULL;
8184
8185 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8186 push_ensure_entry(iseq, &enl, NULL, NULL);
8187
8188 if (RNODE_WHILE(node)->nd_state == 1) {
8189 ADD_INSNL(ret, line_node, jump, next_label);
8190 }
8191 else {
8192 tmp_label = NEW_LABEL(line);
8193 ADD_INSNL(ret, line_node, jump, tmp_label);
8194 }
8195 ADD_LABEL(ret, adjust_label);
8196 ADD_INSN(ret, line_node, putnil);
8197 ADD_LABEL(ret, next_catch_label);
8198 ADD_INSN(ret, line_node, pop);
8199 ADD_INSNL(ret, line_node, jump, next_label);
8200 if (tmp_label) ADD_LABEL(ret, tmp_label);
8201
8202 ADD_LABEL(ret, redo_label);
8203 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8204
8205 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8206 add_trace_branch_coverage(
8207 iseq,
8208 ret,
8209 nd_code_loc(coverage_node),
8210 nd_node_id(coverage_node),
8211 0,
8212 "body",
8213 branches);
8214
8215 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8216 ADD_LABEL(ret, next_label); /* next */
8217
8218 if (type == NODE_WHILE) {
8219 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8220 redo_label, end_label));
8221 }
8222 else {
8223 /* until */
8224 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8225 end_label, redo_label));
8226 }
8227
8228 ADD_LABEL(ret, end_label);
8229 ADD_ADJUST_RESTORE(ret, adjust_label);
8230
8231 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8232 /* ADD_INSN(ret, line_node, putundef); */
8233 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8234 return COMPILE_NG;
8235 }
8236 else {
8237 ADD_INSN(ret, line_node, putnil);
8238 }
8239
8240 ADD_LABEL(ret, break_label); /* break */
8241
8242 if (popped) {
8243 ADD_INSN(ret, line_node, pop);
8244 }
8245
8246 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8247 break_label);
8248 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8249 next_catch_label);
8250 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8251 ISEQ_COMPILE_DATA(iseq)->redo_label);
8252
8253 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8254 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8255 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8256 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8257 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8258 return COMPILE_OK;
8259}
8260
8261static int
8262compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8263{
8264 const int line = nd_line(node);
8265 const NODE *line_node = node;
8266 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8267 LABEL *retry_label = NEW_LABEL(line);
8268 LABEL *retry_end_l = NEW_LABEL(line);
8269 const rb_iseq_t *child_iseq;
8270
8271 ADD_LABEL(ret, retry_label);
8272 if (nd_type_p(node, NODE_FOR)) {
8273 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8274
8275 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8276 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8277 ISEQ_TYPE_BLOCK, line);
8278 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8279 }
8280 else {
8281 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8282 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8283 ISEQ_TYPE_BLOCK, line);
8284 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8285 }
8286
8287 {
8288 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8289 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8290 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8291 //
8292 // Normally, "send" instruction is at the last.
8293 // However, qcall under branch coverage measurement adds some instructions after the "send".
8294 //
8295 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8296 INSN *iobj;
8297 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8298 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8299 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8300 iobj = (INSN*) get_prev_insn(iobj);
8301 }
8302 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8303
8304 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8305 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8306 if (&iobj->link == LAST_ELEMENT(ret)) {
8307 ret->last = (LINK_ELEMENT*) retry_end_l;
8308 }
8309 }
8310
8311 if (popped) {
8312 ADD_INSN(ret, line_node, pop);
8313 }
8314
8315 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8316
8317 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8318 return COMPILE_OK;
8319}
8320
8321static int
8322compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8323{
8324 /* massign to var in "for"
8325 * (args.length == 1 && Array.try_convert(args[0])) || args
8326 */
8327 const NODE *line_node = node;
8328 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8329 LABEL *not_single = NEW_LABEL(nd_line(var));
8330 LABEL *not_ary = NEW_LABEL(nd_line(var));
8331 CHECK(COMPILE(ret, "for var", var));
8332 ADD_INSN(ret, line_node, dup);
8333 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8334 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8335 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8336 ADD_INSNL(ret, line_node, branchunless, not_single);
8337 ADD_INSN(ret, line_node, dup);
8338 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8339 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8340 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8341 ADD_INSN(ret, line_node, swap);
8342 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8343 ADD_INSN(ret, line_node, dup);
8344 ADD_INSNL(ret, line_node, branchunless, not_ary);
8345 ADD_INSN(ret, line_node, swap);
8346 ADD_LABEL(ret, not_ary);
8347 ADD_INSN(ret, line_node, pop);
8348 ADD_LABEL(ret, not_single);
8349 return COMPILE_OK;
8350}
8351
8352static int
8353compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8354{
8355 const NODE *line_node = node;
8356 unsigned long throw_flag = 0;
8357
8358 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8359 /* while/until */
8360 LABEL *splabel = NEW_LABEL(0);
8361 ADD_LABEL(ret, splabel);
8362 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8363 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8364 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8365 add_ensure_iseq(ret, iseq, 0);
8366 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8367 ADD_ADJUST_RESTORE(ret, splabel);
8368
8369 if (!popped) {
8370 ADD_INSN(ret, line_node, putnil);
8371 }
8372 }
8373 else {
8374 const rb_iseq_t *ip = iseq;
8375
8376 while (ip) {
8377 if (!ISEQ_COMPILE_DATA(ip)) {
8378 ip = 0;
8379 break;
8380 }
8381
8382 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8383 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8384 }
8385 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8386 throw_flag = 0;
8387 }
8388 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8389 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8390 return COMPILE_NG;
8391 }
8392 else {
8393 ip = ISEQ_BODY(ip)->parent_iseq;
8394 continue;
8395 }
8396
8397 /* escape from block */
8398 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8399 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8400 if (popped) {
8401 ADD_INSN(ret, line_node, pop);
8402 }
8403 return COMPILE_OK;
8404 }
8405 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8406 return COMPILE_NG;
8407 }
8408 return COMPILE_OK;
8409}
8410
8411static int
8412compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8413{
8414 const NODE *line_node = node;
8415 unsigned long throw_flag = 0;
8416
8417 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8418 LABEL *splabel = NEW_LABEL(0);
8419 debugs("next in while loop\n");
8420 ADD_LABEL(ret, splabel);
8421 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8422 add_ensure_iseq(ret, iseq, 0);
8423 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8424 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8425 ADD_ADJUST_RESTORE(ret, splabel);
8426 if (!popped) {
8427 ADD_INSN(ret, line_node, putnil);
8428 }
8429 }
8430 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8431 LABEL *splabel = NEW_LABEL(0);
8432 debugs("next in block\n");
8433 ADD_LABEL(ret, splabel);
8434 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8435 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8436 add_ensure_iseq(ret, iseq, 0);
8437 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8438 ADD_ADJUST_RESTORE(ret, splabel);
8439
8440 if (!popped) {
8441 ADD_INSN(ret, line_node, putnil);
8442 }
8443 }
8444 else {
8445 const rb_iseq_t *ip = iseq;
8446
8447 while (ip) {
8448 if (!ISEQ_COMPILE_DATA(ip)) {
8449 ip = 0;
8450 break;
8451 }
8452
8453 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8454 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8455 /* while loop */
8456 break;
8457 }
8458 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8459 break;
8460 }
8461 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8462 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8463 return COMPILE_NG;
8464 }
8465
8466 ip = ISEQ_BODY(ip)->parent_iseq;
8467 }
8468 if (ip != 0) {
8469 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8470 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8471
8472 if (popped) {
8473 ADD_INSN(ret, line_node, pop);
8474 }
8475 }
8476 else {
8477 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8478 return COMPILE_NG;
8479 }
8480 }
8481 return COMPILE_OK;
8482}
8483
8484static int
8485compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8486{
8487 const NODE *line_node = node;
8488
8489 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8490 LABEL *splabel = NEW_LABEL(0);
8491 debugs("redo in while");
8492 ADD_LABEL(ret, splabel);
8493 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8494 add_ensure_iseq(ret, iseq, 0);
8495 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8496 ADD_ADJUST_RESTORE(ret, splabel);
8497 if (!popped) {
8498 ADD_INSN(ret, line_node, putnil);
8499 }
8500 }
8501 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8502 LABEL *splabel = NEW_LABEL(0);
8503
8504 debugs("redo in block");
8505 ADD_LABEL(ret, splabel);
8506 add_ensure_iseq(ret, iseq, 0);
8507 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8508 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8509 ADD_ADJUST_RESTORE(ret, splabel);
8510
8511 if (!popped) {
8512 ADD_INSN(ret, line_node, putnil);
8513 }
8514 }
8515 else {
8516 const rb_iseq_t *ip = iseq;
8517
8518 while (ip) {
8519 if (!ISEQ_COMPILE_DATA(ip)) {
8520 ip = 0;
8521 break;
8522 }
8523
8524 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8525 break;
8526 }
8527 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8528 break;
8529 }
8530 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8531 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8532 return COMPILE_NG;
8533 }
8534
8535 ip = ISEQ_BODY(ip)->parent_iseq;
8536 }
8537 if (ip != 0) {
8538 ADD_INSN(ret, line_node, putnil);
8539 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8540
8541 if (popped) {
8542 ADD_INSN(ret, line_node, pop);
8543 }
8544 }
8545 else {
8546 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8547 return COMPILE_NG;
8548 }
8549 }
8550 return COMPILE_OK;
8551}
8552
8553static int
8554compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8555{
8556 const NODE *line_node = node;
8557
8558 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8559 ADD_INSN(ret, line_node, putnil);
8560 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8561
8562 if (popped) {
8563 ADD_INSN(ret, line_node, pop);
8564 }
8565 }
8566 else {
8567 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8568 return COMPILE_NG;
8569 }
8570 return COMPILE_OK;
8571}
8572
8573static int
8574compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8575{
8576 const int line = nd_line(node);
8577 const NODE *line_node = node;
8578 LABEL *lstart = NEW_LABEL(line);
8579 LABEL *lend = NEW_LABEL(line);
8580 LABEL *lcont = NEW_LABEL(line);
8581 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8582 rb_str_concat(rb_str_new2("rescue in "),
8583 ISEQ_BODY(iseq)->location.label),
8584 ISEQ_TYPE_RESCUE, line);
8585
8586 lstart->rescued = LABEL_RESCUE_BEG;
8587 lend->rescued = LABEL_RESCUE_END;
8588 ADD_LABEL(ret, lstart);
8589
8590 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8591 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8592 {
8593 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8594 }
8595 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8596
8597 ADD_LABEL(ret, lend);
8598 if (RNODE_RESCUE(node)->nd_else) {
8599 ADD_INSN(ret, line_node, pop);
8600 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8601 }
8602 ADD_INSN(ret, line_node, nop);
8603 ADD_LABEL(ret, lcont);
8604
8605 if (popped) {
8606 ADD_INSN(ret, line_node, pop);
8607 }
8608
8609 /* register catch entry */
8610 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8611 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8612 return COMPILE_OK;
8613}
8614
8615static int
8616compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8617{
8618 const int line = nd_line(node);
8619 const NODE *line_node = node;
8620 const NODE *resq = node;
8621 const NODE *narg;
8622 LABEL *label_miss, *label_hit;
8623
8624 while (resq) {
8625 label_miss = NEW_LABEL(line);
8626 label_hit = NEW_LABEL(line);
8627
8628 narg = RNODE_RESBODY(resq)->nd_args;
8629 if (narg) {
8630 switch (nd_type(narg)) {
8631 case NODE_LIST:
8632 while (narg) {
8633 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8634 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8635 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8636 ADD_INSNL(ret, line_node, branchif, label_hit);
8637 narg = RNODE_LIST(narg)->nd_next;
8638 }
8639 break;
8640 case NODE_SPLAT:
8641 case NODE_ARGSCAT:
8642 case NODE_ARGSPUSH:
8643 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8644 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8645 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8646 ADD_INSNL(ret, line_node, branchif, label_hit);
8647 break;
8648 default:
8649 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8650 }
8651 }
8652 else {
8653 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8654 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8655 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8656 ADD_INSNL(ret, line_node, branchif, label_hit);
8657 }
8658 ADD_INSNL(ret, line_node, jump, label_miss);
8659 ADD_LABEL(ret, label_hit);
8660 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8661
8662 if (RNODE_RESBODY(resq)->nd_exc_var) {
8663 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8664 }
8665
8666 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) {
8667 // empty body
8668 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8669 }
8670 else {
8671 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8672 }
8673
8674 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8675 ADD_INSN(ret, line_node, nop);
8676 }
8677 ADD_INSN(ret, line_node, leave);
8678 ADD_LABEL(ret, label_miss);
8679 resq = RNODE_RESBODY(resq)->nd_next;
8680 }
8681 return COMPILE_OK;
8682}
8683
8684static int
8685compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8686{
8687 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8688 const NODE *line_node = node;
8689 DECL_ANCHOR(ensr);
8690 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8691 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8692 ISEQ_TYPE_ENSURE, line);
8693 LABEL *lstart = NEW_LABEL(line);
8694 LABEL *lend = NEW_LABEL(line);
8695 LABEL *lcont = NEW_LABEL(line);
8696 LINK_ELEMENT *last;
8697 int last_leave = 0;
8698 struct ensure_range er;
8699 struct iseq_compile_data_ensure_node_stack enl;
8700 struct ensure_range *erange;
8701
8702 INIT_ANCHOR(ensr);
8703 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8704 last = ensr->last;
8705 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8706
8707 er.begin = lstart;
8708 er.end = lend;
8709 er.next = 0;
8710 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8711
8712 ADD_LABEL(ret, lstart);
8713 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8714 ADD_LABEL(ret, lend);
8715 ADD_SEQ(ret, ensr);
8716 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8717 ADD_LABEL(ret, lcont);
8718 if (last_leave) ADD_INSN(ret, line_node, pop);
8719
8720 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8721 if (lstart->link.next != &lend->link) {
8722 while (erange) {
8723 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8724 ensure, lcont);
8725 erange = erange->next;
8726 }
8727 }
8728
8729 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8730 return COMPILE_OK;
8731}
8732
8733static int
8734compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8735{
8736 const NODE *line_node = node;
8737
8738 if (iseq) {
8739 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8740 const rb_iseq_t *is = iseq;
8741 enum rb_iseq_type t = type;
8742 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8743 LABEL *splabel = 0;
8744
8745 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8746 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8747 t = ISEQ_BODY(is)->type;
8748 }
8749 switch (t) {
8750 case ISEQ_TYPE_TOP:
8751 case ISEQ_TYPE_MAIN:
8752 if (retval) {
8753 rb_warn("argument of top-level return is ignored");
8754 }
8755 if (is == iseq) {
8756 /* plain top-level, leave directly */
8757 type = ISEQ_TYPE_METHOD;
8758 }
8759 break;
8760 default:
8761 break;
8762 }
8763
8764 if (type == ISEQ_TYPE_METHOD) {
8765 splabel = NEW_LABEL(0);
8766 ADD_LABEL(ret, splabel);
8767 ADD_ADJUST(ret, line_node, 0);
8768 }
8769
8770 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8771
8772 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8773 add_ensure_iseq(ret, iseq, 1);
8774 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8775 ADD_INSN(ret, line_node, leave);
8776 ADD_ADJUST_RESTORE(ret, splabel);
8777
8778 if (!popped) {
8779 ADD_INSN(ret, line_node, putnil);
8780 }
8781 }
8782 else {
8783 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8784 if (popped) {
8785 ADD_INSN(ret, line_node, pop);
8786 }
8787 }
8788 }
8789 return COMPILE_OK;
8790}
8791
8792static bool
8793drop_unreachable_return(LINK_ANCHOR *ret)
8794{
8795 LINK_ELEMENT *i = ret->last, *last;
8796 if (!i) return false;
8797 if (IS_TRACE(i)) i = i->prev;
8798 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8799 last = i = i->prev;
8800 if (IS_ADJUST(i)) i = i->prev;
8801 if (!IS_INSN(i)) return false;
8802 switch (INSN_OF(i)) {
8803 case BIN(leave):
8804 case BIN(jump):
8805 break;
8806 default:
8807 return false;
8808 }
8809 (ret->last = last->prev)->next = NULL;
8810 return true;
8811}
8812
8813static int
8814compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8815{
8816 CHECK(COMPILE_(ret, "nd_body", node, popped));
8817
8818 if (!popped && !all_string_result_p(node)) {
8819 const NODE *line_node = node;
8820 const unsigned int flag = VM_CALL_FCALL;
8821
8822 // Note, this dup could be removed if we are willing to change anytostring. It pops
8823 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8824 ADD_INSN(ret, line_node, dup);
8825 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8826 ADD_INSN(ret, line_node, anytostring);
8827 }
8828 return COMPILE_OK;
8829}
8830
8831static void
8832compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8833{
8834 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8835
8836 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8837 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8838}
8839
8840static LABEL *
8841qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8842{
8843 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8844 VALUE br = 0;
8845
8846 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8847 *branches = br;
8848 ADD_INSN(recv, line_node, dup);
8849 ADD_INSNL(recv, line_node, branchnil, else_label);
8850 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8851 return else_label;
8852}
8853
8854static void
8855qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8856{
8857 LABEL *end_label;
8858 if (!else_label) return;
8859 end_label = NEW_LABEL(nd_line(line_node));
8860 ADD_INSNL(ret, line_node, jump, end_label);
8861 ADD_LABEL(ret, else_label);
8862 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8863 ADD_LABEL(ret, end_label);
8864}
8865
8866static int
8867compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8868{
8869 /* optimization shortcut
8870 * "literal".freeze -> opt_str_freeze("literal")
8871 */
8872 if (get_nd_recv(node) &&
8873 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8874 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8875 get_nd_args(node) == NULL &&
8876 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8877 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8878 VALUE str = get_string_value(get_nd_recv(node));
8879 if (get_node_call_nd_mid(node) == idUMinus) {
8880 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8881 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8882 }
8883 else {
8884 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8885 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8886 }
8887 RB_OBJ_WRITTEN(iseq, Qundef, str);
8888 if (popped) {
8889 ADD_INSN(ret, line_node, pop);
8890 }
8891 return TRUE;
8892 }
8893 /* optimization shortcut
8894 * obj["literal"] -> opt_aref_with(obj, "literal")
8895 */
8896 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8897 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8898 (nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
8899 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8900 !frozen_string_literal_p(iseq) &&
8901 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8902 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8903 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8904 ADD_INSN2(ret, line_node, opt_aref_with, str,
8905 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8906 RB_OBJ_WRITTEN(iseq, Qundef, str);
8907 if (popped) {
8908 ADD_INSN(ret, line_node, pop);
8909 }
8910 return TRUE;
8911 }
8912 return FALSE;
8913}
8914
8915static int
8916iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8917{
8918 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8919}
8920
8921static const struct rb_builtin_function *
8922iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8923{
8924 int i;
8925 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8926 for (i=0; table[i].index != -1; i++) {
8927 if (strcmp(table[i].name, name) == 0) {
8928 return &table[i];
8929 }
8930 }
8931 return NULL;
8932}
8933
8934static const char *
8935iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8936{
8937 const char *name = rb_id2name(mid);
8938 static const char prefix[] = "__builtin_";
8939 const size_t prefix_len = sizeof(prefix) - 1;
8940
8941 switch (type) {
8942 case NODE_CALL:
8943 if (recv) {
8944 switch (nd_type(recv)) {
8945 case NODE_VCALL:
8946 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8947 return name;
8948 }
8949 break;
8950 case NODE_CONST:
8951 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8952 return name;
8953 }
8954 break;
8955 default: break;
8956 }
8957 }
8958 break;
8959 case NODE_VCALL:
8960 case NODE_FCALL:
8961 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8962 return &name[prefix_len];
8963 }
8964 break;
8965 default: break;
8966 }
8967 return NULL;
8968}
8969
8970static int
8971delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8972{
8973
8974 if (argc == 0) {
8975 *pstart_index = 0;
8976 return TRUE;
8977 }
8978 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8979 unsigned int start=0;
8980
8981 // local_table: [p1, p2, p3, l1, l2, l3]
8982 // arguments: [p3, l1, l2] -> 2
8983 for (start = 0;
8984 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8985 start++) {
8986 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8987
8988 for (unsigned int i=start; i-start<argc; i++) {
8989 if (IS_INSN(elem) &&
8990 INSN_OF(elem) == BIN(getlocal)) {
8991 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8992 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8993
8994 if (local_level == 0) {
8995 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8996 if (0) { // for debug
8997 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8998 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8999 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9000 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9001 }
9002 if (i == index) {
9003 elem = elem->next;
9004 continue; /* for */
9005 }
9006 else {
9007 goto next;
9008 }
9009 }
9010 else {
9011 goto fail; // level != 0 is unsupported
9012 }
9013 }
9014 else {
9015 goto fail; // insn is not a getlocal
9016 }
9017 }
9018 goto success;
9019 next:;
9020 }
9021 fail:
9022 return FALSE;
9023 success:
9024 *pstart_index = start;
9025 return TRUE;
9026 }
9027 else {
9028 return FALSE;
9029 }
9030}
9031
9032// Compile Primitive.attr! :leaf, ...
9033static int
9034compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9035{
9036 VALUE symbol;
9037 VALUE string;
9038 if (!node) goto no_arg;
9039 while (node) {
9040 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9041 const NODE *next = RNODE_LIST(node)->nd_next;
9042
9043 node = RNODE_LIST(node)->nd_head;
9044 if (!node) goto no_arg;
9045 switch (nd_type(node)) {
9046 case NODE_SYM:
9047 symbol = rb_node_sym_string_val(node);
9048 break;
9049 default:
9050 goto bad_arg;
9051 }
9052
9053 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9054
9055 string = rb_sym2str(symbol);
9056 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9057 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9058 }
9059 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9060 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9061 }
9062 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9063 iseq_set_use_block(iseq);
9064 }
9065 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9066 // Let the iseq act like a C method in backtraces
9067 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9068 }
9069 else {
9070 goto unknown_arg;
9071 }
9072 node = next;
9073 }
9074 return COMPILE_OK;
9075 no_arg:
9076 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9077 return COMPILE_NG;
9078 non_symbol_arg:
9079 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9080 return COMPILE_NG;
9081 unknown_arg:
9082 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9083 return COMPILE_NG;
9084 bad_arg:
9085 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9086}
9087
9088static int
9089compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9090{
9091 VALUE name;
9092
9093 if (!node) goto no_arg;
9094 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9095 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9096 node = RNODE_LIST(node)->nd_head;
9097 if (!node) goto no_arg;
9098 switch (nd_type(node)) {
9099 case NODE_SYM:
9100 name = rb_node_sym_string_val(node);
9101 break;
9102 default:
9103 goto bad_arg;
9104 }
9105 if (!SYMBOL_P(name)) goto non_symbol_arg;
9106 if (!popped) {
9107 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9108 }
9109 return COMPILE_OK;
9110 no_arg:
9111 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9112 return COMPILE_NG;
9113 too_many_arg:
9114 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9115 return COMPILE_NG;
9116 non_symbol_arg:
9117 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9118 rb_builtin_class_name(name));
9119 return COMPILE_NG;
9120 bad_arg:
9121 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9122}
9123
9124static NODE *
9125mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9126{
9127 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9128 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9129 return RNODE_IF(node)->nd_body;
9130 }
9131 else {
9132 rb_bug("mandatory_node: can't find mandatory node");
9133 }
9134}
9135
9136static int
9137compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9138{
9139 // arguments
9140 struct rb_args_info args = {
9141 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9142 };
9143 rb_node_args_t args_node;
9144 rb_node_init(RNODE(&args_node), NODE_ARGS);
9145 args_node.nd_ainfo = args;
9146
9147 // local table without non-mandatory parameters
9148 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9149 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9150
9151 VALUE idtmp = 0;
9152 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9153 tbl->size = table_size;
9154
9155 int i;
9156
9157 // lead parameters
9158 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9159 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9160 }
9161 // local variables
9162 for (; i<table_size; i++) {
9163 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9164 }
9165
9166 rb_node_scope_t scope_node;
9167 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9168 scope_node.nd_tbl = tbl;
9169 scope_node.nd_body = mandatory_node(iseq, node);
9170 scope_node.nd_args = &args_node;
9171
9172 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9173
9174 const rb_iseq_t *mandatory_only_iseq =
9175 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9176 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9177 nd_line(line_node), NULL, 0,
9178 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9179 ISEQ_BODY(iseq)->variable.script_lines);
9180 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9181
9182 ALLOCV_END(idtmp);
9183 return COMPILE_OK;
9184}
9185
9186static int
9187compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9188 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9189{
9190 NODE *args_node = get_nd_args(node);
9191
9192 if (parent_block != NULL) {
9193 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9194 return COMPILE_NG;
9195 }
9196 else {
9197# define BUILTIN_INLINE_PREFIX "_bi"
9198 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9199 bool cconst = false;
9200 retry:;
9201 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9202
9203 if (bf == NULL) {
9204 if (strcmp("cstmt!", builtin_func) == 0 ||
9205 strcmp("cexpr!", builtin_func) == 0) {
9206 // ok
9207 }
9208 else if (strcmp("cconst!", builtin_func) == 0) {
9209 cconst = true;
9210 }
9211 else if (strcmp("cinit!", builtin_func) == 0) {
9212 // ignore
9213 return COMPILE_OK;
9214 }
9215 else if (strcmp("attr!", builtin_func) == 0) {
9216 return compile_builtin_attr(iseq, args_node);
9217 }
9218 else if (strcmp("arg!", builtin_func) == 0) {
9219 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9220 }
9221 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9222 if (popped) {
9223 rb_bug("mandatory_only? should be in if condition");
9224 }
9225 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9226 rb_bug("mandatory_only? should be put on top");
9227 }
9228
9229 ADD_INSN1(ret, line_node, putobject, Qfalse);
9230 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9231 }
9232 else if (1) {
9233 rb_bug("can't find builtin function:%s", builtin_func);
9234 }
9235 else {
9236 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9237 return COMPILE_NG;
9238 }
9239
9240 int inline_index = nd_line(node);
9241 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9242 builtin_func = inline_func;
9243 args_node = NULL;
9244 goto retry;
9245 }
9246
9247 if (cconst) {
9248 typedef VALUE(*builtin_func0)(void *, VALUE);
9249 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9250 ADD_INSN1(ret, line_node, putobject, const_val);
9251 return COMPILE_OK;
9252 }
9253
9254 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9255
9256 unsigned int flag = 0;
9257 struct rb_callinfo_kwarg *keywords = NULL;
9258 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9259
9260 if (FIX2INT(argc) != bf->argc) {
9261 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9262 builtin_func, bf->argc, FIX2INT(argc));
9263 return COMPILE_NG;
9264 }
9265
9266 unsigned int start_index;
9267 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9268 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9269 }
9270 else {
9271 ADD_SEQ(ret, args);
9272 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9273 }
9274
9275 if (popped) ADD_INSN(ret, line_node, pop);
9276 return COMPILE_OK;
9277 }
9278}
9279
9280static int
9281compile_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)
9282{
9283 /* call: obj.method(...)
9284 * fcall: func(...)
9285 * vcall: func
9286 */
9287 DECL_ANCHOR(recv);
9288 DECL_ANCHOR(args);
9289 ID mid = get_node_call_nd_mid(node);
9290 VALUE argc;
9291 unsigned int flag = 0;
9292 struct rb_callinfo_kwarg *keywords = NULL;
9293 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9294 LABEL *else_label = NULL;
9295 VALUE branches = Qfalse;
9296
9297 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9298
9299 INIT_ANCHOR(recv);
9300 INIT_ANCHOR(args);
9301#if OPT_SUPPORT_JOKE
9302 if (nd_type_p(node, NODE_VCALL)) {
9303 ID id_bitblt;
9304 ID id_answer;
9305
9306 CONST_ID(id_bitblt, "bitblt");
9307 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9308
9309 if (mid == id_bitblt) {
9310 ADD_INSN(ret, line_node, bitblt);
9311 return COMPILE_OK;
9312 }
9313 else if (mid == id_answer) {
9314 ADD_INSN(ret, line_node, answer);
9315 return COMPILE_OK;
9316 }
9317 }
9318 /* only joke */
9319 {
9320 ID goto_id;
9321 ID label_id;
9322
9323 CONST_ID(goto_id, "__goto__");
9324 CONST_ID(label_id, "__label__");
9325
9326 if (nd_type_p(node, NODE_FCALL) &&
9327 (mid == goto_id || mid == label_id)) {
9328 LABEL *label;
9329 st_data_t data;
9330 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9331 VALUE label_name;
9332
9333 if (!labels_table) {
9334 labels_table = st_init_numtable();
9335 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9336 }
9337 {
9338 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9339 return COMPILE_NG;
9340 }
9341
9342 if (mid == goto_id) {
9343 ADD_INSNL(ret, line_node, jump, label);
9344 }
9345 else {
9346 ADD_LABEL(ret, label);
9347 }
9348 return COMPILE_OK;
9349 }
9350 }
9351#endif
9352
9353 const char *builtin_func;
9354 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9355 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9356 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9357 }
9358
9359 /* receiver */
9360 if (!assume_receiver) {
9361 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9362 int idx, level;
9363
9364 if (mid == idCall &&
9365 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9366 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9367 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9368 }
9369 else if (private_recv_p(node)) {
9370 ADD_INSN(recv, node, putself);
9371 flag |= VM_CALL_FCALL;
9372 }
9373 else {
9374 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9375 }
9376
9377 if (type == NODE_QCALL) {
9378 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9379 }
9380 }
9381 else if (type == NODE_FCALL || type == NODE_VCALL) {
9382 ADD_CALL_RECEIVER(recv, line_node);
9383 }
9384 }
9385
9386 /* args */
9387 if (type != NODE_VCALL) {
9388 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9389 CHECK(!NIL_P(argc));
9390 }
9391 else {
9392 argc = INT2FIX(0);
9393 }
9394
9395 ADD_SEQ(ret, recv);
9396 ADD_SEQ(ret, args);
9397
9398 debugp_param("call args argc", argc);
9399 debugp_param("call method", ID2SYM(mid));
9400
9401 switch ((int)type) {
9402 case NODE_VCALL:
9403 flag |= VM_CALL_VCALL;
9404 /* VCALL is funcall, so fall through */
9405 case NODE_FCALL:
9406 flag |= VM_CALL_FCALL;
9407 }
9408
9409 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9410 ADD_INSN(ret, line_node, splatkw);
9411 }
9412 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9413
9414 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9415 if (popped) {
9416 ADD_INSN(ret, line_node, pop);
9417 }
9418 return COMPILE_OK;
9419}
9420
9421static int
9422compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9423{
9424 const int line = nd_line(node);
9425 VALUE argc;
9426 unsigned int flag = 0;
9427 int asgnflag = 0;
9428 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9429
9430 /*
9431 * a[x] (op)= y
9432 *
9433 * nil # nil
9434 * eval a # nil a
9435 * eval x # nil a x
9436 * dupn 2 # nil a x a x
9437 * send :[] # nil a x a[x]
9438 * eval y # nil a x a[x] y
9439 * send op # nil a x ret
9440 * setn 3 # ret a x ret
9441 * send []= # ret ?
9442 * pop # ret
9443 */
9444
9445 /*
9446 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9447 * NODE_OP_ASGN nd_recv
9448 * nd_args->nd_head
9449 * nd_args->nd_body
9450 * nd_mid
9451 */
9452
9453 if (!popped) {
9454 ADD_INSN(ret, node, putnil);
9455 }
9456 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9457 CHECK(asgnflag != -1);
9458 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9459 case NODE_ZLIST:
9460 argc = INT2FIX(0);
9461 break;
9462 default:
9463 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9464 CHECK(!NIL_P(argc));
9465 }
9466 int dup_argn = FIX2INT(argc) + 1;
9467 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9468 flag |= asgnflag;
9469 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9470
9471 if (id == idOROP || id == idANDOP) {
9472 /* a[x] ||= y or a[x] &&= y
9473
9474 unless/if a[x]
9475 a[x]= y
9476 else
9477 nil
9478 end
9479 */
9480 LABEL *label = NEW_LABEL(line);
9481 LABEL *lfin = NEW_LABEL(line);
9482
9483 ADD_INSN(ret, node, dup);
9484 if (id == idOROP) {
9485 ADD_INSNL(ret, node, branchif, label);
9486 }
9487 else { /* idANDOP */
9488 ADD_INSNL(ret, node, branchunless, label);
9489 }
9490 ADD_INSN(ret, node, pop);
9491
9492 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9493 if (!popped) {
9494 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9495 }
9496 if (flag & VM_CALL_ARGS_SPLAT) {
9497 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9498 ADD_INSN(ret, node, swap);
9499 ADD_INSN1(ret, node, splatarray, Qtrue);
9500 ADD_INSN(ret, node, swap);
9501 flag |= VM_CALL_ARGS_SPLAT_MUT;
9502 }
9503 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9504 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9505 }
9506 else {
9507 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9508 }
9509 ADD_INSN(ret, node, pop);
9510 ADD_INSNL(ret, node, jump, lfin);
9511 ADD_LABEL(ret, label);
9512 if (!popped) {
9513 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9514 }
9515 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9516 ADD_LABEL(ret, lfin);
9517 }
9518 else {
9519 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9520 ADD_SEND(ret, node, id, INT2FIX(1));
9521 if (!popped) {
9522 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9523 }
9524 if (flag & VM_CALL_ARGS_SPLAT) {
9525 if (flag & VM_CALL_KW_SPLAT) {
9526 ADD_INSN1(ret, node, topn, INT2FIX(2));
9527 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9528 ADD_INSN1(ret, node, splatarray, Qtrue);
9529 flag |= VM_CALL_ARGS_SPLAT_MUT;
9530 }
9531 ADD_INSN(ret, node, swap);
9532 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9533 ADD_INSN1(ret, node, setn, INT2FIX(2));
9534 ADD_INSN(ret, node, pop);
9535 }
9536 else {
9537 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9538 ADD_INSN(ret, node, swap);
9539 ADD_INSN1(ret, node, splatarray, Qtrue);
9540 ADD_INSN(ret, node, swap);
9541 flag |= VM_CALL_ARGS_SPLAT_MUT;
9542 }
9543 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9544 }
9545 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9546 }
9547 else {
9548 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9549 }
9550 ADD_INSN(ret, node, pop);
9551 }
9552 return COMPILE_OK;
9553}
9554
9555static int
9556compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9557{
9558 const int line = nd_line(node);
9559 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9560 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9561 int asgnflag;
9562 LABEL *lfin = NEW_LABEL(line);
9563 LABEL *lcfin = NEW_LABEL(line);
9564 LABEL *lskip = 0;
9565 /*
9566 class C; attr_accessor :c; end
9567 r = C.new
9568 r.a &&= v # asgn2
9569
9570 eval r # r
9571 dup # r r
9572 eval r.a # r o
9573
9574 # or
9575 dup # r o o
9576 if lcfin # r o
9577 pop # r
9578 eval v # r v
9579 swap # v r
9580 topn 1 # v r v
9581 send a= # v ?
9582 jump lfin # v ?
9583
9584 lcfin: # r o
9585 swap # o r
9586
9587 lfin: # o ?
9588 pop # o
9589
9590 # or (popped)
9591 if lcfin # r
9592 eval v # r v
9593 send a= # ?
9594 jump lfin # ?
9595
9596 lcfin: # r
9597
9598 lfin: # ?
9599 pop #
9600
9601 # and
9602 dup # r o o
9603 unless lcfin
9604 pop # r
9605 eval v # r v
9606 swap # v r
9607 topn 1 # v r v
9608 send a= # v ?
9609 jump lfin # v ?
9610
9611 # others
9612 eval v # r o v
9613 send ?? # r w
9614 send a= # w
9615
9616 */
9617
9618 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9619 CHECK(asgnflag != -1);
9620 if (RNODE_OP_ASGN2(node)->nd_aid) {
9621 lskip = NEW_LABEL(line);
9622 ADD_INSN(ret, node, dup);
9623 ADD_INSNL(ret, node, branchnil, lskip);
9624 }
9625 ADD_INSN(ret, node, dup);
9626 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9627
9628 if (atype == idOROP || atype == idANDOP) {
9629 if (!popped) {
9630 ADD_INSN(ret, node, dup);
9631 }
9632 if (atype == idOROP) {
9633 ADD_INSNL(ret, node, branchif, lcfin);
9634 }
9635 else { /* idANDOP */
9636 ADD_INSNL(ret, node, branchunless, lcfin);
9637 }
9638 if (!popped) {
9639 ADD_INSN(ret, node, pop);
9640 }
9641 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9642 if (!popped) {
9643 ADD_INSN(ret, node, swap);
9644 ADD_INSN1(ret, node, topn, INT2FIX(1));
9645 }
9646 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9647 ADD_INSNL(ret, node, jump, lfin);
9648
9649 ADD_LABEL(ret, lcfin);
9650 if (!popped) {
9651 ADD_INSN(ret, node, swap);
9652 }
9653
9654 ADD_LABEL(ret, lfin);
9655 }
9656 else {
9657 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9658 ADD_SEND(ret, node, atype, INT2FIX(1));
9659 if (!popped) {
9660 ADD_INSN(ret, node, swap);
9661 ADD_INSN1(ret, node, topn, INT2FIX(1));
9662 }
9663 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9664 }
9665 if (lskip && popped) {
9666 ADD_LABEL(ret, lskip);
9667 }
9668 ADD_INSN(ret, node, pop);
9669 if (lskip && !popped) {
9670 ADD_LABEL(ret, lskip);
9671 }
9672 return COMPILE_OK;
9673}
9674
9675static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9676
9677static int
9678compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9679{
9680 const int line = nd_line(node);
9681 LABEL *lfin = 0;
9682 LABEL *lassign = 0;
9683 ID mid;
9684
9685 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9686 case NODE_COLON3:
9687 ADD_INSN1(ret, node, putobject, rb_cObject);
9688 break;
9689 case NODE_COLON2:
9690 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9691 break;
9692 default:
9693 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9694 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9695 return COMPILE_NG;
9696 }
9697 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9698 /* cref */
9699 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9700 lassign = NEW_LABEL(line);
9701 ADD_INSN(ret, node, dup); /* cref cref */
9702 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9703 ID2SYM(mid), Qtrue); /* cref bool */
9704 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9705 }
9706 ADD_INSN(ret, node, dup); /* cref cref */
9707 ADD_INSN1(ret, node, putobject, Qtrue);
9708 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9709
9710 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9711 lfin = NEW_LABEL(line);
9712 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9713 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9714 ADD_INSNL(ret, node, branchif, lfin);
9715 else /* idANDOP */
9716 ADD_INSNL(ret, node, branchunless, lfin);
9717 /* cref [obj] */
9718 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9719 if (lassign) ADD_LABEL(ret, lassign);
9720 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9721 /* cref value */
9722 if (popped)
9723 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9724 else {
9725 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9726 ADD_INSN(ret, node, swap); /* cref value value cref */
9727 }
9728 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9729 ADD_LABEL(ret, lfin); /* cref [value] */
9730 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9731 ADD_INSN(ret, node, pop); /* [value] */
9732 }
9733 else {
9734 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9735 /* cref obj value */
9736 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9737 /* cref value */
9738 ADD_INSN(ret, node, swap); /* value cref */
9739 if (!popped) {
9740 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9741 ADD_INSN(ret, node, swap); /* value value cref */
9742 }
9743 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9744 }
9745 return COMPILE_OK;
9746}
9747
9748static int
9749compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9750{
9751 const int line = nd_line(node);
9752 LABEL *lfin = NEW_LABEL(line);
9753 LABEL *lassign;
9754
9755 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9756 LABEL *lfinish[2];
9757 lfinish[0] = lfin;
9758 lfinish[1] = 0;
9759 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9760 lassign = lfinish[1];
9761 if (!lassign) {
9762 lassign = NEW_LABEL(line);
9763 }
9764 ADD_INSNL(ret, node, branchunless, lassign);
9765 }
9766 else {
9767 lassign = NEW_LABEL(line);
9768 }
9769
9770 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9771
9772 if (!popped) {
9773 ADD_INSN(ret, node, dup);
9774 }
9775
9776 if (type == NODE_OP_ASGN_AND) {
9777 ADD_INSNL(ret, node, branchunless, lfin);
9778 }
9779 else {
9780 ADD_INSNL(ret, node, branchif, lfin);
9781 }
9782
9783 if (!popped) {
9784 ADD_INSN(ret, node, pop);
9785 }
9786
9787 ADD_LABEL(ret, lassign);
9788 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9789 ADD_LABEL(ret, lfin);
9790 return COMPILE_OK;
9791}
9792
9793static int
9794compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9795{
9796 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9797 DECL_ANCHOR(args);
9798 int argc;
9799 unsigned int flag = 0;
9800 struct rb_callinfo_kwarg *keywords = NULL;
9801 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9802 int use_block = 1;
9803
9804 INIT_ANCHOR(args);
9805 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9806
9807 if (type == NODE_SUPER) {
9808 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9809 CHECK(!NIL_P(vargc));
9810 argc = FIX2INT(vargc);
9811 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9812 ADD_INSN(args, node, splatkw);
9813 }
9814
9815 if (flag & VM_CALL_ARGS_BLOCKARG) {
9816 use_block = 0;
9817 }
9818 }
9819 else {
9820 /* NODE_ZSUPER */
9821 int i;
9822 const rb_iseq_t *liseq = body->local_iseq;
9823 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9824 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9825 int lvar_level = get_lvar_level(iseq);
9826
9827 argc = local_body->param.lead_num;
9828
9829 /* normal arguments */
9830 for (i = 0; i < local_body->param.lead_num; i++) {
9831 int idx = local_body->local_table_size - i;
9832 ADD_GETLOCAL(args, node, idx, lvar_level);
9833 }
9834
9835 /* forward ... */
9836 if (local_body->param.flags.forwardable) {
9837 flag |= VM_CALL_FORWARDING;
9838 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9839 ADD_GETLOCAL(args, node, idx, lvar_level);
9840 }
9841
9842 if (local_body->param.flags.has_opt) {
9843 /* optional arguments */
9844 int j;
9845 for (j = 0; j < local_body->param.opt_num; j++) {
9846 int idx = local_body->local_table_size - (i + j);
9847 ADD_GETLOCAL(args, node, idx, lvar_level);
9848 }
9849 i += j;
9850 argc = i;
9851 }
9852 if (local_body->param.flags.has_rest) {
9853 /* rest argument */
9854 int idx = local_body->local_table_size - local_body->param.rest_start;
9855 ADD_GETLOCAL(args, node, idx, lvar_level);
9856 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9857
9858 argc = local_body->param.rest_start + 1;
9859 flag |= VM_CALL_ARGS_SPLAT;
9860 }
9861 if (local_body->param.flags.has_post) {
9862 /* post arguments */
9863 int post_len = local_body->param.post_num;
9864 int post_start = local_body->param.post_start;
9865
9866 if (local_body->param.flags.has_rest) {
9867 int j;
9868 for (j=0; j<post_len; j++) {
9869 int idx = local_body->local_table_size - (post_start + j);
9870 ADD_GETLOCAL(args, node, idx, lvar_level);
9871 }
9872 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9873 flag |= VM_CALL_ARGS_SPLAT_MUT;
9874 /* argc is settled at above */
9875 }
9876 else {
9877 int j;
9878 for (j=0; j<post_len; j++) {
9879 int idx = local_body->local_table_size - (post_start + j);
9880 ADD_GETLOCAL(args, node, idx, lvar_level);
9881 }
9882 argc = post_len + post_start;
9883 }
9884 }
9885
9886 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9887 int local_size = local_body->local_table_size;
9888 argc++;
9889
9890 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9891
9892 if (local_body->param.flags.has_kwrest) {
9893 int idx = local_body->local_table_size - local_kwd->rest_start;
9894 ADD_GETLOCAL(args, node, idx, lvar_level);
9895 RUBY_ASSERT(local_kwd->num > 0);
9896 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9897 }
9898 else {
9899 ADD_INSN1(args, node, newhash, INT2FIX(0));
9900 }
9901 for (i = 0; i < local_kwd->num; ++i) {
9902 ID id = local_kwd->table[i];
9903 int idx = local_size - get_local_var_idx(liseq, id);
9904 ADD_INSN1(args, node, putobject, ID2SYM(id));
9905 ADD_GETLOCAL(args, node, idx, lvar_level);
9906 }
9907 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9908 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9909 }
9910 else if (local_body->param.flags.has_kwrest) {
9911 int idx = local_body->local_table_size - local_kwd->rest_start;
9912 ADD_GETLOCAL(args, node, idx, lvar_level);
9913 argc++;
9914 flag |= VM_CALL_KW_SPLAT;
9915 }
9916 }
9917
9918 if (use_block && parent_block == NULL) {
9919 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9920 }
9921
9922 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9923 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9924 ADD_INSN(ret, node, putself);
9925 ADD_SEQ(ret, args);
9926
9927 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
9928
9929 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
9930 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
9931 }
9932 else {
9933 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
9934 }
9935
9936 if (popped) {
9937 ADD_INSN(ret, node, pop);
9938 }
9939 return COMPILE_OK;
9940}
9941
9942static int
9943compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9944{
9945 DECL_ANCHOR(args);
9946 VALUE argc;
9947 unsigned int flag = 0;
9948 struct rb_callinfo_kwarg *keywords = NULL;
9949
9950 INIT_ANCHOR(args);
9951
9952 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9953 case ISEQ_TYPE_TOP:
9954 case ISEQ_TYPE_MAIN:
9955 case ISEQ_TYPE_CLASS:
9956 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9957 return COMPILE_NG;
9958 default: /* valid */;
9959 }
9960
9961 if (RNODE_YIELD(node)->nd_head) {
9962 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9963 CHECK(!NIL_P(argc));
9964 }
9965 else {
9966 argc = INT2FIX(0);
9967 }
9968
9969 ADD_SEQ(ret, args);
9970 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9971 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9972
9973 if (popped) {
9974 ADD_INSN(ret, node, pop);
9975 }
9976
9977 int level = 0;
9978 const rb_iseq_t *tmp_iseq = iseq;
9979 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9980 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9981 }
9982 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9983
9984 return COMPILE_OK;
9985}
9986
9987static int
9988compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9989{
9990 DECL_ANCHOR(recv);
9991 DECL_ANCHOR(val);
9992
9993 INIT_ANCHOR(recv);
9994 INIT_ANCHOR(val);
9995 switch ((int)type) {
9996 case NODE_MATCH:
9997 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
9998 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9999 INT2FIX(0));
10000 break;
10001 case NODE_MATCH2:
10002 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10003 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10004 break;
10005 case NODE_MATCH3:
10006 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10007 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10008 break;
10009 }
10010
10011 ADD_SEQ(ret, recv);
10012 ADD_SEQ(ret, val);
10013 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10014
10015 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10016 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10017 }
10018
10019 if (popped) {
10020 ADD_INSN(ret, node, pop);
10021 }
10022 return COMPILE_OK;
10023}
10024
10025static int
10026compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10027{
10028 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10029 /* constant */
10030 VALUE segments;
10031 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10032 (segments = collect_const_segments(iseq, node))) {
10033 ISEQ_BODY(iseq)->ic_size++;
10034 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10035 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10036 }
10037 else {
10038 /* constant */
10039 DECL_ANCHOR(pref);
10040 DECL_ANCHOR(body);
10041
10042 INIT_ANCHOR(pref);
10043 INIT_ANCHOR(body);
10044 CHECK(compile_const_prefix(iseq, node, pref, body));
10045 if (LIST_INSN_SIZE_ZERO(pref)) {
10046 ADD_INSN(ret, node, putnil);
10047 ADD_SEQ(ret, body);
10048 }
10049 else {
10050 ADD_SEQ(ret, pref);
10051 ADD_SEQ(ret, body);
10052 }
10053 }
10054 }
10055 else {
10056 /* function call */
10057 ADD_CALL_RECEIVER(ret, node);
10058 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10059 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10060 }
10061 if (popped) {
10062 ADD_INSN(ret, node, pop);
10063 }
10064 return COMPILE_OK;
10065}
10066
10067static int
10068compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10069{
10070 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10071
10072 /* add cache insn */
10073 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10074 ISEQ_BODY(iseq)->ic_size++;
10075 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10076 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10077 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10078 }
10079 else {
10080 ADD_INSN1(ret, node, putobject, rb_cObject);
10081 ADD_INSN1(ret, node, putobject, Qtrue);
10082 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10083 }
10084
10085 if (popped) {
10086 ADD_INSN(ret, node, pop);
10087 }
10088 return COMPILE_OK;
10089}
10090
10091static int
10092compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10093{
10094 VALUE flag = INT2FIX(excl);
10095 const NODE *b = RNODE_DOT2(node)->nd_beg;
10096 const NODE *e = RNODE_DOT2(node)->nd_end;
10097
10098 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10099 if (!popped) {
10100 VALUE bv = optimized_range_item(b);
10101 VALUE ev = optimized_range_item(e);
10102 VALUE val = rb_range_new(bv, ev, excl);
10103 ADD_INSN1(ret, node, putobject, val);
10104 RB_OBJ_WRITTEN(iseq, Qundef, val);
10105 }
10106 }
10107 else {
10108 CHECK(COMPILE_(ret, "min", b, popped));
10109 CHECK(COMPILE_(ret, "max", e, popped));
10110 if (!popped) {
10111 ADD_INSN1(ret, node, newrange, flag);
10112 }
10113 }
10114 return COMPILE_OK;
10115}
10116
10117static int
10118compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10119{
10120 if (!popped) {
10121 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10122 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10123 }
10124 else {
10125 const rb_iseq_t *ip = iseq;
10126 int level = 0;
10127 while (ip) {
10128 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10129 break;
10130 }
10131 ip = ISEQ_BODY(ip)->parent_iseq;
10132 level++;
10133 }
10134 if (ip) {
10135 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10136 }
10137 else {
10138 ADD_INSN(ret, node, putnil);
10139 }
10140 }
10141 }
10142 return COMPILE_OK;
10143}
10144
10145static int
10146compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10147{
10148 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10149 LABEL *end_label = NEW_LABEL(nd_line(node));
10150 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10151
10152 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10153 /* required argument. do nothing */
10154 COMPILE_ERROR(ERROR_ARGS "unreachable");
10155 return COMPILE_NG;
10156 }
10157 else if (nd_type_p(default_value, NODE_SYM) ||
10158 nd_type_p(default_value, NODE_REGX) ||
10159 nd_type_p(default_value, NODE_LINE) ||
10160 nd_type_p(default_value, NODE_INTEGER) ||
10161 nd_type_p(default_value, NODE_FLOAT) ||
10162 nd_type_p(default_value, NODE_RATIONAL) ||
10163 nd_type_p(default_value, NODE_IMAGINARY) ||
10164 nd_type_p(default_value, NODE_NIL) ||
10165 nd_type_p(default_value, NODE_TRUE) ||
10166 nd_type_p(default_value, NODE_FALSE)) {
10167 COMPILE_ERROR(ERROR_ARGS "unreachable");
10168 return COMPILE_NG;
10169 }
10170 else {
10171 /* if keywordcheck(_kw_bits, nth_keyword)
10172 * kw = default_value
10173 * end
10174 */
10175 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10176 int keyword_idx = body->param.keyword->num;
10177
10178 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10179 ADD_INSNL(ret, node, branchif, end_label);
10180 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10181 ADD_LABEL(ret, end_label);
10182 }
10183 return COMPILE_OK;
10184}
10185
10186static int
10187compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10188{
10189 DECL_ANCHOR(recv);
10190 DECL_ANCHOR(args);
10191 unsigned int flag = 0;
10192 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10193 VALUE argc;
10194 LABEL *else_label = NULL;
10195 VALUE branches = Qfalse;
10196
10197 /* optimization shortcut
10198 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10199 */
10200 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10201 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10202 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10203 (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
10204 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10205 !frozen_string_literal_p(iseq) &&
10206 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10207 {
10208 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10209 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10210 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10211 if (!popped) {
10212 ADD_INSN(ret, node, swap);
10213 ADD_INSN1(ret, node, topn, INT2FIX(1));
10214 }
10215 ADD_INSN2(ret, node, opt_aset_with, str,
10216 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10217 RB_OBJ_WRITTEN(iseq, Qundef, str);
10218 ADD_INSN(ret, node, pop);
10219 return COMPILE_OK;
10220 }
10221
10222 INIT_ANCHOR(recv);
10223 INIT_ANCHOR(args);
10224 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10225 CHECK(!NIL_P(argc));
10226
10227 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10228 CHECK(asgnflag != -1);
10229 flag |= (unsigned int)asgnflag;
10230
10231 debugp_param("argc", argc);
10232 debugp_param("nd_mid", ID2SYM(mid));
10233
10234 if (!rb_is_attrset_id(mid)) {
10235 /* safe nav attr */
10236 mid = rb_id_attrset(mid);
10237 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10238 }
10239 if (!popped) {
10240 ADD_INSN(ret, node, putnil);
10241 ADD_SEQ(ret, recv);
10242 ADD_SEQ(ret, args);
10243
10244 if (flag & VM_CALL_ARGS_SPLAT) {
10245 ADD_INSN(ret, node, dup);
10246 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10247 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10248 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10249 ADD_INSN (ret, node, pop);
10250 }
10251 else {
10252 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10253 }
10254 }
10255 else {
10256 ADD_SEQ(ret, recv);
10257 ADD_SEQ(ret, args);
10258 }
10259 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10260 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10261 ADD_INSN(ret, node, pop);
10262 return COMPILE_OK;
10263}
10264
10265static int
10266compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10267{
10268 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10269 ADD_SEQ(ret, sub);
10270
10271 if (copy) {
10272 /*
10273 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10274 * NEW_LIST(value, loc), loc);
10275 */
10276 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10277 }
10278 else {
10279 /*
10280 * NEW_CALL(fcore, rb_intern("make_shareable"),
10281 * NEW_LIST(value, loc), loc);
10282 */
10283 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10284 }
10285
10286 return COMPILE_OK;
10287}
10288
10289static VALUE
10290node_const_decl_val(const NODE *node)
10291{
10292 VALUE path;
10293 switch (nd_type(node)) {
10294 case NODE_CDECL:
10295 if (RNODE_CDECL(node)->nd_vid) {
10296 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10297 goto end;
10298 }
10299 else {
10300 node = RNODE_CDECL(node)->nd_else;
10301 }
10302 break;
10303 case NODE_COLON2:
10304 break;
10305 case NODE_COLON3:
10306 // ::Const
10307 path = rb_str_new_cstr("::");
10308 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10309 goto end;
10310 default:
10311 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10312 UNREACHABLE_RETURN(0);
10313 }
10314
10315 path = rb_ary_new();
10316 if (node) {
10317 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10318 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10319 }
10320 if (node && nd_type_p(node, NODE_CONST)) {
10321 // Const::Name
10322 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10323 }
10324 else if (node && nd_type_p(node, NODE_COLON3)) {
10325 // ::Const::Name
10326 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10327 rb_ary_push(path, rb_str_new(0, 0));
10328 }
10329 else {
10330 // expression::Name
10331 rb_ary_push(path, rb_str_new_cstr("..."));
10332 }
10333 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10334 }
10335 end:
10336 path = rb_fstring(path);
10337 return path;
10338}
10339
10340static VALUE
10341const_decl_path(NODE *dest)
10342{
10343 VALUE path = Qnil;
10344 if (!nd_type_p(dest, NODE_CALL)) {
10345 path = node_const_decl_val(dest);
10346 }
10347 return path;
10348}
10349
10350static int
10351compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10352{
10353 /*
10354 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10355 */
10356 VALUE path = const_decl_path(dest);
10357 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10358 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10359 ADD_INSN1(ret, value, putobject, path);
10360 RB_OBJ_WRITTEN(iseq, Qundef, path);
10361 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10362
10363 return COMPILE_OK;
10364}
10365
10366#ifndef SHAREABLE_BARE_EXPRESSION
10367#define SHAREABLE_BARE_EXPRESSION 1
10368#endif
10369
10370static int
10371compile_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)
10372{
10373# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10374 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10375 VALUE lit = Qnil;
10376 DECL_ANCHOR(anchor);
10377
10378 enum node_type type = nd_type(node);
10379 switch (type) {
10380 case NODE_TRUE:
10381 *value_p = Qtrue;
10382 goto compile;
10383 case NODE_FALSE:
10384 *value_p = Qfalse;
10385 goto compile;
10386 case NODE_NIL:
10387 *value_p = Qnil;
10388 goto compile;
10389 case NODE_SYM:
10390 *value_p = rb_node_sym_string_val(node);
10391 goto compile;
10392 case NODE_REGX:
10393 *value_p = rb_node_regx_string_val(node);
10394 goto compile;
10395 case NODE_LINE:
10396 *value_p = rb_node_line_lineno_val(node);
10397 goto compile;
10398 case NODE_INTEGER:
10399 *value_p = rb_node_integer_literal_val(node);
10400 goto compile;
10401 case NODE_FLOAT:
10402 *value_p = rb_node_float_literal_val(node);
10403 goto compile;
10404 case NODE_RATIONAL:
10405 *value_p = rb_node_rational_literal_val(node);
10406 goto compile;
10407 case NODE_IMAGINARY:
10408 *value_p = rb_node_imaginary_literal_val(node);
10409 goto compile;
10410 case NODE_ENCODING:
10411 *value_p = rb_node_encoding_val(node);
10412
10413 compile:
10414 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10415 *shareable_literal_p = 1;
10416 return COMPILE_OK;
10417
10418 case NODE_DSTR:
10419 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10420 if (shareable == rb_parser_shareable_literal) {
10421 /*
10422 * NEW_CALL(node, idUMinus, 0, loc);
10423 *
10424 * -"#{var}"
10425 */
10426 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10427 }
10428 *value_p = Qundef;
10429 *shareable_literal_p = 1;
10430 return COMPILE_OK;
10431
10432 case NODE_STR:{
10433 VALUE lit = rb_node_str_string_val(node);
10434 ADD_INSN1(ret, node, putobject, lit);
10435 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10436 *value_p = lit;
10437 *shareable_literal_p = 1;
10438
10439 return COMPILE_OK;
10440 }
10441
10442 case NODE_FILE:{
10443 VALUE lit = rb_node_file_path_val(node);
10444 ADD_INSN1(ret, node, putobject, lit);
10445 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10446 *value_p = lit;
10447 *shareable_literal_p = 1;
10448
10449 return COMPILE_OK;
10450 }
10451
10452 case NODE_ZLIST:{
10453 VALUE lit = rb_ary_new();
10454 OBJ_FREEZE(lit);
10455 ADD_INSN1(ret, node, putobject, lit);
10456 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10457 *value_p = lit;
10458 *shareable_literal_p = 1;
10459
10460 return COMPILE_OK;
10461 }
10462
10463 case NODE_LIST:{
10464 INIT_ANCHOR(anchor);
10465 lit = rb_ary_new();
10466 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10467 VALUE val;
10468 int shareable_literal_p2;
10469 NODE *elt = RNODE_LIST(n)->nd_head;
10470 if (elt) {
10471 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10472 if (shareable_literal_p2) {
10473 /* noop */
10474 }
10475 else if (RTEST(lit)) {
10476 rb_ary_clear(lit);
10477 lit = Qfalse;
10478 }
10479 }
10480 if (RTEST(lit)) {
10481 if (!UNDEF_P(val)) {
10482 rb_ary_push(lit, val);
10483 }
10484 else {
10485 rb_ary_clear(lit);
10486 lit = Qnil; /* make shareable at runtime */
10487 }
10488 }
10489 }
10490 break;
10491 }
10492 case NODE_HASH:{
10493 if (!RNODE_HASH(node)->nd_brace) {
10494 *value_p = Qundef;
10495 *shareable_literal_p = 0;
10496 return COMPILE_OK;
10497 }
10498 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10499 if (!RNODE_LIST(n)->nd_head) {
10500 // If the hash node have a keyword splat, fall back to the default case.
10501 goto compile_shareable;
10502 }
10503 }
10504
10505 INIT_ANCHOR(anchor);
10506 lit = rb_hash_new();
10507 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10508 VALUE key_val = 0;
10509 VALUE value_val = 0;
10510 int shareable_literal_p2;
10511 NODE *key = RNODE_LIST(n)->nd_head;
10512 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10513 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10514 if (shareable_literal_p2) {
10515 /* noop */
10516 }
10517 else if (RTEST(lit)) {
10518 rb_hash_clear(lit);
10519 lit = Qfalse;
10520 }
10521 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10522 if (shareable_literal_p2) {
10523 /* noop */
10524 }
10525 else if (RTEST(lit)) {
10526 rb_hash_clear(lit);
10527 lit = Qfalse;
10528 }
10529 if (RTEST(lit)) {
10530 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10531 rb_hash_aset(lit, key_val, value_val);
10532 }
10533 else {
10534 rb_hash_clear(lit);
10535 lit = Qnil; /* make shareable at runtime */
10536 }
10537 }
10538 }
10539 break;
10540 }
10541
10542 default:
10543
10544 compile_shareable:
10545 if (shareable == rb_parser_shareable_literal &&
10546 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10547 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10548 *value_p = Qundef;
10549 *shareable_literal_p = 1;
10550 return COMPILE_OK;
10551 }
10552 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10553 *value_p = Qundef;
10554 *shareable_literal_p = 0;
10555 return COMPILE_OK;
10556 }
10557
10558 /* Array or Hash that does not have keyword splat */
10559 if (!lit) {
10560 if (nd_type(node) == NODE_LIST) {
10561 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10562 }
10563 else if (nd_type(node) == NODE_HASH) {
10564 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10565 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10566 }
10567 *value_p = Qundef;
10568 *shareable_literal_p = 0;
10569 ADD_SEQ(ret, anchor);
10570 return COMPILE_OK;
10571 }
10572 if (NIL_P(lit)) {
10573 // if shareable_literal, all elements should have been ensured
10574 // as shareable
10575 if (nd_type(node) == NODE_LIST) {
10576 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10577 }
10578 else if (nd_type(node) == NODE_HASH) {
10579 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10580 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10581 }
10582 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10583 *value_p = Qundef;
10584 *shareable_literal_p = 1;
10585 }
10586 else {
10587 VALUE val = rb_ractor_make_shareable(lit);
10588 ADD_INSN1(ret, node, putobject, val);
10589 RB_OBJ_WRITTEN(iseq, Qundef, val);
10590 *value_p = val;
10591 *shareable_literal_p = 1;
10592 }
10593
10594 return COMPILE_OK;
10595}
10596
10597static int
10598compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10599{
10600 int literal_p = 0;
10601 VALUE val;
10602 DECL_ANCHOR(anchor);
10603 INIT_ANCHOR(anchor);
10604
10605 switch (shareable) {
10606 case rb_parser_shareable_none:
10607 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10608 return COMPILE_OK;
10609
10610 case rb_parser_shareable_literal:
10611 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10612 ADD_SEQ(ret, anchor);
10613 return COMPILE_OK;
10614
10615 case rb_parser_shareable_copy:
10616 case rb_parser_shareable_everything:
10617 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10618 if (!literal_p) {
10619 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10620 }
10621 else {
10622 ADD_SEQ(ret, anchor);
10623 }
10624 return COMPILE_OK;
10625 default:
10626 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10627 }
10628}
10629
10630static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10638static int
10639iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10640{
10641 if (node == 0) {
10642 if (!popped) {
10643 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10644 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10645 debugs("node: NODE_NIL(implicit)\n");
10646 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10647 }
10648 return COMPILE_OK;
10649 }
10650 return iseq_compile_each0(iseq, ret, node, popped);
10651}
10652
10653static int
10654iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10655{
10656 const int line = (int)nd_line(node);
10657 const enum node_type type = nd_type(node);
10658 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10659
10660 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10661 /* ignore */
10662 }
10663 else {
10664 if (nd_fl_newline(node)) {
10665 int event = RUBY_EVENT_LINE;
10666 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10667 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10668 event |= RUBY_EVENT_COVERAGE_LINE;
10669 }
10670 ADD_TRACE(ret, event);
10671 }
10672 }
10673
10674 debug_node_start(node);
10675#undef BEFORE_RETURN
10676#define BEFORE_RETURN debug_node_end()
10677
10678 switch (type) {
10679 case NODE_BLOCK:
10680 CHECK(compile_block(iseq, ret, node, popped));
10681 break;
10682 case NODE_IF:
10683 case NODE_UNLESS:
10684 CHECK(compile_if(iseq, ret, node, popped, type));
10685 break;
10686 case NODE_CASE:
10687 CHECK(compile_case(iseq, ret, node, popped));
10688 break;
10689 case NODE_CASE2:
10690 CHECK(compile_case2(iseq, ret, node, popped));
10691 break;
10692 case NODE_CASE3:
10693 CHECK(compile_case3(iseq, ret, node, popped));
10694 break;
10695 case NODE_WHILE:
10696 case NODE_UNTIL:
10697 CHECK(compile_loop(iseq, ret, node, popped, type));
10698 break;
10699 case NODE_FOR:
10700 case NODE_ITER:
10701 CHECK(compile_iter(iseq, ret, node, popped));
10702 break;
10703 case NODE_FOR_MASGN:
10704 CHECK(compile_for_masgn(iseq, ret, node, popped));
10705 break;
10706 case NODE_BREAK:
10707 CHECK(compile_break(iseq, ret, node, popped));
10708 break;
10709 case NODE_NEXT:
10710 CHECK(compile_next(iseq, ret, node, popped));
10711 break;
10712 case NODE_REDO:
10713 CHECK(compile_redo(iseq, ret, node, popped));
10714 break;
10715 case NODE_RETRY:
10716 CHECK(compile_retry(iseq, ret, node, popped));
10717 break;
10718 case NODE_BEGIN:{
10719 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10720 break;
10721 }
10722 case NODE_RESCUE:
10723 CHECK(compile_rescue(iseq, ret, node, popped));
10724 break;
10725 case NODE_RESBODY:
10726 CHECK(compile_resbody(iseq, ret, node, popped));
10727 break;
10728 case NODE_ENSURE:
10729 CHECK(compile_ensure(iseq, ret, node, popped));
10730 break;
10731
10732 case NODE_AND:
10733 case NODE_OR:{
10734 LABEL *end_label = NEW_LABEL(line);
10735 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10736 if (!popped) {
10737 ADD_INSN(ret, node, dup);
10738 }
10739 if (type == NODE_AND) {
10740 ADD_INSNL(ret, node, branchunless, end_label);
10741 }
10742 else {
10743 ADD_INSNL(ret, node, branchif, end_label);
10744 }
10745 if (!popped) {
10746 ADD_INSN(ret, node, pop);
10747 }
10748 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10749 ADD_LABEL(ret, end_label);
10750 break;
10751 }
10752
10753 case NODE_MASGN:{
10754 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10755 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10756 compile_massign(iseq, ret, node, popped);
10757 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10758 break;
10759 }
10760
10761 case NODE_LASGN:{
10762 ID id = RNODE_LASGN(node)->nd_vid;
10763 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10764
10765 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10766 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10767
10768 if (!popped) {
10769 ADD_INSN(ret, node, dup);
10770 }
10771 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10772 break;
10773 }
10774 case NODE_DASGN: {
10775 int idx, lv, ls;
10776 ID id = RNODE_DASGN(node)->nd_vid;
10777 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10778 debugi("dassn id", rb_id2str(id) ? id : '*');
10779
10780 if (!popped) {
10781 ADD_INSN(ret, node, dup);
10782 }
10783
10784 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10785
10786 if (idx < 0) {
10787 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10788 rb_id2str(id));
10789 goto ng;
10790 }
10791 ADD_SETLOCAL(ret, node, ls - idx, lv);
10792 break;
10793 }
10794 case NODE_GASGN:{
10795 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10796
10797 if (!popped) {
10798 ADD_INSN(ret, node, dup);
10799 }
10800 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10801 break;
10802 }
10803 case NODE_IASGN:{
10804 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10805 if (!popped) {
10806 ADD_INSN(ret, node, dup);
10807 }
10808 ADD_INSN2(ret, node, setinstancevariable,
10809 ID2SYM(RNODE_IASGN(node)->nd_vid),
10810 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10811 break;
10812 }
10813 case NODE_CDECL:{
10814 if (RNODE_CDECL(node)->nd_vid) {
10815 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10816
10817 if (!popped) {
10818 ADD_INSN(ret, node, dup);
10819 }
10820
10821 ADD_INSN1(ret, node, putspecialobject,
10822 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10823 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10824 }
10825 else {
10826 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10827 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10828 ADD_INSN(ret, node, swap);
10829
10830 if (!popped) {
10831 ADD_INSN1(ret, node, topn, INT2FIX(1));
10832 ADD_INSN(ret, node, swap);
10833 }
10834
10835 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10836 }
10837 break;
10838 }
10839 case NODE_CVASGN:{
10840 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10841 if (!popped) {
10842 ADD_INSN(ret, node, dup);
10843 }
10844 ADD_INSN2(ret, node, setclassvariable,
10845 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10846 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10847 break;
10848 }
10849 case NODE_OP_ASGN1:
10850 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10851 break;
10852 case NODE_OP_ASGN2:
10853 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10854 break;
10855 case NODE_OP_CDECL:
10856 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10857 break;
10858 case NODE_OP_ASGN_AND:
10859 case NODE_OP_ASGN_OR:
10860 CHECK(compile_op_log(iseq, ret, node, popped, type));
10861 break;
10862 case NODE_CALL: /* obj.foo */
10863 case NODE_OPCALL: /* foo[] */
10864 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10865 break;
10866 }
10867 case NODE_QCALL: /* obj&.foo */
10868 case NODE_FCALL: /* foo() */
10869 case NODE_VCALL: /* foo (variable or call) */
10870 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10871 goto ng;
10872 }
10873 break;
10874 case NODE_SUPER:
10875 case NODE_ZSUPER:
10876 CHECK(compile_super(iseq, ret, node, popped, type));
10877 break;
10878 case NODE_LIST:{
10879 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10880 break;
10881 }
10882 case NODE_ZLIST:{
10883 if (!popped) {
10884 ADD_INSN1(ret, node, newarray, INT2FIX(0));
10885 }
10886 break;
10887 }
10888 case NODE_HASH:
10889 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10890 break;
10891 case NODE_RETURN:
10892 CHECK(compile_return(iseq, ret, node, popped));
10893 break;
10894 case NODE_YIELD:
10895 CHECK(compile_yield(iseq, ret, node, popped));
10896 break;
10897 case NODE_LVAR:{
10898 if (!popped) {
10899 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10900 }
10901 break;
10902 }
10903 case NODE_DVAR:{
10904 int lv, idx, ls;
10905 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10906 if (!popped) {
10907 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10908 if (idx < 0) {
10909 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10910 rb_id2str(RNODE_DVAR(node)->nd_vid));
10911 goto ng;
10912 }
10913 ADD_GETLOCAL(ret, node, ls - idx, lv);
10914 }
10915 break;
10916 }
10917 case NODE_GVAR:{
10918 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10919 if (popped) {
10920 ADD_INSN(ret, node, pop);
10921 }
10922 break;
10923 }
10924 case NODE_IVAR:{
10925 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10926 if (!popped) {
10927 ADD_INSN2(ret, node, getinstancevariable,
10928 ID2SYM(RNODE_IVAR(node)->nd_vid),
10929 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10930 }
10931 break;
10932 }
10933 case NODE_CONST:{
10934 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10935
10936 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10937 body->ic_size++;
10938 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10939 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10940 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10941 }
10942 else {
10943 ADD_INSN(ret, node, putnil);
10944 ADD_INSN1(ret, node, putobject, Qtrue);
10945 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10946 }
10947
10948 if (popped) {
10949 ADD_INSN(ret, node, pop);
10950 }
10951 break;
10952 }
10953 case NODE_CVAR:{
10954 if (!popped) {
10955 ADD_INSN2(ret, node, getclassvariable,
10956 ID2SYM(RNODE_CVAR(node)->nd_vid),
10957 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10958 }
10959 break;
10960 }
10961 case NODE_NTH_REF:{
10962 if (!popped) {
10963 if (!RNODE_NTH_REF(node)->nd_nth) {
10964 ADD_INSN(ret, node, putnil);
10965 break;
10966 }
10967 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10968 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10969 }
10970 break;
10971 }
10972 case NODE_BACK_REF:{
10973 if (!popped) {
10974 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10975 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10976 }
10977 break;
10978 }
10979 case NODE_MATCH:
10980 case NODE_MATCH2:
10981 case NODE_MATCH3:
10982 CHECK(compile_match(iseq, ret, node, popped, type));
10983 break;
10984 case NODE_SYM:{
10985 if (!popped) {
10986 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
10987 }
10988 break;
10989 }
10990 case NODE_LINE:{
10991 if (!popped) {
10992 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
10993 }
10994 break;
10995 }
10996 case NODE_ENCODING:{
10997 if (!popped) {
10998 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
10999 }
11000 break;
11001 }
11002 case NODE_INTEGER:{
11003 VALUE lit = rb_node_integer_literal_val(node);
11004 debugp_param("integer", lit);
11005 if (!popped) {
11006 ADD_INSN1(ret, node, putobject, lit);
11007 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11008 }
11009 break;
11010 }
11011 case NODE_FLOAT:{
11012 VALUE lit = rb_node_float_literal_val(node);
11013 debugp_param("float", lit);
11014 if (!popped) {
11015 ADD_INSN1(ret, node, putobject, lit);
11016 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11017 }
11018 break;
11019 }
11020 case NODE_RATIONAL:{
11021 VALUE lit = rb_node_rational_literal_val(node);
11022 debugp_param("rational", lit);
11023 if (!popped) {
11024 ADD_INSN1(ret, node, putobject, lit);
11025 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11026 }
11027 break;
11028 }
11029 case NODE_IMAGINARY:{
11030 VALUE lit = rb_node_imaginary_literal_val(node);
11031 debugp_param("imaginary", lit);
11032 if (!popped) {
11033 ADD_INSN1(ret, node, putobject, lit);
11034 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11035 }
11036 break;
11037 }
11038 case NODE_FILE:
11039 case NODE_STR:{
11040 debugp_param("nd_lit", get_string_value(node));
11041 if (!popped) {
11042 VALUE lit = get_string_value(node);
11043 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11044 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11045 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11046 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11047 }
11048 switch (option->frozen_string_literal) {
11049 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11050 ADD_INSN1(ret, node, putchilledstring, lit);
11051 break;
11052 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11053 ADD_INSN1(ret, node, putstring, lit);
11054 break;
11055 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11056 ADD_INSN1(ret, node, putobject, lit);
11057 break;
11058 default:
11059 rb_bug("invalid frozen_string_literal");
11060 }
11061 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11062 }
11063 break;
11064 }
11065 case NODE_DSTR:{
11066 compile_dstr(iseq, ret, node);
11067
11068 if (popped) {
11069 ADD_INSN(ret, node, pop);
11070 }
11071 break;
11072 }
11073 case NODE_XSTR:{
11074 ADD_CALL_RECEIVER(ret, node);
11075 VALUE str = rb_node_str_string_val(node);
11076 ADD_INSN1(ret, node, putobject, str);
11077 RB_OBJ_WRITTEN(iseq, Qundef, str);
11078 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11079
11080 if (popped) {
11081 ADD_INSN(ret, node, pop);
11082 }
11083 break;
11084 }
11085 case NODE_DXSTR:{
11086 ADD_CALL_RECEIVER(ret, node);
11087 compile_dstr(iseq, ret, node);
11088 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11089
11090 if (popped) {
11091 ADD_INSN(ret, node, pop);
11092 }
11093 break;
11094 }
11095 case NODE_EVSTR:
11096 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11097 break;
11098 case NODE_REGX:{
11099 if (!popped) {
11100 VALUE lit = rb_node_regx_string_val(node);
11101 ADD_INSN1(ret, node, putobject, lit);
11102 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11103 }
11104 break;
11105 }
11106 case NODE_DREGX:
11107 compile_dregx(iseq, ret, node, popped);
11108 break;
11109 case NODE_ONCE:{
11110 int ic_index = body->ise_size++;
11111 const rb_iseq_t *block_iseq;
11112 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11113
11114 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11115 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11116
11117 if (popped) {
11118 ADD_INSN(ret, node, pop);
11119 }
11120 break;
11121 }
11122 case NODE_ARGSCAT:{
11123 if (popped) {
11124 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11125 ADD_INSN1(ret, node, splatarray, Qfalse);
11126 ADD_INSN(ret, node, pop);
11127 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11128 ADD_INSN1(ret, node, splatarray, Qfalse);
11129 ADD_INSN(ret, node, pop);
11130 }
11131 else {
11132 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11133 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11134 if (nd_type_p(body_node, NODE_LIST)) {
11135 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11136 }
11137 else {
11138 CHECK(COMPILE(ret, "argscat body", body_node));
11139 ADD_INSN(ret, node, concattoarray);
11140 }
11141 }
11142 break;
11143 }
11144 case NODE_ARGSPUSH:{
11145 if (popped) {
11146 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11147 ADD_INSN1(ret, node, splatarray, Qfalse);
11148 ADD_INSN(ret, node, pop);
11149 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11150 }
11151 else {
11152 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11153 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11154 if (keyword_node_p(body_node)) {
11155 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11156 ADD_INSN(ret, node, pushtoarraykwsplat);
11157 }
11158 else if (static_literal_node_p(body_node, iseq, false)) {
11159 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11160 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11161 }
11162 else {
11163 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11164 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11165 }
11166 }
11167 break;
11168 }
11169 case NODE_SPLAT:{
11170 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11171 ADD_INSN1(ret, node, splatarray, Qtrue);
11172
11173 if (popped) {
11174 ADD_INSN(ret, node, pop);
11175 }
11176 break;
11177 }
11178 case NODE_DEFN:{
11179 ID mid = RNODE_DEFN(node)->nd_mid;
11180 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11181 rb_id2str(mid),
11182 ISEQ_TYPE_METHOD, line);
11183
11184 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11185 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11186 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11187
11188 if (!popped) {
11189 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11190 }
11191
11192 break;
11193 }
11194 case NODE_DEFS:{
11195 ID mid = RNODE_DEFS(node)->nd_mid;
11196 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11197 rb_id2str(mid),
11198 ISEQ_TYPE_METHOD, line);
11199
11200 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11201 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11202 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11203 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11204
11205 if (!popped) {
11206 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11207 }
11208 break;
11209 }
11210 case NODE_ALIAS:{
11211 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11212 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11213 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11214 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11215 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11216
11217 if (popped) {
11218 ADD_INSN(ret, node, pop);
11219 }
11220 break;
11221 }
11222 case NODE_VALIAS:{
11223 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11224 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11225 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11226 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11227
11228 if (popped) {
11229 ADD_INSN(ret, node, pop);
11230 }
11231 break;
11232 }
11233 case NODE_UNDEF:{
11234 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11235
11236 for (long i = 0; i < ary->len; i++) {
11237 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11238 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11239 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11240 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11241
11242 if (i < ary->len - 1) {
11243 ADD_INSN(ret, node, pop);
11244 }
11245 }
11246
11247 if (popped) {
11248 ADD_INSN(ret, node, pop);
11249 }
11250 break;
11251 }
11252 case NODE_CLASS:{
11253 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11254 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11255 ISEQ_TYPE_CLASS, line);
11256 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11257 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11258 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11259
11260 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11261 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11262 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11263
11264 if (popped) {
11265 ADD_INSN(ret, node, pop);
11266 }
11267 break;
11268 }
11269 case NODE_MODULE:{
11270 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11271 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11272 ISEQ_TYPE_CLASS, line);
11273 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11274 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11275
11276 ADD_INSN (ret, node, putnil); /* dummy */
11277 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11278 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11279
11280 if (popped) {
11281 ADD_INSN(ret, node, pop);
11282 }
11283 break;
11284 }
11285 case NODE_SCLASS:{
11286 ID singletonclass;
11287 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11288 ISEQ_TYPE_CLASS, line);
11289
11290 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11291 ADD_INSN (ret, node, putnil);
11292 CONST_ID(singletonclass, "singletonclass");
11293 ADD_INSN3(ret, node, defineclass,
11294 ID2SYM(singletonclass), singleton_class,
11295 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11296 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11297
11298 if (popped) {
11299 ADD_INSN(ret, node, pop);
11300 }
11301 break;
11302 }
11303 case NODE_COLON2:
11304 CHECK(compile_colon2(iseq, ret, node, popped));
11305 break;
11306 case NODE_COLON3:
11307 CHECK(compile_colon3(iseq, ret, node, popped));
11308 break;
11309 case NODE_DOT2:
11310 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11311 break;
11312 case NODE_DOT3:
11313 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11314 break;
11315 case NODE_FLIP2:
11316 case NODE_FLIP3:{
11317 LABEL *lend = NEW_LABEL(line);
11318 LABEL *ltrue = NEW_LABEL(line);
11319 LABEL *lfalse = NEW_LABEL(line);
11320 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11321 ltrue, lfalse));
11322 ADD_LABEL(ret, ltrue);
11323 ADD_INSN1(ret, node, putobject, Qtrue);
11324 ADD_INSNL(ret, node, jump, lend);
11325 ADD_LABEL(ret, lfalse);
11326 ADD_INSN1(ret, node, putobject, Qfalse);
11327 ADD_LABEL(ret, lend);
11328 break;
11329 }
11330 case NODE_SELF:{
11331 if (!popped) {
11332 ADD_INSN(ret, node, putself);
11333 }
11334 break;
11335 }
11336 case NODE_NIL:{
11337 if (!popped) {
11338 ADD_INSN(ret, node, putnil);
11339 }
11340 break;
11341 }
11342 case NODE_TRUE:{
11343 if (!popped) {
11344 ADD_INSN1(ret, node, putobject, Qtrue);
11345 }
11346 break;
11347 }
11348 case NODE_FALSE:{
11349 if (!popped) {
11350 ADD_INSN1(ret, node, putobject, Qfalse);
11351 }
11352 break;
11353 }
11354 case NODE_ERRINFO:
11355 CHECK(compile_errinfo(iseq, ret, node, popped));
11356 break;
11357 case NODE_DEFINED:
11358 if (!popped) {
11359 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11360 }
11361 break;
11362 case NODE_POSTEXE:{
11363 /* compiled to:
11364 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11365 */
11366 int is_index = body->ise_size++;
11367 struct rb_iseq_new_with_callback_callback_func *ifunc =
11368 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11369 const rb_iseq_t *once_iseq =
11370 new_child_iseq_with_callback(iseq, ifunc,
11371 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
11372
11373 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11374 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11375
11376 if (popped) {
11377 ADD_INSN(ret, node, pop);
11378 }
11379 break;
11380 }
11381 case NODE_KW_ARG:
11382 CHECK(compile_kw_arg(iseq, ret, node, popped));
11383 break;
11384 case NODE_DSYM:{
11385 compile_dstr(iseq, ret, node);
11386 if (!popped) {
11387 ADD_INSN(ret, node, intern);
11388 }
11389 else {
11390 ADD_INSN(ret, node, pop);
11391 }
11392 break;
11393 }
11394 case NODE_ATTRASGN:
11395 CHECK(compile_attrasgn(iseq, ret, node, popped));
11396 break;
11397 case NODE_LAMBDA:{
11398 /* compile same as lambda{...} */
11399 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11400 VALUE argc = INT2FIX(0);
11401
11402 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11403 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11404 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11405
11406 if (popped) {
11407 ADD_INSN(ret, node, pop);
11408 }
11409 break;
11410 }
11411 default:
11412 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11413 ng:
11414 debug_node_end();
11415 return COMPILE_NG;
11416 }
11417
11418 debug_node_end();
11419 return COMPILE_OK;
11420}
11421
11422/***************************/
11423/* instruction information */
11424/***************************/
11425
11426static int
11427insn_data_length(INSN *iobj)
11428{
11429 return insn_len(iobj->insn_id);
11430}
11431
11432static int
11433calc_sp_depth(int depth, INSN *insn)
11434{
11435 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11436}
11437
11438static VALUE
11439opobj_inspect(VALUE obj)
11440{
11441 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11442 switch (BUILTIN_TYPE(obj)) {
11443 case T_STRING:
11444 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11445 break;
11446 case T_ARRAY:
11447 obj = rb_ary_dup(obj);
11448 break;
11449 default:
11450 break;
11451 }
11452 }
11453 return rb_inspect(obj);
11454}
11455
11456
11457
11458static VALUE
11459insn_data_to_s_detail(INSN *iobj)
11460{
11461 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11462
11463 if (iobj->operands) {
11464 const char *types = insn_op_types(iobj->insn_id);
11465 int j;
11466
11467 for (j = 0; types[j]; j++) {
11468 char type = types[j];
11469
11470 switch (type) {
11471 case TS_OFFSET: /* label(destination position) */
11472 {
11473 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11474 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11475 break;
11476 }
11477 break;
11478 case TS_ISEQ: /* iseq */
11479 {
11480 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11481 VALUE val = Qnil;
11482 if (0 && iseq) { /* TODO: invalidate now */
11483 val = (VALUE)iseq;
11484 }
11485 rb_str_concat(str, opobj_inspect(val));
11486 }
11487 break;
11488 case TS_LINDEX:
11489 case TS_NUM: /* ulong */
11490 case TS_VALUE: /* VALUE */
11491 {
11492 VALUE v = OPERAND_AT(iobj, j);
11493 if (!CLASS_OF(v))
11494 rb_str_cat2(str, "<hidden>");
11495 else {
11496 rb_str_concat(str, opobj_inspect(v));
11497 }
11498 break;
11499 }
11500 case TS_ID: /* ID */
11501 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11502 break;
11503 case TS_IC: /* inline cache */
11504 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11505 break;
11506 case TS_IVC: /* inline ivar cache */
11507 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11508 break;
11509 case TS_ICVARC: /* inline cvar cache */
11510 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11511 break;
11512 case TS_ISE: /* inline storage entry */
11513 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11514 break;
11515 case TS_CALLDATA: /* we store these as call infos at compile time */
11516 {
11517 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11518 rb_str_cat2(str, "<calldata:");
11519 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11520 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11521 break;
11522 }
11523 case TS_CDHASH: /* case/when condition cache */
11524 rb_str_cat2(str, "<ch>");
11525 break;
11526 case TS_FUNCPTR:
11527 {
11528 void *func = (void *)OPERAND_AT(iobj, j);
11529#ifdef HAVE_DLADDR
11530 Dl_info info;
11531 if (dladdr(func, &info) && info.dli_sname) {
11532 rb_str_cat2(str, info.dli_sname);
11533 break;
11534 }
11535#endif
11536 rb_str_catf(str, "<%p>", func);
11537 }
11538 break;
11539 case TS_BUILTIN:
11540 rb_str_cat2(str, "<TS_BUILTIN>");
11541 break;
11542 default:{
11543 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11544 }
11545 }
11546 if (types[j + 1]) {
11547 rb_str_cat2(str, ", ");
11548 }
11549 }
11550 }
11551 return str;
11552}
11553
11554static void
11555dump_disasm_list(const LINK_ELEMENT *link)
11556{
11557 dump_disasm_list_with_cursor(link, NULL, NULL);
11558}
11559
11560static void
11561dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11562{
11563 int pos = 0;
11564 INSN *iobj;
11565 LABEL *lobj;
11566 VALUE str;
11567
11568 printf("-- raw disasm--------\n");
11569
11570 while (link) {
11571 if (curr) printf(curr == link ? "*" : " ");
11572 switch (link->type) {
11573 case ISEQ_ELEMENT_INSN:
11574 {
11575 iobj = (INSN *)link;
11576 str = insn_data_to_s_detail(iobj);
11577 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11578 pos += insn_data_length(iobj);
11579 break;
11580 }
11581 case ISEQ_ELEMENT_LABEL:
11582 {
11583 lobj = (LABEL *)link;
11584 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11585 dest == lobj ? " <---" : "");
11586 break;
11587 }
11588 case ISEQ_ELEMENT_TRACE:
11589 {
11590 TRACE *trace = (TRACE *)link;
11591 printf(" trace: %0x\n", trace->event);
11592 break;
11593 }
11594 case ISEQ_ELEMENT_ADJUST:
11595 {
11596 ADJUST *adjust = (ADJUST *)link;
11597 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11598 break;
11599 }
11600 default:
11601 /* ignore */
11602 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11603 }
11604 link = link->next;
11605 }
11606 printf("---------------------\n");
11607 fflush(stdout);
11608}
11609
11610int
11611rb_insn_len(VALUE insn)
11612{
11613 return insn_len(insn);
11614}
11615
11616const char *
11617rb_insns_name(int i)
11618{
11619 return insn_name(i);
11620}
11621
11622 VALUE
11623rb_insns_name_array(void)
11624{
11625 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11626 int i;
11627 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11628 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11629 }
11630 return rb_ary_freeze(ary);
11631}
11632
11633static LABEL *
11634register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11635{
11636 LABEL *label = 0;
11637 st_data_t tmp;
11638 obj = rb_to_symbol_type(obj);
11639
11640 if (st_lookup(labels_table, obj, &tmp) == 0) {
11641 label = NEW_LABEL(0);
11642 st_insert(labels_table, obj, (st_data_t)label);
11643 }
11644 else {
11645 label = (LABEL *)tmp;
11646 }
11647 LABEL_REF(label);
11648 return label;
11649}
11650
11651static VALUE
11652get_exception_sym2type(VALUE sym)
11653{
11654 static VALUE symRescue, symEnsure, symRetry;
11655 static VALUE symBreak, symRedo, symNext;
11656
11657 if (symRescue == 0) {
11658 symRescue = ID2SYM(rb_intern_const("rescue"));
11659 symEnsure = ID2SYM(rb_intern_const("ensure"));
11660 symRetry = ID2SYM(rb_intern_const("retry"));
11661 symBreak = ID2SYM(rb_intern_const("break"));
11662 symRedo = ID2SYM(rb_intern_const("redo"));
11663 symNext = ID2SYM(rb_intern_const("next"));
11664 }
11665
11666 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11667 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11668 if (sym == symRetry) return CATCH_TYPE_RETRY;
11669 if (sym == symBreak) return CATCH_TYPE_BREAK;
11670 if (sym == symRedo) return CATCH_TYPE_REDO;
11671 if (sym == symNext) return CATCH_TYPE_NEXT;
11672 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11673 return 0;
11674}
11675
11676static int
11677iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11678 VALUE exception)
11679{
11680 int i;
11681
11682 for (i=0; i<RARRAY_LEN(exception); i++) {
11683 const rb_iseq_t *eiseq;
11684 VALUE v, type;
11685 LABEL *lstart, *lend, *lcont;
11686 unsigned int sp;
11687
11688 v = rb_to_array_type(RARRAY_AREF(exception, i));
11689 if (RARRAY_LEN(v) != 6) {
11690 rb_raise(rb_eSyntaxError, "wrong exception entry");
11691 }
11692 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11693 if (NIL_P(RARRAY_AREF(v, 1))) {
11694 eiseq = NULL;
11695 }
11696 else {
11697 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11698 }
11699
11700 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11701 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11702 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11703 sp = NUM2UINT(RARRAY_AREF(v, 5));
11704
11705 /* TODO: Dirty Hack! Fix me */
11706 if (type == CATCH_TYPE_RESCUE ||
11707 type == CATCH_TYPE_BREAK ||
11708 type == CATCH_TYPE_NEXT) {
11709 ++sp;
11710 }
11711
11712 lcont->sp = sp;
11713
11714 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11715
11716 RB_GC_GUARD(v);
11717 }
11718 return COMPILE_OK;
11719}
11720
11721static struct st_table *
11722insn_make_insn_table(void)
11723{
11724 struct st_table *table;
11725 int i;
11726 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11727
11728 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11729 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11730 }
11731
11732 return table;
11733}
11734
11735static const rb_iseq_t *
11736iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11737{
11738 VALUE iseqw;
11739 const rb_iseq_t *loaded_iseq;
11740
11741 if (RB_TYPE_P(op, T_ARRAY)) {
11742 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11743 }
11744 else if (CLASS_OF(op) == rb_cISeq) {
11745 iseqw = op;
11746 }
11747 else {
11748 rb_raise(rb_eSyntaxError, "ISEQ is required");
11749 }
11750
11751 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11752 return loaded_iseq;
11753}
11754
11755static VALUE
11756iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11757{
11758 ID mid = 0;
11759 int orig_argc = 0;
11760 unsigned int flag = 0;
11761 struct rb_callinfo_kwarg *kw_arg = 0;
11762
11763 if (!NIL_P(op)) {
11764 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11765 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11766 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11767 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11768
11769 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11770 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11771 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11772
11773 if (!NIL_P(vkw_arg)) {
11774 int i;
11775 int len = RARRAY_LENINT(vkw_arg);
11776 size_t n = rb_callinfo_kwarg_bytes(len);
11777
11778 kw_arg = xmalloc(n);
11779 kw_arg->references = 0;
11780 kw_arg->keyword_len = len;
11781 for (i = 0; i < len; i++) {
11782 VALUE kw = RARRAY_AREF(vkw_arg, i);
11783 SYM2ID(kw); /* make immortal */
11784 kw_arg->keywords[i] = kw;
11785 }
11786 }
11787 }
11788
11789 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11790 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11791 return (VALUE)ci;
11792}
11793
11794static rb_event_flag_t
11795event_name_to_flag(VALUE sym)
11796{
11797#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11798 CHECK_EVENT(RUBY_EVENT_LINE);
11799 CHECK_EVENT(RUBY_EVENT_CLASS);
11800 CHECK_EVENT(RUBY_EVENT_END);
11801 CHECK_EVENT(RUBY_EVENT_CALL);
11802 CHECK_EVENT(RUBY_EVENT_RETURN);
11803 CHECK_EVENT(RUBY_EVENT_B_CALL);
11804 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11805 CHECK_EVENT(RUBY_EVENT_RESCUE);
11806#undef CHECK_EVENT
11807 return RUBY_EVENT_NONE;
11808}
11809
11810static int
11811iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11812 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11813{
11814 /* TODO: body should be frozen */
11815 long i, len = RARRAY_LEN(body);
11816 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11817 int j;
11818 int line_no = 0, node_id = -1, insn_idx = 0;
11819 int ret = COMPILE_OK;
11820
11821 /*
11822 * index -> LABEL *label
11823 */
11824 static struct st_table *insn_table;
11825
11826 if (insn_table == 0) {
11827 insn_table = insn_make_insn_table();
11828 }
11829
11830 for (i=0; i<len; i++) {
11831 VALUE obj = RARRAY_AREF(body, i);
11832
11833 if (SYMBOL_P(obj)) {
11834 rb_event_flag_t event;
11835 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11836 ADD_TRACE(anchor, event);
11837 }
11838 else {
11839 LABEL *label = register_label(iseq, labels_table, obj);
11840 ADD_LABEL(anchor, label);
11841 }
11842 }
11843 else if (FIXNUM_P(obj)) {
11844 line_no = NUM2INT(obj);
11845 }
11846 else if (RB_TYPE_P(obj, T_ARRAY)) {
11847 VALUE *argv = 0;
11848 int argc = RARRAY_LENINT(obj) - 1;
11849 st_data_t insn_id;
11850 VALUE insn;
11851
11852 if (node_ids) {
11853 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11854 }
11855
11856 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11857 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11858 /* TODO: exception */
11859 COMPILE_ERROR(iseq, line_no,
11860 "unknown instruction: %+"PRIsVALUE, insn);
11861 ret = COMPILE_NG;
11862 break;
11863 }
11864
11865 if (argc != insn_len((VALUE)insn_id)-1) {
11866 COMPILE_ERROR(iseq, line_no,
11867 "operand size mismatch");
11868 ret = COMPILE_NG;
11869 break;
11870 }
11871
11872 if (argc > 0) {
11873 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11874
11875 // add element before operand setup to make GC root
11876 ADD_ELEM(anchor,
11877 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11878 (enum ruby_vminsn_type)insn_id, argc, argv));
11879
11880 for (j=0; j<argc; j++) {
11881 VALUE op = rb_ary_entry(obj, j+1);
11882 switch (insn_op_type((VALUE)insn_id, j)) {
11883 case TS_OFFSET: {
11884 LABEL *label = register_label(iseq, labels_table, op);
11885 argv[j] = (VALUE)label;
11886 break;
11887 }
11888 case TS_LINDEX:
11889 case TS_NUM:
11890 (void)NUM2INT(op);
11891 argv[j] = op;
11892 break;
11893 case TS_VALUE:
11894 argv[j] = op;
11895 RB_OBJ_WRITTEN(iseq, Qundef, op);
11896 break;
11897 case TS_ISEQ:
11898 {
11899 if (op != Qnil) {
11900 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
11901 argv[j] = v;
11902 RB_OBJ_WRITTEN(iseq, Qundef, v);
11903 }
11904 else {
11905 argv[j] = 0;
11906 }
11907 }
11908 break;
11909 case TS_ISE:
11910 argv[j] = op;
11911 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11912 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
11913 }
11914 break;
11915 case TS_IC:
11916 {
11917 VALUE segments = rb_ary_new();
11918 op = rb_to_array_type(op);
11919
11920 for (int i = 0; i < RARRAY_LEN(op); i++) {
11921 VALUE sym = RARRAY_AREF(op, i);
11922 sym = rb_to_symbol_type(sym);
11923 rb_ary_push(segments, sym);
11924 }
11925
11926 RB_GC_GUARD(op);
11927 argv[j] = segments;
11928 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11929 ISEQ_BODY(iseq)->ic_size++;
11930 }
11931 break;
11932 case TS_IVC: /* inline ivar cache */
11933 argv[j] = op;
11934 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
11935 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
11936 }
11937 break;
11938 case TS_ICVARC: /* inline cvar cache */
11939 argv[j] = op;
11940 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
11941 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
11942 }
11943 break;
11944 case TS_CALLDATA:
11945 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
11946 break;
11947 case TS_ID:
11948 argv[j] = rb_to_symbol_type(op);
11949 break;
11950 case TS_CDHASH:
11951 {
11952 int i;
11953 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
11954
11955 RHASH_TBL_RAW(map)->type = &cdhash_type;
11956 op = rb_to_array_type(op);
11957 for (i=0; i<RARRAY_LEN(op); i+=2) {
11958 VALUE key = RARRAY_AREF(op, i);
11959 VALUE sym = RARRAY_AREF(op, i+1);
11960 LABEL *label =
11961 register_label(iseq, labels_table, sym);
11962 rb_hash_aset(map, key, (VALUE)label | 1);
11963 }
11964 RB_GC_GUARD(op);
11965 argv[j] = map;
11966 RB_OBJ_WRITTEN(iseq, Qundef, map);
11967 }
11968 break;
11969 case TS_FUNCPTR:
11970 {
11971#if SIZEOF_VALUE <= SIZEOF_LONG
11972 long funcptr = NUM2LONG(op);
11973#else
11974 LONG_LONG funcptr = NUM2LL(op);
11975#endif
11976 argv[j] = (VALUE)funcptr;
11977 }
11978 break;
11979 default:
11980 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11981 }
11982 }
11983 }
11984 else {
11985 ADD_ELEM(anchor,
11986 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11987 (enum ruby_vminsn_type)insn_id, argc, NULL));
11988 }
11989 }
11990 else {
11991 rb_raise(rb_eTypeError, "unexpected object for instruction");
11992 }
11993 }
11994 RTYPEDDATA_DATA(labels_wrapper) = 0;
11995 RB_GC_GUARD(labels_wrapper);
11996 validate_labels(iseq, labels_table);
11997 if (!ret) return ret;
11998 return iseq_setup(iseq, anchor);
11999}
12000
12001#define CHECK_ARRAY(v) rb_to_array_type(v)
12002#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12003
12004static int
12005int_param(int *dst, VALUE param, VALUE sym)
12006{
12007 VALUE val = rb_hash_aref(param, sym);
12008 if (FIXNUM_P(val)) {
12009 *dst = FIX2INT(val);
12010 return TRUE;
12011 }
12012 else if (!NIL_P(val)) {
12013 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12014 sym, val);
12015 }
12016 return FALSE;
12017}
12018
12019static const struct rb_iseq_param_keyword *
12020iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12021{
12022 int i, j;
12023 int len = RARRAY_LENINT(keywords);
12024 int default_len;
12025 VALUE key, sym, default_val;
12026 VALUE *dvs;
12027 ID *ids;
12028 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12029
12030 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12031
12032 keyword->num = len;
12033#define SYM(s) ID2SYM(rb_intern_const(#s))
12034 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12035 i = keyword->bits_start - keyword->num;
12036 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12037#undef SYM
12038
12039 /* required args */
12040 for (i = 0; i < len; i++) {
12041 VALUE val = RARRAY_AREF(keywords, i);
12042
12043 if (!SYMBOL_P(val)) {
12044 goto default_values;
12045 }
12046 ids[i] = SYM2ID(val);
12047 keyword->required_num++;
12048 }
12049
12050 default_values: /* note: we intentionally preserve `i' from previous loop */
12051 default_len = len - i;
12052 if (default_len == 0) {
12053 keyword->table = ids;
12054 return keyword;
12055 }
12056 else if (default_len < 0) {
12057 UNREACHABLE;
12058 }
12059
12060 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12061
12062 for (j = 0; i < len; i++, j++) {
12063 key = RARRAY_AREF(keywords, i);
12064 CHECK_ARRAY(key);
12065
12066 switch (RARRAY_LEN(key)) {
12067 case 1:
12068 sym = RARRAY_AREF(key, 0);
12069 default_val = Qundef;
12070 break;
12071 case 2:
12072 sym = RARRAY_AREF(key, 0);
12073 default_val = RARRAY_AREF(key, 1);
12074 break;
12075 default:
12076 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12077 }
12078 ids[i] = SYM2ID(sym);
12079 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12080 }
12081
12082 keyword->table = ids;
12083 keyword->default_values = dvs;
12084
12085 return keyword;
12086}
12087
12088static void
12089iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
12090{
12091 rb_gc_mark(obj);
12092}
12093
12094void
12095rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
12096{
12097 INSN *iobj = 0;
12098 size_t size = sizeof(INSN);
12099 unsigned int pos = 0;
12100
12101 while (storage) {
12102#ifdef STRICT_ALIGNMENT
12103 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12104#else
12105 const size_t padding = 0; /* expected to be optimized by compiler */
12106#endif /* STRICT_ALIGNMENT */
12107 size_t offset = pos + size + padding;
12108 if (offset > storage->size || offset > storage->pos) {
12109 pos = 0;
12110 storage = storage->next;
12111 }
12112 else {
12113#ifdef STRICT_ALIGNMENT
12114 pos += (int)padding;
12115#endif /* STRICT_ALIGNMENT */
12116
12117 iobj = (INSN *)&storage->buff[pos];
12118
12119 if (iobj->operands) {
12120 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
12121 }
12122 pos += (int)size;
12123 }
12124 }
12125}
12126
12127static const rb_data_type_t labels_wrapper_type = {
12128 .wrap_struct_name = "compiler/labels_wrapper",
12129 .function = {
12130 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12131 .dfree = (RUBY_DATA_FUNC)st_free_table,
12132 },
12133 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12134};
12135
12136void
12137rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12138 VALUE exception, VALUE body)
12139{
12140#define SYM(s) ID2SYM(rb_intern_const(#s))
12141 int i, len;
12142 unsigned int arg_size, local_size, stack_max;
12143 ID *tbl;
12144 struct st_table *labels_table = st_init_numtable();
12145 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12146 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12147 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12148 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12149 DECL_ANCHOR(anchor);
12150 INIT_ANCHOR(anchor);
12151
12152 len = RARRAY_LENINT(locals);
12153 ISEQ_BODY(iseq)->local_table_size = len;
12154 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12155
12156 for (i = 0; i < len; i++) {
12157 VALUE lv = RARRAY_AREF(locals, i);
12158
12159 if (sym_arg_rest == lv) {
12160 tbl[i] = 0;
12161 }
12162 else {
12163 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12164 }
12165 }
12166
12167#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12168 if (INT_PARAM(lead_num)) {
12169 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12170 }
12171 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12172 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12173 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12174 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12175#undef INT_PARAM
12176 {
12177#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12178 int x;
12179 INT_PARAM(arg_size);
12180 INT_PARAM(local_size);
12181 INT_PARAM(stack_max);
12182#undef INT_PARAM
12183 }
12184
12185 VALUE node_ids = Qfalse;
12186#ifdef USE_ISEQ_NODE_ID
12187 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12188 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12189 rb_raise(rb_eTypeError, "node_ids is not an array");
12190 }
12191#endif
12192
12193 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12194 len = RARRAY_LENINT(arg_opt_labels);
12195 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12196
12197 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12198 VALUE *opt_table = ALLOC_N(VALUE, len);
12199
12200 for (i = 0; i < len; i++) {
12201 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12202 LABEL *label = register_label(iseq, labels_table, ent);
12203 opt_table[i] = (VALUE)label;
12204 }
12205
12206 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12207 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12208 }
12209 }
12210 else if (!NIL_P(arg_opt_labels)) {
12211 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12212 arg_opt_labels);
12213 }
12214
12215 if (RB_TYPE_P(keywords, T_ARRAY)) {
12216 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12217 }
12218 else if (!NIL_P(keywords)) {
12219 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12220 keywords);
12221 }
12222
12223 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12224 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12225 }
12226
12227 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12228 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12229 }
12230
12231 if (int_param(&i, params, SYM(kwrest))) {
12232 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12233 if (keyword == NULL) {
12234 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12235 }
12236 keyword->rest_start = i;
12237 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12238 }
12239#undef SYM
12240 iseq_calc_param_size(iseq);
12241
12242 /* exception */
12243 iseq_build_from_ary_exception(iseq, labels_table, exception);
12244
12245 /* body */
12246 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12247
12248 ISEQ_BODY(iseq)->param.size = arg_size;
12249 ISEQ_BODY(iseq)->local_table_size = local_size;
12250 ISEQ_BODY(iseq)->stack_max = stack_max;
12251}
12252
12253/* for parser */
12254
12255int
12256rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12257{
12258 if (iseq) {
12259 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12260 while (body->type == ISEQ_TYPE_BLOCK ||
12261 body->type == ISEQ_TYPE_RESCUE ||
12262 body->type == ISEQ_TYPE_ENSURE ||
12263 body->type == ISEQ_TYPE_EVAL ||
12264 body->type == ISEQ_TYPE_MAIN
12265 ) {
12266 unsigned int i;
12267
12268 for (i = 0; i < body->local_table_size; i++) {
12269 if (body->local_table[i] == id) {
12270 return 1;
12271 }
12272 }
12273 iseq = body->parent_iseq;
12274 body = ISEQ_BODY(iseq);
12275 }
12276 }
12277 return 0;
12278}
12279
12280int
12281rb_local_defined(ID id, const rb_iseq_t *iseq)
12282{
12283 if (iseq) {
12284 unsigned int i;
12285 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12286
12287 for (i=0; i<body->local_table_size; i++) {
12288 if (body->local_table[i] == id) {
12289 return 1;
12290 }
12291 }
12292 }
12293 return 0;
12294}
12295
12296/* ISeq binary format */
12297
12298#ifndef IBF_ISEQ_DEBUG
12299#define IBF_ISEQ_DEBUG 0
12300#endif
12301
12302#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12303#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12304#endif
12305
12306typedef uint32_t ibf_offset_t;
12307#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12308
12309#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12310#ifdef RUBY_DEVEL
12311#define IBF_DEVEL_VERSION 4
12312#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12313#else
12314#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12315#endif
12316
12317static const char IBF_ENDIAN_MARK =
12318#ifdef WORDS_BIGENDIAN
12319 'b'
12320#else
12321 'l'
12322#endif
12323 ;
12324
12325 struct ibf_header {
12326 char magic[4]; /* YARB */
12327 uint32_t major_version;
12328 uint32_t minor_version;
12329 uint32_t size;
12330 uint32_t extra_size;
12331
12332 uint32_t iseq_list_size;
12333 uint32_t global_object_list_size;
12334 ibf_offset_t iseq_list_offset;
12335 ibf_offset_t global_object_list_offset;
12336 uint8_t endian;
12337 uint8_t wordsize; /* assume no 2048-bit CPU */
12338};
12339
12340 struct ibf_dump_buffer {
12341 VALUE str;
12342 st_table *obj_table; /* obj -> obj number */
12343};
12344
12345 struct ibf_dump {
12346 st_table *iseq_table; /* iseq -> iseq number */
12347 struct ibf_dump_buffer global_buffer;
12348 struct ibf_dump_buffer *current_buffer;
12349};
12350
12351 struct ibf_load_buffer {
12352 const char *buff;
12353 ibf_offset_t size;
12354
12355 VALUE obj_list; /* [obj0, ...] */
12356 unsigned int obj_list_size;
12357 ibf_offset_t obj_list_offset;
12358};
12359
12360 struct ibf_load {
12361 const struct ibf_header *header;
12362 VALUE iseq_list; /* [iseq0, ...] */
12363 struct ibf_load_buffer global_buffer;
12364 VALUE loader_obj;
12365 rb_iseq_t *iseq;
12366 VALUE str;
12367 struct ibf_load_buffer *current_buffer;
12368};
12369
12370 struct pinned_list {
12371 long size;
12372 VALUE buffer[1];
12373};
12374
12375static void
12376pinned_list_mark(void *ptr)
12377{
12378 long i;
12379 struct pinned_list *list = (struct pinned_list *)ptr;
12380 for (i = 0; i < list->size; i++) {
12381 if (list->buffer[i]) {
12382 rb_gc_mark(list->buffer[i]);
12383 }
12384 }
12385}
12386
12387static const rb_data_type_t pinned_list_type = {
12388 "pinned_list",
12389 {
12390 pinned_list_mark,
12391 RUBY_DEFAULT_FREE,
12392 NULL, // No external memory to report,
12393 },
12394 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12395};
12396
12397static VALUE
12398pinned_list_fetch(VALUE list, long offset)
12399{
12400 struct pinned_list * ptr;
12401
12402 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12403
12404 if (offset >= ptr->size) {
12405 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12406 }
12407
12408 return ptr->buffer[offset];
12409}
12410
12411static void
12412pinned_list_store(VALUE list, long offset, VALUE object)
12413{
12414 struct pinned_list * ptr;
12415
12416 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12417
12418 if (offset >= ptr->size) {
12419 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12420 }
12421
12422 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12423}
12424
12425static VALUE
12426pinned_list_new(long size)
12427{
12428 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12429 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12430 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12431 ptr->size = size;
12432 return obj_list;
12433}
12434
12435static ibf_offset_t
12436ibf_dump_pos(struct ibf_dump *dump)
12437{
12438 long pos = RSTRING_LEN(dump->current_buffer->str);
12439#if SIZEOF_LONG > SIZEOF_INT
12440 if (pos >= UINT_MAX) {
12441 rb_raise(rb_eRuntimeError, "dump size exceeds");
12442 }
12443#endif
12444 return (unsigned int)pos;
12445}
12446
12447static void
12448ibf_dump_align(struct ibf_dump *dump, size_t align)
12449{
12450 ibf_offset_t pos = ibf_dump_pos(dump);
12451 if (pos % align) {
12452 static const char padding[sizeof(VALUE)];
12453 size_t size = align - ((size_t)pos % align);
12454#if SIZEOF_LONG > SIZEOF_INT
12455 if (pos + size >= UINT_MAX) {
12456 rb_raise(rb_eRuntimeError, "dump size exceeds");
12457 }
12458#endif
12459 for (; size > sizeof(padding); size -= sizeof(padding)) {
12460 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12461 }
12462 rb_str_cat(dump->current_buffer->str, padding, size);
12463 }
12464}
12465
12466static ibf_offset_t
12467ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12468{
12469 ibf_offset_t pos = ibf_dump_pos(dump);
12470 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12471 /* TODO: overflow check */
12472 return pos;
12473}
12474
12475static ibf_offset_t
12476ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12477{
12478 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12479}
12480
12481static void
12482ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12483{
12484 VALUE str = dump->current_buffer->str;
12485 char *ptr = RSTRING_PTR(str);
12486 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12487 rb_bug("ibf_dump_overwrite: overflow");
12488 memcpy(ptr + offset, buff, size);
12489}
12490
12491static const void *
12492ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12493{
12494 ibf_offset_t beg = *offset;
12495 *offset += size;
12496 return load->current_buffer->buff + beg;
12497}
12498
12499static void *
12500ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12501{
12502 void *buff = ruby_xmalloc2(x, y);
12503 size_t size = x * y;
12504 memcpy(buff, load->current_buffer->buff + offset, size);
12505 return buff;
12506}
12507
12508#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12509
12510#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12511#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12512#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12513#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12514#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12515
12516static int
12517ibf_table_lookup(struct st_table *table, st_data_t key)
12518{
12519 st_data_t val;
12520
12521 if (st_lookup(table, key, &val)) {
12522 return (int)val;
12523 }
12524 else {
12525 return -1;
12526 }
12527}
12528
12529static int
12530ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12531{
12532 int index = ibf_table_lookup(table, key);
12533
12534 if (index < 0) { /* not found */
12535 index = (int)table->num_entries;
12536 st_insert(table, key, (st_data_t)index);
12537 }
12538
12539 return index;
12540}
12541
12542/* dump/load generic */
12543
12544static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12545
12546static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12547static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12548
12549static st_table *
12550ibf_dump_object_table_new(void)
12551{
12552 st_table *obj_table = st_init_numtable(); /* need free */
12553 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12554
12555 return obj_table;
12556}
12557
12558static VALUE
12559ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12560{
12561 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12562}
12563
12564static VALUE
12565ibf_dump_id(struct ibf_dump *dump, ID id)
12566{
12567 if (id == 0 || rb_id2name(id) == NULL) {
12568 return 0;
12569 }
12570 return ibf_dump_object(dump, rb_id2sym(id));
12571}
12572
12573static ID
12574ibf_load_id(const struct ibf_load *load, const ID id_index)
12575{
12576 if (id_index == 0) {
12577 return 0;
12578 }
12579 VALUE sym = ibf_load_object(load, id_index);
12580 if (rb_integer_type_p(sym)) {
12581 /* Load hidden local variables as indexes */
12582 return NUM2ULONG(sym);
12583 }
12584 return rb_sym2id(sym);
12585}
12586
12587/* dump/load: code */
12588
12589static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12590
12591static int
12592ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12593{
12594 if (iseq == NULL) {
12595 return -1;
12596 }
12597 else {
12598 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12599 }
12600}
12601
12602static unsigned char
12603ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12604{
12605 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12606 return (unsigned char)load->current_buffer->buff[(*offset)++];
12607}
12608
12609/*
12610 * Small uint serialization
12611 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12612 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12613 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12614 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12615 * ...
12616 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12617 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12618 */
12619static void
12620ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12621{
12622 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12623 ibf_dump_write(dump, &x, sizeof(VALUE));
12624 return;
12625 }
12626
12627 enum { max_byte_length = sizeof(VALUE) + 1 };
12628
12629 unsigned char bytes[max_byte_length];
12630 ibf_offset_t n;
12631
12632 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12633 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12634 }
12635
12636 x <<= 1;
12637 x |= 1;
12638 x <<= n;
12639 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12640 n++;
12641
12642 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12643}
12644
12645static VALUE
12646ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12647{
12648 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12649 union { char s[sizeof(VALUE)]; VALUE v; } x;
12650
12651 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12652 *offset += sizeof(VALUE);
12653
12654 return x.v;
12655 }
12656
12657 enum { max_byte_length = sizeof(VALUE) + 1 };
12658
12659 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12660 const unsigned char c = buffer[*offset];
12661
12662 ibf_offset_t n =
12663 c & 1 ? 1 :
12664 c == 0 ? 9 : ntz_int32(c) + 1;
12665 VALUE x = (VALUE)c >> n;
12666
12667 if (*offset + n > load->current_buffer->size) {
12668 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12669 }
12670
12671 ibf_offset_t i;
12672 for (i = 1; i < n; i++) {
12673 x <<= 8;
12674 x |= (VALUE)buffer[*offset + i];
12675 }
12676
12677 *offset += n;
12678 return x;
12679}
12680
12681static void
12682ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12683{
12684 // short: index
12685 // short: name.length
12686 // bytes: name
12687 // // omit argc (only verify with name)
12688 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12689
12690 size_t len = strlen(bf->name);
12691 ibf_dump_write_small_value(dump, (VALUE)len);
12692 ibf_dump_write(dump, bf->name, len);
12693}
12694
12695static const struct rb_builtin_function *
12696ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12697{
12698 int i = (int)ibf_load_small_value(load, offset);
12699 int len = (int)ibf_load_small_value(load, offset);
12700 const char *name = (char *)ibf_load_ptr(load, offset, len);
12701
12702 if (0) {
12703 fprintf(stderr, "%.*s!!\n", len, name);
12704 }
12705
12706 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12707 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12708 if (strncmp(table[i].name, name, len) != 0) {
12709 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12710 }
12711 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12712
12713 return &table[i];
12714}
12715
12716static ibf_offset_t
12717ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12718{
12719 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12720 const int iseq_size = body->iseq_size;
12721 int code_index;
12722 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12723
12724 ibf_offset_t offset = ibf_dump_pos(dump);
12725
12726 for (code_index=0; code_index<iseq_size;) {
12727 const VALUE insn = orig_code[code_index++];
12728 const char *types = insn_op_types(insn);
12729 int op_index;
12730
12731 /* opcode */
12732 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12733 ibf_dump_write_small_value(dump, insn);
12734
12735 /* operands */
12736 for (op_index=0; types[op_index]; op_index++, code_index++) {
12737 VALUE op = orig_code[code_index];
12738 VALUE wv;
12739
12740 switch (types[op_index]) {
12741 case TS_CDHASH:
12742 case TS_VALUE:
12743 wv = ibf_dump_object(dump, op);
12744 break;
12745 case TS_ISEQ:
12746 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12747 break;
12748 case TS_IC:
12749 {
12750 IC ic = (IC)op;
12751 VALUE arr = idlist_to_array(ic->segments);
12752 wv = ibf_dump_object(dump, arr);
12753 }
12754 break;
12755 case TS_ISE:
12756 case TS_IVC:
12757 case TS_ICVARC:
12758 {
12759 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)op;
12760 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12761 }
12762 break;
12763 case TS_CALLDATA:
12764 {
12765 goto skip_wv;
12766 }
12767 case TS_ID:
12768 wv = ibf_dump_id(dump, (ID)op);
12769 break;
12770 case TS_FUNCPTR:
12771 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12772 goto skip_wv;
12773 case TS_BUILTIN:
12774 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12775 goto skip_wv;
12776 default:
12777 wv = op;
12778 break;
12779 }
12780 ibf_dump_write_small_value(dump, wv);
12781 skip_wv:;
12782 }
12783 RUBY_ASSERT(insn_len(insn) == op_index+1);
12784 }
12785
12786 return offset;
12787}
12788
12789static VALUE *
12790ibf_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)
12791{
12792 VALUE iseqv = (VALUE)iseq;
12793 unsigned int code_index;
12794 ibf_offset_t reading_pos = bytecode_offset;
12795 VALUE *code = ALLOC_N(VALUE, iseq_size);
12796
12797 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12798 struct rb_call_data *cd_entries = load_body->call_data;
12799 int ic_index = 0;
12800
12801 iseq_bits_t * mark_offset_bits;
12802
12803 iseq_bits_t tmp[1] = {0};
12804
12805 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12806 mark_offset_bits = tmp;
12807 }
12808 else {
12809 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12810 }
12811 bool needs_bitmap = false;
12812
12813 for (code_index=0; code_index<iseq_size;) {
12814 /* opcode */
12815 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12816 const char *types = insn_op_types(insn);
12817 int op_index;
12818
12819 code_index++;
12820
12821 /* operands */
12822 for (op_index=0; types[op_index]; op_index++, code_index++) {
12823 const char operand_type = types[op_index];
12824 switch (operand_type) {
12825 case TS_VALUE:
12826 {
12827 VALUE op = ibf_load_small_value(load, &reading_pos);
12828 VALUE v = ibf_load_object(load, op);
12829 code[code_index] = v;
12830 if (!SPECIAL_CONST_P(v)) {
12831 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12832 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12833 needs_bitmap = true;
12834 }
12835 break;
12836 }
12837 case TS_CDHASH:
12838 {
12839 VALUE op = ibf_load_small_value(load, &reading_pos);
12840 VALUE v = ibf_load_object(load, op);
12841 v = rb_hash_dup(v); // hash dumped as frozen
12842 RHASH_TBL_RAW(v)->type = &cdhash_type;
12843 rb_hash_rehash(v); // hash function changed
12844 freeze_hide_obj(v);
12845
12846 // Overwrite the existing hash in the object list. This
12847 // is to keep the object alive during load time.
12848 // [Bug #17984] [ruby-core:104259]
12849 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12850
12851 code[code_index] = v;
12852 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12853 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12854 needs_bitmap = true;
12855 break;
12856 }
12857 case TS_ISEQ:
12858 {
12859 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12860 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12861 code[code_index] = v;
12862 if (!SPECIAL_CONST_P(v)) {
12863 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12864 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12865 needs_bitmap = true;
12866 }
12867 break;
12868 }
12869 case TS_IC:
12870 {
12871 VALUE op = ibf_load_small_value(load, &reading_pos);
12872 VALUE arr = ibf_load_object(load, op);
12873
12874 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12875 ic->segments = array_to_idlist(arr);
12876
12877 code[code_index] = (VALUE)ic;
12878 }
12879 break;
12880 case TS_ISE:
12881 case TS_ICVARC:
12882 case TS_IVC:
12883 {
12884 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
12885
12886 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12887 code[code_index] = (VALUE)ic;
12888
12889 if (operand_type == TS_IVC) {
12890 IVC cache = (IVC)ic;
12891
12892 if (insn == BIN(setinstancevariable)) {
12893 ID iv_name = (ID)code[code_index - 1];
12894 cache->iv_set_name = iv_name;
12895 }
12896 else {
12897 cache->iv_set_name = 0;
12898 }
12899
12900 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12901 }
12902
12903 }
12904 break;
12905 case TS_CALLDATA:
12906 {
12907 code[code_index] = (VALUE)cd_entries++;
12908 }
12909 break;
12910 case TS_ID:
12911 {
12912 VALUE op = ibf_load_small_value(load, &reading_pos);
12913 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
12914 }
12915 break;
12916 case TS_FUNCPTR:
12917 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12918 break;
12919 case TS_BUILTIN:
12920 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
12921 break;
12922 default:
12923 code[code_index] = ibf_load_small_value(load, &reading_pos);
12924 continue;
12925 }
12926 }
12927 if (insn_len(insn) != op_index+1) {
12928 rb_raise(rb_eRuntimeError, "operand size mismatch");
12929 }
12930 }
12931
12932 load_body->iseq_encoded = code;
12933 load_body->iseq_size = code_index;
12934
12935 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
12936 load_body->mark_bits.single = mark_offset_bits[0];
12937 }
12938 else {
12939 if (needs_bitmap) {
12940 load_body->mark_bits.list = mark_offset_bits;
12941 }
12942 else {
12943 load_body->mark_bits.list = 0;
12944 ruby_xfree(mark_offset_bits);
12945 }
12946 }
12947
12948 RUBY_ASSERT(code_index == iseq_size);
12949 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
12950 return code;
12951}
12952
12953static ibf_offset_t
12954ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12955{
12956 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
12957
12958 if (opt_num > 0) {
12959 IBF_W_ALIGN(VALUE);
12960 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
12961 }
12962 else {
12963 return ibf_dump_pos(dump);
12964 }
12965}
12966
12967static VALUE *
12968ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
12969{
12970 if (opt_num > 0) {
12971 VALUE *table = ALLOC_N(VALUE, opt_num+1);
12972 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
12973 return table;
12974 }
12975 else {
12976 return NULL;
12977 }
12978}
12979
12980static ibf_offset_t
12981ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
12982{
12983 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
12984
12985 if (kw) {
12986 struct rb_iseq_param_keyword dump_kw = *kw;
12987 int dv_num = kw->num - kw->required_num;
12988 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
12989 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
12990 int i;
12991
12992 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12993 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12994
12995 dump_kw.table = IBF_W(ids, ID, kw->num);
12996 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12997 IBF_W_ALIGN(struct rb_iseq_param_keyword);
12998 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12999 }
13000 else {
13001 return 0;
13002 }
13003}
13004
13005static const struct rb_iseq_param_keyword *
13006ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13007{
13008 if (param_keyword_offset) {
13009 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13010 int dv_num = kw->num - kw->required_num;
13011 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13012
13013 int i;
13014 for (i=0; i<dv_num; i++) {
13015 dvs[i] = ibf_load_object(load, dvs[i]);
13016 }
13017
13018 // Will be set once the local table is loaded.
13019 kw->table = NULL;
13020
13021 kw->default_values = dvs;
13022 return kw;
13023 }
13024 else {
13025 return NULL;
13026 }
13027}
13028
13029static ibf_offset_t
13030ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13031{
13032 ibf_offset_t offset = ibf_dump_pos(dump);
13033 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13034
13035 unsigned int i;
13036 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13037 ibf_dump_write_small_value(dump, entries[i].line_no);
13038#ifdef USE_ISEQ_NODE_ID
13039 ibf_dump_write_small_value(dump, entries[i].node_id);
13040#endif
13041 ibf_dump_write_small_value(dump, entries[i].events);
13042 }
13043
13044 return offset;
13045}
13046
13047static struct iseq_insn_info_entry *
13048ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13049{
13050 ibf_offset_t reading_pos = body_offset;
13051 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13052
13053 unsigned int i;
13054 for (i = 0; i < size; i++) {
13055 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13056#ifdef USE_ISEQ_NODE_ID
13057 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13058#endif
13059 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13060 }
13061
13062 return entries;
13063}
13064
13065static ibf_offset_t
13066ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13067{
13068 ibf_offset_t offset = ibf_dump_pos(dump);
13069
13070 unsigned int last = 0;
13071 unsigned int i;
13072 for (i = 0; i < size; i++) {
13073 ibf_dump_write_small_value(dump, positions[i] - last);
13074 last = positions[i];
13075 }
13076
13077 return offset;
13078}
13079
13080static unsigned int *
13081ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13082{
13083 ibf_offset_t reading_pos = positions_offset;
13084 unsigned int *positions = ALLOC_N(unsigned int, size);
13085
13086 unsigned int last = 0;
13087 unsigned int i;
13088 for (i = 0; i < size; i++) {
13089 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13090 last = positions[i];
13091 }
13092
13093 return positions;
13094}
13095
13096static ibf_offset_t
13097ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13098{
13099 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13100 const int size = body->local_table_size;
13101 ID *table = ALLOCA_N(ID, size);
13102 int i;
13103
13104 for (i=0; i<size; i++) {
13105 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13106 if (v == 0) {
13107 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13108 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13109 }
13110 table[i] = v;
13111 }
13112
13113 IBF_W_ALIGN(ID);
13114 return ibf_dump_write(dump, table, sizeof(ID) * size);
13115}
13116
13117static ID *
13118ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13119{
13120 if (size > 0) {
13121 ID *table = IBF_R(local_table_offset, ID, size);
13122 int i;
13123
13124 for (i=0; i<size; i++) {
13125 table[i] = ibf_load_id(load, table[i]);
13126 }
13127 return table;
13128 }
13129 else {
13130 return NULL;
13131 }
13132}
13133
13134static ibf_offset_t
13135ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13136{
13137 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13138
13139 if (table) {
13140 int *iseq_indices = ALLOCA_N(int, table->size);
13141 unsigned int i;
13142
13143 for (i=0; i<table->size; i++) {
13144 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13145 }
13146
13147 const ibf_offset_t offset = ibf_dump_pos(dump);
13148
13149 for (i=0; i<table->size; i++) {
13150 ibf_dump_write_small_value(dump, iseq_indices[i]);
13151 ibf_dump_write_small_value(dump, table->entries[i].type);
13152 ibf_dump_write_small_value(dump, table->entries[i].start);
13153 ibf_dump_write_small_value(dump, table->entries[i].end);
13154 ibf_dump_write_small_value(dump, table->entries[i].cont);
13155 ibf_dump_write_small_value(dump, table->entries[i].sp);
13156 }
13157 return offset;
13158 }
13159 else {
13160 return ibf_dump_pos(dump);
13161 }
13162}
13163
13164static struct iseq_catch_table *
13165ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13166{
13167 if (size) {
13168 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13169 table->size = size;
13170
13171 ibf_offset_t reading_pos = catch_table_offset;
13172
13173 unsigned int i;
13174 for (i=0; i<table->size; i++) {
13175 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13176 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13177 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13178 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13179 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13180 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13181
13182 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13183 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13184 }
13185 return table;
13186 }
13187 else {
13188 return NULL;
13189 }
13190}
13191
13192static ibf_offset_t
13193ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13194{
13195 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13196 const unsigned int ci_size = body->ci_size;
13197 const struct rb_call_data *cds = body->call_data;
13198
13199 ibf_offset_t offset = ibf_dump_pos(dump);
13200
13201 unsigned int i;
13202
13203 for (i = 0; i < ci_size; i++) {
13204 const struct rb_callinfo *ci = cds[i].ci;
13205 if (ci != NULL) {
13206 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13207 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13208 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13209
13210 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13211 if (kwarg) {
13212 int len = kwarg->keyword_len;
13213 ibf_dump_write_small_value(dump, len);
13214 for (int j=0; j<len; j++) {
13215 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13216 ibf_dump_write_small_value(dump, keyword);
13217 }
13218 }
13219 else {
13220 ibf_dump_write_small_value(dump, 0);
13221 }
13222 }
13223 else {
13224 // TODO: truncate NULL ci from call_data.
13225 ibf_dump_write_small_value(dump, (VALUE)-1);
13226 }
13227 }
13228
13229 return offset;
13230}
13231
13232 struct outer_variable_pair {
13233 ID id;
13234 VALUE name;
13235 VALUE val;
13236};
13237
13238 struct outer_variable_list {
13239 size_t num;
13240 struct outer_variable_pair pairs[1];
13241};
13242
13243static enum rb_id_table_iterator_result
13244store_outer_variable(ID id, VALUE val, void *dump)
13245{
13246 struct outer_variable_list *ovlist = dump;
13247 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13248 pair->id = id;
13249 pair->name = rb_id2str(id);
13250 pair->val = val;
13251 return ID_TABLE_CONTINUE;
13252}
13253
13254static int
13255outer_variable_cmp(const void *a, const void *b, void *arg)
13256{
13257 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13258 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13259
13260 if (!ap->name) {
13261 return -1;
13262 } else if (!bp->name) {
13263 return 1;
13264 }
13265
13266 return rb_str_cmp(ap->name, bp->name);
13267}
13268
13269static ibf_offset_t
13270ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13271{
13272 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13273
13274 ibf_offset_t offset = ibf_dump_pos(dump);
13275
13276 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13277 ibf_dump_write_small_value(dump, (VALUE)size);
13278 if (size > 0) {
13279 VALUE buff;
13280 size_t buffsize =
13281 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13282 offsetof(struct outer_variable_list, pairs),
13283 rb_eArgError);
13284 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13285 ovlist->num = 0;
13286 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13287 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13288 for (size_t i = 0; i < size; ++i) {
13289 ID id = ovlist->pairs[i].id;
13290 ID val = ovlist->pairs[i].val;
13291 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13292 ibf_dump_write_small_value(dump, val);
13293 }
13294 }
13295
13296 return offset;
13297}
13298
13299/* note that we dump out rb_call_info but load back rb_call_data */
13300static void
13301ibf_load_ci_entries(const struct ibf_load *load,
13302 ibf_offset_t ci_entries_offset,
13303 unsigned int ci_size,
13304 struct rb_call_data **cd_ptr)
13305{
13306 ibf_offset_t reading_pos = ci_entries_offset;
13307
13308 unsigned int i;
13309
13310 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13311 *cd_ptr = cds;
13312
13313 for (i = 0; i < ci_size; i++) {
13314 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13315 if (mid_index != (VALUE)-1) {
13316 ID mid = ibf_load_id(load, mid_index);
13317 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13318 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13319
13320 struct rb_callinfo_kwarg *kwarg = NULL;
13321 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13322 if (kwlen > 0) {
13323 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13324 kwarg->references = 0;
13325 kwarg->keyword_len = kwlen;
13326 for (int j=0; j<kwlen; j++) {
13327 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13328 kwarg->keywords[j] = ibf_load_object(load, keyword);
13329 }
13330 }
13331
13332 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13333 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13334 cds[i].cc = vm_cc_empty();
13335 }
13336 else {
13337 // NULL ci
13338 cds[i].ci = NULL;
13339 cds[i].cc = NULL;
13340 }
13341 }
13342}
13343
13344static struct rb_id_table *
13345ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13346{
13347 ibf_offset_t reading_pos = outer_variables_offset;
13348
13349 struct rb_id_table *tbl = NULL;
13350
13351 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13352
13353 if (table_size > 0) {
13354 tbl = rb_id_table_create(table_size);
13355 }
13356
13357 for (size_t i = 0; i < table_size; i++) {
13358 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13359 VALUE value = ibf_load_small_value(load, &reading_pos);
13360 if (!key) key = rb_make_temporary_id(i);
13361 rb_id_table_insert(tbl, key, value);
13362 }
13363
13364 return tbl;
13365}
13366
13367static ibf_offset_t
13368ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13369{
13370 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13371
13372 unsigned int *positions;
13373
13374 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13375
13376 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13377 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13378 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13379
13380#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13381 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13382
13383 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13384 struct ibf_dump_buffer buffer;
13385 buffer.str = rb_str_new(0, 0);
13386 buffer.obj_table = ibf_dump_object_table_new();
13387 dump->current_buffer = &buffer;
13388#endif
13389
13390 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13391 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13392 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13393 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13394 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13395
13396 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13397 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13398 ruby_xfree(positions);
13399
13400 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13401 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13402 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13403 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13404 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13405 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13406 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13407 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13408
13409#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13410 ibf_offset_t local_obj_list_offset;
13411 unsigned int local_obj_list_size;
13412
13413 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13414#endif
13415
13416 ibf_offset_t body_offset = ibf_dump_pos(dump);
13417
13418 /* dump the constant body */
13419 unsigned int param_flags =
13420 (body->param.flags.has_lead << 0) |
13421 (body->param.flags.has_opt << 1) |
13422 (body->param.flags.has_rest << 2) |
13423 (body->param.flags.has_post << 3) |
13424 (body->param.flags.has_kw << 4) |
13425 (body->param.flags.has_kwrest << 5) |
13426 (body->param.flags.has_block << 6) |
13427 (body->param.flags.ambiguous_param0 << 7) |
13428 (body->param.flags.accepts_no_kwarg << 8) |
13429 (body->param.flags.ruby2_keywords << 9) |
13430 (body->param.flags.anon_rest << 10) |
13431 (body->param.flags.anon_kwrest << 11) |
13432 (body->param.flags.use_block << 12) |
13433 (body->param.flags.forwardable << 13) ;
13434
13435#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13436# define IBF_BODY_OFFSET(x) (x)
13437#else
13438# define IBF_BODY_OFFSET(x) (body_offset - (x))
13439#endif
13440
13441 ibf_dump_write_small_value(dump, body->type);
13442 ibf_dump_write_small_value(dump, body->iseq_size);
13443 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13444 ibf_dump_write_small_value(dump, bytecode_size);
13445 ibf_dump_write_small_value(dump, param_flags);
13446 ibf_dump_write_small_value(dump, body->param.size);
13447 ibf_dump_write_small_value(dump, body->param.lead_num);
13448 ibf_dump_write_small_value(dump, body->param.opt_num);
13449 ibf_dump_write_small_value(dump, body->param.rest_start);
13450 ibf_dump_write_small_value(dump, body->param.post_start);
13451 ibf_dump_write_small_value(dump, body->param.post_num);
13452 ibf_dump_write_small_value(dump, body->param.block_start);
13453 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13454 ibf_dump_write_small_value(dump, param_keyword_offset);
13455 ibf_dump_write_small_value(dump, location_pathobj_index);
13456 ibf_dump_write_small_value(dump, location_base_label_index);
13457 ibf_dump_write_small_value(dump, location_label_index);
13458 ibf_dump_write_small_value(dump, body->location.first_lineno);
13459 ibf_dump_write_small_value(dump, body->location.node_id);
13460 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13461 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13462 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13463 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13464 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13465 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13466 ibf_dump_write_small_value(dump, body->insns_info.size);
13467 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13468 ibf_dump_write_small_value(dump, catch_table_size);
13469 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13470 ibf_dump_write_small_value(dump, parent_iseq_index);
13471 ibf_dump_write_small_value(dump, local_iseq_index);
13472 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13473 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13474 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13475 ibf_dump_write_small_value(dump, body->variable.flip_count);
13476 ibf_dump_write_small_value(dump, body->local_table_size);
13477 ibf_dump_write_small_value(dump, body->ivc_size);
13478 ibf_dump_write_small_value(dump, body->icvarc_size);
13479 ibf_dump_write_small_value(dump, body->ise_size);
13480 ibf_dump_write_small_value(dump, body->ic_size);
13481 ibf_dump_write_small_value(dump, body->ci_size);
13482 ibf_dump_write_small_value(dump, body->stack_max);
13483 ibf_dump_write_small_value(dump, body->builtin_attrs);
13484 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13485
13486#undef IBF_BODY_OFFSET
13487
13488#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13489 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13490
13491 dump->current_buffer = saved_buffer;
13492 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13493
13494 ibf_offset_t offset = ibf_dump_pos(dump);
13495 ibf_dump_write_small_value(dump, iseq_start);
13496 ibf_dump_write_small_value(dump, iseq_length_bytes);
13497 ibf_dump_write_small_value(dump, body_offset);
13498
13499 ibf_dump_write_small_value(dump, local_obj_list_offset);
13500 ibf_dump_write_small_value(dump, local_obj_list_size);
13501
13502 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13503
13504 return offset;
13505#else
13506 return body_offset;
13507#endif
13508}
13509
13510static VALUE
13511ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13512{
13513 VALUE str = ibf_load_object(load, str_index);
13514 if (str != Qnil) {
13515 str = rb_fstring(str);
13516 }
13517 return str;
13518}
13519
13520static void
13521ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13522{
13523 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13524
13525 ibf_offset_t reading_pos = offset;
13526
13527#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13528 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13529 load->current_buffer = &load->global_buffer;
13530
13531 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13532 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13533 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13534
13535 struct ibf_load_buffer buffer;
13536 buffer.buff = load->global_buffer.buff + iseq_start;
13537 buffer.size = iseq_length_bytes;
13538 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13539 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13540 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13541
13542 load->current_buffer = &buffer;
13543 reading_pos = body_offset;
13544#endif
13545
13546#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13547# define IBF_BODY_OFFSET(x) (x)
13548#else
13549# define IBF_BODY_OFFSET(x) (offset - (x))
13550#endif
13551
13552 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13553 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13554 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13555 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13556 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13557 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13558 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13559 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13560 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13561 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13562 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13563 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13564 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13565 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13566 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13567 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13568 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13569 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13570 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13571 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13572 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13573 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13574 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13575 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13576 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13577 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13578 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13579 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13580 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13581 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13582 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13583 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13584 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13585 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13586 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13587 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13588
13589 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13590 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13591 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13592 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13593
13594 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13595 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13596 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13597 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13598
13599 // setup fname and dummy frame
13600 VALUE path = ibf_load_object(load, location_pathobj_index);
13601 {
13602 VALUE realpath = Qnil;
13603
13604 if (RB_TYPE_P(path, T_STRING)) {
13605 realpath = path = rb_fstring(path);
13606 }
13607 else if (RB_TYPE_P(path, T_ARRAY)) {
13608 VALUE pathobj = path;
13609 if (RARRAY_LEN(pathobj) != 2) {
13610 rb_raise(rb_eRuntimeError, "path object size mismatch");
13611 }
13612 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13613 realpath = RARRAY_AREF(pathobj, 1);
13614 if (!NIL_P(realpath)) {
13615 if (!RB_TYPE_P(realpath, T_STRING)) {
13616 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13617 "(%x), path=%+"PRIsVALUE,
13618 realpath, TYPE(realpath), path);
13619 }
13620 realpath = rb_fstring(realpath);
13621 }
13622 }
13623 else {
13624 rb_raise(rb_eRuntimeError, "unexpected path object");
13625 }
13626 rb_iseq_pathobj_set(iseq, path, realpath);
13627 }
13628
13629 // push dummy frame
13630 rb_execution_context_t *ec = GET_EC();
13631 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13632
13633#undef IBF_BODY_OFFSET
13634
13635 load_body->type = type;
13636 load_body->stack_max = stack_max;
13637 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13638 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13639 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13640 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13641 load_body->param.flags.has_kw = FALSE;
13642 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13643 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13644 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13645 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13646 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13647 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13648 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13649 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13650 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13651 load_body->param.size = param_size;
13652 load_body->param.lead_num = param_lead_num;
13653 load_body->param.opt_num = param_opt_num;
13654 load_body->param.rest_start = param_rest_start;
13655 load_body->param.post_start = param_post_start;
13656 load_body->param.post_num = param_post_num;
13657 load_body->param.block_start = param_block_start;
13658 load_body->local_table_size = local_table_size;
13659 load_body->ci_size = ci_size;
13660 load_body->insns_info.size = insns_info_size;
13661
13662 ISEQ_COVERAGE_SET(iseq, Qnil);
13663 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13664 load_body->variable.flip_count = variable_flip_count;
13665 load_body->variable.script_lines = Qnil;
13666
13667 load_body->location.first_lineno = location_first_lineno;
13668 load_body->location.node_id = location_node_id;
13669 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13670 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13671 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13672 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13673 load_body->builtin_attrs = builtin_attrs;
13674 load_body->prism = prism;
13675
13676 load_body->ivc_size = ivc_size;
13677 load_body->icvarc_size = icvarc_size;
13678 load_body->ise_size = ise_size;
13679 load_body->ic_size = ic_size;
13680
13681 if (ISEQ_IS_SIZE(load_body)) {
13682 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13683 }
13684 else {
13685 load_body->is_entries = NULL;
13686 }
13687 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13688 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13689 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13690 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13691 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13692 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13693 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13694 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13695 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13696 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13697 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13698 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13699
13700 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13701 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13702 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13703
13704 // This must be done after the local table is loaded.
13705 if (load_body->param.keyword != NULL) {
13706 RUBY_ASSERT(load_body->local_table);
13707 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13708 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13709 }
13710
13711 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13712#if VM_INSN_INFO_TABLE_IMPL == 2
13713 rb_iseq_insns_info_encode_positions(iseq);
13714#endif
13715
13716 rb_iseq_translate_threaded_code(iseq);
13717
13718#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13719 load->current_buffer = &load->global_buffer;
13720#endif
13721
13722 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13723 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13724
13725#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13726 load->current_buffer = saved_buffer;
13727#endif
13728 verify_call_cache(iseq);
13729
13730 RB_GC_GUARD(dummy_frame);
13731 rb_vm_pop_frame_no_int(ec);
13732}
13733
13734 struct ibf_dump_iseq_list_arg
13735{
13736 struct ibf_dump *dump;
13737 VALUE offset_list;
13738};
13739
13740static int
13741ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13742{
13743 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13744 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13745
13746 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13747 rb_ary_push(args->offset_list, UINT2NUM(offset));
13748
13749 return ST_CONTINUE;
13750}
13751
13752static void
13753ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13754{
13755 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13756
13757 struct ibf_dump_iseq_list_arg args;
13758 args.dump = dump;
13759 args.offset_list = offset_list;
13760
13761 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13762
13763 st_index_t i;
13764 st_index_t size = dump->iseq_table->num_entries;
13765 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13766
13767 for (i = 0; i < size; i++) {
13768 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13769 }
13770
13771 ibf_dump_align(dump, sizeof(ibf_offset_t));
13772 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13773 header->iseq_list_size = (unsigned int)size;
13774}
13775
13776#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13777
13778/*
13779 * Binary format
13780 * - ibf_object_header
13781 * - ibf_object_xxx (xxx is type)
13782 */
13783
13784 struct ibf_object_header {
13785 unsigned int type: 5;
13786 unsigned int special_const: 1;
13787 unsigned int frozen: 1;
13788 unsigned int internal: 1;
13789};
13790
13791enum ibf_object_class_index {
13792 IBF_OBJECT_CLASS_OBJECT,
13793 IBF_OBJECT_CLASS_ARRAY,
13794 IBF_OBJECT_CLASS_STANDARD_ERROR,
13795 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13796 IBF_OBJECT_CLASS_TYPE_ERROR,
13797 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13798};
13799
13800 struct ibf_object_regexp {
13801 long srcstr;
13802 char option;
13803};
13804
13805 struct ibf_object_hash {
13806 long len;
13807 long keyval[FLEX_ARY_LEN];
13808};
13809
13810 struct ibf_object_struct_range {
13811 long class_index;
13812 long len;
13813 long beg;
13814 long end;
13815 int excl;
13816};
13817
13818 struct ibf_object_bignum {
13819 ssize_t slen;
13820 BDIGIT digits[FLEX_ARY_LEN];
13821};
13822
13823enum ibf_object_data_type {
13824 IBF_OBJECT_DATA_ENCODING,
13825};
13826
13827 struct ibf_object_complex_rational {
13828 long a, b;
13829};
13830
13831 struct ibf_object_symbol {
13832 long str;
13833};
13834
13835#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13836 ((((offset) - 1) / (align) + 1) * (align))
13837#define IBF_OBJBODY(type, offset) (const type *)\
13838 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13839
13840static const void *
13841ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13842{
13843 if (offset >= load->current_buffer->size) {
13844 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13845 }
13846 return load->current_buffer->buff + offset;
13847}
13848
13849NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13850
13851static void
13852ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13853{
13854 char buff[0x100];
13855 rb_raw_obj_info(buff, sizeof(buff), obj);
13856 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13857}
13858
13859NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13860
13861static VALUE
13862ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13863{
13864 rb_raise(rb_eArgError, "unsupported");
13865 UNREACHABLE_RETURN(Qnil);
13866}
13867
13868static void
13869ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13870{
13871 enum ibf_object_class_index cindex;
13872 if (obj == rb_cObject) {
13873 cindex = IBF_OBJECT_CLASS_OBJECT;
13874 }
13875 else if (obj == rb_cArray) {
13876 cindex = IBF_OBJECT_CLASS_ARRAY;
13877 }
13878 else if (obj == rb_eStandardError) {
13879 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13880 }
13881 else if (obj == rb_eNoMatchingPatternError) {
13882 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13883 }
13884 else if (obj == rb_eTypeError) {
13885 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13886 }
13887 else if (obj == rb_eNoMatchingPatternKeyError) {
13888 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13889 }
13890 else {
13891 rb_obj_info_dump(obj);
13892 rb_p(obj);
13893 rb_bug("unsupported class");
13894 }
13895 ibf_dump_write_small_value(dump, (VALUE)cindex);
13896}
13897
13898static VALUE
13899ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13900{
13901 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13902
13903 switch (cindex) {
13904 case IBF_OBJECT_CLASS_OBJECT:
13905 return rb_cObject;
13906 case IBF_OBJECT_CLASS_ARRAY:
13907 return rb_cArray;
13908 case IBF_OBJECT_CLASS_STANDARD_ERROR:
13909 return rb_eStandardError;
13910 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13911 return rb_eNoMatchingPatternError;
13912 case IBF_OBJECT_CLASS_TYPE_ERROR:
13913 return rb_eTypeError;
13914 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13915 return rb_eNoMatchingPatternKeyError;
13916 }
13917
13918 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
13919}
13920
13921
13922static void
13923ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
13924{
13925 double dbl = RFLOAT_VALUE(obj);
13926 (void)IBF_W(&dbl, double, 1);
13927}
13928
13929static VALUE
13930ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13931{
13932 double d;
13933 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
13934 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
13935 return DBL2NUM(d);
13936}
13937
13938static void
13939ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
13940{
13941 long encindex = (long)rb_enc_get_index(obj);
13942 long len = RSTRING_LEN(obj);
13943 const char *ptr = RSTRING_PTR(obj);
13944
13945 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13946 rb_encoding *enc = rb_enc_from_index((int)encindex);
13947 const char *enc_name = rb_enc_name(enc);
13948 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
13949 }
13950
13951 ibf_dump_write_small_value(dump, encindex);
13952 ibf_dump_write_small_value(dump, len);
13953 IBF_WP(ptr, char, len);
13954}
13955
13956static VALUE
13957ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13958{
13959 ibf_offset_t reading_pos = offset;
13960
13961 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13962 const long len = (long)ibf_load_small_value(load, &reading_pos);
13963 const char *ptr = load->current_buffer->buff + reading_pos;
13964
13965 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13966 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13967 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13968 }
13969
13970 VALUE str;
13971 if (header->frozen && !header->internal) {
13972 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
13973 }
13974 else {
13975 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
13976
13977 if (header->internal) rb_obj_hide(str);
13978 if (header->frozen) str = rb_fstring(str);
13979 }
13980 return str;
13981}
13982
13983static void
13984ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
13985{
13986 VALUE srcstr = RREGEXP_SRC(obj);
13987 struct ibf_object_regexp regexp;
13988 regexp.option = (char)rb_reg_options(obj);
13989 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
13990
13991 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
13992 ibf_dump_write_small_value(dump, regexp.srcstr);
13993}
13994
13995static VALUE
13996ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13997{
13998 struct ibf_object_regexp regexp;
13999 regexp.option = ibf_load_byte(load, &offset);
14000 regexp.srcstr = ibf_load_small_value(load, &offset);
14001
14002 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14003 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14004
14005 if (header->internal) rb_obj_hide(reg);
14006 if (header->frozen) rb_obj_freeze(reg);
14007
14008 return reg;
14009}
14010
14011static void
14012ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14013{
14014 long i, len = RARRAY_LEN(obj);
14015 ibf_dump_write_small_value(dump, len);
14016 for (i=0; i<len; i++) {
14017 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14018 ibf_dump_write_small_value(dump, index);
14019 }
14020}
14021
14022static VALUE
14023ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14024{
14025 ibf_offset_t reading_pos = offset;
14026
14027 const long len = (long)ibf_load_small_value(load, &reading_pos);
14028
14029 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14030 int i;
14031
14032 for (i=0; i<len; i++) {
14033 const VALUE index = ibf_load_small_value(load, &reading_pos);
14034 rb_ary_push(ary, ibf_load_object(load, index));
14035 }
14036
14037 if (header->frozen) rb_ary_freeze(ary);
14038
14039 return ary;
14040}
14041
14042static int
14043ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14044{
14045 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14046
14047 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14048 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14049
14050 ibf_dump_write_small_value(dump, key_index);
14051 ibf_dump_write_small_value(dump, val_index);
14052 return ST_CONTINUE;
14053}
14054
14055static void
14056ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14057{
14058 long len = RHASH_SIZE(obj);
14059 ibf_dump_write_small_value(dump, (VALUE)len);
14060
14061 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14062}
14063
14064static VALUE
14065ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14066{
14067 long len = (long)ibf_load_small_value(load, &offset);
14068 VALUE obj = rb_hash_new_with_size(len);
14069 int i;
14070
14071 for (i = 0; i < len; i++) {
14072 VALUE key_index = ibf_load_small_value(load, &offset);
14073 VALUE val_index = ibf_load_small_value(load, &offset);
14074
14075 VALUE key = ibf_load_object(load, key_index);
14076 VALUE val = ibf_load_object(load, val_index);
14077 rb_hash_aset(obj, key, val);
14078 }
14079 rb_hash_rehash(obj);
14080
14081 if (header->internal) rb_obj_hide(obj);
14082 if (header->frozen) rb_obj_freeze(obj);
14083
14084 return obj;
14085}
14086
14087static void
14088ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14089{
14090 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14091 struct ibf_object_struct_range range;
14092 VALUE beg, end;
14093 IBF_ZERO(range);
14094 range.len = 3;
14095 range.class_index = 0;
14096
14097 rb_range_values(obj, &beg, &end, &range.excl);
14098 range.beg = (long)ibf_dump_object(dump, beg);
14099 range.end = (long)ibf_dump_object(dump, end);
14100
14101 IBF_W_ALIGN(struct ibf_object_struct_range);
14102 IBF_WV(range);
14103 }
14104 else {
14105 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14106 rb_class_name(CLASS_OF(obj)));
14107 }
14108}
14109
14110static VALUE
14111ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14112{
14113 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14114 VALUE beg = ibf_load_object(load, range->beg);
14115 VALUE end = ibf_load_object(load, range->end);
14116 VALUE obj = rb_range_new(beg, end, range->excl);
14117 if (header->internal) rb_obj_hide(obj);
14118 if (header->frozen) rb_obj_freeze(obj);
14119 return obj;
14120}
14121
14122static void
14123ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14124{
14125 ssize_t len = BIGNUM_LEN(obj);
14126 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14127 BDIGIT *d = BIGNUM_DIGITS(obj);
14128
14129 (void)IBF_W(&slen, ssize_t, 1);
14130 IBF_WP(d, BDIGIT, len);
14131}
14132
14133static VALUE
14134ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14135{
14136 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14137 int sign = bignum->slen > 0;
14138 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14139 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14140 INTEGER_PACK_LSWORD_FIRST |
14141 INTEGER_PACK_NATIVE_BYTE_ORDER;
14142 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14143 big_unpack_flags |
14144 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14145 if (header->internal) rb_obj_hide(obj);
14146 if (header->frozen) rb_obj_freeze(obj);
14147 return obj;
14148}
14149
14150static void
14151ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14152{
14153 if (rb_data_is_encoding(obj)) {
14154 rb_encoding *enc = rb_to_encoding(obj);
14155 const char *name = rb_enc_name(enc);
14156 long len = strlen(name) + 1;
14157 long data[2];
14158 data[0] = IBF_OBJECT_DATA_ENCODING;
14159 data[1] = len;
14160 (void)IBF_W(data, long, 2);
14161 IBF_WP(name, char, len);
14162 }
14163 else {
14164 ibf_dump_object_unsupported(dump, obj);
14165 }
14166}
14167
14168static VALUE
14169ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14170{
14171 const long *body = IBF_OBJBODY(long, offset);
14172 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14173 /* const long len = body[1]; */
14174 const char *data = (const char *)&body[2];
14175
14176 switch (type) {
14177 case IBF_OBJECT_DATA_ENCODING:
14178 {
14179 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14180 return encobj;
14181 }
14182 }
14183
14184 return ibf_load_object_unsupported(load, header, offset);
14185}
14186
14187static void
14188ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14189{
14190 long data[2];
14191 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14192 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14193
14194 (void)IBF_W(data, long, 2);
14195}
14196
14197static VALUE
14198ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14199{
14200 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14201 VALUE a = ibf_load_object(load, nums->a);
14202 VALUE b = ibf_load_object(load, nums->b);
14203 VALUE obj = header->type == T_COMPLEX ?
14204 rb_complex_new(a, b) : rb_rational_new(a, b);
14205
14206 if (header->internal) rb_obj_hide(obj);
14207 if (header->frozen) rb_obj_freeze(obj);
14208 return obj;
14209}
14210
14211static void
14212ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14213{
14214 ibf_dump_object_string(dump, rb_sym2str(obj));
14215}
14216
14217static VALUE
14218ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14219{
14220 ibf_offset_t reading_pos = offset;
14221
14222 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14223 const long len = (long)ibf_load_small_value(load, &reading_pos);
14224 const char *ptr = load->current_buffer->buff + reading_pos;
14225
14226 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14227 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14228 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14229 }
14230
14231 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14232 return ID2SYM(id);
14233}
14234
14235typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14236static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14237 ibf_dump_object_unsupported, /* T_NONE */
14238 ibf_dump_object_unsupported, /* T_OBJECT */
14239 ibf_dump_object_class, /* T_CLASS */
14240 ibf_dump_object_unsupported, /* T_MODULE */
14241 ibf_dump_object_float, /* T_FLOAT */
14242 ibf_dump_object_string, /* T_STRING */
14243 ibf_dump_object_regexp, /* T_REGEXP */
14244 ibf_dump_object_array, /* T_ARRAY */
14245 ibf_dump_object_hash, /* T_HASH */
14246 ibf_dump_object_struct, /* T_STRUCT */
14247 ibf_dump_object_bignum, /* T_BIGNUM */
14248 ibf_dump_object_unsupported, /* T_FILE */
14249 ibf_dump_object_data, /* T_DATA */
14250 ibf_dump_object_unsupported, /* T_MATCH */
14251 ibf_dump_object_complex_rational, /* T_COMPLEX */
14252 ibf_dump_object_complex_rational, /* T_RATIONAL */
14253 ibf_dump_object_unsupported, /* 0x10 */
14254 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14255 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14256 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14257 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14258 ibf_dump_object_unsupported, /* T_FIXNUM */
14259 ibf_dump_object_unsupported, /* T_UNDEF */
14260 ibf_dump_object_unsupported, /* 0x17 */
14261 ibf_dump_object_unsupported, /* 0x18 */
14262 ibf_dump_object_unsupported, /* 0x19 */
14263 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14264 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14265 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14266 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14267 ibf_dump_object_unsupported, /* 0x1e */
14268 ibf_dump_object_unsupported, /* 0x1f */
14269};
14270
14271static void
14272ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14273{
14274 unsigned char byte =
14275 (header.type << 0) |
14276 (header.special_const << 5) |
14277 (header.frozen << 6) |
14278 (header.internal << 7);
14279
14280 IBF_WV(byte);
14281}
14282
14283static struct ibf_object_header
14284ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14285{
14286 unsigned char byte = ibf_load_byte(load, offset);
14287
14288 struct ibf_object_header header;
14289 header.type = (byte >> 0) & 0x1f;
14290 header.special_const = (byte >> 5) & 0x01;
14291 header.frozen = (byte >> 6) & 0x01;
14292 header.internal = (byte >> 7) & 0x01;
14293
14294 return header;
14295}
14296
14297static ibf_offset_t
14298ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14299{
14300 struct ibf_object_header obj_header;
14301 ibf_offset_t current_offset;
14302 IBF_ZERO(obj_header);
14303 obj_header.type = TYPE(obj);
14304
14305 IBF_W_ALIGN(ibf_offset_t);
14306 current_offset = ibf_dump_pos(dump);
14307
14308 if (SPECIAL_CONST_P(obj) &&
14309 ! (SYMBOL_P(obj) ||
14310 RB_FLOAT_TYPE_P(obj))) {
14311 obj_header.special_const = TRUE;
14312 obj_header.frozen = TRUE;
14313 obj_header.internal = TRUE;
14314 ibf_dump_object_object_header(dump, obj_header);
14315 ibf_dump_write_small_value(dump, obj);
14316 }
14317 else {
14318 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14319 obj_header.special_const = FALSE;
14320 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14321 ibf_dump_object_object_header(dump, obj_header);
14322 (*dump_object_functions[obj_header.type])(dump, obj);
14323 }
14324
14325 return current_offset;
14326}
14327
14328typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14329static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14330 ibf_load_object_unsupported, /* T_NONE */
14331 ibf_load_object_unsupported, /* T_OBJECT */
14332 ibf_load_object_class, /* T_CLASS */
14333 ibf_load_object_unsupported, /* T_MODULE */
14334 ibf_load_object_float, /* T_FLOAT */
14335 ibf_load_object_string, /* T_STRING */
14336 ibf_load_object_regexp, /* T_REGEXP */
14337 ibf_load_object_array, /* T_ARRAY */
14338 ibf_load_object_hash, /* T_HASH */
14339 ibf_load_object_struct, /* T_STRUCT */
14340 ibf_load_object_bignum, /* T_BIGNUM */
14341 ibf_load_object_unsupported, /* T_FILE */
14342 ibf_load_object_data, /* T_DATA */
14343 ibf_load_object_unsupported, /* T_MATCH */
14344 ibf_load_object_complex_rational, /* T_COMPLEX */
14345 ibf_load_object_complex_rational, /* T_RATIONAL */
14346 ibf_load_object_unsupported, /* 0x10 */
14347 ibf_load_object_unsupported, /* T_NIL */
14348 ibf_load_object_unsupported, /* T_TRUE */
14349 ibf_load_object_unsupported, /* T_FALSE */
14350 ibf_load_object_symbol,
14351 ibf_load_object_unsupported, /* T_FIXNUM */
14352 ibf_load_object_unsupported, /* T_UNDEF */
14353 ibf_load_object_unsupported, /* 0x17 */
14354 ibf_load_object_unsupported, /* 0x18 */
14355 ibf_load_object_unsupported, /* 0x19 */
14356 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14357 ibf_load_object_unsupported, /* T_NODE 0x1b */
14358 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14359 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14360 ibf_load_object_unsupported, /* 0x1e */
14361 ibf_load_object_unsupported, /* 0x1f */
14362};
14363
14364static VALUE
14365ibf_load_object(const struct ibf_load *load, VALUE object_index)
14366{
14367 if (object_index == 0) {
14368 return Qnil;
14369 }
14370 else {
14371 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14372 if (!obj) {
14373 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14374 ibf_offset_t offset = offsets[object_index];
14375 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14376
14377#if IBF_ISEQ_DEBUG
14378 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14379 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14380 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14381 header.type, header.special_const, header.frozen, header.internal);
14382#endif
14383 if (offset >= load->current_buffer->size) {
14384 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14385 }
14386
14387 if (header.special_const) {
14388 ibf_offset_t reading_pos = offset;
14389
14390 obj = ibf_load_small_value(load, &reading_pos);
14391 }
14392 else {
14393 obj = (*load_object_functions[header.type])(load, &header, offset);
14394 }
14395
14396 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14397 }
14398#if IBF_ISEQ_DEBUG
14399 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14400 object_index, obj);
14401#endif
14402 return obj;
14403 }
14404}
14405
14406 struct ibf_dump_object_list_arg
14407{
14408 struct ibf_dump *dump;
14409 VALUE offset_list;
14410};
14411
14412static int
14413ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14414{
14415 VALUE obj = (VALUE)key;
14416 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14417
14418 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14419 rb_ary_push(args->offset_list, UINT2NUM(offset));
14420
14421 return ST_CONTINUE;
14422}
14423
14424static void
14425ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14426{
14427 st_table *obj_table = dump->current_buffer->obj_table;
14428 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14429
14430 struct ibf_dump_object_list_arg args;
14431 args.dump = dump;
14432 args.offset_list = offset_list;
14433
14434 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14435
14436 IBF_W_ALIGN(ibf_offset_t);
14437 *obj_list_offset = ibf_dump_pos(dump);
14438
14439 st_index_t size = obj_table->num_entries;
14440 st_index_t i;
14441
14442 for (i=0; i<size; i++) {
14443 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14444 IBF_WV(offset);
14445 }
14446
14447 *obj_list_size = (unsigned int)size;
14448}
14449
14450static void
14451ibf_dump_mark(void *ptr)
14452{
14453 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14454 rb_gc_mark(dump->global_buffer.str);
14455
14456 rb_mark_set(dump->global_buffer.obj_table);
14457 rb_mark_set(dump->iseq_table);
14458}
14459
14460static void
14461ibf_dump_free(void *ptr)
14462{
14463 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14464 if (dump->global_buffer.obj_table) {
14465 st_free_table(dump->global_buffer.obj_table);
14466 dump->global_buffer.obj_table = 0;
14467 }
14468 if (dump->iseq_table) {
14469 st_free_table(dump->iseq_table);
14470 dump->iseq_table = 0;
14471 }
14472}
14473
14474static size_t
14475ibf_dump_memsize(const void *ptr)
14476{
14477 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14478 size_t size = 0;
14479 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14480 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14481 return size;
14482}
14483
14484static const rb_data_type_t ibf_dump_type = {
14485 "ibf_dump",
14486 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14487 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14488};
14489
14490static void
14491ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14492{
14493 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14494 dump->iseq_table = NULL;
14495
14496 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14497 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14498 dump->iseq_table = st_init_numtable(); /* need free */
14499
14500 dump->current_buffer = &dump->global_buffer;
14501}
14502
14503 VALUE
14504rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14505{
14506 struct ibf_dump *dump;
14507 struct ibf_header header = {{0}};
14508 VALUE dump_obj;
14509 VALUE str;
14510
14511 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14512 ISEQ_BODY(iseq)->local_iseq != iseq) {
14513 rb_raise(rb_eRuntimeError, "should be top of iseq");
14514 }
14515 if (RTEST(ISEQ_COVERAGE(iseq))) {
14516 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14517 }
14518
14519 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14520 ibf_dump_setup(dump, dump_obj);
14521
14522 ibf_dump_write(dump, &header, sizeof(header));
14523 ibf_dump_iseq(dump, iseq);
14524
14525 header.magic[0] = 'Y'; /* YARB */
14526 header.magic[1] = 'A';
14527 header.magic[2] = 'R';
14528 header.magic[3] = 'B';
14529 header.major_version = IBF_MAJOR_VERSION;
14530 header.minor_version = IBF_MINOR_VERSION;
14531 header.endian = IBF_ENDIAN_MARK;
14532 header.wordsize = (uint8_t)SIZEOF_VALUE;
14533 ibf_dump_iseq_list(dump, &header);
14534 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14535 header.size = ibf_dump_pos(dump);
14536
14537 if (RTEST(opt)) {
14538 VALUE opt_str = opt;
14539 const char *ptr = StringValuePtr(opt_str);
14540 header.extra_size = RSTRING_LENINT(opt_str);
14541 ibf_dump_write(dump, ptr, header.extra_size);
14542 }
14543 else {
14544 header.extra_size = 0;
14545 }
14546
14547 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14548
14549 str = dump->global_buffer.str;
14550 RB_GC_GUARD(dump_obj);
14551 return str;
14552}
14553
14554static const ibf_offset_t *
14555ibf_iseq_list(const struct ibf_load *load)
14556{
14557 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14558}
14559
14560void
14561rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14562{
14563 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14564 rb_iseq_t *prev_src_iseq = load->iseq;
14565 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14566 load->iseq = iseq;
14567#if IBF_ISEQ_DEBUG
14568 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14569 iseq->aux.loader.index, offset,
14570 load->header->size);
14571#endif
14572 ibf_load_iseq_each(load, iseq, offset);
14573 ISEQ_COMPILE_DATA_CLEAR(iseq);
14574 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14575 rb_iseq_init_trace(iseq);
14576 load->iseq = prev_src_iseq;
14577}
14578
14579#if USE_LAZY_LOAD
14580const rb_iseq_t *
14581rb_iseq_complete(const rb_iseq_t *iseq)
14582{
14583 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14584 return iseq;
14585}
14586#endif
14587
14588static rb_iseq_t *
14589ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14590{
14591 int iseq_index = (int)(VALUE)index_iseq;
14592
14593#if IBF_ISEQ_DEBUG
14594 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14595 (void *)index_iseq, (void *)load->iseq_list);
14596#endif
14597 if (iseq_index == -1) {
14598 return NULL;
14599 }
14600 else {
14601 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14602
14603#if IBF_ISEQ_DEBUG
14604 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14605#endif
14606 if (iseqv) {
14607 return (rb_iseq_t *)iseqv;
14608 }
14609 else {
14610 rb_iseq_t *iseq = iseq_imemo_alloc();
14611#if IBF_ISEQ_DEBUG
14612 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14613#endif
14614 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14615 iseq->aux.loader.obj = load->loader_obj;
14616 iseq->aux.loader.index = iseq_index;
14617#if IBF_ISEQ_DEBUG
14618 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14619 (void *)iseq, (void *)load->loader_obj, iseq_index);
14620#endif
14621 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14622
14623 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14624#if IBF_ISEQ_DEBUG
14625 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14626#endif
14627 rb_ibf_load_iseq_complete(iseq);
14628 }
14629
14630#if IBF_ISEQ_DEBUG
14631 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14632 (void *)iseq, (void *)load->iseq);
14633#endif
14634 return iseq;
14635 }
14636 }
14637}
14638
14639static void
14640ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14641{
14642 struct ibf_header *header = (struct ibf_header *)bytes;
14643 load->loader_obj = loader_obj;
14644 load->global_buffer.buff = bytes;
14645 load->header = header;
14646 load->global_buffer.size = header->size;
14647 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14648 load->global_buffer.obj_list_size = header->global_object_list_size;
14649 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14650 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14651 load->iseq = NULL;
14652
14653 load->current_buffer = &load->global_buffer;
14654
14655 if (size < header->size) {
14656 rb_raise(rb_eRuntimeError, "broken binary format");
14657 }
14658 if (strncmp(header->magic, "YARB", 4) != 0) {
14659 rb_raise(rb_eRuntimeError, "unknown binary format");
14660 }
14661 if (header->major_version != IBF_MAJOR_VERSION ||
14662 header->minor_version != IBF_MINOR_VERSION) {
14663 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14664 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14665 }
14666 if (header->endian != IBF_ENDIAN_MARK) {
14667 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14668 }
14669 if (header->wordsize != SIZEOF_VALUE) {
14670 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14671 }
14672 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14673 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14674 header->iseq_list_offset);
14675 }
14676 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14677 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14678 load->global_buffer.obj_list_offset);
14679 }
14680}
14681
14682static void
14683ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14684{
14685 StringValue(str);
14686
14687 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14688 rb_raise(rb_eRuntimeError, "broken binary format");
14689 }
14690
14691 if (USE_LAZY_LOAD) {
14692 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14693 }
14694
14695 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14696 RB_OBJ_WRITE(loader_obj, &load->str, str);
14697}
14698
14699static void
14700ibf_loader_mark(void *ptr)
14701{
14702 struct ibf_load *load = (struct ibf_load *)ptr;
14703 rb_gc_mark(load->str);
14704 rb_gc_mark(load->iseq_list);
14705 rb_gc_mark(load->global_buffer.obj_list);
14706}
14707
14708static void
14709ibf_loader_free(void *ptr)
14710{
14711 struct ibf_load *load = (struct ibf_load *)ptr;
14712 ruby_xfree(load);
14713}
14714
14715static size_t
14716ibf_loader_memsize(const void *ptr)
14717{
14718 return sizeof(struct ibf_load);
14719}
14720
14721static const rb_data_type_t ibf_load_type = {
14722 "ibf_loader",
14723 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14724 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14725};
14726
14727const rb_iseq_t *
14728rb_iseq_ibf_load(VALUE str)
14729{
14730 struct ibf_load *load;
14731 rb_iseq_t *iseq;
14732 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14733
14734 ibf_load_setup(load, loader_obj, str);
14735 iseq = ibf_load_iseq(load, 0);
14736
14737 RB_GC_GUARD(loader_obj);
14738 return iseq;
14739}
14740
14741const rb_iseq_t *
14742rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14743{
14744 struct ibf_load *load;
14745 rb_iseq_t *iseq;
14746 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14747
14748 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14749 iseq = ibf_load_iseq(load, 0);
14750
14751 RB_GC_GUARD(loader_obj);
14752 return iseq;
14753}
14754
14755 VALUE
14756rb_iseq_ibf_load_extra_data(VALUE str)
14757{
14758 struct ibf_load *load;
14759 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14760 VALUE extra_str;
14761
14762 ibf_load_setup(load, loader_obj, str);
14763 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14764 RB_GC_GUARD(loader_obj);
14765 return extra_str;
14766}
14767
14768#include "prism_compile.c"
RUBY_ASSERT
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
LONG_LONG
#define LONG_LONG
Definition long_long.h:38
RUBY_ALIGNOF
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
RUBY_EVENT_END
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
RUBY_EVENT_C_CALL
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
RUBY_EVENT_B_RETURN
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
RUBY_EVENT_CLASS
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
RUBY_EVENT_NONE
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
RUBY_EVENT_LINE
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
RUBY_EVENT_RETURN
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
RUBY_EVENT_C_RETURN
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
RUBY_EVENT_B_CALL
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
rb_event_flag_t
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
RUBY_EVENT_CALL
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
RUBY_EVENT_RESCUE
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
RBIMPL_ATTR_FORMAT
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format)).
Definition format.h:29
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
T_COMPLEX
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
TYPE
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
NUM2ULONG
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
NUM2LL
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
REALLOC_N
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
ALLOCV
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
RFLOAT_VALUE
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
xfree
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
T_NIL
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
T_FLOAT
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
T_BIGNUM
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
SPECIAL_CONST_P
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
Definition special_consts.h:56
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
ULONG2NUM
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
SYM2ID
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
FIX2UINT
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
ZALLOC
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
FIXABLE
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
xmalloc
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
LONG2FIX
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
FIX2INT
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
NUM2UINT
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
ZALLOC_N
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
ASSUME
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
T_RATIONAL
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
T_HASH
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
FL_SET
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:129
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
NUM2INT
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
FIX2LONG
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
T_ARRAY
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
T_SYMBOL
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
DBL2NUM
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
BUILTIN_TYPE
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
FL_TEST
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
FL_FREEZE
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:67
NUM2LONG
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
FL_UNSET
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:133
UINT2NUM
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
CONST_ID
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
ALLOCV_END
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
SYMBOL_P
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
T_REGEXP
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
ruby_debug
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
rb_eNotImpError
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
rb_eStandardError
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
rb_eNoMatchingPatternError
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
rb_exc_fatal
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:689
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
rb_eNoMatchingPatternKeyError
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
rb_eIndexError
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
rb_eSyntaxError
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
rb_obj_reveal
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:113
rb_cArray
VALUE rb_cArray
Array class.
Definition array.c:40
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:104
rb_cHash
VALUE rb_cHash
Hash class.
Definition hash.c:113
rb_inspect
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
rb_cRange
VALUE rb_cRange
Range class.
Definition range.c:31
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:865
rb_obj_freeze
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1260
RB_OBJ_WRITTEN
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
RB_OBJ_WRITE
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
rb_memerror
void rb_memerror(void)
Triggers out-of-memory error.
Definition gc.c:4501
rb_ary_new
VALUE rb_ary_new(void)
Allocates a new, empty array.
Definition array.c:741
INTEGER_PACK_NATIVE_BYTE_ORDER
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
INTEGER_PACK_NEGATIVE
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
INTEGER_PACK_LSWORD_FIRST
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
rb_hash_new
VALUE rb_hash_new(void)
Creates a new, empty hash object.
Definition hash.c:1477
rb_is_const_id
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1064
rb_is_attrset_id
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1088
rb_range_values
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1804
rb_range_new
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:68
rb_rational_new
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
rb_reg_options
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4198
rb_str_append
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3685
rb_str_tmp_new
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1678
rb_str_hash_cmp
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4054
rb_str_new
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
rb_str_hash
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4040
rb_str_cat
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3453
rb_str_cmp
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4110
rb_str_concat
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:3927
rb_str_freeze
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3185
rb_str_new_cstr
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:492
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
rb_id2sym
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:952
rb_sym2str
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:971
rb_sym2id
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:918
len
int len
Length of the buffer.
Definition io.h:8
ractor.h
rb_ractor_make_shareable
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:3118
re.h
util.h
DECIMAL_SIZE_OF
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
ruby_qsort
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
rb_long2int
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
MEMCPY
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
ALLOCA_N
#define ALLOCA_N(type, n)
Definition memory.h:292
MEMZERO
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
RB_GC_GUARD
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
RB_ALLOCV
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition cxxanyargs.hpp:56
ruby::backward::cxxanyargs::st_foreach
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition cxxanyargs.hpp:432
ruby::backward::cxxanyargs::rb_hash_foreach
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
Definition cxxanyargs.hpp:482
RBIMPL_ATTR_NORETURN
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]].
Definition noreturn.h:38
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
RARRAY_LENINT
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
RARRAY_ASET
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
RBASIC_CLASS
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:153
RUBY_DEFAULT_FREE
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
RUBY_DATA_FUNC
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
RHASH_SIZE
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
RREGEXP_SRC
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
StringValue
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
StringValuePtr
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
RSTRING_LENINT
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:449
rb_data_type_t
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:197
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
rb_p
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9046
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
METHOD
Definition proc.c:30
RComplex
Internal header for Complex.
Definition complex.h:13
RNode_LIST
Definition rubyparser.h:557
RRational
Internal header for Rational.
Definition rational.h:16
cdhash_set_label_struct
Definition compile.c:2276
ensure_range
Definition compile.c:115
ibf_dump_buffer
Definition compile.c:12340
ibf_dump_iseq_list_arg
Definition compile.c:13735
ibf_dump_object_list_arg
Definition compile.c:14407
ibf_dump
Definition compile.c:12345
ibf_header
Definition compile.c:12325
ibf_load_buffer
Definition compile.c:12351
ibf_load
Definition compile.c:12360
ibf_object_bignum
Definition compile.c:13818
ibf_object_complex_rational
Definition compile.c:13827
ibf_object_hash
Definition compile.c:13805
ibf_object_header
Definition compile.c:13784
ibf_object_regexp
Definition compile.c:13800
ibf_object_struct_range
Definition compile.c:13810
ibf_object_symbol
Definition compile.c:13831
iseq_adjust_data
Definition compile.c:103
iseq_catch_table_entry
Definition iseq.h:270
iseq_catch_table
Definition iseq.h:281
iseq_compile_data_ensure_node_stack
Definition compile.c:121
iseq_compile_data_storage
Definition iseq.h:300
iseq_inline_constant_cache::segments
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
iseq_insn_data
Definition compile.c:90
iseq_insn_info_entry
Definition iseq.h:241
iseq_label_data
Definition compile.c:78
iseq_link_anchor
Definition compile.c:66
iseq_link_element
Definition compile.c:54
iseq_trace_data
Definition compile.c:109
masgn_lhs_node
Definition compile.c:5517
masgn_state
Definition compile.c:5526
outer_variable_list
Definition compile.c:13238
outer_variable_pair
Definition compile.c:13232
pinned_list
Definition compile.c:12370
rb_args_info
Definition rubyparser.h:739
rb_builtin_function
Definition builtin.h:6
rb_call_data
Definition vm_callinfo.h:576
rb_callcache
Definition vm_callinfo.h:278
rb_callinfo_kwarg
Definition vm_callinfo.h:48
rb_callinfo
Definition vm_callinfo.h:65
rb_id_table
Definition id_table.c:41
rb_iseq_constant_body
Definition vm_core.h:404
rb_iseq_constant_body::param
struct rb_iseq_constant_body::@000024342312237062266020177166377106262102236123 param
parameter information
rb_iseq_new_with_callback_callback_func
Definition vm_core.h:1233
st_table
Definition st.h:79
iseq_inline_storage_entry
Definition vm_core.h:297
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
SIZEOF_VALUE
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_FLOAT_TYPE_P
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
rb_integer_type_p
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
RB_TYPE_P
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
RUBY_T_MASK
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145