Ruby 3.4.1p0 (2024-12-25 revision 48d4efcb85000e1ebae42004e963b5d0cedddcf2)
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
54typedef struct iseq_link_element {
55 enum {
56 ISEQ_ELEMENT_ANCHOR,
57 ISEQ_ELEMENT_LABEL,
58 ISEQ_ELEMENT_INSN,
59 ISEQ_ELEMENT_ADJUST,
60 ISEQ_ELEMENT_TRACE,
61 } type;
62 struct iseq_link_element *next;
63 struct iseq_link_element *prev;
64} LINK_ELEMENT;
65
66typedef 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
78typedef struct iseq_label_data {
79 LINK_ELEMENT link;
80 int label_no;
81 int position;
82 int sc_state;
83 int sp;
84 int refcnt;
85 unsigned int set: 1;
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
88} LABEL;
89
90typedef struct iseq_insn_data {
91 LINK_ELEMENT link;
92 enum ruby_vminsn_type insn_id;
93 int operand_size;
94 int sc_state;
95 VALUE *operands;
96 struct {
97 int line_no;
98 int node_id;
99 rb_event_flag_t events;
100 } insn_info;
101} INSN;
102
103typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
122 const void *ensure_node;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
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
362#endif
363RBIMPL_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
846VALUE
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
862VALUE
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
1001VALUE *
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 {
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 {
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:
2268 }
2269}
2270
2271static const struct st_hash_type cdhash_type = {
2272 rb_iseq_cdhash_cmp,
2273 rb_iseq_cdhash_hash,
2274};
2275
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{
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):
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];
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];
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
5303VALUE
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
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
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;
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,
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{
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
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
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;
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 (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10180 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10181 (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)) &&
10182 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10183 !frozen_string_literal_p(iseq) &&
10184 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10185 {
10186 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10187 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10188 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10189 if (!popped) {
10190 ADD_INSN(ret, node, swap);
10191 ADD_INSN1(ret, node, topn, INT2FIX(1));
10192 }
10193 ADD_INSN2(ret, node, opt_aset_with, str,
10194 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10195 RB_OBJ_WRITTEN(iseq, Qundef, str);
10196 ADD_INSN(ret, node, pop);
10197 return COMPILE_OK;
10198 }
10199
10200 INIT_ANCHOR(recv);
10201 INIT_ANCHOR(args);
10202 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10203 CHECK(!NIL_P(argc));
10204
10205 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10206 CHECK(asgnflag != -1);
10207 flag |= (unsigned int)asgnflag;
10208
10209 debugp_param("argc", argc);
10210 debugp_param("nd_mid", ID2SYM(mid));
10211
10212 if (!rb_is_attrset_id(mid)) {
10213 /* safe nav attr */
10214 mid = rb_id_attrset(mid);
10215 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10216 }
10217 if (!popped) {
10218 ADD_INSN(ret, node, putnil);
10219 ADD_SEQ(ret, recv);
10220 ADD_SEQ(ret, args);
10221
10222 if (flag & VM_CALL_ARGS_SPLAT) {
10223 ADD_INSN(ret, node, dup);
10224 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10225 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10226 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10227 ADD_INSN (ret, node, pop);
10228 }
10229 else {
10230 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10231 }
10232 }
10233 else {
10234 ADD_SEQ(ret, recv);
10235 ADD_SEQ(ret, args);
10236 }
10237 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10238 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10239 ADD_INSN(ret, node, pop);
10240 return COMPILE_OK;
10241}
10242
10243static int
10244compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10245{
10246 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10247 ADD_SEQ(ret, sub);
10248
10249 if (copy) {
10250 /*
10251 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10252 * NEW_LIST(value, loc), loc);
10253 */
10254 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10255 }
10256 else {
10257 /*
10258 * NEW_CALL(fcore, rb_intern("make_shareable"),
10259 * NEW_LIST(value, loc), loc);
10260 */
10261 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10262 }
10263
10264 return COMPILE_OK;
10265}
10266
10267static VALUE
10268node_const_decl_val(const NODE *node)
10269{
10270 VALUE path;
10271 switch (nd_type(node)) {
10272 case NODE_CDECL:
10273 if (RNODE_CDECL(node)->nd_vid) {
10274 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10275 goto end;
10276 }
10277 else {
10278 node = RNODE_CDECL(node)->nd_else;
10279 }
10280 break;
10281 case NODE_COLON2:
10282 break;
10283 case NODE_COLON3:
10284 // ::Const
10285 path = rb_str_new_cstr("::");
10286 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10287 goto end;
10288 default:
10289 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10291 }
10292
10293 path = rb_ary_new();
10294 if (node) {
10295 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10296 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10297 }
10298 if (node && nd_type_p(node, NODE_CONST)) {
10299 // Const::Name
10300 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10301 }
10302 else if (node && nd_type_p(node, NODE_COLON3)) {
10303 // ::Const::Name
10304 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10305 rb_ary_push(path, rb_str_new(0, 0));
10306 }
10307 else {
10308 // expression::Name
10309 rb_ary_push(path, rb_str_new_cstr("..."));
10310 }
10311 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10312 }
10313 end:
10314 path = rb_fstring(path);
10315 return path;
10316}
10317
10318static VALUE
10319const_decl_path(NODE *dest)
10320{
10321 VALUE path = Qnil;
10322 if (!nd_type_p(dest, NODE_CALL)) {
10323 path = node_const_decl_val(dest);
10324 }
10325 return path;
10326}
10327
10328static int
10329compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10330{
10331 /*
10332 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10333 */
10334 VALUE path = const_decl_path(dest);
10335 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10336 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10337 ADD_INSN1(ret, value, putobject, path);
10338 RB_OBJ_WRITTEN(iseq, Qundef, path);
10339 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10340
10341 return COMPILE_OK;
10342}
10343
10344#ifndef SHAREABLE_BARE_EXPRESSION
10345#define SHAREABLE_BARE_EXPRESSION 1
10346#endif
10347
10348static int
10349compile_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)
10350{
10351# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10352 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10353 VALUE lit = Qnil;
10354 DECL_ANCHOR(anchor);
10355
10356 enum node_type type = nd_type(node);
10357 switch (type) {
10358 case NODE_TRUE:
10359 *value_p = Qtrue;
10360 goto compile;
10361 case NODE_FALSE:
10362 *value_p = Qfalse;
10363 goto compile;
10364 case NODE_NIL:
10365 *value_p = Qnil;
10366 goto compile;
10367 case NODE_SYM:
10368 *value_p = rb_node_sym_string_val(node);
10369 goto compile;
10370 case NODE_REGX:
10371 *value_p = rb_node_regx_string_val(node);
10372 goto compile;
10373 case NODE_LINE:
10374 *value_p = rb_node_line_lineno_val(node);
10375 goto compile;
10376 case NODE_INTEGER:
10377 *value_p = rb_node_integer_literal_val(node);
10378 goto compile;
10379 case NODE_FLOAT:
10380 *value_p = rb_node_float_literal_val(node);
10381 goto compile;
10382 case NODE_RATIONAL:
10383 *value_p = rb_node_rational_literal_val(node);
10384 goto compile;
10385 case NODE_IMAGINARY:
10386 *value_p = rb_node_imaginary_literal_val(node);
10387 goto compile;
10388 case NODE_ENCODING:
10389 *value_p = rb_node_encoding_val(node);
10390
10391 compile:
10392 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10393 *shareable_literal_p = 1;
10394 return COMPILE_OK;
10395
10396 case NODE_DSTR:
10397 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10398 if (shareable == rb_parser_shareable_literal) {
10399 /*
10400 * NEW_CALL(node, idUMinus, 0, loc);
10401 *
10402 * -"#{var}"
10403 */
10404 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10405 }
10406 *value_p = Qundef;
10407 *shareable_literal_p = 1;
10408 return COMPILE_OK;
10409
10410 case NODE_STR:{
10411 VALUE lit = rb_node_str_string_val(node);
10412 ADD_INSN1(ret, node, putobject, lit);
10413 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10414 *value_p = lit;
10415 *shareable_literal_p = 1;
10416
10417 return COMPILE_OK;
10418 }
10419
10420 case NODE_FILE:{
10421 VALUE lit = rb_node_file_path_val(node);
10422 ADD_INSN1(ret, node, putobject, lit);
10423 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10424 *value_p = lit;
10425 *shareable_literal_p = 1;
10426
10427 return COMPILE_OK;
10428 }
10429
10430 case NODE_ZLIST:{
10431 VALUE lit = rb_ary_new();
10432 OBJ_FREEZE(lit);
10433 ADD_INSN1(ret, node, putobject, lit);
10434 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10435 *value_p = lit;
10436 *shareable_literal_p = 1;
10437
10438 return COMPILE_OK;
10439 }
10440
10441 case NODE_LIST:{
10442 INIT_ANCHOR(anchor);
10443 lit = rb_ary_new();
10444 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10445 VALUE val;
10446 int shareable_literal_p2;
10447 NODE *elt = RNODE_LIST(n)->nd_head;
10448 if (elt) {
10449 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10450 if (shareable_literal_p2) {
10451 /* noop */
10452 }
10453 else if (RTEST(lit)) {
10454 rb_ary_clear(lit);
10455 lit = Qfalse;
10456 }
10457 }
10458 if (RTEST(lit)) {
10459 if (!UNDEF_P(val)) {
10460 rb_ary_push(lit, val);
10461 }
10462 else {
10463 rb_ary_clear(lit);
10464 lit = Qnil; /* make shareable at runtime */
10465 }
10466 }
10467 }
10468 break;
10469 }
10470 case NODE_HASH:{
10471 if (!RNODE_HASH(node)->nd_brace) {
10472 *value_p = Qundef;
10473 *shareable_literal_p = 0;
10474 return COMPILE_OK;
10475 }
10476 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10477 if (!RNODE_LIST(n)->nd_head) {
10478 // If the hash node have a keyword splat, fall back to the default case.
10479 goto compile_shareable;
10480 }
10481 }
10482
10483 INIT_ANCHOR(anchor);
10484 lit = rb_hash_new();
10485 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10486 VALUE key_val = 0;
10487 VALUE value_val = 0;
10488 int shareable_literal_p2;
10489 NODE *key = RNODE_LIST(n)->nd_head;
10490 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10491 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10492 if (shareable_literal_p2) {
10493 /* noop */
10494 }
10495 else if (RTEST(lit)) {
10496 rb_hash_clear(lit);
10497 lit = Qfalse;
10498 }
10499 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10500 if (shareable_literal_p2) {
10501 /* noop */
10502 }
10503 else if (RTEST(lit)) {
10504 rb_hash_clear(lit);
10505 lit = Qfalse;
10506 }
10507 if (RTEST(lit)) {
10508 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10509 rb_hash_aset(lit, key_val, value_val);
10510 }
10511 else {
10512 rb_hash_clear(lit);
10513 lit = Qnil; /* make shareable at runtime */
10514 }
10515 }
10516 }
10517 break;
10518 }
10519
10520 default:
10521
10522 compile_shareable:
10523 if (shareable == rb_parser_shareable_literal &&
10524 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10525 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10526 *value_p = Qundef;
10527 *shareable_literal_p = 1;
10528 return COMPILE_OK;
10529 }
10530 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10531 *value_p = Qundef;
10532 *shareable_literal_p = 0;
10533 return COMPILE_OK;
10534 }
10535
10536 /* Array or Hash that does not have keyword splat */
10537 if (!lit) {
10538 if (nd_type(node) == NODE_LIST) {
10539 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10540 }
10541 else if (nd_type(node) == NODE_HASH) {
10542 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10543 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10544 }
10545 *value_p = Qundef;
10546 *shareable_literal_p = 0;
10547 ADD_SEQ(ret, anchor);
10548 return COMPILE_OK;
10549 }
10550 if (NIL_P(lit)) {
10551 // if shareable_literal, all elements should have been ensured
10552 // as shareable
10553 if (nd_type(node) == NODE_LIST) {
10554 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10555 }
10556 else if (nd_type(node) == NODE_HASH) {
10557 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10558 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10559 }
10560 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10561 *value_p = Qundef;
10562 *shareable_literal_p = 1;
10563 }
10564 else {
10566 ADD_INSN1(ret, node, putobject, val);
10567 RB_OBJ_WRITTEN(iseq, Qundef, val);
10568 *value_p = val;
10569 *shareable_literal_p = 1;
10570 }
10571
10572 return COMPILE_OK;
10573}
10574
10575static int
10576compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10577{
10578 int literal_p = 0;
10579 VALUE val;
10580 DECL_ANCHOR(anchor);
10581 INIT_ANCHOR(anchor);
10582
10583 switch (shareable) {
10584 case rb_parser_shareable_none:
10585 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10586 return COMPILE_OK;
10587
10588 case rb_parser_shareable_literal:
10589 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10590 ADD_SEQ(ret, anchor);
10591 return COMPILE_OK;
10592
10593 case rb_parser_shareable_copy:
10594 case rb_parser_shareable_everything:
10595 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10596 if (!literal_p) {
10597 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10598 }
10599 else {
10600 ADD_SEQ(ret, anchor);
10601 }
10602 return COMPILE_OK;
10603 default:
10604 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10605 }
10606}
10607
10608static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10616static int
10617iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10618{
10619 if (node == 0) {
10620 if (!popped) {
10621 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10622 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10623 debugs("node: NODE_NIL(implicit)\n");
10624 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10625 }
10626 return COMPILE_OK;
10627 }
10628 return iseq_compile_each0(iseq, ret, node, popped);
10629}
10630
10631static int
10632iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10633{
10634 const int line = (int)nd_line(node);
10635 const enum node_type type = nd_type(node);
10636 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10637
10638 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10639 /* ignore */
10640 }
10641 else {
10642 if (nd_fl_newline(node)) {
10643 int event = RUBY_EVENT_LINE;
10644 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10645 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10646 event |= RUBY_EVENT_COVERAGE_LINE;
10647 }
10648 ADD_TRACE(ret, event);
10649 }
10650 }
10651
10652 debug_node_start(node);
10653#undef BEFORE_RETURN
10654#define BEFORE_RETURN debug_node_end()
10655
10656 switch (type) {
10657 case NODE_BLOCK:
10658 CHECK(compile_block(iseq, ret, node, popped));
10659 break;
10660 case NODE_IF:
10661 case NODE_UNLESS:
10662 CHECK(compile_if(iseq, ret, node, popped, type));
10663 break;
10664 case NODE_CASE:
10665 CHECK(compile_case(iseq, ret, node, popped));
10666 break;
10667 case NODE_CASE2:
10668 CHECK(compile_case2(iseq, ret, node, popped));
10669 break;
10670 case NODE_CASE3:
10671 CHECK(compile_case3(iseq, ret, node, popped));
10672 break;
10673 case NODE_WHILE:
10674 case NODE_UNTIL:
10675 CHECK(compile_loop(iseq, ret, node, popped, type));
10676 break;
10677 case NODE_FOR:
10678 case NODE_ITER:
10679 CHECK(compile_iter(iseq, ret, node, popped));
10680 break;
10681 case NODE_FOR_MASGN:
10682 CHECK(compile_for_masgn(iseq, ret, node, popped));
10683 break;
10684 case NODE_BREAK:
10685 CHECK(compile_break(iseq, ret, node, popped));
10686 break;
10687 case NODE_NEXT:
10688 CHECK(compile_next(iseq, ret, node, popped));
10689 break;
10690 case NODE_REDO:
10691 CHECK(compile_redo(iseq, ret, node, popped));
10692 break;
10693 case NODE_RETRY:
10694 CHECK(compile_retry(iseq, ret, node, popped));
10695 break;
10696 case NODE_BEGIN:{
10697 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10698 break;
10699 }
10700 case NODE_RESCUE:
10701 CHECK(compile_rescue(iseq, ret, node, popped));
10702 break;
10703 case NODE_RESBODY:
10704 CHECK(compile_resbody(iseq, ret, node, popped));
10705 break;
10706 case NODE_ENSURE:
10707 CHECK(compile_ensure(iseq, ret, node, popped));
10708 break;
10709
10710 case NODE_AND:
10711 case NODE_OR:{
10712 LABEL *end_label = NEW_LABEL(line);
10713 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10714 if (!popped) {
10715 ADD_INSN(ret, node, dup);
10716 }
10717 if (type == NODE_AND) {
10718 ADD_INSNL(ret, node, branchunless, end_label);
10719 }
10720 else {
10721 ADD_INSNL(ret, node, branchif, end_label);
10722 }
10723 if (!popped) {
10724 ADD_INSN(ret, node, pop);
10725 }
10726 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10727 ADD_LABEL(ret, end_label);
10728 break;
10729 }
10730
10731 case NODE_MASGN:{
10732 compile_massign(iseq, ret, node, popped);
10733 break;
10734 }
10735
10736 case NODE_LASGN:{
10737 ID id = RNODE_LASGN(node)->nd_vid;
10738 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10739
10740 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10741 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10742
10743 if (!popped) {
10744 ADD_INSN(ret, node, dup);
10745 }
10746 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10747 break;
10748 }
10749 case NODE_DASGN: {
10750 int idx, lv, ls;
10751 ID id = RNODE_DASGN(node)->nd_vid;
10752 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10753 debugi("dassn id", rb_id2str(id) ? id : '*');
10754
10755 if (!popped) {
10756 ADD_INSN(ret, node, dup);
10757 }
10758
10759 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10760
10761 if (idx < 0) {
10762 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10763 rb_id2str(id));
10764 goto ng;
10765 }
10766 ADD_SETLOCAL(ret, node, ls - idx, lv);
10767 break;
10768 }
10769 case NODE_GASGN:{
10770 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10771
10772 if (!popped) {
10773 ADD_INSN(ret, node, dup);
10774 }
10775 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10776 break;
10777 }
10778 case NODE_IASGN:{
10779 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10780 if (!popped) {
10781 ADD_INSN(ret, node, dup);
10782 }
10783 ADD_INSN2(ret, node, setinstancevariable,
10784 ID2SYM(RNODE_IASGN(node)->nd_vid),
10785 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10786 break;
10787 }
10788 case NODE_CDECL:{
10789 if (RNODE_CDECL(node)->nd_vid) {
10790 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10791
10792 if (!popped) {
10793 ADD_INSN(ret, node, dup);
10794 }
10795
10796 ADD_INSN1(ret, node, putspecialobject,
10797 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10798 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10799 }
10800 else {
10801 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10802 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10803 ADD_INSN(ret, node, swap);
10804
10805 if (!popped) {
10806 ADD_INSN1(ret, node, topn, INT2FIX(1));
10807 ADD_INSN(ret, node, swap);
10808 }
10809
10810 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10811 }
10812 break;
10813 }
10814 case NODE_CVASGN:{
10815 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10816 if (!popped) {
10817 ADD_INSN(ret, node, dup);
10818 }
10819 ADD_INSN2(ret, node, setclassvariable,
10820 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10821 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10822 break;
10823 }
10824 case NODE_OP_ASGN1:
10825 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10826 break;
10827 case NODE_OP_ASGN2:
10828 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10829 break;
10830 case NODE_OP_CDECL:
10831 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10832 break;
10833 case NODE_OP_ASGN_AND:
10834 case NODE_OP_ASGN_OR:
10835 CHECK(compile_op_log(iseq, ret, node, popped, type));
10836 break;
10837 case NODE_CALL: /* obj.foo */
10838 case NODE_OPCALL: /* foo[] */
10839 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10840 break;
10841 }
10842 case NODE_QCALL: /* obj&.foo */
10843 case NODE_FCALL: /* foo() */
10844 case NODE_VCALL: /* foo (variable or call) */
10845 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10846 goto ng;
10847 }
10848 break;
10849 case NODE_SUPER:
10850 case NODE_ZSUPER:
10851 CHECK(compile_super(iseq, ret, node, popped, type));
10852 break;
10853 case NODE_LIST:{
10854 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10855 break;
10856 }
10857 case NODE_ZLIST:{
10858 if (!popped) {
10859 ADD_INSN1(ret, node, newarray, INT2FIX(0));
10860 }
10861 break;
10862 }
10863 case NODE_HASH:
10864 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10865 break;
10866 case NODE_RETURN:
10867 CHECK(compile_return(iseq, ret, node, popped));
10868 break;
10869 case NODE_YIELD:
10870 CHECK(compile_yield(iseq, ret, node, popped));
10871 break;
10872 case NODE_LVAR:{
10873 if (!popped) {
10874 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10875 }
10876 break;
10877 }
10878 case NODE_DVAR:{
10879 int lv, idx, ls;
10880 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10881 if (!popped) {
10882 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10883 if (idx < 0) {
10884 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10885 rb_id2str(RNODE_DVAR(node)->nd_vid));
10886 goto ng;
10887 }
10888 ADD_GETLOCAL(ret, node, ls - idx, lv);
10889 }
10890 break;
10891 }
10892 case NODE_GVAR:{
10893 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10894 if (popped) {
10895 ADD_INSN(ret, node, pop);
10896 }
10897 break;
10898 }
10899 case NODE_IVAR:{
10900 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10901 if (!popped) {
10902 ADD_INSN2(ret, node, getinstancevariable,
10903 ID2SYM(RNODE_IVAR(node)->nd_vid),
10904 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10905 }
10906 break;
10907 }
10908 case NODE_CONST:{
10909 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10910
10911 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10912 body->ic_size++;
10913 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10914 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10915 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10916 }
10917 else {
10918 ADD_INSN(ret, node, putnil);
10919 ADD_INSN1(ret, node, putobject, Qtrue);
10920 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10921 }
10922
10923 if (popped) {
10924 ADD_INSN(ret, node, pop);
10925 }
10926 break;
10927 }
10928 case NODE_CVAR:{
10929 if (!popped) {
10930 ADD_INSN2(ret, node, getclassvariable,
10931 ID2SYM(RNODE_CVAR(node)->nd_vid),
10932 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10933 }
10934 break;
10935 }
10936 case NODE_NTH_REF:{
10937 if (!popped) {
10938 if (!RNODE_NTH_REF(node)->nd_nth) {
10939 ADD_INSN(ret, node, putnil);
10940 break;
10941 }
10942 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10943 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10944 }
10945 break;
10946 }
10947 case NODE_BACK_REF:{
10948 if (!popped) {
10949 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10950 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10951 }
10952 break;
10953 }
10954 case NODE_MATCH:
10955 case NODE_MATCH2:
10956 case NODE_MATCH3:
10957 CHECK(compile_match(iseq, ret, node, popped, type));
10958 break;
10959 case NODE_SYM:{
10960 if (!popped) {
10961 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
10962 }
10963 break;
10964 }
10965 case NODE_LINE:{
10966 if (!popped) {
10967 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
10968 }
10969 break;
10970 }
10971 case NODE_ENCODING:{
10972 if (!popped) {
10973 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
10974 }
10975 break;
10976 }
10977 case NODE_INTEGER:{
10978 VALUE lit = rb_node_integer_literal_val(node);
10979 debugp_param("integer", lit);
10980 if (!popped) {
10981 ADD_INSN1(ret, node, putobject, lit);
10982 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10983 }
10984 break;
10985 }
10986 case NODE_FLOAT:{
10987 VALUE lit = rb_node_float_literal_val(node);
10988 debugp_param("float", lit);
10989 if (!popped) {
10990 ADD_INSN1(ret, node, putobject, lit);
10991 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10992 }
10993 break;
10994 }
10995 case NODE_RATIONAL:{
10996 VALUE lit = rb_node_rational_literal_val(node);
10997 debugp_param("rational", lit);
10998 if (!popped) {
10999 ADD_INSN1(ret, node, putobject, lit);
11000 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11001 }
11002 break;
11003 }
11004 case NODE_IMAGINARY:{
11005 VALUE lit = rb_node_imaginary_literal_val(node);
11006 debugp_param("imaginary", lit);
11007 if (!popped) {
11008 ADD_INSN1(ret, node, putobject, lit);
11009 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11010 }
11011 break;
11012 }
11013 case NODE_FILE:
11014 case NODE_STR:{
11015 debugp_param("nd_lit", get_string_value(node));
11016 if (!popped) {
11017 VALUE lit = get_string_value(node);
11018 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11019 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11020 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11021 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11022 }
11023 switch (option->frozen_string_literal) {
11024 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11025 ADD_INSN1(ret, node, putchilledstring, lit);
11026 break;
11027 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11028 ADD_INSN1(ret, node, putstring, lit);
11029 break;
11030 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11031 ADD_INSN1(ret, node, putobject, lit);
11032 break;
11033 default:
11034 rb_bug("invalid frozen_string_literal");
11035 }
11036 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11037 }
11038 break;
11039 }
11040 case NODE_DSTR:{
11041 compile_dstr(iseq, ret, node);
11042
11043 if (popped) {
11044 ADD_INSN(ret, node, pop);
11045 }
11046 break;
11047 }
11048 case NODE_XSTR:{
11049 ADD_CALL_RECEIVER(ret, node);
11050 VALUE str = rb_node_str_string_val(node);
11051 ADD_INSN1(ret, node, putobject, str);
11052 RB_OBJ_WRITTEN(iseq, Qundef, str);
11053 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11054
11055 if (popped) {
11056 ADD_INSN(ret, node, pop);
11057 }
11058 break;
11059 }
11060 case NODE_DXSTR:{
11061 ADD_CALL_RECEIVER(ret, node);
11062 compile_dstr(iseq, ret, node);
11063 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11064
11065 if (popped) {
11066 ADD_INSN(ret, node, pop);
11067 }
11068 break;
11069 }
11070 case NODE_EVSTR:
11071 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11072 break;
11073 case NODE_REGX:{
11074 if (!popped) {
11075 VALUE lit = rb_node_regx_string_val(node);
11076 ADD_INSN1(ret, node, putobject, lit);
11077 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11078 }
11079 break;
11080 }
11081 case NODE_DREGX:
11082 compile_dregx(iseq, ret, node, popped);
11083 break;
11084 case NODE_ONCE:{
11085 int ic_index = body->ise_size++;
11086 const rb_iseq_t *block_iseq;
11087 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11088
11089 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11090 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11091
11092 if (popped) {
11093 ADD_INSN(ret, node, pop);
11094 }
11095 break;
11096 }
11097 case NODE_ARGSCAT:{
11098 if (popped) {
11099 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11100 ADD_INSN1(ret, node, splatarray, Qfalse);
11101 ADD_INSN(ret, node, pop);
11102 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11103 ADD_INSN1(ret, node, splatarray, Qfalse);
11104 ADD_INSN(ret, node, pop);
11105 }
11106 else {
11107 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11108 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11109 if (nd_type_p(body_node, NODE_LIST)) {
11110 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11111 }
11112 else {
11113 CHECK(COMPILE(ret, "argscat body", body_node));
11114 ADD_INSN(ret, node, concattoarray);
11115 }
11116 }
11117 break;
11118 }
11119 case NODE_ARGSPUSH:{
11120 if (popped) {
11121 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11122 ADD_INSN1(ret, node, splatarray, Qfalse);
11123 ADD_INSN(ret, node, pop);
11124 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11125 }
11126 else {
11127 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11128 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11129 if (keyword_node_p(body_node)) {
11130 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11131 ADD_INSN(ret, node, pushtoarraykwsplat);
11132 }
11133 else if (static_literal_node_p(body_node, iseq, false)) {
11134 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11135 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11136 }
11137 else {
11138 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11139 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11140 }
11141 }
11142 break;
11143 }
11144 case NODE_SPLAT:{
11145 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11146 ADD_INSN1(ret, node, splatarray, Qtrue);
11147
11148 if (popped) {
11149 ADD_INSN(ret, node, pop);
11150 }
11151 break;
11152 }
11153 case NODE_DEFN:{
11154 ID mid = RNODE_DEFN(node)->nd_mid;
11155 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11156 rb_id2str(mid),
11157 ISEQ_TYPE_METHOD, line);
11158
11159 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11160 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11161 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11162
11163 if (!popped) {
11164 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11165 }
11166
11167 break;
11168 }
11169 case NODE_DEFS:{
11170 ID mid = RNODE_DEFS(node)->nd_mid;
11171 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11172 rb_id2str(mid),
11173 ISEQ_TYPE_METHOD, line);
11174
11175 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11176 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11177 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11178 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11179
11180 if (!popped) {
11181 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11182 }
11183 break;
11184 }
11185 case NODE_ALIAS:{
11186 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11187 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11188 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11189 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11190 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11191
11192 if (popped) {
11193 ADD_INSN(ret, node, pop);
11194 }
11195 break;
11196 }
11197 case NODE_VALIAS:{
11198 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11199 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11200 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11201 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11202
11203 if (popped) {
11204 ADD_INSN(ret, node, pop);
11205 }
11206 break;
11207 }
11208 case NODE_UNDEF:{
11209 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11210
11211 for (long i = 0; i < ary->len; i++) {
11212 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11213 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11214 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11215 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11216
11217 if (i < ary->len - 1) {
11218 ADD_INSN(ret, node, pop);
11219 }
11220 }
11221
11222 if (popped) {
11223 ADD_INSN(ret, node, pop);
11224 }
11225 break;
11226 }
11227 case NODE_CLASS:{
11228 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11229 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11230 ISEQ_TYPE_CLASS, line);
11231 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11232 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11233 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11234
11235 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11236 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11237 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11238
11239 if (popped) {
11240 ADD_INSN(ret, node, pop);
11241 }
11242 break;
11243 }
11244 case NODE_MODULE:{
11245 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11246 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11247 ISEQ_TYPE_CLASS, line);
11248 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11249 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11250
11251 ADD_INSN (ret, node, putnil); /* dummy */
11252 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11253 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11254
11255 if (popped) {
11256 ADD_INSN(ret, node, pop);
11257 }
11258 break;
11259 }
11260 case NODE_SCLASS:{
11261 ID singletonclass;
11262 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11263 ISEQ_TYPE_CLASS, line);
11264
11265 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11266 ADD_INSN (ret, node, putnil);
11267 CONST_ID(singletonclass, "singletonclass");
11268 ADD_INSN3(ret, node, defineclass,
11269 ID2SYM(singletonclass), singleton_class,
11270 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11271 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11272
11273 if (popped) {
11274 ADD_INSN(ret, node, pop);
11275 }
11276 break;
11277 }
11278 case NODE_COLON2:
11279 CHECK(compile_colon2(iseq, ret, node, popped));
11280 break;
11281 case NODE_COLON3:
11282 CHECK(compile_colon3(iseq, ret, node, popped));
11283 break;
11284 case NODE_DOT2:
11285 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11286 break;
11287 case NODE_DOT3:
11288 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11289 break;
11290 case NODE_FLIP2:
11291 case NODE_FLIP3:{
11292 LABEL *lend = NEW_LABEL(line);
11293 LABEL *ltrue = NEW_LABEL(line);
11294 LABEL *lfalse = NEW_LABEL(line);
11295 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11296 ltrue, lfalse));
11297 ADD_LABEL(ret, ltrue);
11298 ADD_INSN1(ret, node, putobject, Qtrue);
11299 ADD_INSNL(ret, node, jump, lend);
11300 ADD_LABEL(ret, lfalse);
11301 ADD_INSN1(ret, node, putobject, Qfalse);
11302 ADD_LABEL(ret, lend);
11303 break;
11304 }
11305 case NODE_SELF:{
11306 if (!popped) {
11307 ADD_INSN(ret, node, putself);
11308 }
11309 break;
11310 }
11311 case NODE_NIL:{
11312 if (!popped) {
11313 ADD_INSN(ret, node, putnil);
11314 }
11315 break;
11316 }
11317 case NODE_TRUE:{
11318 if (!popped) {
11319 ADD_INSN1(ret, node, putobject, Qtrue);
11320 }
11321 break;
11322 }
11323 case NODE_FALSE:{
11324 if (!popped) {
11325 ADD_INSN1(ret, node, putobject, Qfalse);
11326 }
11327 break;
11328 }
11329 case NODE_ERRINFO:
11330 CHECK(compile_errinfo(iseq, ret, node, popped));
11331 break;
11332 case NODE_DEFINED:
11333 if (!popped) {
11334 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11335 }
11336 break;
11337 case NODE_POSTEXE:{
11338 /* compiled to:
11339 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11340 */
11341 int is_index = body->ise_size++;
11343 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11344 const rb_iseq_t *once_iseq =
11345 new_child_iseq_with_callback(iseq, ifunc,
11346 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
11347
11348 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11349 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11350
11351 if (popped) {
11352 ADD_INSN(ret, node, pop);
11353 }
11354 break;
11355 }
11356 case NODE_KW_ARG:
11357 CHECK(compile_kw_arg(iseq, ret, node, popped));
11358 break;
11359 case NODE_DSYM:{
11360 compile_dstr(iseq, ret, node);
11361 if (!popped) {
11362 ADD_INSN(ret, node, intern);
11363 }
11364 else {
11365 ADD_INSN(ret, node, pop);
11366 }
11367 break;
11368 }
11369 case NODE_ATTRASGN:
11370 CHECK(compile_attrasgn(iseq, ret, node, popped));
11371 break;
11372 case NODE_LAMBDA:{
11373 /* compile same as lambda{...} */
11374 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11375 VALUE argc = INT2FIX(0);
11376
11377 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11378 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11379 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11380
11381 if (popped) {
11382 ADD_INSN(ret, node, pop);
11383 }
11384 break;
11385 }
11386 default:
11387 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11388 ng:
11389 debug_node_end();
11390 return COMPILE_NG;
11391 }
11392
11393 debug_node_end();
11394 return COMPILE_OK;
11395}
11396
11397/***************************/
11398/* instruction information */
11399/***************************/
11400
11401static int
11402insn_data_length(INSN *iobj)
11403{
11404 return insn_len(iobj->insn_id);
11405}
11406
11407static int
11408calc_sp_depth(int depth, INSN *insn)
11409{
11410 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11411}
11412
11413static VALUE
11414opobj_inspect(VALUE obj)
11415{
11416 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11417 switch (BUILTIN_TYPE(obj)) {
11418 case T_STRING:
11419 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11420 break;
11421 case T_ARRAY:
11422 obj = rb_ary_dup(obj);
11423 break;
11424 default:
11425 break;
11426 }
11427 }
11428 return rb_inspect(obj);
11429}
11430
11431
11432
11433static VALUE
11434insn_data_to_s_detail(INSN *iobj)
11435{
11436 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11437
11438 if (iobj->operands) {
11439 const char *types = insn_op_types(iobj->insn_id);
11440 int j;
11441
11442 for (j = 0; types[j]; j++) {
11443 char type = types[j];
11444
11445 switch (type) {
11446 case TS_OFFSET: /* label(destination position) */
11447 {
11448 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11449 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11450 break;
11451 }
11452 break;
11453 case TS_ISEQ: /* iseq */
11454 {
11455 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11456 VALUE val = Qnil;
11457 if (0 && iseq) { /* TODO: invalidate now */
11458 val = (VALUE)iseq;
11459 }
11460 rb_str_concat(str, opobj_inspect(val));
11461 }
11462 break;
11463 case TS_LINDEX:
11464 case TS_NUM: /* ulong */
11465 case TS_VALUE: /* VALUE */
11466 {
11467 VALUE v = OPERAND_AT(iobj, j);
11468 if (!CLASS_OF(v))
11469 rb_str_cat2(str, "<hidden>");
11470 else {
11471 rb_str_concat(str, opobj_inspect(v));
11472 }
11473 break;
11474 }
11475 case TS_ID: /* ID */
11476 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11477 break;
11478 case TS_IC: /* inline cache */
11479 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11480 break;
11481 case TS_IVC: /* inline ivar cache */
11482 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11483 break;
11484 case TS_ICVARC: /* inline cvar cache */
11485 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11486 break;
11487 case TS_ISE: /* inline storage entry */
11488 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11489 break;
11490 case TS_CALLDATA: /* we store these as call infos at compile time */
11491 {
11492 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11493 rb_str_cat2(str, "<calldata:");
11494 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11495 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11496 break;
11497 }
11498 case TS_CDHASH: /* case/when condition cache */
11499 rb_str_cat2(str, "<ch>");
11500 break;
11501 case TS_FUNCPTR:
11502 {
11503 void *func = (void *)OPERAND_AT(iobj, j);
11504#ifdef HAVE_DLADDR
11505 Dl_info info;
11506 if (dladdr(func, &info) && info.dli_sname) {
11507 rb_str_cat2(str, info.dli_sname);
11508 break;
11509 }
11510#endif
11511 rb_str_catf(str, "<%p>", func);
11512 }
11513 break;
11514 case TS_BUILTIN:
11515 rb_str_cat2(str, "<TS_BUILTIN>");
11516 break;
11517 default:{
11518 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11519 }
11520 }
11521 if (types[j + 1]) {
11522 rb_str_cat2(str, ", ");
11523 }
11524 }
11525 }
11526 return str;
11527}
11528
11529static void
11530dump_disasm_list(const LINK_ELEMENT *link)
11531{
11532 dump_disasm_list_with_cursor(link, NULL, NULL);
11533}
11534
11535static void
11536dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11537{
11538 int pos = 0;
11539 INSN *iobj;
11540 LABEL *lobj;
11541 VALUE str;
11542
11543 printf("-- raw disasm--------\n");
11544
11545 while (link) {
11546 if (curr) printf(curr == link ? "*" : " ");
11547 switch (link->type) {
11548 case ISEQ_ELEMENT_INSN:
11549 {
11550 iobj = (INSN *)link;
11551 str = insn_data_to_s_detail(iobj);
11552 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11553 pos += insn_data_length(iobj);
11554 break;
11555 }
11556 case ISEQ_ELEMENT_LABEL:
11557 {
11558 lobj = (LABEL *)link;
11559 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11560 dest == lobj ? " <---" : "");
11561 break;
11562 }
11563 case ISEQ_ELEMENT_TRACE:
11564 {
11565 TRACE *trace = (TRACE *)link;
11566 printf(" trace: %0x\n", trace->event);
11567 break;
11568 }
11569 case ISEQ_ELEMENT_ADJUST:
11570 {
11571 ADJUST *adjust = (ADJUST *)link;
11572 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11573 break;
11574 }
11575 default:
11576 /* ignore */
11577 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11578 }
11579 link = link->next;
11580 }
11581 printf("---------------------\n");
11582 fflush(stdout);
11583}
11584
11585int
11586rb_insn_len(VALUE insn)
11587{
11588 return insn_len(insn);
11589}
11590
11591const char *
11592rb_insns_name(int i)
11593{
11594 return insn_name(i);
11595}
11596
11597VALUE
11598rb_insns_name_array(void)
11599{
11600 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11601 int i;
11602 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11603 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11604 }
11605 return rb_ary_freeze(ary);
11606}
11607
11608static LABEL *
11609register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11610{
11611 LABEL *label = 0;
11612 st_data_t tmp;
11613 obj = rb_to_symbol_type(obj);
11614
11615 if (st_lookup(labels_table, obj, &tmp) == 0) {
11616 label = NEW_LABEL(0);
11617 st_insert(labels_table, obj, (st_data_t)label);
11618 }
11619 else {
11620 label = (LABEL *)tmp;
11621 }
11622 LABEL_REF(label);
11623 return label;
11624}
11625
11626static VALUE
11627get_exception_sym2type(VALUE sym)
11628{
11629 static VALUE symRescue, symEnsure, symRetry;
11630 static VALUE symBreak, symRedo, symNext;
11631
11632 if (symRescue == 0) {
11633 symRescue = ID2SYM(rb_intern_const("rescue"));
11634 symEnsure = ID2SYM(rb_intern_const("ensure"));
11635 symRetry = ID2SYM(rb_intern_const("retry"));
11636 symBreak = ID2SYM(rb_intern_const("break"));
11637 symRedo = ID2SYM(rb_intern_const("redo"));
11638 symNext = ID2SYM(rb_intern_const("next"));
11639 }
11640
11641 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11642 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11643 if (sym == symRetry) return CATCH_TYPE_RETRY;
11644 if (sym == symBreak) return CATCH_TYPE_BREAK;
11645 if (sym == symRedo) return CATCH_TYPE_REDO;
11646 if (sym == symNext) return CATCH_TYPE_NEXT;
11647 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11648 return 0;
11649}
11650
11651static int
11652iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11653 VALUE exception)
11654{
11655 int i;
11656
11657 for (i=0; i<RARRAY_LEN(exception); i++) {
11658 const rb_iseq_t *eiseq;
11659 VALUE v, type;
11660 LABEL *lstart, *lend, *lcont;
11661 unsigned int sp;
11662
11663 v = rb_to_array_type(RARRAY_AREF(exception, i));
11664 if (RARRAY_LEN(v) != 6) {
11665 rb_raise(rb_eSyntaxError, "wrong exception entry");
11666 }
11667 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11668 if (NIL_P(RARRAY_AREF(v, 1))) {
11669 eiseq = NULL;
11670 }
11671 else {
11672 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11673 }
11674
11675 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11676 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11677 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11678 sp = NUM2UINT(RARRAY_AREF(v, 5));
11679
11680 /* TODO: Dirty Hack! Fix me */
11681 if (type == CATCH_TYPE_RESCUE ||
11682 type == CATCH_TYPE_BREAK ||
11683 type == CATCH_TYPE_NEXT) {
11684 ++sp;
11685 }
11686
11687 lcont->sp = sp;
11688
11689 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11690
11691 RB_GC_GUARD(v);
11692 }
11693 return COMPILE_OK;
11694}
11695
11696static struct st_table *
11697insn_make_insn_table(void)
11698{
11699 struct st_table *table;
11700 int i;
11701 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11702
11703 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11704 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11705 }
11706
11707 return table;
11708}
11709
11710static const rb_iseq_t *
11711iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11712{
11713 VALUE iseqw;
11714 const rb_iseq_t *loaded_iseq;
11715
11716 if (RB_TYPE_P(op, T_ARRAY)) {
11717 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11718 }
11719 else if (CLASS_OF(op) == rb_cISeq) {
11720 iseqw = op;
11721 }
11722 else {
11723 rb_raise(rb_eSyntaxError, "ISEQ is required");
11724 }
11725
11726 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11727 return loaded_iseq;
11728}
11729
11730static VALUE
11731iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11732{
11733 ID mid = 0;
11734 int orig_argc = 0;
11735 unsigned int flag = 0;
11736 struct rb_callinfo_kwarg *kw_arg = 0;
11737
11738 if (!NIL_P(op)) {
11739 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11740 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11741 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11742 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11743
11744 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11745 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11746 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11747
11748 if (!NIL_P(vkw_arg)) {
11749 int i;
11750 int len = RARRAY_LENINT(vkw_arg);
11751 size_t n = rb_callinfo_kwarg_bytes(len);
11752
11753 kw_arg = xmalloc(n);
11754 kw_arg->references = 0;
11755 kw_arg->keyword_len = len;
11756 for (i = 0; i < len; i++) {
11757 VALUE kw = RARRAY_AREF(vkw_arg, i);
11758 SYM2ID(kw); /* make immortal */
11759 kw_arg->keywords[i] = kw;
11760 }
11761 }
11762 }
11763
11764 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11765 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11766 return (VALUE)ci;
11767}
11768
11769static rb_event_flag_t
11770event_name_to_flag(VALUE sym)
11771{
11772#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11773 CHECK_EVENT(RUBY_EVENT_LINE);
11774 CHECK_EVENT(RUBY_EVENT_CLASS);
11775 CHECK_EVENT(RUBY_EVENT_END);
11776 CHECK_EVENT(RUBY_EVENT_CALL);
11777 CHECK_EVENT(RUBY_EVENT_RETURN);
11778 CHECK_EVENT(RUBY_EVENT_B_CALL);
11779 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11780 CHECK_EVENT(RUBY_EVENT_RESCUE);
11781#undef CHECK_EVENT
11782 return RUBY_EVENT_NONE;
11783}
11784
11785static int
11786iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11787 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11788{
11789 /* TODO: body should be frozen */
11790 long i, len = RARRAY_LEN(body);
11791 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11792 int j;
11793 int line_no = 0, node_id = -1, insn_idx = 0;
11794 int ret = COMPILE_OK;
11795
11796 /*
11797 * index -> LABEL *label
11798 */
11799 static struct st_table *insn_table;
11800
11801 if (insn_table == 0) {
11802 insn_table = insn_make_insn_table();
11803 }
11804
11805 for (i=0; i<len; i++) {
11806 VALUE obj = RARRAY_AREF(body, i);
11807
11808 if (SYMBOL_P(obj)) {
11809 rb_event_flag_t event;
11810 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11811 ADD_TRACE(anchor, event);
11812 }
11813 else {
11814 LABEL *label = register_label(iseq, labels_table, obj);
11815 ADD_LABEL(anchor, label);
11816 }
11817 }
11818 else if (FIXNUM_P(obj)) {
11819 line_no = NUM2INT(obj);
11820 }
11821 else if (RB_TYPE_P(obj, T_ARRAY)) {
11822 VALUE *argv = 0;
11823 int argc = RARRAY_LENINT(obj) - 1;
11824 st_data_t insn_id;
11825 VALUE insn;
11826
11827 if (node_ids) {
11828 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11829 }
11830
11831 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11832 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11833 /* TODO: exception */
11834 COMPILE_ERROR(iseq, line_no,
11835 "unknown instruction: %+"PRIsVALUE, insn);
11836 ret = COMPILE_NG;
11837 break;
11838 }
11839
11840 if (argc != insn_len((VALUE)insn_id)-1) {
11841 COMPILE_ERROR(iseq, line_no,
11842 "operand size mismatch");
11843 ret = COMPILE_NG;
11844 break;
11845 }
11846
11847 if (argc > 0) {
11848 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11849
11850 // add element before operand setup to make GC root
11851 ADD_ELEM(anchor,
11852 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11853 (enum ruby_vminsn_type)insn_id, argc, argv));
11854
11855 for (j=0; j<argc; j++) {
11856 VALUE op = rb_ary_entry(obj, j+1);
11857 switch (insn_op_type((VALUE)insn_id, j)) {
11858 case TS_OFFSET: {
11859 LABEL *label = register_label(iseq, labels_table, op);
11860 argv[j] = (VALUE)label;
11861 break;
11862 }
11863 case TS_LINDEX:
11864 case TS_NUM:
11865 (void)NUM2INT(op);
11866 argv[j] = op;
11867 break;
11868 case TS_VALUE:
11869 argv[j] = op;
11870 RB_OBJ_WRITTEN(iseq, Qundef, op);
11871 break;
11872 case TS_ISEQ:
11873 {
11874 if (op != Qnil) {
11875 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
11876 argv[j] = v;
11877 RB_OBJ_WRITTEN(iseq, Qundef, v);
11878 }
11879 else {
11880 argv[j] = 0;
11881 }
11882 }
11883 break;
11884 case TS_ISE:
11885 argv[j] = op;
11886 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11887 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
11888 }
11889 break;
11890 case TS_IC:
11891 {
11892 VALUE segments = rb_ary_new();
11893 op = rb_to_array_type(op);
11894
11895 for (int i = 0; i < RARRAY_LEN(op); i++) {
11896 VALUE sym = RARRAY_AREF(op, i);
11897 sym = rb_to_symbol_type(sym);
11898 rb_ary_push(segments, sym);
11899 }
11900
11901 RB_GC_GUARD(op);
11902 argv[j] = segments;
11903 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11904 ISEQ_BODY(iseq)->ic_size++;
11905 }
11906 break;
11907 case TS_IVC: /* inline ivar cache */
11908 argv[j] = op;
11909 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
11910 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
11911 }
11912 break;
11913 case TS_ICVARC: /* inline cvar cache */
11914 argv[j] = op;
11915 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
11916 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
11917 }
11918 break;
11919 case TS_CALLDATA:
11920 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
11921 break;
11922 case TS_ID:
11923 argv[j] = rb_to_symbol_type(op);
11924 break;
11925 case TS_CDHASH:
11926 {
11927 int i;
11928 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
11929
11930 RHASH_TBL_RAW(map)->type = &cdhash_type;
11931 op = rb_to_array_type(op);
11932 for (i=0; i<RARRAY_LEN(op); i+=2) {
11933 VALUE key = RARRAY_AREF(op, i);
11934 VALUE sym = RARRAY_AREF(op, i+1);
11935 LABEL *label =
11936 register_label(iseq, labels_table, sym);
11937 rb_hash_aset(map, key, (VALUE)label | 1);
11938 }
11939 RB_GC_GUARD(op);
11940 argv[j] = map;
11941 RB_OBJ_WRITTEN(iseq, Qundef, map);
11942 }
11943 break;
11944 case TS_FUNCPTR:
11945 {
11946#if SIZEOF_VALUE <= SIZEOF_LONG
11947 long funcptr = NUM2LONG(op);
11948#else
11949 LONG_LONG funcptr = NUM2LL(op);
11950#endif
11951 argv[j] = (VALUE)funcptr;
11952 }
11953 break;
11954 default:
11955 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11956 }
11957 }
11958 }
11959 else {
11960 ADD_ELEM(anchor,
11961 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11962 (enum ruby_vminsn_type)insn_id, argc, NULL));
11963 }
11964 }
11965 else {
11966 rb_raise(rb_eTypeError, "unexpected object for instruction");
11967 }
11968 }
11969 RTYPEDDATA_DATA(labels_wrapper) = 0;
11970 RB_GC_GUARD(labels_wrapper);
11971 validate_labels(iseq, labels_table);
11972 if (!ret) return ret;
11973 return iseq_setup(iseq, anchor);
11974}
11975
11976#define CHECK_ARRAY(v) rb_to_array_type(v)
11977#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11978
11979static int
11980int_param(int *dst, VALUE param, VALUE sym)
11981{
11982 VALUE val = rb_hash_aref(param, sym);
11983 if (FIXNUM_P(val)) {
11984 *dst = FIX2INT(val);
11985 return TRUE;
11986 }
11987 else if (!NIL_P(val)) {
11988 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
11989 sym, val);
11990 }
11991 return FALSE;
11992}
11993
11994static const struct rb_iseq_param_keyword *
11995iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
11996{
11997 int i, j;
11998 int len = RARRAY_LENINT(keywords);
11999 int default_len;
12000 VALUE key, sym, default_val;
12001 VALUE *dvs;
12002 ID *ids;
12003 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12004
12005 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12006
12007 keyword->num = len;
12008#define SYM(s) ID2SYM(rb_intern_const(#s))
12009 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12010 i = keyword->bits_start - keyword->num;
12011 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12012#undef SYM
12013
12014 /* required args */
12015 for (i = 0; i < len; i++) {
12016 VALUE val = RARRAY_AREF(keywords, i);
12017
12018 if (!SYMBOL_P(val)) {
12019 goto default_values;
12020 }
12021 ids[i] = SYM2ID(val);
12022 keyword->required_num++;
12023 }
12024
12025 default_values: /* note: we intentionally preserve `i' from previous loop */
12026 default_len = len - i;
12027 if (default_len == 0) {
12028 keyword->table = ids;
12029 return keyword;
12030 }
12031 else if (default_len < 0) {
12033 }
12034
12035 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12036
12037 for (j = 0; i < len; i++, j++) {
12038 key = RARRAY_AREF(keywords, i);
12039 CHECK_ARRAY(key);
12040
12041 switch (RARRAY_LEN(key)) {
12042 case 1:
12043 sym = RARRAY_AREF(key, 0);
12044 default_val = Qundef;
12045 break;
12046 case 2:
12047 sym = RARRAY_AREF(key, 0);
12048 default_val = RARRAY_AREF(key, 1);
12049 break;
12050 default:
12051 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12052 }
12053 ids[i] = SYM2ID(sym);
12054 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12055 }
12056
12057 keyword->table = ids;
12058 keyword->default_values = dvs;
12059
12060 return keyword;
12061}
12062
12063static void
12064iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
12065{
12066 rb_gc_mark(obj);
12067}
12068
12069void
12070rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
12071{
12072 INSN *iobj = 0;
12073 size_t size = sizeof(INSN);
12074 unsigned int pos = 0;
12075
12076 while (storage) {
12077#ifdef STRICT_ALIGNMENT
12078 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12079#else
12080 const size_t padding = 0; /* expected to be optimized by compiler */
12081#endif /* STRICT_ALIGNMENT */
12082 size_t offset = pos + size + padding;
12083 if (offset > storage->size || offset > storage->pos) {
12084 pos = 0;
12085 storage = storage->next;
12086 }
12087 else {
12088#ifdef STRICT_ALIGNMENT
12089 pos += (int)padding;
12090#endif /* STRICT_ALIGNMENT */
12091
12092 iobj = (INSN *)&storage->buff[pos];
12093
12094 if (iobj->operands) {
12095 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
12096 }
12097 pos += (int)size;
12098 }
12099 }
12100}
12101
12102static const rb_data_type_t labels_wrapper_type = {
12103 .wrap_struct_name = "compiler/labels_wrapper",
12104 .function = {
12105 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12106 .dfree = (RUBY_DATA_FUNC)st_free_table,
12107 },
12108 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12109};
12110
12111void
12112rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12113 VALUE exception, VALUE body)
12114{
12115#define SYM(s) ID2SYM(rb_intern_const(#s))
12116 int i, len;
12117 unsigned int arg_size, local_size, stack_max;
12118 ID *tbl;
12119 struct st_table *labels_table = st_init_numtable();
12120 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12121 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12122 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12123 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12124 DECL_ANCHOR(anchor);
12125 INIT_ANCHOR(anchor);
12126
12127 len = RARRAY_LENINT(locals);
12128 ISEQ_BODY(iseq)->local_table_size = len;
12129 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12130
12131 for (i = 0; i < len; i++) {
12132 VALUE lv = RARRAY_AREF(locals, i);
12133
12134 if (sym_arg_rest == lv) {
12135 tbl[i] = 0;
12136 }
12137 else {
12138 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12139 }
12140 }
12141
12142#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12143 if (INT_PARAM(lead_num)) {
12144 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12145 }
12146 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12147 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12148 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12149 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12150#undef INT_PARAM
12151 {
12152#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12153 int x;
12154 INT_PARAM(arg_size);
12155 INT_PARAM(local_size);
12156 INT_PARAM(stack_max);
12157#undef INT_PARAM
12158 }
12159
12160 VALUE node_ids = Qfalse;
12161#ifdef USE_ISEQ_NODE_ID
12162 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12163 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12164 rb_raise(rb_eTypeError, "node_ids is not an array");
12165 }
12166#endif
12167
12168 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12169 len = RARRAY_LENINT(arg_opt_labels);
12170 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12171
12172 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12173 VALUE *opt_table = ALLOC_N(VALUE, len);
12174
12175 for (i = 0; i < len; i++) {
12176 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12177 LABEL *label = register_label(iseq, labels_table, ent);
12178 opt_table[i] = (VALUE)label;
12179 }
12180
12181 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12182 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12183 }
12184 }
12185 else if (!NIL_P(arg_opt_labels)) {
12186 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12187 arg_opt_labels);
12188 }
12189
12190 if (RB_TYPE_P(keywords, T_ARRAY)) {
12191 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12192 }
12193 else if (!NIL_P(keywords)) {
12194 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12195 keywords);
12196 }
12197
12198 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12199 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12200 }
12201
12202 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12203 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12204 }
12205
12206 if (int_param(&i, params, SYM(kwrest))) {
12207 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12208 if (keyword == NULL) {
12209 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12210 }
12211 keyword->rest_start = i;
12212 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12213 }
12214#undef SYM
12215 iseq_calc_param_size(iseq);
12216
12217 /* exception */
12218 iseq_build_from_ary_exception(iseq, labels_table, exception);
12219
12220 /* body */
12221 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12222
12223 ISEQ_BODY(iseq)->param.size = arg_size;
12224 ISEQ_BODY(iseq)->local_table_size = local_size;
12225 ISEQ_BODY(iseq)->stack_max = stack_max;
12226}
12227
12228/* for parser */
12229
12230int
12231rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12232{
12233 if (iseq) {
12234 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12235 while (body->type == ISEQ_TYPE_BLOCK ||
12236 body->type == ISEQ_TYPE_RESCUE ||
12237 body->type == ISEQ_TYPE_ENSURE ||
12238 body->type == ISEQ_TYPE_EVAL ||
12239 body->type == ISEQ_TYPE_MAIN
12240 ) {
12241 unsigned int i;
12242
12243 for (i = 0; i < body->local_table_size; i++) {
12244 if (body->local_table[i] == id) {
12245 return 1;
12246 }
12247 }
12248 iseq = body->parent_iseq;
12249 body = ISEQ_BODY(iseq);
12250 }
12251 }
12252 return 0;
12253}
12254
12255int
12256rb_local_defined(ID id, const rb_iseq_t *iseq)
12257{
12258 if (iseq) {
12259 unsigned int i;
12260 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12261
12262 for (i=0; i<body->local_table_size; i++) {
12263 if (body->local_table[i] == id) {
12264 return 1;
12265 }
12266 }
12267 }
12268 return 0;
12269}
12270
12271/* ISeq binary format */
12272
12273#ifndef IBF_ISEQ_DEBUG
12274#define IBF_ISEQ_DEBUG 0
12275#endif
12276
12277#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12278#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12279#endif
12280
12281typedef uint32_t ibf_offset_t;
12282#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12283
12284#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12285#ifdef RUBY_DEVEL
12286#define IBF_DEVEL_VERSION 4
12287#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12288#else
12289#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12290#endif
12291
12292static const char IBF_ENDIAN_MARK =
12293#ifdef WORDS_BIGENDIAN
12294 'b'
12295#else
12296 'l'
12297#endif
12298 ;
12299
12301 char magic[4]; /* YARB */
12302 uint32_t major_version;
12303 uint32_t minor_version;
12304 uint32_t size;
12305 uint32_t extra_size;
12306
12307 uint32_t iseq_list_size;
12308 uint32_t global_object_list_size;
12309 ibf_offset_t iseq_list_offset;
12310 ibf_offset_t global_object_list_offset;
12311 uint8_t endian;
12312 uint8_t wordsize; /* assume no 2048-bit CPU */
12313};
12314
12316 VALUE str;
12317 st_table *obj_table; /* obj -> obj number */
12318};
12319
12320struct ibf_dump {
12321 st_table *iseq_table; /* iseq -> iseq number */
12322 struct ibf_dump_buffer global_buffer;
12323 struct ibf_dump_buffer *current_buffer;
12324};
12325
12327 const char *buff;
12328 ibf_offset_t size;
12329
12330 VALUE obj_list; /* [obj0, ...] */
12331 unsigned int obj_list_size;
12332 ibf_offset_t obj_list_offset;
12333};
12334
12335struct ibf_load {
12336 const struct ibf_header *header;
12337 VALUE iseq_list; /* [iseq0, ...] */
12338 struct ibf_load_buffer global_buffer;
12339 VALUE loader_obj;
12340 rb_iseq_t *iseq;
12341 VALUE str;
12342 struct ibf_load_buffer *current_buffer;
12343};
12344
12346 long size;
12347 VALUE buffer[1];
12348};
12349
12350static void
12351pinned_list_mark(void *ptr)
12352{
12353 long i;
12354 struct pinned_list *list = (struct pinned_list *)ptr;
12355 for (i = 0; i < list->size; i++) {
12356 if (list->buffer[i]) {
12357 rb_gc_mark(list->buffer[i]);
12358 }
12359 }
12360}
12361
12362static const rb_data_type_t pinned_list_type = {
12363 "pinned_list",
12364 {
12365 pinned_list_mark,
12367 NULL, // No external memory to report,
12368 },
12369 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12370};
12371
12372static VALUE
12373pinned_list_fetch(VALUE list, long offset)
12374{
12375 struct pinned_list * ptr;
12376
12377 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12378
12379 if (offset >= ptr->size) {
12380 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12381 }
12382
12383 return ptr->buffer[offset];
12384}
12385
12386static void
12387pinned_list_store(VALUE list, long offset, VALUE object)
12388{
12389 struct pinned_list * ptr;
12390
12391 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12392
12393 if (offset >= ptr->size) {
12394 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12395 }
12396
12397 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12398}
12399
12400static VALUE
12401pinned_list_new(long size)
12402{
12403 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12404 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12405 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12406 ptr->size = size;
12407 return obj_list;
12408}
12409
12410static ibf_offset_t
12411ibf_dump_pos(struct ibf_dump *dump)
12412{
12413 long pos = RSTRING_LEN(dump->current_buffer->str);
12414#if SIZEOF_LONG > SIZEOF_INT
12415 if (pos >= UINT_MAX) {
12416 rb_raise(rb_eRuntimeError, "dump size exceeds");
12417 }
12418#endif
12419 return (unsigned int)pos;
12420}
12421
12422static void
12423ibf_dump_align(struct ibf_dump *dump, size_t align)
12424{
12425 ibf_offset_t pos = ibf_dump_pos(dump);
12426 if (pos % align) {
12427 static const char padding[sizeof(VALUE)];
12428 size_t size = align - ((size_t)pos % align);
12429#if SIZEOF_LONG > SIZEOF_INT
12430 if (pos + size >= UINT_MAX) {
12431 rb_raise(rb_eRuntimeError, "dump size exceeds");
12432 }
12433#endif
12434 for (; size > sizeof(padding); size -= sizeof(padding)) {
12435 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12436 }
12437 rb_str_cat(dump->current_buffer->str, padding, size);
12438 }
12439}
12440
12441static ibf_offset_t
12442ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12443{
12444 ibf_offset_t pos = ibf_dump_pos(dump);
12445 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12446 /* TODO: overflow check */
12447 return pos;
12448}
12449
12450static ibf_offset_t
12451ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12452{
12453 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12454}
12455
12456static void
12457ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12458{
12459 VALUE str = dump->current_buffer->str;
12460 char *ptr = RSTRING_PTR(str);
12461 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12462 rb_bug("ibf_dump_overwrite: overflow");
12463 memcpy(ptr + offset, buff, size);
12464}
12465
12466static const void *
12467ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12468{
12469 ibf_offset_t beg = *offset;
12470 *offset += size;
12471 return load->current_buffer->buff + beg;
12472}
12473
12474static void *
12475ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12476{
12477 void *buff = ruby_xmalloc2(x, y);
12478 size_t size = x * y;
12479 memcpy(buff, load->current_buffer->buff + offset, size);
12480 return buff;
12481}
12482
12483#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12484
12485#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12486#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12487#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12488#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12489#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12490
12491static int
12492ibf_table_lookup(struct st_table *table, st_data_t key)
12493{
12494 st_data_t val;
12495
12496 if (st_lookup(table, key, &val)) {
12497 return (int)val;
12498 }
12499 else {
12500 return -1;
12501 }
12502}
12503
12504static int
12505ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12506{
12507 int index = ibf_table_lookup(table, key);
12508
12509 if (index < 0) { /* not found */
12510 index = (int)table->num_entries;
12511 st_insert(table, key, (st_data_t)index);
12512 }
12513
12514 return index;
12515}
12516
12517/* dump/load generic */
12518
12519static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12520
12521static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12522static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12523
12524static st_table *
12525ibf_dump_object_table_new(void)
12526{
12527 st_table *obj_table = st_init_numtable(); /* need free */
12528 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12529
12530 return obj_table;
12531}
12532
12533static VALUE
12534ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12535{
12536 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12537}
12538
12539static VALUE
12540ibf_dump_id(struct ibf_dump *dump, ID id)
12541{
12542 if (id == 0 || rb_id2name(id) == NULL) {
12543 return 0;
12544 }
12545 return ibf_dump_object(dump, rb_id2sym(id));
12546}
12547
12548static ID
12549ibf_load_id(const struct ibf_load *load, const ID id_index)
12550{
12551 if (id_index == 0) {
12552 return 0;
12553 }
12554 VALUE sym = ibf_load_object(load, id_index);
12555 if (rb_integer_type_p(sym)) {
12556 /* Load hidden local variables as indexes */
12557 return NUM2ULONG(sym);
12558 }
12559 return rb_sym2id(sym);
12560}
12561
12562/* dump/load: code */
12563
12564static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12565
12566static int
12567ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12568{
12569 if (iseq == NULL) {
12570 return -1;
12571 }
12572 else {
12573 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12574 }
12575}
12576
12577static unsigned char
12578ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12579{
12580 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12581 return (unsigned char)load->current_buffer->buff[(*offset)++];
12582}
12583
12584/*
12585 * Small uint serialization
12586 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12587 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12588 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12589 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12590 * ...
12591 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12592 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12593 */
12594static void
12595ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12596{
12597 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12598 ibf_dump_write(dump, &x, sizeof(VALUE));
12599 return;
12600 }
12601
12602 enum { max_byte_length = sizeof(VALUE) + 1 };
12603
12604 unsigned char bytes[max_byte_length];
12605 ibf_offset_t n;
12606
12607 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12608 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12609 }
12610
12611 x <<= 1;
12612 x |= 1;
12613 x <<= n;
12614 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12615 n++;
12616
12617 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12618}
12619
12620static VALUE
12621ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12622{
12623 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12624 union { char s[sizeof(VALUE)]; VALUE v; } x;
12625
12626 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12627 *offset += sizeof(VALUE);
12628
12629 return x.v;
12630 }
12631
12632 enum { max_byte_length = sizeof(VALUE) + 1 };
12633
12634 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12635 const unsigned char c = buffer[*offset];
12636
12637 ibf_offset_t n =
12638 c & 1 ? 1 :
12639 c == 0 ? 9 : ntz_int32(c) + 1;
12640 VALUE x = (VALUE)c >> n;
12641
12642 if (*offset + n > load->current_buffer->size) {
12643 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12644 }
12645
12646 ibf_offset_t i;
12647 for (i = 1; i < n; i++) {
12648 x <<= 8;
12649 x |= (VALUE)buffer[*offset + i];
12650 }
12651
12652 *offset += n;
12653 return x;
12654}
12655
12656static void
12657ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12658{
12659 // short: index
12660 // short: name.length
12661 // bytes: name
12662 // // omit argc (only verify with name)
12663 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12664
12665 size_t len = strlen(bf->name);
12666 ibf_dump_write_small_value(dump, (VALUE)len);
12667 ibf_dump_write(dump, bf->name, len);
12668}
12669
12670static const struct rb_builtin_function *
12671ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12672{
12673 int i = (int)ibf_load_small_value(load, offset);
12674 int len = (int)ibf_load_small_value(load, offset);
12675 const char *name = (char *)ibf_load_ptr(load, offset, len);
12676
12677 if (0) {
12678 fprintf(stderr, "%.*s!!\n", len, name);
12679 }
12680
12681 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12682 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12683 if (strncmp(table[i].name, name, len) != 0) {
12684 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12685 }
12686 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12687
12688 return &table[i];
12689}
12690
12691static ibf_offset_t
12692ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12693{
12694 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12695 const int iseq_size = body->iseq_size;
12696 int code_index;
12697 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12698
12699 ibf_offset_t offset = ibf_dump_pos(dump);
12700
12701 for (code_index=0; code_index<iseq_size;) {
12702 const VALUE insn = orig_code[code_index++];
12703 const char *types = insn_op_types(insn);
12704 int op_index;
12705
12706 /* opcode */
12707 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12708 ibf_dump_write_small_value(dump, insn);
12709
12710 /* operands */
12711 for (op_index=0; types[op_index]; op_index++, code_index++) {
12712 VALUE op = orig_code[code_index];
12713 VALUE wv;
12714
12715 switch (types[op_index]) {
12716 case TS_CDHASH:
12717 case TS_VALUE:
12718 wv = ibf_dump_object(dump, op);
12719 break;
12720 case TS_ISEQ:
12721 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12722 break;
12723 case TS_IC:
12724 {
12725 IC ic = (IC)op;
12726 VALUE arr = idlist_to_array(ic->segments);
12727 wv = ibf_dump_object(dump, arr);
12728 }
12729 break;
12730 case TS_ISE:
12731 case TS_IVC:
12732 case TS_ICVARC:
12733 {
12735 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12736 }
12737 break;
12738 case TS_CALLDATA:
12739 {
12740 goto skip_wv;
12741 }
12742 case TS_ID:
12743 wv = ibf_dump_id(dump, (ID)op);
12744 break;
12745 case TS_FUNCPTR:
12746 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12747 goto skip_wv;
12748 case TS_BUILTIN:
12749 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12750 goto skip_wv;
12751 default:
12752 wv = op;
12753 break;
12754 }
12755 ibf_dump_write_small_value(dump, wv);
12756 skip_wv:;
12757 }
12758 RUBY_ASSERT(insn_len(insn) == op_index+1);
12759 }
12760
12761 return offset;
12762}
12763
12764static VALUE *
12765ibf_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)
12766{
12767 VALUE iseqv = (VALUE)iseq;
12768 unsigned int code_index;
12769 ibf_offset_t reading_pos = bytecode_offset;
12770 VALUE *code = ALLOC_N(VALUE, iseq_size);
12771
12772 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12773 struct rb_call_data *cd_entries = load_body->call_data;
12774 int ic_index = 0;
12775
12776 iseq_bits_t * mark_offset_bits;
12777
12778 iseq_bits_t tmp[1] = {0};
12779
12780 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12781 mark_offset_bits = tmp;
12782 }
12783 else {
12784 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12785 }
12786 bool needs_bitmap = false;
12787
12788 for (code_index=0; code_index<iseq_size;) {
12789 /* opcode */
12790 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12791 const char *types = insn_op_types(insn);
12792 int op_index;
12793
12794 code_index++;
12795
12796 /* operands */
12797 for (op_index=0; types[op_index]; op_index++, code_index++) {
12798 const char operand_type = types[op_index];
12799 switch (operand_type) {
12800 case TS_VALUE:
12801 {
12802 VALUE op = ibf_load_small_value(load, &reading_pos);
12803 VALUE v = ibf_load_object(load, op);
12804 code[code_index] = v;
12805 if (!SPECIAL_CONST_P(v)) {
12806 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12807 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12808 needs_bitmap = true;
12809 }
12810 break;
12811 }
12812 case TS_CDHASH:
12813 {
12814 VALUE op = ibf_load_small_value(load, &reading_pos);
12815 VALUE v = ibf_load_object(load, op);
12816 v = rb_hash_dup(v); // hash dumped as frozen
12817 RHASH_TBL_RAW(v)->type = &cdhash_type;
12818 rb_hash_rehash(v); // hash function changed
12819 freeze_hide_obj(v);
12820
12821 // Overwrite the existing hash in the object list. This
12822 // is to keep the object alive during load time.
12823 // [Bug #17984] [ruby-core:104259]
12824 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12825
12826 code[code_index] = v;
12827 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12828 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12829 needs_bitmap = true;
12830 break;
12831 }
12832 case TS_ISEQ:
12833 {
12834 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12835 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12836 code[code_index] = v;
12837 if (!SPECIAL_CONST_P(v)) {
12838 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12839 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12840 needs_bitmap = true;
12841 }
12842 break;
12843 }
12844 case TS_IC:
12845 {
12846 VALUE op = ibf_load_small_value(load, &reading_pos);
12847 VALUE arr = ibf_load_object(load, op);
12848
12849 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12850 ic->segments = array_to_idlist(arr);
12851
12852 code[code_index] = (VALUE)ic;
12853 }
12854 break;
12855 case TS_ISE:
12856 case TS_ICVARC:
12857 case TS_IVC:
12858 {
12859 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
12860
12861 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12862 code[code_index] = (VALUE)ic;
12863
12864 if (operand_type == TS_IVC) {
12865 IVC cache = (IVC)ic;
12866
12867 if (insn == BIN(setinstancevariable)) {
12868 ID iv_name = (ID)code[code_index - 1];
12869 cache->iv_set_name = iv_name;
12870 }
12871 else {
12872 cache->iv_set_name = 0;
12873 }
12874
12875 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12876 }
12877
12878 }
12879 break;
12880 case TS_CALLDATA:
12881 {
12882 code[code_index] = (VALUE)cd_entries++;
12883 }
12884 break;
12885 case TS_ID:
12886 {
12887 VALUE op = ibf_load_small_value(load, &reading_pos);
12888 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
12889 }
12890 break;
12891 case TS_FUNCPTR:
12892 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12893 break;
12894 case TS_BUILTIN:
12895 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
12896 break;
12897 default:
12898 code[code_index] = ibf_load_small_value(load, &reading_pos);
12899 continue;
12900 }
12901 }
12902 if (insn_len(insn) != op_index+1) {
12903 rb_raise(rb_eRuntimeError, "operand size mismatch");
12904 }
12905 }
12906
12907 load_body->iseq_encoded = code;
12908 load_body->iseq_size = code_index;
12909
12910 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
12911 load_body->mark_bits.single = mark_offset_bits[0];
12912 }
12913 else {
12914 if (needs_bitmap) {
12915 load_body->mark_bits.list = mark_offset_bits;
12916 }
12917 else {
12918 load_body->mark_bits.list = 0;
12919 ruby_xfree(mark_offset_bits);
12920 }
12921 }
12922
12923 RUBY_ASSERT(code_index == iseq_size);
12924 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
12925 return code;
12926}
12927
12928static ibf_offset_t
12929ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12930{
12931 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
12932
12933 if (opt_num > 0) {
12934 IBF_W_ALIGN(VALUE);
12935 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
12936 }
12937 else {
12938 return ibf_dump_pos(dump);
12939 }
12940}
12941
12942static VALUE *
12943ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
12944{
12945 if (opt_num > 0) {
12946 VALUE *table = ALLOC_N(VALUE, opt_num+1);
12947 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
12948 return table;
12949 }
12950 else {
12951 return NULL;
12952 }
12953}
12954
12955static ibf_offset_t
12956ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
12957{
12958 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
12959
12960 if (kw) {
12961 struct rb_iseq_param_keyword dump_kw = *kw;
12962 int dv_num = kw->num - kw->required_num;
12963 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
12964 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
12965 int i;
12966
12967 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12968 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12969
12970 dump_kw.table = IBF_W(ids, ID, kw->num);
12971 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12972 IBF_W_ALIGN(struct rb_iseq_param_keyword);
12973 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12974 }
12975 else {
12976 return 0;
12977 }
12978}
12979
12980static const struct rb_iseq_param_keyword *
12981ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
12982{
12983 if (param_keyword_offset) {
12984 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
12985 int dv_num = kw->num - kw->required_num;
12986 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
12987
12988 int i;
12989 for (i=0; i<dv_num; i++) {
12990 dvs[i] = ibf_load_object(load, dvs[i]);
12991 }
12992
12993 // Will be set once the local table is loaded.
12994 kw->table = NULL;
12995
12996 kw->default_values = dvs;
12997 return kw;
12998 }
12999 else {
13000 return NULL;
13001 }
13002}
13003
13004static ibf_offset_t
13005ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13006{
13007 ibf_offset_t offset = ibf_dump_pos(dump);
13008 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13009
13010 unsigned int i;
13011 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13012 ibf_dump_write_small_value(dump, entries[i].line_no);
13013#ifdef USE_ISEQ_NODE_ID
13014 ibf_dump_write_small_value(dump, entries[i].node_id);
13015#endif
13016 ibf_dump_write_small_value(dump, entries[i].events);
13017 }
13018
13019 return offset;
13020}
13021
13022static struct iseq_insn_info_entry *
13023ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13024{
13025 ibf_offset_t reading_pos = body_offset;
13026 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13027
13028 unsigned int i;
13029 for (i = 0; i < size; i++) {
13030 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13031#ifdef USE_ISEQ_NODE_ID
13032 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13033#endif
13034 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13035 }
13036
13037 return entries;
13038}
13039
13040static ibf_offset_t
13041ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13042{
13043 ibf_offset_t offset = ibf_dump_pos(dump);
13044
13045 unsigned int last = 0;
13046 unsigned int i;
13047 for (i = 0; i < size; i++) {
13048 ibf_dump_write_small_value(dump, positions[i] - last);
13049 last = positions[i];
13050 }
13051
13052 return offset;
13053}
13054
13055static unsigned int *
13056ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13057{
13058 ibf_offset_t reading_pos = positions_offset;
13059 unsigned int *positions = ALLOC_N(unsigned int, size);
13060
13061 unsigned int last = 0;
13062 unsigned int i;
13063 for (i = 0; i < size; i++) {
13064 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13065 last = positions[i];
13066 }
13067
13068 return positions;
13069}
13070
13071static ibf_offset_t
13072ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13073{
13074 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13075 const int size = body->local_table_size;
13076 ID *table = ALLOCA_N(ID, size);
13077 int i;
13078
13079 for (i=0; i<size; i++) {
13080 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13081 if (v == 0) {
13082 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13083 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13084 }
13085 table[i] = v;
13086 }
13087
13088 IBF_W_ALIGN(ID);
13089 return ibf_dump_write(dump, table, sizeof(ID) * size);
13090}
13091
13092static ID *
13093ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13094{
13095 if (size > 0) {
13096 ID *table = IBF_R(local_table_offset, ID, size);
13097 int i;
13098
13099 for (i=0; i<size; i++) {
13100 table[i] = ibf_load_id(load, table[i]);
13101 }
13102 return table;
13103 }
13104 else {
13105 return NULL;
13106 }
13107}
13108
13109static ibf_offset_t
13110ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13111{
13112 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13113
13114 if (table) {
13115 int *iseq_indices = ALLOCA_N(int, table->size);
13116 unsigned int i;
13117
13118 for (i=0; i<table->size; i++) {
13119 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13120 }
13121
13122 const ibf_offset_t offset = ibf_dump_pos(dump);
13123
13124 for (i=0; i<table->size; i++) {
13125 ibf_dump_write_small_value(dump, iseq_indices[i]);
13126 ibf_dump_write_small_value(dump, table->entries[i].type);
13127 ibf_dump_write_small_value(dump, table->entries[i].start);
13128 ibf_dump_write_small_value(dump, table->entries[i].end);
13129 ibf_dump_write_small_value(dump, table->entries[i].cont);
13130 ibf_dump_write_small_value(dump, table->entries[i].sp);
13131 }
13132 return offset;
13133 }
13134 else {
13135 return ibf_dump_pos(dump);
13136 }
13137}
13138
13139static struct iseq_catch_table *
13140ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
13141{
13142 if (size) {
13143 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13144 table->size = size;
13145
13146 ibf_offset_t reading_pos = catch_table_offset;
13147
13148 unsigned int i;
13149 for (i=0; i<table->size; i++) {
13150 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13151 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13152 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13153 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13154 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13155 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13156
13157 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13158 }
13159 return table;
13160 }
13161 else {
13162 return NULL;
13163 }
13164}
13165
13166static ibf_offset_t
13167ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13168{
13169 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13170 const unsigned int ci_size = body->ci_size;
13171 const struct rb_call_data *cds = body->call_data;
13172
13173 ibf_offset_t offset = ibf_dump_pos(dump);
13174
13175 unsigned int i;
13176
13177 for (i = 0; i < ci_size; i++) {
13178 const struct rb_callinfo *ci = cds[i].ci;
13179 if (ci != NULL) {
13180 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13181 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13182 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13183
13184 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13185 if (kwarg) {
13186 int len = kwarg->keyword_len;
13187 ibf_dump_write_small_value(dump, len);
13188 for (int j=0; j<len; j++) {
13189 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13190 ibf_dump_write_small_value(dump, keyword);
13191 }
13192 }
13193 else {
13194 ibf_dump_write_small_value(dump, 0);
13195 }
13196 }
13197 else {
13198 // TODO: truncate NULL ci from call_data.
13199 ibf_dump_write_small_value(dump, (VALUE)-1);
13200 }
13201 }
13202
13203 return offset;
13204}
13205
13207 ID id;
13208 VALUE name;
13209 VALUE val;
13210};
13211
13213 size_t num;
13214 struct outer_variable_pair pairs[1];
13215};
13216
13217static enum rb_id_table_iterator_result
13218store_outer_variable(ID id, VALUE val, void *dump)
13219{
13220 struct outer_variable_list *ovlist = dump;
13221 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13222 pair->id = id;
13223 pair->name = rb_id2str(id);
13224 pair->val = val;
13225 return ID_TABLE_CONTINUE;
13226}
13227
13228static int
13229outer_variable_cmp(const void *a, const void *b, void *arg)
13230{
13231 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13232 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13233 return rb_str_cmp(ap->name, bp->name);
13234}
13235
13236static ibf_offset_t
13237ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13238{
13239 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13240
13241 ibf_offset_t offset = ibf_dump_pos(dump);
13242
13243 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13244 ibf_dump_write_small_value(dump, (VALUE)size);
13245 if (size > 0) {
13246 VALUE buff;
13247 size_t buffsize =
13248 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13249 offsetof(struct outer_variable_list, pairs),
13250 rb_eArgError);
13251 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13252 ovlist->num = 0;
13253 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13254 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13255 for (size_t i = 0; i < size; ++i) {
13256 ID id = ovlist->pairs[i].id;
13257 ID val = ovlist->pairs[i].val;
13258 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13259 ibf_dump_write_small_value(dump, val);
13260 }
13261 }
13262
13263 return offset;
13264}
13265
13266/* note that we dump out rb_call_info but load back rb_call_data */
13267static void
13268ibf_load_ci_entries(const struct ibf_load *load,
13269 ibf_offset_t ci_entries_offset,
13270 unsigned int ci_size,
13271 struct rb_call_data **cd_ptr)
13272{
13273 ibf_offset_t reading_pos = ci_entries_offset;
13274
13275 unsigned int i;
13276
13277 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13278 *cd_ptr = cds;
13279
13280 for (i = 0; i < ci_size; i++) {
13281 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13282 if (mid_index != (VALUE)-1) {
13283 ID mid = ibf_load_id(load, mid_index);
13284 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13285 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13286
13287 struct rb_callinfo_kwarg *kwarg = NULL;
13288 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13289 if (kwlen > 0) {
13290 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13291 kwarg->references = 0;
13292 kwarg->keyword_len = kwlen;
13293 for (int j=0; j<kwlen; j++) {
13294 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13295 kwarg->keywords[j] = ibf_load_object(load, keyword);
13296 }
13297 }
13298
13299 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13300 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13301 cds[i].cc = vm_cc_empty();
13302 }
13303 else {
13304 // NULL ci
13305 cds[i].ci = NULL;
13306 cds[i].cc = NULL;
13307 }
13308 }
13309}
13310
13311static struct rb_id_table *
13312ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13313{
13314 ibf_offset_t reading_pos = outer_variables_offset;
13315
13316 struct rb_id_table *tbl = NULL;
13317
13318 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13319
13320 if (table_size > 0) {
13321 tbl = rb_id_table_create(table_size);
13322 }
13323
13324 for (size_t i = 0; i < table_size; i++) {
13325 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13326 VALUE value = ibf_load_small_value(load, &reading_pos);
13327 if (!key) key = rb_make_temporary_id(i);
13328 rb_id_table_insert(tbl, key, value);
13329 }
13330
13331 return tbl;
13332}
13333
13334static ibf_offset_t
13335ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13336{
13337 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13338
13339 unsigned int *positions;
13340
13341 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13342
13343 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13344 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13345 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13346
13347#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13348 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13349
13350 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13351 struct ibf_dump_buffer buffer;
13352 buffer.str = rb_str_new(0, 0);
13353 buffer.obj_table = ibf_dump_object_table_new();
13354 dump->current_buffer = &buffer;
13355#endif
13356
13357 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13358 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13359 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13360 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13361 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13362
13363 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13364 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13365 ruby_xfree(positions);
13366
13367 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13368 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13369 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13370 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13371 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13372 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13373 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13374 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13375
13376#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13377 ibf_offset_t local_obj_list_offset;
13378 unsigned int local_obj_list_size;
13379
13380 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13381#endif
13382
13383 ibf_offset_t body_offset = ibf_dump_pos(dump);
13384
13385 /* dump the constant body */
13386 unsigned int param_flags =
13387 (body->param.flags.has_lead << 0) |
13388 (body->param.flags.has_opt << 1) |
13389 (body->param.flags.has_rest << 2) |
13390 (body->param.flags.has_post << 3) |
13391 (body->param.flags.has_kw << 4) |
13392 (body->param.flags.has_kwrest << 5) |
13393 (body->param.flags.has_block << 6) |
13394 (body->param.flags.ambiguous_param0 << 7) |
13395 (body->param.flags.accepts_no_kwarg << 8) |
13396 (body->param.flags.ruby2_keywords << 9) |
13397 (body->param.flags.anon_rest << 10) |
13398 (body->param.flags.anon_kwrest << 11) |
13399 (body->param.flags.use_block << 12) |
13400 (body->param.flags.forwardable << 13) ;
13401
13402#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13403# define IBF_BODY_OFFSET(x) (x)
13404#else
13405# define IBF_BODY_OFFSET(x) (body_offset - (x))
13406#endif
13407
13408 ibf_dump_write_small_value(dump, body->type);
13409 ibf_dump_write_small_value(dump, body->iseq_size);
13410 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13411 ibf_dump_write_small_value(dump, bytecode_size);
13412 ibf_dump_write_small_value(dump, param_flags);
13413 ibf_dump_write_small_value(dump, body->param.size);
13414 ibf_dump_write_small_value(dump, body->param.lead_num);
13415 ibf_dump_write_small_value(dump, body->param.opt_num);
13416 ibf_dump_write_small_value(dump, body->param.rest_start);
13417 ibf_dump_write_small_value(dump, body->param.post_start);
13418 ibf_dump_write_small_value(dump, body->param.post_num);
13419 ibf_dump_write_small_value(dump, body->param.block_start);
13420 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13421 ibf_dump_write_small_value(dump, param_keyword_offset);
13422 ibf_dump_write_small_value(dump, location_pathobj_index);
13423 ibf_dump_write_small_value(dump, location_base_label_index);
13424 ibf_dump_write_small_value(dump, location_label_index);
13425 ibf_dump_write_small_value(dump, body->location.first_lineno);
13426 ibf_dump_write_small_value(dump, body->location.node_id);
13427 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13428 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13429 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13430 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13431 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13432 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13433 ibf_dump_write_small_value(dump, body->insns_info.size);
13434 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13435 ibf_dump_write_small_value(dump, catch_table_size);
13436 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13437 ibf_dump_write_small_value(dump, parent_iseq_index);
13438 ibf_dump_write_small_value(dump, local_iseq_index);
13439 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13440 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13441 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13442 ibf_dump_write_small_value(dump, body->variable.flip_count);
13443 ibf_dump_write_small_value(dump, body->local_table_size);
13444 ibf_dump_write_small_value(dump, body->ivc_size);
13445 ibf_dump_write_small_value(dump, body->icvarc_size);
13446 ibf_dump_write_small_value(dump, body->ise_size);
13447 ibf_dump_write_small_value(dump, body->ic_size);
13448 ibf_dump_write_small_value(dump, body->ci_size);
13449 ibf_dump_write_small_value(dump, body->stack_max);
13450 ibf_dump_write_small_value(dump, body->builtin_attrs);
13451 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13452
13453#undef IBF_BODY_OFFSET
13454
13455#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13456 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13457
13458 dump->current_buffer = saved_buffer;
13459 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13460
13461 ibf_offset_t offset = ibf_dump_pos(dump);
13462 ibf_dump_write_small_value(dump, iseq_start);
13463 ibf_dump_write_small_value(dump, iseq_length_bytes);
13464 ibf_dump_write_small_value(dump, body_offset);
13465
13466 ibf_dump_write_small_value(dump, local_obj_list_offset);
13467 ibf_dump_write_small_value(dump, local_obj_list_size);
13468
13469 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13470
13471 return offset;
13472#else
13473 return body_offset;
13474#endif
13475}
13476
13477static VALUE
13478ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13479{
13480 VALUE str = ibf_load_object(load, str_index);
13481 if (str != Qnil) {
13482 str = rb_fstring(str);
13483 }
13484 return str;
13485}
13486
13487static void
13488ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13489{
13490 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13491
13492 ibf_offset_t reading_pos = offset;
13493
13494#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13495 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13496 load->current_buffer = &load->global_buffer;
13497
13498 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13499 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13500 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13501
13502 struct ibf_load_buffer buffer;
13503 buffer.buff = load->global_buffer.buff + iseq_start;
13504 buffer.size = iseq_length_bytes;
13505 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13506 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13507 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13508
13509 load->current_buffer = &buffer;
13510 reading_pos = body_offset;
13511#endif
13512
13513#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13514# define IBF_BODY_OFFSET(x) (x)
13515#else
13516# define IBF_BODY_OFFSET(x) (offset - (x))
13517#endif
13518
13519 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13520 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13521 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13522 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13523 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13524 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13525 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13526 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13527 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13528 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13529 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13530 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13531 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13532 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13533 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13534 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13535 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13536 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13537 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13538 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13539 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13540 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13541 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13542 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13543 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13544 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13545 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13546 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13547 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13548 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13549 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13550 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13551 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13552 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13553 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13554 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13555
13556 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13557 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13558 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13559 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13560
13561 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13562 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13563 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13564 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13565
13566 // setup fname and dummy frame
13567 VALUE path = ibf_load_object(load, location_pathobj_index);
13568 {
13569 VALUE realpath = Qnil;
13570
13571 if (RB_TYPE_P(path, T_STRING)) {
13572 realpath = path = rb_fstring(path);
13573 }
13574 else if (RB_TYPE_P(path, T_ARRAY)) {
13575 VALUE pathobj = path;
13576 if (RARRAY_LEN(pathobj) != 2) {
13577 rb_raise(rb_eRuntimeError, "path object size mismatch");
13578 }
13579 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13580 realpath = RARRAY_AREF(pathobj, 1);
13581 if (!NIL_P(realpath)) {
13582 if (!RB_TYPE_P(realpath, T_STRING)) {
13583 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13584 "(%x), path=%+"PRIsVALUE,
13585 realpath, TYPE(realpath), path);
13586 }
13587 realpath = rb_fstring(realpath);
13588 }
13589 }
13590 else {
13591 rb_raise(rb_eRuntimeError, "unexpected path object");
13592 }
13593 rb_iseq_pathobj_set(iseq, path, realpath);
13594 }
13595
13596 // push dummy frame
13597 rb_execution_context_t *ec = GET_EC();
13598 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13599
13600#undef IBF_BODY_OFFSET
13601
13602 load_body->type = type;
13603 load_body->stack_max = stack_max;
13604 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13605 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13606 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13607 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13608 load_body->param.flags.has_kw = FALSE;
13609 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13610 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13611 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13612 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13613 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13614 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13615 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13616 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13617 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13618 load_body->param.size = param_size;
13619 load_body->param.lead_num = param_lead_num;
13620 load_body->param.opt_num = param_opt_num;
13621 load_body->param.rest_start = param_rest_start;
13622 load_body->param.post_start = param_post_start;
13623 load_body->param.post_num = param_post_num;
13624 load_body->param.block_start = param_block_start;
13625 load_body->local_table_size = local_table_size;
13626 load_body->ci_size = ci_size;
13627 load_body->insns_info.size = insns_info_size;
13628
13629 ISEQ_COVERAGE_SET(iseq, Qnil);
13630 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13631 load_body->variable.flip_count = variable_flip_count;
13632 load_body->variable.script_lines = Qnil;
13633
13634 load_body->location.first_lineno = location_first_lineno;
13635 load_body->location.node_id = location_node_id;
13636 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13637 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13638 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13639 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13640 load_body->builtin_attrs = builtin_attrs;
13641 load_body->prism = prism;
13642
13643 load_body->ivc_size = ivc_size;
13644 load_body->icvarc_size = icvarc_size;
13645 load_body->ise_size = ise_size;
13646 load_body->ic_size = ic_size;
13647
13648 if (ISEQ_IS_SIZE(load_body)) {
13649 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13650 }
13651 else {
13652 load_body->is_entries = NULL;
13653 }
13654 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13655 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13656 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13657 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13658 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13659 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13660 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13661 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13662 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
13663 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13664 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13665 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13666
13667 // This must be done after the local table is loaded.
13668 if (load_body->param.keyword != NULL) {
13669 RUBY_ASSERT(load_body->local_table);
13670 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13671 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13672 }
13673
13674 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13675#if VM_INSN_INFO_TABLE_IMPL == 2
13676 rb_iseq_insns_info_encode_positions(iseq);
13677#endif
13678
13679 rb_iseq_translate_threaded_code(iseq);
13680
13681#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13682 load->current_buffer = &load->global_buffer;
13683#endif
13684
13685 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13686 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13687
13688#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13689 load->current_buffer = saved_buffer;
13690#endif
13691 verify_call_cache(iseq);
13692
13693 RB_GC_GUARD(dummy_frame);
13694 rb_vm_pop_frame_no_int(ec);
13695}
13696
13698{
13699 struct ibf_dump *dump;
13700 VALUE offset_list;
13701};
13702
13703static int
13704ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13705{
13706 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13707 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13708
13709 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13710 rb_ary_push(args->offset_list, UINT2NUM(offset));
13711
13712 return ST_CONTINUE;
13713}
13714
13715static void
13716ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13717{
13718 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13719
13720 struct ibf_dump_iseq_list_arg args;
13721 args.dump = dump;
13722 args.offset_list = offset_list;
13723
13724 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13725
13726 st_index_t i;
13727 st_index_t size = dump->iseq_table->num_entries;
13728 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13729
13730 for (i = 0; i < size; i++) {
13731 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13732 }
13733
13734 ibf_dump_align(dump, sizeof(ibf_offset_t));
13735 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13736 header->iseq_list_size = (unsigned int)size;
13737}
13738
13739#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13740
13741/*
13742 * Binary format
13743 * - ibf_object_header
13744 * - ibf_object_xxx (xxx is type)
13745 */
13746
13748 unsigned int type: 5;
13749 unsigned int special_const: 1;
13750 unsigned int frozen: 1;
13751 unsigned int internal: 1;
13752};
13753
13754enum ibf_object_class_index {
13755 IBF_OBJECT_CLASS_OBJECT,
13756 IBF_OBJECT_CLASS_ARRAY,
13757 IBF_OBJECT_CLASS_STANDARD_ERROR,
13758 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13759 IBF_OBJECT_CLASS_TYPE_ERROR,
13760 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13761};
13762
13764 long srcstr;
13765 char option;
13766};
13767
13769 long len;
13770 long keyval[FLEX_ARY_LEN];
13771};
13772
13774 long class_index;
13775 long len;
13776 long beg;
13777 long end;
13778 int excl;
13779};
13780
13782 ssize_t slen;
13783 BDIGIT digits[FLEX_ARY_LEN];
13784};
13785
13786enum ibf_object_data_type {
13787 IBF_OBJECT_DATA_ENCODING,
13788};
13789
13791 long a, b;
13792};
13793
13795 long str;
13796};
13797
13798#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13799 ((((offset) - 1) / (align) + 1) * (align))
13800#define IBF_OBJBODY(type, offset) (const type *)\
13801 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13802
13803static const void *
13804ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13805{
13806 if (offset >= load->current_buffer->size) {
13807 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13808 }
13809 return load->current_buffer->buff + offset;
13810}
13811
13812NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13813
13814static void
13815ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13816{
13817 char buff[0x100];
13818 rb_raw_obj_info(buff, sizeof(buff), obj);
13819 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13820}
13821
13822NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13823
13824static VALUE
13825ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13826{
13827 rb_raise(rb_eArgError, "unsupported");
13829}
13830
13831static void
13832ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13833{
13834 enum ibf_object_class_index cindex;
13835 if (obj == rb_cObject) {
13836 cindex = IBF_OBJECT_CLASS_OBJECT;
13837 }
13838 else if (obj == rb_cArray) {
13839 cindex = IBF_OBJECT_CLASS_ARRAY;
13840 }
13841 else if (obj == rb_eStandardError) {
13842 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13843 }
13844 else if (obj == rb_eNoMatchingPatternError) {
13845 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13846 }
13847 else if (obj == rb_eTypeError) {
13848 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13849 }
13850 else if (obj == rb_eNoMatchingPatternKeyError) {
13851 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13852 }
13853 else {
13854 rb_obj_info_dump(obj);
13855 rb_p(obj);
13856 rb_bug("unsupported class");
13857 }
13858 ibf_dump_write_small_value(dump, (VALUE)cindex);
13859}
13860
13861static VALUE
13862ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13863{
13864 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13865
13866 switch (cindex) {
13867 case IBF_OBJECT_CLASS_OBJECT:
13868 return rb_cObject;
13869 case IBF_OBJECT_CLASS_ARRAY:
13870 return rb_cArray;
13871 case IBF_OBJECT_CLASS_STANDARD_ERROR:
13872 return rb_eStandardError;
13873 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13875 case IBF_OBJECT_CLASS_TYPE_ERROR:
13876 return rb_eTypeError;
13877 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13879 }
13880
13881 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
13882}
13883
13884
13885static void
13886ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
13887{
13888 double dbl = RFLOAT_VALUE(obj);
13889 (void)IBF_W(&dbl, double, 1);
13890}
13891
13892static VALUE
13893ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13894{
13895 const double *dblp = IBF_OBJBODY(double, offset);
13896 return DBL2NUM(*dblp);
13897}
13898
13899static void
13900ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
13901{
13902 long encindex = (long)rb_enc_get_index(obj);
13903 long len = RSTRING_LEN(obj);
13904 const char *ptr = RSTRING_PTR(obj);
13905
13906 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13907 rb_encoding *enc = rb_enc_from_index((int)encindex);
13908 const char *enc_name = rb_enc_name(enc);
13909 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
13910 }
13911
13912 ibf_dump_write_small_value(dump, encindex);
13913 ibf_dump_write_small_value(dump, len);
13914 IBF_WP(ptr, char, len);
13915}
13916
13917static VALUE
13918ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13919{
13920 ibf_offset_t reading_pos = offset;
13921
13922 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13923 const long len = (long)ibf_load_small_value(load, &reading_pos);
13924 const char *ptr = load->current_buffer->buff + reading_pos;
13925
13926 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13927 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13928 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13929 }
13930
13931 VALUE str;
13932 if (header->frozen && !header->internal) {
13933 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
13934 }
13935 else {
13936 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
13937
13938 if (header->internal) rb_obj_hide(str);
13939 if (header->frozen) str = rb_fstring(str);
13940 }
13941 return str;
13942}
13943
13944static void
13945ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
13946{
13947 VALUE srcstr = RREGEXP_SRC(obj);
13948 struct ibf_object_regexp regexp;
13949 regexp.option = (char)rb_reg_options(obj);
13950 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
13951
13952 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
13953 ibf_dump_write_small_value(dump, regexp.srcstr);
13954}
13955
13956static VALUE
13957ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13958{
13959 struct ibf_object_regexp regexp;
13960 regexp.option = ibf_load_byte(load, &offset);
13961 regexp.srcstr = ibf_load_small_value(load, &offset);
13962
13963 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
13964 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
13965
13966 if (header->internal) rb_obj_hide(reg);
13967 if (header->frozen) rb_obj_freeze(reg);
13968
13969 return reg;
13970}
13971
13972static void
13973ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
13974{
13975 long i, len = RARRAY_LEN(obj);
13976 ibf_dump_write_small_value(dump, len);
13977 for (i=0; i<len; i++) {
13978 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
13979 ibf_dump_write_small_value(dump, index);
13980 }
13981}
13982
13983static VALUE
13984ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13985{
13986 ibf_offset_t reading_pos = offset;
13987
13988 const long len = (long)ibf_load_small_value(load, &reading_pos);
13989
13990 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
13991 int i;
13992
13993 for (i=0; i<len; i++) {
13994 const VALUE index = ibf_load_small_value(load, &reading_pos);
13995 rb_ary_push(ary, ibf_load_object(load, index));
13996 }
13997
13998 if (header->frozen) rb_ary_freeze(ary);
13999
14000 return ary;
14001}
14002
14003static int
14004ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14005{
14006 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14007
14008 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14009 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14010
14011 ibf_dump_write_small_value(dump, key_index);
14012 ibf_dump_write_small_value(dump, val_index);
14013 return ST_CONTINUE;
14014}
14015
14016static void
14017ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14018{
14019 long len = RHASH_SIZE(obj);
14020 ibf_dump_write_small_value(dump, (VALUE)len);
14021
14022 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14023}
14024
14025static VALUE
14026ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14027{
14028 long len = (long)ibf_load_small_value(load, &offset);
14029 VALUE obj = rb_hash_new_with_size(len);
14030 int i;
14031
14032 for (i = 0; i < len; i++) {
14033 VALUE key_index = ibf_load_small_value(load, &offset);
14034 VALUE val_index = ibf_load_small_value(load, &offset);
14035
14036 VALUE key = ibf_load_object(load, key_index);
14037 VALUE val = ibf_load_object(load, val_index);
14038 rb_hash_aset(obj, key, val);
14039 }
14040 rb_hash_rehash(obj);
14041
14042 if (header->internal) rb_obj_hide(obj);
14043 if (header->frozen) rb_obj_freeze(obj);
14044
14045 return obj;
14046}
14047
14048static void
14049ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14050{
14051 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14052 struct ibf_object_struct_range range;
14053 VALUE beg, end;
14054 IBF_ZERO(range);
14055 range.len = 3;
14056 range.class_index = 0;
14057
14058 rb_range_values(obj, &beg, &end, &range.excl);
14059 range.beg = (long)ibf_dump_object(dump, beg);
14060 range.end = (long)ibf_dump_object(dump, end);
14061
14062 IBF_W_ALIGN(struct ibf_object_struct_range);
14063 IBF_WV(range);
14064 }
14065 else {
14066 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14067 rb_class_name(CLASS_OF(obj)));
14068 }
14069}
14070
14071static VALUE
14072ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14073{
14074 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14075 VALUE beg = ibf_load_object(load, range->beg);
14076 VALUE end = ibf_load_object(load, range->end);
14077 VALUE obj = rb_range_new(beg, end, range->excl);
14078 if (header->internal) rb_obj_hide(obj);
14079 if (header->frozen) rb_obj_freeze(obj);
14080 return obj;
14081}
14082
14083static void
14084ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14085{
14086 ssize_t len = BIGNUM_LEN(obj);
14087 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14088 BDIGIT *d = BIGNUM_DIGITS(obj);
14089
14090 (void)IBF_W(&slen, ssize_t, 1);
14091 IBF_WP(d, BDIGIT, len);
14092}
14093
14094static VALUE
14095ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14096{
14097 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14098 int sign = bignum->slen > 0;
14099 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14100 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14103 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14104 big_unpack_flags |
14105 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14106 if (header->internal) rb_obj_hide(obj);
14107 if (header->frozen) rb_obj_freeze(obj);
14108 return obj;
14109}
14110
14111static void
14112ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14113{
14114 if (rb_data_is_encoding(obj)) {
14115 rb_encoding *enc = rb_to_encoding(obj);
14116 const char *name = rb_enc_name(enc);
14117 long len = strlen(name) + 1;
14118 long data[2];
14119 data[0] = IBF_OBJECT_DATA_ENCODING;
14120 data[1] = len;
14121 (void)IBF_W(data, long, 2);
14122 IBF_WP(name, char, len);
14123 }
14124 else {
14125 ibf_dump_object_unsupported(dump, obj);
14126 }
14127}
14128
14129static VALUE
14130ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14131{
14132 const long *body = IBF_OBJBODY(long, offset);
14133 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14134 /* const long len = body[1]; */
14135 const char *data = (const char *)&body[2];
14136
14137 switch (type) {
14138 case IBF_OBJECT_DATA_ENCODING:
14139 {
14140 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14141 return encobj;
14142 }
14143 }
14144
14145 return ibf_load_object_unsupported(load, header, offset);
14146}
14147
14148static void
14149ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14150{
14151 long data[2];
14152 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14153 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14154
14155 (void)IBF_W(data, long, 2);
14156}
14157
14158static VALUE
14159ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14160{
14161 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14162 VALUE a = ibf_load_object(load, nums->a);
14163 VALUE b = ibf_load_object(load, nums->b);
14164 VALUE obj = header->type == T_COMPLEX ?
14165 rb_complex_new(a, b) : rb_rational_new(a, b);
14166
14167 if (header->internal) rb_obj_hide(obj);
14168 if (header->frozen) rb_obj_freeze(obj);
14169 return obj;
14170}
14171
14172static void
14173ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14174{
14175 ibf_dump_object_string(dump, rb_sym2str(obj));
14176}
14177
14178static VALUE
14179ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14180{
14181 ibf_offset_t reading_pos = offset;
14182
14183 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14184 const long len = (long)ibf_load_small_value(load, &reading_pos);
14185 const char *ptr = load->current_buffer->buff + reading_pos;
14186
14187 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14188 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14189 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14190 }
14191
14192 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14193 return ID2SYM(id);
14194}
14195
14196typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14197static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14198 ibf_dump_object_unsupported, /* T_NONE */
14199 ibf_dump_object_unsupported, /* T_OBJECT */
14200 ibf_dump_object_class, /* T_CLASS */
14201 ibf_dump_object_unsupported, /* T_MODULE */
14202 ibf_dump_object_float, /* T_FLOAT */
14203 ibf_dump_object_string, /* T_STRING */
14204 ibf_dump_object_regexp, /* T_REGEXP */
14205 ibf_dump_object_array, /* T_ARRAY */
14206 ibf_dump_object_hash, /* T_HASH */
14207 ibf_dump_object_struct, /* T_STRUCT */
14208 ibf_dump_object_bignum, /* T_BIGNUM */
14209 ibf_dump_object_unsupported, /* T_FILE */
14210 ibf_dump_object_data, /* T_DATA */
14211 ibf_dump_object_unsupported, /* T_MATCH */
14212 ibf_dump_object_complex_rational, /* T_COMPLEX */
14213 ibf_dump_object_complex_rational, /* T_RATIONAL */
14214 ibf_dump_object_unsupported, /* 0x10 */
14215 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14216 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14217 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14218 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14219 ibf_dump_object_unsupported, /* T_FIXNUM */
14220 ibf_dump_object_unsupported, /* T_UNDEF */
14221 ibf_dump_object_unsupported, /* 0x17 */
14222 ibf_dump_object_unsupported, /* 0x18 */
14223 ibf_dump_object_unsupported, /* 0x19 */
14224 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14225 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14226 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14227 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14228 ibf_dump_object_unsupported, /* 0x1e */
14229 ibf_dump_object_unsupported, /* 0x1f */
14230};
14231
14232static void
14233ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14234{
14235 unsigned char byte =
14236 (header.type << 0) |
14237 (header.special_const << 5) |
14238 (header.frozen << 6) |
14239 (header.internal << 7);
14240
14241 IBF_WV(byte);
14242}
14243
14244static struct ibf_object_header
14245ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14246{
14247 unsigned char byte = ibf_load_byte(load, offset);
14248
14249 struct ibf_object_header header;
14250 header.type = (byte >> 0) & 0x1f;
14251 header.special_const = (byte >> 5) & 0x01;
14252 header.frozen = (byte >> 6) & 0x01;
14253 header.internal = (byte >> 7) & 0x01;
14254
14255 return header;
14256}
14257
14258static ibf_offset_t
14259ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14260{
14261 struct ibf_object_header obj_header;
14262 ibf_offset_t current_offset;
14263 IBF_ZERO(obj_header);
14264 obj_header.type = TYPE(obj);
14265
14266 IBF_W_ALIGN(ibf_offset_t);
14267 current_offset = ibf_dump_pos(dump);
14268
14269 if (SPECIAL_CONST_P(obj) &&
14270 ! (SYMBOL_P(obj) ||
14271 RB_FLOAT_TYPE_P(obj))) {
14272 obj_header.special_const = TRUE;
14273 obj_header.frozen = TRUE;
14274 obj_header.internal = TRUE;
14275 ibf_dump_object_object_header(dump, obj_header);
14276 ibf_dump_write_small_value(dump, obj);
14277 }
14278 else {
14279 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14280 obj_header.special_const = FALSE;
14281 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14282 ibf_dump_object_object_header(dump, obj_header);
14283 (*dump_object_functions[obj_header.type])(dump, obj);
14284 }
14285
14286 return current_offset;
14287}
14288
14289typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14290static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14291 ibf_load_object_unsupported, /* T_NONE */
14292 ibf_load_object_unsupported, /* T_OBJECT */
14293 ibf_load_object_class, /* T_CLASS */
14294 ibf_load_object_unsupported, /* T_MODULE */
14295 ibf_load_object_float, /* T_FLOAT */
14296 ibf_load_object_string, /* T_STRING */
14297 ibf_load_object_regexp, /* T_REGEXP */
14298 ibf_load_object_array, /* T_ARRAY */
14299 ibf_load_object_hash, /* T_HASH */
14300 ibf_load_object_struct, /* T_STRUCT */
14301 ibf_load_object_bignum, /* T_BIGNUM */
14302 ibf_load_object_unsupported, /* T_FILE */
14303 ibf_load_object_data, /* T_DATA */
14304 ibf_load_object_unsupported, /* T_MATCH */
14305 ibf_load_object_complex_rational, /* T_COMPLEX */
14306 ibf_load_object_complex_rational, /* T_RATIONAL */
14307 ibf_load_object_unsupported, /* 0x10 */
14308 ibf_load_object_unsupported, /* T_NIL */
14309 ibf_load_object_unsupported, /* T_TRUE */
14310 ibf_load_object_unsupported, /* T_FALSE */
14311 ibf_load_object_symbol,
14312 ibf_load_object_unsupported, /* T_FIXNUM */
14313 ibf_load_object_unsupported, /* T_UNDEF */
14314 ibf_load_object_unsupported, /* 0x17 */
14315 ibf_load_object_unsupported, /* 0x18 */
14316 ibf_load_object_unsupported, /* 0x19 */
14317 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14318 ibf_load_object_unsupported, /* T_NODE 0x1b */
14319 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14320 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14321 ibf_load_object_unsupported, /* 0x1e */
14322 ibf_load_object_unsupported, /* 0x1f */
14323};
14324
14325static VALUE
14326ibf_load_object(const struct ibf_load *load, VALUE object_index)
14327{
14328 if (object_index == 0) {
14329 return Qnil;
14330 }
14331 else {
14332 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14333 if (!obj) {
14334 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14335 ibf_offset_t offset = offsets[object_index];
14336 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14337
14338#if IBF_ISEQ_DEBUG
14339 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14340 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14341 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14342 header.type, header.special_const, header.frozen, header.internal);
14343#endif
14344 if (offset >= load->current_buffer->size) {
14345 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14346 }
14347
14348 if (header.special_const) {
14349 ibf_offset_t reading_pos = offset;
14350
14351 obj = ibf_load_small_value(load, &reading_pos);
14352 }
14353 else {
14354 obj = (*load_object_functions[header.type])(load, &header, offset);
14355 }
14356
14357 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14358 }
14359#if IBF_ISEQ_DEBUG
14360 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14361 object_index, obj);
14362#endif
14363 return obj;
14364 }
14365}
14366
14368{
14369 struct ibf_dump *dump;
14370 VALUE offset_list;
14371};
14372
14373static int
14374ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14375{
14376 VALUE obj = (VALUE)key;
14377 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14378
14379 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14380 rb_ary_push(args->offset_list, UINT2NUM(offset));
14381
14382 return ST_CONTINUE;
14383}
14384
14385static void
14386ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14387{
14388 st_table *obj_table = dump->current_buffer->obj_table;
14389 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14390
14391 struct ibf_dump_object_list_arg args;
14392 args.dump = dump;
14393 args.offset_list = offset_list;
14394
14395 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14396
14397 IBF_W_ALIGN(ibf_offset_t);
14398 *obj_list_offset = ibf_dump_pos(dump);
14399
14400 st_index_t size = obj_table->num_entries;
14401 st_index_t i;
14402
14403 for (i=0; i<size; i++) {
14404 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14405 IBF_WV(offset);
14406 }
14407
14408 *obj_list_size = (unsigned int)size;
14409}
14410
14411static void
14412ibf_dump_mark(void *ptr)
14413{
14414 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14415 rb_gc_mark(dump->global_buffer.str);
14416
14417 rb_mark_set(dump->global_buffer.obj_table);
14418 rb_mark_set(dump->iseq_table);
14419}
14420
14421static void
14422ibf_dump_free(void *ptr)
14423{
14424 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14425 if (dump->global_buffer.obj_table) {
14426 st_free_table(dump->global_buffer.obj_table);
14427 dump->global_buffer.obj_table = 0;
14428 }
14429 if (dump->iseq_table) {
14430 st_free_table(dump->iseq_table);
14431 dump->iseq_table = 0;
14432 }
14433}
14434
14435static size_t
14436ibf_dump_memsize(const void *ptr)
14437{
14438 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14439 size_t size = 0;
14440 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14441 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14442 return size;
14443}
14444
14445static const rb_data_type_t ibf_dump_type = {
14446 "ibf_dump",
14447 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14448 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14449};
14450
14451static void
14452ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14453{
14454 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14455 dump->iseq_table = NULL;
14456
14457 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14458 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14459 dump->iseq_table = st_init_numtable(); /* need free */
14460
14461 dump->current_buffer = &dump->global_buffer;
14462}
14463
14464VALUE
14465rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14466{
14467 struct ibf_dump *dump;
14468 struct ibf_header header = {{0}};
14469 VALUE dump_obj;
14470 VALUE str;
14471
14472 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14473 ISEQ_BODY(iseq)->local_iseq != iseq) {
14474 rb_raise(rb_eRuntimeError, "should be top of iseq");
14475 }
14476 if (RTEST(ISEQ_COVERAGE(iseq))) {
14477 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14478 }
14479
14480 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14481 ibf_dump_setup(dump, dump_obj);
14482
14483 ibf_dump_write(dump, &header, sizeof(header));
14484 ibf_dump_iseq(dump, iseq);
14485
14486 header.magic[0] = 'Y'; /* YARB */
14487 header.magic[1] = 'A';
14488 header.magic[2] = 'R';
14489 header.magic[3] = 'B';
14490 header.major_version = IBF_MAJOR_VERSION;
14491 header.minor_version = IBF_MINOR_VERSION;
14492 header.endian = IBF_ENDIAN_MARK;
14493 header.wordsize = (uint8_t)SIZEOF_VALUE;
14494 ibf_dump_iseq_list(dump, &header);
14495 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14496 header.size = ibf_dump_pos(dump);
14497
14498 if (RTEST(opt)) {
14499 VALUE opt_str = opt;
14500 const char *ptr = StringValuePtr(opt_str);
14501 header.extra_size = RSTRING_LENINT(opt_str);
14502 ibf_dump_write(dump, ptr, header.extra_size);
14503 }
14504 else {
14505 header.extra_size = 0;
14506 }
14507
14508 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14509
14510 str = dump->global_buffer.str;
14511 RB_GC_GUARD(dump_obj);
14512 return str;
14513}
14514
14515static const ibf_offset_t *
14516ibf_iseq_list(const struct ibf_load *load)
14517{
14518 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14519}
14520
14521void
14522rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14523{
14524 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14525 rb_iseq_t *prev_src_iseq = load->iseq;
14526 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14527 load->iseq = iseq;
14528#if IBF_ISEQ_DEBUG
14529 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14530 iseq->aux.loader.index, offset,
14531 load->header->size);
14532#endif
14533 ibf_load_iseq_each(load, iseq, offset);
14534 ISEQ_COMPILE_DATA_CLEAR(iseq);
14535 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14536 rb_iseq_init_trace(iseq);
14537 load->iseq = prev_src_iseq;
14538}
14539
14540#if USE_LAZY_LOAD
14541const rb_iseq_t *
14542rb_iseq_complete(const rb_iseq_t *iseq)
14543{
14544 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14545 return iseq;
14546}
14547#endif
14548
14549static rb_iseq_t *
14550ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14551{
14552 int iseq_index = (int)(VALUE)index_iseq;
14553
14554#if IBF_ISEQ_DEBUG
14555 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14556 (void *)index_iseq, (void *)load->iseq_list);
14557#endif
14558 if (iseq_index == -1) {
14559 return NULL;
14560 }
14561 else {
14562 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14563
14564#if IBF_ISEQ_DEBUG
14565 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14566#endif
14567 if (iseqv) {
14568 return (rb_iseq_t *)iseqv;
14569 }
14570 else {
14571 rb_iseq_t *iseq = iseq_imemo_alloc();
14572#if IBF_ISEQ_DEBUG
14573 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14574#endif
14575 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14576 iseq->aux.loader.obj = load->loader_obj;
14577 iseq->aux.loader.index = iseq_index;
14578#if IBF_ISEQ_DEBUG
14579 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14580 (void *)iseq, (void *)load->loader_obj, iseq_index);
14581#endif
14582 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14583
14584 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14585#if IBF_ISEQ_DEBUG
14586 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14587#endif
14588 rb_ibf_load_iseq_complete(iseq);
14589 }
14590
14591#if IBF_ISEQ_DEBUG
14592 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14593 (void *)iseq, (void *)load->iseq);
14594#endif
14595 return iseq;
14596 }
14597 }
14598}
14599
14600static void
14601ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14602{
14603 struct ibf_header *header = (struct ibf_header *)bytes;
14604 load->loader_obj = loader_obj;
14605 load->global_buffer.buff = bytes;
14606 load->header = header;
14607 load->global_buffer.size = header->size;
14608 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14609 load->global_buffer.obj_list_size = header->global_object_list_size;
14610 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14611 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14612 load->iseq = NULL;
14613
14614 load->current_buffer = &load->global_buffer;
14615
14616 if (size < header->size) {
14617 rb_raise(rb_eRuntimeError, "broken binary format");
14618 }
14619 if (strncmp(header->magic, "YARB", 4) != 0) {
14620 rb_raise(rb_eRuntimeError, "unknown binary format");
14621 }
14622 if (header->major_version != IBF_MAJOR_VERSION ||
14623 header->minor_version != IBF_MINOR_VERSION) {
14624 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14625 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14626 }
14627 if (header->endian != IBF_ENDIAN_MARK) {
14628 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14629 }
14630 if (header->wordsize != SIZEOF_VALUE) {
14631 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14632 }
14633 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14634 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14635 header->iseq_list_offset);
14636 }
14637 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14638 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14639 load->global_buffer.obj_list_offset);
14640 }
14641}
14642
14643static void
14644ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14645{
14646 StringValue(str);
14647
14648 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14649 rb_raise(rb_eRuntimeError, "broken binary format");
14650 }
14651
14652 if (USE_LAZY_LOAD) {
14653 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14654 }
14655
14656 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14657 RB_OBJ_WRITE(loader_obj, &load->str, str);
14658}
14659
14660static void
14661ibf_loader_mark(void *ptr)
14662{
14663 struct ibf_load *load = (struct ibf_load *)ptr;
14664 rb_gc_mark(load->str);
14665 rb_gc_mark(load->iseq_list);
14666 rb_gc_mark(load->global_buffer.obj_list);
14667}
14668
14669static void
14670ibf_loader_free(void *ptr)
14671{
14672 struct ibf_load *load = (struct ibf_load *)ptr;
14673 ruby_xfree(load);
14674}
14675
14676static size_t
14677ibf_loader_memsize(const void *ptr)
14678{
14679 return sizeof(struct ibf_load);
14680}
14681
14682static const rb_data_type_t ibf_load_type = {
14683 "ibf_loader",
14684 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14685 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14686};
14687
14688const rb_iseq_t *
14689rb_iseq_ibf_load(VALUE str)
14690{
14691 struct ibf_load *load;
14692 rb_iseq_t *iseq;
14693 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14694
14695 ibf_load_setup(load, loader_obj, str);
14696 iseq = ibf_load_iseq(load, 0);
14697
14698 RB_GC_GUARD(loader_obj);
14699 return iseq;
14700}
14701
14702const rb_iseq_t *
14703rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14704{
14705 struct ibf_load *load;
14706 rb_iseq_t *iseq;
14707 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14708
14709 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14710 iseq = ibf_load_iseq(load, 0);
14711
14712 RB_GC_GUARD(loader_obj);
14713 return iseq;
14714}
14715
14716VALUE
14717rb_iseq_ibf_load_extra_data(VALUE str)
14718{
14719 struct ibf_load *load;
14720 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14721 VALUE extra_str;
14722
14723 ibf_load_setup(load, loader_obj, str);
14724 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14725 RB_GC_GUARD(loader_obj);
14726 return extra_str;
14727}
14728
14729#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:129
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:67
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:133
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:689
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:113
VALUE rb_cArray
Array class.
Definition array.c:40
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:104
VALUE rb_cHash
Hash class.
Definition hash.c:113
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
VALUE rb_cRange
Range class.
Definition range.c:31
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
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1260
#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
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
#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
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1063
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1087
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1799
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:68
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4198
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:3676
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1671
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4045
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4031
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3444
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4101
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:3918
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3176
#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
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:412
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:951
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:970
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:917
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:3115
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:150
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:449
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:197
#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
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9035
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:29
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:269
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition iseq.h:240
struct rb_iseq_constant_body::@000024342312237062266020177166377106262102236123 param
parameter information
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145