Ruby: compile.c Source File

Ruby 3.4.4p34 (2025-05-14 revision a38531fd3f617bf734ef7d6c595325f69985ea1d)

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
3135optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3136{
3137 /*
3138 * putobject obj
3139 * dup
3140 * checktype T_XXX
3141 * branchif l1
3142 * l2:
3143 * ...
3144 * l1:
3145 *
3146 * => obj is a T_XXX
3147 *
3148 * putobject obj (T_XXX)
3149 * jump L1
3150 * L1:
3151 *
3152 * => obj is not a T_XXX
3153 *
3154 * putobject obj (T_XXX)
3155 * jump L2
3156 * L2:
3157 */
3158 int line, node_id;
3159 INSN *niobj, *ciobj, *dup = 0;
3160 LABEL *dest = 0;
3161 VALUE type;
3162
3163 switch (INSN_OF(iobj)) {
3164 case BIN(putstring):
3165 case BIN(putchilledstring):
3166 type = INT2FIX(T_STRING);
3167 break;
3168 case BIN(putnil):
3169 type = INT2FIX(T_NIL);
3170 break;
3171 case BIN(putobject):
3172 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3173 break;
3174 default: return FALSE;
3175 }
3176
3177 ciobj = (INSN *)get_next_insn(iobj);
3178 if (IS_INSN_ID(ciobj, jump)) {
3179 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3180 }
3181 if (IS_INSN_ID(ciobj, dup)) {
3182 ciobj = (INSN *)get_next_insn(dup = ciobj);
3183 }
3184 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3185 niobj = (INSN *)get_next_insn(ciobj);
3186 if (!niobj) {
3187 /* TODO: putobject true/false */
3188 return FALSE;
3189 }
3190 switch (INSN_OF(niobj)) {
3191 case BIN(branchif):
3192 if (OPERAND_AT(ciobj, 0) == type) {
3193 dest = (LABEL *)OPERAND_AT(niobj, 0);
3194 }
3195 break;
3196 case BIN(branchunless):
3197 if (OPERAND_AT(ciobj, 0) != type) {
3198 dest = (LABEL *)OPERAND_AT(niobj, 0);
3199 }
3200 break;
3201 default:
3202 return FALSE;
3203 }
3204 line = ciobj->insn_info.line_no;
3205 node_id = ciobj->insn_info.node_id;
3206 if (!dest) {
3207 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3208 dest = (LABEL *)niobj->link.next; /* reuse label */
3209 }
3210 else {
3211 dest = NEW_LABEL(line);
3212 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3213 }
3214 }
3215 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3216 LABEL_REF(dest);
3217 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3218 return TRUE;
3219}
3220
3221static const struct rb_callinfo *
3222ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3223{
3224 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3225 vm_ci_flag(ci) | add,
3226 vm_ci_argc(ci),
3227 vm_ci_kwarg(ci));
3228 RB_OBJ_WRITTEN(iseq, ci, nci);
3229 return nci;
3230}
3231
3232static const struct rb_callinfo *
3233ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3234{
3235 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3236 vm_ci_flag(ci),
3237 argc,
3238 vm_ci_kwarg(ci));
3239 RB_OBJ_WRITTEN(iseq, ci, nci);
3240 return nci;
3241}
3242
3243#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3244
3245static int
3246iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3247{
3248 INSN *const iobj = (INSN *)list;
3249
3250 again:
3251 optimize_checktype(iseq, iobj);
3252
3253 if (IS_INSN_ID(iobj, jump)) {
3254 INSN *niobj, *diobj, *piobj;
3255 diobj = (INSN *)get_destination_insn(iobj);
3256 niobj = (INSN *)get_next_insn(iobj);
3257
3258 if (diobj == niobj) {
3259 /*
3260 * jump LABEL
3261 * LABEL:
3262 * =>
3263 * LABEL:
3264 */
3265 unref_destination(iobj, 0);
3266 ELEM_REMOVE(&iobj->link);
3267 return COMPILE_OK;
3268 }
3269 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3270 IS_INSN_ID(diobj, jump) &&
3271 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3272 diobj->insn_info.events == 0) {
3273 /*
3274 * useless jump elimination:
3275 * jump LABEL1
3276 * ...
3277 * LABEL1:
3278 * jump LABEL2
3279 *
3280 * => in this case, first jump instruction should jump to
3281 * LABEL2 directly
3282 */
3283 if (replace_destination(iobj, diobj)) {
3284 remove_unreachable_chunk(iseq, iobj->link.next);
3285 goto again;
3286 }
3287 }
3288 else if (IS_INSN_ID(diobj, leave)) {
3289 /*
3290 * jump LABEL
3291 * ...
3292 * LABEL:
3293 * leave
3294 * =>
3295 * leave
3296 * ...
3297 * LABEL:
3298 * leave
3299 */
3300 /* replace */
3301 unref_destination(iobj, 0);
3302 iobj->insn_id = BIN(leave);
3303 iobj->operand_size = 0;
3304 iobj->insn_info = diobj->insn_info;
3305 goto again;
3306 }
3307 else if (IS_INSN(iobj->link.prev) &&
3308 (piobj = (INSN *)iobj->link.prev) &&
3309 (IS_INSN_ID(piobj, branchif) ||
3310 IS_INSN_ID(piobj, branchunless))) {
3311 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3312 if (niobj == pdiobj) {
3313 int refcnt = IS_LABEL(piobj->link.next) ?
3314 ((LABEL *)piobj->link.next)->refcnt : 0;
3315 /*
3316 * useless jump elimination (if/unless destination):
3317 * if L1
3318 * jump L2
3319 * L1:
3320 * ...
3321 * L2:
3322 *
3323 * ==>
3324 * unless L2
3325 * L1:
3326 * ...
3327 * L2:
3328 */
3329 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3330 ? BIN(branchunless) : BIN(branchif);
3331 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3332 ELEM_REMOVE(&iobj->link);
3333 }
3334 else {
3335 /* TODO: replace other branch destinations too */
3336 }
3337 return COMPILE_OK;
3338 }
3339 else if (diobj == pdiobj) {
3340 /*
3341 * useless jump elimination (if/unless before jump):
3342 * L1:
3343 * ...
3344 * if L1
3345 * jump L1
3346 *
3347 * ==>
3348 * L1:
3349 * ...
3350 * pop
3351 * jump L1
3352 */
3353 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3354 ELEM_REPLACE(&piobj->link, &popiobj->link);
3355 }
3356 }
3357 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3358 goto again;
3359 }
3360 }
3361
3362 /*
3363 * putstring "beg"
3364 * putstring "end"
3365 * newrange excl
3366 *
3367 * ==>
3368 *
3369 * putobject "beg".."end"
3370 */
3371 if (IS_INSN_ID(iobj, newrange)) {
3372 INSN *const range = iobj;
3373 INSN *beg, *end;
3374 VALUE str_beg, str_end;
3375
3376 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3377 is_frozen_putstring(end, &str_end) &&
3378 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3379 is_frozen_putstring(beg, &str_beg)) {
3380 int excl = FIX2INT(OPERAND_AT(range, 0));
3381 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3382
3383 ELEM_REMOVE(&beg->link);
3384 ELEM_REMOVE(&end->link);
3385 range->insn_id = BIN(putobject);
3386 OPERAND_AT(range, 0) = lit_range;
3387 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3388 }
3389 }
3390
3391 if (IS_INSN_ID(iobj, leave)) {
3392 remove_unreachable_chunk(iseq, iobj->link.next);
3393 }
3394
3395 /*
3396 * ...
3397 * duparray [...]
3398 * concatarray | concattoarray
3399 * =>
3400 * ...
3401 * putobject [...]
3402 * concatarray | concattoarray
3403 */
3404 if (IS_INSN_ID(iobj, duparray)) {
3405 LINK_ELEMENT *next = iobj->link.next;
3406 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3407 iobj->insn_id = BIN(putobject);
3408 }
3409 }
3410
3411 /*
3412 * duparray [...]
3413 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3414 * =>
3415 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3416 */
3417 if (IS_INSN_ID(iobj, duparray)) {
3418 LINK_ELEMENT *next = iobj->link.next;
3419 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3420 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3421 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3422
3423 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3424 VALUE ary = iobj->operands[0];
3425 rb_obj_reveal(ary, rb_cArray);
3426
3427 iobj->insn_id = BIN(opt_ary_freeze);
3428 iobj->operand_size = 2;
3429 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3430 iobj->operands[0] = ary;
3431 iobj->operands[1] = (VALUE)ci;
3432 ELEM_REMOVE(next);
3433 }
3434 }
3435 }
3436
3437 /*
3438 * duphash {...}
3439 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3440 * =>
3441 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3442 */
3443 if (IS_INSN_ID(iobj, duphash)) {
3444 LINK_ELEMENT *next = iobj->link.next;
3445 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3446 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3447 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3448
3449 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3450 VALUE hash = iobj->operands[0];
3451 rb_obj_reveal(hash, rb_cHash);
3452
3453 iobj->insn_id = BIN(opt_hash_freeze);
3454 iobj->operand_size = 2;
3455 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3456 iobj->operands[0] = hash;
3457 iobj->operands[1] = (VALUE)ci;
3458 ELEM_REMOVE(next);
3459 }
3460 }
3461 }
3462
3463 /*
3464 * newarray 0
3465 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3466 * =>
3467 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3468 */
3469 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3470 LINK_ELEMENT *next = iobj->link.next;
3471 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3472 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3473 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3474
3475 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3476 iobj->insn_id = BIN(opt_ary_freeze);
3477 iobj->operand_size = 2;
3478 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3479 iobj->operands[0] = rb_cArray_empty_frozen;
3480 iobj->operands[1] = (VALUE)ci;
3481 ELEM_REMOVE(next);
3482 }
3483 }
3484 }
3485
3486 /*
3487 * newhash 0
3488 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3489 * =>
3490 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3491 */
3492 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3493 LINK_ELEMENT *next = iobj->link.next;
3494 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3495 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3496 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3497
3498 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3499 iobj->insn_id = BIN(opt_hash_freeze);
3500 iobj->operand_size = 2;
3501 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3502 iobj->operands[0] = rb_cHash_empty_frozen;
3503 iobj->operands[1] = (VALUE)ci;
3504 ELEM_REMOVE(next);
3505 }
3506 }
3507 }
3508
3509 if (IS_INSN_ID(iobj, branchif) ||
3510 IS_INSN_ID(iobj, branchnil) ||
3511 IS_INSN_ID(iobj, branchunless)) {
3512 /*
3513 * if L1
3514 * ...
3515 * L1:
3516 * jump L2
3517 * =>
3518 * if L2
3519 */
3520 INSN *nobj = (INSN *)get_destination_insn(iobj);
3521
3522 /* This is super nasty hack!!!
3523 *
3524 * This jump-jump optimization may ignore event flags of the jump
3525 * instruction being skipped. Actually, Line 2 TracePoint event
3526 * is never fired in the following code:
3527 *
3528 * 1: raise if 1 == 2
3529 * 2: while true
3530 * 3: break
3531 * 4: end
3532 *
3533 * This is critical for coverage measurement. [Bug #15980]
3534 *
3535 * This is a stopgap measure: stop the jump-jump optimization if
3536 * coverage measurement is enabled and if the skipped instruction
3537 * has any event flag.
3538 *
3539 * Note that, still, TracePoint Line event does not occur on Line 2.
3540 * This should be fixed in future.
3541 */
3542 int stop_optimization =
3543 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3544 nobj->link.type == ISEQ_ELEMENT_INSN &&
3545 nobj->insn_info.events;
3546 if (!stop_optimization) {
3547 INSN *pobj = (INSN *)iobj->link.prev;
3548 int prev_dup = 0;
3549 if (pobj) {
3550 if (!IS_INSN(&pobj->link))
3551 pobj = 0;
3552 else if (IS_INSN_ID(pobj, dup))
3553 prev_dup = 1;
3554 }
3555
3556 for (;;) {
3557 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3558 if (!replace_destination(iobj, nobj)) break;
3559 }
3560 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3561 !!(nobj = (INSN *)nobj->link.next) &&
3562 /* basic blocks, with no labels in the middle */
3563 nobj->insn_id == iobj->insn_id) {
3564 /*
3565 * dup
3566 * if L1
3567 * ...
3568 * L1:
3569 * dup
3570 * if L2
3571 * =>
3572 * dup
3573 * if L2
3574 * ...
3575 * L1:
3576 * dup
3577 * if L2
3578 */
3579 if (!replace_destination(iobj, nobj)) break;
3580 }
3581 else if (pobj) {
3582 /*
3583 * putnil
3584 * if L1
3585 * =>
3586 * # nothing
3587 *
3588 * putobject true
3589 * if L1
3590 * =>
3591 * jump L1
3592 *
3593 * putstring ".."
3594 * if L1
3595 * =>
3596 * jump L1
3597 *
3598 * putstring ".."
3599 * dup
3600 * if L1
3601 * =>
3602 * putstring ".."
3603 * jump L1
3604 *
3605 */
3606 int cond;
3607 if (prev_dup && IS_INSN(pobj->link.prev)) {
3608 pobj = (INSN *)pobj->link.prev;
3609 }
3610 if (IS_INSN_ID(pobj, putobject)) {
3611 cond = (IS_INSN_ID(iobj, branchif) ?
3612 OPERAND_AT(pobj, 0) != Qfalse :
3613 IS_INSN_ID(iobj, branchunless) ?
3614 OPERAND_AT(pobj, 0) == Qfalse :
3615 FALSE);
3616 }
3617 else if (IS_INSN_ID(pobj, putstring) ||
3618 IS_INSN_ID(pobj, duparray) ||
3619 IS_INSN_ID(pobj, newarray)) {
3620 cond = IS_INSN_ID(iobj, branchif);
3621 }
3622 else if (IS_INSN_ID(pobj, putnil)) {
3623 cond = !IS_INSN_ID(iobj, branchif);
3624 }
3625 else break;
3626 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3627 ELEM_REMOVE(iobj->link.prev);
3628 }
3629 else if (!iseq_pop_newarray(iseq, pobj)) {
3630 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3631 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3632 }
3633 if (cond) {
3634 if (prev_dup) {
3635 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3636 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3637 }
3638 iobj->insn_id = BIN(jump);
3639 goto again;
3640 }
3641 else {
3642 unref_destination(iobj, 0);
3643 ELEM_REMOVE(&iobj->link);
3644 }
3645 break;
3646 }
3647 else break;
3648 nobj = (INSN *)get_destination_insn(nobj);
3649 }
3650 }
3651 }
3652
3653 if (IS_INSN_ID(iobj, pop)) {
3654 /*
3655 * putself / putnil / putobject obj / putstring "..."
3656 * pop
3657 * =>
3658 * # do nothing
3659 */
3660 LINK_ELEMENT *prev = iobj->link.prev;
3661 if (IS_INSN(prev)) {
3662 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3663 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3664 previ == BIN(putself) || previ == BIN(putstring) ||
3665 previ == BIN(putchilledstring) ||
3666 previ == BIN(dup) ||
3667 previ == BIN(getlocal) ||
3668 previ == BIN(getblockparam) ||
3669 previ == BIN(getblockparamproxy) ||
3670 previ == BIN(getinstancevariable) ||
3671 previ == BIN(duparray)) {
3672 /* just push operand or static value and pop soon, no
3673 * side effects */
3674 ELEM_REMOVE(prev);
3675 ELEM_REMOVE(&iobj->link);
3676 }
3677 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3678 ELEM_REMOVE(&iobj->link);
3679 }
3680 else if (previ == BIN(concatarray)) {
3681 INSN *piobj = (INSN *)prev;
3682 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3683 INSN_OF(piobj) = BIN(pop);
3684 }
3685 else if (previ == BIN(concatstrings)) {
3686 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3687 ELEM_REMOVE(prev);
3688 }
3689 else {
3690 ELEM_REMOVE(&iobj->link);
3691 INSN_OF(prev) = BIN(adjuststack);
3692 }
3693 }
3694 }
3695 }
3696
3697 if (IS_INSN_ID(iobj, newarray) ||
3698 IS_INSN_ID(iobj, duparray) ||
3699 IS_INSN_ID(iobj, concatarray) ||
3700 IS_INSN_ID(iobj, splatarray) ||
3701 0) {
3702 /*
3703 * newarray N
3704 * splatarray
3705 * =>
3706 * newarray N
3707 * newarray always puts an array
3708 */
3709 LINK_ELEMENT *next = iobj->link.next;
3710 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3711 /* remove splatarray following always-array insn */
3712 ELEM_REMOVE(next);
3713 }
3714 }
3715
3716 if (IS_INSN_ID(iobj, newarray)) {
3717 LINK_ELEMENT *next = iobj->link.next;
3718 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3719 OPERAND_AT(next, 1) == INT2FIX(0)) {
3720 VALUE op1, op2;
3721 op1 = OPERAND_AT(iobj, 0);
3722 op2 = OPERAND_AT(next, 0);
3723 ELEM_REMOVE(next);
3724
3725 if (op1 == op2) {
3726 /*
3727 * newarray 2
3728 * expandarray 2, 0
3729 * =>
3730 * swap
3731 */
3732 if (op1 == INT2FIX(2)) {
3733 INSN_OF(iobj) = BIN(swap);
3734 iobj->operand_size = 0;
3735 }
3736 /*
3737 * newarray X
3738 * expandarray X, 0
3739 * =>
3740 * opt_reverse X
3741 */
3742 else {
3743 INSN_OF(iobj) = BIN(opt_reverse);
3744 }
3745 }
3746 else {
3747 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3748 INSN_OF(iobj) = BIN(opt_reverse);
3749 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3750
3751 if (op1 > op2) {
3752 /* X > Y
3753 * newarray X
3754 * expandarray Y, 0
3755 * =>
3756 * pop * (Y-X)
3757 * opt_reverse Y
3758 */
3759 for (; diff > 0; diff--) {
3760 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3761 }
3762 }
3763 else { /* (op1 < op2) */
3764 /* X < Y
3765 * newarray X
3766 * expandarray Y, 0
3767 * =>
3768 * putnil * (Y-X)
3769 * opt_reverse Y
3770 */
3771 for (; diff < 0; diff++) {
3772 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3773 }
3774 }
3775 }
3776 }
3777 }
3778
3779 if (IS_INSN_ID(iobj, duparray)) {
3780 LINK_ELEMENT *next = iobj->link.next;
3781 /*
3782 * duparray obj
3783 * expandarray X, 0
3784 * =>
3785 * putobject obj
3786 * expandarray X, 0
3787 */
3788 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3789 INSN_OF(iobj) = BIN(putobject);
3790 }
3791 }
3792
3793 if (IS_INSN_ID(iobj, anytostring)) {
3794 LINK_ELEMENT *next = iobj->link.next;
3795 /*
3796 * anytostring
3797 * concatstrings 1
3798 * =>
3799 * anytostring
3800 */
3801 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3802 OPERAND_AT(next, 0) == INT2FIX(1)) {
3803 ELEM_REMOVE(next);
3804 }
3805 }
3806
3807 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3808 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3809 /*
3810 * putstring ""
3811 * concatstrings N
3812 * =>
3813 * concatstrings N-1
3814 */
3815 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3816 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3817 INSN *next = (INSN *)iobj->link.next;
3818 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3819 ELEM_REMOVE(&next->link);
3820 }
3821 ELEM_REMOVE(&iobj->link);
3822 }
3823 }
3824
3825 if (IS_INSN_ID(iobj, concatstrings)) {
3826 /*
3827 * concatstrings N
3828 * concatstrings M
3829 * =>
3830 * concatstrings N+M-1
3831 */
3832 LINK_ELEMENT *next = iobj->link.next;
3833 INSN *jump = 0;
3834 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3835 next = get_destination_insn(jump = (INSN *)next);
3836 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3837 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3838 OPERAND_AT(iobj, 0) = INT2FIX(n);
3839 if (jump) {
3840 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3841 if (!--label->refcnt) {
3842 ELEM_REMOVE(&label->link);
3843 }
3844 else {
3845 label = NEW_LABEL(0);
3846 OPERAND_AT(jump, 0) = (VALUE)label;
3847 }
3848 label->refcnt++;
3849 ELEM_INSERT_NEXT(next, &label->link);
3850 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3851 }
3852 else {
3853 ELEM_REMOVE(next);
3854 }
3855 }
3856 }
3857
3858 if (do_tailcallopt &&
3859 (IS_INSN_ID(iobj, send) ||
3860 IS_INSN_ID(iobj, opt_aref_with) ||
3861 IS_INSN_ID(iobj, opt_aset_with) ||
3862 IS_INSN_ID(iobj, invokesuper))) {
3863 /*
3864 * send ...
3865 * leave
3866 * =>
3867 * send ..., ... | VM_CALL_TAILCALL, ...
3868 * leave # unreachable
3869 */
3870 INSN *piobj = NULL;
3871 if (iobj->link.next) {
3872 LINK_ELEMENT *next = iobj->link.next;
3873 do {
3874 if (!IS_INSN(next)) {
3875 next = next->next;
3876 continue;
3877 }
3878 switch (INSN_OF(next)) {
3879 case BIN(nop):
3880 next = next->next;
3881 break;
3882 case BIN(jump):
3883 /* if cond
3884 * return tailcall
3885 * end
3886 */
3887 next = get_destination_insn((INSN *)next);
3888 break;
3889 case BIN(leave):
3890 piobj = iobj;
3891 /* fall through */
3892 default:
3893 next = NULL;
3894 break;
3895 }
3896 } while (next);
3897 }
3898
3899 if (piobj) {
3900 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3901 if (IS_INSN_ID(piobj, send) ||
3902 IS_INSN_ID(piobj, invokesuper)) {
3903 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3904 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3905 OPERAND_AT(piobj, 0) = (VALUE)ci;
3906 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3907 }
3908 }
3909 else {
3910 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3911 OPERAND_AT(piobj, 0) = (VALUE)ci;
3912 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3913 }
3914 }
3915 }
3916
3917 if (IS_INSN_ID(iobj, dup)) {
3918 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3919 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3920
3921 /*
3922 * dup
3923 * setlocal x, y
3924 * setlocal x, y
3925 * =>
3926 * dup
3927 * setlocal x, y
3928 */
3929 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3930 set2 = set1->next;
3931 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3932 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3933 ELEM_REMOVE(set1);
3934 ELEM_REMOVE(&iobj->link);
3935 }
3936 }
3937
3938 /*
3939 * dup
3940 * setlocal x, y
3941 * dup
3942 * setlocal x, y
3943 * =>
3944 * dup
3945 * setlocal x, y
3946 */
3947 else if (IS_NEXT_INSN_ID(set1, dup) &&
3948 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3949 set2 = set1->next->next;
3950 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3951 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3952 ELEM_REMOVE(set1->next);
3953 ELEM_REMOVE(set2);
3954 }
3955 }
3956 }
3957 }
3958
3959 /*
3960 * getlocal x, y
3961 * dup
3962 * setlocal x, y
3963 * =>
3964 * dup
3965 */
3966 if (IS_INSN_ID(iobj, getlocal)) {
3967 LINK_ELEMENT *niobj = &iobj->link;
3968 if (IS_NEXT_INSN_ID(niobj, dup)) {
3969 niobj = niobj->next;
3970 }
3971 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3972 LINK_ELEMENT *set1 = niobj->next;
3973 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3974 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3975 ELEM_REMOVE(set1);
3976 ELEM_REMOVE(niobj);
3977 }
3978 }
3979 }
3980
3981 /*
3982 * opt_invokebuiltin_delegate
3983 * trace
3984 * leave
3985 * =>
3986 * opt_invokebuiltin_delegate_leave
3987 * trace
3988 * leave
3989 */
3990 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3991 if (IS_TRACE(iobj->link.next)) {
3992 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3993 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3994 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
3995 if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
3996 iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
3997 }
3998 }
3999 }
4000 }
4001
4002 /*
4003 * getblockparam
4004 * branchif / branchunless
4005 * =>
4006 * getblockparamproxy
4007 * branchif / branchunless
4008 */
4009 if (IS_INSN_ID(iobj, getblockparam)) {
4010 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4011 iobj->insn_id = BIN(getblockparamproxy);
4012 }
4013 }
4014
4015 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4016 LINK_ELEMENT *niobj = &iobj->link;
4017 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4018 niobj = niobj->next;
4019 LINK_ELEMENT *siobj;
4020 unsigned int set_flags = 0, unset_flags = 0;
4021
4022 /*
4023 * Eliminate hash allocation for f(*a, kw: 1)
4024 *
4025 * splatarray false
4026 * duphash
4027 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4028 * =>
4029 * splatarray false
4030 * putobject
4031 * send ARGS_SPLAT|KW_SPLAT
4032 */
4033 if (IS_NEXT_INSN_ID(niobj, send)) {
4034 siobj = niobj->next;
4035 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4036 unset_flags = VM_CALL_ARGS_BLOCKARG;
4037 }
4038 /*
4039 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4040 *
4041 * splatarray false
4042 * duphash
4043 * getlocal / getinstancevariable / getblockparamproxy
4044 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4045 * =>
4046 * splatarray false
4047 * putobject
4048 * getlocal / getinstancevariable / getblockparamproxy
4049 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4050 */
4051 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4052 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4053 siobj = niobj->next->next;
4054 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4055 }
4056
4057 if (set_flags) {
4058 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4059 unsigned int flags = vm_ci_flag(ci);
4060 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4061 ((INSN*)niobj)->insn_id = BIN(putobject);
4062 OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
4063
4064 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4065 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4066 RB_OBJ_WRITTEN(iseq, ci, nci);
4067 OPERAND_AT(siobj, 0) = (VALUE)nci;
4068 }
4069 }
4070 }
4071 }
4072
4073 return COMPILE_OK;
4074}
4075
4076static int
4077insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4078{
4079 iobj->insn_id = insn_id;
4080 iobj->operand_size = insn_len(insn_id) - 1;
4081 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4082
4083 if (insn_id == BIN(opt_neq)) {
4084 VALUE original_ci = iobj->operands[0];
4085 iobj->operand_size = 2;
4086 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4087 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4088 iobj->operands[1] = original_ci;
4089 }
4090
4091 return COMPILE_OK;
4092}
4093
4094static int
4095iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4096{
4097 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4098 IS_INSN(iobj->link.next)) {
4099 /*
4100 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4101 */
4102 INSN *niobj = (INSN *)iobj->link.next;
4103 if (IS_INSN_ID(niobj, send)) {
4104 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4105 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4106 VALUE method = INT2FIX(0);
4107 switch (vm_ci_mid(ci)) {
4108 case idMax:
4109 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4110 break;
4111 case idMin:
4112 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4113 break;
4114 case idHash:
4115 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4116 break;
4117 }
4118
4119 if (method != INT2FIX(0)) {
4120 VALUE num = iobj->operands[0];
4121 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4122 iobj->insn_id = BIN(opt_newarray_send);
4123 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4124 iobj->operands[0] = num;
4125 iobj->operands[1] = method;
4126 iobj->operand_size = operand_len;
4127 ELEM_REMOVE(&niobj->link);
4128 return COMPILE_OK;
4129 }
4130 }
4131 }
4132 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4133 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4134 IS_NEXT_INSN_ID(&niobj->link, send)) {
4135 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4136 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4137 VALUE num = iobj->operands[0];
4138 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4139 iobj->insn_id = BIN(opt_newarray_send);
4140 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4141 iobj->operands[0] = FIXNUM_INC(num, 1);
4142 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4143 iobj->operand_size = operand_len;
4144 ELEM_REMOVE(&iobj->link);
4145 ELEM_REMOVE(niobj->link.next);
4146 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4147 return COMPILE_OK;
4148 }
4149 }
4150 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4151 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
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, getlocal) &&
4155 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4156 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4157 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4158 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4159 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4160 VALUE num = iobj->operands[0];
4161 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4162 iobj->insn_id = BIN(opt_newarray_send);
4163 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4164 iobj->operands[0] = FIXNUM_INC(num, 2);
4165 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4166 iobj->operand_size = operand_len;
4167 // Remove the "send" insn.
4168 ELEM_REMOVE((niobj->link.next)->next);
4169 // Remove the modified insn from its original "newarray" position...
4170 ELEM_REMOVE(&iobj->link);
4171 // and insert it after the buffer insn.
4172 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4173 return COMPILE_OK;
4174 }
4175 }
4176
4177 // Break the "else if" chain since some prior checks abort after sub-ifs.
4178 // We already found "newarray". To match `[...].include?(arg)` we look for
4179 // the instruction(s) representing the argument followed by a "send".
4180 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4181 IS_INSN_ID(niobj, putobject) ||
4182 IS_INSN_ID(niobj, putself) ||
4183 IS_INSN_ID(niobj, getlocal) ||
4184 IS_INSN_ID(niobj, getinstancevariable)) &&
4185 IS_NEXT_INSN_ID(&niobj->link, send)) {
4186
4187 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4188 const struct rb_callinfo *ci;
4189 // Allow any number (0 or more) of simple method calls on the argument
4190 // (as in `[...].include?(arg.method1.method2)`.
4191 do {
4192 sendobj = sendobj->next;
4193 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4194 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4195
4196 // If this send is for .include? with one arg we can do our opt.
4197 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4198 VALUE num = iobj->operands[0];
4199 INSN *sendins = (INSN *)sendobj;
4200 sendins->insn_id = BIN(opt_newarray_send);
4201 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4202 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4203 sendins->operands[0] = FIXNUM_INC(num, 1);
4204 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4205 // Remove the original "newarray" insn.
4206 ELEM_REMOVE(&iobj->link);
4207 return COMPILE_OK;
4208 }
4209 }
4210 }
4211
4212 /*
4213 * duparray [...]
4214 * some insn for the arg...
4215 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4216 * =>
4217 * arg insn...
4218 * opt_duparray_send [...], :include?, 1
4219 */
4220 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4221 INSN *niobj = (INSN *)iobj->link.next;
4222 if ((IS_INSN_ID(niobj, getlocal) ||
4223 IS_INSN_ID(niobj, getinstancevariable) ||
4224 IS_INSN_ID(niobj, putself)) &&
4225 IS_NEXT_INSN_ID(&niobj->link, send)) {
4226
4227 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4228 const struct rb_callinfo *ci;
4229 // Allow any number (0 or more) of simple method calls on the argument
4230 // (as in `[...].include?(arg.method1.method2)`.
4231 do {
4232 sendobj = sendobj->next;
4233 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4234 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4235
4236 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4237 // Move the array arg from duparray to opt_duparray_send.
4238 VALUE ary = iobj->operands[0];
4239 rb_obj_reveal(ary, rb_cArray);
4240
4241 INSN *sendins = (INSN *)sendobj;
4242 sendins->insn_id = BIN(opt_duparray_send);
4243 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4244 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4245 sendins->operands[0] = ary;
4246 sendins->operands[1] = rb_id2sym(idIncludeP);
4247 sendins->operands[2] = INT2FIX(1);
4248
4249 // Remove the duparray insn.
4250 ELEM_REMOVE(&iobj->link);
4251 return COMPILE_OK;
4252 }
4253 }
4254 }
4255
4256
4257 if (IS_INSN_ID(iobj, send)) {
4258 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4259 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4260
4261#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4262 if (vm_ci_simple(ci)) {
4263 switch (vm_ci_argc(ci)) {
4264 case 0:
4265 switch (vm_ci_mid(ci)) {
4266 case idLength: SP_INSN(length); return COMPILE_OK;
4267 case idSize: SP_INSN(size); return COMPILE_OK;
4268 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4269 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4270 case idSucc: SP_INSN(succ); return COMPILE_OK;
4271 case idNot: SP_INSN(not); return COMPILE_OK;
4272 }
4273 break;
4274 case 1:
4275 switch (vm_ci_mid(ci)) {
4276 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4277 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4278 case idMULT: SP_INSN(mult); return COMPILE_OK;
4279 case idDIV: SP_INSN(div); return COMPILE_OK;
4280 case idMOD: SP_INSN(mod); return COMPILE_OK;
4281 case idEq: SP_INSN(eq); return COMPILE_OK;
4282 case idNeq: SP_INSN(neq); return COMPILE_OK;
4283 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4284 case idLT: SP_INSN(lt); return COMPILE_OK;
4285 case idLE: SP_INSN(le); return COMPILE_OK;
4286 case idGT: SP_INSN(gt); return COMPILE_OK;
4287 case idGE: SP_INSN(ge); return COMPILE_OK;
4288 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4289 case idAREF: SP_INSN(aref); return COMPILE_OK;
4290 case idAnd: SP_INSN(and); return COMPILE_OK;
4291 case idOr: SP_INSN(or); return COMPILE_OK;
4292 }
4293 break;
4294 case 2:
4295 switch (vm_ci_mid(ci)) {
4296 case idASET: SP_INSN(aset); return COMPILE_OK;
4297 }
4298 break;
4299 }
4300 }
4301
4302 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4303 iobj->insn_id = BIN(opt_send_without_block);
4304 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4305 }
4306 }
4307#undef SP_INSN
4308
4309 return COMPILE_OK;
4310}
4311
4312static inline int
4313tailcallable_p(rb_iseq_t *iseq)
4314{
4315 switch (ISEQ_BODY(iseq)->type) {
4316 case ISEQ_TYPE_TOP:
4317 case ISEQ_TYPE_EVAL:
4318 case ISEQ_TYPE_MAIN:
4319 /* not tail callable because cfp will be over popped */
4320 case ISEQ_TYPE_RESCUE:
4321 case ISEQ_TYPE_ENSURE:
4322 /* rescue block can't tail call because of errinfo */
4323 return FALSE;
4324 default:
4325 return TRUE;
4326 }
4327}
4328
4329static int
4330iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4331{
4332 LINK_ELEMENT *list;
4333 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4334 const int do_tailcallopt = tailcallable_p(iseq) &&
4335 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4336 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4337 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4338 int rescue_level = 0;
4339 int tailcallopt = do_tailcallopt;
4340
4341 list = FIRST_ELEMENT(anchor);
4342
4343 int do_block_optimization = 0;
4344
4345 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4346 do_block_optimization = 1;
4347 }
4348
4349 while (list) {
4350 if (IS_INSN(list)) {
4351 if (do_peepholeopt) {
4352 iseq_peephole_optimize(iseq, list, tailcallopt);
4353 }
4354 if (do_si) {
4355 iseq_specialized_instruction(iseq, (INSN *)list);
4356 }
4357 if (do_ou) {
4358 insn_operands_unification((INSN *)list);
4359 }
4360
4361 if (do_block_optimization) {
4362 INSN * item = (INSN *)list;
4363 if (IS_INSN_ID(item, jump)) {
4364 do_block_optimization = 0;
4365 }
4366 }
4367 }
4368 if (IS_LABEL(list)) {
4369 switch (((LABEL *)list)->rescued) {
4370 case LABEL_RESCUE_BEG:
4371 rescue_level++;
4372 tailcallopt = FALSE;
4373 break;
4374 case LABEL_RESCUE_END:
4375 if (!--rescue_level) tailcallopt = do_tailcallopt;
4376 break;
4377 }
4378 }
4379 list = list->next;
4380 }
4381
4382 if (do_block_optimization) {
4383 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4384 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4385 ELEM_REMOVE(le);
4386 }
4387 }
4388 return COMPILE_OK;
4389}
4390
4391#if OPT_INSTRUCTIONS_UNIFICATION
4392static INSN *
4393new_unified_insn(rb_iseq_t *iseq,
4394 int insn_id, int size, LINK_ELEMENT *seq_list)
4395{
4396 INSN *iobj = 0;
4397 LINK_ELEMENT *list = seq_list;
4398 int i, argc = 0;
4399 VALUE *operands = 0, *ptr = 0;
4400
4401
4402 /* count argc */
4403 for (i = 0; i < size; i++) {
4404 iobj = (INSN *)list;
4405 argc += iobj->operand_size;
4406 list = list->next;
4407 }
4408
4409 if (argc > 0) {
4410 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4411 }
4412
4413 /* copy operands */
4414 list = seq_list;
4415 for (i = 0; i < size; i++) {
4416 iobj = (INSN *)list;
4417 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4418 ptr += iobj->operand_size;
4419 list = list->next;
4420 }
4421
4422 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4423}
4424#endif
4425
4426/*
4427 * This scheme can get more performance if do this optimize with
4428 * label address resolving.
4429 * It's future work (if compile time was bottle neck).
4430 */
4431static int
4432iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4433{
4434#if OPT_INSTRUCTIONS_UNIFICATION
4435 LINK_ELEMENT *list;
4436 INSN *iobj, *niobj;
4437 int id, k;
4438 intptr_t j;
4439
4440 list = FIRST_ELEMENT(anchor);
4441 while (list) {
4442 if (IS_INSN(list)) {
4443 iobj = (INSN *)list;
4444 id = iobj->insn_id;
4445 if (unified_insns_data[id] != 0) {
4446 const int *const *entry = unified_insns_data[id];
4447 for (j = 1; j < (intptr_t)entry[0]; j++) {
4448 const int *unified = entry[j];
4449 LINK_ELEMENT *li = list->next;
4450 for (k = 2; k < unified[1]; k++) {
4451 if (!IS_INSN(li) ||
4452 ((INSN *)li)->insn_id != unified[k]) {
4453 goto miss;
4454 }
4455 li = li->next;
4456 }
4457 /* matched */
4458 niobj =
4459 new_unified_insn(iseq, unified[0], unified[1] - 1,
4460 list);
4461
4462 /* insert to list */
4463 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4464 niobj->link.next = li;
4465 if (li) {
4466 li->prev = (LINK_ELEMENT *)niobj;
4467 }
4468
4469 list->prev->next = (LINK_ELEMENT *)niobj;
4470 list = (LINK_ELEMENT *)niobj;
4471 break;
4472 miss:;
4473 }
4474 }
4475 }
4476 list = list->next;
4477 }
4478#endif
4479 return COMPILE_OK;
4480}
4481
4482static int
4483all_string_result_p(const NODE *node)
4484{
4485 if (!node) return FALSE;
4486 switch (nd_type(node)) {
4487 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4488 return TRUE;
4489 case NODE_IF: case NODE_UNLESS:
4490 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4491 if (all_string_result_p(RNODE_IF(node)->nd_body))
4492 return all_string_result_p(RNODE_IF(node)->nd_else);
4493 return FALSE;
4494 case NODE_AND: case NODE_OR:
4495 if (!RNODE_AND(node)->nd_2nd)
4496 return all_string_result_p(RNODE_AND(node)->nd_1st);
4497 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4498 return FALSE;
4499 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4500 default:
4501 return FALSE;
4502 }
4503}
4504
4505static int
4506compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4507{
4508 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4509 VALUE lit = rb_node_dstr_string_val(node);
4510 LINK_ELEMENT *first_lit = 0;
4511 int cnt = 0;
4512
4513 debugp_param("nd_lit", lit);
4514 if (!NIL_P(lit)) {
4515 cnt++;
4516 if (!RB_TYPE_P(lit, T_STRING)) {
4517 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4518 rb_builtin_type_name(TYPE(lit)));
4519 return COMPILE_NG;
4520 }
4521 lit = rb_fstring(lit);
4522 ADD_INSN1(ret, node, putobject, lit);
4523 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4524 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4525 }
4526
4527 while (list) {
4528 const NODE *const head = list->nd_head;
4529 if (nd_type_p(head, NODE_STR)) {
4530 lit = rb_node_str_string_val(head);
4531 ADD_INSN1(ret, head, putobject, lit);
4532 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4533 lit = Qnil;
4534 }
4535 else {
4536 CHECK(COMPILE(ret, "each string", head));
4537 }
4538 cnt++;
4539 list = (struct RNode_LIST *)list->nd_next;
4540 }
4541 if (NIL_P(lit) && first_lit) {
4542 ELEM_REMOVE(first_lit);
4543 --cnt;
4544 }
4545 *cntp = cnt;
4546
4547 return COMPILE_OK;
4548}
4549
4550static int
4551compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4552{
4553 while (node && nd_type_p(node, NODE_BLOCK)) {
4554 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4555 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4556 node = RNODE_BLOCK(node)->nd_next;
4557 }
4558 if (node) {
4559 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4560 }
4561 return COMPILE_OK;
4562}
4563
4564static int
4565compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4566{
4567 int cnt;
4568 if (!RNODE_DSTR(node)->nd_next) {
4569 VALUE lit = rb_node_dstr_string_val(node);
4570 ADD_INSN1(ret, node, putstring, lit);
4571 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4572 }
4573 else {
4574 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4575 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4576 }
4577 return COMPILE_OK;
4578}
4579
4580static int
4581compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4582{
4583 int cnt;
4584 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4585
4586 if (!RNODE_DREGX(node)->nd_next) {
4587 if (!popped) {
4588 VALUE src = rb_node_dregx_string_val(node);
4589 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4590 ADD_INSN1(ret, node, putobject, match);
4591 RB_OBJ_WRITTEN(iseq, Qundef, match);
4592 }
4593 return COMPILE_OK;
4594 }
4595
4596 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4597 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4598
4599 if (popped) {
4600 ADD_INSN(ret, node, pop);
4601 }
4602
4603 return COMPILE_OK;
4604}
4605
4606static int
4607compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4608 LABEL *then_label, LABEL *else_label)
4609{
4610 const int line = nd_line(node);
4611 LABEL *lend = NEW_LABEL(line);
4612 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4613 + VM_SVAR_FLIPFLOP_START;
4614 VALUE key = INT2FIX(cnt);
4615
4616 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4617 ADD_INSNL(ret, node, branchif, lend);
4618
4619 /* *flip == 0 */
4620 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4621 ADD_INSNL(ret, node, branchunless, else_label);
4622 ADD_INSN1(ret, node, putobject, Qtrue);
4623 ADD_INSN1(ret, node, setspecial, key);
4624 if (!again) {
4625 ADD_INSNL(ret, node, jump, then_label);
4626 }
4627
4628 /* *flip == 1 */
4629 ADD_LABEL(ret, lend);
4630 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4631 ADD_INSNL(ret, node, branchunless, then_label);
4632 ADD_INSN1(ret, node, putobject, Qfalse);
4633 ADD_INSN1(ret, node, setspecial, key);
4634 ADD_INSNL(ret, node, jump, then_label);
4635
4636 return COMPILE_OK;
4637}
4638
4639static int
4640compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4641 LABEL *then_label, LABEL *else_label);
4642
4643#define COMPILE_SINGLE 2
4644static int
4645compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4646 LABEL *then_label, LABEL *else_label)
4647{
4648 DECL_ANCHOR(seq);
4649 INIT_ANCHOR(seq);
4650 LABEL *label = NEW_LABEL(nd_line(cond));
4651 if (!then_label) then_label = label;
4652 else if (!else_label) else_label = label;
4653
4654 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4655
4656 if (LIST_INSN_SIZE_ONE(seq)) {
4657 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4658 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4659 return COMPILE_OK;
4660 }
4661 if (!label->refcnt) {
4662 return COMPILE_SINGLE;
4663 }
4664 ADD_LABEL(seq, label);
4665 ADD_SEQ(ret, seq);
4666 return COMPILE_OK;
4667}
4668
4669static int
4670compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4671 LABEL *then_label, LABEL *else_label)
4672{
4673 int ok;
4674 DECL_ANCHOR(ignore);
4675
4676 again:
4677 switch (nd_type(cond)) {
4678 case NODE_AND:
4679 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4680 cond = RNODE_AND(cond)->nd_2nd;
4681 if (ok == COMPILE_SINGLE) {
4682 INIT_ANCHOR(ignore);
4683 ret = ignore;
4684 then_label = NEW_LABEL(nd_line(cond));
4685 }
4686 goto again;
4687 case NODE_OR:
4688 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4689 cond = RNODE_OR(cond)->nd_2nd;
4690 if (ok == COMPILE_SINGLE) {
4691 INIT_ANCHOR(ignore);
4692 ret = ignore;
4693 else_label = NEW_LABEL(nd_line(cond));
4694 }
4695 goto again;
4696 case NODE_SYM:
4697 case NODE_LINE:
4698 case NODE_FILE:
4699 case NODE_ENCODING:
4700 case NODE_INTEGER: /* NODE_INTEGER is always true */
4701 case NODE_FLOAT: /* NODE_FLOAT is always true */
4702 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4703 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4704 case NODE_TRUE:
4705 case NODE_STR:
4706 case NODE_REGX:
4707 case NODE_ZLIST:
4708 case NODE_LAMBDA:
4709 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4710 ADD_INSNL(ret, cond, jump, then_label);
4711 return COMPILE_OK;
4712 case NODE_FALSE:
4713 case NODE_NIL:
4714 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4715 ADD_INSNL(ret, cond, jump, else_label);
4716 return COMPILE_OK;
4717 case NODE_LIST:
4718 case NODE_ARGSCAT:
4719 case NODE_DREGX:
4720 case NODE_DSTR:
4721 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4722 ADD_INSNL(ret, cond, jump, then_label);
4723 return COMPILE_OK;
4724 case NODE_FLIP2:
4725 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4726 return COMPILE_OK;
4727 case NODE_FLIP3:
4728 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4729 return COMPILE_OK;
4730 case NODE_DEFINED:
4731 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4732 break;
4733 default:
4734 {
4735 DECL_ANCHOR(cond_seq);
4736 INIT_ANCHOR(cond_seq);
4737
4738 CHECK(COMPILE(cond_seq, "branch condition", cond));
4739
4740 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4741 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4742 if (insn->insn_id == BIN(putobject)) {
4743 if (RTEST(insn->operands[0])) {
4744 ADD_INSNL(ret, cond, jump, then_label);
4745 // maybe unreachable
4746 return COMPILE_OK;
4747 }
4748 else {
4749 ADD_INSNL(ret, cond, jump, else_label);
4750 return COMPILE_OK;
4751 }
4752 }
4753 }
4754 ADD_SEQ(ret, cond_seq);
4755 }
4756 break;
4757 }
4758
4759 ADD_INSNL(ret, cond, branchunless, else_label);
4760 ADD_INSNL(ret, cond, jump, then_label);
4761 return COMPILE_OK;
4762}
4763
4764#define HASH_BRACE 1
4765
4766static int
4767keyword_node_p(const NODE *const node)
4768{
4769 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4770}
4771
4772static VALUE
4773get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4774{
4775 switch (nd_type(node)) {
4776 case NODE_SYM:
4777 return rb_node_sym_string_val(node);
4778 default:
4779 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4780 }
4781}
4782
4783static VALUE
4784node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4785{
4786 NODE *node = node_hash->nd_head;
4787 VALUE hash = rb_hash_new();
4788 VALUE ary = rb_ary_new();
4789
4790 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4791 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4792 VALUE idx = rb_hash_aref(hash, key);
4793 if (!NIL_P(idx)) {
4794 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4795 (*count_ptr)--;
4796 }
4797 rb_hash_aset(hash, key, INT2FIX(i));
4798 rb_ary_store(ary, i, Qtrue);
4799 (*count_ptr)++;
4800 }
4801
4802 return ary;
4803}
4804
4805static int
4806compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4807 const NODE *const root_node,
4808 struct rb_callinfo_kwarg **const kw_arg_ptr,
4809 unsigned int *flag)
4810{
4811 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4812 RUBY_ASSERT(kw_arg_ptr != NULL);
4813 RUBY_ASSERT(flag != NULL);
4814
4815 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4816 const NODE *node = RNODE_HASH(root_node)->nd_head;
4817 int seen_nodes = 0;
4818
4819 while (node) {
4820 const NODE *key_node = RNODE_LIST(node)->nd_head;
4821 seen_nodes++;
4822
4823 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4824 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4825 /* can be keywords */
4826 }
4827 else {
4828 if (flag) {
4829 *flag |= VM_CALL_KW_SPLAT;
4830 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4831 /* A new hash will be created for the keyword arguments
4832 * in this case, so mark the method as passing mutable
4833 * keyword splat.
4834 */
4835 *flag |= VM_CALL_KW_SPLAT_MUT;
4836 }
4837 }
4838 return FALSE;
4839 }
4840 node = RNODE_LIST(node)->nd_next; /* skip value node */
4841 node = RNODE_LIST(node)->nd_next;
4842 }
4843
4844 /* may be keywords */
4845 node = RNODE_HASH(root_node)->nd_head;
4846 {
4847 int len = 0;
4848 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4849 struct rb_callinfo_kwarg *kw_arg =
4850 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4851 VALUE *keywords = kw_arg->keywords;
4852 int i = 0;
4853 int j = 0;
4854 kw_arg->references = 0;
4855 kw_arg->keyword_len = len;
4856
4857 *kw_arg_ptr = kw_arg;
4858
4859 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4860 const NODE *key_node = RNODE_LIST(node)->nd_head;
4861 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4862 int popped = TRUE;
4863 if (rb_ary_entry(key_index, i)) {
4864 keywords[j] = get_symbol_value(iseq, key_node);
4865 j++;
4866 popped = FALSE;
4867 }
4868 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4869 }
4870 RUBY_ASSERT(j == len);
4871 return TRUE;
4872 }
4873 }
4874 return FALSE;
4875}
4876
4877static int
4878compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4879{
4880 int len = 0;
4881
4882 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4883 if (CPDEBUG > 0) {
4884 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4885 }
4886
4887 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4888 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4889 }
4890 else {
4891 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4892 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4893 }
4894 }
4895
4896 return len;
4897}
4898
4899static inline bool
4900frozen_string_literal_p(const rb_iseq_t *iseq)
4901{
4902 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4903}
4904
4905static inline bool
4906static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
4907{
4908 switch (nd_type(node)) {
4909 case NODE_SYM:
4910 case NODE_REGX:
4911 case NODE_LINE:
4912 case NODE_ENCODING:
4913 case NODE_INTEGER:
4914 case NODE_FLOAT:
4915 case NODE_RATIONAL:
4916 case NODE_IMAGINARY:
4917 case NODE_NIL:
4918 case NODE_TRUE:
4919 case NODE_FALSE:
4920 return TRUE;
4921 case NODE_STR:
4922 case NODE_FILE:
4923 return hash_key || frozen_string_literal_p(iseq);
4924 default:
4925 return FALSE;
4926 }
4927}
4928
4929static inline VALUE
4930static_literal_value(const NODE *node, rb_iseq_t *iseq)
4931{
4932 switch (nd_type(node)) {
4933 case NODE_INTEGER:
4934 return rb_node_integer_literal_val(node);
4935 case NODE_FLOAT:
4936 return rb_node_float_literal_val(node);
4937 case NODE_RATIONAL:
4938 return rb_node_rational_literal_val(node);
4939 case NODE_IMAGINARY:
4940 return rb_node_imaginary_literal_val(node);
4941 case NODE_NIL:
4942 return Qnil;
4943 case NODE_TRUE:
4944 return Qtrue;
4945 case NODE_FALSE:
4946 return Qfalse;
4947 case NODE_SYM:
4948 return rb_node_sym_string_val(node);
4949 case NODE_REGX:
4950 return rb_node_regx_string_val(node);
4951 case NODE_LINE:
4952 return rb_node_line_lineno_val(node);
4953 case NODE_ENCODING:
4954 return rb_node_encoding_val(node);
4955 case NODE_FILE:
4956 case NODE_STR:
4957 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4958 VALUE lit = get_string_value(node);
4959 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
4960 }
4961 else {
4962 return get_string_value(node);
4963 }
4964 default:
4965 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
4966 }
4967}
4968
4969static int
4970compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
4971{
4972 const NODE *line_node = node;
4973
4974 if (nd_type_p(node, NODE_ZLIST)) {
4975 if (!popped) {
4976 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4977 }
4978 return 0;
4979 }
4980
4981 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4982
4983 if (popped) {
4984 for (; node; node = RNODE_LIST(node)->nd_next) {
4985 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
4986 }
4987 return 1;
4988 }
4989
4990 /* Compilation of an array literal.
4991 * The following code is essentially the same as:
4992 *
4993 * for (int count = 0; node; count++; node->nd_next) {
4994 * compile(node->nd_head);
4995 * }
4996 * ADD_INSN(newarray, count);
4997 *
4998 * However, there are three points.
4999 *
5000 * - The code above causes stack overflow for a big string literal.
5001 * The following limits the stack length up to max_stack_len.
5002 *
5003 * [x1,x2,...,x10000] =>
5004 * push x1 ; push x2 ; ...; push x256; newarray 256;
5005 * push x257; push x258; ...; push x512; pushtoarray 256;
5006 * push x513; push x514; ...; push x768; pushtoarray 256;
5007 * ...
5008 *
5009 * - Long subarray can be optimized by pre-allocating a hidden array.
5010 *
5011 * [1,2,3,...,100] =>
5012 * duparray [1,2,3,...,100]
5013 *
5014 * [x, 1,2,3,...,100, z] =>
5015 * push x; newarray 1;
5016 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5017 * push z; pushtoarray 1;
5018 *
5019 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5020 * to only push it onto the array if it is not empty
5021 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5022 *
5023 * [1,2,3,**kw] =>
5024 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5025 */
5026
5027 const int max_stack_len = 0x100;
5028 const int min_tmp_ary_len = 0x40;
5029 int stack_len = 0;
5030
5031 /* Either create a new array, or push to the existing array */
5032#define FLUSH_CHUNK \
5033 if (stack_len) { \
5034 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5035 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5036 first_chunk = FALSE; \
5037 stack_len = 0; \
5038 }
5039
5040 while (node) {
5041 int count = 1;
5042
5043 /* pre-allocation check (this branch can be omittable) */
5044 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5045 /* count the elements that are optimizable */
5046 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5047 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5048 count++;
5049
5050 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5051 /* The literal contains only optimizable elements, or the subarray is long enough */
5052 VALUE ary = rb_ary_hidden_new(count);
5053
5054 /* Create a hidden array */
5055 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5056 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5057 OBJ_FREEZE(ary);
5058
5059 /* Emit optimized code */
5060 FLUSH_CHUNK;
5061 if (first_chunk) {
5062 ADD_INSN1(ret, line_node, duparray, ary);
5063 first_chunk = FALSE;
5064 }
5065 else {
5066 ADD_INSN1(ret, line_node, putobject, ary);
5067 ADD_INSN(ret, line_node, concattoarray);
5068 }
5069 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5070 }
5071 }
5072
5073 /* Base case: Compile "count" elements */
5074 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5075 if (CPDEBUG > 0) {
5076 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5077 }
5078
5079 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5080 /* Create array or push existing non-keyword elements onto array */
5081 if (stack_len == 0 && first_chunk) {
5082 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5083 }
5084 else {
5085 FLUSH_CHUNK;
5086 }
5087 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5088 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5089 return 1;
5090 }
5091 else {
5092 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5093 stack_len++;
5094 }
5095
5096 /* If there are many pushed elements, flush them to avoid stack overflow */
5097 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5098 }
5099 }
5100
5101 FLUSH_CHUNK;
5102#undef FLUSH_CHUNK
5103 return 1;
5104}
5105
5106static inline int
5107static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5108{
5109 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);
5110}
5111
5112static int
5113compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5114{
5115 const NODE *line_node = node;
5116
5117 node = RNODE_HASH(node)->nd_head;
5118
5119 if (!node || nd_type_p(node, NODE_ZLIST)) {
5120 if (!popped) {
5121 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5122 }
5123 return 0;
5124 }
5125
5126 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5127
5128 if (popped) {
5129 for (; node; node = RNODE_LIST(node)->nd_next) {
5130 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5131 }
5132 return 1;
5133 }
5134
5135 /* Compilation of a hash literal (or keyword arguments).
5136 * This is very similar to compile_array, but there are some differences:
5137 *
5138 * - It contains key-value pairs. So we need to take every two elements.
5139 * We can assume that the length is always even.
5140 *
5141 * - Merging is done by a method call (id_core_hash_merge_ptr).
5142 * Sometimes we need to insert the receiver, so "anchor" is needed.
5143 * In addition, a method call is much slower than concatarray.
5144 * So it pays only when the subsequence is really long.
5145 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5146 *
5147 * - We need to handle keyword splat: **kw.
5148 * For **kw, the key part (node->nd_head) is NULL, and the value part
5149 * (node->nd_next->nd_head) is "kw".
5150 * The code is a bit difficult to avoid hash allocation for **{}.
5151 */
5152
5153 const int max_stack_len = 0x100;
5154 const int min_tmp_hash_len = 0x800;
5155 int stack_len = 0;
5156 int first_chunk = 1;
5157 DECL_ANCHOR(anchor);
5158 INIT_ANCHOR(anchor);
5159
5160 /* Convert pushed elements to a hash, and merge if needed */
5161#define FLUSH_CHUNK() \
5162 if (stack_len) { \
5163 if (first_chunk) { \
5164 APPEND_LIST(ret, anchor); \
5165 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5166 } \
5167 else { \
5168 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5169 ADD_INSN(ret, line_node, swap); \
5170 APPEND_LIST(ret, anchor); \
5171 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5172 } \
5173 INIT_ANCHOR(anchor); \
5174 first_chunk = stack_len = 0; \
5175 }
5176
5177 while (node) {
5178 int count = 1;
5179
5180 /* pre-allocation check (this branch can be omittable) */
5181 if (static_literal_node_pair_p(node, iseq)) {
5182 /* count the elements that are optimizable */
5183 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5184 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5185 count++;
5186
5187 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5188 /* The literal contains only optimizable elements, or the subsequence is long enough */
5189 VALUE ary = rb_ary_hidden_new(count);
5190
5191 /* Create a hidden hash */
5192 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5193 VALUE elem[2];
5194 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5195 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5196 rb_ary_cat(ary, elem, 2);
5197 }
5198 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5199 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5200 hash = rb_obj_hide(hash);
5201 OBJ_FREEZE(hash);
5202
5203 /* Emit optimized code */
5204 FLUSH_CHUNK();
5205 if (first_chunk) {
5206 ADD_INSN1(ret, line_node, duphash, hash);
5207 first_chunk = 0;
5208 }
5209 else {
5210 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5211 ADD_INSN(ret, line_node, swap);
5212
5213 ADD_INSN1(ret, line_node, putobject, hash);
5214
5215 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5216 }
5217 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5218 }
5219 }
5220
5221 /* Base case: Compile "count" elements */
5222 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5223
5224 if (CPDEBUG > 0) {
5225 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5226 }
5227
5228 if (RNODE_LIST(node)->nd_head) {
5229 /* Normal key-value pair */
5230 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5231 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5232 stack_len += 2;
5233
5234 /* If there are many pushed elements, flush them to avoid stack overflow */
5235 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5236 }
5237 else {
5238 /* kwsplat case: foo(..., **kw, ...) */
5239 FLUSH_CHUNK();
5240
5241 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5242 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5243 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5244 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5245 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5246
5247 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5248 if (empty_kw) {
5249 if (only_kw && method_call_keywords) {
5250 /* **{} appears at the only keyword argument in method call,
5251 * so it won't be modified.
5252 * kw is a special NODE_LIT that contains a special empty hash,
5253 * so this emits: putobject {}.
5254 * This is only done for method calls and not for literal hashes,
5255 * because literal hashes should always result in a new hash.
5256 */
5257 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5258 }
5259 else if (first_kw) {
5260 /* **{} appears as the first keyword argument, so it may be modified.
5261 * We need to create a fresh hash object.
5262 */
5263 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5264 }
5265 /* Any empty keyword splats that are not the first can be ignored.
5266 * since merging an empty hash into the existing hash is the same
5267 * as not merging it. */
5268 }
5269 else {
5270 if (only_kw && method_call_keywords) {
5271 /* **kw is only keyword argument in method call.
5272 * Use directly. This will be not be flagged as mutable.
5273 * This is only done for method calls and not for literal hashes,
5274 * because literal hashes should always result in a new hash.
5275 */
5276 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5277 }
5278 else {
5279 /* There is more than one keyword argument, or this is not a method
5280 * call. In that case, we need to add an empty hash (if first keyword),
5281 * or merge the hash to the accumulated hash (if not the first keyword).
5282 */
5283 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5284 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5285 else ADD_INSN(ret, line_node, swap);
5286
5287 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5288
5289 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5290 }
5291 }
5292
5293 first_chunk = 0;
5294 }
5295 }
5296 }
5297
5298 FLUSH_CHUNK();
5299#undef FLUSH_CHUNK
5300 return 1;
5301}
5302
5303 VALUE
5304rb_node_case_when_optimizable_literal(const NODE *const node)
5305{
5306 switch (nd_type(node)) {
5307 case NODE_INTEGER:
5308 return rb_node_integer_literal_val(node);
5309 case NODE_FLOAT: {
5310 VALUE v = rb_node_float_literal_val(node);
5311 double ival;
5312
5313 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5314 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5315 }
5316 return v;
5317 }
5318 case NODE_RATIONAL:
5319 case NODE_IMAGINARY:
5320 return Qundef;
5321 case NODE_NIL:
5322 return Qnil;
5323 case NODE_TRUE:
5324 return Qtrue;
5325 case NODE_FALSE:
5326 return Qfalse;
5327 case NODE_SYM:
5328 return rb_node_sym_string_val(node);
5329 case NODE_LINE:
5330 return rb_node_line_lineno_val(node);
5331 case NODE_STR:
5332 return rb_node_str_string_val(node);
5333 case NODE_FILE:
5334 return rb_node_file_path_val(node);
5335 }
5336 return Qundef;
5337}
5338
5339static int
5340when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5341 LABEL *l1, int only_special_literals, VALUE literals)
5342{
5343 while (vals) {
5344 const NODE *val = RNODE_LIST(vals)->nd_head;
5345 VALUE lit = rb_node_case_when_optimizable_literal(val);
5346
5347 if (UNDEF_P(lit)) {
5348 only_special_literals = 0;
5349 }
5350 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5351 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5352 }
5353
5354 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5355 debugp_param("nd_lit", get_string_value(val));
5356 lit = get_string_value(val);
5357 ADD_INSN1(cond_seq, val, putobject, lit);
5358 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5359 }
5360 else {
5361 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5362 }
5363
5364 // Emit pattern === target
5365 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5366 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5367 ADD_INSNL(cond_seq, val, branchif, l1);
5368 vals = RNODE_LIST(vals)->nd_next;
5369 }
5370 return only_special_literals;
5371}
5372
5373static int
5374when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5375 LABEL *l1, int only_special_literals, VALUE literals)
5376{
5377 const NODE *line_node = vals;
5378
5379 switch (nd_type(vals)) {
5380 case NODE_LIST:
5381 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5382 return COMPILE_NG;
5383 break;
5384 case NODE_SPLAT:
5385 ADD_INSN (cond_seq, line_node, dup);
5386 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5387 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5388 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5389 ADD_INSNL(cond_seq, line_node, branchif, l1);
5390 break;
5391 case NODE_ARGSCAT:
5392 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5393 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5394 break;
5395 case NODE_ARGSPUSH:
5396 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5397 ADD_INSN (cond_seq, line_node, dup);
5398 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5399 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5400 ADD_INSNL(cond_seq, line_node, branchif, l1);
5401 break;
5402 default:
5403 ADD_INSN (cond_seq, line_node, dup);
5404 CHECK(COMPILE(cond_seq, "when val", vals));
5405 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5406 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5407 ADD_INSNL(cond_seq, line_node, branchif, l1);
5408 break;
5409 }
5410 return COMPILE_OK;
5411}
5412
5413/* Multiple Assignment Handling
5414 *
5415 * In order to handle evaluation of multiple assignment such that the left hand side
5416 * is evaluated before the right hand side, we need to process the left hand side
5417 * and see if there are any attributes that need to be assigned, or constants set
5418 * on explicit objects. If so, we add instructions to evaluate the receiver of
5419 * any assigned attributes or constants before we process the right hand side.
5420 *
5421 * For a multiple assignment such as:
5422 *
5423 * l1.m1, l2[0] = r3, r4
5424 *
5425 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5426 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5427 * On the VM stack, this looks like:
5428 *
5429 * self # putself
5430 * l1 # send
5431 * l1, self # putself
5432 * l1, l2 # send
5433 * l1, l2, 0 # putobject 0
5434 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5435 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5436 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5437 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5438 * l1, l2, 0, [r3, r4], r4, m1= # send
5439 * l1, l2, 0, [r3, r4], r4 # pop
5440 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5441 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5442 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5443 * l1, l2, 0, [r3, r4], r4, []= # send
5444 * l1, l2, 0, [r3, r4], r4 # pop
5445 * l1, l2, 0, [r3, r4] # pop
5446 * [r3, r4], l2, 0, [r3, r4] # setn 3
5447 * [r3, r4], l2, 0 # pop
5448 * [r3, r4], l2 # pop
5449 * [r3, r4] # pop
5450 *
5451 * This is made more complex when you have to handle splats, post args,
5452 * and arbitrary levels of nesting. You need to keep track of the total
5453 * number of attributes to set, and for each attribute, how many entries
5454 * are on the stack before the final attribute, in order to correctly
5455 * calculate the topn value to use to get the receiver of the attribute
5456 * setter method.
5457 *
5458 * A brief description of the VM stack for simple multiple assignment
5459 * with no splat (rhs_array will not be present if the return value of
5460 * the multiple assignment is not needed):
5461 *
5462 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5463 *
5464 * For multiple assignment with splats, while processing the part before
5465 * the splat (splat+post here is an array of the splat and the post arguments):
5466 *
5467 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5468 *
5469 * When processing the splat and post arguments:
5470 *
5471 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5472 *
5473 * When processing nested multiple assignment, existing values on the stack
5474 * are kept. So for:
5475 *
5476 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5477 *
5478 * The stack layout would be the following before processing the nested
5479 * multiple assignment:
5480 *
5481 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5482 *
5483 * In order to handle this correctly, we need to keep track of the nesting
5484 * level for each attribute assignment, as well as the attribute number
5485 * (left hand side attributes are processed left to right) and number of
5486 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5487 * this information.
5488 *
5489 * We also need to track information for the entire multiple assignment, such
5490 * as the total number of arguments, and the current nesting level, to
5491 * handle both nested multiple assignment as well as cases where the
5492 * rhs is not needed. We also need to keep track of all attribute
5493 * assignments in this, which we do using a linked listed. struct masgn_state
5494 * tracks this information.
5495 */
5496
5497 struct masgn_lhs_node {
5498 INSN *before_insn;
5499 struct masgn_lhs_node *next;
5500 const NODE *line_node;
5501 int argn;
5502 int num_args;
5503 int lhs_pos;
5504};
5505
5506 struct masgn_state {
5507 struct masgn_lhs_node *first_memo;
5508 struct masgn_lhs_node *last_memo;
5509 int lhs_level;
5510 int num_args;
5511 bool nested;
5512};
5513
5514static int
5515add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5516{
5517 if (!state) {
5518 rb_bug("no masgn_state");
5519 }
5520
5521 struct masgn_lhs_node *memo;
5522 memo = malloc(sizeof(struct masgn_lhs_node));
5523 if (!memo) {
5524 return COMPILE_NG;
5525 }
5526
5527 memo->before_insn = before_insn;
5528 memo->line_node = line_node;
5529 memo->argn = state->num_args + 1;
5530 memo->num_args = argc;
5531 state->num_args += argc;
5532 memo->lhs_pos = lhs_pos;
5533 memo->next = NULL;
5534 if (!state->first_memo) {
5535 state->first_memo = memo;
5536 }
5537 else {
5538 state->last_memo->next = memo;
5539 }
5540 state->last_memo = memo;
5541
5542 return COMPILE_OK;
5543}
5544
5545static 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);
5546
5547static int
5548compile_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)
5549{
5550 switch (nd_type(node)) {
5551 case NODE_ATTRASGN: {
5552 INSN *iobj;
5553 const NODE *line_node = node;
5554
5555 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5556
5557 bool safenav_call = false;
5558 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5559 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5560 ASSUME(iobj);
5561 ELEM_REMOVE(insn_element);
5562 if (!IS_INSN_ID(iobj, send)) {
5563 safenav_call = true;
5564 iobj = (INSN *)get_prev_insn(iobj);
5565 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5566 }
5567 (pre->last = iobj->link.prev)->next = 0;
5568
5569 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5570 int argc = vm_ci_argc(ci) + 1;
5571 ci = ci_argc_set(iseq, ci, argc);
5572 OPERAND_AT(iobj, 0) = (VALUE)ci;
5573 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5574
5575 if (argc == 1) {
5576 ADD_INSN(lhs, line_node, swap);
5577 }
5578 else {
5579 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5580 }
5581
5582 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5583 return COMPILE_NG;
5584 }
5585
5586 iobj->link.prev = lhs->last;
5587 lhs->last->next = &iobj->link;
5588 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5589 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5590 int argc = vm_ci_argc(ci);
5591 bool dupsplat = false;
5592 ci = ci_argc_set(iseq, ci, argc - 1);
5593 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5594 /* Given h[*a], _ = ary
5595 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5596 * `a` must be dupped, because it will be appended with ary[0]
5597 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5598 */
5599 dupsplat = true;
5600 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5601 }
5602 OPERAND_AT(iobj, 0) = (VALUE)ci;
5603 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5604
5605 /* Given: h[*a], h[*b, 1] = ary
5606 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5607 * so this uses splatarray true on a to dup it before using pushtoarray
5608 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5609 * so you can use pushtoarray directly
5610 */
5611 int line_no = nd_line(line_node);
5612 int node_id = nd_node_id(line_node);
5613
5614 if (dupsplat) {
5615 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5616 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5617 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5618 }
5619 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5620 }
5621 if (!safenav_call) {
5622 ADD_INSN(lhs, line_node, pop);
5623 if (argc != 1) {
5624 ADD_INSN(lhs, line_node, pop);
5625 }
5626 }
5627 for (int i=0; i < argc; i++) {
5628 ADD_INSN(post, line_node, pop);
5629 }
5630 break;
5631 }
5632 case NODE_MASGN: {
5633 DECL_ANCHOR(nest_rhs);
5634 INIT_ANCHOR(nest_rhs);
5635 DECL_ANCHOR(nest_lhs);
5636 INIT_ANCHOR(nest_lhs);
5637
5638 int prev_level = state->lhs_level;
5639 bool prev_nested = state->nested;
5640 state->nested = 1;
5641 state->lhs_level = lhs_pos - 1;
5642 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5643 state->lhs_level = prev_level;
5644 state->nested = prev_nested;
5645
5646 ADD_SEQ(lhs, nest_rhs);
5647 ADD_SEQ(lhs, nest_lhs);
5648 break;
5649 }
5650 case NODE_CDECL:
5651 if (!RNODE_CDECL(node)->nd_vid) {
5652 /* Special handling only needed for expr::C, not for C */
5653 INSN *iobj;
5654
5655 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5656
5657 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5658 iobj = (INSN *)insn_element; /* setconstant insn */
5659 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5660 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5661 ELEM_REMOVE(insn_element);
5662 pre->last = iobj->link.prev;
5663 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5664
5665 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5666 return COMPILE_NG;
5667 }
5668
5669 ADD_INSN(post, node, pop);
5670 break;
5671 }
5672 /* Fallthrough */
5673 default: {
5674 DECL_ANCHOR(anchor);
5675 INIT_ANCHOR(anchor);
5676 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5677 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5678 ADD_SEQ(lhs, anchor);
5679 }
5680 }
5681
5682 return COMPILE_OK;
5683}
5684
5685static int
5686compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5687{
5688 if (lhsn) {
5689 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5690 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5691 }
5692 return COMPILE_OK;
5693}
5694
5695static int
5696compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5697 const NODE *rhsn, const NODE *orig_lhsn)
5698{
5699 VALUE mem[64];
5700 const int memsize = numberof(mem);
5701 int memindex = 0;
5702 int llen = 0, rlen = 0;
5703 int i;
5704 const NODE *lhsn = orig_lhsn;
5705
5706#define MEMORY(v) { \
5707 int i; \
5708 if (memindex == memsize) return 0; \
5709 for (i=0; i<memindex; i++) { \
5710 if (mem[i] == (v)) return 0; \
5711 } \
5712 mem[memindex++] = (v); \
5713}
5714
5715 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5716 return 0;
5717 }
5718
5719 while (lhsn) {
5720 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5721 switch (nd_type(ln)) {
5722 case NODE_LASGN:
5723 case NODE_DASGN:
5724 case NODE_IASGN:
5725 case NODE_CVASGN:
5726 MEMORY(get_nd_vid(ln));
5727 break;
5728 default:
5729 return 0;
5730 }
5731 lhsn = RNODE_LIST(lhsn)->nd_next;
5732 llen++;
5733 }
5734
5735 while (rhsn) {
5736 if (llen <= rlen) {
5737 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5738 }
5739 else {
5740 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5741 }
5742 rhsn = RNODE_LIST(rhsn)->nd_next;
5743 rlen++;
5744 }
5745
5746 if (llen > rlen) {
5747 for (i=0; i<llen-rlen; i++) {
5748 ADD_INSN(ret, orig_lhsn, putnil);
5749 }
5750 }
5751
5752 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5753 return 1;
5754}
5755
5756static int
5757compile_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)
5758{
5759 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5760 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5761 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5762 const NODE *lhsn_count = lhsn;
5763 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5764
5765 int llen = 0;
5766 int lpos = 0;
5767
5768 while (lhsn_count) {
5769 llen++;
5770 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5771 }
5772 while (lhsn) {
5773 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5774 lpos++;
5775 lhsn = RNODE_LIST(lhsn)->nd_next;
5776 }
5777
5778 if (lhs_splat) {
5779 if (nd_type_p(splatn, NODE_POSTARG)) {
5780 /*a, b, *r, p1, p2 */
5781 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5782 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5783 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5784 int ppos = 0;
5785 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5786
5787 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5788
5789 if (NODE_NAMED_REST_P(restn)) {
5790 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5791 }
5792 while (postn) {
5793 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5794 ppos++;
5795 postn = RNODE_LIST(postn)->nd_next;
5796 }
5797 }
5798 else {
5799 /* a, b, *r */
5800 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5801 }
5802 }
5803
5804 if (!state->nested) {
5805 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5806 }
5807
5808 if (!popped) {
5809 ADD_INSN(rhs, node, dup);
5810 }
5811 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5812 return COMPILE_OK;
5813}
5814
5815static int
5816compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5817{
5818 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5819 struct masgn_state state;
5820 state.lhs_level = popped ? 0 : 1;
5821 state.nested = 0;
5822 state.num_args = 0;
5823 state.first_memo = NULL;
5824 state.last_memo = NULL;
5825
5826 DECL_ANCHOR(pre);
5827 INIT_ANCHOR(pre);
5828 DECL_ANCHOR(rhs);
5829 INIT_ANCHOR(rhs);
5830 DECL_ANCHOR(lhs);
5831 INIT_ANCHOR(lhs);
5832 DECL_ANCHOR(post);
5833 INIT_ANCHOR(post);
5834 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5835
5836 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5837 while (memo) {
5838 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5839 for (int i = 0; i < memo->num_args; i++) {
5840 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5841 }
5842 tmp_memo = memo->next;
5843 free(memo);
5844 memo = tmp_memo;
5845 }
5846 CHECK(ok);
5847
5848 ADD_SEQ(ret, pre);
5849 ADD_SEQ(ret, rhs);
5850 ADD_SEQ(ret, lhs);
5851 if (!popped && state.num_args >= 1) {
5852 /* make sure rhs array is returned before popping */
5853 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5854 }
5855 ADD_SEQ(ret, post);
5856 }
5857 return COMPILE_OK;
5858}
5859
5860static VALUE
5861collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5862{
5863 VALUE arr = rb_ary_new();
5864 for (;;) {
5865 switch (nd_type(node)) {
5866 case NODE_CONST:
5867 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5868 return arr;
5869 case NODE_COLON3:
5870 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5871 rb_ary_unshift(arr, ID2SYM(idNULL));
5872 return arr;
5873 case NODE_COLON2:
5874 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5875 node = RNODE_COLON2(node)->nd_head;
5876 break;
5877 default:
5878 return Qfalse;
5879 }
5880 }
5881}
5882
5883static int
5884compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5885 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5886{
5887 switch (nd_type(node)) {
5888 case NODE_CONST:
5889 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5890 ADD_INSN1(body, node, putobject, Qtrue);
5891 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5892 break;
5893 case NODE_COLON3:
5894 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5895 ADD_INSN(body, node, pop);
5896 ADD_INSN1(body, node, putobject, rb_cObject);
5897 ADD_INSN1(body, node, putobject, Qtrue);
5898 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5899 break;
5900 case NODE_COLON2:
5901 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5902 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5903 ADD_INSN1(body, node, putobject, Qfalse);
5904 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5905 break;
5906 default:
5907 CHECK(COMPILE(pref, "const colon2 prefix", node));
5908 break;
5909 }
5910 return COMPILE_OK;
5911}
5912
5913static int
5914compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5915{
5916 if (nd_type_p(cpath, NODE_COLON3)) {
5917 /* toplevel class ::Foo */
5918 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5919 return VM_DEFINECLASS_FLAG_SCOPED;
5920 }
5921 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5922 /* Bar::Foo */
5923 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5924 return VM_DEFINECLASS_FLAG_SCOPED;
5925 }
5926 else {
5927 /* class at cbase Foo */
5928 ADD_INSN1(ret, cpath, putspecialobject,
5929 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5930 return 0;
5931 }
5932}
5933
5934static inline int
5935private_recv_p(const NODE *node)
5936{
5937 NODE *recv = get_nd_recv(node);
5938 if (recv && nd_type_p(recv, NODE_SELF)) {
5939 return RNODE_SELF(recv)->nd_state != 0;
5940 }
5941 return 0;
5942}
5943
5944static void
5945defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5946 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
5947
5948static int
5949compile_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);
5950
5951static void
5952defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5953 const NODE *const node, LABEL **lfinish, VALUE needstr,
5954 bool keep_result)
5955{
5956 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5957 enum node_type type;
5958 const int line = nd_line(node);
5959 const NODE *line_node = node;
5960
5961 switch (type = nd_type(node)) {
5962
5963 /* easy literals */
5964 case NODE_NIL:
5965 expr_type = DEFINED_NIL;
5966 break;
5967 case NODE_SELF:
5968 expr_type = DEFINED_SELF;
5969 break;
5970 case NODE_TRUE:
5971 expr_type = DEFINED_TRUE;
5972 break;
5973 case NODE_FALSE:
5974 expr_type = DEFINED_FALSE;
5975 break;
5976
5977 case NODE_HASH:
5978 case NODE_LIST:{
5979 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
5980
5981 if (vals) {
5982 do {
5983 if (RNODE_LIST(vals)->nd_head) {
5984 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
5985
5986 if (!lfinish[1]) {
5987 lfinish[1] = NEW_LABEL(line);
5988 }
5989 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5990 }
5991 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
5992 }
5993 }
5994 /* fall through */
5995 case NODE_STR:
5996 case NODE_SYM:
5997 case NODE_REGX:
5998 case NODE_LINE:
5999 case NODE_FILE:
6000 case NODE_ENCODING:
6001 case NODE_INTEGER:
6002 case NODE_FLOAT:
6003 case NODE_RATIONAL:
6004 case NODE_IMAGINARY:
6005 case NODE_ZLIST:
6006 case NODE_AND:
6007 case NODE_OR:
6008 default:
6009 expr_type = DEFINED_EXPR;
6010 break;
6011
6012 case NODE_SPLAT:
6013 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6014 if (!lfinish[1]) {
6015 lfinish[1] = NEW_LABEL(line);
6016 }
6017 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6018 expr_type = DEFINED_EXPR;
6019 break;
6020
6021 /* variables */
6022 case NODE_LVAR:
6023 case NODE_DVAR:
6024 expr_type = DEFINED_LVAR;
6025 break;
6026
6027#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6028 case NODE_IVAR:
6029 ADD_INSN3(ret, line_node, definedivar,
6030 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6031 return;
6032
6033 case NODE_GVAR:
6034 ADD_INSN(ret, line_node, putnil);
6035 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6036 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6037 return;
6038
6039 case NODE_CVAR:
6040 ADD_INSN(ret, line_node, putnil);
6041 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6042 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6043 return;
6044
6045 case NODE_CONST:
6046 ADD_INSN(ret, line_node, putnil);
6047 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6048 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6049 return;
6050 case NODE_COLON2:
6051 if (!lfinish[1]) {
6052 lfinish[1] = NEW_LABEL(line);
6053 }
6054 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6055 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6056 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6057
6058 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6059 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6060 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6061 }
6062 else {
6063 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6064 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6065 }
6066 return;
6067 case NODE_COLON3:
6068 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6069 ADD_INSN3(ret, line_node, defined,
6070 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6071 return;
6072
6073 /* method dispatch */
6074 case NODE_CALL:
6075 case NODE_OPCALL:
6076 case NODE_VCALL:
6077 case NODE_FCALL:
6078 case NODE_ATTRASGN:{
6079 const int explicit_receiver =
6080 (type == NODE_CALL || type == NODE_OPCALL ||
6081 (type == NODE_ATTRASGN && !private_recv_p(node)));
6082
6083 if (get_nd_args(node) || explicit_receiver) {
6084 if (!lfinish[1]) {
6085 lfinish[1] = NEW_LABEL(line);
6086 }
6087 if (!lfinish[2]) {
6088 lfinish[2] = NEW_LABEL(line);
6089 }
6090 }
6091 if (get_nd_args(node)) {
6092 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6093 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6094 }
6095 if (explicit_receiver) {
6096 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6097 switch (nd_type(get_nd_recv(node))) {
6098 case NODE_CALL:
6099 case NODE_OPCALL:
6100 case NODE_VCALL:
6101 case NODE_FCALL:
6102 case NODE_ATTRASGN:
6103 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6104 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6105 break;
6106 default:
6107 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6108 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6109 break;
6110 }
6111 if (keep_result) {
6112 ADD_INSN(ret, line_node, dup);
6113 }
6114 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6115 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6116 }
6117 else {
6118 ADD_INSN(ret, line_node, putself);
6119 if (keep_result) {
6120 ADD_INSN(ret, line_node, dup);
6121 }
6122 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6123 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6124 }
6125 return;
6126 }
6127
6128 case NODE_YIELD:
6129 ADD_INSN(ret, line_node, putnil);
6130 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6131 PUSH_VAL(DEFINED_YIELD));
6132 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6133 return;
6134
6135 case NODE_BACK_REF:
6136 case NODE_NTH_REF:
6137 ADD_INSN(ret, line_node, putnil);
6138 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6139 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6140 PUSH_VAL(DEFINED_GVAR));
6141 return;
6142
6143 case NODE_SUPER:
6144 case NODE_ZSUPER:
6145 ADD_INSN(ret, line_node, putnil);
6146 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6147 PUSH_VAL(DEFINED_ZSUPER));
6148 return;
6149
6150#undef PUSH_VAL
6151 case NODE_OP_ASGN1:
6152 case NODE_OP_ASGN2:
6153 case NODE_OP_ASGN_OR:
6154 case NODE_OP_ASGN_AND:
6155 case NODE_MASGN:
6156 case NODE_LASGN:
6157 case NODE_DASGN:
6158 case NODE_GASGN:
6159 case NODE_IASGN:
6160 case NODE_CDECL:
6161 case NODE_CVASGN:
6162 case NODE_OP_CDECL:
6163 expr_type = DEFINED_ASGN;
6164 break;
6165 }
6166
6167 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6168
6169 if (needstr != Qfalse) {
6170 VALUE str = rb_iseq_defined_string(expr_type);
6171 ADD_INSN1(ret, line_node, putobject, str);
6172 }
6173 else {
6174 ADD_INSN1(ret, line_node, putobject, Qtrue);
6175 }
6176}
6177
6178static void
6179build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6180{
6181 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6182 iseq_set_exception_local_table(iseq);
6183}
6184
6185static void
6186defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6187 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6188{
6189 LINK_ELEMENT *lcur = ret->last;
6190 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6191 if (lfinish[1]) {
6192 int line = nd_line(node);
6193 LABEL *lstart = NEW_LABEL(line);
6194 LABEL *lend = NEW_LABEL(line);
6195 const rb_iseq_t *rescue;
6196 struct rb_iseq_new_with_callback_callback_func *ifunc =
6197 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6198 rescue = new_child_iseq_with_callback(iseq, ifunc,
6199 rb_str_concat(rb_str_new2("defined guard in "),
6200 ISEQ_BODY(iseq)->location.label),
6201 iseq, ISEQ_TYPE_RESCUE, 0);
6202 lstart->rescued = LABEL_RESCUE_BEG;
6203 lend->rescued = LABEL_RESCUE_END;
6204 APPEND_LABEL(ret, lcur, lstart);
6205 ADD_LABEL(ret, lend);
6206 if (!ignore) {
6207 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6208 }
6209 }
6210}
6211
6212static int
6213compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6214{
6215 const int line = nd_line(node);
6216 const NODE *line_node = node;
6217 if (!RNODE_DEFINED(node)->nd_head) {
6218 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6219 ADD_INSN1(ret, line_node, putobject, str);
6220 }
6221 else {
6222 LABEL *lfinish[3];
6223 LINK_ELEMENT *last = ret->last;
6224 lfinish[0] = NEW_LABEL(line);
6225 lfinish[1] = 0;
6226 lfinish[2] = 0;
6227 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6228 if (lfinish[1]) {
6229 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6230 ADD_INSN(ret, line_node, swap);
6231 if (lfinish[2]) {
6232 ADD_LABEL(ret, lfinish[2]);
6233 }
6234 ADD_INSN(ret, line_node, pop);
6235 ADD_LABEL(ret, lfinish[1]);
6236 }
6237 ADD_LABEL(ret, lfinish[0]);
6238 }
6239 return COMPILE_OK;
6240}
6241
6242static VALUE
6243make_name_for_block(const rb_iseq_t *orig_iseq)
6244{
6245 int level = 1;
6246 const rb_iseq_t *iseq = orig_iseq;
6247
6248 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6249 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6250 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6251 level++;
6252 }
6253 iseq = ISEQ_BODY(iseq)->parent_iseq;
6254 }
6255 }
6256
6257 if (level == 1) {
6258 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6259 }
6260 else {
6261 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6262 }
6263}
6264
6265static void
6266push_ensure_entry(rb_iseq_t *iseq,
6267 struct iseq_compile_data_ensure_node_stack *enl,
6268 struct ensure_range *er, const void *const node)
6269{
6270 enl->ensure_node = node;
6271 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6272 enl->erange = er;
6273 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6274}
6275
6276static void
6277add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6278 LABEL *lstart, LABEL *lend)
6279{
6280 struct ensure_range *ne =
6281 compile_data_alloc(iseq, sizeof(struct ensure_range));
6282
6283 while (erange->next != 0) {
6284 erange = erange->next;
6285 }
6286 ne->next = 0;
6287 ne->begin = lend;
6288 ne->end = erange->end;
6289 erange->end = lstart;
6290
6291 erange->next = ne;
6292}
6293
6294static bool
6295can_add_ensure_iseq(const rb_iseq_t *iseq)
6296{
6297 struct iseq_compile_data_ensure_node_stack *e;
6298 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6299 while (e) {
6300 if (e->ensure_node) return false;
6301 e = e->prev;
6302 }
6303 }
6304 return true;
6305}
6306
6307static void
6308add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6309{
6310 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6311
6312 struct iseq_compile_data_ensure_node_stack *enlp =
6313 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6314 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6315 DECL_ANCHOR(ensure);
6316
6317 INIT_ANCHOR(ensure);
6318 while (enlp) {
6319 if (enlp->erange != NULL) {
6320 DECL_ANCHOR(ensure_part);
6321 LABEL *lstart = NEW_LABEL(0);
6322 LABEL *lend = NEW_LABEL(0);
6323 INIT_ANCHOR(ensure_part);
6324
6325 add_ensure_range(iseq, enlp->erange, lstart, lend);
6326
6327 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6328 ADD_LABEL(ensure_part, lstart);
6329 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6330 ADD_LABEL(ensure_part, lend);
6331 ADD_SEQ(ensure, ensure_part);
6332 }
6333 else {
6334 if (!is_return) {
6335 break;
6336 }
6337 }
6338 enlp = enlp->prev;
6339 }
6340 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6341 ADD_SEQ(ret, ensure);
6342}
6343
6344#if RUBY_DEBUG
6345static int
6346check_keyword(const NODE *node)
6347{
6348 /* This check is essentially a code clone of compile_keyword_arg. */
6349
6350 if (nd_type_p(node, NODE_LIST)) {
6351 while (RNODE_LIST(node)->nd_next) {
6352 node = RNODE_LIST(node)->nd_next;
6353 }
6354 node = RNODE_LIST(node)->nd_head;
6355 }
6356
6357 return keyword_node_p(node);
6358}
6359#endif
6360
6361static bool
6362keyword_node_single_splat_p(NODE *kwnode)
6363{
6364 RUBY_ASSERT(keyword_node_p(kwnode));
6365
6366 NODE *node = RNODE_HASH(kwnode)->nd_head;
6367 return RNODE_LIST(node)->nd_head == NULL &&
6368 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6369}
6370
6371static void
6372compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6373 NODE *kwnode, unsigned int *flag_ptr)
6374{
6375 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6376 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6377 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6378 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6379 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6380}
6381
6382#define SPLATARRAY_FALSE 0
6383#define SPLATARRAY_TRUE 1
6384#define DUP_SINGLE_KW_SPLAT 2
6385
6386static int
6387setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6388 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6389{
6390 if (!argn) return 0;
6391
6392 NODE *kwnode = NULL;
6393
6394 switch (nd_type(argn)) {
6395 case NODE_LIST: {
6396 // f(x, y, z)
6397 int len = compile_args(iseq, args, argn, &kwnode);
6398 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6399
6400 if (kwnode) {
6401 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6402 len -= 1;
6403 }
6404 else {
6405 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6406 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6407 }
6408 else {
6409 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6410 }
6411 }
6412 }
6413
6414 return len;
6415 }
6416 case NODE_SPLAT: {
6417 // f(*a)
6418 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6419 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6420 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6421 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6422 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6423 return 1;
6424 }
6425 case NODE_ARGSCAT: {
6426 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6427 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6428 bool args_pushed = false;
6429
6430 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6431 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6432 if (kwnode) rest_len--;
6433 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6434 args_pushed = true;
6435 }
6436 else {
6437 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6438 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6439 }
6440
6441 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6442 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6443 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6444 argc += 1;
6445 }
6446 else if (!args_pushed) {
6447 ADD_INSN(args, argn, concattoarray);
6448 }
6449
6450 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6451 if (kwnode) {
6452 // kwsplat
6453 *flag_ptr |= VM_CALL_KW_SPLAT;
6454 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6455 argc += 1;
6456 }
6457
6458 return argc;
6459 }
6460 case NODE_ARGSPUSH: {
6461 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6462 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6463
6464 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6465 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6466 if (kwnode) rest_len--;
6467 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6468 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6469 }
6470 else {
6471 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6472 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6473 }
6474 else {
6475 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6476 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6477 }
6478 }
6479
6480 if (kwnode) {
6481 // f(*a, k:1)
6482 *flag_ptr |= VM_CALL_KW_SPLAT;
6483 if (!keyword_node_single_splat_p(kwnode)) {
6484 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6485 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6486 }
6487 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6488 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6489 }
6490 else {
6491 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6492 }
6493 argc += 1;
6494 }
6495
6496 return argc;
6497 }
6498 default: {
6499 UNKNOWN_NODE("setup_arg", argn, Qnil);
6500 }
6501 }
6502}
6503
6504static void
6505setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6506{
6507 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6508 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6509 }
6510}
6511
6512static bool
6513setup_args_dup_rest_p(const NODE *argn)
6514{
6515 switch(nd_type(argn)) {
6516 case NODE_LVAR:
6517 case NODE_DVAR:
6518 case NODE_GVAR:
6519 case NODE_IVAR:
6520 case NODE_CVAR:
6521 case NODE_CONST:
6522 case NODE_COLON3:
6523 case NODE_INTEGER:
6524 case NODE_FLOAT:
6525 case NODE_RATIONAL:
6526 case NODE_IMAGINARY:
6527 case NODE_STR:
6528 case NODE_SYM:
6529 case NODE_REGX:
6530 case NODE_SELF:
6531 case NODE_NIL:
6532 case NODE_TRUE:
6533 case NODE_FALSE:
6534 case NODE_LAMBDA:
6535 case NODE_NTH_REF:
6536 case NODE_BACK_REF:
6537 return false;
6538 case NODE_COLON2:
6539 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6540 default:
6541 return true;
6542 }
6543}
6544
6545static VALUE
6546setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6547 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6548{
6549 VALUE ret;
6550 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6551
6552 if (argn) {
6553 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6554 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6555
6556 if (check_arg) {
6557 switch(nd_type(check_arg)) {
6558 case(NODE_SPLAT):
6559 // avoid caller side array allocation for f(*arg)
6560 dup_rest = SPLATARRAY_FALSE;
6561 break;
6562 case(NODE_ARGSCAT):
6563 // avoid caller side array allocation for f(1, *arg)
6564 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6565 break;
6566 case(NODE_ARGSPUSH):
6567 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6568 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6569 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6570 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6571 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6572 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6573
6574 if (dup_rest == SPLATARRAY_FALSE) {
6575 // require allocation for keyword key/value/splat that may modify splatted argument
6576 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6577 while (node) {
6578 NODE *key_node = RNODE_LIST(node)->nd_head;
6579 if (key_node && setup_args_dup_rest_p(key_node)) {
6580 dup_rest = SPLATARRAY_TRUE;
6581 break;
6582 }
6583
6584 node = RNODE_LIST(node)->nd_next;
6585 NODE *value_node = RNODE_LIST(node)->nd_head;
6586 if (setup_args_dup_rest_p(value_node)) {
6587 dup_rest = SPLATARRAY_TRUE;
6588 break;
6589 }
6590
6591 node = RNODE_LIST(node)->nd_next;
6592 }
6593 }
6594 break;
6595 default:
6596 break;
6597 }
6598 }
6599
6600 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6601 // for block pass that may modify splatted argument, dup rest and kwrest if given
6602 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6603 }
6604 }
6605 initial_dup_rest = dup_rest;
6606
6607 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6608 DECL_ANCHOR(arg_block);
6609 INIT_ANCHOR(arg_block);
6610
6611 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6612 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6613
6614 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6615 const NODE * arg_node =
6616 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6617
6618 int argc = 0;
6619
6620 // Only compile leading args:
6621 // foo(x, y, ...)
6622 // ^^^^
6623 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6624 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6625 }
6626
6627 *flag |= VM_CALL_FORWARDING;
6628
6629 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6630 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6631 return INT2FIX(argc);
6632 }
6633 else {
6634 *flag |= VM_CALL_ARGS_BLOCKARG;
6635
6636 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6637 }
6638
6639 if (LIST_INSN_SIZE_ONE(arg_block)) {
6640 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6641 if (IS_INSN(elem)) {
6642 INSN *iobj = (INSN *)elem;
6643 if (iobj->insn_id == BIN(getblockparam)) {
6644 iobj->insn_id = BIN(getblockparamproxy);
6645 }
6646 }
6647 }
6648 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6649 ADD_SEQ(args, arg_block);
6650 }
6651 else {
6652 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6653 }
6654 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6655 return ret;
6656}
6657
6658static void
6659build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6660{
6661 const NODE *body = ptr;
6662 int line = nd_line(body);
6663 VALUE argc = INT2FIX(0);
6664 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6665
6666 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6667 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6668 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6669 iseq_set_local_table(iseq, 0, 0);
6670}
6671
6672static void
6673compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6674{
6675 const NODE *vars;
6676 LINK_ELEMENT *last;
6677 int line = nd_line(node);
6678 const NODE *line_node = node;
6679 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6680
6681#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6682 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6683#else
6684 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6685#endif
6686 ADD_INSN(ret, line_node, dup);
6687 ADD_INSNL(ret, line_node, branchunless, fail_label);
6688
6689 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6690 INSN *cap;
6691 if (RNODE_BLOCK(vars)->nd_next) {
6692 ADD_INSN(ret, line_node, dup);
6693 }
6694 last = ret->last;
6695 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6696 last = last->next; /* putobject :var */
6697 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6698 NULL, INT2FIX(0), NULL);
6699 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6700#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6701 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6702 /* only one name */
6703 DECL_ANCHOR(nom);
6704
6705 INIT_ANCHOR(nom);
6706 ADD_INSNL(nom, line_node, jump, end_label);
6707 ADD_LABEL(nom, fail_label);
6708# if 0 /* $~ must be MatchData or nil */
6709 ADD_INSN(nom, line_node, pop);
6710 ADD_INSN(nom, line_node, putnil);
6711# endif
6712 ADD_LABEL(nom, end_label);
6713 (nom->last->next = cap->link.next)->prev = nom->last;
6714 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6715 return;
6716 }
6717#endif
6718 }
6719 ADD_INSNL(ret, line_node, jump, end_label);
6720 ADD_LABEL(ret, fail_label);
6721 ADD_INSN(ret, line_node, pop);
6722 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6723 last = ret->last;
6724 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6725 last = last->next; /* putobject :var */
6726 ((INSN*)last)->insn_id = BIN(putnil);
6727 ((INSN*)last)->operand_size = 0;
6728 }
6729 ADD_LABEL(ret, end_label);
6730}
6731
6732static int
6733optimizable_range_item_p(const NODE *n)
6734{
6735 if (!n) return FALSE;
6736 switch (nd_type(n)) {
6737 case NODE_LINE:
6738 return TRUE;
6739 case NODE_INTEGER:
6740 return TRUE;
6741 case NODE_NIL:
6742 return TRUE;
6743 default:
6744 return FALSE;
6745 }
6746}
6747
6748static VALUE
6749optimized_range_item(const NODE *n)
6750{
6751 switch (nd_type(n)) {
6752 case NODE_LINE:
6753 return rb_node_line_lineno_val(n);
6754 case NODE_INTEGER:
6755 return rb_node_integer_literal_val(n);
6756 case NODE_FLOAT:
6757 return rb_node_float_literal_val(n);
6758 case NODE_RATIONAL:
6759 return rb_node_rational_literal_val(n);
6760 case NODE_IMAGINARY:
6761 return rb_node_imaginary_literal_val(n);
6762 case NODE_NIL:
6763 return Qnil;
6764 default:
6765 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6766 }
6767}
6768
6769static int
6770compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6771{
6772 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6773 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6774
6775 const int line = nd_line(node);
6776 const NODE *line_node = node;
6777 DECL_ANCHOR(cond_seq);
6778 LABEL *then_label, *else_label, *end_label;
6779 VALUE branches = Qfalse;
6780
6781 INIT_ANCHOR(cond_seq);
6782 then_label = NEW_LABEL(line);
6783 else_label = NEW_LABEL(line);
6784 end_label = 0;
6785
6786 NODE *cond = RNODE_IF(node)->nd_cond;
6787 if (nd_type(cond) == NODE_BLOCK) {
6788 cond = RNODE_BLOCK(cond)->nd_head;
6789 }
6790
6791 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6792 ADD_SEQ(ret, cond_seq);
6793
6794 if (then_label->refcnt && else_label->refcnt) {
6795 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6796 }
6797
6798 if (then_label->refcnt) {
6799 ADD_LABEL(ret, then_label);
6800
6801 DECL_ANCHOR(then_seq);
6802 INIT_ANCHOR(then_seq);
6803 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6804
6805 if (else_label->refcnt) {
6806 const NODE *const coverage_node = node_body ? node_body : node;
6807 add_trace_branch_coverage(
6808 iseq,
6809 ret,
6810 nd_code_loc(coverage_node),
6811 nd_node_id(coverage_node),
6812 0,
6813 type == NODE_IF ? "then" : "else",
6814 branches);
6815 end_label = NEW_LABEL(line);
6816 ADD_INSNL(then_seq, line_node, jump, end_label);
6817 if (!popped) {
6818 ADD_INSN(then_seq, line_node, pop);
6819 }
6820 }
6821 ADD_SEQ(ret, then_seq);
6822 }
6823
6824 if (else_label->refcnt) {
6825 ADD_LABEL(ret, else_label);
6826
6827 DECL_ANCHOR(else_seq);
6828 INIT_ANCHOR(else_seq);
6829 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6830
6831 if (then_label->refcnt) {
6832 const NODE *const coverage_node = node_else ? node_else : node;
6833 add_trace_branch_coverage(
6834 iseq,
6835 ret,
6836 nd_code_loc(coverage_node),
6837 nd_node_id(coverage_node),
6838 1,
6839 type == NODE_IF ? "else" : "then",
6840 branches);
6841 }
6842 ADD_SEQ(ret, else_seq);
6843 }
6844
6845 if (end_label) {
6846 ADD_LABEL(ret, end_label);
6847 }
6848
6849 return COMPILE_OK;
6850}
6851
6852static int
6853compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6854{
6855 const NODE *vals;
6856 const NODE *node = orig_node;
6857 LABEL *endlabel, *elselabel;
6858 DECL_ANCHOR(head);
6859 DECL_ANCHOR(body_seq);
6860 DECL_ANCHOR(cond_seq);
6861 int only_special_literals = 1;
6862 VALUE literals = rb_hash_new();
6863 int line;
6864 enum node_type type;
6865 const NODE *line_node;
6866 VALUE branches = Qfalse;
6867 int branch_id = 0;
6868
6869 INIT_ANCHOR(head);
6870 INIT_ANCHOR(body_seq);
6871 INIT_ANCHOR(cond_seq);
6872
6873 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6874
6875 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6876
6877 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6878
6879 node = RNODE_CASE(node)->nd_body;
6880 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6881 type = nd_type(node);
6882 line = nd_line(node);
6883 line_node = node;
6884
6885 endlabel = NEW_LABEL(line);
6886 elselabel = NEW_LABEL(line);
6887
6888 ADD_SEQ(ret, head); /* case VAL */
6889
6890 while (type == NODE_WHEN) {
6891 LABEL *l1;
6892
6893 l1 = NEW_LABEL(line);
6894 ADD_LABEL(body_seq, l1);
6895 ADD_INSN(body_seq, line_node, pop);
6896
6897 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6898 add_trace_branch_coverage(
6899 iseq,
6900 body_seq,
6901 nd_code_loc(coverage_node),
6902 nd_node_id(coverage_node),
6903 branch_id++,
6904 "when",
6905 branches);
6906
6907 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6908 ADD_INSNL(body_seq, line_node, jump, endlabel);
6909
6910 vals = RNODE_WHEN(node)->nd_head;
6911 if (vals) {
6912 switch (nd_type(vals)) {
6913 case NODE_LIST:
6914 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6915 if (only_special_literals < 0) return COMPILE_NG;
6916 break;
6917 case NODE_SPLAT:
6918 case NODE_ARGSCAT:
6919 case NODE_ARGSPUSH:
6920 only_special_literals = 0;
6921 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6922 break;
6923 default:
6924 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6925 }
6926 }
6927 else {
6928 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6929 }
6930
6931 node = RNODE_WHEN(node)->nd_next;
6932 if (!node) {
6933 break;
6934 }
6935 type = nd_type(node);
6936 line = nd_line(node);
6937 line_node = node;
6938 }
6939 /* else */
6940 if (node) {
6941 ADD_LABEL(cond_seq, elselabel);
6942 ADD_INSN(cond_seq, line_node, pop);
6943 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
6944 CHECK(COMPILE_(cond_seq, "else", node, popped));
6945 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6946 }
6947 else {
6948 debugs("== else (implicit)\n");
6949 ADD_LABEL(cond_seq, elselabel);
6950 ADD_INSN(cond_seq, orig_node, pop);
6951 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
6952 if (!popped) {
6953 ADD_INSN(cond_seq, orig_node, putnil);
6954 }
6955 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6956 }
6957
6958 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6959 ADD_INSN(ret, orig_node, dup);
6960 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6961 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6962 LABEL_REF(elselabel);
6963 }
6964
6965 ADD_SEQ(ret, cond_seq);
6966 ADD_SEQ(ret, body_seq);
6967 ADD_LABEL(ret, endlabel);
6968 return COMPILE_OK;
6969}
6970
6971static int
6972compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6973{
6974 const NODE *vals;
6975 const NODE *val;
6976 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6977 LABEL *endlabel;
6978 DECL_ANCHOR(body_seq);
6979 VALUE branches = Qfalse;
6980 int branch_id = 0;
6981
6982 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
6983
6984 INIT_ANCHOR(body_seq);
6985 endlabel = NEW_LABEL(nd_line(node));
6986
6987 while (node && nd_type_p(node, NODE_WHEN)) {
6988 const int line = nd_line(node);
6989 LABEL *l1 = NEW_LABEL(line);
6990 ADD_LABEL(body_seq, l1);
6991
6992 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6993 add_trace_branch_coverage(
6994 iseq,
6995 body_seq,
6996 nd_code_loc(coverage_node),
6997 nd_node_id(coverage_node),
6998 branch_id++,
6999 "when",
7000 branches);
7001
7002 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7003 ADD_INSNL(body_seq, node, jump, endlabel);
7004
7005 vals = RNODE_WHEN(node)->nd_head;
7006 if (!vals) {
7007 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7008 }
7009 switch (nd_type(vals)) {
7010 case NODE_LIST:
7011 while (vals) {
7012 LABEL *lnext;
7013 val = RNODE_LIST(vals)->nd_head;
7014 lnext = NEW_LABEL(nd_line(val));
7015 debug_compile("== when2\n", (void)0);
7016 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7017 ADD_LABEL(ret, lnext);
7018 vals = RNODE_LIST(vals)->nd_next;
7019 }
7020 break;
7021 case NODE_SPLAT:
7022 case NODE_ARGSCAT:
7023 case NODE_ARGSPUSH:
7024 ADD_INSN(ret, vals, putnil);
7025 CHECK(COMPILE(ret, "when2/cond splat", vals));
7026 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7027 ADD_INSNL(ret, vals, branchif, l1);
7028 break;
7029 default:
7030 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7031 }
7032 node = RNODE_WHEN(node)->nd_next;
7033 }
7034 /* else */
7035 const NODE *const coverage_node = node ? node : orig_node;
7036 add_trace_branch_coverage(
7037 iseq,
7038 ret,
7039 nd_code_loc(coverage_node),
7040 nd_node_id(coverage_node),
7041 branch_id,
7042 "else",
7043 branches);
7044 CHECK(COMPILE_(ret, "else", node, popped));
7045 ADD_INSNL(ret, orig_node, jump, endlabel);
7046
7047 ADD_SEQ(ret, body_seq);
7048 ADD_LABEL(ret, endlabel);
7049 return COMPILE_OK;
7050}
7051
7052static 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);
7053
7054static 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);
7055static 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);
7056static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7057static 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);
7058static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7059
7060#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7061#define CASE3_BI_OFFSET_ERROR_STRING 1
7062#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7063#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7064#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7065
7066static int
7067iseq_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)
7068{
7069 const int line = nd_line(node);
7070 const NODE *line_node = node;
7071
7072 switch (nd_type(node)) {
7073 case NODE_ARYPTN: {
7074 /*
7075 * if pattern.use_rest_num?
7076 * rest_num = 0
7077 * end
7078 * if pattern.has_constant_node?
7079 * unless pattern.constant === obj
7080 * goto match_failed
7081 * end
7082 * end
7083 * unless obj.respond_to?(:deconstruct)
7084 * goto match_failed
7085 * end
7086 * d = obj.deconstruct
7087 * unless Array === d
7088 * goto type_error
7089 * end
7090 * min_argc = pattern.pre_args_num + pattern.post_args_num
7091 * if pattern.has_rest_arg?
7092 * unless d.length >= min_argc
7093 * goto match_failed
7094 * end
7095 * else
7096 * unless d.length == min_argc
7097 * goto match_failed
7098 * end
7099 * end
7100 * pattern.pre_args_num.each do |i|
7101 * unless pattern.pre_args[i].match?(d[i])
7102 * goto match_failed
7103 * end
7104 * end
7105 * if pattern.use_rest_num?
7106 * rest_num = d.length - min_argc
7107 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7108 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7109 * goto match_failed
7110 * end
7111 * end
7112 * end
7113 * pattern.post_args_num.each do |i|
7114 * j = pattern.pre_args_num + i
7115 * j += rest_num
7116 * unless pattern.post_args[i].match?(d[j])
7117 * goto match_failed
7118 * end
7119 * end
7120 * goto matched
7121 * type_error:
7122 * FrozenCore.raise TypeError
7123 * match_failed:
7124 * goto unmatched
7125 */
7126 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7127 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7128 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7129
7130 const int min_argc = pre_args_num + post_args_num;
7131 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7132 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7133
7134 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7135 int i;
7136 match_failed = NEW_LABEL(line);
7137 type_error = NEW_LABEL(line);
7138 deconstruct = NEW_LABEL(line);
7139 deconstructed = NEW_LABEL(line);
7140
7141 if (use_rest_num) {
7142 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7143 ADD_INSN(ret, line_node, swap);
7144 if (base_index) {
7145 base_index++;
7146 }
7147 }
7148
7149 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7150
7151 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7152
7153 ADD_INSN(ret, line_node, dup);
7154 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7155 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7156 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7157 if (in_single_pattern) {
7158 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7159 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7160 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7161 INT2FIX(min_argc), base_index + 1 /* (1) */));
7162 }
7163 ADD_INSNL(ret, line_node, branchunless, match_failed);
7164
7165 for (i = 0; i < pre_args_num; i++) {
7166 ADD_INSN(ret, line_node, dup);
7167 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7168 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7169 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));
7170 args = RNODE_LIST(args)->nd_next;
7171 }
7172
7173 if (RNODE_ARYPTN(node)->rest_arg) {
7174 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7175 ADD_INSN(ret, line_node, dup);
7176 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7177 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7178 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7179 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7180 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7181 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7182 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7183
7184 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));
7185 }
7186 else {
7187 if (post_args_num > 0) {
7188 ADD_INSN(ret, line_node, dup);
7189 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7190 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7191 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7192 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7193 ADD_INSN(ret, line_node, pop);
7194 }
7195 }
7196 }
7197
7198 args = RNODE_ARYPTN(node)->post_args;
7199 for (i = 0; i < post_args_num; i++) {
7200 ADD_INSN(ret, line_node, dup);
7201
7202 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7203 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7204 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7205
7206 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7207 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));
7208 args = RNODE_LIST(args)->nd_next;
7209 }
7210
7211 ADD_INSN(ret, line_node, pop);
7212 if (use_rest_num) {
7213 ADD_INSN(ret, line_node, pop);
7214 }
7215 ADD_INSNL(ret, line_node, jump, matched);
7216 ADD_INSN(ret, line_node, putnil);
7217 if (use_rest_num) {
7218 ADD_INSN(ret, line_node, putnil);
7219 }
7220
7221 ADD_LABEL(ret, type_error);
7222 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7223 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7224 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7225 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7226 ADD_INSN(ret, line_node, pop);
7227
7228 ADD_LABEL(ret, match_failed);
7229 ADD_INSN(ret, line_node, pop);
7230 if (use_rest_num) {
7231 ADD_INSN(ret, line_node, pop);
7232 }
7233 ADD_INSNL(ret, line_node, jump, unmatched);
7234
7235 break;
7236 }
7237 case NODE_FNDPTN: {
7238 /*
7239 * if pattern.has_constant_node?
7240 * unless pattern.constant === obj
7241 * goto match_failed
7242 * end
7243 * end
7244 * unless obj.respond_to?(:deconstruct)
7245 * goto match_failed
7246 * end
7247 * d = obj.deconstruct
7248 * unless Array === d
7249 * goto type_error
7250 * end
7251 * unless d.length >= pattern.args_num
7252 * goto match_failed
7253 * end
7254 *
7255 * begin
7256 * len = d.length
7257 * limit = d.length - pattern.args_num
7258 * i = 0
7259 * while i <= limit
7260 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7261 * if pattern.has_pre_rest_arg_id
7262 * unless pattern.pre_rest_arg.match?(d[0, i])
7263 * goto find_failed
7264 * end
7265 * end
7266 * if pattern.has_post_rest_arg_id
7267 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7268 * goto find_failed
7269 * end
7270 * end
7271 * goto find_succeeded
7272 * end
7273 * i+=1
7274 * end
7275 * find_failed:
7276 * goto match_failed
7277 * find_succeeded:
7278 * end
7279 *
7280 * goto matched
7281 * type_error:
7282 * FrozenCore.raise TypeError
7283 * match_failed:
7284 * goto unmatched
7285 */
7286 const NODE *args = RNODE_FNDPTN(node)->args;
7287 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7288
7289 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7290 match_failed = NEW_LABEL(line);
7291 type_error = NEW_LABEL(line);
7292 deconstruct = NEW_LABEL(line);
7293 deconstructed = NEW_LABEL(line);
7294
7295 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7296
7297 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7298
7299 ADD_INSN(ret, line_node, dup);
7300 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7301 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7302 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7303 if (in_single_pattern) {
7304 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) */));
7305 }
7306 ADD_INSNL(ret, line_node, branchunless, match_failed);
7307
7308 {
7309 LABEL *while_begin = NEW_LABEL(nd_line(node));
7310 LABEL *next_loop = NEW_LABEL(nd_line(node));
7311 LABEL *find_succeeded = NEW_LABEL(line);
7312 LABEL *find_failed = NEW_LABEL(nd_line(node));
7313 int j;
7314
7315 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7316 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7317
7318 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7319 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7320 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7321
7322 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7323
7324 ADD_LABEL(ret, while_begin);
7325
7326 ADD_INSN(ret, line_node, dup);
7327 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7328 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7329 ADD_INSNL(ret, line_node, branchunless, find_failed);
7330
7331 for (j = 0; j < args_num; j++) {
7332 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7333 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7334 if (j != 0) {
7335 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7336 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7337 }
7338 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7339
7340 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));
7341 args = RNODE_LIST(args)->nd_next;
7342 }
7343
7344 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7345 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7346 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7347 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7348 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7349 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));
7350 }
7351 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7352 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7353 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7354 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7355 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7356 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7357 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7358 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));
7359 }
7360 ADD_INSNL(ret, line_node, jump, find_succeeded);
7361
7362 ADD_LABEL(ret, next_loop);
7363 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7364 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7365 ADD_INSNL(ret, line_node, jump, while_begin);
7366
7367 ADD_LABEL(ret, find_failed);
7368 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7369 if (in_single_pattern) {
7370 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7371 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7372 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7373 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7374 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7375
7376 ADD_INSN1(ret, line_node, putobject, Qfalse);
7377 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7378
7379 ADD_INSN(ret, line_node, pop);
7380 ADD_INSN(ret, line_node, pop);
7381 }
7382 ADD_INSNL(ret, line_node, jump, match_failed);
7383 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7384
7385 ADD_LABEL(ret, find_succeeded);
7386 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7387 }
7388
7389 ADD_INSN(ret, line_node, pop);
7390 ADD_INSNL(ret, line_node, jump, matched);
7391 ADD_INSN(ret, line_node, putnil);
7392
7393 ADD_LABEL(ret, type_error);
7394 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7395 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7396 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7397 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7398 ADD_INSN(ret, line_node, pop);
7399
7400 ADD_LABEL(ret, match_failed);
7401 ADD_INSN(ret, line_node, pop);
7402 ADD_INSNL(ret, line_node, jump, unmatched);
7403
7404 break;
7405 }
7406 case NODE_HSHPTN: {
7407 /*
7408 * keys = nil
7409 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7410 * keys = pattern.kw_args_node.keys
7411 * end
7412 * if pattern.has_constant_node?
7413 * unless pattern.constant === obj
7414 * goto match_failed
7415 * end
7416 * end
7417 * unless obj.respond_to?(:deconstruct_keys)
7418 * goto match_failed
7419 * end
7420 * d = obj.deconstruct_keys(keys)
7421 * unless Hash === d
7422 * goto type_error
7423 * end
7424 * if pattern.has_kw_rest_arg_node?
7425 * d = d.dup
7426 * end
7427 * if pattern.has_kw_args_node?
7428 * pattern.kw_args_node.each |k,|
7429 * unless d.key?(k)
7430 * goto match_failed
7431 * end
7432 * end
7433 * pattern.kw_args_node.each |k, pat|
7434 * if pattern.has_kw_rest_arg_node?
7435 * unless pat.match?(d.delete(k))
7436 * goto match_failed
7437 * end
7438 * else
7439 * unless pat.match?(d[k])
7440 * goto match_failed
7441 * end
7442 * end
7443 * end
7444 * else
7445 * unless d.empty?
7446 * goto match_failed
7447 * end
7448 * end
7449 * if pattern.has_kw_rest_arg_node?
7450 * if pattern.no_rest_keyword?
7451 * unless d.empty?
7452 * goto match_failed
7453 * end
7454 * else
7455 * unless pattern.kw_rest_arg_node.match?(d)
7456 * goto match_failed
7457 * end
7458 * end
7459 * end
7460 * goto matched
7461 * type_error:
7462 * FrozenCore.raise TypeError
7463 * match_failed:
7464 * goto unmatched
7465 */
7466 LABEL *match_failed, *type_error;
7467 VALUE keys = Qnil;
7468
7469 match_failed = NEW_LABEL(line);
7470 type_error = NEW_LABEL(line);
7471
7472 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7473 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7474 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7475 while (kw_args) {
7476 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7477 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7478 }
7479 }
7480
7481 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7482
7483 ADD_INSN(ret, line_node, dup);
7484 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7485 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7486 if (in_single_pattern) {
7487 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7488 }
7489 ADD_INSNL(ret, line_node, branchunless, match_failed);
7490
7491 if (NIL_P(keys)) {
7492 ADD_INSN(ret, line_node, putnil);
7493 }
7494 else {
7495 ADD_INSN1(ret, line_node, duparray, keys);
7496 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7497 }
7498 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7499
7500 ADD_INSN(ret, line_node, dup);
7501 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7502 ADD_INSNL(ret, line_node, branchunless, type_error);
7503
7504 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7505 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7506 }
7507
7508 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7509 int i;
7510 int keys_num;
7511 const NODE *args;
7512 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7513 if (args) {
7514 DECL_ANCHOR(match_values);
7515 INIT_ANCHOR(match_values);
7516 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7517 for (i = 0; i < keys_num; i++) {
7518 NODE *key_node = RNODE_LIST(args)->nd_head;
7519 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7520 VALUE key = get_symbol_value(iseq, key_node);
7521
7522 ADD_INSN(ret, line_node, dup);
7523 ADD_INSN1(ret, line_node, putobject, key);
7524 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7525 if (in_single_pattern) {
7526 LABEL *match_succeeded;
7527 match_succeeded = NEW_LABEL(line);
7528
7529 ADD_INSN(ret, line_node, dup);
7530 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7531
7532 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7533 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7534 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7535 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7536 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7537 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7538 ADD_INSN1(ret, line_node, putobject, key); // (7)
7539 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7540
7541 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7542
7543 ADD_LABEL(ret, match_succeeded);
7544 }
7545 ADD_INSNL(ret, line_node, branchunless, match_failed);
7546
7547 ADD_INSN(match_values, line_node, dup);
7548 ADD_INSN1(match_values, line_node, putobject, key);
7549 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7550 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7551 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7552 }
7553 ADD_SEQ(ret, match_values);
7554 }
7555 }
7556 else {
7557 ADD_INSN(ret, line_node, dup);
7558 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7559 if (in_single_pattern) {
7560 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7561 }
7562 ADD_INSNL(ret, line_node, branchunless, match_failed);
7563 }
7564
7565 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7566 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7567 ADD_INSN(ret, line_node, dup);
7568 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7569 if (in_single_pattern) {
7570 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7571 }
7572 ADD_INSNL(ret, line_node, branchunless, match_failed);
7573 }
7574 else {
7575 ADD_INSN(ret, line_node, dup); // (11)
7576 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));
7577 }
7578 }
7579
7580 ADD_INSN(ret, line_node, pop);
7581 ADD_INSNL(ret, line_node, jump, matched);
7582 ADD_INSN(ret, line_node, putnil);
7583
7584 ADD_LABEL(ret, type_error);
7585 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7586 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7587 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7588 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7589 ADD_INSN(ret, line_node, pop);
7590
7591 ADD_LABEL(ret, match_failed);
7592 ADD_INSN(ret, line_node, pop);
7593 ADD_INSNL(ret, line_node, jump, unmatched);
7594 break;
7595 }
7596 case NODE_SYM:
7597 case NODE_REGX:
7598 case NODE_LINE:
7599 case NODE_INTEGER:
7600 case NODE_FLOAT:
7601 case NODE_RATIONAL:
7602 case NODE_IMAGINARY:
7603 case NODE_FILE:
7604 case NODE_ENCODING:
7605 case NODE_STR:
7606 case NODE_XSTR:
7607 case NODE_DSTR:
7608 case NODE_DSYM:
7609 case NODE_DREGX:
7610 case NODE_LIST:
7611 case NODE_ZLIST:
7612 case NODE_LAMBDA:
7613 case NODE_DOT2:
7614 case NODE_DOT3:
7615 case NODE_CONST:
7616 case NODE_LVAR:
7617 case NODE_DVAR:
7618 case NODE_IVAR:
7619 case NODE_CVAR:
7620 case NODE_GVAR:
7621 case NODE_TRUE:
7622 case NODE_FALSE:
7623 case NODE_SELF:
7624 case NODE_NIL:
7625 case NODE_COLON2:
7626 case NODE_COLON3:
7627 case NODE_BEGIN:
7628 case NODE_BLOCK:
7629 case NODE_ONCE:
7630 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7631 if (in_single_pattern) {
7632 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7633 }
7634 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7635 if (in_single_pattern) {
7636 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7637 }
7638 ADD_INSNL(ret, line_node, branchif, matched);
7639 ADD_INSNL(ret, line_node, jump, unmatched);
7640 break;
7641 case NODE_LASGN: {
7642 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7643 ID id = RNODE_LASGN(node)->nd_vid;
7644 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7645
7646 if (in_alt_pattern) {
7647 const char *name = rb_id2name(id);
7648 if (name && strlen(name) > 0 && name[0] != '_') {
7649 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7650 rb_id2str(id));
7651 return COMPILE_NG;
7652 }
7653 }
7654
7655 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7656 ADD_INSNL(ret, line_node, jump, matched);
7657 break;
7658 }
7659 case NODE_DASGN: {
7660 int idx, lv, ls;
7661 ID id = RNODE_DASGN(node)->nd_vid;
7662
7663 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7664
7665 if (in_alt_pattern) {
7666 const char *name = rb_id2name(id);
7667 if (name && strlen(name) > 0 && name[0] != '_') {
7668 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7669 rb_id2str(id));
7670 return COMPILE_NG;
7671 }
7672 }
7673
7674 if (idx < 0) {
7675 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7676 rb_id2str(id));
7677 return COMPILE_NG;
7678 }
7679 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7680 ADD_INSNL(ret, line_node, jump, matched);
7681 break;
7682 }
7683 case NODE_IF:
7684 case NODE_UNLESS: {
7685 LABEL *match_failed;
7686 match_failed = unmatched;
7687 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7688 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7689 if (in_single_pattern) {
7690 LABEL *match_succeeded;
7691 match_succeeded = NEW_LABEL(line);
7692
7693 ADD_INSN(ret, line_node, dup);
7694 if (nd_type_p(node, NODE_IF)) {
7695 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7696 }
7697 else {
7698 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7699 }
7700
7701 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7702 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7703 ADD_INSN1(ret, line_node, putobject, Qfalse);
7704 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7705
7706 ADD_INSN(ret, line_node, pop);
7707 ADD_INSN(ret, line_node, pop);
7708
7709 ADD_LABEL(ret, match_succeeded);
7710 }
7711 if (nd_type_p(node, NODE_IF)) {
7712 ADD_INSNL(ret, line_node, branchunless, match_failed);
7713 }
7714 else {
7715 ADD_INSNL(ret, line_node, branchif, match_failed);
7716 }
7717 ADD_INSNL(ret, line_node, jump, matched);
7718 break;
7719 }
7720 case NODE_HASH: {
7721 NODE *n;
7722 LABEL *match_failed;
7723 match_failed = NEW_LABEL(line);
7724
7725 n = RNODE_HASH(node)->nd_head;
7726 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7727 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7728 return COMPILE_NG;
7729 }
7730
7731 ADD_INSN(ret, line_node, dup); // (1)
7732 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));
7733 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));
7734 ADD_INSN(ret, line_node, putnil);
7735
7736 ADD_LABEL(ret, match_failed);
7737 ADD_INSN(ret, line_node, pop);
7738 ADD_INSNL(ret, line_node, jump, unmatched);
7739 break;
7740 }
7741 case NODE_OR: {
7742 LABEL *match_succeeded, *fin;
7743 match_succeeded = NEW_LABEL(line);
7744 fin = NEW_LABEL(line);
7745
7746 ADD_INSN(ret, line_node, dup); // (1)
7747 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));
7748 ADD_LABEL(ret, match_succeeded);
7749 ADD_INSN(ret, line_node, pop);
7750 ADD_INSNL(ret, line_node, jump, matched);
7751 ADD_INSN(ret, line_node, putnil);
7752 ADD_LABEL(ret, fin);
7753 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7754 break;
7755 }
7756 default:
7757 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7758 }
7759 return COMPILE_OK;
7760}
7761
7762static int
7763iseq_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)
7764{
7765 LABEL *fin = NEW_LABEL(nd_line(node));
7766 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7767 ADD_LABEL(ret, fin);
7768 return COMPILE_OK;
7769}
7770
7771static int
7772iseq_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)
7773{
7774 const NODE *line_node = node;
7775
7776 if (RNODE_ARYPTN(node)->nd_pconst) {
7777 ADD_INSN(ret, line_node, dup); // (1)
7778 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7779 if (in_single_pattern) {
7780 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7781 }
7782 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7783 if (in_single_pattern) {
7784 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7785 }
7786 ADD_INSNL(ret, line_node, branchunless, match_failed);
7787 }
7788 return COMPILE_OK;
7789}
7790
7791
7792static int
7793iseq_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)
7794{
7795 const NODE *line_node = node;
7796
7797 // NOTE: this optimization allows us to re-use the #deconstruct value
7798 // (or its absence).
7799 if (use_deconstructed_cache) {
7800 // If value is nil then we haven't tried to deconstruct
7801 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7802 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7803
7804 // If false then the value is not deconstructable
7805 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7806 ADD_INSNL(ret, line_node, branchunless, match_failed);
7807
7808 // Drop value, add deconstructed to the stack and jump
7809 ADD_INSN(ret, line_node, pop); // (1)
7810 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7811 ADD_INSNL(ret, line_node, jump, deconstructed);
7812 }
7813 else {
7814 ADD_INSNL(ret, line_node, jump, deconstruct);
7815 }
7816
7817 ADD_LABEL(ret, deconstruct);
7818 ADD_INSN(ret, line_node, dup);
7819 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7820 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7821
7822 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7823 if (use_deconstructed_cache) {
7824 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7825 }
7826
7827 if (in_single_pattern) {
7828 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7829 }
7830
7831 ADD_INSNL(ret, line_node, branchunless, match_failed);
7832
7833 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7834
7835 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7836 if (use_deconstructed_cache) {
7837 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7838 }
7839
7840 ADD_INSN(ret, line_node, dup);
7841 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7842 ADD_INSNL(ret, line_node, branchunless, type_error);
7843
7844 ADD_LABEL(ret, deconstructed);
7845
7846 return COMPILE_OK;
7847}
7848
7849static int
7850iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7851{
7852 /*
7853 * if match_succeeded?
7854 * goto match_succeeded
7855 * end
7856 * error_string = FrozenCore.sprintf(errmsg, matchee)
7857 * key_error_p = false
7858 * match_succeeded:
7859 */
7860 const int line = nd_line(node);
7861 const NODE *line_node = node;
7862 LABEL *match_succeeded = NEW_LABEL(line);
7863
7864 ADD_INSN(ret, line_node, dup);
7865 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7866
7867 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7868 ADD_INSN1(ret, line_node, putobject, errmsg);
7869 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7870 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7871 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7872
7873 ADD_INSN1(ret, line_node, putobject, Qfalse);
7874 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7875
7876 ADD_INSN(ret, line_node, pop);
7877 ADD_INSN(ret, line_node, pop);
7878 ADD_LABEL(ret, match_succeeded);
7879
7880 return COMPILE_OK;
7881}
7882
7883static int
7884iseq_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)
7885{
7886 /*
7887 * if match_succeeded?
7888 * goto match_succeeded
7889 * end
7890 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7891 * key_error_p = false
7892 * match_succeeded:
7893 */
7894 const int line = nd_line(node);
7895 const NODE *line_node = node;
7896 LABEL *match_succeeded = NEW_LABEL(line);
7897
7898 ADD_INSN(ret, line_node, dup);
7899 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7900
7901 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7902 ADD_INSN1(ret, line_node, putobject, errmsg);
7903 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7904 ADD_INSN(ret, line_node, dup);
7905 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7906 ADD_INSN1(ret, line_node, putobject, pattern_length);
7907 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7908 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7909
7910 ADD_INSN1(ret, line_node, putobject, Qfalse);
7911 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7912
7913 ADD_INSN(ret, line_node, pop);
7914 ADD_INSN(ret, line_node, pop);
7915 ADD_LABEL(ret, match_succeeded);
7916
7917 return COMPILE_OK;
7918}
7919
7920static int
7921iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7922{
7923 /*
7924 * if match_succeeded?
7925 * goto match_succeeded
7926 * end
7927 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7928 * key_error_p = false
7929 * match_succeeded:
7930 */
7931 const int line = nd_line(node);
7932 const NODE *line_node = node;
7933 LABEL *match_succeeded = NEW_LABEL(line);
7934
7935 ADD_INSN(ret, line_node, dup);
7936 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7937
7938 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7939 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7940 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7941 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7942 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7943 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7944
7945 ADD_INSN1(ret, line_node, putobject, Qfalse);
7946 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7947
7948 ADD_INSN(ret, line_node, pop);
7949 ADD_INSN(ret, line_node, pop);
7950
7951 ADD_LABEL(ret, match_succeeded);
7952 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7953 ADD_INSN(ret, line_node, pop);
7954 ADD_INSN(ret, line_node, pop);
7955
7956 return COMPILE_OK;
7957}
7958
7959static int
7960compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7961{
7962 const NODE *pattern;
7963 const NODE *node = orig_node;
7964 LABEL *endlabel, *elselabel;
7965 DECL_ANCHOR(head);
7966 DECL_ANCHOR(body_seq);
7967 DECL_ANCHOR(cond_seq);
7968 int line;
7969 enum node_type type;
7970 const NODE *line_node;
7971 VALUE branches = 0;
7972 int branch_id = 0;
7973 bool single_pattern;
7974
7975 INIT_ANCHOR(head);
7976 INIT_ANCHOR(body_seq);
7977 INIT_ANCHOR(cond_seq);
7978
7979 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7980
7981 node = RNODE_CASE3(node)->nd_body;
7982 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7983 type = nd_type(node);
7984 line = nd_line(node);
7985 line_node = node;
7986 single_pattern = !RNODE_IN(node)->nd_next;
7987
7988 endlabel = NEW_LABEL(line);
7989 elselabel = NEW_LABEL(line);
7990
7991 if (single_pattern) {
7992 /* allocate stack for ... */
7993 ADD_INSN(head, line_node, putnil); /* key_error_key */
7994 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7995 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7996 ADD_INSN(head, line_node, putnil); /* error_string */
7997 }
7998 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7999
8000 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8001
8002 ADD_SEQ(ret, head); /* case VAL */
8003
8004 while (type == NODE_IN) {
8005 LABEL *l1;
8006
8007 if (branch_id) {
8008 ADD_INSN(body_seq, line_node, putnil);
8009 }
8010 l1 = NEW_LABEL(line);
8011 ADD_LABEL(body_seq, l1);
8012 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8013
8014 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8015 add_trace_branch_coverage(
8016 iseq,
8017 body_seq,
8018 nd_code_loc(coverage_node),
8019 nd_node_id(coverage_node),
8020 branch_id++,
8021 "in",
8022 branches);
8023
8024 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8025 ADD_INSNL(body_seq, line_node, jump, endlabel);
8026
8027 pattern = RNODE_IN(node)->nd_head;
8028 if (pattern) {
8029 int pat_line = nd_line(pattern);
8030 LABEL *next_pat = NEW_LABEL(pat_line);
8031 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8032 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8033 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8034 ADD_LABEL(cond_seq, next_pat);
8035 LABEL_UNREMOVABLE(next_pat);
8036 }
8037 else {
8038 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8039 return COMPILE_NG;
8040 }
8041
8042 node = RNODE_IN(node)->nd_next;
8043 if (!node) {
8044 break;
8045 }
8046 type = nd_type(node);
8047 line = nd_line(node);
8048 line_node = node;
8049 }
8050 /* else */
8051 if (node) {
8052 ADD_LABEL(cond_seq, elselabel);
8053 ADD_INSN(cond_seq, line_node, pop);
8054 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8055 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8056 CHECK(COMPILE_(cond_seq, "else", node, popped));
8057 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8058 ADD_INSN(cond_seq, line_node, putnil);
8059 if (popped) {
8060 ADD_INSN(cond_seq, line_node, putnil);
8061 }
8062 }
8063 else {
8064 debugs("== else (implicit)\n");
8065 ADD_LABEL(cond_seq, elselabel);
8066 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8067 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8068
8069 if (single_pattern) {
8070 /*
8071 * if key_error_p
8072 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8073 * else
8074 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8075 * end
8076 */
8077 LABEL *key_error, *fin;
8078 struct rb_callinfo_kwarg *kw_arg;
8079
8080 key_error = NEW_LABEL(line);
8081 fin = NEW_LABEL(line);
8082
8083 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8084 kw_arg->references = 0;
8085 kw_arg->keyword_len = 2;
8086 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8087 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8088
8089 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8090 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8091 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8092 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8093 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8094 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8095 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8096 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8097 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8098 ADD_INSNL(cond_seq, orig_node, jump, fin);
8099
8100 ADD_LABEL(cond_seq, key_error);
8101 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8102 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8103 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8104 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8105 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8106 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8107 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8108 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8109 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8110 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8111
8112 ADD_LABEL(cond_seq, fin);
8113 }
8114 else {
8115 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8116 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8117 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8118 }
8119 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8120 if (!popped) {
8121 ADD_INSN(cond_seq, orig_node, putnil);
8122 }
8123 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8124 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8125 if (popped) {
8126 ADD_INSN(cond_seq, line_node, putnil);
8127 }
8128 }
8129
8130 ADD_SEQ(ret, cond_seq);
8131 ADD_SEQ(ret, body_seq);
8132 ADD_LABEL(ret, endlabel);
8133 return COMPILE_OK;
8134}
8135
8136#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8137#undef CASE3_BI_OFFSET_ERROR_STRING
8138#undef CASE3_BI_OFFSET_KEY_ERROR_P
8139#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8140#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8141
8142static int
8143compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8144{
8145 const int line = (int)nd_line(node);
8146 const NODE *line_node = node;
8147
8148 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8149 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8150 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8151 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8152 VALUE branches = Qfalse;
8153
8154 struct iseq_compile_data_ensure_node_stack enl;
8155
8156 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8157 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8158 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8159 LABEL *end_label = NEW_LABEL(line);
8160 LABEL *adjust_label = NEW_LABEL(line);
8161
8162 LABEL *next_catch_label = NEW_LABEL(line);
8163 LABEL *tmp_label = NULL;
8164
8165 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8166 push_ensure_entry(iseq, &enl, NULL, NULL);
8167
8168 if (RNODE_WHILE(node)->nd_state == 1) {
8169 ADD_INSNL(ret, line_node, jump, next_label);
8170 }
8171 else {
8172 tmp_label = NEW_LABEL(line);
8173 ADD_INSNL(ret, line_node, jump, tmp_label);
8174 }
8175 ADD_LABEL(ret, adjust_label);
8176 ADD_INSN(ret, line_node, putnil);
8177 ADD_LABEL(ret, next_catch_label);
8178 ADD_INSN(ret, line_node, pop);
8179 ADD_INSNL(ret, line_node, jump, next_label);
8180 if (tmp_label) ADD_LABEL(ret, tmp_label);
8181
8182 ADD_LABEL(ret, redo_label);
8183 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8184
8185 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8186 add_trace_branch_coverage(
8187 iseq,
8188 ret,
8189 nd_code_loc(coverage_node),
8190 nd_node_id(coverage_node),
8191 0,
8192 "body",
8193 branches);
8194
8195 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8196 ADD_LABEL(ret, next_label); /* next */
8197
8198 if (type == NODE_WHILE) {
8199 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8200 redo_label, end_label));
8201 }
8202 else {
8203 /* until */
8204 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8205 end_label, redo_label));
8206 }
8207
8208 ADD_LABEL(ret, end_label);
8209 ADD_ADJUST_RESTORE(ret, adjust_label);
8210
8211 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8212 /* ADD_INSN(ret, line_node, putundef); */
8213 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8214 return COMPILE_NG;
8215 }
8216 else {
8217 ADD_INSN(ret, line_node, putnil);
8218 }
8219
8220 ADD_LABEL(ret, break_label); /* break */
8221
8222 if (popped) {
8223 ADD_INSN(ret, line_node, pop);
8224 }
8225
8226 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8227 break_label);
8228 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8229 next_catch_label);
8230 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8231 ISEQ_COMPILE_DATA(iseq)->redo_label);
8232
8233 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8234 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8235 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8236 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8237 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8238 return COMPILE_OK;
8239}
8240
8241static int
8242compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8243{
8244 const int line = nd_line(node);
8245 const NODE *line_node = node;
8246 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8247 LABEL *retry_label = NEW_LABEL(line);
8248 LABEL *retry_end_l = NEW_LABEL(line);
8249 const rb_iseq_t *child_iseq;
8250
8251 ADD_LABEL(ret, retry_label);
8252 if (nd_type_p(node, NODE_FOR)) {
8253 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8254
8255 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8256 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8257 ISEQ_TYPE_BLOCK, line);
8258 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8259 }
8260 else {
8261 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8262 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8263 ISEQ_TYPE_BLOCK, line);
8264 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8265 }
8266
8267 {
8268 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8269 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8270 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8271 //
8272 // Normally, "send" instruction is at the last.
8273 // However, qcall under branch coverage measurement adds some instructions after the "send".
8274 //
8275 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8276 INSN *iobj;
8277 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8278 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8279 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8280 iobj = (INSN*) get_prev_insn(iobj);
8281 }
8282 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8283
8284 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8285 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8286 if (&iobj->link == LAST_ELEMENT(ret)) {
8287 ret->last = (LINK_ELEMENT*) retry_end_l;
8288 }
8289 }
8290
8291 if (popped) {
8292 ADD_INSN(ret, line_node, pop);
8293 }
8294
8295 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8296
8297 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8298 return COMPILE_OK;
8299}
8300
8301static int
8302compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8303{
8304 /* massign to var in "for"
8305 * (args.length == 1 && Array.try_convert(args[0])) || args
8306 */
8307 const NODE *line_node = node;
8308 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8309 LABEL *not_single = NEW_LABEL(nd_line(var));
8310 LABEL *not_ary = NEW_LABEL(nd_line(var));
8311 CHECK(COMPILE(ret, "for var", var));
8312 ADD_INSN(ret, line_node, dup);
8313 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8314 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8315 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8316 ADD_INSNL(ret, line_node, branchunless, not_single);
8317 ADD_INSN(ret, line_node, dup);
8318 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8319 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8320 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8321 ADD_INSN(ret, line_node, swap);
8322 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8323 ADD_INSN(ret, line_node, dup);
8324 ADD_INSNL(ret, line_node, branchunless, not_ary);
8325 ADD_INSN(ret, line_node, swap);
8326 ADD_LABEL(ret, not_ary);
8327 ADD_INSN(ret, line_node, pop);
8328 ADD_LABEL(ret, not_single);
8329 return COMPILE_OK;
8330}
8331
8332static int
8333compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8334{
8335 const NODE *line_node = node;
8336 unsigned long throw_flag = 0;
8337
8338 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8339 /* while/until */
8340 LABEL *splabel = NEW_LABEL(0);
8341 ADD_LABEL(ret, splabel);
8342 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8343 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8344 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8345 add_ensure_iseq(ret, iseq, 0);
8346 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8347 ADD_ADJUST_RESTORE(ret, splabel);
8348
8349 if (!popped) {
8350 ADD_INSN(ret, line_node, putnil);
8351 }
8352 }
8353 else {
8354 const rb_iseq_t *ip = iseq;
8355
8356 while (ip) {
8357 if (!ISEQ_COMPILE_DATA(ip)) {
8358 ip = 0;
8359 break;
8360 }
8361
8362 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8363 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8364 }
8365 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8366 throw_flag = 0;
8367 }
8368 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8369 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8370 return COMPILE_NG;
8371 }
8372 else {
8373 ip = ISEQ_BODY(ip)->parent_iseq;
8374 continue;
8375 }
8376
8377 /* escape from block */
8378 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8379 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8380 if (popped) {
8381 ADD_INSN(ret, line_node, pop);
8382 }
8383 return COMPILE_OK;
8384 }
8385 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8386 return COMPILE_NG;
8387 }
8388 return COMPILE_OK;
8389}
8390
8391static int
8392compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8393{
8394 const NODE *line_node = node;
8395 unsigned long throw_flag = 0;
8396
8397 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8398 LABEL *splabel = NEW_LABEL(0);
8399 debugs("next in while loop\n");
8400 ADD_LABEL(ret, splabel);
8401 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8402 add_ensure_iseq(ret, iseq, 0);
8403 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8404 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8405 ADD_ADJUST_RESTORE(ret, splabel);
8406 if (!popped) {
8407 ADD_INSN(ret, line_node, putnil);
8408 }
8409 }
8410 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8411 LABEL *splabel = NEW_LABEL(0);
8412 debugs("next in block\n");
8413 ADD_LABEL(ret, splabel);
8414 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8415 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8416 add_ensure_iseq(ret, iseq, 0);
8417 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8418 ADD_ADJUST_RESTORE(ret, splabel);
8419
8420 if (!popped) {
8421 ADD_INSN(ret, line_node, putnil);
8422 }
8423 }
8424 else {
8425 const rb_iseq_t *ip = iseq;
8426
8427 while (ip) {
8428 if (!ISEQ_COMPILE_DATA(ip)) {
8429 ip = 0;
8430 break;
8431 }
8432
8433 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8434 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8435 /* while loop */
8436 break;
8437 }
8438 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8439 break;
8440 }
8441 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8442 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8443 return COMPILE_NG;
8444 }
8445
8446 ip = ISEQ_BODY(ip)->parent_iseq;
8447 }
8448 if (ip != 0) {
8449 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8450 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8451
8452 if (popped) {
8453 ADD_INSN(ret, line_node, pop);
8454 }
8455 }
8456 else {
8457 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8458 return COMPILE_NG;
8459 }
8460 }
8461 return COMPILE_OK;
8462}
8463
8464static int
8465compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8466{
8467 const NODE *line_node = node;
8468
8469 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8470 LABEL *splabel = NEW_LABEL(0);
8471 debugs("redo in while");
8472 ADD_LABEL(ret, splabel);
8473 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8474 add_ensure_iseq(ret, iseq, 0);
8475 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8476 ADD_ADJUST_RESTORE(ret, splabel);
8477 if (!popped) {
8478 ADD_INSN(ret, line_node, putnil);
8479 }
8480 }
8481 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8482 LABEL *splabel = NEW_LABEL(0);
8483
8484 debugs("redo in block");
8485 ADD_LABEL(ret, splabel);
8486 add_ensure_iseq(ret, iseq, 0);
8487 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8488 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8489 ADD_ADJUST_RESTORE(ret, splabel);
8490
8491 if (!popped) {
8492 ADD_INSN(ret, line_node, putnil);
8493 }
8494 }
8495 else {
8496 const rb_iseq_t *ip = iseq;
8497
8498 while (ip) {
8499 if (!ISEQ_COMPILE_DATA(ip)) {
8500 ip = 0;
8501 break;
8502 }
8503
8504 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8505 break;
8506 }
8507 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8508 break;
8509 }
8510 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8511 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8512 return COMPILE_NG;
8513 }
8514
8515 ip = ISEQ_BODY(ip)->parent_iseq;
8516 }
8517 if (ip != 0) {
8518 ADD_INSN(ret, line_node, putnil);
8519 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8520
8521 if (popped) {
8522 ADD_INSN(ret, line_node, pop);
8523 }
8524 }
8525 else {
8526 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8527 return COMPILE_NG;
8528 }
8529 }
8530 return COMPILE_OK;
8531}
8532
8533static int
8534compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8535{
8536 const NODE *line_node = node;
8537
8538 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8539 ADD_INSN(ret, line_node, putnil);
8540 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8541
8542 if (popped) {
8543 ADD_INSN(ret, line_node, pop);
8544 }
8545 }
8546 else {
8547 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8548 return COMPILE_NG;
8549 }
8550 return COMPILE_OK;
8551}
8552
8553static int
8554compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8555{
8556 const int line = nd_line(node);
8557 const NODE *line_node = node;
8558 LABEL *lstart = NEW_LABEL(line);
8559 LABEL *lend = NEW_LABEL(line);
8560 LABEL *lcont = NEW_LABEL(line);
8561 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8562 rb_str_concat(rb_str_new2("rescue in "),
8563 ISEQ_BODY(iseq)->location.label),
8564 ISEQ_TYPE_RESCUE, line);
8565
8566 lstart->rescued = LABEL_RESCUE_BEG;
8567 lend->rescued = LABEL_RESCUE_END;
8568 ADD_LABEL(ret, lstart);
8569
8570 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8571 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8572 {
8573 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8574 }
8575 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8576
8577 ADD_LABEL(ret, lend);
8578 if (RNODE_RESCUE(node)->nd_else) {
8579 ADD_INSN(ret, line_node, pop);
8580 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8581 }
8582 ADD_INSN(ret, line_node, nop);
8583 ADD_LABEL(ret, lcont);
8584
8585 if (popped) {
8586 ADD_INSN(ret, line_node, pop);
8587 }
8588
8589 /* register catch entry */
8590 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8591 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8592 return COMPILE_OK;
8593}
8594
8595static int
8596compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8597{
8598 const int line = nd_line(node);
8599 const NODE *line_node = node;
8600 const NODE *resq = node;
8601 const NODE *narg;
8602 LABEL *label_miss, *label_hit;
8603
8604 while (resq) {
8605 label_miss = NEW_LABEL(line);
8606 label_hit = NEW_LABEL(line);
8607
8608 narg = RNODE_RESBODY(resq)->nd_args;
8609 if (narg) {
8610 switch (nd_type(narg)) {
8611 case NODE_LIST:
8612 while (narg) {
8613 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8614 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8615 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8616 ADD_INSNL(ret, line_node, branchif, label_hit);
8617 narg = RNODE_LIST(narg)->nd_next;
8618 }
8619 break;
8620 case NODE_SPLAT:
8621 case NODE_ARGSCAT:
8622 case NODE_ARGSPUSH:
8623 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8624 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8625 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8626 ADD_INSNL(ret, line_node, branchif, label_hit);
8627 break;
8628 default:
8629 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8630 }
8631 }
8632 else {
8633 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8634 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8635 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8636 ADD_INSNL(ret, line_node, branchif, label_hit);
8637 }
8638 ADD_INSNL(ret, line_node, jump, label_miss);
8639 ADD_LABEL(ret, label_hit);
8640 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8641
8642 if (RNODE_RESBODY(resq)->nd_exc_var) {
8643 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8644 }
8645
8646 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) {
8647 // empty body
8648 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8649 }
8650 else {
8651 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8652 }
8653
8654 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8655 ADD_INSN(ret, line_node, nop);
8656 }
8657 ADD_INSN(ret, line_node, leave);
8658 ADD_LABEL(ret, label_miss);
8659 resq = RNODE_RESBODY(resq)->nd_next;
8660 }
8661 return COMPILE_OK;
8662}
8663
8664static int
8665compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8666{
8667 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8668 const NODE *line_node = node;
8669 DECL_ANCHOR(ensr);
8670 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8671 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8672 ISEQ_TYPE_ENSURE, line);
8673 LABEL *lstart = NEW_LABEL(line);
8674 LABEL *lend = NEW_LABEL(line);
8675 LABEL *lcont = NEW_LABEL(line);
8676 LINK_ELEMENT *last;
8677 int last_leave = 0;
8678 struct ensure_range er;
8679 struct iseq_compile_data_ensure_node_stack enl;
8680 struct ensure_range *erange;
8681
8682 INIT_ANCHOR(ensr);
8683 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8684 last = ensr->last;
8685 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8686
8687 er.begin = lstart;
8688 er.end = lend;
8689 er.next = 0;
8690 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8691
8692 ADD_LABEL(ret, lstart);
8693 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8694 ADD_LABEL(ret, lend);
8695 ADD_SEQ(ret, ensr);
8696 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8697 ADD_LABEL(ret, lcont);
8698 if (last_leave) ADD_INSN(ret, line_node, pop);
8699
8700 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8701 if (lstart->link.next != &lend->link) {
8702 while (erange) {
8703 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8704 ensure, lcont);
8705 erange = erange->next;
8706 }
8707 }
8708
8709 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8710 return COMPILE_OK;
8711}
8712
8713static int
8714compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8715{
8716 const NODE *line_node = node;
8717
8718 if (iseq) {
8719 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8720 const rb_iseq_t *is = iseq;
8721 enum rb_iseq_type t = type;
8722 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8723 LABEL *splabel = 0;
8724
8725 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8726 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8727 t = ISEQ_BODY(is)->type;
8728 }
8729 switch (t) {
8730 case ISEQ_TYPE_TOP:
8731 case ISEQ_TYPE_MAIN:
8732 if (retval) {
8733 rb_warn("argument of top-level return is ignored");
8734 }
8735 if (is == iseq) {
8736 /* plain top-level, leave directly */
8737 type = ISEQ_TYPE_METHOD;
8738 }
8739 break;
8740 default:
8741 break;
8742 }
8743
8744 if (type == ISEQ_TYPE_METHOD) {
8745 splabel = NEW_LABEL(0);
8746 ADD_LABEL(ret, splabel);
8747 ADD_ADJUST(ret, line_node, 0);
8748 }
8749
8750 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8751
8752 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8753 add_ensure_iseq(ret, iseq, 1);
8754 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8755 ADD_INSN(ret, line_node, leave);
8756 ADD_ADJUST_RESTORE(ret, splabel);
8757
8758 if (!popped) {
8759 ADD_INSN(ret, line_node, putnil);
8760 }
8761 }
8762 else {
8763 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8764 if (popped) {
8765 ADD_INSN(ret, line_node, pop);
8766 }
8767 }
8768 }
8769 return COMPILE_OK;
8770}
8771
8772static bool
8773drop_unreachable_return(LINK_ANCHOR *ret)
8774{
8775 LINK_ELEMENT *i = ret->last, *last;
8776 if (!i) return false;
8777 if (IS_TRACE(i)) i = i->prev;
8778 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8779 last = i = i->prev;
8780 if (IS_ADJUST(i)) i = i->prev;
8781 if (!IS_INSN(i)) return false;
8782 switch (INSN_OF(i)) {
8783 case BIN(leave):
8784 case BIN(jump):
8785 break;
8786 default:
8787 return false;
8788 }
8789 (ret->last = last->prev)->next = NULL;
8790 return true;
8791}
8792
8793static int
8794compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8795{
8796 CHECK(COMPILE_(ret, "nd_body", node, popped));
8797
8798 if (!popped && !all_string_result_p(node)) {
8799 const NODE *line_node = node;
8800 const unsigned int flag = VM_CALL_FCALL;
8801
8802 // Note, this dup could be removed if we are willing to change anytostring. It pops
8803 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8804 ADD_INSN(ret, line_node, dup);
8805 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8806 ADD_INSN(ret, line_node, anytostring);
8807 }
8808 return COMPILE_OK;
8809}
8810
8811static void
8812compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8813{
8814 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8815
8816 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8817 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8818}
8819
8820static LABEL *
8821qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8822{
8823 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8824 VALUE br = 0;
8825
8826 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8827 *branches = br;
8828 ADD_INSN(recv, line_node, dup);
8829 ADD_INSNL(recv, line_node, branchnil, else_label);
8830 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8831 return else_label;
8832}
8833
8834static void
8835qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8836{
8837 LABEL *end_label;
8838 if (!else_label) return;
8839 end_label = NEW_LABEL(nd_line(line_node));
8840 ADD_INSNL(ret, line_node, jump, end_label);
8841 ADD_LABEL(ret, else_label);
8842 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8843 ADD_LABEL(ret, end_label);
8844}
8845
8846static int
8847compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8848{
8849 /* optimization shortcut
8850 * "literal".freeze -> opt_str_freeze("literal")
8851 */
8852 if (get_nd_recv(node) &&
8853 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8854 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8855 get_nd_args(node) == NULL &&
8856 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8857 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8858 VALUE str = get_string_value(get_nd_recv(node));
8859 if (get_node_call_nd_mid(node) == idUMinus) {
8860 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8861 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8862 }
8863 else {
8864 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8865 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8866 }
8867 RB_OBJ_WRITTEN(iseq, Qundef, str);
8868 if (popped) {
8869 ADD_INSN(ret, line_node, pop);
8870 }
8871 return TRUE;
8872 }
8873 /* optimization shortcut
8874 * obj["literal"] -> opt_aref_with(obj, "literal")
8875 */
8876 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8877 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8878 (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)) &&
8879 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8880 !frozen_string_literal_p(iseq) &&
8881 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8882 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8883 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8884 ADD_INSN2(ret, line_node, opt_aref_with, str,
8885 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8886 RB_OBJ_WRITTEN(iseq, Qundef, str);
8887 if (popped) {
8888 ADD_INSN(ret, line_node, pop);
8889 }
8890 return TRUE;
8891 }
8892 return FALSE;
8893}
8894
8895static int
8896iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8897{
8898 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8899}
8900
8901static const struct rb_builtin_function *
8902iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8903{
8904 int i;
8905 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8906 for (i=0; table[i].index != -1; i++) {
8907 if (strcmp(table[i].name, name) == 0) {
8908 return &table[i];
8909 }
8910 }
8911 return NULL;
8912}
8913
8914static const char *
8915iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8916{
8917 const char *name = rb_id2name(mid);
8918 static const char prefix[] = "__builtin_";
8919 const size_t prefix_len = sizeof(prefix) - 1;
8920
8921 switch (type) {
8922 case NODE_CALL:
8923 if (recv) {
8924 switch (nd_type(recv)) {
8925 case NODE_VCALL:
8926 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8927 return name;
8928 }
8929 break;
8930 case NODE_CONST:
8931 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8932 return name;
8933 }
8934 break;
8935 default: break;
8936 }
8937 }
8938 break;
8939 case NODE_VCALL:
8940 case NODE_FCALL:
8941 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8942 return &name[prefix_len];
8943 }
8944 break;
8945 default: break;
8946 }
8947 return NULL;
8948}
8949
8950static int
8951delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8952{
8953
8954 if (argc == 0) {
8955 *pstart_index = 0;
8956 return TRUE;
8957 }
8958 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8959 unsigned int start=0;
8960
8961 // local_table: [p1, p2, p3, l1, l2, l3]
8962 // arguments: [p3, l1, l2] -> 2
8963 for (start = 0;
8964 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8965 start++) {
8966 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8967
8968 for (unsigned int i=start; i-start<argc; i++) {
8969 if (IS_INSN(elem) &&
8970 INSN_OF(elem) == BIN(getlocal)) {
8971 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8972 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8973
8974 if (local_level == 0) {
8975 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8976 if (0) { // for debug
8977 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8978 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8979 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8980 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8981 }
8982 if (i == index) {
8983 elem = elem->next;
8984 continue; /* for */
8985 }
8986 else {
8987 goto next;
8988 }
8989 }
8990 else {
8991 goto fail; // level != 0 is unsupported
8992 }
8993 }
8994 else {
8995 goto fail; // insn is not a getlocal
8996 }
8997 }
8998 goto success;
8999 next:;
9000 }
9001 fail:
9002 return FALSE;
9003 success:
9004 *pstart_index = start;
9005 return TRUE;
9006 }
9007 else {
9008 return FALSE;
9009 }
9010}
9011
9012// Compile Primitive.attr! :leaf, ...
9013static int
9014compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9015{
9016 VALUE symbol;
9017 VALUE string;
9018 if (!node) goto no_arg;
9019 while (node) {
9020 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9021 const NODE *next = RNODE_LIST(node)->nd_next;
9022
9023 node = RNODE_LIST(node)->nd_head;
9024 if (!node) goto no_arg;
9025 switch (nd_type(node)) {
9026 case NODE_SYM:
9027 symbol = rb_node_sym_string_val(node);
9028 break;
9029 default:
9030 goto bad_arg;
9031 }
9032
9033 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9034
9035 string = rb_sym2str(symbol);
9036 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9037 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9038 }
9039 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9040 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9041 }
9042 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9043 iseq_set_use_block(iseq);
9044 }
9045 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9046 // Let the iseq act like a C method in backtraces
9047 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9048 }
9049 else {
9050 goto unknown_arg;
9051 }
9052 node = next;
9053 }
9054 return COMPILE_OK;
9055 no_arg:
9056 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9057 return COMPILE_NG;
9058 non_symbol_arg:
9059 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9060 return COMPILE_NG;
9061 unknown_arg:
9062 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9063 return COMPILE_NG;
9064 bad_arg:
9065 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9066}
9067
9068static int
9069compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9070{
9071 VALUE name;
9072
9073 if (!node) goto no_arg;
9074 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9075 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9076 node = RNODE_LIST(node)->nd_head;
9077 if (!node) goto no_arg;
9078 switch (nd_type(node)) {
9079 case NODE_SYM:
9080 name = rb_node_sym_string_val(node);
9081 break;
9082 default:
9083 goto bad_arg;
9084 }
9085 if (!SYMBOL_P(name)) goto non_symbol_arg;
9086 if (!popped) {
9087 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9088 }
9089 return COMPILE_OK;
9090 no_arg:
9091 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9092 return COMPILE_NG;
9093 too_many_arg:
9094 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9095 return COMPILE_NG;
9096 non_symbol_arg:
9097 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9098 rb_builtin_class_name(name));
9099 return COMPILE_NG;
9100 bad_arg:
9101 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9102}
9103
9104static NODE *
9105mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9106{
9107 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9108 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9109 return RNODE_IF(node)->nd_body;
9110 }
9111 else {
9112 rb_bug("mandatory_node: can't find mandatory node");
9113 }
9114}
9115
9116static int
9117compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9118{
9119 // arguments
9120 struct rb_args_info args = {
9121 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9122 };
9123 rb_node_args_t args_node;
9124 rb_node_init(RNODE(&args_node), NODE_ARGS);
9125 args_node.nd_ainfo = args;
9126
9127 // local table without non-mandatory parameters
9128 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9129 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9130
9131 VALUE idtmp = 0;
9132 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9133 tbl->size = table_size;
9134
9135 int i;
9136
9137 // lead parameters
9138 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9139 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9140 }
9141 // local variables
9142 for (; i<table_size; i++) {
9143 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9144 }
9145
9146 rb_node_scope_t scope_node;
9147 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9148 scope_node.nd_tbl = tbl;
9149 scope_node.nd_body = mandatory_node(iseq, node);
9150 scope_node.nd_args = &args_node;
9151
9152 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9153
9154 ISEQ_BODY(iseq)->mandatory_only_iseq =
9155 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9156 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9157 nd_line(line_node), NULL, 0,
9158 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9159 ISEQ_BODY(iseq)->variable.script_lines);
9160
9161 ALLOCV_END(idtmp);
9162 return COMPILE_OK;
9163}
9164
9165static int
9166compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9167 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9168{
9169 NODE *args_node = get_nd_args(node);
9170
9171 if (parent_block != NULL) {
9172 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9173 return COMPILE_NG;
9174 }
9175 else {
9176# define BUILTIN_INLINE_PREFIX "_bi"
9177 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9178 bool cconst = false;
9179 retry:;
9180 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9181
9182 if (bf == NULL) {
9183 if (strcmp("cstmt!", builtin_func) == 0 ||
9184 strcmp("cexpr!", builtin_func) == 0) {
9185 // ok
9186 }
9187 else if (strcmp("cconst!", builtin_func) == 0) {
9188 cconst = true;
9189 }
9190 else if (strcmp("cinit!", builtin_func) == 0) {
9191 // ignore
9192 return COMPILE_OK;
9193 }
9194 else if (strcmp("attr!", builtin_func) == 0) {
9195 return compile_builtin_attr(iseq, args_node);
9196 }
9197 else if (strcmp("arg!", builtin_func) == 0) {
9198 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9199 }
9200 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9201 if (popped) {
9202 rb_bug("mandatory_only? should be in if condition");
9203 }
9204 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9205 rb_bug("mandatory_only? should be put on top");
9206 }
9207
9208 ADD_INSN1(ret, line_node, putobject, Qfalse);
9209 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9210 }
9211 else if (1) {
9212 rb_bug("can't find builtin function:%s", builtin_func);
9213 }
9214 else {
9215 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9216 return COMPILE_NG;
9217 }
9218
9219 int inline_index = nd_line(node);
9220 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9221 builtin_func = inline_func;
9222 args_node = NULL;
9223 goto retry;
9224 }
9225
9226 if (cconst) {
9227 typedef VALUE(*builtin_func0)(void *, VALUE);
9228 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9229 ADD_INSN1(ret, line_node, putobject, const_val);
9230 return COMPILE_OK;
9231 }
9232
9233 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9234
9235 unsigned int flag = 0;
9236 struct rb_callinfo_kwarg *keywords = NULL;
9237 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9238
9239 if (FIX2INT(argc) != bf->argc) {
9240 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9241 builtin_func, bf->argc, FIX2INT(argc));
9242 return COMPILE_NG;
9243 }
9244
9245 unsigned int start_index;
9246 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9247 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9248 }
9249 else {
9250 ADD_SEQ(ret, args);
9251 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9252 }
9253
9254 if (popped) ADD_INSN(ret, line_node, pop);
9255 return COMPILE_OK;
9256 }
9257}
9258
9259static int
9260compile_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)
9261{
9262 /* call: obj.method(...)
9263 * fcall: func(...)
9264 * vcall: func
9265 */
9266 DECL_ANCHOR(recv);
9267 DECL_ANCHOR(args);
9268 ID mid = get_node_call_nd_mid(node);
9269 VALUE argc;
9270 unsigned int flag = 0;
9271 struct rb_callinfo_kwarg *keywords = NULL;
9272 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9273 LABEL *else_label = NULL;
9274 VALUE branches = Qfalse;
9275
9276 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9277
9278 INIT_ANCHOR(recv);
9279 INIT_ANCHOR(args);
9280#if OPT_SUPPORT_JOKE
9281 if (nd_type_p(node, NODE_VCALL)) {
9282 ID id_bitblt;
9283 ID id_answer;
9284
9285 CONST_ID(id_bitblt, "bitblt");
9286 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9287
9288 if (mid == id_bitblt) {
9289 ADD_INSN(ret, line_node, bitblt);
9290 return COMPILE_OK;
9291 }
9292 else if (mid == id_answer) {
9293 ADD_INSN(ret, line_node, answer);
9294 return COMPILE_OK;
9295 }
9296 }
9297 /* only joke */
9298 {
9299 ID goto_id;
9300 ID label_id;
9301
9302 CONST_ID(goto_id, "__goto__");
9303 CONST_ID(label_id, "__label__");
9304
9305 if (nd_type_p(node, NODE_FCALL) &&
9306 (mid == goto_id || mid == label_id)) {
9307 LABEL *label;
9308 st_data_t data;
9309 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9310 VALUE label_name;
9311
9312 if (!labels_table) {
9313 labels_table = st_init_numtable();
9314 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9315 }
9316 {
9317 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9318 return COMPILE_NG;
9319 }
9320
9321 if (mid == goto_id) {
9322 ADD_INSNL(ret, line_node, jump, label);
9323 }
9324 else {
9325 ADD_LABEL(ret, label);
9326 }
9327 return COMPILE_OK;
9328 }
9329 }
9330#endif
9331
9332 const char *builtin_func;
9333 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9334 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9335 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9336 }
9337
9338 /* receiver */
9339 if (!assume_receiver) {
9340 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9341 int idx, level;
9342
9343 if (mid == idCall &&
9344 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9345 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9346 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9347 }
9348 else if (private_recv_p(node)) {
9349 ADD_INSN(recv, node, putself);
9350 flag |= VM_CALL_FCALL;
9351 }
9352 else {
9353 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9354 }
9355
9356 if (type == NODE_QCALL) {
9357 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9358 }
9359 }
9360 else if (type == NODE_FCALL || type == NODE_VCALL) {
9361 ADD_CALL_RECEIVER(recv, line_node);
9362 }
9363 }
9364
9365 /* args */
9366 if (type != NODE_VCALL) {
9367 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9368 CHECK(!NIL_P(argc));
9369 }
9370 else {
9371 argc = INT2FIX(0);
9372 }
9373
9374 ADD_SEQ(ret, recv);
9375 ADD_SEQ(ret, args);
9376
9377 debugp_param("call args argc", argc);
9378 debugp_param("call method", ID2SYM(mid));
9379
9380 switch ((int)type) {
9381 case NODE_VCALL:
9382 flag |= VM_CALL_VCALL;
9383 /* VCALL is funcall, so fall through */
9384 case NODE_FCALL:
9385 flag |= VM_CALL_FCALL;
9386 }
9387
9388 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9389 ADD_INSN(ret, line_node, splatkw);
9390 }
9391 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9392
9393 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9394 if (popped) {
9395 ADD_INSN(ret, line_node, pop);
9396 }
9397 return COMPILE_OK;
9398}
9399
9400static int
9401compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9402{
9403 const int line = nd_line(node);
9404 VALUE argc;
9405 unsigned int flag = 0;
9406 int asgnflag = 0;
9407 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9408
9409 /*
9410 * a[x] (op)= y
9411 *
9412 * nil # nil
9413 * eval a # nil a
9414 * eval x # nil a x
9415 * dupn 2 # nil a x a x
9416 * send :[] # nil a x a[x]
9417 * eval y # nil a x a[x] y
9418 * send op # nil a x ret
9419 * setn 3 # ret a x ret
9420 * send []= # ret ?
9421 * pop # ret
9422 */
9423
9424 /*
9425 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9426 * NODE_OP_ASGN nd_recv
9427 * nd_args->nd_head
9428 * nd_args->nd_body
9429 * nd_mid
9430 */
9431
9432 if (!popped) {
9433 ADD_INSN(ret, node, putnil);
9434 }
9435 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9436 CHECK(asgnflag != -1);
9437 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9438 case NODE_ZLIST:
9439 argc = INT2FIX(0);
9440 break;
9441 default:
9442 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9443 CHECK(!NIL_P(argc));
9444 }
9445 int dup_argn = FIX2INT(argc) + 1;
9446 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9447 flag |= asgnflag;
9448 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9449
9450 if (id == idOROP || id == idANDOP) {
9451 /* a[x] ||= y or a[x] &&= y
9452
9453 unless/if a[x]
9454 a[x]= y
9455 else
9456 nil
9457 end
9458 */
9459 LABEL *label = NEW_LABEL(line);
9460 LABEL *lfin = NEW_LABEL(line);
9461
9462 ADD_INSN(ret, node, dup);
9463 if (id == idOROP) {
9464 ADD_INSNL(ret, node, branchif, label);
9465 }
9466 else { /* idANDOP */
9467 ADD_INSNL(ret, node, branchunless, label);
9468 }
9469 ADD_INSN(ret, node, pop);
9470
9471 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9472 if (!popped) {
9473 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9474 }
9475 if (flag & VM_CALL_ARGS_SPLAT) {
9476 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9477 ADD_INSN(ret, node, swap);
9478 ADD_INSN1(ret, node, splatarray, Qtrue);
9479 ADD_INSN(ret, node, swap);
9480 flag |= VM_CALL_ARGS_SPLAT_MUT;
9481 }
9482 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9483 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9484 }
9485 else {
9486 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9487 }
9488 ADD_INSN(ret, node, pop);
9489 ADD_INSNL(ret, node, jump, lfin);
9490 ADD_LABEL(ret, label);
9491 if (!popped) {
9492 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9493 }
9494 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9495 ADD_LABEL(ret, lfin);
9496 }
9497 else {
9498 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9499 ADD_SEND(ret, node, id, INT2FIX(1));
9500 if (!popped) {
9501 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9502 }
9503 if (flag & VM_CALL_ARGS_SPLAT) {
9504 if (flag & VM_CALL_KW_SPLAT) {
9505 ADD_INSN1(ret, node, topn, INT2FIX(2));
9506 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9507 ADD_INSN1(ret, node, splatarray, Qtrue);
9508 flag |= VM_CALL_ARGS_SPLAT_MUT;
9509 }
9510 ADD_INSN(ret, node, swap);
9511 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9512 ADD_INSN1(ret, node, setn, INT2FIX(2));
9513 ADD_INSN(ret, node, pop);
9514 }
9515 else {
9516 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9517 ADD_INSN(ret, node, swap);
9518 ADD_INSN1(ret, node, splatarray, Qtrue);
9519 ADD_INSN(ret, node, swap);
9520 flag |= VM_CALL_ARGS_SPLAT_MUT;
9521 }
9522 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9523 }
9524 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9525 }
9526 else {
9527 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9528 }
9529 ADD_INSN(ret, node, pop);
9530 }
9531 return COMPILE_OK;
9532}
9533
9534static int
9535compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9536{
9537 const int line = nd_line(node);
9538 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9539 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9540 int asgnflag;
9541 LABEL *lfin = NEW_LABEL(line);
9542 LABEL *lcfin = NEW_LABEL(line);
9543 LABEL *lskip = 0;
9544 /*
9545 class C; attr_accessor :c; end
9546 r = C.new
9547 r.a &&= v # asgn2
9548
9549 eval r # r
9550 dup # r r
9551 eval r.a # r o
9552
9553 # or
9554 dup # r o o
9555 if lcfin # r o
9556 pop # r
9557 eval v # r v
9558 swap # v r
9559 topn 1 # v r v
9560 send a= # v ?
9561 jump lfin # v ?
9562
9563 lcfin: # r o
9564 swap # o r
9565
9566 lfin: # o ?
9567 pop # o
9568
9569 # or (popped)
9570 if lcfin # r
9571 eval v # r v
9572 send a= # ?
9573 jump lfin # ?
9574
9575 lcfin: # r
9576
9577 lfin: # ?
9578 pop #
9579
9580 # and
9581 dup # r o o
9582 unless lcfin
9583 pop # r
9584 eval v # r v
9585 swap # v r
9586 topn 1 # v r v
9587 send a= # v ?
9588 jump lfin # v ?
9589
9590 # others
9591 eval v # r o v
9592 send ?? # r w
9593 send a= # w
9594
9595 */
9596
9597 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9598 CHECK(asgnflag != -1);
9599 if (RNODE_OP_ASGN2(node)->nd_aid) {
9600 lskip = NEW_LABEL(line);
9601 ADD_INSN(ret, node, dup);
9602 ADD_INSNL(ret, node, branchnil, lskip);
9603 }
9604 ADD_INSN(ret, node, dup);
9605 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9606
9607 if (atype == idOROP || atype == idANDOP) {
9608 if (!popped) {
9609 ADD_INSN(ret, node, dup);
9610 }
9611 if (atype == idOROP) {
9612 ADD_INSNL(ret, node, branchif, lcfin);
9613 }
9614 else { /* idANDOP */
9615 ADD_INSNL(ret, node, branchunless, lcfin);
9616 }
9617 if (!popped) {
9618 ADD_INSN(ret, node, pop);
9619 }
9620 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9621 if (!popped) {
9622 ADD_INSN(ret, node, swap);
9623 ADD_INSN1(ret, node, topn, INT2FIX(1));
9624 }
9625 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9626 ADD_INSNL(ret, node, jump, lfin);
9627
9628 ADD_LABEL(ret, lcfin);
9629 if (!popped) {
9630 ADD_INSN(ret, node, swap);
9631 }
9632
9633 ADD_LABEL(ret, lfin);
9634 }
9635 else {
9636 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9637 ADD_SEND(ret, node, atype, INT2FIX(1));
9638 if (!popped) {
9639 ADD_INSN(ret, node, swap);
9640 ADD_INSN1(ret, node, topn, INT2FIX(1));
9641 }
9642 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9643 }
9644 if (lskip && popped) {
9645 ADD_LABEL(ret, lskip);
9646 }
9647 ADD_INSN(ret, node, pop);
9648 if (lskip && !popped) {
9649 ADD_LABEL(ret, lskip);
9650 }
9651 return COMPILE_OK;
9652}
9653
9654static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9655
9656static int
9657compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9658{
9659 const int line = nd_line(node);
9660 LABEL *lfin = 0;
9661 LABEL *lassign = 0;
9662 ID mid;
9663
9664 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9665 case NODE_COLON3:
9666 ADD_INSN1(ret, node, putobject, rb_cObject);
9667 break;
9668 case NODE_COLON2:
9669 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9670 break;
9671 default:
9672 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9673 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9674 return COMPILE_NG;
9675 }
9676 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9677 /* cref */
9678 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9679 lassign = NEW_LABEL(line);
9680 ADD_INSN(ret, node, dup); /* cref cref */
9681 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9682 ID2SYM(mid), Qtrue); /* cref bool */
9683 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9684 }
9685 ADD_INSN(ret, node, dup); /* cref cref */
9686 ADD_INSN1(ret, node, putobject, Qtrue);
9687 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9688
9689 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9690 lfin = NEW_LABEL(line);
9691 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9692 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9693 ADD_INSNL(ret, node, branchif, lfin);
9694 else /* idANDOP */
9695 ADD_INSNL(ret, node, branchunless, lfin);
9696 /* cref [obj] */
9697 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9698 if (lassign) ADD_LABEL(ret, lassign);
9699 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9700 /* cref value */
9701 if (popped)
9702 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9703 else {
9704 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9705 ADD_INSN(ret, node, swap); /* cref value value cref */
9706 }
9707 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9708 ADD_LABEL(ret, lfin); /* cref [value] */
9709 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9710 ADD_INSN(ret, node, pop); /* [value] */
9711 }
9712 else {
9713 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9714 /* cref obj value */
9715 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9716 /* cref value */
9717 ADD_INSN(ret, node, swap); /* value cref */
9718 if (!popped) {
9719 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9720 ADD_INSN(ret, node, swap); /* value value cref */
9721 }
9722 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9723 }
9724 return COMPILE_OK;
9725}
9726
9727static int
9728compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9729{
9730 const int line = nd_line(node);
9731 LABEL *lfin = NEW_LABEL(line);
9732 LABEL *lassign;
9733
9734 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9735 LABEL *lfinish[2];
9736 lfinish[0] = lfin;
9737 lfinish[1] = 0;
9738 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9739 lassign = lfinish[1];
9740 if (!lassign) {
9741 lassign = NEW_LABEL(line);
9742 }
9743 ADD_INSNL(ret, node, branchunless, lassign);
9744 }
9745 else {
9746 lassign = NEW_LABEL(line);
9747 }
9748
9749 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9750
9751 if (!popped) {
9752 ADD_INSN(ret, node, dup);
9753 }
9754
9755 if (type == NODE_OP_ASGN_AND) {
9756 ADD_INSNL(ret, node, branchunless, lfin);
9757 }
9758 else {
9759 ADD_INSNL(ret, node, branchif, lfin);
9760 }
9761
9762 if (!popped) {
9763 ADD_INSN(ret, node, pop);
9764 }
9765
9766 ADD_LABEL(ret, lassign);
9767 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9768 ADD_LABEL(ret, lfin);
9769 return COMPILE_OK;
9770}
9771
9772static int
9773compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9774{
9775 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9776 DECL_ANCHOR(args);
9777 int argc;
9778 unsigned int flag = 0;
9779 struct rb_callinfo_kwarg *keywords = NULL;
9780 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9781 int use_block = 1;
9782
9783 INIT_ANCHOR(args);
9784 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9785
9786 if (type == NODE_SUPER) {
9787 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9788 CHECK(!NIL_P(vargc));
9789 argc = FIX2INT(vargc);
9790 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9791 ADD_INSN(args, node, splatkw);
9792 }
9793
9794 if (flag & VM_CALL_ARGS_BLOCKARG) {
9795 use_block = 0;
9796 }
9797 }
9798 else {
9799 /* NODE_ZSUPER */
9800 int i;
9801 const rb_iseq_t *liseq = body->local_iseq;
9802 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9803 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9804 int lvar_level = get_lvar_level(iseq);
9805
9806 argc = local_body->param.lead_num;
9807
9808 /* normal arguments */
9809 for (i = 0; i < local_body->param.lead_num; i++) {
9810 int idx = local_body->local_table_size - i;
9811 ADD_GETLOCAL(args, node, idx, lvar_level);
9812 }
9813
9814 /* forward ... */
9815 if (local_body->param.flags.forwardable) {
9816 flag |= VM_CALL_FORWARDING;
9817 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9818 ADD_GETLOCAL(args, node, idx, lvar_level);
9819 }
9820
9821 if (local_body->param.flags.has_opt) {
9822 /* optional arguments */
9823 int j;
9824 for (j = 0; j < local_body->param.opt_num; j++) {
9825 int idx = local_body->local_table_size - (i + j);
9826 ADD_GETLOCAL(args, node, idx, lvar_level);
9827 }
9828 i += j;
9829 argc = i;
9830 }
9831 if (local_body->param.flags.has_rest) {
9832 /* rest argument */
9833 int idx = local_body->local_table_size - local_body->param.rest_start;
9834 ADD_GETLOCAL(args, node, idx, lvar_level);
9835 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9836
9837 argc = local_body->param.rest_start + 1;
9838 flag |= VM_CALL_ARGS_SPLAT;
9839 }
9840 if (local_body->param.flags.has_post) {
9841 /* post arguments */
9842 int post_len = local_body->param.post_num;
9843 int post_start = local_body->param.post_start;
9844
9845 if (local_body->param.flags.has_rest) {
9846 int j;
9847 for (j=0; j<post_len; j++) {
9848 int idx = local_body->local_table_size - (post_start + j);
9849 ADD_GETLOCAL(args, node, idx, lvar_level);
9850 }
9851 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9852 flag |= VM_CALL_ARGS_SPLAT_MUT;
9853 /* argc is settled at above */
9854 }
9855 else {
9856 int j;
9857 for (j=0; j<post_len; j++) {
9858 int idx = local_body->local_table_size - (post_start + j);
9859 ADD_GETLOCAL(args, node, idx, lvar_level);
9860 }
9861 argc = post_len + post_start;
9862 }
9863 }
9864
9865 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9866 int local_size = local_body->local_table_size;
9867 argc++;
9868
9869 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9870
9871 if (local_body->param.flags.has_kwrest) {
9872 int idx = local_body->local_table_size - local_kwd->rest_start;
9873 ADD_GETLOCAL(args, node, idx, lvar_level);
9874 RUBY_ASSERT(local_kwd->num > 0);
9875 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9876 }
9877 else {
9878 ADD_INSN1(args, node, newhash, INT2FIX(0));
9879 }
9880 for (i = 0; i < local_kwd->num; ++i) {
9881 ID id = local_kwd->table[i];
9882 int idx = local_size - get_local_var_idx(liseq, id);
9883 ADD_INSN1(args, node, putobject, ID2SYM(id));
9884 ADD_GETLOCAL(args, node, idx, lvar_level);
9885 }
9886 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9887 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9888 }
9889 else if (local_body->param.flags.has_kwrest) {
9890 int idx = local_body->local_table_size - local_kwd->rest_start;
9891 ADD_GETLOCAL(args, node, idx, lvar_level);
9892 argc++;
9893 flag |= VM_CALL_KW_SPLAT;
9894 }
9895 }
9896
9897 if (use_block && parent_block == NULL) {
9898 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9899 }
9900
9901 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9902 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9903 ADD_INSN(ret, node, putself);
9904 ADD_SEQ(ret, args);
9905
9906 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
9907
9908 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
9909 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
9910 }
9911 else {
9912 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
9913 }
9914
9915 if (popped) {
9916 ADD_INSN(ret, node, pop);
9917 }
9918 return COMPILE_OK;
9919}
9920
9921static int
9922compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9923{
9924 DECL_ANCHOR(args);
9925 VALUE argc;
9926 unsigned int flag = 0;
9927 struct rb_callinfo_kwarg *keywords = NULL;
9928
9929 INIT_ANCHOR(args);
9930
9931 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9932 case ISEQ_TYPE_TOP:
9933 case ISEQ_TYPE_MAIN:
9934 case ISEQ_TYPE_CLASS:
9935 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9936 return COMPILE_NG;
9937 default: /* valid */;
9938 }
9939
9940 if (RNODE_YIELD(node)->nd_head) {
9941 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9942 CHECK(!NIL_P(argc));
9943 }
9944 else {
9945 argc = INT2FIX(0);
9946 }
9947
9948 ADD_SEQ(ret, args);
9949 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9950 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9951
9952 if (popped) {
9953 ADD_INSN(ret, node, pop);
9954 }
9955
9956 int level = 0;
9957 const rb_iseq_t *tmp_iseq = iseq;
9958 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9959 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9960 }
9961 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9962
9963 return COMPILE_OK;
9964}
9965
9966static int
9967compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9968{
9969 DECL_ANCHOR(recv);
9970 DECL_ANCHOR(val);
9971
9972 INIT_ANCHOR(recv);
9973 INIT_ANCHOR(val);
9974 switch ((int)type) {
9975 case NODE_MATCH:
9976 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
9977 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9978 INT2FIX(0));
9979 break;
9980 case NODE_MATCH2:
9981 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
9982 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
9983 break;
9984 case NODE_MATCH3:
9985 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
9986 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
9987 break;
9988 }
9989
9990 ADD_SEQ(ret, recv);
9991 ADD_SEQ(ret, val);
9992 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9993
9994 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
9995 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
9996 }
9997
9998 if (popped) {
9999 ADD_INSN(ret, node, pop);
10000 }
10001 return COMPILE_OK;
10002}
10003
10004static int
10005compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10006{
10007 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10008 /* constant */
10009 VALUE segments;
10010 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10011 (segments = collect_const_segments(iseq, node))) {
10012 ISEQ_BODY(iseq)->ic_size++;
10013 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10014 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10015 }
10016 else {
10017 /* constant */
10018 DECL_ANCHOR(pref);
10019 DECL_ANCHOR(body);
10020
10021 INIT_ANCHOR(pref);
10022 INIT_ANCHOR(body);
10023 CHECK(compile_const_prefix(iseq, node, pref, body));
10024 if (LIST_INSN_SIZE_ZERO(pref)) {
10025 ADD_INSN(ret, node, putnil);
10026 ADD_SEQ(ret, body);
10027 }
10028 else {
10029 ADD_SEQ(ret, pref);
10030 ADD_SEQ(ret, body);
10031 }
10032 }
10033 }
10034 else {
10035 /* function call */
10036 ADD_CALL_RECEIVER(ret, node);
10037 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10038 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10039 }
10040 if (popped) {
10041 ADD_INSN(ret, node, pop);
10042 }
10043 return COMPILE_OK;
10044}
10045
10046static int
10047compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10048{
10049 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10050
10051 /* add cache insn */
10052 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10053 ISEQ_BODY(iseq)->ic_size++;
10054 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10055 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10056 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10057 }
10058 else {
10059 ADD_INSN1(ret, node, putobject, rb_cObject);
10060 ADD_INSN1(ret, node, putobject, Qtrue);
10061 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10062 }
10063
10064 if (popped) {
10065 ADD_INSN(ret, node, pop);
10066 }
10067 return COMPILE_OK;
10068}
10069
10070static int
10071compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10072{
10073 VALUE flag = INT2FIX(excl);
10074 const NODE *b = RNODE_DOT2(node)->nd_beg;
10075 const NODE *e = RNODE_DOT2(node)->nd_end;
10076
10077 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10078 if (!popped) {
10079 VALUE bv = optimized_range_item(b);
10080 VALUE ev = optimized_range_item(e);
10081 VALUE val = rb_range_new(bv, ev, excl);
10082 ADD_INSN1(ret, node, putobject, val);
10083 RB_OBJ_WRITTEN(iseq, Qundef, val);
10084 }
10085 }
10086 else {
10087 CHECK(COMPILE_(ret, "min", b, popped));
10088 CHECK(COMPILE_(ret, "max", e, popped));
10089 if (!popped) {
10090 ADD_INSN1(ret, node, newrange, flag);
10091 }
10092 }
10093 return COMPILE_OK;
10094}
10095
10096static int
10097compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10098{
10099 if (!popped) {
10100 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10101 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10102 }
10103 else {
10104 const rb_iseq_t *ip = iseq;
10105 int level = 0;
10106 while (ip) {
10107 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10108 break;
10109 }
10110 ip = ISEQ_BODY(ip)->parent_iseq;
10111 level++;
10112 }
10113 if (ip) {
10114 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10115 }
10116 else {
10117 ADD_INSN(ret, node, putnil);
10118 }
10119 }
10120 }
10121 return COMPILE_OK;
10122}
10123
10124static int
10125compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10126{
10127 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10128 LABEL *end_label = NEW_LABEL(nd_line(node));
10129 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10130
10131 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10132 /* required argument. do nothing */
10133 COMPILE_ERROR(ERROR_ARGS "unreachable");
10134 return COMPILE_NG;
10135 }
10136 else if (nd_type_p(default_value, NODE_SYM) ||
10137 nd_type_p(default_value, NODE_REGX) ||
10138 nd_type_p(default_value, NODE_LINE) ||
10139 nd_type_p(default_value, NODE_INTEGER) ||
10140 nd_type_p(default_value, NODE_FLOAT) ||
10141 nd_type_p(default_value, NODE_RATIONAL) ||
10142 nd_type_p(default_value, NODE_IMAGINARY) ||
10143 nd_type_p(default_value, NODE_NIL) ||
10144 nd_type_p(default_value, NODE_TRUE) ||
10145 nd_type_p(default_value, NODE_FALSE)) {
10146 COMPILE_ERROR(ERROR_ARGS "unreachable");
10147 return COMPILE_NG;
10148 }
10149 else {
10150 /* if keywordcheck(_kw_bits, nth_keyword)
10151 * kw = default_value
10152 * end
10153 */
10154 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10155 int keyword_idx = body->param.keyword->num;
10156
10157 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10158 ADD_INSNL(ret, node, branchif, end_label);
10159 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10160 ADD_LABEL(ret, end_label);
10161 }
10162 return COMPILE_OK;
10163}
10164
10165static int
10166compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10167{
10168 DECL_ANCHOR(recv);
10169 DECL_ANCHOR(args);
10170 unsigned int flag = 0;
10171 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10172 VALUE argc;
10173 LABEL *else_label = NULL;
10174 VALUE branches = Qfalse;
10175
10176 /* optimization shortcut
10177 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10178 */
10179 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10180 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10181 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10182 (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)) &&
10183 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10184 !frozen_string_literal_p(iseq) &&
10185 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10186 {
10187 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10188 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10189 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10190 if (!popped) {
10191 ADD_INSN(ret, node, swap);
10192 ADD_INSN1(ret, node, topn, INT2FIX(1));
10193 }
10194 ADD_INSN2(ret, node, opt_aset_with, str,
10195 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10196 RB_OBJ_WRITTEN(iseq, Qundef, str);
10197 ADD_INSN(ret, node, pop);
10198 return COMPILE_OK;
10199 }
10200
10201 INIT_ANCHOR(recv);
10202 INIT_ANCHOR(args);
10203 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10204 CHECK(!NIL_P(argc));
10205
10206 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10207 CHECK(asgnflag != -1);
10208 flag |= (unsigned int)asgnflag;
10209
10210 debugp_param("argc", argc);
10211 debugp_param("nd_mid", ID2SYM(mid));
10212
10213 if (!rb_is_attrset_id(mid)) {
10214 /* safe nav attr */
10215 mid = rb_id_attrset(mid);
10216 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10217 }
10218 if (!popped) {
10219 ADD_INSN(ret, node, putnil);
10220 ADD_SEQ(ret, recv);
10221 ADD_SEQ(ret, args);
10222
10223 if (flag & VM_CALL_ARGS_SPLAT) {
10224 ADD_INSN(ret, node, dup);
10225 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10226 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10227 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10228 ADD_INSN (ret, node, pop);
10229 }
10230 else {
10231 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10232 }
10233 }
10234 else {
10235 ADD_SEQ(ret, recv);
10236 ADD_SEQ(ret, args);
10237 }
10238 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10239 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10240 ADD_INSN(ret, node, pop);
10241 return COMPILE_OK;
10242}
10243
10244static int
10245compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10246{
10247 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10248 ADD_SEQ(ret, sub);
10249
10250 if (copy) {
10251 /*
10252 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10253 * NEW_LIST(value, loc), loc);
10254 */
10255 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10256 }
10257 else {
10258 /*
10259 * NEW_CALL(fcore, rb_intern("make_shareable"),
10260 * NEW_LIST(value, loc), loc);
10261 */
10262 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10263 }
10264
10265 return COMPILE_OK;
10266}
10267
10268static VALUE
10269node_const_decl_val(const NODE *node)
10270{
10271 VALUE path;
10272 switch (nd_type(node)) {
10273 case NODE_CDECL:
10274 if (RNODE_CDECL(node)->nd_vid) {
10275 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10276 goto end;
10277 }
10278 else {
10279 node = RNODE_CDECL(node)->nd_else;
10280 }
10281 break;
10282 case NODE_COLON2:
10283 break;
10284 case NODE_COLON3:
10285 // ::Const
10286 path = rb_str_new_cstr("::");
10287 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10288 goto end;
10289 default:
10290 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10291 UNREACHABLE_RETURN(0);
10292 }
10293
10294 path = rb_ary_new();
10295 if (node) {
10296 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10297 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10298 }
10299 if (node && nd_type_p(node, NODE_CONST)) {
10300 // Const::Name
10301 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10302 }
10303 else if (node && nd_type_p(node, NODE_COLON3)) {
10304 // ::Const::Name
10305 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10306 rb_ary_push(path, rb_str_new(0, 0));
10307 }
10308 else {
10309 // expression::Name
10310 rb_ary_push(path, rb_str_new_cstr("..."));
10311 }
10312 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10313 }
10314 end:
10315 path = rb_fstring(path);
10316 return path;
10317}
10318
10319static VALUE
10320const_decl_path(NODE *dest)
10321{
10322 VALUE path = Qnil;
10323 if (!nd_type_p(dest, NODE_CALL)) {
10324 path = node_const_decl_val(dest);
10325 }
10326 return path;
10327}
10328
10329static int
10330compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10331{
10332 /*
10333 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10334 */
10335 VALUE path = const_decl_path(dest);
10336 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10337 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10338 ADD_INSN1(ret, value, putobject, path);
10339 RB_OBJ_WRITTEN(iseq, Qundef, path);
10340 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10341
10342 return COMPILE_OK;
10343}
10344
10345#ifndef SHAREABLE_BARE_EXPRESSION
10346#define SHAREABLE_BARE_EXPRESSION 1
10347#endif
10348
10349static int
10350compile_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)
10351{
10352# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10353 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10354 VALUE lit = Qnil;
10355 DECL_ANCHOR(anchor);
10356
10357 enum node_type type = nd_type(node);
10358 switch (type) {
10359 case NODE_TRUE:
10360 *value_p = Qtrue;
10361 goto compile;
10362 case NODE_FALSE:
10363 *value_p = Qfalse;
10364 goto compile;
10365 case NODE_NIL:
10366 *value_p = Qnil;
10367 goto compile;
10368 case NODE_SYM:
10369 *value_p = rb_node_sym_string_val(node);
10370 goto compile;
10371 case NODE_REGX:
10372 *value_p = rb_node_regx_string_val(node);
10373 goto compile;
10374 case NODE_LINE:
10375 *value_p = rb_node_line_lineno_val(node);
10376 goto compile;
10377 case NODE_INTEGER:
10378 *value_p = rb_node_integer_literal_val(node);
10379 goto compile;
10380 case NODE_FLOAT:
10381 *value_p = rb_node_float_literal_val(node);
10382 goto compile;
10383 case NODE_RATIONAL:
10384 *value_p = rb_node_rational_literal_val(node);
10385 goto compile;
10386 case NODE_IMAGINARY:
10387 *value_p = rb_node_imaginary_literal_val(node);
10388 goto compile;
10389 case NODE_ENCODING:
10390 *value_p = rb_node_encoding_val(node);
10391
10392 compile:
10393 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10394 *shareable_literal_p = 1;
10395 return COMPILE_OK;
10396
10397 case NODE_DSTR:
10398 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10399 if (shareable == rb_parser_shareable_literal) {
10400 /*
10401 * NEW_CALL(node, idUMinus, 0, loc);
10402 *
10403 * -"#{var}"
10404 */
10405 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10406 }
10407 *value_p = Qundef;
10408 *shareable_literal_p = 1;
10409 return COMPILE_OK;
10410
10411 case NODE_STR:{
10412 VALUE lit = rb_node_str_string_val(node);
10413 ADD_INSN1(ret, node, putobject, lit);
10414 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10415 *value_p = lit;
10416 *shareable_literal_p = 1;
10417
10418 return COMPILE_OK;
10419 }
10420
10421 case NODE_FILE:{
10422 VALUE lit = rb_node_file_path_val(node);
10423 ADD_INSN1(ret, node, putobject, lit);
10424 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10425 *value_p = lit;
10426 *shareable_literal_p = 1;
10427
10428 return COMPILE_OK;
10429 }
10430
10431 case NODE_ZLIST:{
10432 VALUE lit = rb_ary_new();
10433 OBJ_FREEZE(lit);
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_LIST:{
10443 INIT_ANCHOR(anchor);
10444 lit = rb_ary_new();
10445 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10446 VALUE val;
10447 int shareable_literal_p2;
10448 NODE *elt = RNODE_LIST(n)->nd_head;
10449 if (elt) {
10450 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10451 if (shareable_literal_p2) {
10452 /* noop */
10453 }
10454 else if (RTEST(lit)) {
10455 rb_ary_clear(lit);
10456 lit = Qfalse;
10457 }
10458 }
10459 if (RTEST(lit)) {
10460 if (!UNDEF_P(val)) {
10461 rb_ary_push(lit, val);
10462 }
10463 else {
10464 rb_ary_clear(lit);
10465 lit = Qnil; /* make shareable at runtime */
10466 }
10467 }
10468 }
10469 break;
10470 }
10471 case NODE_HASH:{
10472 if (!RNODE_HASH(node)->nd_brace) {
10473 *value_p = Qundef;
10474 *shareable_literal_p = 0;
10475 return COMPILE_OK;
10476 }
10477 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10478 if (!RNODE_LIST(n)->nd_head) {
10479 // If the hash node have a keyword splat, fall back to the default case.
10480 goto compile_shareable;
10481 }
10482 }
10483
10484 INIT_ANCHOR(anchor);
10485 lit = rb_hash_new();
10486 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10487 VALUE key_val = 0;
10488 VALUE value_val = 0;
10489 int shareable_literal_p2;
10490 NODE *key = RNODE_LIST(n)->nd_head;
10491 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10492 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10493 if (shareable_literal_p2) {
10494 /* noop */
10495 }
10496 else if (RTEST(lit)) {
10497 rb_hash_clear(lit);
10498 lit = Qfalse;
10499 }
10500 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10501 if (shareable_literal_p2) {
10502 /* noop */
10503 }
10504 else if (RTEST(lit)) {
10505 rb_hash_clear(lit);
10506 lit = Qfalse;
10507 }
10508 if (RTEST(lit)) {
10509 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10510 rb_hash_aset(lit, key_val, value_val);
10511 }
10512 else {
10513 rb_hash_clear(lit);
10514 lit = Qnil; /* make shareable at runtime */
10515 }
10516 }
10517 }
10518 break;
10519 }
10520
10521 default:
10522
10523 compile_shareable:
10524 if (shareable == rb_parser_shareable_literal &&
10525 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10526 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10527 *value_p = Qundef;
10528 *shareable_literal_p = 1;
10529 return COMPILE_OK;
10530 }
10531 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10532 *value_p = Qundef;
10533 *shareable_literal_p = 0;
10534 return COMPILE_OK;
10535 }
10536
10537 /* Array or Hash that does not have keyword splat */
10538 if (!lit) {
10539 if (nd_type(node) == NODE_LIST) {
10540 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10541 }
10542 else if (nd_type(node) == NODE_HASH) {
10543 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10544 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10545 }
10546 *value_p = Qundef;
10547 *shareable_literal_p = 0;
10548 ADD_SEQ(ret, anchor);
10549 return COMPILE_OK;
10550 }
10551 if (NIL_P(lit)) {
10552 // if shareable_literal, all elements should have been ensured
10553 // as shareable
10554 if (nd_type(node) == NODE_LIST) {
10555 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10556 }
10557 else if (nd_type(node) == NODE_HASH) {
10558 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10559 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10560 }
10561 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10562 *value_p = Qundef;
10563 *shareable_literal_p = 1;
10564 }
10565 else {
10566 VALUE val = rb_ractor_make_shareable(lit);
10567 ADD_INSN1(ret, node, putobject, val);
10568 RB_OBJ_WRITTEN(iseq, Qundef, val);
10569 *value_p = val;
10570 *shareable_literal_p = 1;
10571 }
10572
10573 return COMPILE_OK;
10574}
10575
10576static int
10577compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10578{
10579 int literal_p = 0;
10580 VALUE val;
10581 DECL_ANCHOR(anchor);
10582 INIT_ANCHOR(anchor);
10583
10584 switch (shareable) {
10585 case rb_parser_shareable_none:
10586 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10587 return COMPILE_OK;
10588
10589 case rb_parser_shareable_literal:
10590 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10591 ADD_SEQ(ret, anchor);
10592 return COMPILE_OK;
10593
10594 case rb_parser_shareable_copy:
10595 case rb_parser_shareable_everything:
10596 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10597 if (!literal_p) {
10598 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10599 }
10600 else {
10601 ADD_SEQ(ret, anchor);
10602 }
10603 return COMPILE_OK;
10604 default:
10605 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10606 }
10607}
10608
10609static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10617static int
10618iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10619{
10620 if (node == 0) {
10621 if (!popped) {
10622 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10623 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10624 debugs("node: NODE_NIL(implicit)\n");
10625 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10626 }
10627 return COMPILE_OK;
10628 }
10629 return iseq_compile_each0(iseq, ret, node, popped);
10630}
10631
10632static int
10633iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10634{
10635 const int line = (int)nd_line(node);
10636 const enum node_type type = nd_type(node);
10637 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10638
10639 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10640 /* ignore */
10641 }
10642 else {
10643 if (nd_fl_newline(node)) {
10644 int event = RUBY_EVENT_LINE;
10645 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10646 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10647 event |= RUBY_EVENT_COVERAGE_LINE;
10648 }
10649 ADD_TRACE(ret, event);
10650 }
10651 }
10652
10653 debug_node_start(node);
10654#undef BEFORE_RETURN
10655#define BEFORE_RETURN debug_node_end()
10656
10657 switch (type) {
10658 case NODE_BLOCK:
10659 CHECK(compile_block(iseq, ret, node, popped));
10660 break;
10661 case NODE_IF:
10662 case NODE_UNLESS:
10663 CHECK(compile_if(iseq, ret, node, popped, type));
10664 break;
10665 case NODE_CASE:
10666 CHECK(compile_case(iseq, ret, node, popped));
10667 break;
10668 case NODE_CASE2:
10669 CHECK(compile_case2(iseq, ret, node, popped));
10670 break;
10671 case NODE_CASE3:
10672 CHECK(compile_case3(iseq, ret, node, popped));
10673 break;
10674 case NODE_WHILE:
10675 case NODE_UNTIL:
10676 CHECK(compile_loop(iseq, ret, node, popped, type));
10677 break;
10678 case NODE_FOR:
10679 case NODE_ITER:
10680 CHECK(compile_iter(iseq, ret, node, popped));
10681 break;
10682 case NODE_FOR_MASGN:
10683 CHECK(compile_for_masgn(iseq, ret, node, popped));
10684 break;
10685 case NODE_BREAK:
10686 CHECK(compile_break(iseq, ret, node, popped));
10687 break;
10688 case NODE_NEXT:
10689 CHECK(compile_next(iseq, ret, node, popped));
10690 break;
10691 case NODE_REDO:
10692 CHECK(compile_redo(iseq, ret, node, popped));
10693 break;
10694 case NODE_RETRY:
10695 CHECK(compile_retry(iseq, ret, node, popped));
10696 break;
10697 case NODE_BEGIN:{
10698 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10699 break;
10700 }
10701 case NODE_RESCUE:
10702 CHECK(compile_rescue(iseq, ret, node, popped));
10703 break;
10704 case NODE_RESBODY:
10705 CHECK(compile_resbody(iseq, ret, node, popped));
10706 break;
10707 case NODE_ENSURE:
10708 CHECK(compile_ensure(iseq, ret, node, popped));
10709 break;
10710
10711 case NODE_AND:
10712 case NODE_OR:{
10713 LABEL *end_label = NEW_LABEL(line);
10714 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10715 if (!popped) {
10716 ADD_INSN(ret, node, dup);
10717 }
10718 if (type == NODE_AND) {
10719 ADD_INSNL(ret, node, branchunless, end_label);
10720 }
10721 else {
10722 ADD_INSNL(ret, node, branchif, end_label);
10723 }
10724 if (!popped) {
10725 ADD_INSN(ret, node, pop);
10726 }
10727 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10728 ADD_LABEL(ret, end_label);
10729 break;
10730 }
10731
10732 case NODE_MASGN:{
10733 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10734 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10735 compile_massign(iseq, ret, node, popped);
10736 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10737 break;
10738 }
10739
10740 case NODE_LASGN:{
10741 ID id = RNODE_LASGN(node)->nd_vid;
10742 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10743
10744 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10745 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10746
10747 if (!popped) {
10748 ADD_INSN(ret, node, dup);
10749 }
10750 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10751 break;
10752 }
10753 case NODE_DASGN: {
10754 int idx, lv, ls;
10755 ID id = RNODE_DASGN(node)->nd_vid;
10756 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10757 debugi("dassn id", rb_id2str(id) ? id : '*');
10758
10759 if (!popped) {
10760 ADD_INSN(ret, node, dup);
10761 }
10762
10763 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10764
10765 if (idx < 0) {
10766 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10767 rb_id2str(id));
10768 goto ng;
10769 }
10770 ADD_SETLOCAL(ret, node, ls - idx, lv);
10771 break;
10772 }
10773 case NODE_GASGN:{
10774 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10775
10776 if (!popped) {
10777 ADD_INSN(ret, node, dup);
10778 }
10779 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10780 break;
10781 }
10782 case NODE_IASGN:{
10783 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10784 if (!popped) {
10785 ADD_INSN(ret, node, dup);
10786 }
10787 ADD_INSN2(ret, node, setinstancevariable,
10788 ID2SYM(RNODE_IASGN(node)->nd_vid),
10789 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10790 break;
10791 }
10792 case NODE_CDECL:{
10793 if (RNODE_CDECL(node)->nd_vid) {
10794 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10795
10796 if (!popped) {
10797 ADD_INSN(ret, node, dup);
10798 }
10799
10800 ADD_INSN1(ret, node, putspecialobject,
10801 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10802 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10803 }
10804 else {
10805 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10806 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10807 ADD_INSN(ret, node, swap);
10808
10809 if (!popped) {
10810 ADD_INSN1(ret, node, topn, INT2FIX(1));
10811 ADD_INSN(ret, node, swap);
10812 }
10813
10814 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10815 }
10816 break;
10817 }
10818 case NODE_CVASGN:{
10819 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10820 if (!popped) {
10821 ADD_INSN(ret, node, dup);
10822 }
10823 ADD_INSN2(ret, node, setclassvariable,
10824 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10825 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10826 break;
10827 }
10828 case NODE_OP_ASGN1:
10829 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10830 break;
10831 case NODE_OP_ASGN2:
10832 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10833 break;
10834 case NODE_OP_CDECL:
10835 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10836 break;
10837 case NODE_OP_ASGN_AND:
10838 case NODE_OP_ASGN_OR:
10839 CHECK(compile_op_log(iseq, ret, node, popped, type));
10840 break;
10841 case NODE_CALL: /* obj.foo */
10842 case NODE_OPCALL: /* foo[] */
10843 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10844 break;
10845 }
10846 case NODE_QCALL: /* obj&.foo */
10847 case NODE_FCALL: /* foo() */
10848 case NODE_VCALL: /* foo (variable or call) */
10849 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10850 goto ng;
10851 }
10852 break;
10853 case NODE_SUPER:
10854 case NODE_ZSUPER:
10855 CHECK(compile_super(iseq, ret, node, popped, type));
10856 break;
10857 case NODE_LIST:{
10858 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10859 break;
10860 }
10861 case NODE_ZLIST:{
10862 if (!popped) {
10863 ADD_INSN1(ret, node, newarray, INT2FIX(0));
10864 }
10865 break;
10866 }
10867 case NODE_HASH:
10868 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10869 break;
10870 case NODE_RETURN:
10871 CHECK(compile_return(iseq, ret, node, popped));
10872 break;
10873 case NODE_YIELD:
10874 CHECK(compile_yield(iseq, ret, node, popped));
10875 break;
10876 case NODE_LVAR:{
10877 if (!popped) {
10878 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10879 }
10880 break;
10881 }
10882 case NODE_DVAR:{
10883 int lv, idx, ls;
10884 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10885 if (!popped) {
10886 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10887 if (idx < 0) {
10888 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10889 rb_id2str(RNODE_DVAR(node)->nd_vid));
10890 goto ng;
10891 }
10892 ADD_GETLOCAL(ret, node, ls - idx, lv);
10893 }
10894 break;
10895 }
10896 case NODE_GVAR:{
10897 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10898 if (popped) {
10899 ADD_INSN(ret, node, pop);
10900 }
10901 break;
10902 }
10903 case NODE_IVAR:{
10904 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10905 if (!popped) {
10906 ADD_INSN2(ret, node, getinstancevariable,
10907 ID2SYM(RNODE_IVAR(node)->nd_vid),
10908 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10909 }
10910 break;
10911 }
10912 case NODE_CONST:{
10913 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10914
10915 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10916 body->ic_size++;
10917 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10918 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10919 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10920 }
10921 else {
10922 ADD_INSN(ret, node, putnil);
10923 ADD_INSN1(ret, node, putobject, Qtrue);
10924 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10925 }
10926
10927 if (popped) {
10928 ADD_INSN(ret, node, pop);
10929 }
10930 break;
10931 }
10932 case NODE_CVAR:{
10933 if (!popped) {
10934 ADD_INSN2(ret, node, getclassvariable,
10935 ID2SYM(RNODE_CVAR(node)->nd_vid),
10936 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10937 }
10938 break;
10939 }
10940 case NODE_NTH_REF:{
10941 if (!popped) {
10942 if (!RNODE_NTH_REF(node)->nd_nth) {
10943 ADD_INSN(ret, node, putnil);
10944 break;
10945 }
10946 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10947 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10948 }
10949 break;
10950 }
10951 case NODE_BACK_REF:{
10952 if (!popped) {
10953 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10954 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10955 }
10956 break;
10957 }
10958 case NODE_MATCH:
10959 case NODE_MATCH2:
10960 case NODE_MATCH3:
10961 CHECK(compile_match(iseq, ret, node, popped, type));
10962 break;
10963 case NODE_SYM:{
10964 if (!popped) {
10965 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
10966 }
10967 break;
10968 }
10969 case NODE_LINE:{
10970 if (!popped) {
10971 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
10972 }
10973 break;
10974 }
10975 case NODE_ENCODING:{
10976 if (!popped) {
10977 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
10978 }
10979 break;
10980 }
10981 case NODE_INTEGER:{
10982 VALUE lit = rb_node_integer_literal_val(node);
10983 debugp_param("integer", lit);
10984 if (!popped) {
10985 ADD_INSN1(ret, node, putobject, lit);
10986 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10987 }
10988 break;
10989 }
10990 case NODE_FLOAT:{
10991 VALUE lit = rb_node_float_literal_val(node);
10992 debugp_param("float", lit);
10993 if (!popped) {
10994 ADD_INSN1(ret, node, putobject, lit);
10995 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10996 }
10997 break;
10998 }
10999 case NODE_RATIONAL:{
11000 VALUE lit = rb_node_rational_literal_val(node);
11001 debugp_param("rational", lit);
11002 if (!popped) {
11003 ADD_INSN1(ret, node, putobject, lit);
11004 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11005 }
11006 break;
11007 }
11008 case NODE_IMAGINARY:{
11009 VALUE lit = rb_node_imaginary_literal_val(node);
11010 debugp_param("imaginary", lit);
11011 if (!popped) {
11012 ADD_INSN1(ret, node, putobject, lit);
11013 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11014 }
11015 break;
11016 }
11017 case NODE_FILE:
11018 case NODE_STR:{
11019 debugp_param("nd_lit", get_string_value(node));
11020 if (!popped) {
11021 VALUE lit = get_string_value(node);
11022 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11023 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11024 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11025 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11026 }
11027 switch (option->frozen_string_literal) {
11028 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11029 ADD_INSN1(ret, node, putchilledstring, lit);
11030 break;
11031 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11032 ADD_INSN1(ret, node, putstring, lit);
11033 break;
11034 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11035 ADD_INSN1(ret, node, putobject, lit);
11036 break;
11037 default:
11038 rb_bug("invalid frozen_string_literal");
11039 }
11040 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11041 }
11042 break;
11043 }
11044 case NODE_DSTR:{
11045 compile_dstr(iseq, ret, node);
11046
11047 if (popped) {
11048 ADD_INSN(ret, node, pop);
11049 }
11050 break;
11051 }
11052 case NODE_XSTR:{
11053 ADD_CALL_RECEIVER(ret, node);
11054 VALUE str = rb_node_str_string_val(node);
11055 ADD_INSN1(ret, node, putobject, str);
11056 RB_OBJ_WRITTEN(iseq, Qundef, str);
11057 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11058
11059 if (popped) {
11060 ADD_INSN(ret, node, pop);
11061 }
11062 break;
11063 }
11064 case NODE_DXSTR:{
11065 ADD_CALL_RECEIVER(ret, node);
11066 compile_dstr(iseq, ret, node);
11067 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11068
11069 if (popped) {
11070 ADD_INSN(ret, node, pop);
11071 }
11072 break;
11073 }
11074 case NODE_EVSTR:
11075 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11076 break;
11077 case NODE_REGX:{
11078 if (!popped) {
11079 VALUE lit = rb_node_regx_string_val(node);
11080 ADD_INSN1(ret, node, putobject, lit);
11081 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11082 }
11083 break;
11084 }
11085 case NODE_DREGX:
11086 compile_dregx(iseq, ret, node, popped);
11087 break;
11088 case NODE_ONCE:{
11089 int ic_index = body->ise_size++;
11090 const rb_iseq_t *block_iseq;
11091 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11092
11093 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11094 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11095
11096 if (popped) {
11097 ADD_INSN(ret, node, pop);
11098 }
11099 break;
11100 }
11101 case NODE_ARGSCAT:{
11102 if (popped) {
11103 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11104 ADD_INSN1(ret, node, splatarray, Qfalse);
11105 ADD_INSN(ret, node, pop);
11106 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11107 ADD_INSN1(ret, node, splatarray, Qfalse);
11108 ADD_INSN(ret, node, pop);
11109 }
11110 else {
11111 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11112 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11113 if (nd_type_p(body_node, NODE_LIST)) {
11114 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11115 }
11116 else {
11117 CHECK(COMPILE(ret, "argscat body", body_node));
11118 ADD_INSN(ret, node, concattoarray);
11119 }
11120 }
11121 break;
11122 }
11123 case NODE_ARGSPUSH:{
11124 if (popped) {
11125 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11126 ADD_INSN1(ret, node, splatarray, Qfalse);
11127 ADD_INSN(ret, node, pop);
11128 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11129 }
11130 else {
11131 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11132 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11133 if (keyword_node_p(body_node)) {
11134 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11135 ADD_INSN(ret, node, pushtoarraykwsplat);
11136 }
11137 else if (static_literal_node_p(body_node, iseq, false)) {
11138 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11139 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11140 }
11141 else {
11142 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11143 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11144 }
11145 }
11146 break;
11147 }
11148 case NODE_SPLAT:{
11149 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11150 ADD_INSN1(ret, node, splatarray, Qtrue);
11151
11152 if (popped) {
11153 ADD_INSN(ret, node, pop);
11154 }
11155 break;
11156 }
11157 case NODE_DEFN:{
11158 ID mid = RNODE_DEFN(node)->nd_mid;
11159 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11160 rb_id2str(mid),
11161 ISEQ_TYPE_METHOD, line);
11162
11163 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11164 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11165 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11166
11167 if (!popped) {
11168 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11169 }
11170
11171 break;
11172 }
11173 case NODE_DEFS:{
11174 ID mid = RNODE_DEFS(node)->nd_mid;
11175 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11176 rb_id2str(mid),
11177 ISEQ_TYPE_METHOD, line);
11178
11179 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11180 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11181 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11182 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11183
11184 if (!popped) {
11185 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11186 }
11187 break;
11188 }
11189 case NODE_ALIAS:{
11190 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11191 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11192 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11193 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11194 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11195
11196 if (popped) {
11197 ADD_INSN(ret, node, pop);
11198 }
11199 break;
11200 }
11201 case NODE_VALIAS:{
11202 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11203 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11204 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11205 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11206
11207 if (popped) {
11208 ADD_INSN(ret, node, pop);
11209 }
11210 break;
11211 }
11212 case NODE_UNDEF:{
11213 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11214
11215 for (long i = 0; i < ary->len; i++) {
11216 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11217 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11218 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11219 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11220
11221 if (i < ary->len - 1) {
11222 ADD_INSN(ret, node, pop);
11223 }
11224 }
11225
11226 if (popped) {
11227 ADD_INSN(ret, node, pop);
11228 }
11229 break;
11230 }
11231 case NODE_CLASS:{
11232 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11233 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11234 ISEQ_TYPE_CLASS, line);
11235 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11236 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11237 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11238
11239 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11240 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11241 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11242
11243 if (popped) {
11244 ADD_INSN(ret, node, pop);
11245 }
11246 break;
11247 }
11248 case NODE_MODULE:{
11249 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11250 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11251 ISEQ_TYPE_CLASS, line);
11252 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11253 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11254
11255 ADD_INSN (ret, node, putnil); /* dummy */
11256 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11257 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11258
11259 if (popped) {
11260 ADD_INSN(ret, node, pop);
11261 }
11262 break;
11263 }
11264 case NODE_SCLASS:{
11265 ID singletonclass;
11266 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11267 ISEQ_TYPE_CLASS, line);
11268
11269 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11270 ADD_INSN (ret, node, putnil);
11271 CONST_ID(singletonclass, "singletonclass");
11272 ADD_INSN3(ret, node, defineclass,
11273 ID2SYM(singletonclass), singleton_class,
11274 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11275 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11276
11277 if (popped) {
11278 ADD_INSN(ret, node, pop);
11279 }
11280 break;
11281 }
11282 case NODE_COLON2:
11283 CHECK(compile_colon2(iseq, ret, node, popped));
11284 break;
11285 case NODE_COLON3:
11286 CHECK(compile_colon3(iseq, ret, node, popped));
11287 break;
11288 case NODE_DOT2:
11289 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11290 break;
11291 case NODE_DOT3:
11292 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11293 break;
11294 case NODE_FLIP2:
11295 case NODE_FLIP3:{
11296 LABEL *lend = NEW_LABEL(line);
11297 LABEL *ltrue = NEW_LABEL(line);
11298 LABEL *lfalse = NEW_LABEL(line);
11299 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11300 ltrue, lfalse));
11301 ADD_LABEL(ret, ltrue);
11302 ADD_INSN1(ret, node, putobject, Qtrue);
11303 ADD_INSNL(ret, node, jump, lend);
11304 ADD_LABEL(ret, lfalse);
11305 ADD_INSN1(ret, node, putobject, Qfalse);
11306 ADD_LABEL(ret, lend);
11307 break;
11308 }
11309 case NODE_SELF:{
11310 if (!popped) {
11311 ADD_INSN(ret, node, putself);
11312 }
11313 break;
11314 }
11315 case NODE_NIL:{
11316 if (!popped) {
11317 ADD_INSN(ret, node, putnil);
11318 }
11319 break;
11320 }
11321 case NODE_TRUE:{
11322 if (!popped) {
11323 ADD_INSN1(ret, node, putobject, Qtrue);
11324 }
11325 break;
11326 }
11327 case NODE_FALSE:{
11328 if (!popped) {
11329 ADD_INSN1(ret, node, putobject, Qfalse);
11330 }
11331 break;
11332 }
11333 case NODE_ERRINFO:
11334 CHECK(compile_errinfo(iseq, ret, node, popped));
11335 break;
11336 case NODE_DEFINED:
11337 if (!popped) {
11338 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11339 }
11340 break;
11341 case NODE_POSTEXE:{
11342 /* compiled to:
11343 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11344 */
11345 int is_index = body->ise_size++;
11346 struct rb_iseq_new_with_callback_callback_func *ifunc =
11347 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11348 const rb_iseq_t *once_iseq =
11349 new_child_iseq_with_callback(iseq, ifunc,
11350 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
11351
11352 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11353 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11354
11355 if (popped) {
11356 ADD_INSN(ret, node, pop);
11357 }
11358 break;
11359 }
11360 case NODE_KW_ARG:
11361 CHECK(compile_kw_arg(iseq, ret, node, popped));
11362 break;
11363 case NODE_DSYM:{
11364 compile_dstr(iseq, ret, node);
11365 if (!popped) {
11366 ADD_INSN(ret, node, intern);
11367 }
11368 else {
11369 ADD_INSN(ret, node, pop);
11370 }
11371 break;
11372 }
11373 case NODE_ATTRASGN:
11374 CHECK(compile_attrasgn(iseq, ret, node, popped));
11375 break;
11376 case NODE_LAMBDA:{
11377 /* compile same as lambda{...} */
11378 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11379 VALUE argc = INT2FIX(0);
11380
11381 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11382 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11383 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11384
11385 if (popped) {
11386 ADD_INSN(ret, node, pop);
11387 }
11388 break;
11389 }
11390 default:
11391 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11392 ng:
11393 debug_node_end();
11394 return COMPILE_NG;
11395 }
11396
11397 debug_node_end();
11398 return COMPILE_OK;
11399}
11400
11401/***************************/
11402/* instruction information */
11403/***************************/
11404
11405static int
11406insn_data_length(INSN *iobj)
11407{
11408 return insn_len(iobj->insn_id);
11409}
11410
11411static int
11412calc_sp_depth(int depth, INSN *insn)
11413{
11414 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11415}
11416
11417static VALUE
11418opobj_inspect(VALUE obj)
11419{
11420 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11421 switch (BUILTIN_TYPE(obj)) {
11422 case T_STRING:
11423 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11424 break;
11425 case T_ARRAY:
11426 obj = rb_ary_dup(obj);
11427 break;
11428 default:
11429 break;
11430 }
11431 }
11432 return rb_inspect(obj);
11433}
11434
11435
11436
11437static VALUE
11438insn_data_to_s_detail(INSN *iobj)
11439{
11440 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11441
11442 if (iobj->operands) {
11443 const char *types = insn_op_types(iobj->insn_id);
11444 int j;
11445
11446 for (j = 0; types[j]; j++) {
11447 char type = types[j];
11448
11449 switch (type) {
11450 case TS_OFFSET: /* label(destination position) */
11451 {
11452 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11453 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11454 break;
11455 }
11456 break;
11457 case TS_ISEQ: /* iseq */
11458 {
11459 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11460 VALUE val = Qnil;
11461 if (0 && iseq) { /* TODO: invalidate now */
11462 val = (VALUE)iseq;
11463 }
11464 rb_str_concat(str, opobj_inspect(val));
11465 }
11466 break;
11467 case TS_LINDEX:
11468 case TS_NUM: /* ulong */
11469 case TS_VALUE: /* VALUE */
11470 {
11471 VALUE v = OPERAND_AT(iobj, j);
11472 if (!CLASS_OF(v))
11473 rb_str_cat2(str, "<hidden>");
11474 else {
11475 rb_str_concat(str, opobj_inspect(v));
11476 }
11477 break;
11478 }
11479 case TS_ID: /* ID */
11480 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11481 break;
11482 case TS_IC: /* inline cache */
11483 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11484 break;
11485 case TS_IVC: /* inline ivar cache */
11486 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11487 break;
11488 case TS_ICVARC: /* inline cvar cache */
11489 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11490 break;
11491 case TS_ISE: /* inline storage entry */
11492 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11493 break;
11494 case TS_CALLDATA: /* we store these as call infos at compile time */
11495 {
11496 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11497 rb_str_cat2(str, "<calldata:");
11498 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11499 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11500 break;
11501 }
11502 case TS_CDHASH: /* case/when condition cache */
11503 rb_str_cat2(str, "<ch>");
11504 break;
11505 case TS_FUNCPTR:
11506 {
11507 void *func = (void *)OPERAND_AT(iobj, j);
11508#ifdef HAVE_DLADDR
11509 Dl_info info;
11510 if (dladdr(func, &info) && info.dli_sname) {
11511 rb_str_cat2(str, info.dli_sname);
11512 break;
11513 }
11514#endif
11515 rb_str_catf(str, "<%p>", func);
11516 }
11517 break;
11518 case TS_BUILTIN:
11519 rb_str_cat2(str, "<TS_BUILTIN>");
11520 break;
11521 default:{
11522 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11523 }
11524 }
11525 if (types[j + 1]) {
11526 rb_str_cat2(str, ", ");
11527 }
11528 }
11529 }
11530 return str;
11531}
11532
11533static void
11534dump_disasm_list(const LINK_ELEMENT *link)
11535{
11536 dump_disasm_list_with_cursor(link, NULL, NULL);
11537}
11538
11539static void
11540dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11541{
11542 int pos = 0;
11543 INSN *iobj;
11544 LABEL *lobj;
11545 VALUE str;
11546
11547 printf("-- raw disasm--------\n");
11548
11549 while (link) {
11550 if (curr) printf(curr == link ? "*" : " ");
11551 switch (link->type) {
11552 case ISEQ_ELEMENT_INSN:
11553 {
11554 iobj = (INSN *)link;
11555 str = insn_data_to_s_detail(iobj);
11556 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11557 pos += insn_data_length(iobj);
11558 break;
11559 }
11560 case ISEQ_ELEMENT_LABEL:
11561 {
11562 lobj = (LABEL *)link;
11563 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11564 dest == lobj ? " <---" : "");
11565 break;
11566 }
11567 case ISEQ_ELEMENT_TRACE:
11568 {
11569 TRACE *trace = (TRACE *)link;
11570 printf(" trace: %0x\n", trace->event);
11571 break;
11572 }
11573 case ISEQ_ELEMENT_ADJUST:
11574 {
11575 ADJUST *adjust = (ADJUST *)link;
11576 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11577 break;
11578 }
11579 default:
11580 /* ignore */
11581 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11582 }
11583 link = link->next;
11584 }
11585 printf("---------------------\n");
11586 fflush(stdout);
11587}
11588
11589int
11590rb_insn_len(VALUE insn)
11591{
11592 return insn_len(insn);
11593}
11594
11595const char *
11596rb_insns_name(int i)
11597{
11598 return insn_name(i);
11599}
11600
11601 VALUE
11602rb_insns_name_array(void)
11603{
11604 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11605 int i;
11606 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11607 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11608 }
11609 return rb_ary_freeze(ary);
11610}
11611
11612static LABEL *
11613register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11614{
11615 LABEL *label = 0;
11616 st_data_t tmp;
11617 obj = rb_to_symbol_type(obj);
11618
11619 if (st_lookup(labels_table, obj, &tmp) == 0) {
11620 label = NEW_LABEL(0);
11621 st_insert(labels_table, obj, (st_data_t)label);
11622 }
11623 else {
11624 label = (LABEL *)tmp;
11625 }
11626 LABEL_REF(label);
11627 return label;
11628}
11629
11630static VALUE
11631get_exception_sym2type(VALUE sym)
11632{
11633 static VALUE symRescue, symEnsure, symRetry;
11634 static VALUE symBreak, symRedo, symNext;
11635
11636 if (symRescue == 0) {
11637 symRescue = ID2SYM(rb_intern_const("rescue"));
11638 symEnsure = ID2SYM(rb_intern_const("ensure"));
11639 symRetry = ID2SYM(rb_intern_const("retry"));
11640 symBreak = ID2SYM(rb_intern_const("break"));
11641 symRedo = ID2SYM(rb_intern_const("redo"));
11642 symNext = ID2SYM(rb_intern_const("next"));
11643 }
11644
11645 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11646 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11647 if (sym == symRetry) return CATCH_TYPE_RETRY;
11648 if (sym == symBreak) return CATCH_TYPE_BREAK;
11649 if (sym == symRedo) return CATCH_TYPE_REDO;
11650 if (sym == symNext) return CATCH_TYPE_NEXT;
11651 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11652 return 0;
11653}
11654
11655static int
11656iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11657 VALUE exception)
11658{
11659 int i;
11660
11661 for (i=0; i<RARRAY_LEN(exception); i++) {
11662 const rb_iseq_t *eiseq;
11663 VALUE v, type;
11664 LABEL *lstart, *lend, *lcont;
11665 unsigned int sp;
11666
11667 v = rb_to_array_type(RARRAY_AREF(exception, i));
11668 if (RARRAY_LEN(v) != 6) {
11669 rb_raise(rb_eSyntaxError, "wrong exception entry");
11670 }
11671 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11672 if (NIL_P(RARRAY_AREF(v, 1))) {
11673 eiseq = NULL;
11674 }
11675 else {
11676 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11677 }
11678
11679 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11680 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11681 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11682 sp = NUM2UINT(RARRAY_AREF(v, 5));
11683
11684 /* TODO: Dirty Hack! Fix me */
11685 if (type == CATCH_TYPE_RESCUE ||
11686 type == CATCH_TYPE_BREAK ||
11687 type == CATCH_TYPE_NEXT) {
11688 ++sp;
11689 }
11690
11691 lcont->sp = sp;
11692
11693 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11694
11695 RB_GC_GUARD(v);
11696 }
11697 return COMPILE_OK;
11698}
11699
11700static struct st_table *
11701insn_make_insn_table(void)
11702{
11703 struct st_table *table;
11704 int i;
11705 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11706
11707 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11708 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11709 }
11710
11711 return table;
11712}
11713
11714static const rb_iseq_t *
11715iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11716{
11717 VALUE iseqw;
11718 const rb_iseq_t *loaded_iseq;
11719
11720 if (RB_TYPE_P(op, T_ARRAY)) {
11721 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11722 }
11723 else if (CLASS_OF(op) == rb_cISeq) {
11724 iseqw = op;
11725 }
11726 else {
11727 rb_raise(rb_eSyntaxError, "ISEQ is required");
11728 }
11729
11730 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11731 return loaded_iseq;
11732}
11733
11734static VALUE
11735iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11736{
11737 ID mid = 0;
11738 int orig_argc = 0;
11739 unsigned int flag = 0;
11740 struct rb_callinfo_kwarg *kw_arg = 0;
11741
11742 if (!NIL_P(op)) {
11743 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11744 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11745 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11746 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11747
11748 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11749 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11750 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11751
11752 if (!NIL_P(vkw_arg)) {
11753 int i;
11754 int len = RARRAY_LENINT(vkw_arg);
11755 size_t n = rb_callinfo_kwarg_bytes(len);
11756
11757 kw_arg = xmalloc(n);
11758 kw_arg->references = 0;
11759 kw_arg->keyword_len = len;
11760 for (i = 0; i < len; i++) {
11761 VALUE kw = RARRAY_AREF(vkw_arg, i);
11762 SYM2ID(kw); /* make immortal */
11763 kw_arg->keywords[i] = kw;
11764 }
11765 }
11766 }
11767
11768 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11769 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11770 return (VALUE)ci;
11771}
11772
11773static rb_event_flag_t
11774event_name_to_flag(VALUE sym)
11775{
11776#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11777 CHECK_EVENT(RUBY_EVENT_LINE);
11778 CHECK_EVENT(RUBY_EVENT_CLASS);
11779 CHECK_EVENT(RUBY_EVENT_END);
11780 CHECK_EVENT(RUBY_EVENT_CALL);
11781 CHECK_EVENT(RUBY_EVENT_RETURN);
11782 CHECK_EVENT(RUBY_EVENT_B_CALL);
11783 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11784 CHECK_EVENT(RUBY_EVENT_RESCUE);
11785#undef CHECK_EVENT
11786 return RUBY_EVENT_NONE;
11787}
11788
11789static int
11790iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11791 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11792{
11793 /* TODO: body should be frozen */
11794 long i, len = RARRAY_LEN(body);
11795 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11796 int j;
11797 int line_no = 0, node_id = -1, insn_idx = 0;
11798 int ret = COMPILE_OK;
11799
11800 /*
11801 * index -> LABEL *label
11802 */
11803 static struct st_table *insn_table;
11804
11805 if (insn_table == 0) {
11806 insn_table = insn_make_insn_table();
11807 }
11808
11809 for (i=0; i<len; i++) {
11810 VALUE obj = RARRAY_AREF(body, i);
11811
11812 if (SYMBOL_P(obj)) {
11813 rb_event_flag_t event;
11814 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11815 ADD_TRACE(anchor, event);
11816 }
11817 else {
11818 LABEL *label = register_label(iseq, labels_table, obj);
11819 ADD_LABEL(anchor, label);
11820 }
11821 }
11822 else if (FIXNUM_P(obj)) {
11823 line_no = NUM2INT(obj);
11824 }
11825 else if (RB_TYPE_P(obj, T_ARRAY)) {
11826 VALUE *argv = 0;
11827 int argc = RARRAY_LENINT(obj) - 1;
11828 st_data_t insn_id;
11829 VALUE insn;
11830
11831 if (node_ids) {
11832 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11833 }
11834
11835 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11836 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11837 /* TODO: exception */
11838 COMPILE_ERROR(iseq, line_no,
11839 "unknown instruction: %+"PRIsVALUE, insn);
11840 ret = COMPILE_NG;
11841 break;
11842 }
11843
11844 if (argc != insn_len((VALUE)insn_id)-1) {
11845 COMPILE_ERROR(iseq, line_no,
11846 "operand size mismatch");
11847 ret = COMPILE_NG;
11848 break;
11849 }
11850
11851 if (argc > 0) {
11852 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11853
11854 // add element before operand setup to make GC root
11855 ADD_ELEM(anchor,
11856 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11857 (enum ruby_vminsn_type)insn_id, argc, argv));
11858
11859 for (j=0; j<argc; j++) {
11860 VALUE op = rb_ary_entry(obj, j+1);
11861 switch (insn_op_type((VALUE)insn_id, j)) {
11862 case TS_OFFSET: {
11863 LABEL *label = register_label(iseq, labels_table, op);
11864 argv[j] = (VALUE)label;
11865 break;
11866 }
11867 case TS_LINDEX:
11868 case TS_NUM:
11869 (void)NUM2INT(op);
11870 argv[j] = op;
11871 break;
11872 case TS_VALUE:
11873 argv[j] = op;
11874 RB_OBJ_WRITTEN(iseq, Qundef, op);
11875 break;
11876 case TS_ISEQ:
11877 {
11878 if (op != Qnil) {
11879 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
11880 argv[j] = v;
11881 RB_OBJ_WRITTEN(iseq, Qundef, v);
11882 }
11883 else {
11884 argv[j] = 0;
11885 }
11886 }
11887 break;
11888 case TS_ISE:
11889 argv[j] = op;
11890 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11891 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
11892 }
11893 break;
11894 case TS_IC:
11895 {
11896 VALUE segments = rb_ary_new();
11897 op = rb_to_array_type(op);
11898
11899 for (int i = 0; i < RARRAY_LEN(op); i++) {
11900 VALUE sym = RARRAY_AREF(op, i);
11901 sym = rb_to_symbol_type(sym);
11902 rb_ary_push(segments, sym);
11903 }
11904
11905 RB_GC_GUARD(op);
11906 argv[j] = segments;
11907 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11908 ISEQ_BODY(iseq)->ic_size++;
11909 }
11910 break;
11911 case TS_IVC: /* inline ivar cache */
11912 argv[j] = op;
11913 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
11914 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
11915 }
11916 break;
11917 case TS_ICVARC: /* inline cvar cache */
11918 argv[j] = op;
11919 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
11920 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
11921 }
11922 break;
11923 case TS_CALLDATA:
11924 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
11925 break;
11926 case TS_ID:
11927 argv[j] = rb_to_symbol_type(op);
11928 break;
11929 case TS_CDHASH:
11930 {
11931 int i;
11932 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
11933
11934 RHASH_TBL_RAW(map)->type = &cdhash_type;
11935 op = rb_to_array_type(op);
11936 for (i=0; i<RARRAY_LEN(op); i+=2) {
11937 VALUE key = RARRAY_AREF(op, i);
11938 VALUE sym = RARRAY_AREF(op, i+1);
11939 LABEL *label =
11940 register_label(iseq, labels_table, sym);
11941 rb_hash_aset(map, key, (VALUE)label | 1);
11942 }
11943 RB_GC_GUARD(op);
11944 argv[j] = map;
11945 RB_OBJ_WRITTEN(iseq, Qundef, map);
11946 }
11947 break;
11948 case TS_FUNCPTR:
11949 {
11950#if SIZEOF_VALUE <= SIZEOF_LONG
11951 long funcptr = NUM2LONG(op);
11952#else
11953 LONG_LONG funcptr = NUM2LL(op);
11954#endif
11955 argv[j] = (VALUE)funcptr;
11956 }
11957 break;
11958 default:
11959 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11960 }
11961 }
11962 }
11963 else {
11964 ADD_ELEM(anchor,
11965 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11966 (enum ruby_vminsn_type)insn_id, argc, NULL));
11967 }
11968 }
11969 else {
11970 rb_raise(rb_eTypeError, "unexpected object for instruction");
11971 }
11972 }
11973 RTYPEDDATA_DATA(labels_wrapper) = 0;
11974 RB_GC_GUARD(labels_wrapper);
11975 validate_labels(iseq, labels_table);
11976 if (!ret) return ret;
11977 return iseq_setup(iseq, anchor);
11978}
11979
11980#define CHECK_ARRAY(v) rb_to_array_type(v)
11981#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11982
11983static int
11984int_param(int *dst, VALUE param, VALUE sym)
11985{
11986 VALUE val = rb_hash_aref(param, sym);
11987 if (FIXNUM_P(val)) {
11988 *dst = FIX2INT(val);
11989 return TRUE;
11990 }
11991 else if (!NIL_P(val)) {
11992 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
11993 sym, val);
11994 }
11995 return FALSE;
11996}
11997
11998static const struct rb_iseq_param_keyword *
11999iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12000{
12001 int i, j;
12002 int len = RARRAY_LENINT(keywords);
12003 int default_len;
12004 VALUE key, sym, default_val;
12005 VALUE *dvs;
12006 ID *ids;
12007 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12008
12009 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12010
12011 keyword->num = len;
12012#define SYM(s) ID2SYM(rb_intern_const(#s))
12013 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12014 i = keyword->bits_start - keyword->num;
12015 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12016#undef SYM
12017
12018 /* required args */
12019 for (i = 0; i < len; i++) {
12020 VALUE val = RARRAY_AREF(keywords, i);
12021
12022 if (!SYMBOL_P(val)) {
12023 goto default_values;
12024 }
12025 ids[i] = SYM2ID(val);
12026 keyword->required_num++;
12027 }
12028
12029 default_values: /* note: we intentionally preserve `i' from previous loop */
12030 default_len = len - i;
12031 if (default_len == 0) {
12032 keyword->table = ids;
12033 return keyword;
12034 }
12035 else if (default_len < 0) {
12036 UNREACHABLE;
12037 }
12038
12039 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12040
12041 for (j = 0; i < len; i++, j++) {
12042 key = RARRAY_AREF(keywords, i);
12043 CHECK_ARRAY(key);
12044
12045 switch (RARRAY_LEN(key)) {
12046 case 1:
12047 sym = RARRAY_AREF(key, 0);
12048 default_val = Qundef;
12049 break;
12050 case 2:
12051 sym = RARRAY_AREF(key, 0);
12052 default_val = RARRAY_AREF(key, 1);
12053 break;
12054 default:
12055 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12056 }
12057 ids[i] = SYM2ID(sym);
12058 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12059 }
12060
12061 keyword->table = ids;
12062 keyword->default_values = dvs;
12063
12064 return keyword;
12065}
12066
12067static void
12068iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
12069{
12070 rb_gc_mark(obj);
12071}
12072
12073void
12074rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
12075{
12076 INSN *iobj = 0;
12077 size_t size = sizeof(INSN);
12078 unsigned int pos = 0;
12079
12080 while (storage) {
12081#ifdef STRICT_ALIGNMENT
12082 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12083#else
12084 const size_t padding = 0; /* expected to be optimized by compiler */
12085#endif /* STRICT_ALIGNMENT */
12086 size_t offset = pos + size + padding;
12087 if (offset > storage->size || offset > storage->pos) {
12088 pos = 0;
12089 storage = storage->next;
12090 }
12091 else {
12092#ifdef STRICT_ALIGNMENT
12093 pos += (int)padding;
12094#endif /* STRICT_ALIGNMENT */
12095
12096 iobj = (INSN *)&storage->buff[pos];
12097
12098 if (iobj->operands) {
12099 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
12100 }
12101 pos += (int)size;
12102 }
12103 }
12104}
12105
12106static const rb_data_type_t labels_wrapper_type = {
12107 .wrap_struct_name = "compiler/labels_wrapper",
12108 .function = {
12109 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12110 .dfree = (RUBY_DATA_FUNC)st_free_table,
12111 },
12112 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12113};
12114
12115void
12116rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12117 VALUE exception, VALUE body)
12118{
12119#define SYM(s) ID2SYM(rb_intern_const(#s))
12120 int i, len;
12121 unsigned int arg_size, local_size, stack_max;
12122 ID *tbl;
12123 struct st_table *labels_table = st_init_numtable();
12124 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12125 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12126 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12127 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12128 DECL_ANCHOR(anchor);
12129 INIT_ANCHOR(anchor);
12130
12131 len = RARRAY_LENINT(locals);
12132 ISEQ_BODY(iseq)->local_table_size = len;
12133 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12134
12135 for (i = 0; i < len; i++) {
12136 VALUE lv = RARRAY_AREF(locals, i);
12137
12138 if (sym_arg_rest == lv) {
12139 tbl[i] = 0;
12140 }
12141 else {
12142 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12143 }
12144 }
12145
12146#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12147 if (INT_PARAM(lead_num)) {
12148 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12149 }
12150 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12151 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12152 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12153 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12154#undef INT_PARAM
12155 {
12156#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12157 int x;
12158 INT_PARAM(arg_size);
12159 INT_PARAM(local_size);
12160 INT_PARAM(stack_max);
12161#undef INT_PARAM
12162 }
12163
12164 VALUE node_ids = Qfalse;
12165#ifdef USE_ISEQ_NODE_ID
12166 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12167 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12168 rb_raise(rb_eTypeError, "node_ids is not an array");
12169 }
12170#endif
12171
12172 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12173 len = RARRAY_LENINT(arg_opt_labels);
12174 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12175
12176 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12177 VALUE *opt_table = ALLOC_N(VALUE, len);
12178
12179 for (i = 0; i < len; i++) {
12180 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12181 LABEL *label = register_label(iseq, labels_table, ent);
12182 opt_table[i] = (VALUE)label;
12183 }
12184
12185 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12186 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12187 }
12188 }
12189 else if (!NIL_P(arg_opt_labels)) {
12190 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12191 arg_opt_labels);
12192 }
12193
12194 if (RB_TYPE_P(keywords, T_ARRAY)) {
12195 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12196 }
12197 else if (!NIL_P(keywords)) {
12198 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12199 keywords);
12200 }
12201
12202 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12203 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12204 }
12205
12206 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12207 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12208 }
12209
12210 if (int_param(&i, params, SYM(kwrest))) {
12211 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12212 if (keyword == NULL) {
12213 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12214 }
12215 keyword->rest_start = i;
12216 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12217 }
12218#undef SYM
12219 iseq_calc_param_size(iseq);
12220
12221 /* exception */
12222 iseq_build_from_ary_exception(iseq, labels_table, exception);
12223
12224 /* body */
12225 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12226
12227 ISEQ_BODY(iseq)->param.size = arg_size;
12228 ISEQ_BODY(iseq)->local_table_size = local_size;
12229 ISEQ_BODY(iseq)->stack_max = stack_max;
12230}
12231
12232/* for parser */
12233
12234int
12235rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12236{
12237 if (iseq) {
12238 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12239 while (body->type == ISEQ_TYPE_BLOCK ||
12240 body->type == ISEQ_TYPE_RESCUE ||
12241 body->type == ISEQ_TYPE_ENSURE ||
12242 body->type == ISEQ_TYPE_EVAL ||
12243 body->type == ISEQ_TYPE_MAIN
12244 ) {
12245 unsigned int i;
12246
12247 for (i = 0; i < body->local_table_size; i++) {
12248 if (body->local_table[i] == id) {
12249 return 1;
12250 }
12251 }
12252 iseq = body->parent_iseq;
12253 body = ISEQ_BODY(iseq);
12254 }
12255 }
12256 return 0;
12257}
12258
12259int
12260rb_local_defined(ID id, const rb_iseq_t *iseq)
12261{
12262 if (iseq) {
12263 unsigned int i;
12264 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12265
12266 for (i=0; i<body->local_table_size; i++) {
12267 if (body->local_table[i] == id) {
12268 return 1;
12269 }
12270 }
12271 }
12272 return 0;
12273}
12274
12275/* ISeq binary format */
12276
12277#ifndef IBF_ISEQ_DEBUG
12278#define IBF_ISEQ_DEBUG 0
12279#endif
12280
12281#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12282#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12283#endif
12284
12285typedef uint32_t ibf_offset_t;
12286#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12287
12288#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12289#ifdef RUBY_DEVEL
12290#define IBF_DEVEL_VERSION 4
12291#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12292#else
12293#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12294#endif
12295
12296static const char IBF_ENDIAN_MARK =
12297#ifdef WORDS_BIGENDIAN
12298 'b'
12299#else
12300 'l'
12301#endif
12302 ;
12303
12304 struct ibf_header {
12305 char magic[4]; /* YARB */
12306 uint32_t major_version;
12307 uint32_t minor_version;
12308 uint32_t size;
12309 uint32_t extra_size;
12310
12311 uint32_t iseq_list_size;
12312 uint32_t global_object_list_size;
12313 ibf_offset_t iseq_list_offset;
12314 ibf_offset_t global_object_list_offset;
12315 uint8_t endian;
12316 uint8_t wordsize; /* assume no 2048-bit CPU */
12317};
12318
12319 struct ibf_dump_buffer {
12320 VALUE str;
12321 st_table *obj_table; /* obj -> obj number */
12322};
12323
12324 struct ibf_dump {
12325 st_table *iseq_table; /* iseq -> iseq number */
12326 struct ibf_dump_buffer global_buffer;
12327 struct ibf_dump_buffer *current_buffer;
12328};
12329
12330 struct ibf_load_buffer {
12331 const char *buff;
12332 ibf_offset_t size;
12333
12334 VALUE obj_list; /* [obj0, ...] */
12335 unsigned int obj_list_size;
12336 ibf_offset_t obj_list_offset;
12337};
12338
12339 struct ibf_load {
12340 const struct ibf_header *header;
12341 VALUE iseq_list; /* [iseq0, ...] */
12342 struct ibf_load_buffer global_buffer;
12343 VALUE loader_obj;
12344 rb_iseq_t *iseq;
12345 VALUE str;
12346 struct ibf_load_buffer *current_buffer;
12347};
12348
12349 struct pinned_list {
12350 long size;
12351 VALUE buffer[1];
12352};
12353
12354static void
12355pinned_list_mark(void *ptr)
12356{
12357 long i;
12358 struct pinned_list *list = (struct pinned_list *)ptr;
12359 for (i = 0; i < list->size; i++) {
12360 if (list->buffer[i]) {
12361 rb_gc_mark(list->buffer[i]);
12362 }
12363 }
12364}
12365
12366static const rb_data_type_t pinned_list_type = {
12367 "pinned_list",
12368 {
12369 pinned_list_mark,
12370 RUBY_DEFAULT_FREE,
12371 NULL, // No external memory to report,
12372 },
12373 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12374};
12375
12376static VALUE
12377pinned_list_fetch(VALUE list, long offset)
12378{
12379 struct pinned_list * ptr;
12380
12381 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12382
12383 if (offset >= ptr->size) {
12384 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12385 }
12386
12387 return ptr->buffer[offset];
12388}
12389
12390static void
12391pinned_list_store(VALUE list, long offset, VALUE object)
12392{
12393 struct pinned_list * ptr;
12394
12395 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12396
12397 if (offset >= ptr->size) {
12398 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12399 }
12400
12401 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12402}
12403
12404static VALUE
12405pinned_list_new(long size)
12406{
12407 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12408 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12409 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12410 ptr->size = size;
12411 return obj_list;
12412}
12413
12414static ibf_offset_t
12415ibf_dump_pos(struct ibf_dump *dump)
12416{
12417 long pos = RSTRING_LEN(dump->current_buffer->str);
12418#if SIZEOF_LONG > SIZEOF_INT
12419 if (pos >= UINT_MAX) {
12420 rb_raise(rb_eRuntimeError, "dump size exceeds");
12421 }
12422#endif
12423 return (unsigned int)pos;
12424}
12425
12426static void
12427ibf_dump_align(struct ibf_dump *dump, size_t align)
12428{
12429 ibf_offset_t pos = ibf_dump_pos(dump);
12430 if (pos % align) {
12431 static const char padding[sizeof(VALUE)];
12432 size_t size = align - ((size_t)pos % align);
12433#if SIZEOF_LONG > SIZEOF_INT
12434 if (pos + size >= UINT_MAX) {
12435 rb_raise(rb_eRuntimeError, "dump size exceeds");
12436 }
12437#endif
12438 for (; size > sizeof(padding); size -= sizeof(padding)) {
12439 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12440 }
12441 rb_str_cat(dump->current_buffer->str, padding, size);
12442 }
12443}
12444
12445static ibf_offset_t
12446ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12447{
12448 ibf_offset_t pos = ibf_dump_pos(dump);
12449 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12450 /* TODO: overflow check */
12451 return pos;
12452}
12453
12454static ibf_offset_t
12455ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12456{
12457 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12458}
12459
12460static void
12461ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12462{
12463 VALUE str = dump->current_buffer->str;
12464 char *ptr = RSTRING_PTR(str);
12465 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12466 rb_bug("ibf_dump_overwrite: overflow");
12467 memcpy(ptr + offset, buff, size);
12468}
12469
12470static const void *
12471ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12472{
12473 ibf_offset_t beg = *offset;
12474 *offset += size;
12475 return load->current_buffer->buff + beg;
12476}
12477
12478static void *
12479ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12480{
12481 void *buff = ruby_xmalloc2(x, y);
12482 size_t size = x * y;
12483 memcpy(buff, load->current_buffer->buff + offset, size);
12484 return buff;
12485}
12486
12487#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12488
12489#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12490#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12491#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12492#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12493#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12494
12495static int
12496ibf_table_lookup(struct st_table *table, st_data_t key)
12497{
12498 st_data_t val;
12499
12500 if (st_lookup(table, key, &val)) {
12501 return (int)val;
12502 }
12503 else {
12504 return -1;
12505 }
12506}
12507
12508static int
12509ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12510{
12511 int index = ibf_table_lookup(table, key);
12512
12513 if (index < 0) { /* not found */
12514 index = (int)table->num_entries;
12515 st_insert(table, key, (st_data_t)index);
12516 }
12517
12518 return index;
12519}
12520
12521/* dump/load generic */
12522
12523static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12524
12525static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12526static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12527
12528static st_table *
12529ibf_dump_object_table_new(void)
12530{
12531 st_table *obj_table = st_init_numtable(); /* need free */
12532 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12533
12534 return obj_table;
12535}
12536
12537static VALUE
12538ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12539{
12540 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12541}
12542
12543static VALUE
12544ibf_dump_id(struct ibf_dump *dump, ID id)
12545{
12546 if (id == 0 || rb_id2name(id) == NULL) {
12547 return 0;
12548 }
12549 return ibf_dump_object(dump, rb_id2sym(id));
12550}
12551
12552static ID
12553ibf_load_id(const struct ibf_load *load, const ID id_index)
12554{
12555 if (id_index == 0) {
12556 return 0;
12557 }
12558 VALUE sym = ibf_load_object(load, id_index);
12559 if (rb_integer_type_p(sym)) {
12560 /* Load hidden local variables as indexes */
12561 return NUM2ULONG(sym);
12562 }
12563 return rb_sym2id(sym);
12564}
12565
12566/* dump/load: code */
12567
12568static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12569
12570static int
12571ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12572{
12573 if (iseq == NULL) {
12574 return -1;
12575 }
12576 else {
12577 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12578 }
12579}
12580
12581static unsigned char
12582ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12583{
12584 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12585 return (unsigned char)load->current_buffer->buff[(*offset)++];
12586}
12587
12588/*
12589 * Small uint serialization
12590 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12591 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12592 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12593 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12594 * ...
12595 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12596 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12597 */
12598static void
12599ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12600{
12601 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12602 ibf_dump_write(dump, &x, sizeof(VALUE));
12603 return;
12604 }
12605
12606 enum { max_byte_length = sizeof(VALUE) + 1 };
12607
12608 unsigned char bytes[max_byte_length];
12609 ibf_offset_t n;
12610
12611 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12612 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12613 }
12614
12615 x <<= 1;
12616 x |= 1;
12617 x <<= n;
12618 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12619 n++;
12620
12621 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12622}
12623
12624static VALUE
12625ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12626{
12627 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12628 union { char s[sizeof(VALUE)]; VALUE v; } x;
12629
12630 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12631 *offset += sizeof(VALUE);
12632
12633 return x.v;
12634 }
12635
12636 enum { max_byte_length = sizeof(VALUE) + 1 };
12637
12638 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12639 const unsigned char c = buffer[*offset];
12640
12641 ibf_offset_t n =
12642 c & 1 ? 1 :
12643 c == 0 ? 9 : ntz_int32(c) + 1;
12644 VALUE x = (VALUE)c >> n;
12645
12646 if (*offset + n > load->current_buffer->size) {
12647 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12648 }
12649
12650 ibf_offset_t i;
12651 for (i = 1; i < n; i++) {
12652 x <<= 8;
12653 x |= (VALUE)buffer[*offset + i];
12654 }
12655
12656 *offset += n;
12657 return x;
12658}
12659
12660static void
12661ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12662{
12663 // short: index
12664 // short: name.length
12665 // bytes: name
12666 // // omit argc (only verify with name)
12667 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12668
12669 size_t len = strlen(bf->name);
12670 ibf_dump_write_small_value(dump, (VALUE)len);
12671 ibf_dump_write(dump, bf->name, len);
12672}
12673
12674static const struct rb_builtin_function *
12675ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12676{
12677 int i = (int)ibf_load_small_value(load, offset);
12678 int len = (int)ibf_load_small_value(load, offset);
12679 const char *name = (char *)ibf_load_ptr(load, offset, len);
12680
12681 if (0) {
12682 fprintf(stderr, "%.*s!!\n", len, name);
12683 }
12684
12685 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12686 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12687 if (strncmp(table[i].name, name, len) != 0) {
12688 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12689 }
12690 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12691
12692 return &table[i];
12693}
12694
12695static ibf_offset_t
12696ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12697{
12698 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12699 const int iseq_size = body->iseq_size;
12700 int code_index;
12701 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12702
12703 ibf_offset_t offset = ibf_dump_pos(dump);
12704
12705 for (code_index=0; code_index<iseq_size;) {
12706 const VALUE insn = orig_code[code_index++];
12707 const char *types = insn_op_types(insn);
12708 int op_index;
12709
12710 /* opcode */
12711 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12712 ibf_dump_write_small_value(dump, insn);
12713
12714 /* operands */
12715 for (op_index=0; types[op_index]; op_index++, code_index++) {
12716 VALUE op = orig_code[code_index];
12717 VALUE wv;
12718
12719 switch (types[op_index]) {
12720 case TS_CDHASH:
12721 case TS_VALUE:
12722 wv = ibf_dump_object(dump, op);
12723 break;
12724 case TS_ISEQ:
12725 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12726 break;
12727 case TS_IC:
12728 {
12729 IC ic = (IC)op;
12730 VALUE arr = idlist_to_array(ic->segments);
12731 wv = ibf_dump_object(dump, arr);
12732 }
12733 break;
12734 case TS_ISE:
12735 case TS_IVC:
12736 case TS_ICVARC:
12737 {
12738 union iseq_inline_storage_entry *is = (union iseq_inline_storage_entry *)op;
12739 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12740 }
12741 break;
12742 case TS_CALLDATA:
12743 {
12744 goto skip_wv;
12745 }
12746 case TS_ID:
12747 wv = ibf_dump_id(dump, (ID)op);
12748 break;
12749 case TS_FUNCPTR:
12750 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12751 goto skip_wv;
12752 case TS_BUILTIN:
12753 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12754 goto skip_wv;
12755 default:
12756 wv = op;
12757 break;
12758 }
12759 ibf_dump_write_small_value(dump, wv);
12760 skip_wv:;
12761 }
12762 RUBY_ASSERT(insn_len(insn) == op_index+1);
12763 }
12764
12765 return offset;
12766}
12767
12768static VALUE *
12769ibf_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)
12770{
12771 VALUE iseqv = (VALUE)iseq;
12772 unsigned int code_index;
12773 ibf_offset_t reading_pos = bytecode_offset;
12774 VALUE *code = ALLOC_N(VALUE, iseq_size);
12775
12776 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12777 struct rb_call_data *cd_entries = load_body->call_data;
12778 int ic_index = 0;
12779
12780 iseq_bits_t * mark_offset_bits;
12781
12782 iseq_bits_t tmp[1] = {0};
12783
12784 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12785 mark_offset_bits = tmp;
12786 }
12787 else {
12788 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12789 }
12790 bool needs_bitmap = false;
12791
12792 for (code_index=0; code_index<iseq_size;) {
12793 /* opcode */
12794 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12795 const char *types = insn_op_types(insn);
12796 int op_index;
12797
12798 code_index++;
12799
12800 /* operands */
12801 for (op_index=0; types[op_index]; op_index++, code_index++) {
12802 const char operand_type = types[op_index];
12803 switch (operand_type) {
12804 case TS_VALUE:
12805 {
12806 VALUE op = ibf_load_small_value(load, &reading_pos);
12807 VALUE v = ibf_load_object(load, op);
12808 code[code_index] = v;
12809 if (!SPECIAL_CONST_P(v)) {
12810 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12811 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12812 needs_bitmap = true;
12813 }
12814 break;
12815 }
12816 case TS_CDHASH:
12817 {
12818 VALUE op = ibf_load_small_value(load, &reading_pos);
12819 VALUE v = ibf_load_object(load, op);
12820 v = rb_hash_dup(v); // hash dumped as frozen
12821 RHASH_TBL_RAW(v)->type = &cdhash_type;
12822 rb_hash_rehash(v); // hash function changed
12823 freeze_hide_obj(v);
12824
12825 // Overwrite the existing hash in the object list. This
12826 // is to keep the object alive during load time.
12827 // [Bug #17984] [ruby-core:104259]
12828 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12829
12830 code[code_index] = v;
12831 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12832 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12833 needs_bitmap = true;
12834 break;
12835 }
12836 case TS_ISEQ:
12837 {
12838 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12839 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12840 code[code_index] = v;
12841 if (!SPECIAL_CONST_P(v)) {
12842 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12843 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12844 needs_bitmap = true;
12845 }
12846 break;
12847 }
12848 case TS_IC:
12849 {
12850 VALUE op = ibf_load_small_value(load, &reading_pos);
12851 VALUE arr = ibf_load_object(load, op);
12852
12853 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12854 ic->segments = array_to_idlist(arr);
12855
12856 code[code_index] = (VALUE)ic;
12857 }
12858 break;
12859 case TS_ISE:
12860 case TS_ICVARC:
12861 case TS_IVC:
12862 {
12863 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
12864
12865 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12866 code[code_index] = (VALUE)ic;
12867
12868 if (operand_type == TS_IVC) {
12869 IVC cache = (IVC)ic;
12870
12871 if (insn == BIN(setinstancevariable)) {
12872 ID iv_name = (ID)code[code_index - 1];
12873 cache->iv_set_name = iv_name;
12874 }
12875 else {
12876 cache->iv_set_name = 0;
12877 }
12878
12879 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12880 }
12881
12882 }
12883 break;
12884 case TS_CALLDATA:
12885 {
12886 code[code_index] = (VALUE)cd_entries++;
12887 }
12888 break;
12889 case TS_ID:
12890 {
12891 VALUE op = ibf_load_small_value(load, &reading_pos);
12892 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
12893 }
12894 break;
12895 case TS_FUNCPTR:
12896 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12897 break;
12898 case TS_BUILTIN:
12899 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
12900 break;
12901 default:
12902 code[code_index] = ibf_load_small_value(load, &reading_pos);
12903 continue;
12904 }
12905 }
12906 if (insn_len(insn) != op_index+1) {
12907 rb_raise(rb_eRuntimeError, "operand size mismatch");
12908 }
12909 }
12910
12911 load_body->iseq_encoded = code;
12912 load_body->iseq_size = code_index;
12913
12914 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
12915 load_body->mark_bits.single = mark_offset_bits[0];
12916 }
12917 else {
12918 if (needs_bitmap) {
12919 load_body->mark_bits.list = mark_offset_bits;
12920 }
12921 else {
12922 load_body->mark_bits.list = 0;
12923 ruby_xfree(mark_offset_bits);
12924 }
12925 }
12926
12927 RUBY_ASSERT(code_index == iseq_size);
12928 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
12929 return code;
12930}
12931
12932static ibf_offset_t
12933ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12934{
12935 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
12936
12937 if (opt_num > 0) {
12938 IBF_W_ALIGN(VALUE);
12939 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
12940 }
12941 else {
12942 return ibf_dump_pos(dump);
12943 }
12944}
12945
12946static VALUE *
12947ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
12948{
12949 if (opt_num > 0) {
12950 VALUE *table = ALLOC_N(VALUE, opt_num+1);
12951 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
12952 return table;
12953 }
12954 else {
12955 return NULL;
12956 }
12957}
12958
12959static ibf_offset_t
12960ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
12961{
12962 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
12963
12964 if (kw) {
12965 struct rb_iseq_param_keyword dump_kw = *kw;
12966 int dv_num = kw->num - kw->required_num;
12967 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
12968 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
12969 int i;
12970
12971 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12972 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12973
12974 dump_kw.table = IBF_W(ids, ID, kw->num);
12975 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12976 IBF_W_ALIGN(struct rb_iseq_param_keyword);
12977 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12978 }
12979 else {
12980 return 0;
12981 }
12982}
12983
12984static const struct rb_iseq_param_keyword *
12985ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
12986{
12987 if (param_keyword_offset) {
12988 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
12989 int dv_num = kw->num - kw->required_num;
12990 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
12991
12992 int i;
12993 for (i=0; i<dv_num; i++) {
12994 dvs[i] = ibf_load_object(load, dvs[i]);
12995 }
12996
12997 // Will be set once the local table is loaded.
12998 kw->table = NULL;
12999
13000 kw->default_values = dvs;
13001 return kw;
13002 }
13003 else {
13004 return NULL;
13005 }
13006}
13007
13008static ibf_offset_t
13009ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13010{
13011 ibf_offset_t offset = ibf_dump_pos(dump);
13012 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13013
13014 unsigned int i;
13015 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13016 ibf_dump_write_small_value(dump, entries[i].line_no);
13017#ifdef USE_ISEQ_NODE_ID
13018 ibf_dump_write_small_value(dump, entries[i].node_id);
13019#endif
13020 ibf_dump_write_small_value(dump, entries[i].events);
13021 }
13022
13023 return offset;
13024}
13025
13026static struct iseq_insn_info_entry *
13027ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13028{
13029 ibf_offset_t reading_pos = body_offset;
13030 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13031
13032 unsigned int i;
13033 for (i = 0; i < size; i++) {
13034 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13035#ifdef USE_ISEQ_NODE_ID
13036 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13037#endif
13038 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13039 }
13040
13041 return entries;
13042}
13043
13044static ibf_offset_t
13045ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13046{
13047 ibf_offset_t offset = ibf_dump_pos(dump);
13048
13049 unsigned int last = 0;
13050 unsigned int i;
13051 for (i = 0; i < size; i++) {
13052 ibf_dump_write_small_value(dump, positions[i] - last);
13053 last = positions[i];
13054 }
13055
13056 return offset;
13057}
13058
13059static unsigned int *
13060ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13061{
13062 ibf_offset_t reading_pos = positions_offset;
13063 unsigned int *positions = ALLOC_N(unsigned int, size);
13064
13065 unsigned int last = 0;
13066 unsigned int i;
13067 for (i = 0; i < size; i++) {
13068 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13069 last = positions[i];
13070 }
13071
13072 return positions;
13073}
13074
13075static ibf_offset_t
13076ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13077{
13078 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13079 const int size = body->local_table_size;
13080 ID *table = ALLOCA_N(ID, size);
13081 int i;
13082
13083 for (i=0; i<size; i++) {
13084 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13085 if (v == 0) {
13086 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13087 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13088 }
13089 table[i] = v;
13090 }
13091
13092 IBF_W_ALIGN(ID);
13093 return ibf_dump_write(dump, table, sizeof(ID) * size);
13094}
13095
13096static ID *
13097ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13098{
13099 if (size > 0) {
13100 ID *table = IBF_R(local_table_offset, ID, size);
13101 int i;
13102
13103 for (i=0; i<size; i++) {
13104 table[i] = ibf_load_id(load, table[i]);
13105 }
13106 return table;
13107 }
13108 else {
13109 return NULL;
13110 }
13111}
13112
13113static ibf_offset_t
13114ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13115{
13116 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13117
13118 if (table) {
13119 int *iseq_indices = ALLOCA_N(int, table->size);
13120 unsigned int i;
13121
13122 for (i=0; i<table->size; i++) {
13123 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13124 }
13125
13126 const ibf_offset_t offset = ibf_dump_pos(dump);
13127
13128 for (i=0; i<table->size; i++) {
13129 ibf_dump_write_small_value(dump, iseq_indices[i]);
13130 ibf_dump_write_small_value(dump, table->entries[i].type);
13131 ibf_dump_write_small_value(dump, table->entries[i].start);
13132 ibf_dump_write_small_value(dump, table->entries[i].end);
13133 ibf_dump_write_small_value(dump, table->entries[i].cont);
13134 ibf_dump_write_small_value(dump, table->entries[i].sp);
13135 }
13136 return offset;
13137 }
13138 else {
13139 return ibf_dump_pos(dump);
13140 }
13141}
13142
13143static struct iseq_catch_table *
13144ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
13145{
13146 if (size) {
13147 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13148 table->size = size;
13149
13150 ibf_offset_t reading_pos = catch_table_offset;
13151
13152 unsigned int i;
13153 for (i=0; i<table->size; i++) {
13154 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13155 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13156 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13157 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13158 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13159 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13160
13161 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13162 }
13163 return table;
13164 }
13165 else {
13166 return NULL;
13167 }
13168}
13169
13170static ibf_offset_t
13171ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13172{
13173 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13174 const unsigned int ci_size = body->ci_size;
13175 const struct rb_call_data *cds = body->call_data;
13176
13177 ibf_offset_t offset = ibf_dump_pos(dump);
13178
13179 unsigned int i;
13180
13181 for (i = 0; i < ci_size; i++) {
13182 const struct rb_callinfo *ci = cds[i].ci;
13183 if (ci != NULL) {
13184 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13185 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13186 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13187
13188 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13189 if (kwarg) {
13190 int len = kwarg->keyword_len;
13191 ibf_dump_write_small_value(dump, len);
13192 for (int j=0; j<len; j++) {
13193 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13194 ibf_dump_write_small_value(dump, keyword);
13195 }
13196 }
13197 else {
13198 ibf_dump_write_small_value(dump, 0);
13199 }
13200 }
13201 else {
13202 // TODO: truncate NULL ci from call_data.
13203 ibf_dump_write_small_value(dump, (VALUE)-1);
13204 }
13205 }
13206
13207 return offset;
13208}
13209
13210 struct outer_variable_pair {
13211 ID id;
13212 VALUE name;
13213 VALUE val;
13214};
13215
13216 struct outer_variable_list {
13217 size_t num;
13218 struct outer_variable_pair pairs[1];
13219};
13220
13221static enum rb_id_table_iterator_result
13222store_outer_variable(ID id, VALUE val, void *dump)
13223{
13224 struct outer_variable_list *ovlist = dump;
13225 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13226 pair->id = id;
13227 pair->name = rb_id2str(id);
13228 pair->val = val;
13229 return ID_TABLE_CONTINUE;
13230}
13231
13232static int
13233outer_variable_cmp(const void *a, const void *b, void *arg)
13234{
13235 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13236 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13237 return rb_str_cmp(ap->name, bp->name);
13238}
13239
13240static ibf_offset_t
13241ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13242{
13243 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13244
13245 ibf_offset_t offset = ibf_dump_pos(dump);
13246
13247 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13248 ibf_dump_write_small_value(dump, (VALUE)size);
13249 if (size > 0) {
13250 VALUE buff;
13251 size_t buffsize =
13252 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13253 offsetof(struct outer_variable_list, pairs),
13254 rb_eArgError);
13255 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13256 ovlist->num = 0;
13257 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13258 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13259 for (size_t i = 0; i < size; ++i) {
13260 ID id = ovlist->pairs[i].id;
13261 ID val = ovlist->pairs[i].val;
13262 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13263 ibf_dump_write_small_value(dump, val);
13264 }
13265 }
13266
13267 return offset;
13268}
13269
13270/* note that we dump out rb_call_info but load back rb_call_data */
13271static void
13272ibf_load_ci_entries(const struct ibf_load *load,
13273 ibf_offset_t ci_entries_offset,
13274 unsigned int ci_size,
13275 struct rb_call_data **cd_ptr)
13276{
13277 ibf_offset_t reading_pos = ci_entries_offset;
13278
13279 unsigned int i;
13280
13281 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13282 *cd_ptr = cds;
13283
13284 for (i = 0; i < ci_size; i++) {
13285 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13286 if (mid_index != (VALUE)-1) {
13287 ID mid = ibf_load_id(load, mid_index);
13288 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13289 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13290
13291 struct rb_callinfo_kwarg *kwarg = NULL;
13292 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13293 if (kwlen > 0) {
13294 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13295 kwarg->references = 0;
13296 kwarg->keyword_len = kwlen;
13297 for (int j=0; j<kwlen; j++) {
13298 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13299 kwarg->keywords[j] = ibf_load_object(load, keyword);
13300 }
13301 }
13302
13303 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13304 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13305 cds[i].cc = vm_cc_empty();
13306 }
13307 else {
13308 // NULL ci
13309 cds[i].ci = NULL;
13310 cds[i].cc = NULL;
13311 }
13312 }
13313}
13314
13315static struct rb_id_table *
13316ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13317{
13318 ibf_offset_t reading_pos = outer_variables_offset;
13319
13320 struct rb_id_table *tbl = NULL;
13321
13322 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13323
13324 if (table_size > 0) {
13325 tbl = rb_id_table_create(table_size);
13326 }
13327
13328 for (size_t i = 0; i < table_size; i++) {
13329 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13330 VALUE value = ibf_load_small_value(load, &reading_pos);
13331 if (!key) key = rb_make_temporary_id(i);
13332 rb_id_table_insert(tbl, key, value);
13333 }
13334
13335 return tbl;
13336}
13337
13338static ibf_offset_t
13339ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13340{
13341 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13342
13343 unsigned int *positions;
13344
13345 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13346
13347 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13348 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13349 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13350
13351#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13352 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13353
13354 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13355 struct ibf_dump_buffer buffer;
13356 buffer.str = rb_str_new(0, 0);
13357 buffer.obj_table = ibf_dump_object_table_new();
13358 dump->current_buffer = &buffer;
13359#endif
13360
13361 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13362 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13363 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13364 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13365 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13366
13367 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13368 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13369 ruby_xfree(positions);
13370
13371 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13372 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13373 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13374 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13375 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13376 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13377 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13378 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13379
13380#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13381 ibf_offset_t local_obj_list_offset;
13382 unsigned int local_obj_list_size;
13383
13384 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13385#endif
13386
13387 ibf_offset_t body_offset = ibf_dump_pos(dump);
13388
13389 /* dump the constant body */
13390 unsigned int param_flags =
13391 (body->param.flags.has_lead << 0) |
13392 (body->param.flags.has_opt << 1) |
13393 (body->param.flags.has_rest << 2) |
13394 (body->param.flags.has_post << 3) |
13395 (body->param.flags.has_kw << 4) |
13396 (body->param.flags.has_kwrest << 5) |
13397 (body->param.flags.has_block << 6) |
13398 (body->param.flags.ambiguous_param0 << 7) |
13399 (body->param.flags.accepts_no_kwarg << 8) |
13400 (body->param.flags.ruby2_keywords << 9) |
13401 (body->param.flags.anon_rest << 10) |
13402 (body->param.flags.anon_kwrest << 11) |
13403 (body->param.flags.use_block << 12) |
13404 (body->param.flags.forwardable << 13) ;
13405
13406#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13407# define IBF_BODY_OFFSET(x) (x)
13408#else
13409# define IBF_BODY_OFFSET(x) (body_offset - (x))
13410#endif
13411
13412 ibf_dump_write_small_value(dump, body->type);
13413 ibf_dump_write_small_value(dump, body->iseq_size);
13414 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13415 ibf_dump_write_small_value(dump, bytecode_size);
13416 ibf_dump_write_small_value(dump, param_flags);
13417 ibf_dump_write_small_value(dump, body->param.size);
13418 ibf_dump_write_small_value(dump, body->param.lead_num);
13419 ibf_dump_write_small_value(dump, body->param.opt_num);
13420 ibf_dump_write_small_value(dump, body->param.rest_start);
13421 ibf_dump_write_small_value(dump, body->param.post_start);
13422 ibf_dump_write_small_value(dump, body->param.post_num);
13423 ibf_dump_write_small_value(dump, body->param.block_start);
13424 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13425 ibf_dump_write_small_value(dump, param_keyword_offset);
13426 ibf_dump_write_small_value(dump, location_pathobj_index);
13427 ibf_dump_write_small_value(dump, location_base_label_index);
13428 ibf_dump_write_small_value(dump, location_label_index);
13429 ibf_dump_write_small_value(dump, body->location.first_lineno);
13430 ibf_dump_write_small_value(dump, body->location.node_id);
13431 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13432 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13433 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13434 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13435 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13436 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13437 ibf_dump_write_small_value(dump, body->insns_info.size);
13438 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13439 ibf_dump_write_small_value(dump, catch_table_size);
13440 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13441 ibf_dump_write_small_value(dump, parent_iseq_index);
13442 ibf_dump_write_small_value(dump, local_iseq_index);
13443 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13444 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13445 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13446 ibf_dump_write_small_value(dump, body->variable.flip_count);
13447 ibf_dump_write_small_value(dump, body->local_table_size);
13448 ibf_dump_write_small_value(dump, body->ivc_size);
13449 ibf_dump_write_small_value(dump, body->icvarc_size);
13450 ibf_dump_write_small_value(dump, body->ise_size);
13451 ibf_dump_write_small_value(dump, body->ic_size);
13452 ibf_dump_write_small_value(dump, body->ci_size);
13453 ibf_dump_write_small_value(dump, body->stack_max);
13454 ibf_dump_write_small_value(dump, body->builtin_attrs);
13455 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13456
13457#undef IBF_BODY_OFFSET
13458
13459#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13460 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13461
13462 dump->current_buffer = saved_buffer;
13463 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13464
13465 ibf_offset_t offset = ibf_dump_pos(dump);
13466 ibf_dump_write_small_value(dump, iseq_start);
13467 ibf_dump_write_small_value(dump, iseq_length_bytes);
13468 ibf_dump_write_small_value(dump, body_offset);
13469
13470 ibf_dump_write_small_value(dump, local_obj_list_offset);
13471 ibf_dump_write_small_value(dump, local_obj_list_size);
13472
13473 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13474
13475 return offset;
13476#else
13477 return body_offset;
13478#endif
13479}
13480
13481static VALUE
13482ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13483{
13484 VALUE str = ibf_load_object(load, str_index);
13485 if (str != Qnil) {
13486 str = rb_fstring(str);
13487 }
13488 return str;
13489}
13490
13491static void
13492ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13493{
13494 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13495
13496 ibf_offset_t reading_pos = offset;
13497
13498#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13499 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13500 load->current_buffer = &load->global_buffer;
13501
13502 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13503 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13504 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13505
13506 struct ibf_load_buffer buffer;
13507 buffer.buff = load->global_buffer.buff + iseq_start;
13508 buffer.size = iseq_length_bytes;
13509 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13510 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13511 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13512
13513 load->current_buffer = &buffer;
13514 reading_pos = body_offset;
13515#endif
13516
13517#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13518# define IBF_BODY_OFFSET(x) (x)
13519#else
13520# define IBF_BODY_OFFSET(x) (offset - (x))
13521#endif
13522
13523 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13524 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13525 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13526 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13527 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13528 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13529 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13530 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13531 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13532 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13533 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13534 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13535 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13536 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13537 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13538 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13539 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13540 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13541 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13542 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13543 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13544 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13545 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13546 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13547 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13548 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13549 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13550 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13551 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13552 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13553 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13554 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13555 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13556 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13557 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13558 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13559
13560 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13561 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13562 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13563 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13564
13565 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13566 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13567 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13568 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13569
13570 // setup fname and dummy frame
13571 VALUE path = ibf_load_object(load, location_pathobj_index);
13572 {
13573 VALUE realpath = Qnil;
13574
13575 if (RB_TYPE_P(path, T_STRING)) {
13576 realpath = path = rb_fstring(path);
13577 }
13578 else if (RB_TYPE_P(path, T_ARRAY)) {
13579 VALUE pathobj = path;
13580 if (RARRAY_LEN(pathobj) != 2) {
13581 rb_raise(rb_eRuntimeError, "path object size mismatch");
13582 }
13583 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13584 realpath = RARRAY_AREF(pathobj, 1);
13585 if (!NIL_P(realpath)) {
13586 if (!RB_TYPE_P(realpath, T_STRING)) {
13587 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13588 "(%x), path=%+"PRIsVALUE,
13589 realpath, TYPE(realpath), path);
13590 }
13591 realpath = rb_fstring(realpath);
13592 }
13593 }
13594 else {
13595 rb_raise(rb_eRuntimeError, "unexpected path object");
13596 }
13597 rb_iseq_pathobj_set(iseq, path, realpath);
13598 }
13599
13600 // push dummy frame
13601 rb_execution_context_t *ec = GET_EC();
13602 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13603
13604#undef IBF_BODY_OFFSET
13605
13606 load_body->type = type;
13607 load_body->stack_max = stack_max;
13608 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13609 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13610 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13611 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13612 load_body->param.flags.has_kw = FALSE;
13613 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13614 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13615 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13616 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13617 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13618 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13619 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13620 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13621 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13622 load_body->param.size = param_size;
13623 load_body->param.lead_num = param_lead_num;
13624 load_body->param.opt_num = param_opt_num;
13625 load_body->param.rest_start = param_rest_start;
13626 load_body->param.post_start = param_post_start;
13627 load_body->param.post_num = param_post_num;
13628 load_body->param.block_start = param_block_start;
13629 load_body->local_table_size = local_table_size;
13630 load_body->ci_size = ci_size;
13631 load_body->insns_info.size = insns_info_size;
13632
13633 ISEQ_COVERAGE_SET(iseq, Qnil);
13634 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13635 load_body->variable.flip_count = variable_flip_count;
13636 load_body->variable.script_lines = Qnil;
13637
13638 load_body->location.first_lineno = location_first_lineno;
13639 load_body->location.node_id = location_node_id;
13640 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13641 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13642 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13643 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13644 load_body->builtin_attrs = builtin_attrs;
13645 load_body->prism = prism;
13646
13647 load_body->ivc_size = ivc_size;
13648 load_body->icvarc_size = icvarc_size;
13649 load_body->ise_size = ise_size;
13650 load_body->ic_size = ic_size;
13651
13652 if (ISEQ_IS_SIZE(load_body)) {
13653 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13654 }
13655 else {
13656 load_body->is_entries = NULL;
13657 }
13658 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13659 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13660 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13661 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13662 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13663 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13664 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13665 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13666 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
13667 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13668 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13669 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13670
13671 // This must be done after the local table is loaded.
13672 if (load_body->param.keyword != NULL) {
13673 RUBY_ASSERT(load_body->local_table);
13674 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13675 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13676 }
13677
13678 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13679#if VM_INSN_INFO_TABLE_IMPL == 2
13680 rb_iseq_insns_info_encode_positions(iseq);
13681#endif
13682
13683 rb_iseq_translate_threaded_code(iseq);
13684
13685#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13686 load->current_buffer = &load->global_buffer;
13687#endif
13688
13689 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13690 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13691
13692#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13693 load->current_buffer = saved_buffer;
13694#endif
13695 verify_call_cache(iseq);
13696
13697 RB_GC_GUARD(dummy_frame);
13698 rb_vm_pop_frame_no_int(ec);
13699}
13700
13701 struct ibf_dump_iseq_list_arg
13702{
13703 struct ibf_dump *dump;
13704 VALUE offset_list;
13705};
13706
13707static int
13708ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13709{
13710 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13711 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13712
13713 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13714 rb_ary_push(args->offset_list, UINT2NUM(offset));
13715
13716 return ST_CONTINUE;
13717}
13718
13719static void
13720ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13721{
13722 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13723
13724 struct ibf_dump_iseq_list_arg args;
13725 args.dump = dump;
13726 args.offset_list = offset_list;
13727
13728 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13729
13730 st_index_t i;
13731 st_index_t size = dump->iseq_table->num_entries;
13732 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13733
13734 for (i = 0; i < size; i++) {
13735 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13736 }
13737
13738 ibf_dump_align(dump, sizeof(ibf_offset_t));
13739 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13740 header->iseq_list_size = (unsigned int)size;
13741}
13742
13743#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13744
13745/*
13746 * Binary format
13747 * - ibf_object_header
13748 * - ibf_object_xxx (xxx is type)
13749 */
13750
13751 struct ibf_object_header {
13752 unsigned int type: 5;
13753 unsigned int special_const: 1;
13754 unsigned int frozen: 1;
13755 unsigned int internal: 1;
13756};
13757
13758enum ibf_object_class_index {
13759 IBF_OBJECT_CLASS_OBJECT,
13760 IBF_OBJECT_CLASS_ARRAY,
13761 IBF_OBJECT_CLASS_STANDARD_ERROR,
13762 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13763 IBF_OBJECT_CLASS_TYPE_ERROR,
13764 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13765};
13766
13767 struct ibf_object_regexp {
13768 long srcstr;
13769 char option;
13770};
13771
13772 struct ibf_object_hash {
13773 long len;
13774 long keyval[FLEX_ARY_LEN];
13775};
13776
13777 struct ibf_object_struct_range {
13778 long class_index;
13779 long len;
13780 long beg;
13781 long end;
13782 int excl;
13783};
13784
13785 struct ibf_object_bignum {
13786 ssize_t slen;
13787 BDIGIT digits[FLEX_ARY_LEN];
13788};
13789
13790enum ibf_object_data_type {
13791 IBF_OBJECT_DATA_ENCODING,
13792};
13793
13794 struct ibf_object_complex_rational {
13795 long a, b;
13796};
13797
13798 struct ibf_object_symbol {
13799 long str;
13800};
13801
13802#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13803 ((((offset) - 1) / (align) + 1) * (align))
13804#define IBF_OBJBODY(type, offset) (const type *)\
13805 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13806
13807static const void *
13808ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13809{
13810 if (offset >= load->current_buffer->size) {
13811 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13812 }
13813 return load->current_buffer->buff + offset;
13814}
13815
13816NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13817
13818static void
13819ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13820{
13821 char buff[0x100];
13822 rb_raw_obj_info(buff, sizeof(buff), obj);
13823 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13824}
13825
13826NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13827
13828static VALUE
13829ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13830{
13831 rb_raise(rb_eArgError, "unsupported");
13832 UNREACHABLE_RETURN(Qnil);
13833}
13834
13835static void
13836ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13837{
13838 enum ibf_object_class_index cindex;
13839 if (obj == rb_cObject) {
13840 cindex = IBF_OBJECT_CLASS_OBJECT;
13841 }
13842 else if (obj == rb_cArray) {
13843 cindex = IBF_OBJECT_CLASS_ARRAY;
13844 }
13845 else if (obj == rb_eStandardError) {
13846 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13847 }
13848 else if (obj == rb_eNoMatchingPatternError) {
13849 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13850 }
13851 else if (obj == rb_eTypeError) {
13852 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13853 }
13854 else if (obj == rb_eNoMatchingPatternKeyError) {
13855 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13856 }
13857 else {
13858 rb_obj_info_dump(obj);
13859 rb_p(obj);
13860 rb_bug("unsupported class");
13861 }
13862 ibf_dump_write_small_value(dump, (VALUE)cindex);
13863}
13864
13865static VALUE
13866ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13867{
13868 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13869
13870 switch (cindex) {
13871 case IBF_OBJECT_CLASS_OBJECT:
13872 return rb_cObject;
13873 case IBF_OBJECT_CLASS_ARRAY:
13874 return rb_cArray;
13875 case IBF_OBJECT_CLASS_STANDARD_ERROR:
13876 return rb_eStandardError;
13877 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13878 return rb_eNoMatchingPatternError;
13879 case IBF_OBJECT_CLASS_TYPE_ERROR:
13880 return rb_eTypeError;
13881 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13882 return rb_eNoMatchingPatternKeyError;
13883 }
13884
13885 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
13886}
13887
13888
13889static void
13890ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
13891{
13892 double dbl = RFLOAT_VALUE(obj);
13893 (void)IBF_W(&dbl, double, 1);
13894}
13895
13896static VALUE
13897ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13898{
13899 const double *dblp = IBF_OBJBODY(double, offset);
13900 return DBL2NUM(*dblp);
13901}
13902
13903static void
13904ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
13905{
13906 long encindex = (long)rb_enc_get_index(obj);
13907 long len = RSTRING_LEN(obj);
13908 const char *ptr = RSTRING_PTR(obj);
13909
13910 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13911 rb_encoding *enc = rb_enc_from_index((int)encindex);
13912 const char *enc_name = rb_enc_name(enc);
13913 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
13914 }
13915
13916 ibf_dump_write_small_value(dump, encindex);
13917 ibf_dump_write_small_value(dump, len);
13918 IBF_WP(ptr, char, len);
13919}
13920
13921static VALUE
13922ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13923{
13924 ibf_offset_t reading_pos = offset;
13925
13926 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13927 const long len = (long)ibf_load_small_value(load, &reading_pos);
13928 const char *ptr = load->current_buffer->buff + reading_pos;
13929
13930 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13931 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13932 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13933 }
13934
13935 VALUE str;
13936 if (header->frozen && !header->internal) {
13937 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
13938 }
13939 else {
13940 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
13941
13942 if (header->internal) rb_obj_hide(str);
13943 if (header->frozen) str = rb_fstring(str);
13944 }
13945 return str;
13946}
13947
13948static void
13949ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
13950{
13951 VALUE srcstr = RREGEXP_SRC(obj);
13952 struct ibf_object_regexp regexp;
13953 regexp.option = (char)rb_reg_options(obj);
13954 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
13955
13956 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
13957 ibf_dump_write_small_value(dump, regexp.srcstr);
13958}
13959
13960static VALUE
13961ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13962{
13963 struct ibf_object_regexp regexp;
13964 regexp.option = ibf_load_byte(load, &offset);
13965 regexp.srcstr = ibf_load_small_value(load, &offset);
13966
13967 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
13968 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
13969
13970 if (header->internal) rb_obj_hide(reg);
13971 if (header->frozen) rb_obj_freeze(reg);
13972
13973 return reg;
13974}
13975
13976static void
13977ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
13978{
13979 long i, len = RARRAY_LEN(obj);
13980 ibf_dump_write_small_value(dump, len);
13981 for (i=0; i<len; i++) {
13982 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
13983 ibf_dump_write_small_value(dump, index);
13984 }
13985}
13986
13987static VALUE
13988ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13989{
13990 ibf_offset_t reading_pos = offset;
13991
13992 const long len = (long)ibf_load_small_value(load, &reading_pos);
13993
13994 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
13995 int i;
13996
13997 for (i=0; i<len; i++) {
13998 const VALUE index = ibf_load_small_value(load, &reading_pos);
13999 rb_ary_push(ary, ibf_load_object(load, index));
14000 }
14001
14002 if (header->frozen) rb_ary_freeze(ary);
14003
14004 return ary;
14005}
14006
14007static int
14008ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14009{
14010 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14011
14012 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14013 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14014
14015 ibf_dump_write_small_value(dump, key_index);
14016 ibf_dump_write_small_value(dump, val_index);
14017 return ST_CONTINUE;
14018}
14019
14020static void
14021ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14022{
14023 long len = RHASH_SIZE(obj);
14024 ibf_dump_write_small_value(dump, (VALUE)len);
14025
14026 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14027}
14028
14029static VALUE
14030ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14031{
14032 long len = (long)ibf_load_small_value(load, &offset);
14033 VALUE obj = rb_hash_new_with_size(len);
14034 int i;
14035
14036 for (i = 0; i < len; i++) {
14037 VALUE key_index = ibf_load_small_value(load, &offset);
14038 VALUE val_index = ibf_load_small_value(load, &offset);
14039
14040 VALUE key = ibf_load_object(load, key_index);
14041 VALUE val = ibf_load_object(load, val_index);
14042 rb_hash_aset(obj, key, val);
14043 }
14044 rb_hash_rehash(obj);
14045
14046 if (header->internal) rb_obj_hide(obj);
14047 if (header->frozen) rb_obj_freeze(obj);
14048
14049 return obj;
14050}
14051
14052static void
14053ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14054{
14055 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14056 struct ibf_object_struct_range range;
14057 VALUE beg, end;
14058 IBF_ZERO(range);
14059 range.len = 3;
14060 range.class_index = 0;
14061
14062 rb_range_values(obj, &beg, &end, &range.excl);
14063 range.beg = (long)ibf_dump_object(dump, beg);
14064 range.end = (long)ibf_dump_object(dump, end);
14065
14066 IBF_W_ALIGN(struct ibf_object_struct_range);
14067 IBF_WV(range);
14068 }
14069 else {
14070 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14071 rb_class_name(CLASS_OF(obj)));
14072 }
14073}
14074
14075static VALUE
14076ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14077{
14078 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14079 VALUE beg = ibf_load_object(load, range->beg);
14080 VALUE end = ibf_load_object(load, range->end);
14081 VALUE obj = rb_range_new(beg, end, range->excl);
14082 if (header->internal) rb_obj_hide(obj);
14083 if (header->frozen) rb_obj_freeze(obj);
14084 return obj;
14085}
14086
14087static void
14088ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14089{
14090 ssize_t len = BIGNUM_LEN(obj);
14091 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14092 BDIGIT *d = BIGNUM_DIGITS(obj);
14093
14094 (void)IBF_W(&slen, ssize_t, 1);
14095 IBF_WP(d, BDIGIT, len);
14096}
14097
14098static VALUE
14099ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14100{
14101 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14102 int sign = bignum->slen > 0;
14103 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14104 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14105 INTEGER_PACK_LSWORD_FIRST |
14106 INTEGER_PACK_NATIVE_BYTE_ORDER;
14107 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14108 big_unpack_flags |
14109 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14110 if (header->internal) rb_obj_hide(obj);
14111 if (header->frozen) rb_obj_freeze(obj);
14112 return obj;
14113}
14114
14115static void
14116ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14117{
14118 if (rb_data_is_encoding(obj)) {
14119 rb_encoding *enc = rb_to_encoding(obj);
14120 const char *name = rb_enc_name(enc);
14121 long len = strlen(name) + 1;
14122 long data[2];
14123 data[0] = IBF_OBJECT_DATA_ENCODING;
14124 data[1] = len;
14125 (void)IBF_W(data, long, 2);
14126 IBF_WP(name, char, len);
14127 }
14128 else {
14129 ibf_dump_object_unsupported(dump, obj);
14130 }
14131}
14132
14133static VALUE
14134ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14135{
14136 const long *body = IBF_OBJBODY(long, offset);
14137 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14138 /* const long len = body[1]; */
14139 const char *data = (const char *)&body[2];
14140
14141 switch (type) {
14142 case IBF_OBJECT_DATA_ENCODING:
14143 {
14144 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14145 return encobj;
14146 }
14147 }
14148
14149 return ibf_load_object_unsupported(load, header, offset);
14150}
14151
14152static void
14153ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14154{
14155 long data[2];
14156 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14157 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14158
14159 (void)IBF_W(data, long, 2);
14160}
14161
14162static VALUE
14163ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14164{
14165 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14166 VALUE a = ibf_load_object(load, nums->a);
14167 VALUE b = ibf_load_object(load, nums->b);
14168 VALUE obj = header->type == T_COMPLEX ?
14169 rb_complex_new(a, b) : rb_rational_new(a, b);
14170
14171 if (header->internal) rb_obj_hide(obj);
14172 if (header->frozen) rb_obj_freeze(obj);
14173 return obj;
14174}
14175
14176static void
14177ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14178{
14179 ibf_dump_object_string(dump, rb_sym2str(obj));
14180}
14181
14182static VALUE
14183ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14184{
14185 ibf_offset_t reading_pos = offset;
14186
14187 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14188 const long len = (long)ibf_load_small_value(load, &reading_pos);
14189 const char *ptr = load->current_buffer->buff + reading_pos;
14190
14191 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14192 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14193 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14194 }
14195
14196 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14197 return ID2SYM(id);
14198}
14199
14200typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14201static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14202 ibf_dump_object_unsupported, /* T_NONE */
14203 ibf_dump_object_unsupported, /* T_OBJECT */
14204 ibf_dump_object_class, /* T_CLASS */
14205 ibf_dump_object_unsupported, /* T_MODULE */
14206 ibf_dump_object_float, /* T_FLOAT */
14207 ibf_dump_object_string, /* T_STRING */
14208 ibf_dump_object_regexp, /* T_REGEXP */
14209 ibf_dump_object_array, /* T_ARRAY */
14210 ibf_dump_object_hash, /* T_HASH */
14211 ibf_dump_object_struct, /* T_STRUCT */
14212 ibf_dump_object_bignum, /* T_BIGNUM */
14213 ibf_dump_object_unsupported, /* T_FILE */
14214 ibf_dump_object_data, /* T_DATA */
14215 ibf_dump_object_unsupported, /* T_MATCH */
14216 ibf_dump_object_complex_rational, /* T_COMPLEX */
14217 ibf_dump_object_complex_rational, /* T_RATIONAL */
14218 ibf_dump_object_unsupported, /* 0x10 */
14219 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14220 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14221 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14222 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14223 ibf_dump_object_unsupported, /* T_FIXNUM */
14224 ibf_dump_object_unsupported, /* T_UNDEF */
14225 ibf_dump_object_unsupported, /* 0x17 */
14226 ibf_dump_object_unsupported, /* 0x18 */
14227 ibf_dump_object_unsupported, /* 0x19 */
14228 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14229 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14230 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14231 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14232 ibf_dump_object_unsupported, /* 0x1e */
14233 ibf_dump_object_unsupported, /* 0x1f */
14234};
14235
14236static void
14237ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14238{
14239 unsigned char byte =
14240 (header.type << 0) |
14241 (header.special_const << 5) |
14242 (header.frozen << 6) |
14243 (header.internal << 7);
14244
14245 IBF_WV(byte);
14246}
14247
14248static struct ibf_object_header
14249ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14250{
14251 unsigned char byte = ibf_load_byte(load, offset);
14252
14253 struct ibf_object_header header;
14254 header.type = (byte >> 0) & 0x1f;
14255 header.special_const = (byte >> 5) & 0x01;
14256 header.frozen = (byte >> 6) & 0x01;
14257 header.internal = (byte >> 7) & 0x01;
14258
14259 return header;
14260}
14261
14262static ibf_offset_t
14263ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14264{
14265 struct ibf_object_header obj_header;
14266 ibf_offset_t current_offset;
14267 IBF_ZERO(obj_header);
14268 obj_header.type = TYPE(obj);
14269
14270 IBF_W_ALIGN(ibf_offset_t);
14271 current_offset = ibf_dump_pos(dump);
14272
14273 if (SPECIAL_CONST_P(obj) &&
14274 ! (SYMBOL_P(obj) ||
14275 RB_FLOAT_TYPE_P(obj))) {
14276 obj_header.special_const = TRUE;
14277 obj_header.frozen = TRUE;
14278 obj_header.internal = TRUE;
14279 ibf_dump_object_object_header(dump, obj_header);
14280 ibf_dump_write_small_value(dump, obj);
14281 }
14282 else {
14283 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14284 obj_header.special_const = FALSE;
14285 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14286 ibf_dump_object_object_header(dump, obj_header);
14287 (*dump_object_functions[obj_header.type])(dump, obj);
14288 }
14289
14290 return current_offset;
14291}
14292
14293typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14294static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14295 ibf_load_object_unsupported, /* T_NONE */
14296 ibf_load_object_unsupported, /* T_OBJECT */
14297 ibf_load_object_class, /* T_CLASS */
14298 ibf_load_object_unsupported, /* T_MODULE */
14299 ibf_load_object_float, /* T_FLOAT */
14300 ibf_load_object_string, /* T_STRING */
14301 ibf_load_object_regexp, /* T_REGEXP */
14302 ibf_load_object_array, /* T_ARRAY */
14303 ibf_load_object_hash, /* T_HASH */
14304 ibf_load_object_struct, /* T_STRUCT */
14305 ibf_load_object_bignum, /* T_BIGNUM */
14306 ibf_load_object_unsupported, /* T_FILE */
14307 ibf_load_object_data, /* T_DATA */
14308 ibf_load_object_unsupported, /* T_MATCH */
14309 ibf_load_object_complex_rational, /* T_COMPLEX */
14310 ibf_load_object_complex_rational, /* T_RATIONAL */
14311 ibf_load_object_unsupported, /* 0x10 */
14312 ibf_load_object_unsupported, /* T_NIL */
14313 ibf_load_object_unsupported, /* T_TRUE */
14314 ibf_load_object_unsupported, /* T_FALSE */
14315 ibf_load_object_symbol,
14316 ibf_load_object_unsupported, /* T_FIXNUM */
14317 ibf_load_object_unsupported, /* T_UNDEF */
14318 ibf_load_object_unsupported, /* 0x17 */
14319 ibf_load_object_unsupported, /* 0x18 */
14320 ibf_load_object_unsupported, /* 0x19 */
14321 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14322 ibf_load_object_unsupported, /* T_NODE 0x1b */
14323 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14324 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14325 ibf_load_object_unsupported, /* 0x1e */
14326 ibf_load_object_unsupported, /* 0x1f */
14327};
14328
14329static VALUE
14330ibf_load_object(const struct ibf_load *load, VALUE object_index)
14331{
14332 if (object_index == 0) {
14333 return Qnil;
14334 }
14335 else {
14336 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14337 if (!obj) {
14338 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14339 ibf_offset_t offset = offsets[object_index];
14340 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14341
14342#if IBF_ISEQ_DEBUG
14343 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14344 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14345 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14346 header.type, header.special_const, header.frozen, header.internal);
14347#endif
14348 if (offset >= load->current_buffer->size) {
14349 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14350 }
14351
14352 if (header.special_const) {
14353 ibf_offset_t reading_pos = offset;
14354
14355 obj = ibf_load_small_value(load, &reading_pos);
14356 }
14357 else {
14358 obj = (*load_object_functions[header.type])(load, &header, offset);
14359 }
14360
14361 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14362 }
14363#if IBF_ISEQ_DEBUG
14364 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14365 object_index, obj);
14366#endif
14367 return obj;
14368 }
14369}
14370
14371 struct ibf_dump_object_list_arg
14372{
14373 struct ibf_dump *dump;
14374 VALUE offset_list;
14375};
14376
14377static int
14378ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14379{
14380 VALUE obj = (VALUE)key;
14381 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14382
14383 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14384 rb_ary_push(args->offset_list, UINT2NUM(offset));
14385
14386 return ST_CONTINUE;
14387}
14388
14389static void
14390ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14391{
14392 st_table *obj_table = dump->current_buffer->obj_table;
14393 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14394
14395 struct ibf_dump_object_list_arg args;
14396 args.dump = dump;
14397 args.offset_list = offset_list;
14398
14399 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14400
14401 IBF_W_ALIGN(ibf_offset_t);
14402 *obj_list_offset = ibf_dump_pos(dump);
14403
14404 st_index_t size = obj_table->num_entries;
14405 st_index_t i;
14406
14407 for (i=0; i<size; i++) {
14408 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14409 IBF_WV(offset);
14410 }
14411
14412 *obj_list_size = (unsigned int)size;
14413}
14414
14415static void
14416ibf_dump_mark(void *ptr)
14417{
14418 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14419 rb_gc_mark(dump->global_buffer.str);
14420
14421 rb_mark_set(dump->global_buffer.obj_table);
14422 rb_mark_set(dump->iseq_table);
14423}
14424
14425static void
14426ibf_dump_free(void *ptr)
14427{
14428 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14429 if (dump->global_buffer.obj_table) {
14430 st_free_table(dump->global_buffer.obj_table);
14431 dump->global_buffer.obj_table = 0;
14432 }
14433 if (dump->iseq_table) {
14434 st_free_table(dump->iseq_table);
14435 dump->iseq_table = 0;
14436 }
14437}
14438
14439static size_t
14440ibf_dump_memsize(const void *ptr)
14441{
14442 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14443 size_t size = 0;
14444 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14445 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14446 return size;
14447}
14448
14449static const rb_data_type_t ibf_dump_type = {
14450 "ibf_dump",
14451 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14452 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14453};
14454
14455static void
14456ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14457{
14458 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14459 dump->iseq_table = NULL;
14460
14461 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14462 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14463 dump->iseq_table = st_init_numtable(); /* need free */
14464
14465 dump->current_buffer = &dump->global_buffer;
14466}
14467
14468 VALUE
14469rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14470{
14471 struct ibf_dump *dump;
14472 struct ibf_header header = {{0}};
14473 VALUE dump_obj;
14474 VALUE str;
14475
14476 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14477 ISEQ_BODY(iseq)->local_iseq != iseq) {
14478 rb_raise(rb_eRuntimeError, "should be top of iseq");
14479 }
14480 if (RTEST(ISEQ_COVERAGE(iseq))) {
14481 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14482 }
14483
14484 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14485 ibf_dump_setup(dump, dump_obj);
14486
14487 ibf_dump_write(dump, &header, sizeof(header));
14488 ibf_dump_iseq(dump, iseq);
14489
14490 header.magic[0] = 'Y'; /* YARB */
14491 header.magic[1] = 'A';
14492 header.magic[2] = 'R';
14493 header.magic[3] = 'B';
14494 header.major_version = IBF_MAJOR_VERSION;
14495 header.minor_version = IBF_MINOR_VERSION;
14496 header.endian = IBF_ENDIAN_MARK;
14497 header.wordsize = (uint8_t)SIZEOF_VALUE;
14498 ibf_dump_iseq_list(dump, &header);
14499 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14500 header.size = ibf_dump_pos(dump);
14501
14502 if (RTEST(opt)) {
14503 VALUE opt_str = opt;
14504 const char *ptr = StringValuePtr(opt_str);
14505 header.extra_size = RSTRING_LENINT(opt_str);
14506 ibf_dump_write(dump, ptr, header.extra_size);
14507 }
14508 else {
14509 header.extra_size = 0;
14510 }
14511
14512 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14513
14514 str = dump->global_buffer.str;
14515 RB_GC_GUARD(dump_obj);
14516 return str;
14517}
14518
14519static const ibf_offset_t *
14520ibf_iseq_list(const struct ibf_load *load)
14521{
14522 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14523}
14524
14525void
14526rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14527{
14528 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14529 rb_iseq_t *prev_src_iseq = load->iseq;
14530 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14531 load->iseq = iseq;
14532#if IBF_ISEQ_DEBUG
14533 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14534 iseq->aux.loader.index, offset,
14535 load->header->size);
14536#endif
14537 ibf_load_iseq_each(load, iseq, offset);
14538 ISEQ_COMPILE_DATA_CLEAR(iseq);
14539 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14540 rb_iseq_init_trace(iseq);
14541 load->iseq = prev_src_iseq;
14542}
14543
14544#if USE_LAZY_LOAD
14545const rb_iseq_t *
14546rb_iseq_complete(const rb_iseq_t *iseq)
14547{
14548 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14549 return iseq;
14550}
14551#endif
14552
14553static rb_iseq_t *
14554ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14555{
14556 int iseq_index = (int)(VALUE)index_iseq;
14557
14558#if IBF_ISEQ_DEBUG
14559 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14560 (void *)index_iseq, (void *)load->iseq_list);
14561#endif
14562 if (iseq_index == -1) {
14563 return NULL;
14564 }
14565 else {
14566 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14567
14568#if IBF_ISEQ_DEBUG
14569 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14570#endif
14571 if (iseqv) {
14572 return (rb_iseq_t *)iseqv;
14573 }
14574 else {
14575 rb_iseq_t *iseq = iseq_imemo_alloc();
14576#if IBF_ISEQ_DEBUG
14577 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14578#endif
14579 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14580 iseq->aux.loader.obj = load->loader_obj;
14581 iseq->aux.loader.index = iseq_index;
14582#if IBF_ISEQ_DEBUG
14583 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14584 (void *)iseq, (void *)load->loader_obj, iseq_index);
14585#endif
14586 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14587
14588 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14589#if IBF_ISEQ_DEBUG
14590 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14591#endif
14592 rb_ibf_load_iseq_complete(iseq);
14593 }
14594
14595#if IBF_ISEQ_DEBUG
14596 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14597 (void *)iseq, (void *)load->iseq);
14598#endif
14599 return iseq;
14600 }
14601 }
14602}
14603
14604static void
14605ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14606{
14607 struct ibf_header *header = (struct ibf_header *)bytes;
14608 load->loader_obj = loader_obj;
14609 load->global_buffer.buff = bytes;
14610 load->header = header;
14611 load->global_buffer.size = header->size;
14612 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14613 load->global_buffer.obj_list_size = header->global_object_list_size;
14614 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14615 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14616 load->iseq = NULL;
14617
14618 load->current_buffer = &load->global_buffer;
14619
14620 if (size < header->size) {
14621 rb_raise(rb_eRuntimeError, "broken binary format");
14622 }
14623 if (strncmp(header->magic, "YARB", 4) != 0) {
14624 rb_raise(rb_eRuntimeError, "unknown binary format");
14625 }
14626 if (header->major_version != IBF_MAJOR_VERSION ||
14627 header->minor_version != IBF_MINOR_VERSION) {
14628 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14629 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14630 }
14631 if (header->endian != IBF_ENDIAN_MARK) {
14632 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14633 }
14634 if (header->wordsize != SIZEOF_VALUE) {
14635 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14636 }
14637 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14638 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14639 header->iseq_list_offset);
14640 }
14641 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14642 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14643 load->global_buffer.obj_list_offset);
14644 }
14645}
14646
14647static void
14648ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14649{
14650 StringValue(str);
14651
14652 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14653 rb_raise(rb_eRuntimeError, "broken binary format");
14654 }
14655
14656 if (USE_LAZY_LOAD) {
14657 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14658 }
14659
14660 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14661 RB_OBJ_WRITE(loader_obj, &load->str, str);
14662}
14663
14664static void
14665ibf_loader_mark(void *ptr)
14666{
14667 struct ibf_load *load = (struct ibf_load *)ptr;
14668 rb_gc_mark(load->str);
14669 rb_gc_mark(load->iseq_list);
14670 rb_gc_mark(load->global_buffer.obj_list);
14671}
14672
14673static void
14674ibf_loader_free(void *ptr)
14675{
14676 struct ibf_load *load = (struct ibf_load *)ptr;
14677 ruby_xfree(load);
14678}
14679
14680static size_t
14681ibf_loader_memsize(const void *ptr)
14682{
14683 return sizeof(struct ibf_load);
14684}
14685
14686static const rb_data_type_t ibf_load_type = {
14687 "ibf_loader",
14688 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14689 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14690};
14691
14692const rb_iseq_t *
14693rb_iseq_ibf_load(VALUE str)
14694{
14695 struct ibf_load *load;
14696 rb_iseq_t *iseq;
14697 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14698
14699 ibf_load_setup(load, loader_obj, str);
14700 iseq = ibf_load_iseq(load, 0);
14701
14702 RB_GC_GUARD(loader_obj);
14703 return iseq;
14704}
14705
14706const rb_iseq_t *
14707rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14708{
14709 struct ibf_load *load;
14710 rb_iseq_t *iseq;
14711 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14712
14713 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14714 iseq = ibf_load_iseq(load, 0);
14715
14716 RB_GC_GUARD(loader_obj);
14717 return iseq;
14718}
14719
14720 VALUE
14721rb_iseq_ibf_load_extra_data(VALUE str)
14722{
14723 struct ibf_load *load;
14724 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14725 VALUE extra_str;
14726
14727 ibf_load_setup(load, loader_obj, str);
14728 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14729 RB_GC_GUARD(loader_obj);
14730 return extra_str;
14731}
14732
14733#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
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_is_const_id
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1063
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:1087
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:3680
rb_str_tmp_new
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1675
rb_str_hash_cmp
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4049
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:4035
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:3448
rb_str_cmp
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4105
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:3922
rb_str_freeze
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3180
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:951
rb_sym2str
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:970
rb_sym2id
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:917
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:3115
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::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:150
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:468
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:9041
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:29
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:12319
ibf_dump_iseq_list_arg
Definition compile.c:13702
ibf_dump_object_list_arg
Definition compile.c:14372
ibf_dump
Definition compile.c:12324
ibf_header
Definition compile.c:12304
ibf_load_buffer
Definition compile.c:12330
ibf_load
Definition compile.c:12339
ibf_object_bignum
Definition compile.c:13785
ibf_object_complex_rational
Definition compile.c:13794
ibf_object_hash
Definition compile.c:13772
ibf_object_header
Definition compile.c:13751
ibf_object_regexp
Definition compile.c:13767
ibf_object_struct_range
Definition compile.c:13777
ibf_object_symbol
Definition compile.c:13798
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:5497
masgn_state
Definition compile.c:5506
outer_variable_list
Definition compile.c:13216
outer_variable_pair
Definition compile.c:13210
pinned_list
Definition compile.c:12349
rb_args_info
Definition rubyparser.h:739
rb_builtin_function
Definition builtin.h:6
rb_call_data
Definition vm_callinfo.h:572
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