Ruby 3.3.4p94 (2024-07-09 revision be1089c8ec5ba40e09b1553e36b3174bf4014d9d)
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/numeric.h"
30#include "internal/object.h"
31#include "internal/rational.h"
32#include "internal/re.h"
33#include "internal/symbol.h"
34#include "internal/thread.h"
35#include "internal/variable.h"
36#include "iseq.h"
37#include "ruby/re.h"
38#include "ruby/util.h"
39#include "vm_core.h"
40#include "vm_callinfo.h"
41#include "vm_debug.h"
42#include "yjit.h"
43
44#include "builtin.h"
45#include "insns.inc"
46#include "insns_info.inc"
47
48#undef RUBY_UNTYPED_DATA_WARNING
49#define RUBY_UNTYPED_DATA_WARNING 0
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;
65
66typedef struct iseq_link_anchor {
67 LINK_ELEMENT anchor;
68 LINK_ELEMENT *last;
70
71typedef enum {
72 LABEL_RESCUE_NONE,
73 LABEL_RESCUE_BEG,
74 LABEL_RESCUE_END,
75 LABEL_RESCUE_TYPE_MAX
76} LABEL_RESCUE_TYPE;
77
78typedef struct iseq_label_data {
79 LINK_ELEMENT link;
80 int label_no;
81 int position;
82 int sc_state;
83 int sp;
84 int refcnt;
85 unsigned int set: 1;
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
88} LABEL;
89
90typedef struct iseq_insn_data {
91 LINK_ELEMENT link;
92 enum ruby_vminsn_type insn_id;
93 int operand_size;
94 int sc_state;
95 VALUE *operands;
96 struct {
97 int line_no;
98 int node_id;
99 rb_event_flag_t events;
100 } insn_info;
101} INSN;
102
103typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
122 const void *ensure_node;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
142#ifndef CPDEBUG
143#define CPDEBUG 0
144#endif
145
146#if CPDEBUG >= 0
147#define compile_debug CPDEBUG
148#else
149#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
150#endif
151
152#if CPDEBUG
153
154#define compile_debug_print_indent(level) \
155 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156
157#define debugp(header, value) (void) \
158 (compile_debug_print_indent(1) && \
159 ruby_debug_print_value(1, compile_debug, (header), (value)))
160
161#define debugi(header, id) (void) \
162 (compile_debug_print_indent(1) && \
163 ruby_debug_print_id(1, compile_debug, (header), (id)))
164
165#define debugp_param(header, value) (void) \
166 (compile_debug_print_indent(1) && \
167 ruby_debug_print_value(1, compile_debug, (header), (value)))
168
169#define debugp_verbose(header, value) (void) \
170 (compile_debug_print_indent(2) && \
171 ruby_debug_print_value(2, compile_debug, (header), (value)))
172
173#define debugp_verbose_node(header, value) (void) \
174 (compile_debug_print_indent(10) && \
175 ruby_debug_print_value(10, compile_debug, (header), (value)))
176
177#define debug_node_start(node) ((void) \
178 (compile_debug_print_indent(1) && \
179 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
180 gl_node_level++)
181
182#define debug_node_end() gl_node_level --
183
184#else
185
186#define debugi(header, id) ((void)0)
187#define debugp(header, value) ((void)0)
188#define debugp_verbose(header, value) ((void)0)
189#define debugp_verbose_node(header, value) ((void)0)
190#define debugp_param(header, value) ((void)0)
191#define debug_node_start(node) ((void)0)
192#define debug_node_end() ((void)0)
193#endif
194
195#if CPDEBUG > 1 || CPDEBUG < 0
196#undef printf
197#define printf ruby_debug_printf
198#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#else
201#define debugs if(0)printf
202#define debug_compile(msg, v) (v)
203#endif
204
205#define LVAR_ERRINFO (1)
206
207/* create new label */
208#define NEW_LABEL(l) new_label_body(iseq, (l))
209#define LABEL_FORMAT "<L%03d>"
210
211#define NEW_ISEQ(node, name, type, line_no) \
212 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213
214#define NEW_CHILD_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216
217/* 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, (line_node), BIN(insn), 0))
224
225/* insert an instruction before next */
226#define INSERT_BEFORE_INSN(next, line_node, insn) \
227 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
228
229/* insert an instruction after prev */
230#define INSERT_AFTER_INSN(prev, line_node, insn) \
231 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
232
233/* add an instruction with some operands (1, 2, 3, 5) */
234#define ADD_INSN1(seq, line_node, insn, op1) \
235 ADD_ELEM((seq), (LINK_ELEMENT *) \
236 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
237
238/* insert an instruction with some operands (1, 2, 3, 5) before next */
239#define INSERT_BEFORE_INSN1(next, line_node, insn, op1) \
240 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
241 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
242
243/* insert an instruction with some operands (1, 2, 3, 5) after prev */
244#define INSERT_AFTER_INSN1(prev, line_node, insn, op1) \
245 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
246 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
247
248#define LABEL_REF(label) ((label)->refcnt++)
249
250/* add an instruction with label operand (alias of ADD_INSN1) */
251#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
252
253#define ADD_INSN2(seq, line_node, insn, op1, op2) \
254 ADD_ELEM((seq), (LINK_ELEMENT *) \
255 new_insn_body(iseq, (line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
256
257#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
258 ADD_ELEM((seq), (LINK_ELEMENT *) \
259 new_insn_body(iseq, (line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
260
261/* Specific Insn factory */
262#define ADD_SEND(seq, line_node, id, argc) \
263 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
264
265#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
266 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
267
268#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
270
271#define ADD_CALL_RECEIVER(seq, line_node) \
272 ADD_INSN((seq), (line_node), putself)
273
274#define ADD_CALL(seq, line_node, id, argc) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
276
277#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
278 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
279
280#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
281 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
282
283#define ADD_TRACE(seq, event) \
284 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
285#define ADD_TRACE_WITH_DATA(seq, event, data) \
286 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
287
288static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
289static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
290
291#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
292#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
293
294/* add label */
295#define ADD_LABEL(seq, label) \
296 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
297
298#define APPEND_LABEL(seq, before, label) \
299 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
300
301#define ADD_ADJUST(seq, line_node, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
303
304#define ADD_ADJUST_RESTORE(seq, label) \
305 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
306
307#define LABEL_UNREMOVABLE(label) \
308 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
309#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
310 VALUE _e = rb_ary_new3(5, (type), \
311 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
312 (VALUE)(iseqv), (VALUE)(lc) | 1); \
313 LABEL_UNREMOVABLE(ls); \
314 LABEL_REF(le); \
315 LABEL_REF(lc); \
316 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
317 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
318 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
319} while (0)
320
321/* compile node */
322#define COMPILE(anchor, desc, node) \
323 (debug_compile("== " desc "\n", \
324 iseq_compile_each(iseq, (anchor), (node), 0)))
325
326/* compile node, this node's value will be popped */
327#define COMPILE_POPPED(anchor, desc, node) \
328 (debug_compile("== " desc "\n", \
329 iseq_compile_each(iseq, (anchor), (node), 1)))
330
331/* compile node, which is popped when 'popped' is true */
332#define COMPILE_(anchor, desc, node, popped) \
333 (debug_compile("== " desc "\n", \
334 iseq_compile_each(iseq, (anchor), (node), (popped))))
335
336#define COMPILE_RECV(anchor, desc, node, recv) \
337 (private_recv_p(node) ? \
338 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
339 COMPILE(anchor, desc, recv) ? 0 : -1)
340
341#define OPERAND_AT(insn, idx) \
342 (((INSN*)(insn))->operands[(idx)])
343
344#define INSN_OF(insn) \
345 (((INSN*)(insn))->insn_id)
346
347#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
348#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
349#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
350#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
351#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
352#define IS_NEXT_INSN_ID(link, insn) \
353 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
354
355/* error */
356#if CPDEBUG > 0
358#endif
359RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
360static void
361append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
362{
363 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
364 VALUE file = rb_iseq_path(iseq);
365 VALUE err = err_info == Qtrue ? Qfalse : err_info;
366 va_list args;
367
368 va_start(args, fmt);
369 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
370 va_end(args);
371 if (NIL_P(err_info)) {
372 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
373 rb_set_errinfo(err);
374 }
375 else if (!err_info) {
376 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
377 }
378 if (compile_debug) {
379 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
380 rb_exc_fatal(err);
381 }
382}
383
384#if 0
385static void
386compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
387{
388 va_list args;
389 va_start(args, fmt);
390 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
391 va_end(args);
392 abort();
393}
394#endif
395
396#define COMPILE_ERROR append_compile_error
397
398#define ERROR_ARGS_AT(n) iseq, nd_line(n),
399#define ERROR_ARGS ERROR_ARGS_AT(node)
400
401#define EXPECT_NODE(prefix, node, ndtype, errval) \
402do { \
403 const NODE *error_node = (node); \
404 enum node_type error_type = nd_type(error_node); \
405 if (error_type != (ndtype)) { \
406 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
407 prefix ": " #ndtype " is expected, but %s", \
408 ruby_node_name(error_type)); \
409 return errval; \
410 } \
411} while (0)
412
413#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
414do { \
415 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
416 prefix ": must be " #ndtype ", but 0"); \
417 return errval; \
418} while (0)
419
420#define UNKNOWN_NODE(prefix, node, errval) \
421do { \
422 const NODE *error_node = (node); \
423 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
424 ruby_node_name(nd_type(error_node))); \
425 return errval; \
426} while (0)
427
428#define COMPILE_OK 1
429#define COMPILE_NG 0
430
431#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
432#define NO_CHECK(sub) (void)(sub)
433#define BEFORE_RETURN
434
435/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
436 * missing */
437#define DECL_ANCHOR(name) \
438 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
439#define INIT_ANCHOR(name) \
440 (name->last = &name->anchor)
441
442static inline VALUE
443freeze_hide_obj(VALUE obj)
444{
445 OBJ_FREEZE(obj);
446 RBASIC_CLEAR_CLASS(obj);
447 return obj;
448}
449
450#include "optinsn.inc"
451#if OPT_INSTRUCTIONS_UNIFICATION
452#include "optunifs.inc"
453#endif
454
455/* for debug */
456#if CPDEBUG < 0
457#define ISEQ_ARG iseq,
458#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
459#else
460#define ISEQ_ARG
461#define ISEQ_ARG_DECLARE
462#endif
463
464#if CPDEBUG
465#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
466#endif
467
468static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
469static void dump_disasm_list(const LINK_ELEMENT *elem);
470
471static int insn_data_length(INSN *iobj);
472static int calc_sp_depth(int depth, INSN *iobj);
473
474static INSN *new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...);
475static LABEL *new_label_body(rb_iseq_t *iseq, long line);
476static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
477static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
478
479
480static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
481static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
482static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
483static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
484static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
485
486static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl);
487static int iseq_set_exception_local_table(rb_iseq_t *iseq);
488static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
489
490static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
491static int iseq_set_exception_table(rb_iseq_t *iseq);
492static int iseq_set_optargs_table(rb_iseq_t *iseq);
493
494static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
495static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
496
497/*
498 * To make Array to LinkedList, use link_anchor
499 */
500
501static void
502verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
503{
504#if CPDEBUG
505 int flag = 0;
506 LINK_ELEMENT *list, *plist;
507
508 if (!compile_debug) return;
509
510 list = anchor->anchor.next;
511 plist = &anchor->anchor;
512 while (list) {
513 if (plist != list->prev) {
514 flag += 1;
515 }
516 plist = list;
517 list = list->next;
518 }
519
520 if (anchor->last != plist && anchor->last != 0) {
521 flag |= 0x70000;
522 }
523
524 if (flag != 0) {
525 rb_bug("list verify error: %08x (%s)", flag, info);
526 }
527#endif
528}
529#if CPDEBUG < 0
530#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
531#endif
532
533static void
534verify_call_cache(rb_iseq_t *iseq)
535{
536#if CPDEBUG
537 VALUE *original = rb_iseq_original_iseq(iseq);
538 size_t i = 0;
539 while (i < ISEQ_BODY(iseq)->iseq_size) {
540 VALUE insn = original[i];
541 const char *types = insn_op_types(insn);
542
543 for (int j=0; types[j]; j++) {
544 if (types[j] == TS_CALLDATA) {
545 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
546 const struct rb_callinfo *ci = cd->ci;
547 const struct rb_callcache *cc = cd->cc;
548 if (cc != vm_cc_empty()) {
549 vm_ci_dump(ci);
550 rb_bug("call cache is not initialized by vm_cc_empty()");
551 }
552 }
553 }
554 i += insn_len(insn);
555 }
556
557 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
558 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
559 const struct rb_callinfo *ci = cd->ci;
560 const struct rb_callcache *cc = cd->cc;
561 if (cc != NULL && cc != vm_cc_empty()) {
562 vm_ci_dump(ci);
563 rb_bug("call cache is not initialized by vm_cc_empty()");
564 }
565 }
566#endif
567}
568
569/*
570 * elem1, elem2 => elem1, elem2, elem
571 */
572static void
573ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
574{
575 elem->prev = anchor->last;
576 anchor->last->next = elem;
577 anchor->last = elem;
578 verify_list("add", anchor);
579}
580
581/*
582 * elem1, before, elem2 => elem1, before, elem, elem2
583 */
584static void
585APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
586{
587 elem->prev = before;
588 elem->next = before->next;
589 elem->next->prev = elem;
590 before->next = elem;
591 if (before == anchor->last) anchor->last = elem;
592 verify_list("add", anchor);
593}
594#if CPDEBUG < 0
595#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
596#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
597#endif
598
599static int
600branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
601{
602 if (!ISEQ_COVERAGE(iseq)) return 0;
603 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
604 if (first_line <= 0) return 0;
605 return 1;
606}
607
608static VALUE
609decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
610{
611 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
612 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
613
614 if (!branch_coverage_valid_p(iseq, first_lineno)) return Qundef;
615
616 /*
617 * if !structure[node]
618 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
619 * else
620 * branches = structure[node][5]
621 * end
622 */
623
624 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
625 VALUE key = (VALUE)node | 1; // FIXNUM for hash key
626 VALUE branch_base = rb_hash_aref(structure, key);
627 VALUE branches;
628
629 if (NIL_P(branch_base)) {
630 branch_base = rb_ary_hidden_new(6);
631 rb_hash_aset(structure, key, branch_base);
632 rb_ary_push(branch_base, ID2SYM(rb_intern(type)));
633 rb_ary_push(branch_base, INT2FIX(first_lineno));
634 rb_ary_push(branch_base, INT2FIX(first_column));
635 rb_ary_push(branch_base, INT2FIX(last_lineno));
636 rb_ary_push(branch_base, INT2FIX(last_column));
637 branches = rb_hash_new();
638 rb_obj_hide(branches);
639 rb_ary_push(branch_base, branches);
640 }
641 else {
642 branches = RARRAY_AREF(branch_base, 5);
643 }
644
645 return branches;
646}
647
648static NODE
649generate_dummy_line_node(int lineno, int node_id)
650{
651 NODE dummy = { 0 };
652 nd_set_line(&dummy, lineno);
653 nd_set_node_id(&dummy, node_id);
654 return dummy;
655}
656
657static void
658add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *node, int branch_id, const char *type, VALUE branches)
659{
660 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
661 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
662
663 if (!branch_coverage_valid_p(iseq, first_lineno)) return;
664
665 /*
666 * if !branches[branch_id]
667 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
668 * else
669 * counter_idx= branches[branch_id][5]
670 * end
671 */
672
673 VALUE key = INT2FIX(branch_id);
674 VALUE branch = rb_hash_aref(branches, key);
675 long counter_idx;
676
677 if (NIL_P(branch)) {
678 branch = rb_ary_hidden_new(6);
679 rb_hash_aset(branches, key, branch);
680 rb_ary_push(branch, ID2SYM(rb_intern(type)));
681 rb_ary_push(branch, INT2FIX(first_lineno));
682 rb_ary_push(branch, INT2FIX(first_column));
683 rb_ary_push(branch, INT2FIX(last_lineno));
684 rb_ary_push(branch, INT2FIX(last_column));
685 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
686 counter_idx = RARRAY_LEN(counters);
687 rb_ary_push(branch, LONG2FIX(counter_idx));
688 rb_ary_push(counters, INT2FIX(0));
689 }
690 else {
691 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
692 }
693
694 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
695
696 NODE dummy_line_node = generate_dummy_line_node(last_lineno, nd_node_id(node));
697 ADD_INSN(seq, &dummy_line_node, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724static NODE *
725get_nd_recv(const NODE *node)
726{
727 switch (nd_type(node)) {
728 case NODE_CALL:
729 return RNODE_CALL(node)->nd_recv;
730 case NODE_OPCALL:
731 return RNODE_OPCALL(node)->nd_recv;
732 case NODE_FCALL:
733 return 0;
734 case NODE_QCALL:
735 return RNODE_QCALL(node)->nd_recv;
736 case NODE_VCALL:
737 return 0;
738 case NODE_ATTRASGN:
739 return RNODE_ATTRASGN(node)->nd_recv;
740 case NODE_OP_ASGN1:
741 return RNODE_OP_ASGN1(node)->nd_recv;
742 case NODE_OP_ASGN2:
743 return RNODE_OP_ASGN2(node)->nd_recv;
744 default:
745 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
746 }
747}
748
749static ID
750get_node_call_nd_mid(const NODE *node)
751{
752 switch (nd_type(node)) {
753 case NODE_CALL:
754 return RNODE_CALL(node)->nd_mid;
755 case NODE_OPCALL:
756 return RNODE_OPCALL(node)->nd_mid;
757 case NODE_FCALL:
758 return RNODE_FCALL(node)->nd_mid;
759 case NODE_QCALL:
760 return RNODE_QCALL(node)->nd_mid;
761 case NODE_VCALL:
762 return RNODE_VCALL(node)->nd_mid;
763 case NODE_ATTRASGN:
764 return RNODE_ATTRASGN(node)->nd_mid;
765 default:
766 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
767 }
768}
769
770static NODE *
771get_nd_args(const NODE *node)
772{
773 switch (nd_type(node)) {
774 case NODE_CALL:
775 return RNODE_CALL(node)->nd_args;
776 case NODE_OPCALL:
777 return RNODE_OPCALL(node)->nd_args;
778 case NODE_FCALL:
779 return RNODE_FCALL(node)->nd_args;
780 case NODE_QCALL:
781 return RNODE_QCALL(node)->nd_args;
782 case NODE_VCALL:
783 return 0;
784 case NODE_ATTRASGN:
785 return RNODE_ATTRASGN(node)->nd_args;
786 default:
787 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
788 }
789}
790
791static ID
792get_node_colon_nd_mid(const NODE *node)
793{
794 switch (nd_type(node)) {
795 case NODE_COLON2:
796 return RNODE_COLON2(node)->nd_mid;
797 case NODE_COLON3:
798 return RNODE_COLON3(node)->nd_mid;
799 default:
800 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
801 }
802}
803
804static ID
805get_nd_vid(const NODE *node)
806{
807 switch (nd_type(node)) {
808 case NODE_LASGN:
809 return RNODE_LASGN(node)->nd_vid;
810 case NODE_DASGN:
811 return RNODE_DASGN(node)->nd_vid;
812 case NODE_IASGN:
813 return RNODE_IASGN(node)->nd_vid;
814 case NODE_CVASGN:
815 return RNODE_CVASGN(node)->nd_vid;
816 default:
817 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
818 }
819}
820
821
822static NODE *
823get_nd_value(const NODE *node)
824{
825 switch (nd_type(node)) {
826 case NODE_LASGN:
827 return RNODE_LASGN(node)->nd_value;
828 case NODE_DASGN:
829 return RNODE_DASGN(node)->nd_value;
830 default:
831 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
832 }
833}
834
835VALUE
836rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
837{
838 DECL_ANCHOR(ret);
839 INIT_ANCHOR(ret);
840
841 (*ifunc->func)(iseq, ret, ifunc->data);
842
843 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
844 ADD_INSN(ret, &dummy_line_node, leave);
845
846 CHECK(iseq_setup_insn(iseq, ret));
847 return iseq_setup(iseq, ret);
848}
849
850VALUE
851rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
852{
853 DECL_ANCHOR(ret);
854 INIT_ANCHOR(ret);
855
856 if (IMEMO_TYPE_P(node, imemo_ifunc)) {
857 rb_raise(rb_eArgError, "unexpected imemo_ifunc");
858 }
859
860 if (node == 0) {
861 NO_CHECK(COMPILE(ret, "nil", node));
862 iseq_set_local_table(iseq, 0);
863 }
864 /* assume node is T_NODE */
865 else if (nd_type_p(node, NODE_SCOPE)) {
866 /* iseq type of top, method, class, block */
867 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl);
868 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
869
870 switch (ISEQ_BODY(iseq)->type) {
871 case ISEQ_TYPE_BLOCK:
872 {
873 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
874 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
875
876 start->rescued = LABEL_RESCUE_BEG;
877 end->rescued = LABEL_RESCUE_END;
878
879 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
880 NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
881 ADD_INSN (ret, &dummy_line_node, nop);
882 ADD_LABEL(ret, start);
883 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
884 ADD_LABEL(ret, end);
885 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
886 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
887
888 /* wide range catch handler must put at last */
889 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
890 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
891 break;
892 }
893 case ISEQ_TYPE_CLASS:
894 {
895 ADD_TRACE(ret, RUBY_EVENT_CLASS);
896 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
897 ADD_TRACE(ret, RUBY_EVENT_END);
898 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
899 break;
900 }
901 case ISEQ_TYPE_METHOD:
902 {
903 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
904 ADD_TRACE(ret, RUBY_EVENT_CALL);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
907 ADD_TRACE(ret, RUBY_EVENT_RETURN);
908 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
909 break;
910 }
911 default: {
912 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
913 break;
914 }
915 }
916 }
917 else {
918 const char *m;
919#define INVALID_ISEQ_TYPE(type) \
920 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
921 switch (ISEQ_BODY(iseq)->type) {
922 case INVALID_ISEQ_TYPE(METHOD);
923 case INVALID_ISEQ_TYPE(CLASS);
924 case INVALID_ISEQ_TYPE(BLOCK);
925 case INVALID_ISEQ_TYPE(EVAL);
926 case INVALID_ISEQ_TYPE(MAIN);
927 case INVALID_ISEQ_TYPE(TOP);
928#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
929 case ISEQ_TYPE_RESCUE:
930 iseq_set_exception_local_table(iseq);
931 CHECK(COMPILE(ret, "rescue", node));
932 break;
933 case ISEQ_TYPE_ENSURE:
934 iseq_set_exception_local_table(iseq);
935 CHECK(COMPILE_POPPED(ret, "ensure", node));
936 break;
937 case ISEQ_TYPE_PLAIN:
938 CHECK(COMPILE(ret, "ensure", node));
939 break;
940 default:
941 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
942 return COMPILE_NG;
943 invalid_iseq_type:
944 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
945 return COMPILE_NG;
946 }
947 }
948
949 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
950 NODE dummy_line_node = generate_dummy_line_node(0, -1);
951 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
952 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
953 }
954 else {
955 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
956 ADD_INSN(ret, &dummy_line_node, leave);
957 }
958
959#if OPT_SUPPORT_JOKE
960 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
961 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
962 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
963 validate_labels(iseq, labels_table);
964 }
965#endif
966 CHECK(iseq_setup_insn(iseq, ret));
967 return iseq_setup(iseq, ret);
968}
969
970static VALUE rb_translate_prism(pm_parser_t *parser, rb_iseq_t *iseq, pm_scope_node_t *scope_node, LINK_ANCHOR *const ret);
971
972VALUE
973rb_iseq_compile_prism_node(rb_iseq_t * iseq, pm_scope_node_t *scope_node, pm_parser_t *parser)
974{
975 DECL_ANCHOR(ret);
976 INIT_ANCHOR(ret);
977
978 CHECK(rb_translate_prism(parser, iseq, scope_node, ret));
979
980 CHECK(iseq_setup_insn(iseq, ret));
981 return iseq_setup(iseq, ret);
982}
983
984static int
985rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
986{
987#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
988 const void * const *table = rb_vm_get_insns_address_table();
989 unsigned int i;
990 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
991
992 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
993 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
994 int len = insn_len(insn);
995 encoded[i] = (VALUE)table[insn];
996 i += len;
997 }
998 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
999#endif
1000
1001#if USE_YJIT
1002 rb_yjit_live_iseq_count++;
1003#endif
1004
1005 return COMPILE_OK;
1006}
1007
1008VALUE *
1009rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1010{
1011 VALUE *original_code;
1012
1013 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1014 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1015 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1016
1017#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1018 {
1019 unsigned int i;
1020
1021 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1022 const void *addr = (const void *)original_code[i];
1023 const int insn = rb_vm_insn_addr2insn(addr);
1024
1025 original_code[i] = insn;
1026 i += insn_len(insn);
1027 }
1028 }
1029#endif
1030 return original_code;
1031}
1032
1033/*********************************************/
1034/* definition of data structure for compiler */
1035/*********************************************/
1036
1037/*
1038 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1039 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1040 * generate SPARCV8PLUS code with unaligned memory access instructions.
1041 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1042 */
1043#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1044 #define STRICT_ALIGNMENT
1045#endif
1046
1047/*
1048 * Some OpenBSD platforms (including sparc64) require strict alignment.
1049 */
1050#if defined(__OpenBSD__)
1051 #include <sys/endian.h>
1052 #ifdef __STRICT_ALIGNMENT
1053 #define STRICT_ALIGNMENT
1054 #endif
1055#endif
1056
1057#ifdef STRICT_ALIGNMENT
1058 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1059 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1060 #else
1061 #define ALIGNMENT_SIZE SIZEOF_VALUE
1062 #endif
1063 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1064 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1065 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1066#else
1067 #define PADDING_SIZE_MAX 0
1068#endif /* STRICT_ALIGNMENT */
1069
1070#ifdef STRICT_ALIGNMENT
1071/* calculate padding size for aligned memory access */
1072static size_t
1073calc_padding(void *ptr, size_t size)
1074{
1075 size_t mis;
1076 size_t padding = 0;
1077
1078 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1079 if (mis > 0) {
1080 padding = ALIGNMENT_SIZE - mis;
1081 }
1082/*
1083 * On 32-bit sparc or equivalents, when a single VALUE is requested
1084 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1085 */
1086#if ALIGNMENT_SIZE > SIZEOF_VALUE
1087 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1088 padding = 0;
1089 }
1090#endif
1091
1092 return padding;
1093}
1094#endif /* STRICT_ALIGNMENT */
1095
1096static void *
1097compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1098{
1099 void *ptr = 0;
1100 struct iseq_compile_data_storage *storage = *arena;
1101#ifdef STRICT_ALIGNMENT
1102 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1103#else
1104 const size_t padding = 0; /* expected to be optimized by compiler */
1105#endif /* STRICT_ALIGNMENT */
1106
1107 if (size >= INT_MAX - padding) rb_memerror();
1108 if (storage->pos + size + padding > storage->size) {
1109 unsigned int alloc_size = storage->size;
1110
1111 while (alloc_size < size + PADDING_SIZE_MAX) {
1112 if (alloc_size >= INT_MAX / 2) rb_memerror();
1113 alloc_size *= 2;
1114 }
1115 storage->next = (void *)ALLOC_N(char, alloc_size +
1116 offsetof(struct iseq_compile_data_storage, buff));
1117 storage = *arena = storage->next;
1118 storage->next = 0;
1119 storage->pos = 0;
1120 storage->size = alloc_size;
1121#ifdef STRICT_ALIGNMENT
1122 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1123#endif /* STRICT_ALIGNMENT */
1124 }
1125
1126#ifdef STRICT_ALIGNMENT
1127 storage->pos += (int)padding;
1128#endif /* STRICT_ALIGNMENT */
1129
1130 ptr = (void *)&storage->buff[storage->pos];
1131 storage->pos += (int)size;
1132 return ptr;
1133}
1134
1135static void *
1136compile_data_alloc(rb_iseq_t *iseq, size_t size)
1137{
1138 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1139 return compile_data_alloc_with_arena(arena, size);
1140}
1141
1142static inline void *
1143compile_data_alloc2(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 return compile_data_alloc(iseq, size);
1147}
1148
1149static inline void *
1150compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1151{
1152 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1153 void *p = compile_data_alloc(iseq, size);
1154 memset(p, 0, size);
1155 return p;
1156}
1157
1158static INSN *
1159compile_data_alloc_insn(rb_iseq_t *iseq)
1160{
1161 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1162 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1163}
1164
1165static LABEL *
1166compile_data_alloc_label(rb_iseq_t *iseq)
1167{
1168 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1169}
1170
1171static ADJUST *
1172compile_data_alloc_adjust(rb_iseq_t *iseq)
1173{
1174 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1175}
1176
1177static TRACE *
1178compile_data_alloc_trace(rb_iseq_t *iseq)
1179{
1180 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1181}
1182
1183/*
1184 * elem1, elemX => elem1, elem2, elemX
1185 */
1186static void
1187ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1188{
1189 elem2->next = elem1->next;
1190 elem2->prev = elem1;
1191 elem1->next = elem2;
1192 if (elem2->next) {
1193 elem2->next->prev = elem2;
1194 }
1195}
1196
1197/*
1198 * elem1, elemX => elemX, elem2, elem1
1199 */
1200static void
1201ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1202{
1203 elem2->prev = elem1->prev;
1204 elem2->next = elem1;
1205 elem1->prev = elem2;
1206 if (elem2->prev) {
1207 elem2->prev->next = elem2;
1208 }
1209}
1210
1211/*
1212 * elemX, elem1, elemY => elemX, elem2, elemY
1213 */
1214static void
1215ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1216{
1217 elem2->prev = elem1->prev;
1218 elem2->next = elem1->next;
1219 if (elem1->prev) {
1220 elem1->prev->next = elem2;
1221 }
1222 if (elem1->next) {
1223 elem1->next->prev = elem2;
1224 }
1225}
1226
1227static void
1228ELEM_REMOVE(LINK_ELEMENT *elem)
1229{
1230 elem->prev->next = elem->next;
1231 if (elem->next) {
1232 elem->next->prev = elem->prev;
1233 }
1234}
1235
1236static LINK_ELEMENT *
1237FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1238{
1239 return anchor->anchor.next;
1240}
1241
1242static LINK_ELEMENT *
1243LAST_ELEMENT(LINK_ANCHOR *const anchor)
1244{
1245 return anchor->last;
1246}
1247
1248static LINK_ELEMENT *
1249ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1250{
1251 while (elem) {
1252 switch (elem->type) {
1253 case ISEQ_ELEMENT_INSN:
1254 case ISEQ_ELEMENT_ADJUST:
1255 return elem;
1256 default:
1257 elem = elem->next;
1258 }
1259 }
1260 return NULL;
1261}
1262
1263static int
1264LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1265{
1266 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1267 if (first_insn != NULL &&
1268 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1269 return TRUE;
1270 }
1271 else {
1272 return FALSE;
1273 }
1274}
1275
1276static int
1277LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1278{
1279 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1280 return TRUE;
1281 }
1282 else {
1283 return FALSE;
1284 }
1285}
1286
1287/*
1288 * anc1: e1, e2, e3
1289 * anc2: e4, e5
1290 *#=>
1291 * anc1: e1, e2, e3, e4, e5
1292 * anc2: e4, e5 (broken)
1293 */
1294static void
1295APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1296{
1297 if (anc2->anchor.next) {
1298 anc1->last->next = anc2->anchor.next;
1299 anc2->anchor.next->prev = anc1->last;
1300 anc1->last = anc2->last;
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 return labelobj;
1362}
1363
1364static ADJUST *
1365new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1366{
1367 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1368 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1369 adjust->link.next = 0;
1370 adjust->label = label;
1371 adjust->line_no = line;
1372 LABEL_UNREMOVABLE(label);
1373 return adjust;
1374}
1375
1376static void
1377iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
1378{
1379 const char *types = insn_op_types(insn->insn_id);
1380 for (int j = 0; types[j]; j++) {
1381 char type = types[j];
1382 switch (type) {
1383 case TS_CDHASH:
1384 case TS_ISEQ:
1385 case TS_VALUE:
1386 case TS_IC: // constant path array
1387 case TS_CALLDATA: // ci is stored.
1388 func(OPERAND_AT(insn, j), data);
1389 break;
1390 default:
1391 break;
1392 }
1393 }
1394}
1395
1396static void
1397iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
1398{
1399 RB_OBJ_WRITTEN(iseq, Qundef, obj);
1400}
1401
1402static INSN *
1403new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
1404 int insn_id, int argc, VALUE *argv)
1405{
1406 INSN *iobj = compile_data_alloc_insn(iseq);
1407
1408 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1409
1410 iobj->link.type = ISEQ_ELEMENT_INSN;
1411 iobj->link.next = 0;
1412 iobj->insn_id = insn_id;
1413 iobj->insn_info.line_no = nd_line(line_node);
1414 iobj->insn_info.node_id = nd_node_id(line_node);
1415 iobj->insn_info.events = 0;
1416 iobj->operands = argv;
1417 iobj->operand_size = argc;
1418 iobj->sc_state = 0;
1419
1420 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1421
1422 return iobj;
1423}
1424
1425static INSN *
1426new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...)
1427{
1428 VALUE *operands = 0;
1429 va_list argv;
1430 if (argc > 0) {
1431 int i;
1432 va_start(argv, argc);
1433 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1434 for (i = 0; i < argc; i++) {
1435 VALUE v = va_arg(argv, VALUE);
1436 operands[i] = v;
1437 }
1438 va_end(argv);
1439 }
1440 return new_insn_core(iseq, line_node, insn_id, argc, operands);
1441}
1442
1443static const struct rb_callinfo *
1444new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1445{
1446 VM_ASSERT(argc >= 0);
1447
1448 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
1449 kw_arg == NULL && !has_blockiseq) {
1450 flag |= VM_CALL_ARGS_SIMPLE;
1451 }
1452
1453 if (kw_arg) {
1454 flag |= VM_CALL_KWARG;
1455 argc += kw_arg->keyword_len;
1456 }
1457
1458 ISEQ_BODY(iseq)->ci_size++;
1459 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1460 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1461 return ci;
1462}
1463
1464static INSN *
1465new_insn_send(rb_iseq_t *iseq, const NODE *const line_node, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1466{
1467 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1468 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1469 operands[0] = ci;
1470 operands[1] = (VALUE)blockiseq;
1471 if (blockiseq) {
1472 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1473 }
1474 INSN *insn = new_insn_core(iseq, line_node, BIN(send), 2, operands);
1475 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1476 RB_GC_GUARD(ci);
1477 return insn;
1478}
1479
1480static rb_iseq_t *
1481new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1482 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1483{
1484 rb_iseq_t *ret_iseq;
1485 rb_ast_body_t ast;
1486
1487 ast.root = node;
1488 ast.frozen_string_literal = -1;
1489 ast.coverage_enabled = -1;
1490 ast.script_lines = ISEQ_BODY(iseq)->variable.script_lines;
1491
1492 debugs("[new_child_iseq]> ---------------------------------------\n");
1493 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1494 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1495 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1496 line_no, parent,
1497 isolated_depth ? isolated_depth + 1 : 0,
1498 type, ISEQ_COMPILE_DATA(iseq)->option);
1499 debugs("[new_child_iseq]< ---------------------------------------\n");
1500 return ret_iseq;
1501}
1502
1503static rb_iseq_t *
1504new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1505 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1506{
1507 rb_iseq_t *ret_iseq;
1508
1509 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1510 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1511 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1512 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1513 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1514 return ret_iseq;
1515}
1516
1517static void
1518set_catch_except_p(rb_iseq_t *iseq)
1519{
1520 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1521 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1522 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1523 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1524 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1525 }
1526 }
1527}
1528
1529/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1530 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1531 if catch table exists. But we want to optimize while loop, which always has catch
1532 table entries for break/next/redo.
1533
1534 So this function sets true for limited ISeqs with break/next/redo catch table entries
1535 whose child ISeq would really raise an exception. */
1536static void
1537update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1538{
1539 unsigned int pos;
1540 size_t i;
1541 int insn;
1542 const struct iseq_catch_table *ct = body->catch_table;
1543
1544 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1545 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1546 pos = 0;
1547 while (pos < body->iseq_size) {
1548 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1549 if (insn == BIN(throw)) {
1550 set_catch_except_p(iseq);
1551 break;
1552 }
1553 pos += insn_len(insn);
1554 }
1555
1556 if (ct == NULL)
1557 return;
1558
1559 for (i = 0; i < ct->size; i++) {
1560 const struct iseq_catch_table_entry *entry =
1561 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1562 if (entry->type != CATCH_TYPE_BREAK
1563 && entry->type != CATCH_TYPE_NEXT
1564 && entry->type != CATCH_TYPE_REDO) {
1565 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1566 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1567 break;
1568 }
1569 }
1570}
1571
1572static void
1573iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1574{
1575 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1576 if (NIL_P(catch_table_ary)) return;
1577 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1578 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1579 for (i = 0; i < tlen; i++) {
1580 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1581 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1582 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1583 LINK_ELEMENT *e;
1584
1585 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1586
1587 if (ct != CATCH_TYPE_BREAK
1588 && ct != CATCH_TYPE_NEXT
1589 && ct != CATCH_TYPE_REDO) {
1590
1591 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1592 if (e == cont) {
1593 NODE dummy_line_node = generate_dummy_line_node(0, -1);
1594 INSN *nop = new_insn_core(iseq, &dummy_line_node, BIN(nop), 0, 0);
1595 ELEM_INSERT_NEXT(end, &nop->link);
1596 break;
1597 }
1598 }
1599 }
1600 }
1601}
1602
1603static int
1604iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1605{
1606 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1607 return COMPILE_NG;
1608
1609 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1610
1611 if (compile_debug > 5)
1612 dump_disasm_list(FIRST_ELEMENT(anchor));
1613
1614 debugs("[compile step 3.1 (iseq_optimize)]\n");
1615 iseq_optimize(iseq, anchor);
1616
1617 if (compile_debug > 5)
1618 dump_disasm_list(FIRST_ELEMENT(anchor));
1619
1620 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1621 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1622 iseq_insns_unification(iseq, anchor);
1623 if (compile_debug > 5)
1624 dump_disasm_list(FIRST_ELEMENT(anchor));
1625 }
1626
1627 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1628 iseq_insert_nop_between_end_and_cont(iseq);
1629 if (compile_debug > 5)
1630 dump_disasm_list(FIRST_ELEMENT(anchor));
1631
1632 return COMPILE_OK;
1633}
1634
1635static int
1636iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1637{
1638 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1639 return COMPILE_NG;
1640
1641 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1642 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1643 if (compile_debug > 5)
1644 dump_disasm_list(FIRST_ELEMENT(anchor));
1645
1646 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1647 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1648
1649 debugs("[compile step 4.3 (set_optargs_table)] \n");
1650 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1651
1652 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1653 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1654
1655 debugs("[compile step 6 (update_catch_except_flags)] \n");
1656 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1657 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1658
1659 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1660 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1661 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1662 xfree(ISEQ_BODY(iseq)->catch_table);
1663 ISEQ_BODY(iseq)->catch_table = NULL;
1664 }
1665
1666#if VM_INSN_INFO_TABLE_IMPL == 2
1667 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1668 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1669 rb_iseq_insns_info_encode_positions(iseq);
1670 }
1671#endif
1672
1673 if (compile_debug > 1) {
1674 VALUE str = rb_iseq_disasm(iseq);
1675 printf("%s\n", StringValueCStr(str));
1676 }
1677 verify_call_cache(iseq);
1678 debugs("[compile step: finish]\n");
1679
1680 return COMPILE_OK;
1681}
1682
1683static int
1684iseq_set_exception_local_table(rb_iseq_t *iseq)
1685{
1686 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1687 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1688 return COMPILE_OK;
1689}
1690
1691static int
1692get_lvar_level(const rb_iseq_t *iseq)
1693{
1694 int lev = 0;
1695 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1696 lev++;
1697 iseq = ISEQ_BODY(iseq)->parent_iseq;
1698 }
1699 return lev;
1700}
1701
1702static int
1703get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1704{
1705 unsigned int i;
1706
1707 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1708 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1709 return (int)i;
1710 }
1711 }
1712 return -1;
1713}
1714
1715static int
1716get_local_var_idx(const rb_iseq_t *iseq, ID id)
1717{
1718 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1719
1720 if (idx < 0) {
1721 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1722 "get_local_var_idx: %d", idx);
1723 }
1724
1725 return idx;
1726}
1727
1728static int
1729get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1730{
1731 int lv = 0, idx = -1;
1732 const rb_iseq_t *const topmost_iseq = iseq;
1733
1734 while (iseq) {
1735 idx = get_dyna_var_idx_at_raw(iseq, id);
1736 if (idx >= 0) {
1737 break;
1738 }
1739 iseq = ISEQ_BODY(iseq)->parent_iseq;
1740 lv++;
1741 }
1742
1743 if (idx < 0) {
1744 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1745 "get_dyna_var_idx: -1");
1746 }
1747
1748 *level = lv;
1749 *ls = ISEQ_BODY(iseq)->local_table_size;
1750 return idx;
1751}
1752
1753static int
1754iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1755{
1756 const struct rb_iseq_constant_body *body;
1757 while (level > 0) {
1758 iseq = ISEQ_BODY(iseq)->parent_iseq;
1759 level--;
1760 }
1761 body = ISEQ_BODY(iseq);
1762 if (body->local_iseq == iseq && /* local variables */
1763 body->param.flags.has_block &&
1764 body->local_table_size - body->param.block_start == idx) {
1765 return TRUE;
1766 }
1767 else {
1768 return FALSE;
1769 }
1770}
1771
1772static int
1773iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1774{
1775 int level, ls;
1776 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1777 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1778 *pidx = ls - idx;
1779 *plevel = level;
1780 return TRUE;
1781 }
1782 else {
1783 return FALSE;
1784 }
1785}
1786
1787static void
1788access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1789{
1790 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1791
1792 if (isolated_depth && level >= isolated_depth) {
1793 if (id == rb_intern("yield")) {
1794 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1795 }
1796 else {
1797 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
1798 }
1799 }
1800
1801 for (int i=0; i<level; i++) {
1802 VALUE val;
1803 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1804
1805 if (!ovs) {
1806 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1807 }
1808
1809 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1810 if (write && !val) {
1811 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1812 }
1813 }
1814 else {
1815 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1816 }
1817
1818 iseq = ISEQ_BODY(iseq)->parent_iseq;
1819 }
1820}
1821
1822static ID
1823iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1824{
1825 for (int i=0; i<level; i++) {
1826 iseq = ISEQ_BODY(iseq)->parent_iseq;
1827 }
1828
1829 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1830 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1831 return id;
1832}
1833
1834static void
1835iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1836{
1837 if (iseq_local_block_param_p(iseq, idx, level)) {
1838 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1839 }
1840 else {
1841 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1842 }
1843 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1844}
1845
1846static void
1847iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1848{
1849 if (iseq_local_block_param_p(iseq, idx, level)) {
1850 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1851 }
1852 else {
1853 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1854 }
1855 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1856}
1857
1858
1859
1860static void
1861iseq_calc_param_size(rb_iseq_t *iseq)
1862{
1863 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1864 if (body->param.flags.has_opt ||
1865 body->param.flags.has_post ||
1866 body->param.flags.has_rest ||
1867 body->param.flags.has_block ||
1868 body->param.flags.has_kw ||
1869 body->param.flags.has_kwrest) {
1870
1871 if (body->param.flags.has_block) {
1872 body->param.size = body->param.block_start + 1;
1873 }
1874 else if (body->param.flags.has_kwrest) {
1875 body->param.size = body->param.keyword->rest_start + 1;
1876 }
1877 else if (body->param.flags.has_kw) {
1878 body->param.size = body->param.keyword->bits_start + 1;
1879 }
1880 else if (body->param.flags.has_post) {
1881 body->param.size = body->param.post_start + body->param.post_num;
1882 }
1883 else if (body->param.flags.has_rest) {
1884 body->param.size = body->param.rest_start + 1;
1885 }
1886 else if (body->param.flags.has_opt) {
1887 body->param.size = body->param.lead_num + body->param.opt_num;
1888 }
1889 else {
1891 }
1892 }
1893 else {
1894 body->param.size = body->param.lead_num;
1895 }
1896}
1897
1898static int
1899iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1900 const struct rb_args_info *args, int arg_size)
1901{
1902 const rb_node_kw_arg_t *node = args->kw_args;
1903 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1904 struct rb_iseq_param_keyword *keyword;
1905 const VALUE default_values = rb_ary_hidden_new(1);
1906 const VALUE complex_mark = rb_str_tmp_new(0);
1907 int kw = 0, rkw = 0, di = 0, i;
1908
1909 body->param.flags.has_kw = TRUE;
1910 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1911
1912 while (node) {
1913 kw++;
1914 node = node->nd_next;
1915 }
1916 arg_size += kw;
1917 keyword->bits_start = arg_size++;
1918
1919 node = args->kw_args;
1920 while (node) {
1921 const NODE *val_node = get_nd_value(node->nd_body);
1922 VALUE dv;
1923
1924 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1925 ++rkw;
1926 }
1927 else {
1928 switch (nd_type(val_node)) {
1929 case NODE_LIT:
1930 dv = RNODE_LIT(val_node)->nd_lit;
1931 break;
1932 case NODE_NIL:
1933 dv = Qnil;
1934 break;
1935 case NODE_TRUE:
1936 dv = Qtrue;
1937 break;
1938 case NODE_FALSE:
1939 dv = Qfalse;
1940 break;
1941 default:
1942 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1943 dv = complex_mark;
1944 }
1945
1946 keyword->num = ++di;
1947 rb_ary_push(default_values, dv);
1948 }
1949
1950 node = node->nd_next;
1951 }
1952
1953 keyword->num = kw;
1954
1955 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1956 keyword->rest_start = arg_size++;
1957 body->param.flags.has_kwrest = TRUE;
1958 }
1959 keyword->required_num = rkw;
1960 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1961
1962 {
1963 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1964
1965 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1966 VALUE dv = RARRAY_AREF(default_values, i);
1967 if (dv == complex_mark) dv = Qundef;
1968 if (!SPECIAL_CONST_P(dv)) {
1969 RB_OBJ_WRITTEN(iseq, Qundef, dv);
1970 }
1971 dvs[i] = dv;
1972 }
1973
1974 keyword->default_values = dvs;
1975 }
1976 return arg_size;
1977}
1978
1979static int
1980iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1981{
1982 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1983
1984 if (node_args) {
1985 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1986 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
1987 ID rest_id = 0;
1988 int last_comma = 0;
1989 ID block_id = 0;
1990 int arg_size;
1991
1992 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1993
1994 body->param.flags.ruby2_keywords = args->ruby2_keywords;
1995 body->param.lead_num = arg_size = (int)args->pre_args_num;
1996 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1997 debugs(" - argc: %d\n", body->param.lead_num);
1998
1999 rest_id = args->rest_arg;
2000 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2001 last_comma = 1;
2002 rest_id = 0;
2003 }
2004 block_id = args->block_arg;
2005
2006 if (args->opt_args) {
2007 const rb_node_opt_arg_t *node = args->opt_args;
2008 LABEL *label;
2009 VALUE labels = rb_ary_hidden_new(1);
2010 VALUE *opt_table;
2011 int i = 0, j;
2012
2013 while (node) {
2014 label = NEW_LABEL(nd_line(RNODE(node)));
2015 rb_ary_push(labels, (VALUE)label | 1);
2016 ADD_LABEL(optargs, label);
2017 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2018 node = node->nd_next;
2019 i += 1;
2020 }
2021
2022 /* last label */
2023 label = NEW_LABEL(nd_line(node_args));
2024 rb_ary_push(labels, (VALUE)label | 1);
2025 ADD_LABEL(optargs, label);
2026
2027 opt_table = ALLOC_N(VALUE, i+1);
2028
2029 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2030 for (j = 0; j < i+1; j++) {
2031 opt_table[j] &= ~1;
2032 }
2033 rb_ary_clear(labels);
2034
2035 body->param.flags.has_opt = TRUE;
2036 body->param.opt_num = i;
2037 body->param.opt_table = opt_table;
2038 arg_size += i;
2039 }
2040
2041 if (rest_id) {
2042 body->param.rest_start = arg_size++;
2043 body->param.flags.has_rest = TRUE;
2044 assert(body->param.rest_start != -1);
2045 }
2046
2047 if (args->first_post_arg) {
2048 body->param.post_start = arg_size;
2049 body->param.post_num = args->post_args_num;
2050 body->param.flags.has_post = TRUE;
2051 arg_size += args->post_args_num;
2052
2053 if (body->param.flags.has_rest) { /* TODO: why that? */
2054 body->param.post_start = body->param.rest_start + 1;
2055 }
2056 }
2057
2058 if (args->kw_args) {
2059 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2060 }
2061 else if (args->kw_rest_arg) {
2062 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2063 keyword->rest_start = arg_size++;
2064 body->param.keyword = keyword;
2065 body->param.flags.has_kwrest = TRUE;
2066 }
2067 else if (args->no_kwarg) {
2068 body->param.flags.accepts_no_kwarg = TRUE;
2069 }
2070
2071 if (block_id) {
2072 body->param.block_start = arg_size++;
2073 body->param.flags.has_block = TRUE;
2074 }
2075
2076 iseq_calc_param_size(iseq);
2077 body->param.size = arg_size;
2078
2079 if (args->pre_init) { /* m_init */
2080 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2081 }
2082 if (args->post_init) { /* p_init */
2083 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2084 }
2085
2086 if (body->type == ISEQ_TYPE_BLOCK) {
2087 if (body->param.flags.has_opt == FALSE &&
2088 body->param.flags.has_post == FALSE &&
2089 body->param.flags.has_rest == FALSE &&
2090 body->param.flags.has_kw == FALSE &&
2091 body->param.flags.has_kwrest == FALSE) {
2092
2093 if (body->param.lead_num == 1 && last_comma == 0) {
2094 /* {|a|} */
2095 body->param.flags.ambiguous_param0 = TRUE;
2096 }
2097 }
2098 }
2099 }
2100
2101 return COMPILE_OK;
2102}
2103
2104static int
2105iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl)
2106{
2107 unsigned int size = tbl ? tbl->size : 0;
2108
2109 if (size > 0) {
2110 ID *ids = (ID *)ALLOC_N(ID, size);
2111 MEMCPY(ids, tbl->ids, ID, size);
2112 ISEQ_BODY(iseq)->local_table = ids;
2113 }
2114 ISEQ_BODY(iseq)->local_table_size = size;
2115
2116 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2117 return COMPILE_OK;
2118}
2119
2120int
2121rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2122{
2123 int tval, tlit;
2124
2125 if (val == lit) {
2126 return 0;
2127 }
2128 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2129 return val != lit;
2130 }
2131 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2132 return -1;
2133 }
2134 else if (tlit != tval) {
2135 return -1;
2136 }
2137 else if (tlit == T_SYMBOL) {
2138 return val != lit;
2139 }
2140 else if (tlit == T_STRING) {
2141 return rb_str_hash_cmp(lit, val);
2142 }
2143 else if (tlit == T_BIGNUM) {
2144 long x = FIX2LONG(rb_big_cmp(lit, val));
2145
2146 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2147 * There is no need to call rb_fix2int here. */
2148 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2149 return (int)x;
2150 }
2151 else if (tlit == T_FLOAT) {
2152 return rb_float_cmp(lit, val);
2153 }
2154 else if (tlit == T_RATIONAL) {
2155 const struct RRational *rat1 = RRATIONAL(val);
2156 const struct RRational *rat2 = RRATIONAL(lit);
2157 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2158 }
2159 else if (tlit == T_COMPLEX) {
2160 const struct RComplex *comp1 = RCOMPLEX(val);
2161 const struct RComplex *comp2 = RCOMPLEX(lit);
2162 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2163 }
2164 else if (tlit == T_REGEXP) {
2165 return rb_reg_equal(val, lit) ? 0 : -1;
2166 }
2167 else {
2169 }
2170}
2171
2172st_index_t
2173rb_iseq_cdhash_hash(VALUE a)
2174{
2175 switch (OBJ_BUILTIN_TYPE(a)) {
2176 case -1:
2177 case T_SYMBOL:
2178 return (st_index_t)a;
2179 case T_STRING:
2180 return rb_str_hash(a);
2181 case T_BIGNUM:
2182 return FIX2LONG(rb_big_hash(a));
2183 case T_FLOAT:
2184 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2185 case T_RATIONAL:
2186 return rb_rational_hash(a);
2187 case T_COMPLEX:
2188 return rb_complex_hash(a);
2189 case T_REGEXP:
2190 return NUM2LONG(rb_reg_hash(a));
2191 default:
2193 }
2194}
2195
2196static const struct st_hash_type cdhash_type = {
2197 rb_iseq_cdhash_cmp,
2198 rb_iseq_cdhash_hash,
2199};
2200
2202 VALUE hash;
2203 int pos;
2204 int len;
2205};
2206
2207static int
2208cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2209{
2210 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2211 LABEL *lobj = (LABEL *)(val & ~1);
2212 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2213 return ST_CONTINUE;
2214}
2215
2216
2217static inline VALUE
2218get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2219{
2220 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2221}
2222
2223static inline VALUE
2224get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2225{
2226 VALUE val;
2227 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2228 if (tbl) {
2229 if (rb_id_table_lookup(tbl,id,&val)) {
2230 return val;
2231 }
2232 }
2233 else {
2234 tbl = rb_id_table_create(1);
2235 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2236 }
2237 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2238 rb_id_table_insert(tbl,id,val);
2239 return val;
2240}
2241
2242#define BADINSN_DUMP(anchor, list, dest) \
2243 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2244
2245#define BADINSN_ERROR \
2246 (xfree(generated_iseq), \
2247 xfree(insns_info), \
2248 BADINSN_DUMP(anchor, list, NULL), \
2249 COMPILE_ERROR)
2250
2251static int
2252fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2253{
2254 int stack_max = 0, sp = 0, line = 0;
2255 LINK_ELEMENT *list;
2256
2257 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2258 if (IS_LABEL(list)) {
2259 LABEL *lobj = (LABEL *)list;
2260 lobj->set = TRUE;
2261 }
2262 }
2263
2264 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2265 switch (list->type) {
2266 case ISEQ_ELEMENT_INSN:
2267 {
2268 int j, len, insn;
2269 const char *types;
2270 VALUE *operands;
2271 INSN *iobj = (INSN *)list;
2272
2273 /* update sp */
2274 sp = calc_sp_depth(sp, iobj);
2275 if (sp < 0) {
2276 BADINSN_DUMP(anchor, list, NULL);
2277 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2278 "argument stack underflow (%d)", sp);
2279 return -1;
2280 }
2281 if (sp > stack_max) {
2282 stack_max = sp;
2283 }
2284
2285 line = iobj->insn_info.line_no;
2286 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2287 operands = iobj->operands;
2288 insn = iobj->insn_id;
2289 types = insn_op_types(insn);
2290 len = insn_len(insn);
2291
2292 /* operand check */
2293 if (iobj->operand_size != len - 1) {
2294 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2295 BADINSN_DUMP(anchor, list, NULL);
2296 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2297 "operand size miss! (%d for %d)",
2298 iobj->operand_size, len - 1);
2299 return -1;
2300 }
2301
2302 for (j = 0; types[j]; j++) {
2303 if (types[j] == TS_OFFSET) {
2304 /* label(destination position) */
2305 LABEL *lobj = (LABEL *)operands[j];
2306 if (!lobj->set) {
2307 BADINSN_DUMP(anchor, list, NULL);
2308 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2309 "unknown label: "LABEL_FORMAT, lobj->label_no);
2310 return -1;
2311 }
2312 if (lobj->sp == -1) {
2313 lobj->sp = sp;
2314 }
2315 else if (lobj->sp != sp) {
2316 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2317 RSTRING_PTR(rb_iseq_path(iseq)), line,
2318 lobj->label_no, lobj->sp, sp);
2319 }
2320 }
2321 }
2322 break;
2323 }
2324 case ISEQ_ELEMENT_LABEL:
2325 {
2326 LABEL *lobj = (LABEL *)list;
2327 if (lobj->sp == -1) {
2328 lobj->sp = sp;
2329 }
2330 else {
2331 if (lobj->sp != sp) {
2332 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2333 RSTRING_PTR(rb_iseq_path(iseq)), line,
2334 lobj->label_no, lobj->sp, sp);
2335 }
2336 sp = lobj->sp;
2337 }
2338 break;
2339 }
2340 case ISEQ_ELEMENT_TRACE:
2341 {
2342 /* ignore */
2343 break;
2344 }
2345 case ISEQ_ELEMENT_ADJUST:
2346 {
2347 ADJUST *adjust = (ADJUST *)list;
2348 int orig_sp = sp;
2349
2350 sp = adjust->label ? adjust->label->sp : 0;
2351 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2352 BADINSN_DUMP(anchor, list, NULL);
2353 COMPILE_ERROR(iseq, adjust->line_no,
2354 "iseq_set_sequence: adjust bug %d < %d",
2355 orig_sp, sp);
2356 return -1;
2357 }
2358 break;
2359 }
2360 default:
2361 BADINSN_DUMP(anchor, list, NULL);
2362 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2363 return -1;
2364 }
2365 }
2366 return stack_max;
2367}
2368
2369static int
2370add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2371 int insns_info_index, int code_index, const INSN *iobj)
2372{
2373 if (insns_info_index == 0 ||
2374 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2375#ifdef USE_ISEQ_NODE_ID
2376 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2377#endif
2378 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2379 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2380#ifdef USE_ISEQ_NODE_ID
2381 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2382#endif
2383 insns_info[insns_info_index].events = iobj->insn_info.events;
2384 positions[insns_info_index] = code_index;
2385 return TRUE;
2386 }
2387 return FALSE;
2388}
2389
2390static int
2391add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2392 int insns_info_index, int code_index, const ADJUST *adjust)
2393{
2394 insns_info[insns_info_index].line_no = adjust->line_no;
2395 insns_info[insns_info_index].events = 0;
2396 positions[insns_info_index] = code_index;
2397 return TRUE;
2398}
2399
2400static ID *
2401array_to_idlist(VALUE arr)
2402{
2403 RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2404 long size = RARRAY_LEN(arr);
2405 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2406 for (int i = 0; i < size; i++) {
2407 VALUE sym = RARRAY_AREF(arr, i);
2408 ids[i] = SYM2ID(sym);
2409 }
2410 ids[size] = 0;
2411 return ids;
2412}
2413
2414static VALUE
2415idlist_to_array(const ID *ids)
2416{
2417 VALUE arr = rb_ary_new();
2418 while (*ids) {
2419 rb_ary_push(arr, ID2SYM(*ids++));
2420 }
2421 return arr;
2422}
2423
2427static int
2428iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2429{
2430 struct iseq_insn_info_entry *insns_info;
2431 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2432 unsigned int *positions;
2433 LINK_ELEMENT *list;
2434 VALUE *generated_iseq;
2435 rb_event_flag_t events = 0;
2436 long data = 0;
2437
2438 int insn_num, code_index, insns_info_index, sp = 0;
2439 int stack_max = fix_sp_depth(iseq, anchor);
2440
2441 if (stack_max < 0) return COMPILE_NG;
2442
2443 /* fix label position */
2444 insn_num = code_index = 0;
2445 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2446 switch (list->type) {
2447 case ISEQ_ELEMENT_INSN:
2448 {
2449 INSN *iobj = (INSN *)list;
2450 /* update sp */
2451 sp = calc_sp_depth(sp, iobj);
2452 insn_num++;
2453 events = iobj->insn_info.events |= events;
2454 if (ISEQ_COVERAGE(iseq)) {
2455 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2456 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2457 int line = iobj->insn_info.line_no - 1;
2458 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2459 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2460 }
2461 }
2462 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2463 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2464 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2465 }
2466 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2467 }
2468 }
2469 code_index += insn_data_length(iobj);
2470 events = 0;
2471 data = 0;
2472 break;
2473 }
2474 case ISEQ_ELEMENT_LABEL:
2475 {
2476 LABEL *lobj = (LABEL *)list;
2477 lobj->position = code_index;
2478 if (lobj->sp != sp) {
2479 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2480 RSTRING_PTR(rb_iseq_path(iseq)),
2481 lobj->label_no, lobj->sp, sp);
2482 }
2483 sp = lobj->sp;
2484 break;
2485 }
2486 case ISEQ_ELEMENT_TRACE:
2487 {
2488 TRACE *trace = (TRACE *)list;
2489 events |= trace->event;
2490 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2491 break;
2492 }
2493 case ISEQ_ELEMENT_ADJUST:
2494 {
2495 ADJUST *adjust = (ADJUST *)list;
2496 if (adjust->line_no != -1) {
2497 int orig_sp = sp;
2498 sp = adjust->label ? adjust->label->sp : 0;
2499 if (orig_sp - sp > 0) {
2500 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2501 code_index++; /* insn */
2502 insn_num++;
2503 }
2504 }
2505 break;
2506 }
2507 default: break;
2508 }
2509 }
2510
2511 /* make instruction sequence */
2512 generated_iseq = ALLOC_N(VALUE, code_index);
2513 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2514 positions = ALLOC_N(unsigned int, insn_num);
2515 if (ISEQ_IS_SIZE(body)) {
2516 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2517 }
2518 else {
2519 body->is_entries = NULL;
2520 }
2521 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2522 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2523
2524 // Calculate the bitmask buffer size.
2525 // Round the generated_iseq size up to the nearest multiple
2526 // of the number of bits in an unsigned long.
2527
2528 // Allocate enough room for the bitmask list
2529 iseq_bits_t * mark_offset_bits;
2530 int code_size = code_index;
2531
2532 iseq_bits_t tmp[1] = {0};
2533 bool needs_bitmap = false;
2534
2535 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2536 mark_offset_bits = tmp;
2537 }
2538 else {
2539 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2540 }
2541
2542 list = FIRST_ELEMENT(anchor);
2543 insns_info_index = code_index = sp = 0;
2544
2545 while (list) {
2546 switch (list->type) {
2547 case ISEQ_ELEMENT_INSN:
2548 {
2549 int j, len, insn;
2550 const char *types;
2551 VALUE *operands;
2552 INSN *iobj = (INSN *)list;
2553
2554 /* update sp */
2555 sp = calc_sp_depth(sp, iobj);
2556 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2557 operands = iobj->operands;
2558 insn = iobj->insn_id;
2559 generated_iseq[code_index] = insn;
2560 types = insn_op_types(insn);
2561 len = insn_len(insn);
2562
2563 for (j = 0; types[j]; j++) {
2564 char type = types[j];
2565
2566 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2567 switch (type) {
2568 case TS_OFFSET:
2569 {
2570 /* label(destination position) */
2571 LABEL *lobj = (LABEL *)operands[j];
2572 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2573 break;
2574 }
2575 case TS_CDHASH:
2576 {
2577 VALUE map = operands[j];
2578 struct cdhash_set_label_struct data;
2579 data.hash = map;
2580 data.pos = code_index;
2581 data.len = len;
2582 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2583
2584 rb_hash_rehash(map);
2585 freeze_hide_obj(map);
2586 generated_iseq[code_index + 1 + j] = map;
2587 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2588 RB_OBJ_WRITTEN(iseq, Qundef, map);
2589 needs_bitmap = true;
2590 break;
2591 }
2592 case TS_LINDEX:
2593 case TS_NUM: /* ulong */
2594 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2595 break;
2596 case TS_ISEQ: /* iseq */
2597 case TS_VALUE: /* VALUE */
2598 {
2599 VALUE v = operands[j];
2600 generated_iseq[code_index + 1 + j] = v;
2601 /* to mark ruby object */
2602 if (!SPECIAL_CONST_P(v)) {
2603 RB_OBJ_WRITTEN(iseq, Qundef, v);
2604 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2605 needs_bitmap = true;
2606 }
2607 break;
2608 }
2609 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2610 case TS_IC: /* inline cache: constants */
2611 {
2612 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2613 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2614 if (UNLIKELY(ic_index >= body->ic_size)) {
2615 BADINSN_DUMP(anchor, &iobj->link, 0);
2616 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2617 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2618 ic_index, ISEQ_IS_SIZE(body));
2619 }
2620
2621 ic->segments = array_to_idlist(operands[j]);
2622
2623 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2624 }
2625 break;
2626 case TS_IVC: /* inline ivar cache */
2627 {
2628 unsigned int ic_index = FIX2UINT(operands[j]);
2629
2630 IVC cache = ((IVC)&body->is_entries[ic_index]);
2631
2632 if (insn == BIN(setinstancevariable)) {
2633 cache->iv_set_name = SYM2ID(operands[j - 1]);
2634 }
2635 else {
2636 cache->iv_set_name = 0;
2637 }
2638
2639 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2640 }
2641 case TS_ISE: /* inline storage entry: `once` insn */
2642 case TS_ICVARC: /* inline cvar cache */
2643 {
2644 unsigned int ic_index = FIX2UINT(operands[j]);
2645 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2646 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2647 BADINSN_DUMP(anchor, &iobj->link, 0);
2648 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2649 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2650 ic_index, ISEQ_IS_SIZE(body));
2651 }
2652 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2653
2654 break;
2655 }
2656 case TS_CALLDATA:
2657 {
2658 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2659 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2660 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2661 cd->ci = source_ci;
2662 cd->cc = vm_cc_empty();
2663 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2664 break;
2665 }
2666 case TS_ID: /* ID */
2667 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2668 break;
2669 case TS_FUNCPTR:
2670 generated_iseq[code_index + 1 + j] = operands[j];
2671 break;
2672 case TS_BUILTIN:
2673 generated_iseq[code_index + 1 + j] = operands[j];
2674 break;
2675 default:
2676 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2677 "unknown operand type: %c", type);
2678 return COMPILE_NG;
2679 }
2680 }
2681 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2682 code_index += len;
2683 break;
2684 }
2685 case ISEQ_ELEMENT_LABEL:
2686 {
2687 LABEL *lobj = (LABEL *)list;
2688 if (lobj->sp != sp) {
2689 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2690 RSTRING_PTR(rb_iseq_path(iseq)),
2691 lobj->label_no, lobj->sp, sp);
2692 }
2693 sp = lobj->sp;
2694 break;
2695 }
2696 case ISEQ_ELEMENT_ADJUST:
2697 {
2698 ADJUST *adjust = (ADJUST *)list;
2699 int orig_sp = sp;
2700
2701 if (adjust->label) {
2702 sp = adjust->label->sp;
2703 }
2704 else {
2705 sp = 0;
2706 }
2707
2708 if (adjust->line_no != -1) {
2709 const int diff = orig_sp - sp;
2710 if (diff > 0) {
2711 if (insns_info_index == 0) {
2712 COMPILE_ERROR(iseq, adjust->line_no,
2713 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2714 }
2715 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2716 }
2717 if (diff > 1) {
2718 generated_iseq[code_index++] = BIN(adjuststack);
2719 generated_iseq[code_index++] = orig_sp - sp;
2720 }
2721 else if (diff == 1) {
2722 generated_iseq[code_index++] = BIN(pop);
2723 }
2724 else if (diff < 0) {
2725 int label_no = adjust->label ? adjust->label->label_no : -1;
2726 xfree(generated_iseq);
2727 xfree(insns_info);
2728 xfree(positions);
2729 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2730 xfree(mark_offset_bits);
2731 }
2732 debug_list(anchor, list);
2733 COMPILE_ERROR(iseq, adjust->line_no,
2734 "iseq_set_sequence: adjust bug to %d %d < %d",
2735 label_no, orig_sp, sp);
2736 return COMPILE_NG;
2737 }
2738 }
2739 break;
2740 }
2741 default:
2742 /* ignore */
2743 break;
2744 }
2745 list = list->next;
2746 }
2747
2748 body->iseq_encoded = (void *)generated_iseq;
2749 body->iseq_size = code_index;
2750 body->stack_max = stack_max;
2751
2752 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2753 body->mark_bits.single = mark_offset_bits[0];
2754 }
2755 else {
2756 if (needs_bitmap) {
2757 body->mark_bits.list = mark_offset_bits;
2758 }
2759 else {
2760 body->mark_bits.list = 0;
2761 ruby_xfree(mark_offset_bits);
2762 }
2763 }
2764
2765 /* get rid of memory leak when REALLOC failed */
2766 body->insns_info.body = insns_info;
2767 body->insns_info.positions = positions;
2768
2769 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2770 body->insns_info.body = insns_info;
2771 REALLOC_N(positions, unsigned int, insns_info_index);
2772 body->insns_info.positions = positions;
2773 body->insns_info.size = insns_info_index;
2774
2775 return COMPILE_OK;
2776}
2777
2778static int
2779label_get_position(LABEL *lobj)
2780{
2781 return lobj->position;
2782}
2783
2784static int
2785label_get_sp(LABEL *lobj)
2786{
2787 return lobj->sp;
2788}
2789
2790static int
2791iseq_set_exception_table(rb_iseq_t *iseq)
2792{
2793 const VALUE *tptr, *ptr;
2794 unsigned int tlen, i;
2795 struct iseq_catch_table_entry *entry;
2796
2797 ISEQ_BODY(iseq)->catch_table = NULL;
2798
2799 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2800 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2801 tlen = (int)RARRAY_LEN(catch_table_ary);
2802 tptr = RARRAY_CONST_PTR(catch_table_ary);
2803
2804 if (tlen > 0) {
2805 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2806 table->size = tlen;
2807
2808 for (i = 0; i < table->size; i++) {
2809 ptr = RARRAY_CONST_PTR(tptr[i]);
2810 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2811 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2812 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2813 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2814 entry->iseq = (rb_iseq_t *)ptr[3];
2815 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2816
2817 /* stack depth */
2818 if (ptr[4]) {
2819 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2820 entry->cont = label_get_position(lobj);
2821 entry->sp = label_get_sp(lobj);
2822
2823 /* TODO: Dirty Hack! Fix me */
2824 if (entry->type == CATCH_TYPE_RESCUE ||
2825 entry->type == CATCH_TYPE_BREAK ||
2826 entry->type == CATCH_TYPE_NEXT) {
2827 entry->sp--;
2828 }
2829 }
2830 else {
2831 entry->cont = 0;
2832 }
2833 }
2834 ISEQ_BODY(iseq)->catch_table = table;
2835 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2836 }
2837
2838 RB_GC_GUARD(catch_table_ary);
2839
2840 return COMPILE_OK;
2841}
2842
2843/*
2844 * set optional argument table
2845 * def foo(a, b=expr1, c=expr2)
2846 * =>
2847 * b:
2848 * expr1
2849 * c:
2850 * expr2
2851 */
2852static int
2853iseq_set_optargs_table(rb_iseq_t *iseq)
2854{
2855 int i;
2856 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2857
2858 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2859 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2860 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2861 }
2862 }
2863 return COMPILE_OK;
2864}
2865
2866static LINK_ELEMENT *
2867get_destination_insn(INSN *iobj)
2868{
2869 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2870 LINK_ELEMENT *list;
2871 rb_event_flag_t events = 0;
2872
2873 list = lobj->link.next;
2874 while (list) {
2875 switch (list->type) {
2876 case ISEQ_ELEMENT_INSN:
2877 case ISEQ_ELEMENT_ADJUST:
2878 goto found;
2879 case ISEQ_ELEMENT_LABEL:
2880 /* ignore */
2881 break;
2882 case ISEQ_ELEMENT_TRACE:
2883 {
2884 TRACE *trace = (TRACE *)list;
2885 events |= trace->event;
2886 }
2887 break;
2888 default: break;
2889 }
2890 list = list->next;
2891 }
2892 found:
2893 if (list && IS_INSN(list)) {
2894 INSN *iobj = (INSN *)list;
2895 iobj->insn_info.events |= events;
2896 }
2897 return list;
2898}
2899
2900static LINK_ELEMENT *
2901get_next_insn(INSN *iobj)
2902{
2903 LINK_ELEMENT *list = iobj->link.next;
2904
2905 while (list) {
2906 if (IS_INSN(list) || IS_ADJUST(list)) {
2907 return list;
2908 }
2909 list = list->next;
2910 }
2911 return 0;
2912}
2913
2914static LINK_ELEMENT *
2915get_prev_insn(INSN *iobj)
2916{
2917 LINK_ELEMENT *list = iobj->link.prev;
2918
2919 while (list) {
2920 if (IS_INSN(list) || IS_ADJUST(list)) {
2921 return list;
2922 }
2923 list = list->prev;
2924 }
2925 return 0;
2926}
2927
2928static void
2929unref_destination(INSN *iobj, int pos)
2930{
2931 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2932 --lobj->refcnt;
2933 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2934}
2935
2936static void
2937replace_destination(INSN *dobj, INSN *nobj)
2938{
2939 VALUE n = OPERAND_AT(nobj, 0);
2940 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2941 LABEL *nl = (LABEL *)n;
2942 --dl->refcnt;
2943 ++nl->refcnt;
2944 OPERAND_AT(dobj, 0) = n;
2945 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2946}
2947
2948static LABEL*
2949find_destination(INSN *i)
2950{
2951 int pos, len = insn_len(i->insn_id);
2952 for (pos = 0; pos < len; ++pos) {
2953 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2954 return (LABEL *)OPERAND_AT(i, pos);
2955 }
2956 }
2957 return 0;
2958}
2959
2960static int
2961remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2962{
2963 LINK_ELEMENT *first = i, *end;
2964 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2965
2966 if (!i) return 0;
2967 unref_counts = ALLOCA_N(int, nlabels);
2968 MEMZERO(unref_counts, int, nlabels);
2969 end = i;
2970 do {
2971 LABEL *lab;
2972 if (IS_INSN(i)) {
2973 if (IS_INSN_ID(i, leave)) {
2974 end = i;
2975 break;
2976 }
2977 else if ((lab = find_destination((INSN *)i)) != 0) {
2978 if (lab->unremovable) break;
2979 unref_counts[lab->label_no]++;
2980 }
2981 }
2982 else if (IS_LABEL(i)) {
2983 lab = (LABEL *)i;
2984 if (lab->unremovable) return 0;
2985 if (lab->refcnt > unref_counts[lab->label_no]) {
2986 if (i == first) return 0;
2987 break;
2988 }
2989 continue;
2990 }
2991 else if (IS_TRACE(i)) {
2992 /* do nothing */
2993 }
2994 else if (IS_ADJUST(i)) {
2995 LABEL *dest = ((ADJUST *)i)->label;
2996 if (dest && dest->unremovable) return 0;
2997 }
2998 end = i;
2999 } while ((i = i->next) != 0);
3000 i = first;
3001 do {
3002 if (IS_INSN(i)) {
3003 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3004 VALUE insn = INSN_OF(i);
3005 int pos, len = insn_len(insn);
3006 for (pos = 0; pos < len; ++pos) {
3007 switch (insn_op_types(insn)[pos]) {
3008 case TS_OFFSET:
3009 unref_destination((INSN *)i, pos);
3010 break;
3011 case TS_CALLDATA:
3012 --(body->ci_size);
3013 break;
3014 }
3015 }
3016 }
3017 ELEM_REMOVE(i);
3018 } while ((i != end) && (i = i->next) != 0);
3019 return 1;
3020}
3021
3022static int
3023iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3024{
3025 switch (OPERAND_AT(iobj, 0)) {
3026 case INT2FIX(0): /* empty array */
3027 ELEM_REMOVE(&iobj->link);
3028 return TRUE;
3029 case INT2FIX(1): /* single element array */
3030 ELEM_REMOVE(&iobj->link);
3031 return FALSE;
3032 default:
3033 iobj->insn_id = BIN(adjuststack);
3034 return TRUE;
3035 }
3036}
3037
3038static int
3039is_frozen_putstring(INSN *insn, VALUE *op)
3040{
3041 if (IS_INSN_ID(insn, putstring)) {
3042 *op = OPERAND_AT(insn, 0);
3043 return 1;
3044 }
3045 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3046 *op = OPERAND_AT(insn, 0);
3047 return RB_TYPE_P(*op, T_STRING);
3048 }
3049 return 0;
3050}
3051
3052static int
3053optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3054{
3055 /*
3056 * putobject obj
3057 * dup
3058 * checktype T_XXX
3059 * branchif l1
3060 * l2:
3061 * ...
3062 * l1:
3063 *
3064 * => obj is a T_XXX
3065 *
3066 * putobject obj (T_XXX)
3067 * jump L1
3068 * L1:
3069 *
3070 * => obj is not a T_XXX
3071 *
3072 * putobject obj (T_XXX)
3073 * jump L2
3074 * L2:
3075 */
3076 int line, node_id;
3077 INSN *niobj, *ciobj, *dup = 0;
3078 LABEL *dest = 0;
3079 VALUE type;
3080
3081 switch (INSN_OF(iobj)) {
3082 case BIN(putstring):
3084 break;
3085 case BIN(putnil):
3086 type = INT2FIX(T_NIL);
3087 break;
3088 case BIN(putobject):
3089 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3090 break;
3091 default: return FALSE;
3092 }
3093
3094 ciobj = (INSN *)get_next_insn(iobj);
3095 if (IS_INSN_ID(ciobj, jump)) {
3096 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3097 }
3098 if (IS_INSN_ID(ciobj, dup)) {
3099 ciobj = (INSN *)get_next_insn(dup = ciobj);
3100 }
3101 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3102 niobj = (INSN *)get_next_insn(ciobj);
3103 if (!niobj) {
3104 /* TODO: putobject true/false */
3105 return FALSE;
3106 }
3107 switch (INSN_OF(niobj)) {
3108 case BIN(branchif):
3109 if (OPERAND_AT(ciobj, 0) == type) {
3110 dest = (LABEL *)OPERAND_AT(niobj, 0);
3111 }
3112 break;
3113 case BIN(branchunless):
3114 if (OPERAND_AT(ciobj, 0) != type) {
3115 dest = (LABEL *)OPERAND_AT(niobj, 0);
3116 }
3117 break;
3118 default:
3119 return FALSE;
3120 }
3121 line = ciobj->insn_info.line_no;
3122 node_id = ciobj->insn_info.node_id;
3123 NODE dummy_line_node = generate_dummy_line_node(line, node_id);
3124 if (!dest) {
3125 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3126 dest = (LABEL *)niobj->link.next; /* reuse label */
3127 }
3128 else {
3129 dest = NEW_LABEL(line);
3130 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3131 }
3132 }
3133 INSERT_AFTER_INSN1(iobj, &dummy_line_node, jump, dest);
3134 LABEL_REF(dest);
3135 if (!dup) INSERT_AFTER_INSN(iobj, &dummy_line_node, pop);
3136 return TRUE;
3137}
3138
3139static const struct rb_callinfo *
3140ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3141{
3142 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3143 vm_ci_flag(ci) | add,
3144 vm_ci_argc(ci),
3145 vm_ci_kwarg(ci));
3146 RB_OBJ_WRITTEN(iseq, ci, nci);
3147 return nci;
3148}
3149
3150static const struct rb_callinfo *
3151ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3152{
3153 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3154 vm_ci_flag(ci),
3155 argc,
3156 vm_ci_kwarg(ci));
3157 RB_OBJ_WRITTEN(iseq, ci, nci);
3158 return nci;
3159}
3160
3161static int
3162iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3163{
3164 INSN *const iobj = (INSN *)list;
3165
3166 again:
3167 optimize_checktype(iseq, iobj);
3168
3169 if (IS_INSN_ID(iobj, jump)) {
3170 INSN *niobj, *diobj, *piobj;
3171 diobj = (INSN *)get_destination_insn(iobj);
3172 niobj = (INSN *)get_next_insn(iobj);
3173
3174 if (diobj == niobj) {
3175 /*
3176 * jump LABEL
3177 * LABEL:
3178 * =>
3179 * LABEL:
3180 */
3181 unref_destination(iobj, 0);
3182 ELEM_REMOVE(&iobj->link);
3183 return COMPILE_OK;
3184 }
3185 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3186 IS_INSN_ID(diobj, jump) &&
3187 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3188 diobj->insn_info.events == 0) {
3189 /*
3190 * useless jump elimination:
3191 * jump LABEL1
3192 * ...
3193 * LABEL1:
3194 * jump LABEL2
3195 *
3196 * => in this case, first jump instruction should jump to
3197 * LABEL2 directly
3198 */
3199 replace_destination(iobj, diobj);
3200 remove_unreachable_chunk(iseq, iobj->link.next);
3201 goto again;
3202 }
3203 else if (IS_INSN_ID(diobj, leave)) {
3204 /*
3205 * jump LABEL
3206 * ...
3207 * LABEL:
3208 * leave
3209 * =>
3210 * leave
3211 * ...
3212 * LABEL:
3213 * leave
3214 */
3215 /* replace */
3216 unref_destination(iobj, 0);
3217 iobj->insn_id = BIN(leave);
3218 iobj->operand_size = 0;
3219 iobj->insn_info = diobj->insn_info;
3220 goto again;
3221 }
3222 else if (IS_INSN(iobj->link.prev) &&
3223 (piobj = (INSN *)iobj->link.prev) &&
3224 (IS_INSN_ID(piobj, branchif) ||
3225 IS_INSN_ID(piobj, branchunless))) {
3226 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3227 if (niobj == pdiobj) {
3228 int refcnt = IS_LABEL(piobj->link.next) ?
3229 ((LABEL *)piobj->link.next)->refcnt : 0;
3230 /*
3231 * useless jump elimination (if/unless destination):
3232 * if L1
3233 * jump L2
3234 * L1:
3235 * ...
3236 * L2:
3237 *
3238 * ==>
3239 * unless L2
3240 * L1:
3241 * ...
3242 * L2:
3243 */
3244 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3245 ? BIN(branchunless) : BIN(branchif);
3246 replace_destination(piobj, iobj);
3247 if (refcnt <= 1) {
3248 ELEM_REMOVE(&iobj->link);
3249 }
3250 else {
3251 /* TODO: replace other branch destinations too */
3252 }
3253 return COMPILE_OK;
3254 }
3255 else if (diobj == pdiobj) {
3256 /*
3257 * useless jump elimination (if/unless before jump):
3258 * L1:
3259 * ...
3260 * if L1
3261 * jump L1
3262 *
3263 * ==>
3264 * L1:
3265 * ...
3266 * pop
3267 * jump L1
3268 */
3269 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3270 INSN *popiobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, 0);
3271 ELEM_REPLACE(&piobj->link, &popiobj->link);
3272 }
3273 }
3274 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3275 goto again;
3276 }
3277 }
3278
3279 /*
3280 * putstring "beg"
3281 * putstring "end"
3282 * newrange excl
3283 *
3284 * ==>
3285 *
3286 * putobject "beg".."end"
3287 */
3288 if (IS_INSN_ID(iobj, newrange)) {
3289 INSN *const range = iobj;
3290 INSN *beg, *end;
3291 VALUE str_beg, str_end;
3292
3293 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3294 is_frozen_putstring(end, &str_end) &&
3295 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3296 is_frozen_putstring(beg, &str_beg)) {
3297 int excl = FIX2INT(OPERAND_AT(range, 0));
3298 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3299
3300 ELEM_REMOVE(&beg->link);
3301 ELEM_REMOVE(&end->link);
3302 range->insn_id = BIN(putobject);
3303 OPERAND_AT(range, 0) = lit_range;
3304 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3305 }
3306 }
3307
3308 if (IS_INSN_ID(iobj, leave)) {
3309 remove_unreachable_chunk(iseq, iobj->link.next);
3310 }
3311
3312 /*
3313 * ...
3314 * duparray [...]
3315 * concatarray
3316 * =>
3317 * ...
3318 * putobject [...]
3319 * concatarray
3320 */
3321 if (IS_INSN_ID(iobj, duparray)) {
3322 LINK_ELEMENT *next = iobj->link.next;
3323 if (IS_INSN(next) && IS_INSN_ID(next, concatarray)) {
3324 iobj->insn_id = BIN(putobject);
3325 }
3326 }
3327
3328 if (IS_INSN_ID(iobj, branchif) ||
3329 IS_INSN_ID(iobj, branchnil) ||
3330 IS_INSN_ID(iobj, branchunless)) {
3331 /*
3332 * if L1
3333 * ...
3334 * L1:
3335 * jump L2
3336 * =>
3337 * if L2
3338 */
3339 INSN *nobj = (INSN *)get_destination_insn(iobj);
3340
3341 /* This is super nasty hack!!!
3342 *
3343 * This jump-jump optimization may ignore event flags of the jump
3344 * instruction being skipped. Actually, Line 2 TracePoint event
3345 * is never fired in the following code:
3346 *
3347 * 1: raise if 1 == 2
3348 * 2: while true
3349 * 3: break
3350 * 4: end
3351 *
3352 * This is critical for coverage measurement. [Bug #15980]
3353 *
3354 * This is a stopgap measure: stop the jump-jump optimization if
3355 * coverage measurement is enabled and if the skipped instruction
3356 * has any event flag.
3357 *
3358 * Note that, still, TracePoint Line event does not occur on Line 2.
3359 * This should be fixed in future.
3360 */
3361 int stop_optimization =
3362 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3363 nobj->link.type == ISEQ_ELEMENT_INSN &&
3364 nobj->insn_info.events;
3365 if (!stop_optimization) {
3366 INSN *pobj = (INSN *)iobj->link.prev;
3367 int prev_dup = 0;
3368 if (pobj) {
3369 if (!IS_INSN(&pobj->link))
3370 pobj = 0;
3371 else if (IS_INSN_ID(pobj, dup))
3372 prev_dup = 1;
3373 }
3374
3375 for (;;) {
3376 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3377 replace_destination(iobj, nobj);
3378 }
3379 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3380 !!(nobj = (INSN *)nobj->link.next) &&
3381 /* basic blocks, with no labels in the middle */
3382 nobj->insn_id == iobj->insn_id) {
3383 /*
3384 * dup
3385 * if L1
3386 * ...
3387 * L1:
3388 * dup
3389 * if L2
3390 * =>
3391 * dup
3392 * if L2
3393 * ...
3394 * L1:
3395 * dup
3396 * if L2
3397 */
3398 replace_destination(iobj, nobj);
3399 }
3400 else if (pobj) {
3401 /*
3402 * putnil
3403 * if L1
3404 * =>
3405 * # nothing
3406 *
3407 * putobject true
3408 * if L1
3409 * =>
3410 * jump L1
3411 *
3412 * putstring ".."
3413 * if L1
3414 * =>
3415 * jump L1
3416 *
3417 * putstring ".."
3418 * dup
3419 * if L1
3420 * =>
3421 * putstring ".."
3422 * jump L1
3423 *
3424 */
3425 int cond;
3426 if (prev_dup && IS_INSN(pobj->link.prev)) {
3427 pobj = (INSN *)pobj->link.prev;
3428 }
3429 if (IS_INSN_ID(pobj, putobject)) {
3430 cond = (IS_INSN_ID(iobj, branchif) ?
3431 OPERAND_AT(pobj, 0) != Qfalse :
3432 IS_INSN_ID(iobj, branchunless) ?
3433 OPERAND_AT(pobj, 0) == Qfalse :
3434 FALSE);
3435 }
3436 else if (IS_INSN_ID(pobj, putstring) ||
3437 IS_INSN_ID(pobj, duparray) ||
3438 IS_INSN_ID(pobj, newarray)) {
3439 cond = IS_INSN_ID(iobj, branchif);
3440 }
3441 else if (IS_INSN_ID(pobj, putnil)) {
3442 cond = !IS_INSN_ID(iobj, branchif);
3443 }
3444 else break;
3445 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3446 ELEM_REMOVE(iobj->link.prev);
3447 }
3448 else if (!iseq_pop_newarray(iseq, pobj)) {
3449 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3450 pobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, NULL);
3451 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3452 }
3453 if (cond) {
3454 if (prev_dup) {
3455 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3456 pobj = new_insn_core(iseq, &dummy_line_node, BIN(putnil), 0, NULL);
3457 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3458 }
3459 iobj->insn_id = BIN(jump);
3460 goto again;
3461 }
3462 else {
3463 unref_destination(iobj, 0);
3464 ELEM_REMOVE(&iobj->link);
3465 }
3466 break;
3467 }
3468 else break;
3469 nobj = (INSN *)get_destination_insn(nobj);
3470 }
3471 }
3472 }
3473
3474 if (IS_INSN_ID(iobj, pop)) {
3475 /*
3476 * putself / putnil / putobject obj / putstring "..."
3477 * pop
3478 * =>
3479 * # do nothing
3480 */
3481 LINK_ELEMENT *prev = iobj->link.prev;
3482 if (IS_INSN(prev)) {
3483 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3484 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3485 previ == BIN(putself) || previ == BIN(putstring) ||
3486 previ == BIN(dup) ||
3487 previ == BIN(getlocal) ||
3488 previ == BIN(getblockparam) ||
3489 previ == BIN(getblockparamproxy) ||
3490 previ == BIN(getinstancevariable) ||
3491 previ == BIN(duparray)) {
3492 /* just push operand or static value and pop soon, no
3493 * side effects */
3494 ELEM_REMOVE(prev);
3495 ELEM_REMOVE(&iobj->link);
3496 }
3497 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3498 ELEM_REMOVE(&iobj->link);
3499 }
3500 else if (previ == BIN(concatarray)) {
3501 INSN *piobj = (INSN *)prev;
3502 NODE dummy_line_node = generate_dummy_line_node(piobj->insn_info.line_no, piobj->insn_info.node_id);
3503 INSERT_BEFORE_INSN1(piobj, &dummy_line_node, splatarray, Qfalse);
3504 INSN_OF(piobj) = BIN(pop);
3505 }
3506 else if (previ == BIN(concatstrings)) {
3507 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3508 ELEM_REMOVE(prev);
3509 }
3510 else {
3511 ELEM_REMOVE(&iobj->link);
3512 INSN_OF(prev) = BIN(adjuststack);
3513 }
3514 }
3515 }
3516 }
3517
3518 if (IS_INSN_ID(iobj, newarray) ||
3519 IS_INSN_ID(iobj, duparray) ||
3520 IS_INSN_ID(iobj, expandarray) ||
3521 IS_INSN_ID(iobj, concatarray) ||
3522 IS_INSN_ID(iobj, splatarray) ||
3523 0) {
3524 /*
3525 * newarray N
3526 * splatarray
3527 * =>
3528 * newarray N
3529 * newarray always puts an array
3530 */
3531 LINK_ELEMENT *next = iobj->link.next;
3532 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3533 /* remove splatarray following always-array insn */
3534 ELEM_REMOVE(next);
3535 }
3536 }
3537
3538 if (IS_INSN_ID(iobj, newarray)) {
3539 LINK_ELEMENT *next = iobj->link.next;
3540 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3541 OPERAND_AT(next, 1) == INT2FIX(0)) {
3542 VALUE op1, op2;
3543 op1 = OPERAND_AT(iobj, 0);
3544 op2 = OPERAND_AT(next, 0);
3545 ELEM_REMOVE(next);
3546
3547 if (op1 == op2) {
3548 /*
3549 * newarray 2
3550 * expandarray 2, 0
3551 * =>
3552 * swap
3553 */
3554 if (op1 == INT2FIX(2)) {
3555 INSN_OF(iobj) = BIN(swap);
3556 iobj->operand_size = 0;
3557 }
3558 /*
3559 * newarray X
3560 * expandarray X, 0
3561 * =>
3562 * opt_reverse X
3563 */
3564 else {
3565 INSN_OF(iobj) = BIN(opt_reverse);
3566 }
3567 }
3568 else {
3569 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3570 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3571 INSN_OF(iobj) = BIN(opt_reverse);
3572 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3573
3574 if (op1 > op2) {
3575 /* X > Y
3576 * newarray X
3577 * expandarray Y, 0
3578 * =>
3579 * pop * (Y-X)
3580 * opt_reverse Y
3581 */
3582 for (; diff > 0; diff--) {
3583 INSERT_BEFORE_INSN(iobj, &dummy_line_node, pop);
3584 }
3585 }
3586 else { /* (op1 < op2) */
3587 /* X < Y
3588 * newarray X
3589 * expandarray Y, 0
3590 * =>
3591 * putnil * (Y-X)
3592 * opt_reverse Y
3593 */
3594 for (; diff < 0; diff++) {
3595 INSERT_BEFORE_INSN(iobj, &dummy_line_node, putnil);
3596 }
3597 }
3598 }
3599 }
3600 }
3601
3602 if (IS_INSN_ID(iobj, duparray)) {
3603 LINK_ELEMENT *next = iobj->link.next;
3604 /*
3605 * duparray obj
3606 * expandarray X, 0
3607 * =>
3608 * putobject obj
3609 * expandarray X, 0
3610 */
3611 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3612 INSN_OF(iobj) = BIN(putobject);
3613 }
3614 }
3615
3616 if (IS_INSN_ID(iobj, anytostring)) {
3617 LINK_ELEMENT *next = iobj->link.next;
3618 /*
3619 * anytostring
3620 * concatstrings 1
3621 * =>
3622 * anytostring
3623 */
3624 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3625 OPERAND_AT(next, 0) == INT2FIX(1)) {
3626 ELEM_REMOVE(next);
3627 }
3628 }
3629
3630 if (IS_INSN_ID(iobj, putstring) ||
3631 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3632 /*
3633 * putstring ""
3634 * concatstrings N
3635 * =>
3636 * concatstrings N-1
3637 */
3638 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3639 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3640 INSN *next = (INSN *)iobj->link.next;
3641 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3642 ELEM_REMOVE(&next->link);
3643 }
3644 ELEM_REMOVE(&iobj->link);
3645 }
3646 }
3647
3648 if (IS_INSN_ID(iobj, concatstrings)) {
3649 /*
3650 * concatstrings N
3651 * concatstrings M
3652 * =>
3653 * concatstrings N+M-1
3654 */
3655 LINK_ELEMENT *next = iobj->link.next;
3656 INSN *jump = 0;
3657 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3658 next = get_destination_insn(jump = (INSN *)next);
3659 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3660 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3661 OPERAND_AT(iobj, 0) = INT2FIX(n);
3662 if (jump) {
3663 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3664 if (!--label->refcnt) {
3665 ELEM_REMOVE(&label->link);
3666 }
3667 else {
3668 label = NEW_LABEL(0);
3669 OPERAND_AT(jump, 0) = (VALUE)label;
3670 }
3671 label->refcnt++;
3672 ELEM_INSERT_NEXT(next, &label->link);
3673 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3674 }
3675 else {
3676 ELEM_REMOVE(next);
3677 }
3678 }
3679 }
3680
3681 if (do_tailcallopt &&
3682 (IS_INSN_ID(iobj, send) ||
3683 IS_INSN_ID(iobj, opt_aref_with) ||
3684 IS_INSN_ID(iobj, opt_aset_with) ||
3685 IS_INSN_ID(iobj, invokesuper))) {
3686 /*
3687 * send ...
3688 * leave
3689 * =>
3690 * send ..., ... | VM_CALL_TAILCALL, ...
3691 * leave # unreachable
3692 */
3693 INSN *piobj = NULL;
3694 if (iobj->link.next) {
3695 LINK_ELEMENT *next = iobj->link.next;
3696 do {
3697 if (!IS_INSN(next)) {
3698 next = next->next;
3699 continue;
3700 }
3701 switch (INSN_OF(next)) {
3702 case BIN(nop):
3703 next = next->next;
3704 break;
3705 case BIN(jump):
3706 /* if cond
3707 * return tailcall
3708 * end
3709 */
3710 next = get_destination_insn((INSN *)next);
3711 break;
3712 case BIN(leave):
3713 piobj = iobj;
3714 /* fall through */
3715 default:
3716 next = NULL;
3717 break;
3718 }
3719 } while (next);
3720 }
3721
3722 if (piobj) {
3723 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3724 if (IS_INSN_ID(piobj, send) ||
3725 IS_INSN_ID(piobj, invokesuper)) {
3726 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3727 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3728 OPERAND_AT(piobj, 0) = (VALUE)ci;
3729 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3730 }
3731 }
3732 else {
3733 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3734 OPERAND_AT(piobj, 0) = (VALUE)ci;
3735 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3736 }
3737 }
3738 }
3739
3740 if (IS_INSN_ID(iobj, dup)) {
3741 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3742 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3743
3744 /*
3745 * dup
3746 * setlocal x, y
3747 * setlocal x, y
3748 * =>
3749 * dup
3750 * setlocal x, y
3751 */
3752 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3753 set2 = set1->next;
3754 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3755 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3756 ELEM_REMOVE(set1);
3757 ELEM_REMOVE(&iobj->link);
3758 }
3759 }
3760
3761 /*
3762 * dup
3763 * setlocal x, y
3764 * dup
3765 * setlocal x, y
3766 * =>
3767 * dup
3768 * setlocal x, y
3769 */
3770 else if (IS_NEXT_INSN_ID(set1, dup) &&
3771 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3772 set2 = set1->next->next;
3773 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3774 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3775 ELEM_REMOVE(set1->next);
3776 ELEM_REMOVE(set2);
3777 }
3778 }
3779 }
3780 }
3781
3782 /*
3783 * getlocal x, y
3784 * dup
3785 * setlocal x, y
3786 * =>
3787 * dup
3788 */
3789 if (IS_INSN_ID(iobj, getlocal)) {
3790 LINK_ELEMENT *niobj = &iobj->link;
3791 if (IS_NEXT_INSN_ID(niobj, dup)) {
3792 niobj = niobj->next;
3793 }
3794 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3795 LINK_ELEMENT *set1 = niobj->next;
3796 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3797 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3798 ELEM_REMOVE(set1);
3799 ELEM_REMOVE(niobj);
3800 }
3801 }
3802 }
3803
3804 /*
3805 * opt_invokebuiltin_delegate
3806 * trace
3807 * leave
3808 * =>
3809 * opt_invokebuiltin_delegate_leave
3810 * trace
3811 * leave
3812 */
3813 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3814 if (IS_TRACE(iobj->link.next)) {
3815 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3816 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3817 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
3818 if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
3819 iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_INLINE;
3820 }
3821 }
3822 }
3823 }
3824
3825 /*
3826 * getblockparam
3827 * branchif / branchunless
3828 * =>
3829 * getblockparamproxy
3830 * branchif / branchunless
3831 */
3832 if (IS_INSN_ID(iobj, getblockparam)) {
3833 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
3834 iobj->insn_id = BIN(getblockparamproxy);
3835 }
3836 }
3837
3838 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == Qtrue) {
3839 LINK_ELEMENT *niobj = &iobj->link;
3840
3841 /*
3842 * Eliminate array allocation for f(1, *a)
3843 *
3844 * splatarray true
3845 * send ARGS_SPLAT and not KW_SPLAT|ARGS_BLOCKARG
3846 * =>
3847 * splatarray false
3848 * send
3849 */
3850 if (IS_NEXT_INSN_ID(niobj, send)) {
3851 niobj = niobj->next;
3852 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3853 if ((flag & VM_CALL_ARGS_SPLAT) && !(flag & (VM_CALL_KW_SPLAT|VM_CALL_ARGS_BLOCKARG))) {
3854 OPERAND_AT(iobj, 0) = Qfalse;
3855 }
3856 } else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable)) {
3857 niobj = niobj->next;
3858
3859 if (IS_NEXT_INSN_ID(niobj, send)) {
3860 niobj = niobj->next;
3861 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3862
3863 if ((flag & VM_CALL_ARGS_SPLAT)) {
3864 /*
3865 * Eliminate array allocation for f(1, *a, &lvar) and f(1, *a, &@iv)
3866 *
3867 * splatarray true
3868 * getlocal / getinstancevariable
3869 * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
3870 * =>
3871 * splatarray false
3872 * getlocal / getinstancevariable
3873 * send
3874 */
3875 if ((flag & VM_CALL_ARGS_BLOCKARG) && !(flag & VM_CALL_KW_SPLAT)) {
3876 OPERAND_AT(iobj, 0) = Qfalse;
3877 }
3878
3879 /*
3880 * Eliminate array allocation for f(*a, **lvar) and f(*a, **@iv)
3881 *
3882 * splatarray true
3883 * getlocal / getinstancevariable
3884 * send ARGS_SPLAT|KW_SPLAT and not ARGS_BLOCKARG
3885 * =>
3886 * splatarray false
3887 * getlocal / getinstancevariable
3888 * send
3889 */
3890 else if (!(flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT)) {
3891 OPERAND_AT(iobj, 0) = Qfalse;
3892 }
3893 }
3894 }
3895 else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
3896 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
3897 niobj = niobj->next;
3898
3899 /*
3900 * Eliminate array allocation for f(*a, **lvar, &lvar) and f(*a, **@iv, &@iv)
3901 *
3902 * splatarray true
3903 * getlocal / getinstancevariable
3904 * getlocal / getinstancevariable / getblockparamproxy
3905 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
3906 * =>
3907 * splatarray false
3908 * getlocal / getinstancevariable
3909 * getlocal / getinstancevariable / getblockparamproxy
3910 * send
3911 */
3912 if (IS_NEXT_INSN_ID(niobj, send)) {
3913 niobj = niobj->next;
3914 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3915
3916 if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) && (flag & VM_CALL_ARGS_BLOCKARG)) {
3917 OPERAND_AT(iobj, 0) = Qfalse;
3918 }
3919 }
3920 }
3921 }
3922 else if (IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
3923 niobj = niobj->next;
3924
3925 if (IS_NEXT_INSN_ID(niobj, send)) {
3926 niobj = niobj->next;
3927 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3928
3929 /*
3930 * Eliminate array allocation for f(1, *a, &arg)
3931 *
3932 * splatarray true
3933 * getblockparamproxy
3934 * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
3935 * =>
3936 * splatarray false
3937 * getblockparamproxy
3938 * send
3939 */
3940 if ((flag & VM_CALL_ARGS_BLOCKARG) & (flag & VM_CALL_ARGS_SPLAT) && !(flag & VM_CALL_KW_SPLAT)) {
3941 OPERAND_AT(iobj, 0) = Qfalse;
3942 }
3943 }
3944 }
3945 else if (IS_NEXT_INSN_ID(niobj, duphash)) {
3946 niobj = niobj->next;
3947
3948 /*
3949 * Eliminate array allocation for f(*a, kw: 1)
3950 *
3951 * splatarray true
3952 * duphash
3953 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
3954 * =>
3955 * splatarray false
3956 * duphash
3957 * send
3958 */
3959 if (IS_NEXT_INSN_ID(niobj, send)) {
3960 niobj = niobj->next;
3961 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3962
3963 if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) &&
3964 (flag & VM_CALL_KW_SPLAT_MUT) && !(flag & VM_CALL_ARGS_BLOCKARG)) {
3965 OPERAND_AT(iobj, 0) = Qfalse;
3966 }
3967 }
3968 else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
3969 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
3970 niobj = niobj->next;
3971
3972 /*
3973 * Eliminate array allocation for f(*a, kw: 1, &lvar) and f(*a, kw: 1, &@iv)
3974 *
3975 * splatarray true
3976 * duphash
3977 * getlocal / getinstancevariable / getblockparamproxy
3978 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
3979 * =>
3980 * splatarray false
3981 * duphash
3982 * getlocal / getinstancevariable / getblockparamproxy
3983 * send
3984 */
3985 if (IS_NEXT_INSN_ID(niobj, send)) {
3986 niobj = niobj->next;
3987 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3988
3989 if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) &&
3990 (flag & VM_CALL_KW_SPLAT_MUT) && (flag & VM_CALL_ARGS_BLOCKARG)) {
3991 OPERAND_AT(iobj, 0) = Qfalse;
3992 }
3993 }
3994 }
3995 }
3996 }
3997
3998 return COMPILE_OK;
3999}
4000
4001static int
4002insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4003{
4004 iobj->insn_id = insn_id;
4005 iobj->operand_size = insn_len(insn_id) - 1;
4006 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4007
4008 if (insn_id == BIN(opt_neq)) {
4009 VALUE original_ci = iobj->operands[0];
4010 iobj->operand_size = 2;
4011 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4012 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4013 iobj->operands[1] = original_ci;
4014 }
4015
4016 return COMPILE_OK;
4017}
4018
4019static int
4020iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4021{
4022 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4023 IS_INSN(iobj->link.next)) {
4024 /*
4025 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
4026 */
4027 INSN *niobj = (INSN *)iobj->link.next;
4028 if (IS_INSN_ID(niobj, send)) {
4029 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4030 if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
4031 switch (vm_ci_mid(ci)) {
4032 case idMax:
4033 case idMin:
4034 case idHash:
4035 {
4036 VALUE num = iobj->operands[0];
4037 iobj->insn_id = BIN(opt_newarray_send);
4038 iobj->operands = compile_data_calloc2(iseq, insn_len(iobj->insn_id) - 1, sizeof(VALUE));
4039 iobj->operands[0] = num;
4040 iobj->operands[1] = rb_id2sym(vm_ci_mid(ci));
4041 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4042 ELEM_REMOVE(&niobj->link);
4043 return COMPILE_OK;
4044 }
4045 }
4046 }
4047 }
4048 }
4049
4050 if (IS_INSN_ID(iobj, send)) {
4051 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4052 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4053
4054#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4055 if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
4056 switch (vm_ci_argc(ci)) {
4057 case 0:
4058 switch (vm_ci_mid(ci)) {
4059 case idLength: SP_INSN(length); return COMPILE_OK;
4060 case idSize: SP_INSN(size); return COMPILE_OK;
4061 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4062 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4063 case idSucc: SP_INSN(succ); return COMPILE_OK;
4064 case idNot: SP_INSN(not); return COMPILE_OK;
4065 }
4066 break;
4067 case 1:
4068 switch (vm_ci_mid(ci)) {
4069 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4070 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4071 case idMULT: SP_INSN(mult); return COMPILE_OK;
4072 case idDIV: SP_INSN(div); return COMPILE_OK;
4073 case idMOD: SP_INSN(mod); return COMPILE_OK;
4074 case idEq: SP_INSN(eq); return COMPILE_OK;
4075 case idNeq: SP_INSN(neq); return COMPILE_OK;
4076 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4077 case idLT: SP_INSN(lt); return COMPILE_OK;
4078 case idLE: SP_INSN(le); return COMPILE_OK;
4079 case idGT: SP_INSN(gt); return COMPILE_OK;
4080 case idGE: SP_INSN(ge); return COMPILE_OK;
4081 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4082 case idAREF: SP_INSN(aref); return COMPILE_OK;
4083 case idAnd: SP_INSN(and); return COMPILE_OK;
4084 case idOr: SP_INSN(or); return COMPILE_OK;
4085 }
4086 break;
4087 case 2:
4088 switch (vm_ci_mid(ci)) {
4089 case idASET: SP_INSN(aset); return COMPILE_OK;
4090 }
4091 break;
4092 }
4093 }
4094
4095 if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
4096 iobj->insn_id = BIN(opt_send_without_block);
4097 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4098 }
4099 }
4100#undef SP_INSN
4101
4102 return COMPILE_OK;
4103}
4104
4105static inline int
4106tailcallable_p(rb_iseq_t *iseq)
4107{
4108 switch (ISEQ_BODY(iseq)->type) {
4109 case ISEQ_TYPE_TOP:
4110 case ISEQ_TYPE_EVAL:
4111 case ISEQ_TYPE_MAIN:
4112 /* not tail callable because cfp will be over popped */
4113 case ISEQ_TYPE_RESCUE:
4114 case ISEQ_TYPE_ENSURE:
4115 /* rescue block can't tail call because of errinfo */
4116 return FALSE;
4117 default:
4118 return TRUE;
4119 }
4120}
4121
4122static int
4123iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4124{
4125 LINK_ELEMENT *list;
4126 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4127 const int do_tailcallopt = tailcallable_p(iseq) &&
4128 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4129 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4130 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4131 int rescue_level = 0;
4132 int tailcallopt = do_tailcallopt;
4133
4134 list = FIRST_ELEMENT(anchor);
4135
4136 int do_block_optimization = 0;
4137
4138 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4139 do_block_optimization = 1;
4140 }
4141
4142 while (list) {
4143 if (IS_INSN(list)) {
4144 if (do_peepholeopt) {
4145 iseq_peephole_optimize(iseq, list, tailcallopt);
4146 }
4147 if (do_si) {
4148 iseq_specialized_instruction(iseq, (INSN *)list);
4149 }
4150 if (do_ou) {
4151 insn_operands_unification((INSN *)list);
4152 }
4153
4154 if (do_block_optimization) {
4155 INSN * item = (INSN *)list;
4156 if (IS_INSN_ID(item, jump)) {
4157 do_block_optimization = 0;
4158 }
4159 }
4160 }
4161 if (IS_LABEL(list)) {
4162 switch (((LABEL *)list)->rescued) {
4163 case LABEL_RESCUE_BEG:
4164 rescue_level++;
4165 tailcallopt = FALSE;
4166 break;
4167 case LABEL_RESCUE_END:
4168 if (!--rescue_level) tailcallopt = do_tailcallopt;
4169 break;
4170 }
4171 }
4172 list = list->next;
4173 }
4174
4175 if (do_block_optimization) {
4176 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4177 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4178 ELEM_REMOVE(le);
4179 }
4180 }
4181 return COMPILE_OK;
4182}
4183
4184#if OPT_INSTRUCTIONS_UNIFICATION
4185static INSN *
4186new_unified_insn(rb_iseq_t *iseq,
4187 int insn_id, int size, LINK_ELEMENT *seq_list)
4188{
4189 INSN *iobj = 0;
4190 LINK_ELEMENT *list = seq_list;
4191 int i, argc = 0;
4192 VALUE *operands = 0, *ptr = 0;
4193
4194
4195 /* count argc */
4196 for (i = 0; i < size; i++) {
4197 iobj = (INSN *)list;
4198 argc += iobj->operand_size;
4199 list = list->next;
4200 }
4201
4202 if (argc > 0) {
4203 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4204 }
4205
4206 /* copy operands */
4207 list = seq_list;
4208 for (i = 0; i < size; i++) {
4209 iobj = (INSN *)list;
4210 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4211 ptr += iobj->operand_size;
4212 list = list->next;
4213 }
4214
4215 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
4216 return new_insn_core(iseq, &dummy_line_node, insn_id, argc, operands);
4217}
4218#endif
4219
4220/*
4221 * This scheme can get more performance if do this optimize with
4222 * label address resolving.
4223 * It's future work (if compile time was bottle neck).
4224 */
4225static int
4226iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4227{
4228#if OPT_INSTRUCTIONS_UNIFICATION
4229 LINK_ELEMENT *list;
4230 INSN *iobj, *niobj;
4231 int id, k;
4232 intptr_t j;
4233
4234 list = FIRST_ELEMENT(anchor);
4235 while (list) {
4236 if (IS_INSN(list)) {
4237 iobj = (INSN *)list;
4238 id = iobj->insn_id;
4239 if (unified_insns_data[id] != 0) {
4240 const int *const *entry = unified_insns_data[id];
4241 for (j = 1; j < (intptr_t)entry[0]; j++) {
4242 const int *unified = entry[j];
4243 LINK_ELEMENT *li = list->next;
4244 for (k = 2; k < unified[1]; k++) {
4245 if (!IS_INSN(li) ||
4246 ((INSN *)li)->insn_id != unified[k]) {
4247 goto miss;
4248 }
4249 li = li->next;
4250 }
4251 /* matched */
4252 niobj =
4253 new_unified_insn(iseq, unified[0], unified[1] - 1,
4254 list);
4255
4256 /* insert to list */
4257 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4258 niobj->link.next = li;
4259 if (li) {
4260 li->prev = (LINK_ELEMENT *)niobj;
4261 }
4262
4263 list->prev->next = (LINK_ELEMENT *)niobj;
4264 list = (LINK_ELEMENT *)niobj;
4265 break;
4266 miss:;
4267 }
4268 }
4269 }
4270 list = list->next;
4271 }
4272#endif
4273 return COMPILE_OK;
4274}
4275
4276static int
4277all_string_result_p(const NODE *node)
4278{
4279 if (!node) return FALSE;
4280 switch (nd_type(node)) {
4281 case NODE_STR: case NODE_DSTR:
4282 return TRUE;
4283 case NODE_IF: case NODE_UNLESS:
4284 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4285 if (all_string_result_p(RNODE_IF(node)->nd_body))
4286 return all_string_result_p(RNODE_IF(node)->nd_else);
4287 return FALSE;
4288 case NODE_AND: case NODE_OR:
4289 if (!RNODE_AND(node)->nd_2nd)
4290 return all_string_result_p(RNODE_AND(node)->nd_1st);
4291 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4292 return FALSE;
4293 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4294 default:
4295 return FALSE;
4296 }
4297}
4298
4299static int
4300compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4301{
4302 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4303 VALUE lit = RNODE_DSTR(node)->nd_lit;
4304 LINK_ELEMENT *first_lit = 0;
4305 int cnt = 0;
4306
4307 debugp_param("nd_lit", lit);
4308 if (!NIL_P(lit)) {
4309 cnt++;
4310 if (!RB_TYPE_P(lit, T_STRING)) {
4311 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4312 rb_builtin_type_name(TYPE(lit)));
4313 return COMPILE_NG;
4314 }
4315 lit = rb_fstring(lit);
4316 ADD_INSN1(ret, node, putobject, lit);
4317 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4318 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4319 }
4320
4321 while (list) {
4322 const NODE *const head = list->nd_head;
4323 if (nd_type_p(head, NODE_STR)) {
4324 lit = rb_fstring(RNODE_STR(head)->nd_lit);
4325 ADD_INSN1(ret, head, putobject, lit);
4326 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4327 lit = Qnil;
4328 }
4329 else {
4330 CHECK(COMPILE(ret, "each string", head));
4331 }
4332 cnt++;
4333 list = (struct RNode_LIST *)list->nd_next;
4334 }
4335 if (NIL_P(lit) && first_lit) {
4336 ELEM_REMOVE(first_lit);
4337 --cnt;
4338 }
4339 *cntp = cnt;
4340
4341 return COMPILE_OK;
4342}
4343
4344static int
4345compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4346{
4347 while (node && nd_type_p(node, NODE_BLOCK)) {
4348 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4349 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4350 node = RNODE_BLOCK(node)->nd_next;
4351 }
4352 if (node) {
4353 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4354 }
4355 return COMPILE_OK;
4356}
4357
4358static int
4359compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4360{
4361 int cnt;
4362 if (!RNODE_DSTR(node)->nd_next) {
4363 VALUE lit = rb_fstring(RNODE_DSTR(node)->nd_lit);
4364 ADD_INSN1(ret, node, putstring, lit);
4365 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4366 }
4367 else {
4368 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4369 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4370 }
4371 return COMPILE_OK;
4372}
4373
4374static int
4375compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4376{
4377 int cnt;
4378
4379 if (!RNODE_DREGX(node)->nd_next) {
4380 VALUE match = RNODE_DREGX(node)->nd_lit;
4381 if (RB_TYPE_P(match, T_REGEXP)) {
4382 if (!popped) {
4383 ADD_INSN1(ret, node, putobject, match);
4384 RB_OBJ_WRITTEN(iseq, Qundef, match);
4385 }
4386 return COMPILE_OK;
4387 }
4388 }
4389
4390 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4391 ADD_INSN2(ret, node, toregexp, INT2FIX(RNODE_DREGX(node)->nd_cflag), INT2FIX(cnt));
4392
4393 if (popped) {
4394 ADD_INSN(ret, node, pop);
4395 }
4396
4397 return COMPILE_OK;
4398}
4399
4400static int
4401compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4402 LABEL *then_label, LABEL *else_label)
4403{
4404 const int line = nd_line(node);
4405 LABEL *lend = NEW_LABEL(line);
4406 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4407 + VM_SVAR_FLIPFLOP_START;
4408 VALUE key = INT2FIX(cnt);
4409
4410 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4411 ADD_INSNL(ret, node, branchif, lend);
4412
4413 /* *flip == 0 */
4414 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4415 ADD_INSNL(ret, node, branchunless, else_label);
4416 ADD_INSN1(ret, node, putobject, Qtrue);
4417 ADD_INSN1(ret, node, setspecial, key);
4418 if (!again) {
4419 ADD_INSNL(ret, node, jump, then_label);
4420 }
4421
4422 /* *flip == 1 */
4423 ADD_LABEL(ret, lend);
4424 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4425 ADD_INSNL(ret, node, branchunless, then_label);
4426 ADD_INSN1(ret, node, putobject, Qfalse);
4427 ADD_INSN1(ret, node, setspecial, key);
4428 ADD_INSNL(ret, node, jump, then_label);
4429
4430 return COMPILE_OK;
4431}
4432
4433static int
4434compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4435 LABEL *then_label, LABEL *else_label);
4436
4437#define COMPILE_SINGLE 2
4438static int
4439compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4440 LABEL *then_label, LABEL *else_label)
4441{
4442 DECL_ANCHOR(seq);
4443 INIT_ANCHOR(seq);
4444 LABEL *label = NEW_LABEL(nd_line(cond));
4445 if (!then_label) then_label = label;
4446 else if (!else_label) else_label = label;
4447
4448 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4449
4450 if (LIST_INSN_SIZE_ONE(seq)) {
4451 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4452 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4453 return COMPILE_OK;
4454 }
4455 if (!label->refcnt) {
4456 return COMPILE_SINGLE;
4457 }
4458 ADD_LABEL(seq, label);
4459 ADD_SEQ(ret, seq);
4460 return COMPILE_OK;
4461}
4462
4463static int
4464compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4465 LABEL *then_label, LABEL *else_label)
4466{
4467 int ok;
4468 DECL_ANCHOR(ignore);
4469
4470 again:
4471 switch (nd_type(cond)) {
4472 case NODE_AND:
4473 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4474 cond = RNODE_AND(cond)->nd_2nd;
4475 if (ok == COMPILE_SINGLE) {
4476 INIT_ANCHOR(ignore);
4477 ret = ignore;
4478 then_label = NEW_LABEL(nd_line(cond));
4479 }
4480 goto again;
4481 case NODE_OR:
4482 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4483 cond = RNODE_OR(cond)->nd_2nd;
4484 if (ok == COMPILE_SINGLE) {
4485 INIT_ANCHOR(ignore);
4486 ret = ignore;
4487 else_label = NEW_LABEL(nd_line(cond));
4488 }
4489 goto again;
4490 case NODE_LIT: /* NODE_LIT is always true */
4491 case NODE_TRUE:
4492 case NODE_STR:
4493 case NODE_ZLIST:
4494 case NODE_LAMBDA:
4495 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4496 ADD_INSNL(ret, cond, jump, then_label);
4497 return COMPILE_OK;
4498 case NODE_FALSE:
4499 case NODE_NIL:
4500 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4501 ADD_INSNL(ret, cond, jump, else_label);
4502 return COMPILE_OK;
4503 case NODE_LIST:
4504 case NODE_ARGSCAT:
4505 case NODE_DREGX:
4506 case NODE_DSTR:
4507 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4508 ADD_INSNL(ret, cond, jump, then_label);
4509 return COMPILE_OK;
4510 case NODE_FLIP2:
4511 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4512 return COMPILE_OK;
4513 case NODE_FLIP3:
4514 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4515 return COMPILE_OK;
4516 case NODE_DEFINED:
4517 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
4518 break;
4519 default:
4520 {
4521 DECL_ANCHOR(cond_seq);
4522 INIT_ANCHOR(cond_seq);
4523
4524 CHECK(COMPILE(cond_seq, "branch condition", cond));
4525
4526 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4527 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4528 if (insn->insn_id == BIN(putobject)) {
4529 if (RTEST(insn->operands[0])) {
4530 ADD_INSNL(ret, cond, jump, then_label);
4531 // maybe unreachable
4532 return COMPILE_OK;
4533 }
4534 else {
4535 ADD_INSNL(ret, cond, jump, else_label);
4536 return COMPILE_OK;
4537 }
4538 }
4539 }
4540 ADD_SEQ(ret, cond_seq);
4541 }
4542 break;
4543 }
4544
4545 ADD_INSNL(ret, cond, branchunless, else_label);
4546 ADD_INSNL(ret, cond, jump, then_label);
4547 return COMPILE_OK;
4548}
4549
4550#define HASH_BRACE 1
4551
4552static int
4553keyword_node_p(const NODE *const node)
4554{
4555 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4556}
4557
4558static int
4559compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4560 const NODE *const root_node,
4561 struct rb_callinfo_kwarg **const kw_arg_ptr,
4562 unsigned int *flag)
4563{
4564 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4565 RUBY_ASSERT(kw_arg_ptr != NULL);
4566 RUBY_ASSERT(flag != NULL);
4567
4568 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4569 const NODE *node = RNODE_HASH(root_node)->nd_head;
4570 int seen_nodes = 0;
4571
4572 while (node) {
4573 const NODE *key_node = RNODE_LIST(node)->nd_head;
4574 seen_nodes++;
4575
4576 assert(nd_type_p(node, NODE_LIST));
4577 if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(RNODE_LIT(key_node)->nd_lit)) {
4578 /* can be keywords */
4579 }
4580 else {
4581 if (flag) {
4582 *flag |= VM_CALL_KW_SPLAT;
4583 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4584 /* A new hash will be created for the keyword arguments
4585 * in this case, so mark the method as passing mutable
4586 * keyword splat.
4587 */
4588 *flag |= VM_CALL_KW_SPLAT_MUT;
4589 }
4590 }
4591 return FALSE;
4592 }
4593 node = RNODE_LIST(node)->nd_next; /* skip value node */
4594 node = RNODE_LIST(node)->nd_next;
4595 }
4596
4597 /* may be keywords */
4598 node = RNODE_HASH(root_node)->nd_head;
4599 {
4600 int len = (int)RNODE_LIST(node)->as.nd_alen / 2;
4601 struct rb_callinfo_kwarg *kw_arg =
4602 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4603 VALUE *keywords = kw_arg->keywords;
4604 int i = 0;
4605 kw_arg->references = 0;
4606 kw_arg->keyword_len = len;
4607
4608 *kw_arg_ptr = kw_arg;
4609
4610 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4611 const NODE *key_node = RNODE_LIST(node)->nd_head;
4612 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4613 keywords[i] = RNODE_LIT(key_node)->nd_lit;
4614 NO_CHECK(COMPILE(ret, "keyword values", val_node));
4615 }
4616 assert(i == len);
4617 return TRUE;
4618 }
4619 }
4620 return FALSE;
4621}
4622
4623static int
4624compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4625{
4626 int len = 0;
4627
4628 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4629 if (CPDEBUG > 0) {
4630 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4631 }
4632
4633 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4634 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4635 }
4636 else {
4637 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4638 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4639 }
4640 }
4641
4642 return len;
4643}
4644
4645static inline int
4646static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
4647{
4648 switch (nd_type(node)) {
4649 case NODE_LIT:
4650 case NODE_NIL:
4651 case NODE_TRUE:
4652 case NODE_FALSE:
4653 return TRUE;
4654 case NODE_STR:
4655 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
4656 default:
4657 return FALSE;
4658 }
4659}
4660
4661static inline VALUE
4662static_literal_value(const NODE *node, rb_iseq_t *iseq)
4663{
4664 switch (nd_type(node)) {
4665 case NODE_NIL:
4666 return Qnil;
4667 case NODE_TRUE:
4668 return Qtrue;
4669 case NODE_FALSE:
4670 return Qfalse;
4671 case NODE_STR:
4672 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4673 VALUE lit;
4674 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
4675 lit = rb_str_dup(RNODE_STR(node)->nd_lit);
4676 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
4677 return rb_str_freeze(lit);
4678 }
4679 else {
4680 return rb_fstring(RNODE_STR(node)->nd_lit);
4681 }
4682 default:
4683 return RNODE_LIT(node)->nd_lit;
4684 }
4685}
4686
4687static int
4688compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4689{
4690 const NODE *line_node = node;
4691
4692 if (nd_type_p(node, NODE_ZLIST)) {
4693 if (!popped) {
4694 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4695 }
4696 return 0;
4697 }
4698
4699 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4700
4701 if (popped) {
4702 for (; node; node = RNODE_LIST(node)->nd_next) {
4703 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
4704 }
4705 return 1;
4706 }
4707
4708 /* Compilation of an array literal.
4709 * The following code is essentially the same as:
4710 *
4711 * for (int count = 0; node; count++; node->nd_next) {
4712 * compile(node->nd_head);
4713 * }
4714 * ADD_INSN(newarray, count);
4715 *
4716 * However, there are three points.
4717 *
4718 * - The code above causes stack overflow for a big string literal.
4719 * The following limits the stack length up to max_stack_len.
4720 *
4721 * [x1,x2,...,x10000] =>
4722 * push x1 ; push x2 ; ...; push x256; newarray 256;
4723 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4724 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4725 * ...
4726 *
4727 * - Long subarray can be optimized by pre-allocating a hidden array.
4728 *
4729 * [1,2,3,...,100] =>
4730 * duparray [1,2,3,...,100]
4731 *
4732 * [x, 1,2,3,...,100, z] =>
4733 * push x; newarray 1;
4734 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4735 * push z; newarray 1; concatarray
4736 *
4737 * - If the last element is a keyword, newarraykwsplat should be emitted
4738 * to check and remove empty keyword arguments hash from array.
4739 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4740 *
4741 * [1,2,3,**kw] =>
4742 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4743 */
4744
4745 const int max_stack_len = 0x100;
4746 const int min_tmp_ary_len = 0x40;
4747 int stack_len = 0;
4748 int first_chunk = 1;
4749
4750 /* Convert pushed elements to an array, and concatarray if needed */
4751#define FLUSH_CHUNK(newarrayinsn) \
4752 if (stack_len) { \
4753 ADD_INSN1(ret, line_node, newarrayinsn, INT2FIX(stack_len)); \
4754 if (!first_chunk) ADD_INSN(ret, line_node, concatarray); \
4755 first_chunk = stack_len = 0; \
4756 }
4757
4758 while (node) {
4759 int count = 1;
4760
4761 /* pre-allocation check (this branch can be omittable) */
4762 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq)) {
4763 /* count the elements that are optimizable */
4764 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
4765 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq); node_tmp = RNODE_LIST(node_tmp)->nd_next)
4766 count++;
4767
4768 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4769 /* The literal contains only optimizable elements, or the subarray is long enough */
4770 VALUE ary = rb_ary_hidden_new(count);
4771
4772 /* Create a hidden array */
4773 for (; count; count--, node = RNODE_LIST(node)->nd_next)
4774 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
4775 OBJ_FREEZE(ary);
4776
4777 /* Emit optimized code */
4778 FLUSH_CHUNK(newarray);
4779 if (first_chunk) {
4780 ADD_INSN1(ret, line_node, duparray, ary);
4781 first_chunk = 0;
4782 }
4783 else {
4784 ADD_INSN1(ret, line_node, putobject, ary);
4785 ADD_INSN(ret, line_node, concatarray);
4786 }
4787 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4788 }
4789 }
4790
4791 /* Base case: Compile "count" elements */
4792 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
4793 if (CPDEBUG > 0) {
4794 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4795 }
4796
4797 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
4798 stack_len++;
4799
4800 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
4801 /* Reached the end, and the last element is a keyword */
4802 FLUSH_CHUNK(newarraykwsplat);
4803 return 1;
4804 }
4805
4806 /* If there are many pushed elements, flush them to avoid stack overflow */
4807 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4808 }
4809 }
4810
4811 FLUSH_CHUNK(newarray);
4812#undef FLUSH_CHUNK
4813 return 1;
4814}
4815
4816/* Compile an array containing the single element represented by node */
4817static int
4818compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
4819{
4820 if (static_literal_node_p(node, iseq)) {
4821 VALUE ary = rb_ary_hidden_new(1);
4822 rb_ary_push(ary, static_literal_value(node, iseq));
4823 OBJ_FREEZE(ary);
4824
4825 ADD_INSN1(ret, node, duparray, ary);
4826 }
4827 else {
4828 CHECK(COMPILE_(ret, "array element", node, FALSE));
4829 if (keyword_node_p(node)) {
4830 ADD_INSN1(ret, node, newarraykwsplat, INT2FIX(1));
4831 }
4832 else {
4833 ADD_INSN1(ret, node, newarray, INT2FIX(1));
4834 }
4835 }
4836
4837 return 1;
4838}
4839
4840static inline int
4841static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4842{
4843 return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
4844}
4845
4846static int
4847compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4848{
4849 const NODE *line_node = node;
4850
4851 node = RNODE_HASH(node)->nd_head;
4852
4853 if (!node || nd_type_p(node, NODE_ZLIST)) {
4854 if (!popped) {
4855 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4856 }
4857 return 0;
4858 }
4859
4860 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4861
4862 if (popped) {
4863 for (; node; node = RNODE_LIST(node)->nd_next) {
4864 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
4865 }
4866 return 1;
4867 }
4868
4869 /* Compilation of a hash literal (or keyword arguments).
4870 * This is very similar to compile_array, but there are some differences:
4871 *
4872 * - It contains key-value pairs. So we need to take every two elements.
4873 * We can assume that the length is always even.
4874 *
4875 * - Merging is done by a method call (id_core_hash_merge_ptr).
4876 * Sometimes we need to insert the receiver, so "anchor" is needed.
4877 * In addition, a method call is much slower than concatarray.
4878 * So it pays only when the subsequence is really long.
4879 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4880 *
4881 * - We need to handle keyword splat: **kw.
4882 * For **kw, the key part (node->nd_head) is NULL, and the value part
4883 * (node->nd_next->nd_head) is "kw".
4884 * The code is a bit difficult to avoid hash allocation for **{}.
4885 */
4886
4887 const int max_stack_len = 0x100;
4888 const int min_tmp_hash_len = 0x800;
4889 int stack_len = 0;
4890 int first_chunk = 1;
4891 DECL_ANCHOR(anchor);
4892 INIT_ANCHOR(anchor);
4893
4894 /* Convert pushed elements to a hash, and merge if needed */
4895#define FLUSH_CHUNK() \
4896 if (stack_len) { \
4897 if (first_chunk) { \
4898 APPEND_LIST(ret, anchor); \
4899 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4900 } \
4901 else { \
4902 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4903 ADD_INSN(ret, line_node, swap); \
4904 APPEND_LIST(ret, anchor); \
4905 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4906 } \
4907 INIT_ANCHOR(anchor); \
4908 first_chunk = stack_len = 0; \
4909 }
4910
4911 while (node) {
4912 int count = 1;
4913
4914 /* pre-allocation check (this branch can be omittable) */
4915 if (static_literal_node_pair_p(node, iseq)) {
4916 /* count the elements that are optimizable */
4917 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
4918 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
4919 count++;
4920
4921 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4922 /* The literal contains only optimizable elements, or the subsequence is long enough */
4923 VALUE ary = rb_ary_hidden_new(count);
4924
4925 /* Create a hidden hash */
4926 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4927 VALUE elem[2];
4928 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
4929 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
4930 rb_ary_cat(ary, elem, 2);
4931 }
4932 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4933 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
4934 hash = rb_obj_hide(hash);
4935 OBJ_FREEZE(hash);
4936
4937 /* Emit optimized code */
4938 FLUSH_CHUNK();
4939 if (first_chunk) {
4940 ADD_INSN1(ret, line_node, duphash, hash);
4941 first_chunk = 0;
4942 }
4943 else {
4944 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4945 ADD_INSN(ret, line_node, swap);
4946
4947 ADD_INSN1(ret, line_node, putobject, hash);
4948
4949 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4950 }
4951 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4952 }
4953 }
4954
4955 /* Base case: Compile "count" elements */
4956 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4957
4958 if (CPDEBUG > 0) {
4959 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4960 }
4961
4962 if (RNODE_LIST(node)->nd_head) {
4963 /* Normal key-value pair */
4964 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
4965 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
4966 stack_len += 2;
4967
4968 /* If there are many pushed elements, flush them to avoid stack overflow */
4969 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4970 }
4971 else {
4972 /* kwsplat case: foo(..., **kw, ...) */
4973 FLUSH_CHUNK();
4974
4975 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4976 int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(RNODE_LIT(kw)->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4977 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4978 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
4979 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4980
4981 if (empty_kw) {
4982 if (only_kw && method_call_keywords) {
4983 /* **{} appears at the only keyword argument in method call,
4984 * so it won't be modified.
4985 * kw is a special NODE_LIT that contains a special empty hash,
4986 * so this emits: putobject {}.
4987 * This is only done for method calls and not for literal hashes,
4988 * because literal hashes should always result in a new hash.
4989 */
4990 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4991 }
4992 else if (first_kw) {
4993 /* **{} appears as the first keyword argument, so it may be modified.
4994 * We need to create a fresh hash object.
4995 */
4996 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4997 }
4998 /* Any empty keyword splats that are not the first can be ignored.
4999 * since merging an empty hash into the existing hash is the same
5000 * as not merging it. */
5001 }
5002 else {
5003 if (only_kw && method_call_keywords) {
5004 /* **kw is only keyword argument in method call.
5005 * Use directly. This will be not be flagged as mutable.
5006 * This is only done for method calls and not for literal hashes,
5007 * because literal hashes should always result in a new hash.
5008 */
5009 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5010 }
5011 else {
5012 /* There is more than one keyword argument, or this is not a method
5013 * call. In that case, we need to add an empty hash (if first keyword),
5014 * or merge the hash to the accumulated hash (if not the first keyword).
5015 */
5016 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5017 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5018 else ADD_INSN(ret, line_node, swap);
5019
5020 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5021
5022 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5023 }
5024 }
5025
5026 first_chunk = 0;
5027 }
5028 }
5029 }
5030
5031 FLUSH_CHUNK();
5032#undef FLUSH_CHUNK
5033 return 1;
5034}
5035
5036VALUE
5037rb_node_case_when_optimizable_literal(const NODE *const node)
5038{
5039 switch (nd_type(node)) {
5040 case NODE_LIT: {
5041 VALUE v = RNODE_LIT(node)->nd_lit;
5042 double ival;
5043 if (RB_FLOAT_TYPE_P(v) &&
5044 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5045 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5046 }
5047 if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
5048 return Qundef;
5049 }
5050 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
5051 return v;
5052 }
5053 break;
5054 }
5055 case NODE_NIL:
5056 return Qnil;
5057 case NODE_TRUE:
5058 return Qtrue;
5059 case NODE_FALSE:
5060 return Qfalse;
5061 case NODE_STR:
5062 return rb_fstring(RNODE_STR(node)->nd_lit);
5063 }
5064 return Qundef;
5065}
5066
5067static int
5068when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5069 LABEL *l1, int only_special_literals, VALUE literals)
5070{
5071 while (vals) {
5072 const NODE *val = RNODE_LIST(vals)->nd_head;
5073 VALUE lit = rb_node_case_when_optimizable_literal(val);
5074
5075 if (UNDEF_P(lit)) {
5076 only_special_literals = 0;
5077 }
5078 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5079 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5080 }
5081
5082 if (nd_type_p(val, NODE_STR)) {
5083 debugp_param("nd_lit", RNODE_STR(val)->nd_lit);
5084 lit = rb_fstring(RNODE_STR(val)->nd_lit);
5085 ADD_INSN1(cond_seq, val, putobject, lit);
5086 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5087 }
5088 else {
5089 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5090 }
5091
5092 // Emit pattern === target
5093 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5094 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5095 ADD_INSNL(cond_seq, val, branchif, l1);
5096 vals = RNODE_LIST(vals)->nd_next;
5097 }
5098 return only_special_literals;
5099}
5100
5101static int
5102when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5103 LABEL *l1, int only_special_literals, VALUE literals)
5104{
5105 const NODE *line_node = vals;
5106
5107 switch (nd_type(vals)) {
5108 case NODE_LIST:
5109 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5110 return COMPILE_NG;
5111 break;
5112 case NODE_SPLAT:
5113 ADD_INSN (cond_seq, line_node, dup);
5114 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5115 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5116 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5117 ADD_INSNL(cond_seq, line_node, branchif, l1);
5118 break;
5119 case NODE_ARGSCAT:
5120 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5121 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5122 break;
5123 case NODE_ARGSPUSH:
5124 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5125 ADD_INSN (cond_seq, line_node, dup);
5126 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5127 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5128 ADD_INSNL(cond_seq, line_node, branchif, l1);
5129 break;
5130 default:
5131 ADD_INSN (cond_seq, line_node, dup);
5132 CHECK(COMPILE(cond_seq, "when val", vals));
5133 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5134 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5135 ADD_INSNL(cond_seq, line_node, branchif, l1);
5136 break;
5137 }
5138 return COMPILE_OK;
5139}
5140
5141/* Multiple Assignment Handling
5142 *
5143 * In order to handle evaluation of multiple assignment such that the left hand side
5144 * is evaluated before the right hand side, we need to process the left hand side
5145 * and see if there are any attributes that need to be assigned, or constants set
5146 * on explicit objects. If so, we add instructions to evaluate the receiver of
5147 * any assigned attributes or constants before we process the right hand side.
5148 *
5149 * For a multiple assignment such as:
5150 *
5151 * l1.m1, l2[0] = r3, r4
5152 *
5153 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5154 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5155 * On the VM stack, this looks like:
5156 *
5157 * self # putself
5158 * l1 # send
5159 * l1, self # putself
5160 * l1, l2 # send
5161 * l1, l2, 0 # putobject 0
5162 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5163 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5164 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5165 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5166 * l1, l2, 0, [r3, r4], r4, m1= # send
5167 * l1, l2, 0, [r3, r4], r4 # pop
5168 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5169 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5170 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5171 * l1, l2, 0, [r3, r4], r4, []= # send
5172 * l1, l2, 0, [r3, r4], r4 # pop
5173 * l1, l2, 0, [r3, r4] # pop
5174 * [r3, r4], l2, 0, [r3, r4] # setn 3
5175 * [r3, r4], l2, 0 # pop
5176 * [r3, r4], l2 # pop
5177 * [r3, r4] # pop
5178 *
5179 * This is made more complex when you have to handle splats, post args,
5180 * and arbitrary levels of nesting. You need to keep track of the total
5181 * number of attributes to set, and for each attribute, how many entries
5182 * are on the stack before the final attribute, in order to correctly
5183 * calculate the topn value to use to get the receiver of the attribute
5184 * setter method.
5185 *
5186 * A brief description of the VM stack for simple multiple assignment
5187 * with no splat (rhs_array will not be present if the return value of
5188 * the multiple assignment is not needed):
5189 *
5190 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5191 *
5192 * For multiple assignment with splats, while processing the part before
5193 * the splat (splat+post here is an array of the splat and the post arguments):
5194 *
5195 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5196 *
5197 * When processing the splat and post arguments:
5198 *
5199 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5200 *
5201 * When processing nested multiple assignment, existing values on the stack
5202 * are kept. So for:
5203 *
5204 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5205 *
5206 * The stack layout would be the following before processing the nested
5207 * multiple assignment:
5208 *
5209 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5210 *
5211 * In order to handle this correctly, we need to keep track of the nesting
5212 * level for each attribute assignment, as well as the attribute number
5213 * (left hand side attributes are processed left to right) and number of
5214 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5215 * this information.
5216 *
5217 * We also need to track information for the entire multiple assignment, such
5218 * as the total number of arguments, and the current nesting level, to
5219 * handle both nested multiple assignment as well as cases where the
5220 * rhs is not needed. We also need to keep track of all attribute
5221 * assignments in this, which we do using a linked listed. struct masgn_state
5222 * tracks this information.
5223 */
5224
5226 INSN *before_insn;
5227 struct masgn_lhs_node *next;
5228 const NODE *line_node;
5229 int argn;
5230 int num_args;
5231 int lhs_pos;
5232};
5233
5235 struct masgn_lhs_node *first_memo;
5236 struct masgn_lhs_node *last_memo;
5237 int lhs_level;
5238 int num_args;
5239 bool nested;
5240};
5241
5242static int
5243add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5244{
5245 if (!state) {
5246 rb_bug("no masgn_state");
5247 }
5248
5249 struct masgn_lhs_node *memo;
5250 memo = malloc(sizeof(struct masgn_lhs_node));
5251 if (!memo) {
5252 return COMPILE_NG;
5253 }
5254
5255 memo->before_insn = before_insn;
5256 memo->line_node = line_node;
5257 memo->argn = state->num_args + 1;
5258 memo->num_args = argc;
5259 state->num_args += argc;
5260 memo->lhs_pos = lhs_pos;
5261 memo->next = NULL;
5262 if (!state->first_memo) {
5263 state->first_memo = memo;
5264 }
5265 else {
5266 state->last_memo->next = memo;
5267 }
5268 state->last_memo = memo;
5269
5270 return COMPILE_OK;
5271}
5272
5273static 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);
5274
5275static int
5276compile_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)
5277{
5278 switch (nd_type(node)) {
5279 case NODE_ATTRASGN: {
5280 INSN *iobj;
5281 const NODE *line_node = node;
5282
5283 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5284
5285 bool safenav_call = false;
5286 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5287 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5288 ASSUME(iobj);
5289 ELEM_REMOVE(insn_element);
5290 if (!IS_INSN_ID(iobj, send)) {
5291 safenav_call = true;
5292 iobj = (INSN *)get_prev_insn(iobj);
5293 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5294 }
5295 (pre->last = iobj->link.prev)->next = 0;
5296
5297 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5298 int argc = vm_ci_argc(ci) + 1;
5299 ci = ci_argc_set(iseq, ci, argc);
5300 OPERAND_AT(iobj, 0) = (VALUE)ci;
5301 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5302
5303 if (argc == 1) {
5304 ADD_INSN(lhs, line_node, swap);
5305 }
5306 else {
5307 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5308 }
5309
5310 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5311 return COMPILE_NG;
5312 }
5313
5314 iobj->link.prev = lhs->last;
5315 lhs->last->next = &iobj->link;
5316 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5317 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5318 int argc = vm_ci_argc(ci);
5319 ci = ci_argc_set(iseq, ci, argc - 1);
5320 OPERAND_AT(iobj, 0) = (VALUE)ci;
5321 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5322 INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
5323 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
5324 }
5325 if (!safenav_call) {
5326 ADD_INSN(lhs, line_node, pop);
5327 if (argc != 1) {
5328 ADD_INSN(lhs, line_node, pop);
5329 }
5330 }
5331 for (int i=0; i < argc; i++) {
5332 ADD_INSN(post, line_node, pop);
5333 }
5334 break;
5335 }
5336 case NODE_MASGN: {
5337 DECL_ANCHOR(nest_rhs);
5338 INIT_ANCHOR(nest_rhs);
5339 DECL_ANCHOR(nest_lhs);
5340 INIT_ANCHOR(nest_lhs);
5341
5342 int prev_level = state->lhs_level;
5343 bool prev_nested = state->nested;
5344 state->nested = 1;
5345 state->lhs_level = lhs_pos - 1;
5346 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5347 state->lhs_level = prev_level;
5348 state->nested = prev_nested;
5349
5350 ADD_SEQ(lhs, nest_rhs);
5351 ADD_SEQ(lhs, nest_lhs);
5352 break;
5353 }
5354 case NODE_CDECL:
5355 if (!RNODE_CDECL(node)->nd_vid) {
5356 /* Special handling only needed for expr::C, not for C */
5357 INSN *iobj;
5358
5359 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5360
5361 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5362 iobj = (INSN *)insn_element; /* setconstant insn */
5363 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5364 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5365 ELEM_REMOVE(insn_element);
5366 pre->last = iobj->link.prev;
5367 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5368
5369 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5370 return COMPILE_NG;
5371 }
5372
5373 ADD_INSN(post, node, pop);
5374 break;
5375 }
5376 /* Fallthrough */
5377 default: {
5378 DECL_ANCHOR(anchor);
5379 INIT_ANCHOR(anchor);
5380 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5381 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5382 ADD_SEQ(lhs, anchor);
5383 }
5384 }
5385
5386 return COMPILE_OK;
5387}
5388
5389static int
5390compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5391{
5392 if (lhsn) {
5393 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5394 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5395 }
5396 return COMPILE_OK;
5397}
5398
5399static int
5400compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5401 const NODE *rhsn, const NODE *orig_lhsn)
5402{
5403 VALUE mem[64];
5404 const int memsize = numberof(mem);
5405 int memindex = 0;
5406 int llen = 0, rlen = 0;
5407 int i;
5408 const NODE *lhsn = orig_lhsn;
5409
5410#define MEMORY(v) { \
5411 int i; \
5412 if (memindex == memsize) return 0; \
5413 for (i=0; i<memindex; i++) { \
5414 if (mem[i] == (v)) return 0; \
5415 } \
5416 mem[memindex++] = (v); \
5417}
5418
5419 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5420 return 0;
5421 }
5422
5423 while (lhsn) {
5424 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5425 switch (nd_type(ln)) {
5426 case NODE_LASGN:
5427 case NODE_DASGN:
5428 case NODE_IASGN:
5429 case NODE_CVASGN:
5430 MEMORY(get_nd_vid(ln));
5431 break;
5432 default:
5433 return 0;
5434 }
5435 lhsn = RNODE_LIST(lhsn)->nd_next;
5436 llen++;
5437 }
5438
5439 while (rhsn) {
5440 if (llen <= rlen) {
5441 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5442 }
5443 else {
5444 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5445 }
5446 rhsn = RNODE_LIST(rhsn)->nd_next;
5447 rlen++;
5448 }
5449
5450 if (llen > rlen) {
5451 for (i=0; i<llen-rlen; i++) {
5452 ADD_INSN(ret, orig_lhsn, putnil);
5453 }
5454 }
5455
5456 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5457 return 1;
5458}
5459
5460static int
5461compile_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)
5462{
5463 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5464 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5465 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5466 const NODE *lhsn_count = lhsn;
5467 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5468
5469 int llen = 0;
5470 int lpos = 0;
5471
5472 while (lhsn_count) {
5473 llen++;
5474 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5475 }
5476 while (lhsn) {
5477 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5478 lpos++;
5479 lhsn = RNODE_LIST(lhsn)->nd_next;
5480 }
5481
5482 if (lhs_splat) {
5483 if (nd_type_p(splatn, NODE_POSTARG)) {
5484 /*a, b, *r, p1, p2 */
5485 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5486 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5487 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5488 int ppos = 0;
5489 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5490
5491 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5492
5493 if (NODE_NAMED_REST_P(restn)) {
5494 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5495 }
5496 while (postn) {
5497 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5498 ppos++;
5499 postn = RNODE_LIST(postn)->nd_next;
5500 }
5501 }
5502 else {
5503 /* a, b, *r */
5504 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5505 }
5506 }
5507
5508 if (!state->nested) {
5509 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5510 }
5511
5512 if (!popped) {
5513 ADD_INSN(rhs, node, dup);
5514 }
5515 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5516 return COMPILE_OK;
5517}
5518
5519static int
5520compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5521{
5522 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5523 struct masgn_state state;
5524 state.lhs_level = popped ? 0 : 1;
5525 state.nested = 0;
5526 state.num_args = 0;
5527 state.first_memo = NULL;
5528 state.last_memo = NULL;
5529
5530 DECL_ANCHOR(pre);
5531 INIT_ANCHOR(pre);
5532 DECL_ANCHOR(rhs);
5533 INIT_ANCHOR(rhs);
5534 DECL_ANCHOR(lhs);
5535 INIT_ANCHOR(lhs);
5536 DECL_ANCHOR(post);
5537 INIT_ANCHOR(post);
5538 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5539
5540 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5541 while (memo) {
5542 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5543 for (int i = 0; i < memo->num_args; i++) {
5544 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5545 }
5546 tmp_memo = memo->next;
5547 free(memo);
5548 memo = tmp_memo;
5549 }
5550 CHECK(ok);
5551
5552 ADD_SEQ(ret, pre);
5553 ADD_SEQ(ret, rhs);
5554 ADD_SEQ(ret, lhs);
5555 if (!popped && state.num_args >= 1) {
5556 /* make sure rhs array is returned before popping */
5557 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5558 }
5559 ADD_SEQ(ret, post);
5560 }
5561 return COMPILE_OK;
5562}
5563
5564static VALUE
5565collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5566{
5567 VALUE arr = rb_ary_new();
5568 for (;;) {
5569 switch (nd_type(node)) {
5570 case NODE_CONST:
5571 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5572 return arr;
5573 case NODE_COLON3:
5574 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5575 rb_ary_unshift(arr, ID2SYM(idNULL));
5576 return arr;
5577 case NODE_COLON2:
5578 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5579 node = RNODE_COLON2(node)->nd_head;
5580 break;
5581 default:
5582 return Qfalse;
5583 }
5584 }
5585}
5586
5587static int
5588compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5589 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5590{
5591 switch (nd_type(node)) {
5592 case NODE_CONST:
5593 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5594 ADD_INSN1(body, node, putobject, Qtrue);
5595 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5596 break;
5597 case NODE_COLON3:
5598 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5599 ADD_INSN(body, node, pop);
5600 ADD_INSN1(body, node, putobject, rb_cObject);
5601 ADD_INSN1(body, node, putobject, Qtrue);
5602 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5603 break;
5604 case NODE_COLON2:
5605 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5606 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5607 ADD_INSN1(body, node, putobject, Qfalse);
5608 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5609 break;
5610 default:
5611 CHECK(COMPILE(pref, "const colon2 prefix", node));
5612 break;
5613 }
5614 return COMPILE_OK;
5615}
5616
5617static int
5618compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5619{
5620 if (nd_type_p(cpath, NODE_COLON3)) {
5621 /* toplevel class ::Foo */
5622 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5623 return VM_DEFINECLASS_FLAG_SCOPED;
5624 }
5625 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5626 /* Bar::Foo */
5627 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5628 return VM_DEFINECLASS_FLAG_SCOPED;
5629 }
5630 else {
5631 /* class at cbase Foo */
5632 ADD_INSN1(ret, cpath, putspecialobject,
5633 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5634 return 0;
5635 }
5636}
5637
5638static inline int
5639private_recv_p(const NODE *node)
5640{
5641 NODE *recv = get_nd_recv(node);
5642 if (recv && nd_type_p(recv, NODE_SELF)) {
5643 return RNODE_SELF(recv)->nd_state != 0;
5644 }
5645 return 0;
5646}
5647
5648static void
5649defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5650 const NODE *const node, LABEL **lfinish, VALUE needstr);
5651
5652static int
5653compile_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);
5654
5655static void
5656defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5657 const NODE *const node, LABEL **lfinish, VALUE needstr,
5658 bool keep_result)
5659{
5660 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5661 enum node_type type;
5662 const int line = nd_line(node);
5663 const NODE *line_node = node;
5664
5665 switch (type = nd_type(node)) {
5666
5667 /* easy literals */
5668 case NODE_NIL:
5669 expr_type = DEFINED_NIL;
5670 break;
5671 case NODE_SELF:
5672 expr_type = DEFINED_SELF;
5673 break;
5674 case NODE_TRUE:
5675 expr_type = DEFINED_TRUE;
5676 break;
5677 case NODE_FALSE:
5678 expr_type = DEFINED_FALSE;
5679 break;
5680
5681 case NODE_LIST:{
5682 const NODE *vals = node;
5683
5684 do {
5685 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
5686
5687 if (!lfinish[1]) {
5688 lfinish[1] = NEW_LABEL(line);
5689 }
5690 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5691 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
5692 }
5693 /* fall through */
5694 case NODE_STR:
5695 case NODE_LIT:
5696 case NODE_ZLIST:
5697 case NODE_AND:
5698 case NODE_OR:
5699 default:
5700 expr_type = DEFINED_EXPR;
5701 break;
5702
5703 /* variables */
5704 case NODE_LVAR:
5705 case NODE_DVAR:
5706 expr_type = DEFINED_LVAR;
5707 break;
5708
5709#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5710 case NODE_IVAR:
5711 ADD_INSN3(ret, line_node, definedivar,
5712 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
5713 return;
5714
5715 case NODE_GVAR:
5716 ADD_INSN(ret, line_node, putnil);
5717 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
5718 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
5719 return;
5720
5721 case NODE_CVAR:
5722 ADD_INSN(ret, line_node, putnil);
5723 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
5724 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
5725 return;
5726
5727 case NODE_CONST:
5728 ADD_INSN(ret, line_node, putnil);
5729 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
5730 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
5731 return;
5732 case NODE_COLON2:
5733 if (!lfinish[1]) {
5734 lfinish[1] = NEW_LABEL(line);
5735 }
5736 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
5737 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5738 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
5739
5740 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
5741 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
5742 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
5743 }
5744 else {
5745 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5746 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
5747 }
5748 return;
5749 case NODE_COLON3:
5750 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5751 ADD_INSN3(ret, line_node, defined,
5752 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
5753 return;
5754
5755 /* method dispatch */
5756 case NODE_CALL:
5757 case NODE_OPCALL:
5758 case NODE_VCALL:
5759 case NODE_FCALL:
5760 case NODE_ATTRASGN:{
5761 const int explicit_receiver =
5762 (type == NODE_CALL || type == NODE_OPCALL ||
5763 (type == NODE_ATTRASGN && !private_recv_p(node)));
5764
5765 if (get_nd_args(node) || explicit_receiver) {
5766 if (!lfinish[1]) {
5767 lfinish[1] = NEW_LABEL(line);
5768 }
5769 if (!lfinish[2]) {
5770 lfinish[2] = NEW_LABEL(line);
5771 }
5772 }
5773 if (get_nd_args(node)) {
5774 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
5775 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5776 }
5777 if (explicit_receiver) {
5778 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
5779 switch (nd_type(get_nd_recv(node))) {
5780 case NODE_CALL:
5781 case NODE_OPCALL:
5782 case NODE_VCALL:
5783 case NODE_FCALL:
5784 case NODE_ATTRASGN:
5785 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5786 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
5787 break;
5788 default:
5789 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5790 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
5791 break;
5792 }
5793 if (keep_result) {
5794 ADD_INSN(ret, line_node, dup);
5795 }
5796 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5797 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
5798 }
5799 else {
5800 ADD_INSN(ret, line_node, putself);
5801 if (keep_result) {
5802 ADD_INSN(ret, line_node, dup);
5803 }
5804 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
5805 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
5806 }
5807 return;
5808 }
5809
5810 case NODE_YIELD:
5811 ADD_INSN(ret, line_node, putnil);
5812 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
5813 PUSH_VAL(DEFINED_YIELD));
5814 return;
5815
5816 case NODE_BACK_REF:
5817 case NODE_NTH_REF:
5818 ADD_INSN(ret, line_node, putnil);
5819 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
5820 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
5821 PUSH_VAL(DEFINED_GVAR));
5822 return;
5823
5824 case NODE_SUPER:
5825 case NODE_ZSUPER:
5826 ADD_INSN(ret, line_node, putnil);
5827 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
5828 PUSH_VAL(DEFINED_ZSUPER));
5829 return;
5830
5831#undef PUSH_VAL
5832 case NODE_OP_ASGN1:
5833 case NODE_OP_ASGN2:
5834 case NODE_OP_ASGN_OR:
5835 case NODE_OP_ASGN_AND:
5836 case NODE_MASGN:
5837 case NODE_LASGN:
5838 case NODE_DASGN:
5839 case NODE_GASGN:
5840 case NODE_IASGN:
5841 case NODE_CDECL:
5842 case NODE_CVASGN:
5843 expr_type = DEFINED_ASGN;
5844 break;
5845 }
5846
5847 assert(expr_type != DEFINED_NOT_DEFINED);
5848
5849 if (needstr != Qfalse) {
5850 VALUE str = rb_iseq_defined_string(expr_type);
5851 ADD_INSN1(ret, line_node, putobject, str);
5852 }
5853 else {
5854 ADD_INSN1(ret, line_node, putobject, Qtrue);
5855 }
5856}
5857
5858static void
5859build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5860{
5861 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5862 ADD_INSN(ret, &dummy_line_node, putnil);
5863 iseq_set_exception_local_table(iseq);
5864}
5865
5866static void
5867defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5868 const NODE *const node, LABEL **lfinish, VALUE needstr)
5869{
5870 LINK_ELEMENT *lcur = ret->last;
5871 defined_expr0(iseq, ret, node, lfinish, needstr, false);
5872 if (lfinish[1]) {
5873 int line = nd_line(node);
5874 LABEL *lstart = NEW_LABEL(line);
5875 LABEL *lend = NEW_LABEL(line);
5876 const rb_iseq_t *rescue;
5878 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5879 rescue = new_child_iseq_with_callback(iseq, ifunc,
5880 rb_str_concat(rb_str_new2("defined guard in "),
5881 ISEQ_BODY(iseq)->location.label),
5882 iseq, ISEQ_TYPE_RESCUE, 0);
5883 lstart->rescued = LABEL_RESCUE_BEG;
5884 lend->rescued = LABEL_RESCUE_END;
5885 APPEND_LABEL(ret, lcur, lstart);
5886 ADD_LABEL(ret, lend);
5887 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5888 }
5889}
5890
5891static int
5892compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5893{
5894 const int line = nd_line(node);
5895 const NODE *line_node = node;
5896 if (!RNODE_DEFINED(node)->nd_head) {
5897 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5898 ADD_INSN1(ret, line_node, putobject, str);
5899 }
5900 else {
5901 LABEL *lfinish[3];
5902 LINK_ELEMENT *last = ret->last;
5903 lfinish[0] = NEW_LABEL(line);
5904 lfinish[1] = 0;
5905 lfinish[2] = 0;
5906 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr);
5907 if (lfinish[1]) {
5908 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5909 ADD_INSN(ret, line_node, swap);
5910 if (lfinish[2]) {
5911 ADD_LABEL(ret, lfinish[2]);
5912 }
5913 ADD_INSN(ret, line_node, pop);
5914 ADD_LABEL(ret, lfinish[1]);
5915 }
5916 ADD_LABEL(ret, lfinish[0]);
5917 }
5918 return COMPILE_OK;
5919}
5920
5921static VALUE
5922make_name_for_block(const rb_iseq_t *orig_iseq)
5923{
5924 int level = 1;
5925 const rb_iseq_t *iseq = orig_iseq;
5926
5927 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
5928 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
5929 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
5930 level++;
5931 }
5932 iseq = ISEQ_BODY(iseq)->parent_iseq;
5933 }
5934 }
5935
5936 if (level == 1) {
5937 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
5938 }
5939 else {
5940 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
5941 }
5942}
5943
5944static void
5945push_ensure_entry(rb_iseq_t *iseq,
5947 struct ensure_range *er, const void *const node)
5948{
5949 enl->ensure_node = node;
5950 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5951 enl->erange = er;
5952 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5953}
5954
5955static void
5956add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5957 LABEL *lstart, LABEL *lend)
5958{
5959 struct ensure_range *ne =
5960 compile_data_alloc(iseq, sizeof(struct ensure_range));
5961
5962 while (erange->next != 0) {
5963 erange = erange->next;
5964 }
5965 ne->next = 0;
5966 ne->begin = lend;
5967 ne->end = erange->end;
5968 erange->end = lstart;
5969
5970 erange->next = ne;
5971}
5972
5973static bool
5974can_add_ensure_iseq(const rb_iseq_t *iseq)
5975{
5977 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5978 while (e) {
5979 if (e->ensure_node) return false;
5980 e = e->prev;
5981 }
5982 }
5983 return true;
5984}
5985
5986static void
5987add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5988{
5989 assert(can_add_ensure_iseq(iseq));
5990
5992 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5993 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5994 DECL_ANCHOR(ensure);
5995
5996 INIT_ANCHOR(ensure);
5997 while (enlp) {
5998 if (enlp->erange != NULL) {
5999 DECL_ANCHOR(ensure_part);
6000 LABEL *lstart = NEW_LABEL(0);
6001 LABEL *lend = NEW_LABEL(0);
6002 INIT_ANCHOR(ensure_part);
6003
6004 add_ensure_range(iseq, enlp->erange, lstart, lend);
6005
6006 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6007 ADD_LABEL(ensure_part, lstart);
6008 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6009 ADD_LABEL(ensure_part, lend);
6010 ADD_SEQ(ensure, ensure_part);
6011 }
6012 else {
6013 if (!is_return) {
6014 break;
6015 }
6016 }
6017 enlp = enlp->prev;
6018 }
6019 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6020 ADD_SEQ(ret, ensure);
6021}
6022
6023#if RUBY_DEBUG
6024static int
6025check_keyword(const NODE *node)
6026{
6027 /* This check is essentially a code clone of compile_keyword_arg. */
6028
6029 if (nd_type_p(node, NODE_LIST)) {
6030 while (RNODE_LIST(node)->nd_next) {
6031 node = RNODE_LIST(node)->nd_next;
6032 }
6033 node = RNODE_LIST(node)->nd_head;
6034 }
6035
6036 return keyword_node_p(node);
6037}
6038#endif
6039
6040static bool
6041keyword_node_single_splat_p(NODE *kwnode)
6042{
6043 RUBY_ASSERT(keyword_node_p(kwnode));
6044
6045 NODE *node = RNODE_HASH(kwnode)->nd_head;
6046 return RNODE_LIST(node)->nd_head == NULL &&
6047 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6048}
6049
6050static int
6051setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6052 int dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6053{
6054 if (!argn) return 0;
6055
6056 NODE *kwnode = NULL;
6057
6058 switch (nd_type(argn)) {
6059 case NODE_LIST: {
6060 // f(x, y, z)
6061 int len = compile_args(iseq, args, argn, &kwnode);
6062 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6063
6064 if (kwnode) {
6065 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6066 len -= 1;
6067 }
6068 else {
6069 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6070 }
6071 }
6072
6073 return len;
6074 }
6075 case NODE_SPLAT: {
6076 // f(*a)
6077 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6078 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
6079 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6080 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6081 return 1;
6082 }
6083 case NODE_ARGSCAT: {
6084 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6085 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, 1, NULL, NULL);
6086
6087 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6088 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6089 if (kwnode) rest_len--;
6090 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6091 }
6092 else {
6093 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6094 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6095 }
6096
6097 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6098 ADD_INSN1(args, argn, splatarray, Qtrue);
6099 argc += 1;
6100 }
6101 else {
6102 ADD_INSN1(args, argn, splatarray, Qfalse);
6103 ADD_INSN(args, argn, concatarray);
6104 }
6105
6106 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6107 if (kwnode) {
6108 // kwsplat
6109 *flag_ptr |= VM_CALL_KW_SPLAT;
6110 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6111 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6112 argc += 1;
6113 }
6114
6115 return argc;
6116 }
6117 case NODE_ARGSPUSH: {
6118 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6119 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, 1, NULL, NULL);
6120
6121 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6122 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6123 if (kwnode) rest_len--;
6124 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6125 ADD_INSN1(args, argn, newarray, INT2FIX(1));
6126 ADD_INSN(args, argn, concatarray);
6127 }
6128 else {
6129 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6130 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6131 }
6132 else {
6133 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6134 ADD_INSN1(args, argn, newarray, INT2FIX(1));
6135 ADD_INSN(args, argn, concatarray);
6136 }
6137 }
6138
6139 if (kwnode) {
6140 // f(*a, k:1)
6141 *flag_ptr |= VM_CALL_KW_SPLAT;
6142 if (!keyword_node_single_splat_p(kwnode)) {
6143 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6144 }
6145 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6146 argc += 1;
6147 }
6148
6149 return argc;
6150 }
6151 default: {
6152 UNKNOWN_NODE("setup_arg", argn, Qnil);
6153 }
6154 }
6155}
6156
6157static VALUE
6158setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6159 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6160{
6161 VALUE ret;
6162 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6163 unsigned int dup_rest = 1;
6164 DECL_ANCHOR(arg_block);
6165 INIT_ANCHOR(arg_block);
6166 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6167
6168 *flag |= VM_CALL_ARGS_BLOCKARG;
6169
6170 if (LIST_INSN_SIZE_ONE(arg_block)) {
6171 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6172 if (IS_INSN(elem)) {
6173 INSN *iobj = (INSN *)elem;
6174 if (iobj->insn_id == BIN(getblockparam)) {
6175 iobj->insn_id = BIN(getblockparamproxy);
6176 }
6177 dup_rest = 0;
6178 }
6179 }
6180 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, dup_rest, flag, keywords));
6181 ADD_SEQ(args, arg_block);
6182 }
6183 else {
6184 ret = INT2FIX(setup_args_core(iseq, args, argn, 0, flag, keywords));
6185 }
6186 return ret;
6187}
6188
6189static void
6190build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6191{
6192 const NODE *body = ptr;
6193 int line = nd_line(body);
6194 VALUE argc = INT2FIX(0);
6195 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6196
6197 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6198 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6199 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6200 iseq_set_local_table(iseq, 0);
6201}
6202
6203static void
6204compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6205{
6206 const NODE *vars;
6207 LINK_ELEMENT *last;
6208 int line = nd_line(node);
6209 const NODE *line_node = node;
6210 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6211
6212#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6213 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6214#else
6215 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6216#endif
6217 ADD_INSN(ret, line_node, dup);
6218 ADD_INSNL(ret, line_node, branchunless, fail_label);
6219
6220 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6221 INSN *cap;
6222 if (RNODE_BLOCK(vars)->nd_next) {
6223 ADD_INSN(ret, line_node, dup);
6224 }
6225 last = ret->last;
6226 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6227 last = last->next; /* putobject :var */
6228 cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
6229 NULL, INT2FIX(0), NULL);
6230 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6231#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6232 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6233 /* only one name */
6234 DECL_ANCHOR(nom);
6235
6236 INIT_ANCHOR(nom);
6237 ADD_INSNL(nom, line_node, jump, end_label);
6238 ADD_LABEL(nom, fail_label);
6239# if 0 /* $~ must be MatchData or nil */
6240 ADD_INSN(nom, line_node, pop);
6241 ADD_INSN(nom, line_node, putnil);
6242# endif
6243 ADD_LABEL(nom, end_label);
6244 (nom->last->next = cap->link.next)->prev = nom->last;
6245 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6246 return;
6247 }
6248#endif
6249 }
6250 ADD_INSNL(ret, line_node, jump, end_label);
6251 ADD_LABEL(ret, fail_label);
6252 ADD_INSN(ret, line_node, pop);
6253 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6254 last = ret->last;
6255 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6256 last = last->next; /* putobject :var */
6257 ((INSN*)last)->insn_id = BIN(putnil);
6258 ((INSN*)last)->operand_size = 0;
6259 }
6260 ADD_LABEL(ret, end_label);
6261}
6262
6263static int
6264optimizable_range_item_p(const NODE *n)
6265{
6266 if (!n) return FALSE;
6267 switch (nd_type(n)) {
6268 case NODE_LIT:
6269 return RB_INTEGER_TYPE_P(RNODE_LIT(n)->nd_lit);
6270 case NODE_NIL:
6271 return TRUE;
6272 default:
6273 return FALSE;
6274 }
6275}
6276
6277static int
6278compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6279{
6280 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6281 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6282
6283 const int line = nd_line(node);
6284 const NODE *line_node = node;
6285 DECL_ANCHOR(cond_seq);
6286 LABEL *then_label, *else_label, *end_label;
6287 VALUE branches = Qfalse;
6288
6289 INIT_ANCHOR(cond_seq);
6290 then_label = NEW_LABEL(line);
6291 else_label = NEW_LABEL(line);
6292 end_label = 0;
6293
6294 compile_branch_condition(iseq, cond_seq, RNODE_IF(node)->nd_cond, then_label, else_label);
6295 ADD_SEQ(ret, cond_seq);
6296
6297 if (then_label->refcnt && else_label->refcnt) {
6298 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
6299 }
6300
6301 if (then_label->refcnt) {
6302 ADD_LABEL(ret, then_label);
6303
6304 DECL_ANCHOR(then_seq);
6305 INIT_ANCHOR(then_seq);
6306 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6307
6308 if (else_label->refcnt) {
6309 add_trace_branch_coverage(
6310 iseq,
6311 ret,
6312 node_body ? node_body : node,
6313 0,
6314 type == NODE_IF ? "then" : "else",
6315 branches);
6316 end_label = NEW_LABEL(line);
6317 ADD_INSNL(then_seq, line_node, jump, end_label);
6318 if (!popped) {
6319 ADD_INSN(then_seq, line_node, pop);
6320 }
6321 }
6322 ADD_SEQ(ret, then_seq);
6323 }
6324
6325 if (else_label->refcnt) {
6326 ADD_LABEL(ret, else_label);
6327
6328 DECL_ANCHOR(else_seq);
6329 INIT_ANCHOR(else_seq);
6330 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6331
6332 if (then_label->refcnt) {
6333 add_trace_branch_coverage(
6334 iseq,
6335 ret,
6336 node_else ? node_else : node,
6337 1,
6338 type == NODE_IF ? "else" : "then",
6339 branches);
6340 }
6341 ADD_SEQ(ret, else_seq);
6342 }
6343
6344 if (end_label) {
6345 ADD_LABEL(ret, end_label);
6346 }
6347
6348 return COMPILE_OK;
6349}
6350
6351static int
6352compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6353{
6354 const NODE *vals;
6355 const NODE *node = orig_node;
6356 LABEL *endlabel, *elselabel;
6357 DECL_ANCHOR(head);
6358 DECL_ANCHOR(body_seq);
6359 DECL_ANCHOR(cond_seq);
6360 int only_special_literals = 1;
6361 VALUE literals = rb_hash_new();
6362 int line;
6363 enum node_type type;
6364 const NODE *line_node;
6365 VALUE branches = Qfalse;
6366 int branch_id = 0;
6367
6368 INIT_ANCHOR(head);
6369 INIT_ANCHOR(body_seq);
6370 INIT_ANCHOR(cond_seq);
6371
6372 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6373
6374 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6375
6376 branches = decl_branch_base(iseq, node, "case");
6377
6378 node = RNODE_CASE(node)->nd_body;
6379 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6380 type = nd_type(node);
6381 line = nd_line(node);
6382 line_node = node;
6383
6384 endlabel = NEW_LABEL(line);
6385 elselabel = NEW_LABEL(line);
6386
6387 ADD_SEQ(ret, head); /* case VAL */
6388
6389 while (type == NODE_WHEN) {
6390 LABEL *l1;
6391
6392 l1 = NEW_LABEL(line);
6393 ADD_LABEL(body_seq, l1);
6394 ADD_INSN(body_seq, line_node, pop);
6395 add_trace_branch_coverage(
6396 iseq,
6397 body_seq,
6398 RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
6399 branch_id++,
6400 "when",
6401 branches);
6402 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6403 ADD_INSNL(body_seq, line_node, jump, endlabel);
6404
6405 vals = RNODE_WHEN(node)->nd_head;
6406 if (vals) {
6407 switch (nd_type(vals)) {
6408 case NODE_LIST:
6409 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6410 if (only_special_literals < 0) return COMPILE_NG;
6411 break;
6412 case NODE_SPLAT:
6413 case NODE_ARGSCAT:
6414 case NODE_ARGSPUSH:
6415 only_special_literals = 0;
6416 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6417 break;
6418 default:
6419 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6420 }
6421 }
6422 else {
6423 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6424 }
6425
6426 node = RNODE_WHEN(node)->nd_next;
6427 if (!node) {
6428 break;
6429 }
6430 type = nd_type(node);
6431 line = nd_line(node);
6432 line_node = node;
6433 }
6434 /* else */
6435 if (node) {
6436 ADD_LABEL(cond_seq, elselabel);
6437 ADD_INSN(cond_seq, line_node, pop);
6438 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6439 CHECK(COMPILE_(cond_seq, "else", node, popped));
6440 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6441 }
6442 else {
6443 debugs("== else (implicit)\n");
6444 ADD_LABEL(cond_seq, elselabel);
6445 ADD_INSN(cond_seq, orig_node, pop);
6446 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6447 if (!popped) {
6448 ADD_INSN(cond_seq, orig_node, putnil);
6449 }
6450 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6451 }
6452
6453 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6454 ADD_INSN(ret, orig_node, dup);
6455 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6456 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6457 LABEL_REF(elselabel);
6458 }
6459
6460 ADD_SEQ(ret, cond_seq);
6461 ADD_SEQ(ret, body_seq);
6462 ADD_LABEL(ret, endlabel);
6463 return COMPILE_OK;
6464}
6465
6466static int
6467compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6468{
6469 const NODE *vals;
6470 const NODE *val;
6471 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6472 LABEL *endlabel;
6473 DECL_ANCHOR(body_seq);
6474 VALUE branches = Qfalse;
6475 int branch_id = 0;
6476
6477 branches = decl_branch_base(iseq, orig_node, "case");
6478
6479 INIT_ANCHOR(body_seq);
6480 endlabel = NEW_LABEL(nd_line(node));
6481
6482 while (node && nd_type_p(node, NODE_WHEN)) {
6483 const int line = nd_line(node);
6484 LABEL *l1 = NEW_LABEL(line);
6485 ADD_LABEL(body_seq, l1);
6486 add_trace_branch_coverage(
6487 iseq,
6488 body_seq,
6489 RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
6490 branch_id++,
6491 "when",
6492 branches);
6493 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
6494 ADD_INSNL(body_seq, node, jump, endlabel);
6495
6496 vals = RNODE_WHEN(node)->nd_head;
6497 if (!vals) {
6498 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
6499 }
6500 switch (nd_type(vals)) {
6501 case NODE_LIST:
6502 while (vals) {
6503 LABEL *lnext;
6504 val = RNODE_LIST(vals)->nd_head;
6505 lnext = NEW_LABEL(nd_line(val));
6506 debug_compile("== when2\n", (void)0);
6507 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
6508 ADD_LABEL(ret, lnext);
6509 vals = RNODE_LIST(vals)->nd_next;
6510 }
6511 break;
6512 case NODE_SPLAT:
6513 case NODE_ARGSCAT:
6514 case NODE_ARGSPUSH:
6515 ADD_INSN(ret, vals, putnil);
6516 CHECK(COMPILE(ret, "when2/cond splat", vals));
6517 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
6518 ADD_INSNL(ret, vals, branchif, l1);
6519 break;
6520 default:
6521 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
6522 }
6523 node = RNODE_WHEN(node)->nd_next;
6524 }
6525 /* else */
6526 add_trace_branch_coverage(
6527 iseq,
6528 ret,
6529 node ? node : orig_node,
6530 branch_id,
6531 "else",
6532 branches);
6533 CHECK(COMPILE_(ret, "else", node, popped));
6534 ADD_INSNL(ret, orig_node, jump, endlabel);
6535
6536 ADD_SEQ(ret, body_seq);
6537 ADD_LABEL(ret, endlabel);
6538 return COMPILE_OK;
6539}
6540
6541static 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);
6542
6543static 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);
6544static 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);
6545static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
6546static 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);
6547static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
6548
6549#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6550#define CASE3_BI_OFFSET_ERROR_STRING 1
6551#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6552#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6553#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6554
6555static int
6556iseq_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)
6557{
6558 const int line = nd_line(node);
6559 const NODE *line_node = node;
6560
6561 switch (nd_type(node)) {
6562 case NODE_ARYPTN: {
6563 /*
6564 * if pattern.use_rest_num?
6565 * rest_num = 0
6566 * end
6567 * if pattern.has_constant_node?
6568 * unless pattern.constant === obj
6569 * goto match_failed
6570 * end
6571 * end
6572 * unless obj.respond_to?(:deconstruct)
6573 * goto match_failed
6574 * end
6575 * d = obj.deconstruct
6576 * unless Array === d
6577 * goto type_error
6578 * end
6579 * min_argc = pattern.pre_args_num + pattern.post_args_num
6580 * if pattern.has_rest_arg?
6581 * unless d.length >= min_argc
6582 * goto match_failed
6583 * end
6584 * else
6585 * unless d.length == min_argc
6586 * goto match_failed
6587 * end
6588 * end
6589 * pattern.pre_args_num.each do |i|
6590 * unless pattern.pre_args[i].match?(d[i])
6591 * goto match_failed
6592 * end
6593 * end
6594 * if pattern.use_rest_num?
6595 * rest_num = d.length - min_argc
6596 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6597 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6598 * goto match_failed
6599 * end
6600 * end
6601 * end
6602 * pattern.post_args_num.each do |i|
6603 * j = pattern.pre_args_num + i
6604 * j += rest_num
6605 * unless pattern.post_args[i].match?(d[j])
6606 * goto match_failed
6607 * end
6608 * end
6609 * goto matched
6610 * type_error:
6611 * FrozenCore.raise TypeError
6612 * match_failed:
6613 * goto unmatched
6614 */
6615 const NODE *args = RNODE_ARYPTN(node)->pre_args;
6616 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
6617 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
6618
6619 const int min_argc = pre_args_num + post_args_num;
6620 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
6621 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
6622
6623 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6624 int i;
6625 match_failed = NEW_LABEL(line);
6626 type_error = NEW_LABEL(line);
6627 deconstruct = NEW_LABEL(line);
6628 deconstructed = NEW_LABEL(line);
6629
6630 if (use_rest_num) {
6631 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
6632 ADD_INSN(ret, line_node, swap);
6633 if (base_index) {
6634 base_index++;
6635 }
6636 }
6637
6638 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6639
6640 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6641
6642 ADD_INSN(ret, line_node, dup);
6643 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6644 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6645 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
6646 if (in_single_pattern) {
6647 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6648 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6649 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6650 INT2FIX(min_argc), base_index + 1 /* (1) */));
6651 }
6652 ADD_INSNL(ret, line_node, branchunless, match_failed);
6653
6654 for (i = 0; i < pre_args_num; i++) {
6655 ADD_INSN(ret, line_node, dup);
6656 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
6657 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
6658 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));
6659 args = RNODE_LIST(args)->nd_next;
6660 }
6661
6662 if (RNODE_ARYPTN(node)->rest_arg) {
6663 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
6664 ADD_INSN(ret, line_node, dup);
6665 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
6666 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6667 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6668 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6669 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6670 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
6671 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
6672
6673 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));
6674 }
6675 else {
6676 if (post_args_num > 0) {
6677 ADD_INSN(ret, line_node, dup);
6678 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6679 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6680 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6681 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
6682 ADD_INSN(ret, line_node, pop);
6683 }
6684 }
6685 }
6686
6687 args = RNODE_ARYPTN(node)->post_args;
6688 for (i = 0; i < post_args_num; i++) {
6689 ADD_INSN(ret, line_node, dup);
6690
6691 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
6692 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6693 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6694
6695 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
6696 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));
6697 args = RNODE_LIST(args)->nd_next;
6698 }
6699
6700 ADD_INSN(ret, line_node, pop);
6701 if (use_rest_num) {
6702 ADD_INSN(ret, line_node, pop);
6703 }
6704 ADD_INSNL(ret, line_node, jump, matched);
6705 ADD_INSN(ret, line_node, putnil);
6706 if (use_rest_num) {
6707 ADD_INSN(ret, line_node, putnil);
6708 }
6709
6710 ADD_LABEL(ret, type_error);
6711 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6712 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6713 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6714 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6715 ADD_INSN(ret, line_node, pop);
6716
6717 ADD_LABEL(ret, match_failed);
6718 ADD_INSN(ret, line_node, pop);
6719 if (use_rest_num) {
6720 ADD_INSN(ret, line_node, pop);
6721 }
6722 ADD_INSNL(ret, line_node, jump, unmatched);
6723
6724 break;
6725 }
6726 case NODE_FNDPTN: {
6727 /*
6728 * if pattern.has_constant_node?
6729 * unless pattern.constant === obj
6730 * goto match_failed
6731 * end
6732 * end
6733 * unless obj.respond_to?(:deconstruct)
6734 * goto match_failed
6735 * end
6736 * d = obj.deconstruct
6737 * unless Array === d
6738 * goto type_error
6739 * end
6740 * unless d.length >= pattern.args_num
6741 * goto match_failed
6742 * end
6743 *
6744 * begin
6745 * len = d.length
6746 * limit = d.length - pattern.args_num
6747 * i = 0
6748 * while i <= limit
6749 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6750 * if pattern.has_pre_rest_arg_id
6751 * unless pattern.pre_rest_arg.match?(d[0, i])
6752 * goto find_failed
6753 * end
6754 * end
6755 * if pattern.has_post_rest_arg_id
6756 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6757 * goto find_failed
6758 * end
6759 * end
6760 * goto find_succeeded
6761 * end
6762 * i+=1
6763 * end
6764 * find_failed:
6765 * goto match_failed
6766 * find_succeeded:
6767 * end
6768 *
6769 * goto matched
6770 * type_error:
6771 * FrozenCore.raise TypeError
6772 * match_failed:
6773 * goto unmatched
6774 */
6775 const NODE *args = RNODE_FNDPTN(node)->args;
6776 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
6777
6778 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6779 match_failed = NEW_LABEL(line);
6780 type_error = NEW_LABEL(line);
6781 deconstruct = NEW_LABEL(line);
6782 deconstructed = NEW_LABEL(line);
6783
6784 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6785
6786 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6787
6788 ADD_INSN(ret, line_node, dup);
6789 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6790 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6791 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
6792 if (in_single_pattern) {
6793 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) */));
6794 }
6795 ADD_INSNL(ret, line_node, branchunless, match_failed);
6796
6797 {
6798 LABEL *while_begin = NEW_LABEL(nd_line(node));
6799 LABEL *next_loop = NEW_LABEL(nd_line(node));
6800 LABEL *find_succeeded = NEW_LABEL(line);
6801 LABEL *find_failed = NEW_LABEL(nd_line(node));
6802 int j;
6803
6804 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
6805 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
6806
6807 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
6808 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6809 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
6810
6811 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
6812
6813 ADD_LABEL(ret, while_begin);
6814
6815 ADD_INSN(ret, line_node, dup);
6816 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6817 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
6818 ADD_INSNL(ret, line_node, branchunless, find_failed);
6819
6820 for (j = 0; j < args_num; j++) {
6821 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6822 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6823 if (j != 0) {
6824 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
6825 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6826 }
6827 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
6828
6829 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));
6830 args = RNODE_LIST(args)->nd_next;
6831 }
6832
6833 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
6834 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6835 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
6836 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6837 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
6838 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));
6839 }
6840 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
6841 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6842 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6843 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6844 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6845 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6846 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
6847 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));
6848 }
6849 ADD_INSNL(ret, line_node, jump, find_succeeded);
6850
6851 ADD_LABEL(ret, next_loop);
6852 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
6853 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6854 ADD_INSNL(ret, line_node, jump, while_begin);
6855
6856 ADD_LABEL(ret, find_failed);
6857 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6858 if (in_single_pattern) {
6859 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6860 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
6861 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6862 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
6863 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
6864
6865 ADD_INSN1(ret, line_node, putobject, Qfalse);
6866 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
6867
6868 ADD_INSN(ret, line_node, pop);
6869 ADD_INSN(ret, line_node, pop);
6870 }
6871 ADD_INSNL(ret, line_node, jump, match_failed);
6872 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
6873
6874 ADD_LABEL(ret, find_succeeded);
6875 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6876 }
6877
6878 ADD_INSN(ret, line_node, pop);
6879 ADD_INSNL(ret, line_node, jump, matched);
6880 ADD_INSN(ret, line_node, putnil);
6881
6882 ADD_LABEL(ret, type_error);
6883 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6884 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6885 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6886 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6887 ADD_INSN(ret, line_node, pop);
6888
6889 ADD_LABEL(ret, match_failed);
6890 ADD_INSN(ret, line_node, pop);
6891 ADD_INSNL(ret, line_node, jump, unmatched);
6892
6893 break;
6894 }
6895 case NODE_HSHPTN: {
6896 /*
6897 * keys = nil
6898 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6899 * keys = pattern.kw_args_node.keys
6900 * end
6901 * if pattern.has_constant_node?
6902 * unless pattern.constant === obj
6903 * goto match_failed
6904 * end
6905 * end
6906 * unless obj.respond_to?(:deconstruct_keys)
6907 * goto match_failed
6908 * end
6909 * d = obj.deconstruct_keys(keys)
6910 * unless Hash === d
6911 * goto type_error
6912 * end
6913 * if pattern.has_kw_rest_arg_node?
6914 * d = d.dup
6915 * end
6916 * if pattern.has_kw_args_node?
6917 * pattern.kw_args_node.each |k,|
6918 * unless d.key?(k)
6919 * goto match_failed
6920 * end
6921 * end
6922 * pattern.kw_args_node.each |k, pat|
6923 * if pattern.has_kw_rest_arg_node?
6924 * unless pat.match?(d.delete(k))
6925 * goto match_failed
6926 * end
6927 * else
6928 * unless pat.match?(d[k])
6929 * goto match_failed
6930 * end
6931 * end
6932 * end
6933 * else
6934 * unless d.empty?
6935 * goto match_failed
6936 * end
6937 * end
6938 * if pattern.has_kw_rest_arg_node?
6939 * if pattern.no_rest_keyword?
6940 * unless d.empty?
6941 * goto match_failed
6942 * end
6943 * else
6944 * unless pattern.kw_rest_arg_node.match?(d)
6945 * goto match_failed
6946 * end
6947 * end
6948 * end
6949 * goto matched
6950 * type_error:
6951 * FrozenCore.raise TypeError
6952 * match_failed:
6953 * goto unmatched
6954 */
6955 LABEL *match_failed, *type_error;
6956 VALUE keys = Qnil;
6957
6958 match_failed = NEW_LABEL(line);
6959 type_error = NEW_LABEL(line);
6960
6961 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
6962 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
6963 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
6964 while (kw_args) {
6965 rb_ary_push(keys, RNODE_LIT(RNODE_LIST(kw_args)->nd_head)->nd_lit);
6966 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
6967 }
6968 }
6969
6970 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6971
6972 ADD_INSN(ret, line_node, dup);
6973 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6974 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
6975 if (in_single_pattern) {
6976 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
6977 }
6978 ADD_INSNL(ret, line_node, branchunless, match_failed);
6979
6980 if (NIL_P(keys)) {
6981 ADD_INSN(ret, line_node, putnil);
6982 }
6983 else {
6984 ADD_INSN1(ret, line_node, duparray, keys);
6985 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6986 }
6987 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
6988
6989 ADD_INSN(ret, line_node, dup);
6990 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
6991 ADD_INSNL(ret, line_node, branchunless, type_error);
6992
6993 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
6994 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
6995 }
6996
6997 if (RNODE_HSHPTN(node)->nd_pkwargs) {
6998 int i;
6999 int keys_num;
7000 const NODE *args;
7001 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7002 if (args) {
7003 DECL_ANCHOR(match_values);
7004 INIT_ANCHOR(match_values);
7005 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7006 for (i = 0; i < keys_num; i++) {
7007 NODE *key_node = RNODE_LIST(args)->nd_head;
7008 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7009 VALUE key;
7010
7011 if (!nd_type_p(key_node, NODE_LIT)) {
7012 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
7013 }
7014 key = RNODE_LIT(key_node)->nd_lit;
7015
7016 ADD_INSN(ret, line_node, dup);
7017 ADD_INSN1(ret, line_node, putobject, key);
7018 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7019 if (in_single_pattern) {
7020 LABEL *match_succeeded;
7021 match_succeeded = NEW_LABEL(line);
7022
7023 ADD_INSN(ret, line_node, dup);
7024 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7025
7026 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7027 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7028 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7029 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7030 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7031 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7032 ADD_INSN1(ret, line_node, putobject, key); // (7)
7033 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7034
7035 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7036
7037 ADD_LABEL(ret, match_succeeded);
7038 }
7039 ADD_INSNL(ret, line_node, branchunless, match_failed);
7040
7041 ADD_INSN(match_values, line_node, dup);
7042 ADD_INSN1(match_values, line_node, putobject, key);
7043 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7044 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7045 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7046 }
7047 ADD_SEQ(ret, match_values);
7048 }
7049 }
7050 else {
7051 ADD_INSN(ret, line_node, dup);
7052 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7053 if (in_single_pattern) {
7054 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7055 }
7056 ADD_INSNL(ret, line_node, branchunless, match_failed);
7057 }
7058
7059 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7060 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7061 ADD_INSN(ret, line_node, dup);
7062 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7063 if (in_single_pattern) {
7064 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7065 }
7066 ADD_INSNL(ret, line_node, branchunless, match_failed);
7067 }
7068 else {
7069 ADD_INSN(ret, line_node, dup); // (11)
7070 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));
7071 }
7072 }
7073
7074 ADD_INSN(ret, line_node, pop);
7075 ADD_INSNL(ret, line_node, jump, matched);
7076 ADD_INSN(ret, line_node, putnil);
7077
7078 ADD_LABEL(ret, type_error);
7079 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7080 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7081 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7082 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7083 ADD_INSN(ret, line_node, pop);
7084
7085 ADD_LABEL(ret, match_failed);
7086 ADD_INSN(ret, line_node, pop);
7087 ADD_INSNL(ret, line_node, jump, unmatched);
7088 break;
7089 }
7090 case NODE_LIT:
7091 case NODE_STR:
7092 case NODE_XSTR:
7093 case NODE_DSTR:
7094 case NODE_DSYM:
7095 case NODE_DREGX:
7096 case NODE_LIST:
7097 case NODE_ZLIST:
7098 case NODE_LAMBDA:
7099 case NODE_DOT2:
7100 case NODE_DOT3:
7101 case NODE_CONST:
7102 case NODE_LVAR:
7103 case NODE_DVAR:
7104 case NODE_IVAR:
7105 case NODE_CVAR:
7106 case NODE_GVAR:
7107 case NODE_TRUE:
7108 case NODE_FALSE:
7109 case NODE_SELF:
7110 case NODE_NIL:
7111 case NODE_COLON2:
7112 case NODE_COLON3:
7113 case NODE_BEGIN:
7114 case NODE_BLOCK:
7115 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7116 if (in_single_pattern) {
7117 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7118 }
7119 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7120 if (in_single_pattern) {
7121 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7122 }
7123 ADD_INSNL(ret, line_node, branchif, matched);
7124 ADD_INSNL(ret, line_node, jump, unmatched);
7125 break;
7126 case NODE_LASGN: {
7127 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7128 ID id = RNODE_LASGN(node)->nd_vid;
7129 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7130
7131 if (in_alt_pattern) {
7132 const char *name = rb_id2name(id);
7133 if (name && strlen(name) > 0 && name[0] != '_') {
7134 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7135 rb_id2str(id));
7136 return COMPILE_NG;
7137 }
7138 }
7139
7140 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7141 ADD_INSNL(ret, line_node, jump, matched);
7142 break;
7143 }
7144 case NODE_DASGN: {
7145 int idx, lv, ls;
7146 ID id = RNODE_DASGN(node)->nd_vid;
7147
7148 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7149
7150 if (in_alt_pattern) {
7151 const char *name = rb_id2name(id);
7152 if (name && strlen(name) > 0 && name[0] != '_') {
7153 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7154 rb_id2str(id));
7155 return COMPILE_NG;
7156 }
7157 }
7158
7159 if (idx < 0) {
7160 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7161 rb_id2str(id));
7162 return COMPILE_NG;
7163 }
7164 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7165 ADD_INSNL(ret, line_node, jump, matched);
7166 break;
7167 }
7168 case NODE_IF:
7169 case NODE_UNLESS: {
7170 LABEL *match_failed;
7171 match_failed = unmatched;
7172 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7173 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7174 if (in_single_pattern) {
7175 LABEL *match_succeeded;
7176 match_succeeded = NEW_LABEL(line);
7177
7178 ADD_INSN(ret, line_node, dup);
7179 if (nd_type_p(node, NODE_IF)) {
7180 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7181 }
7182 else {
7183 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7184 }
7185
7186 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7187 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7188 ADD_INSN1(ret, line_node, putobject, Qfalse);
7189 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7190
7191 ADD_INSN(ret, line_node, pop);
7192 ADD_INSN(ret, line_node, pop);
7193
7194 ADD_LABEL(ret, match_succeeded);
7195 }
7196 if (nd_type_p(node, NODE_IF)) {
7197 ADD_INSNL(ret, line_node, branchunless, match_failed);
7198 }
7199 else {
7200 ADD_INSNL(ret, line_node, branchif, match_failed);
7201 }
7202 ADD_INSNL(ret, line_node, jump, matched);
7203 break;
7204 }
7205 case NODE_HASH: {
7206 NODE *n;
7207 LABEL *match_failed;
7208 match_failed = NEW_LABEL(line);
7209
7210 n = RNODE_HASH(node)->nd_head;
7211 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7212 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7213 return COMPILE_NG;
7214 }
7215
7216 ADD_INSN(ret, line_node, dup); // (1)
7217 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));
7218 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));
7219 ADD_INSN(ret, line_node, putnil);
7220
7221 ADD_LABEL(ret, match_failed);
7222 ADD_INSN(ret, line_node, pop);
7223 ADD_INSNL(ret, line_node, jump, unmatched);
7224 break;
7225 }
7226 case NODE_OR: {
7227 LABEL *match_succeeded, *fin;
7228 match_succeeded = NEW_LABEL(line);
7229 fin = NEW_LABEL(line);
7230
7231 ADD_INSN(ret, line_node, dup); // (1)
7232 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));
7233 ADD_LABEL(ret, match_succeeded);
7234 ADD_INSN(ret, line_node, pop);
7235 ADD_INSNL(ret, line_node, jump, matched);
7236 ADD_INSN(ret, line_node, putnil);
7237 ADD_LABEL(ret, fin);
7238 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7239 break;
7240 }
7241 default:
7242 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7243 }
7244 return COMPILE_OK;
7245}
7246
7247static int
7248iseq_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)
7249{
7250 LABEL *fin = NEW_LABEL(nd_line(node));
7251 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7252 ADD_LABEL(ret, fin);
7253 return COMPILE_OK;
7254}
7255
7256static int
7257iseq_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)
7258{
7259 const NODE *line_node = node;
7260
7261 if (RNODE_ARYPTN(node)->nd_pconst) {
7262 ADD_INSN(ret, line_node, dup); // (1)
7263 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7264 if (in_single_pattern) {
7265 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7266 }
7267 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7268 if (in_single_pattern) {
7269 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7270 }
7271 ADD_INSNL(ret, line_node, branchunless, match_failed);
7272 }
7273 return COMPILE_OK;
7274}
7275
7276
7277static int
7278iseq_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)
7279{
7280 const NODE *line_node = node;
7281
7282 // NOTE: this optimization allows us to re-use the #deconstruct value
7283 // (or its absence).
7284 if (use_deconstructed_cache) {
7285 // If value is nil then we haven't tried to deconstruct
7286 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7287 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7288
7289 // If false then the value is not deconstructable
7290 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7291 ADD_INSNL(ret, line_node, branchunless, match_failed);
7292
7293 // Drop value, add deconstructed to the stack and jump
7294 ADD_INSN(ret, line_node, pop); // (1)
7295 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7296 ADD_INSNL(ret, line_node, jump, deconstructed);
7297 }
7298 else {
7299 ADD_INSNL(ret, line_node, jump, deconstruct);
7300 }
7301
7302 ADD_LABEL(ret, deconstruct);
7303 ADD_INSN(ret, line_node, dup);
7304 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7305 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7306
7307 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7308 if (use_deconstructed_cache) {
7309 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7310 }
7311
7312 if (in_single_pattern) {
7313 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7314 }
7315
7316 ADD_INSNL(ret, line_node, branchunless, match_failed);
7317
7318 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7319
7320 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7321 if (use_deconstructed_cache) {
7322 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7323 }
7324
7325 ADD_INSN(ret, line_node, dup);
7326 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7327 ADD_INSNL(ret, line_node, branchunless, type_error);
7328
7329 ADD_LABEL(ret, deconstructed);
7330
7331 return COMPILE_OK;
7332}
7333
7334static int
7335iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7336{
7337 /*
7338 * if match_succeeded?
7339 * goto match_succeeded
7340 * end
7341 * error_string = FrozenCore.sprintf(errmsg, matchee)
7342 * key_error_p = false
7343 * match_succeeded:
7344 */
7345 const int line = nd_line(node);
7346 const NODE *line_node = node;
7347 LABEL *match_succeeded = NEW_LABEL(line);
7348
7349 ADD_INSN(ret, line_node, dup);
7350 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7351
7352 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7353 ADD_INSN1(ret, line_node, putobject, errmsg);
7354 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7355 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7356 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7357
7358 ADD_INSN1(ret, line_node, putobject, Qfalse);
7359 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7360
7361 ADD_INSN(ret, line_node, pop);
7362 ADD_INSN(ret, line_node, pop);
7363 ADD_LABEL(ret, match_succeeded);
7364
7365 return COMPILE_OK;
7366}
7367
7368static int
7369iseq_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)
7370{
7371 /*
7372 * if match_succeeded?
7373 * goto match_succeeded
7374 * end
7375 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7376 * key_error_p = false
7377 * match_succeeded:
7378 */
7379 const int line = nd_line(node);
7380 const NODE *line_node = node;
7381 LABEL *match_succeeded = NEW_LABEL(line);
7382
7383 ADD_INSN(ret, line_node, dup);
7384 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7385
7386 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7387 ADD_INSN1(ret, line_node, putobject, errmsg);
7388 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7389 ADD_INSN(ret, line_node, dup);
7390 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7391 ADD_INSN1(ret, line_node, putobject, pattern_length);
7392 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7393 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7394
7395 ADD_INSN1(ret, line_node, putobject, Qfalse);
7396 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7397
7398 ADD_INSN(ret, line_node, pop);
7399 ADD_INSN(ret, line_node, pop);
7400 ADD_LABEL(ret, match_succeeded);
7401
7402 return COMPILE_OK;
7403}
7404
7405static int
7406iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7407{
7408 /*
7409 * if match_succeeded?
7410 * goto match_succeeded
7411 * end
7412 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7413 * key_error_p = false
7414 * match_succeeded:
7415 */
7416 const int line = nd_line(node);
7417 const NODE *line_node = node;
7418 LABEL *match_succeeded = NEW_LABEL(line);
7419
7420 ADD_INSN(ret, line_node, dup);
7421 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7422
7423 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7424 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7425 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7426 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7427 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7428 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7429
7430 ADD_INSN1(ret, line_node, putobject, Qfalse);
7431 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7432
7433 ADD_INSN(ret, line_node, pop);
7434 ADD_INSN(ret, line_node, pop);
7435
7436 ADD_LABEL(ret, match_succeeded);
7437 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7438 ADD_INSN(ret, line_node, pop);
7439 ADD_INSN(ret, line_node, pop);
7440
7441 return COMPILE_OK;
7442}
7443
7444static int
7445compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7446{
7447 const NODE *pattern;
7448 const NODE *node = orig_node;
7449 LABEL *endlabel, *elselabel;
7450 DECL_ANCHOR(head);
7451 DECL_ANCHOR(body_seq);
7452 DECL_ANCHOR(cond_seq);
7453 int line;
7454 enum node_type type;
7455 const NODE *line_node;
7456 VALUE branches = 0;
7457 int branch_id = 0;
7458 bool single_pattern;
7459
7460 INIT_ANCHOR(head);
7461 INIT_ANCHOR(body_seq);
7462 INIT_ANCHOR(cond_seq);
7463
7464 branches = decl_branch_base(iseq, node, "case");
7465
7466 node = RNODE_CASE3(node)->nd_body;
7467 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7468 type = nd_type(node);
7469 line = nd_line(node);
7470 line_node = node;
7471 single_pattern = !RNODE_IN(node)->nd_next;
7472
7473 endlabel = NEW_LABEL(line);
7474 elselabel = NEW_LABEL(line);
7475
7476 if (single_pattern) {
7477 /* allocate stack for ... */
7478 ADD_INSN(head, line_node, putnil); /* key_error_key */
7479 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7480 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7481 ADD_INSN(head, line_node, putnil); /* error_string */
7482 }
7483 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7484
7485 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
7486
7487 ADD_SEQ(ret, head); /* case VAL */
7488
7489 while (type == NODE_IN) {
7490 LABEL *l1;
7491
7492 if (branch_id) {
7493 ADD_INSN(body_seq, line_node, putnil);
7494 }
7495 l1 = NEW_LABEL(line);
7496 ADD_LABEL(body_seq, l1);
7497 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
7498 add_trace_branch_coverage(
7499 iseq,
7500 body_seq,
7501 RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node,
7502 branch_id++,
7503 "in",
7504 branches);
7505 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
7506 ADD_INSNL(body_seq, line_node, jump, endlabel);
7507
7508 pattern = RNODE_IN(node)->nd_head;
7509 if (pattern) {
7510 int pat_line = nd_line(pattern);
7511 LABEL *next_pat = NEW_LABEL(pat_line);
7512 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
7513 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7514 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
7515 ADD_LABEL(cond_seq, next_pat);
7516 LABEL_UNREMOVABLE(next_pat);
7517 }
7518 else {
7519 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7520 return COMPILE_NG;
7521 }
7522
7523 node = RNODE_IN(node)->nd_next;
7524 if (!node) {
7525 break;
7526 }
7527 type = nd_type(node);
7528 line = nd_line(node);
7529 line_node = node;
7530 }
7531 /* else */
7532 if (node) {
7533 ADD_LABEL(cond_seq, elselabel);
7534 ADD_INSN(cond_seq, line_node, pop);
7535 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
7536 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
7537 CHECK(COMPILE_(cond_seq, "else", node, popped));
7538 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7539 ADD_INSN(cond_seq, line_node, putnil);
7540 if (popped) {
7541 ADD_INSN(cond_seq, line_node, putnil);
7542 }
7543 }
7544 else {
7545 debugs("== else (implicit)\n");
7546 ADD_LABEL(cond_seq, elselabel);
7547 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
7548 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7549
7550 if (single_pattern) {
7551 /*
7552 * if key_error_p
7553 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7554 * else
7555 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7556 * end
7557 */
7558 LABEL *key_error, *fin;
7559 struct rb_callinfo_kwarg *kw_arg;
7560
7561 key_error = NEW_LABEL(line);
7562 fin = NEW_LABEL(line);
7563
7564 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
7565 kw_arg->references = 0;
7566 kw_arg->keyword_len = 2;
7567 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
7568 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
7569
7570 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7571 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7572 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7573 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7574 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7575 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7576 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7577 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7578 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7579 ADD_INSNL(cond_seq, orig_node, jump, fin);
7580
7581 ADD_LABEL(cond_seq, key_error);
7582 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7583 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7584 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7585 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7586 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7587 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7588 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7589 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7590 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
7591 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
7592
7593 ADD_LABEL(cond_seq, fin);
7594 }
7595 else {
7596 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7597 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
7598 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7599 }
7600 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
7601 if (!popped) {
7602 ADD_INSN(cond_seq, orig_node, putnil);
7603 }
7604 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7605 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
7606 if (popped) {
7607 ADD_INSN(cond_seq, line_node, putnil);
7608 }
7609 }
7610
7611 ADD_SEQ(ret, cond_seq);
7612 ADD_SEQ(ret, body_seq);
7613 ADD_LABEL(ret, endlabel);
7614 return COMPILE_OK;
7615}
7616
7617#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7618#undef CASE3_BI_OFFSET_ERROR_STRING
7619#undef CASE3_BI_OFFSET_KEY_ERROR_P
7620#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7621#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7622
7623static int
7624compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7625{
7626 const int line = (int)nd_line(node);
7627 const NODE *line_node = node;
7628
7629 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7630 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7631 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7632 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7633 VALUE branches = Qfalse;
7634
7636
7637 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
7638 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
7639 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
7640 LABEL *end_label = NEW_LABEL(line);
7641 LABEL *adjust_label = NEW_LABEL(line);
7642
7643 LABEL *next_catch_label = NEW_LABEL(line);
7644 LABEL *tmp_label = NULL;
7645
7646 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7647 push_ensure_entry(iseq, &enl, NULL, NULL);
7648
7649 if (RNODE_WHILE(node)->nd_state == 1) {
7650 ADD_INSNL(ret, line_node, jump, next_label);
7651 }
7652 else {
7653 tmp_label = NEW_LABEL(line);
7654 ADD_INSNL(ret, line_node, jump, tmp_label);
7655 }
7656 ADD_LABEL(ret, adjust_label);
7657 ADD_INSN(ret, line_node, putnil);
7658 ADD_LABEL(ret, next_catch_label);
7659 ADD_INSN(ret, line_node, pop);
7660 ADD_INSNL(ret, line_node, jump, next_label);
7661 if (tmp_label) ADD_LABEL(ret, tmp_label);
7662
7663 ADD_LABEL(ret, redo_label);
7664 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
7665 add_trace_branch_coverage(
7666 iseq,
7667 ret,
7668 RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node,
7669 0,
7670 "body",
7671 branches);
7672 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
7673 ADD_LABEL(ret, next_label); /* next */
7674
7675 if (type == NODE_WHILE) {
7676 compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
7677 redo_label, end_label);
7678 }
7679 else {
7680 /* until */
7681 compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
7682 end_label, redo_label);
7683 }
7684
7685 ADD_LABEL(ret, end_label);
7686 ADD_ADJUST_RESTORE(ret, adjust_label);
7687
7688 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
7689 /* ADD_INSN(ret, line_node, putundef); */
7690 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
7691 return COMPILE_NG;
7692 }
7693 else {
7694 ADD_INSN(ret, line_node, putnil);
7695 }
7696
7697 ADD_LABEL(ret, break_label); /* break */
7698
7699 if (popped) {
7700 ADD_INSN(ret, line_node, pop);
7701 }
7702
7703 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7704 break_label);
7705 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7706 next_catch_label);
7707 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7708 ISEQ_COMPILE_DATA(iseq)->redo_label);
7709
7710 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7711 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7712 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7713 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7714 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7715 return COMPILE_OK;
7716}
7717
7718static int
7719compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7720{
7721 const int line = nd_line(node);
7722 const NODE *line_node = node;
7723 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7724 LABEL *retry_label = NEW_LABEL(line);
7725 LABEL *retry_end_l = NEW_LABEL(line);
7726 const rb_iseq_t *child_iseq;
7727
7728 ADD_LABEL(ret, retry_label);
7729 if (nd_type_p(node, NODE_FOR)) {
7730 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
7731
7732 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7733 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
7734 ISEQ_TYPE_BLOCK, line);
7735 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
7736 }
7737 else {
7738 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7739 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
7740 ISEQ_TYPE_BLOCK, line);
7741 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
7742 }
7743
7744 {
7745 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7746 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7747 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7748 //
7749 // Normally, "send" instruction is at the last.
7750 // However, qcall under branch coverage measurement adds some instructions after the "send".
7751 //
7752 // Note that "invokesuper" appears instead of "send".
7753 INSN *iobj;
7754 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
7755 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
7756 while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
7757 iobj = (INSN*) get_prev_insn(iobj);
7758 }
7759 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
7760
7761 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7762 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7763 if (&iobj->link == LAST_ELEMENT(ret)) {
7764 ret->last = (LINK_ELEMENT*) retry_end_l;
7765 }
7766 }
7767
7768 if (popped) {
7769 ADD_INSN(ret, line_node, pop);
7770 }
7771
7772 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7773
7774 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7775 return COMPILE_OK;
7776}
7777
7778static int
7779compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7780{
7781 /* massign to var in "for"
7782 * (args.length == 1 && Array.try_convert(args[0])) || args
7783 */
7784 const NODE *line_node = node;
7785 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
7786 LABEL *not_single = NEW_LABEL(nd_line(var));
7787 LABEL *not_ary = NEW_LABEL(nd_line(var));
7788 CHECK(COMPILE(ret, "for var", var));
7789 ADD_INSN(ret, line_node, dup);
7790 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
7791 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7792 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
7793 ADD_INSNL(ret, line_node, branchunless, not_single);
7794 ADD_INSN(ret, line_node, dup);
7795 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7796 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
7797 ADD_INSN1(ret, line_node, putobject, rb_cArray);
7798 ADD_INSN(ret, line_node, swap);
7799 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
7800 ADD_INSN(ret, line_node, dup);
7801 ADD_INSNL(ret, line_node, branchunless, not_ary);
7802 ADD_INSN(ret, line_node, swap);
7803 ADD_LABEL(ret, not_ary);
7804 ADD_INSN(ret, line_node, pop);
7805 ADD_LABEL(ret, not_single);
7806 return COMPILE_OK;
7807}
7808
7809static int
7810compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7811{
7812 const NODE *line_node = node;
7813 unsigned long throw_flag = 0;
7814
7815 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7816 /* while/until */
7817 LABEL *splabel = NEW_LABEL(0);
7818 ADD_LABEL(ret, splabel);
7819 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7820 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
7821 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7822 add_ensure_iseq(ret, iseq, 0);
7823 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7824 ADD_ADJUST_RESTORE(ret, splabel);
7825
7826 if (!popped) {
7827 ADD_INSN(ret, line_node, putnil);
7828 }
7829 }
7830 else {
7831 const rb_iseq_t *ip = iseq;
7832
7833 while (ip) {
7834 if (!ISEQ_COMPILE_DATA(ip)) {
7835 ip = 0;
7836 break;
7837 }
7838
7839 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7840 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7841 }
7842 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7843 throw_flag = 0;
7844 }
7845 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7846 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
7847 return COMPILE_NG;
7848 }
7849 else {
7850 ip = ISEQ_BODY(ip)->parent_iseq;
7851 continue;
7852 }
7853
7854 /* escape from block */
7855 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
7856 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
7857 if (popped) {
7858 ADD_INSN(ret, line_node, pop);
7859 }
7860 return COMPILE_OK;
7861 }
7862 COMPILE_ERROR(ERROR_ARGS "Invalid break");
7863 return COMPILE_NG;
7864 }
7865 return COMPILE_OK;
7866}
7867
7868static int
7869compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7870{
7871 const NODE *line_node = node;
7872 unsigned long throw_flag = 0;
7873
7874 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7875 LABEL *splabel = NEW_LABEL(0);
7876 debugs("next in while loop\n");
7877 ADD_LABEL(ret, splabel);
7878 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
7879 add_ensure_iseq(ret, iseq, 0);
7880 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7881 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7882 ADD_ADJUST_RESTORE(ret, splabel);
7883 if (!popped) {
7884 ADD_INSN(ret, line_node, putnil);
7885 }
7886 }
7887 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7888 LABEL *splabel = NEW_LABEL(0);
7889 debugs("next in block\n");
7890 ADD_LABEL(ret, splabel);
7891 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7892 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
7893 add_ensure_iseq(ret, iseq, 0);
7894 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7895 ADD_ADJUST_RESTORE(ret, splabel);
7896 splabel->unremovable = FALSE;
7897
7898 if (!popped) {
7899 ADD_INSN(ret, line_node, putnil);
7900 }
7901 }
7902 else {
7903 const rb_iseq_t *ip = iseq;
7904
7905 while (ip) {
7906 if (!ISEQ_COMPILE_DATA(ip)) {
7907 ip = 0;
7908 break;
7909 }
7910
7911 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7912 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7913 /* while loop */
7914 break;
7915 }
7916 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7917 break;
7918 }
7919 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7920 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
7921 return COMPILE_NG;
7922 }
7923
7924 ip = ISEQ_BODY(ip)->parent_iseq;
7925 }
7926 if (ip != 0) {
7927 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
7928 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
7929
7930 if (popped) {
7931 ADD_INSN(ret, line_node, pop);
7932 }
7933 }
7934 else {
7935 COMPILE_ERROR(ERROR_ARGS "Invalid next");
7936 return COMPILE_NG;
7937 }
7938 }
7939 return COMPILE_OK;
7940}
7941
7942static int
7943compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7944{
7945 const NODE *line_node = node;
7946
7947 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7948 LABEL *splabel = NEW_LABEL(0);
7949 debugs("redo in while");
7950 ADD_LABEL(ret, splabel);
7951 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7952 add_ensure_iseq(ret, iseq, 0);
7953 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7954 ADD_ADJUST_RESTORE(ret, splabel);
7955 if (!popped) {
7956 ADD_INSN(ret, line_node, putnil);
7957 }
7958 }
7959 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7960 LABEL *splabel = NEW_LABEL(0);
7961
7962 debugs("redo in block");
7963 ADD_LABEL(ret, splabel);
7964 add_ensure_iseq(ret, iseq, 0);
7965 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7966 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7967 ADD_ADJUST_RESTORE(ret, splabel);
7968
7969 if (!popped) {
7970 ADD_INSN(ret, line_node, putnil);
7971 }
7972 }
7973 else {
7974 const rb_iseq_t *ip = iseq;
7975
7976 while (ip) {
7977 if (!ISEQ_COMPILE_DATA(ip)) {
7978 ip = 0;
7979 break;
7980 }
7981
7982 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7983 break;
7984 }
7985 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7986 break;
7987 }
7988 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7989 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
7990 return COMPILE_NG;
7991 }
7992
7993 ip = ISEQ_BODY(ip)->parent_iseq;
7994 }
7995 if (ip != 0) {
7996 ADD_INSN(ret, line_node, putnil);
7997 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7998
7999 if (popped) {
8000 ADD_INSN(ret, line_node, pop);
8001 }
8002 }
8003 else {
8004 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8005 return COMPILE_NG;
8006 }
8007 }
8008 return COMPILE_OK;
8009}
8010
8011static int
8012compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8013{
8014 const NODE *line_node = node;
8015
8016 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8017 ADD_INSN(ret, line_node, putnil);
8018 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8019
8020 if (popped) {
8021 ADD_INSN(ret, line_node, pop);
8022 }
8023 }
8024 else {
8025 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8026 return COMPILE_NG;
8027 }
8028 return COMPILE_OK;
8029}
8030
8031static int
8032compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8033{
8034 const int line = nd_line(node);
8035 const NODE *line_node = node;
8036 LABEL *lstart = NEW_LABEL(line);
8037 LABEL *lend = NEW_LABEL(line);
8038 LABEL *lcont = NEW_LABEL(line);
8039 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8040 rb_str_concat(rb_str_new2("rescue in "),
8041 ISEQ_BODY(iseq)->location.label),
8042 ISEQ_TYPE_RESCUE, line);
8043
8044 lstart->rescued = LABEL_RESCUE_BEG;
8045 lend->rescued = LABEL_RESCUE_END;
8046 ADD_LABEL(ret, lstart);
8047
8048 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8049 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8050 {
8051 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8052 }
8053 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8054
8055 ADD_LABEL(ret, lend);
8056 if (RNODE_RESCUE(node)->nd_else) {
8057 ADD_INSN(ret, line_node, pop);
8058 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8059 }
8060 ADD_INSN(ret, line_node, nop);
8061 ADD_LABEL(ret, lcont);
8062
8063 if (popped) {
8064 ADD_INSN(ret, line_node, pop);
8065 }
8066
8067 /* register catch entry */
8068 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8069 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8070 return COMPILE_OK;
8071}
8072
8073static int
8074compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8075{
8076 const int line = nd_line(node);
8077 const NODE *line_node = node;
8078 const NODE *resq = node;
8079 const NODE *narg;
8080 LABEL *label_miss, *label_hit;
8081
8082 while (resq) {
8083 label_miss = NEW_LABEL(line);
8084 label_hit = NEW_LABEL(line);
8085
8086 narg = RNODE_RESBODY(resq)->nd_args;
8087 if (narg) {
8088 switch (nd_type(narg)) {
8089 case NODE_LIST:
8090 while (narg) {
8091 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8092 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8093 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8094 ADD_INSNL(ret, line_node, branchif, label_hit);
8095 narg = RNODE_LIST(narg)->nd_next;
8096 }
8097 break;
8098 case NODE_SPLAT:
8099 case NODE_ARGSCAT:
8100 case NODE_ARGSPUSH:
8101 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8102 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8103 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8104 ADD_INSNL(ret, line_node, branchif, label_hit);
8105 break;
8106 default:
8107 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8108 }
8109 }
8110 else {
8111 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8112 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8113 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8114 ADD_INSNL(ret, line_node, branchif, label_hit);
8115 }
8116 ADD_INSNL(ret, line_node, jump, label_miss);
8117 ADD_LABEL(ret, label_hit);
8118 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8119
8120 if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL) {
8121 // empty body
8122 int lineno = nd_line(RNODE_RESBODY(resq)->nd_body);
8123 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
8124 ADD_INSN(ret, &dummy_line_node, putnil);
8125 }
8126 else {
8127 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8128 }
8129
8130 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8131 ADD_INSN(ret, line_node, nop);
8132 }
8133 ADD_INSN(ret, line_node, leave);
8134 ADD_LABEL(ret, label_miss);
8135 resq = RNODE_RESBODY(resq)->nd_head;
8136 }
8137 return COMPILE_OK;
8138}
8139
8140static int
8141compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8142{
8143 const int line = nd_line(node);
8144 const NODE *line_node = node;
8145 DECL_ANCHOR(ensr);
8146 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8147 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8148 ISEQ_TYPE_ENSURE, line);
8149 LABEL *lstart = NEW_LABEL(line);
8150 LABEL *lend = NEW_LABEL(line);
8151 LABEL *lcont = NEW_LABEL(line);
8152 LINK_ELEMENT *last;
8153 int last_leave = 0;
8154 struct ensure_range er;
8156 struct ensure_range *erange;
8157
8158 INIT_ANCHOR(ensr);
8159 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8160 last = ensr->last;
8161 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8162
8163 er.begin = lstart;
8164 er.end = lend;
8165 er.next = 0;
8166 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8167
8168 ADD_LABEL(ret, lstart);
8169 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8170 ADD_LABEL(ret, lend);
8171 ADD_SEQ(ret, ensr);
8172 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8173 ADD_LABEL(ret, lcont);
8174 if (last_leave) ADD_INSN(ret, line_node, pop);
8175
8176 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8177 if (lstart->link.next != &lend->link) {
8178 while (erange) {
8179 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8180 ensure, lcont);
8181 erange = erange->next;
8182 }
8183 }
8184
8185 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8186 return COMPILE_OK;
8187}
8188
8189static int
8190compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8191{
8192 const NODE *line_node = node;
8193
8194 if (iseq) {
8195 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8196 const rb_iseq_t *is = iseq;
8197 enum rb_iseq_type t = type;
8198 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8199 LABEL *splabel = 0;
8200
8201 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8202 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8203 t = ISEQ_BODY(is)->type;
8204 }
8205 switch (t) {
8206 case ISEQ_TYPE_TOP:
8207 case ISEQ_TYPE_MAIN:
8208 if (retval) {
8209 rb_warn("argument of top-level return is ignored");
8210 }
8211 if (is == iseq) {
8212 /* plain top-level, leave directly */
8213 type = ISEQ_TYPE_METHOD;
8214 }
8215 break;
8216 default:
8217 break;
8218 }
8219
8220 if (type == ISEQ_TYPE_METHOD) {
8221 splabel = NEW_LABEL(0);
8222 ADD_LABEL(ret, splabel);
8223 ADD_ADJUST(ret, line_node, 0);
8224 }
8225
8226 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8227
8228 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8229 add_ensure_iseq(ret, iseq, 1);
8230 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8231 ADD_INSN(ret, line_node, leave);
8232 ADD_ADJUST_RESTORE(ret, splabel);
8233
8234 if (!popped) {
8235 ADD_INSN(ret, line_node, putnil);
8236 }
8237 }
8238 else {
8239 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8240 if (popped) {
8241 ADD_INSN(ret, line_node, pop);
8242 }
8243 }
8244 }
8245 return COMPILE_OK;
8246}
8247
8248static int
8249compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8250{
8251 CHECK(COMPILE_(ret, "nd_body", node, popped));
8252
8253 if (!popped && !all_string_result_p(node)) {
8254 const NODE *line_node = node;
8255 const unsigned int flag = VM_CALL_FCALL;
8256
8257 // Note, this dup could be removed if we are willing to change anytostring. It pops
8258 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8259 ADD_INSN(ret, line_node, dup);
8260 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8261 ADD_INSN(ret, line_node, anytostring);
8262 }
8263 return COMPILE_OK;
8264}
8265
8266static void
8267compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8268{
8269 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8270
8271 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8272 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8273}
8274
8275static LABEL *
8276qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8277{
8278 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8279 VALUE br = 0;
8280
8281 br = decl_branch_base(iseq, node, "&.");
8282 *branches = br;
8283 ADD_INSN(recv, line_node, dup);
8284 ADD_INSNL(recv, line_node, branchnil, else_label);
8285 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
8286 return else_label;
8287}
8288
8289static void
8290qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8291{
8292 LABEL *end_label;
8293 if (!else_label) return;
8294 end_label = NEW_LABEL(nd_line(line_node));
8295 ADD_INSNL(ret, line_node, jump, end_label);
8296 ADD_LABEL(ret, else_label);
8297 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
8298 ADD_LABEL(ret, end_label);
8299}
8300
8301static int
8302compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8303{
8304 /* optimization shortcut
8305 * "literal".freeze -> opt_str_freeze("literal")
8306 */
8307 if (get_nd_recv(node) && nd_type_p(get_nd_recv(node), NODE_STR) &&
8308 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8309 get_nd_args(node) == NULL &&
8310 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8311 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8312 VALUE str = rb_fstring(RNODE_STR(get_nd_recv(node))->nd_lit);
8313 if (get_node_call_nd_mid(node) == idUMinus) {
8314 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8315 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8316 }
8317 else {
8318 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8319 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8320 }
8321 RB_OBJ_WRITTEN(iseq, Qundef, str);
8322 if (popped) {
8323 ADD_INSN(ret, line_node, pop);
8324 }
8325 return TRUE;
8326 }
8327 /* optimization shortcut
8328 * obj["literal"] -> opt_aref_with(obj, "literal")
8329 */
8330 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8331 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8332 nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) &&
8333 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8334 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8335 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8336 VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(get_nd_args(node))->nd_head)->nd_lit);
8337 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8338 ADD_INSN2(ret, line_node, opt_aref_with, str,
8339 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8340 RB_OBJ_WRITTEN(iseq, Qundef, str);
8341 if (popped) {
8342 ADD_INSN(ret, line_node, pop);
8343 }
8344 return TRUE;
8345 }
8346 return FALSE;
8347}
8348
8349static int
8350iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8351{
8352 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8353}
8354
8355static const struct rb_builtin_function *
8356iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8357{
8358 int i;
8359 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8360 for (i=0; table[i].index != -1; i++) {
8361 if (strcmp(table[i].name, name) == 0) {
8362 return &table[i];
8363 }
8364 }
8365 return NULL;
8366}
8367
8368static const char *
8369iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8370{
8371 const char *name = rb_id2name(mid);
8372 static const char prefix[] = "__builtin_";
8373 const size_t prefix_len = sizeof(prefix) - 1;
8374
8375 switch (type) {
8376 case NODE_CALL:
8377 if (recv) {
8378 switch (nd_type(recv)) {
8379 case NODE_VCALL:
8380 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8381 return name;
8382 }
8383 break;
8384 case NODE_CONST:
8385 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8386 return name;
8387 }
8388 break;
8389 default: break;
8390 }
8391 }
8392 break;
8393 case NODE_VCALL:
8394 case NODE_FCALL:
8395 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8396 return &name[prefix_len];
8397 }
8398 break;
8399 default: break;
8400 }
8401 return NULL;
8402}
8403
8404static int
8405delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8406{
8407
8408 if (argc == 0) {
8409 *pstart_index = 0;
8410 return TRUE;
8411 }
8412 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8413 unsigned int start=0;
8414
8415 // local_table: [p1, p2, p3, l1, l2, l3]
8416 // arguments: [p3, l1, l2] -> 2
8417 for (start = 0;
8418 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8419 start++) {
8420 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8421
8422 for (unsigned int i=start; i-start<argc; i++) {
8423 if (IS_INSN(elem) &&
8424 INSN_OF(elem) == BIN(getlocal)) {
8425 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8426 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8427
8428 if (local_level == 0) {
8429 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8430 if (0) { // for debug
8431 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8432 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8433 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8434 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8435 }
8436 if (i == index) {
8437 elem = elem->next;
8438 continue; /* for */
8439 }
8440 else {
8441 goto next;
8442 }
8443 }
8444 else {
8445 goto fail; // level != 0 is unsupported
8446 }
8447 }
8448 else {
8449 goto fail; // insn is not a getlocal
8450 }
8451 }
8452 goto success;
8453 next:;
8454 }
8455 fail:
8456 return FALSE;
8457 success:
8458 *pstart_index = start;
8459 return TRUE;
8460 }
8461 else {
8462 return FALSE;
8463 }
8464}
8465
8466// Compile Primitive.attr! :leaf, ...
8467static int
8468compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
8469{
8470 VALUE symbol;
8471 VALUE string;
8472 if (!node) goto no_arg;
8473 while (node) {
8474 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8475 const NODE *next = RNODE_LIST(node)->nd_next;
8476
8477 node = RNODE_LIST(node)->nd_head;
8478 if (!node) goto no_arg;
8479 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8480
8481 symbol = RNODE_LIT(node)->nd_lit;
8482 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
8483
8484 string = rb_sym_to_s(symbol);
8485 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
8486 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
8487 }
8488 else if (strcmp(RSTRING_PTR(string), "no_gc") == 0) {
8489 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_NO_GC;
8490 }
8491 else {
8492 goto unknown_arg;
8493 }
8494 node = next;
8495 }
8496 return COMPILE_OK;
8497 no_arg:
8498 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
8499 return COMPILE_NG;
8500 non_symbol_arg:
8501 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
8502 return COMPILE_NG;
8503 unknown_arg:
8504 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
8505 return COMPILE_NG;
8506 bad_arg:
8507 UNKNOWN_NODE("attr!", node, COMPILE_NG);
8508}
8509
8510static int
8511compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
8512{
8513 if (!node) goto no_arg;
8514 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8515 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
8516 node = RNODE_LIST(node)->nd_head;
8517 if (!node) goto no_arg;
8518 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8519 VALUE name = RNODE_LIT(node)->nd_lit;
8520 if (!SYMBOL_P(name)) goto non_symbol_arg;
8521 if (!popped) {
8522 compile_lvar(iseq, ret, line_node, SYM2ID(name));
8523 }
8524 return COMPILE_OK;
8525 no_arg:
8526 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
8527 return COMPILE_NG;
8528 too_many_arg:
8529 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
8530 return COMPILE_NG;
8531 non_symbol_arg:
8532 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
8533 rb_builtin_class_name(name));
8534 return COMPILE_NG;
8535 bad_arg:
8536 UNKNOWN_NODE("arg!", node, COMPILE_NG);
8537}
8538
8539static NODE *
8540mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
8541{
8542 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
8543 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
8544 return RNODE_IF(node)->nd_body;
8545 }
8546 else {
8547 rb_bug("mandatory_node: can't find mandatory node");
8548 }
8549}
8550
8551static int
8552compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
8553{
8554 // arguments
8555 struct rb_args_info args = {
8556 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
8557 };
8558 rb_node_args_t args_node;
8559 rb_node_init(RNODE(&args_node), NODE_ARGS);
8560 args_node.nd_ainfo = args;
8561
8562 // local table without non-mandatory parameters
8563 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
8564 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
8565
8566 VALUE idtmp = 0;
8567 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
8568 tbl->size = table_size;
8569
8570 int i;
8571
8572 // lead parameters
8573 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
8574 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
8575 }
8576 // local variables
8577 for (; i<table_size; i++) {
8578 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
8579 }
8580
8581 rb_node_scope_t scope_node;
8582 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
8583 scope_node.nd_tbl = tbl;
8584 scope_node.nd_body = mandatory_node(iseq, node);
8585 scope_node.nd_args = &args_node;
8586
8587 rb_ast_body_t ast = {
8588 .root = RNODE(&scope_node),
8589 .frozen_string_literal = -1,
8590 .coverage_enabled = -1,
8591 .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
8592 };
8593
8594 ISEQ_BODY(iseq)->mandatory_only_iseq =
8595 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
8596 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
8597 nd_line(line_node), NULL, 0,
8598 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
8599
8600 ALLOCV_END(idtmp);
8601 return COMPILE_OK;
8602}
8603
8604static int
8605compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
8606 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
8607{
8608 NODE *args_node = get_nd_args(node);
8609
8610 if (parent_block != NULL) {
8611 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
8612 return COMPILE_NG;
8613 }
8614 else {
8615# define BUILTIN_INLINE_PREFIX "_bi"
8616 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
8617 bool cconst = false;
8618 retry:;
8619 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
8620
8621 if (bf == NULL) {
8622 if (strcmp("cstmt!", builtin_func) == 0 ||
8623 strcmp("cexpr!", builtin_func) == 0) {
8624 // ok
8625 }
8626 else if (strcmp("cconst!", builtin_func) == 0) {
8627 cconst = true;
8628 }
8629 else if (strcmp("cinit!", builtin_func) == 0) {
8630 // ignore
8631 GET_VM()->builtin_inline_index++;
8632 return COMPILE_OK;
8633 }
8634 else if (strcmp("attr!", builtin_func) == 0) {
8635 return compile_builtin_attr(iseq, args_node);
8636 }
8637 else if (strcmp("arg!", builtin_func) == 0) {
8638 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8639 }
8640 else if (strcmp("mandatory_only?", builtin_func) == 0) {
8641 if (popped) {
8642 rb_bug("mandatory_only? should be in if condition");
8643 }
8644 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8645 rb_bug("mandatory_only? should be put on top");
8646 }
8647
8648 ADD_INSN1(ret, line_node, putobject, Qfalse);
8649 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8650 }
8651 else if (1) {
8652 rb_bug("can't find builtin function:%s", builtin_func);
8653 }
8654 else {
8655 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
8656 return COMPILE_NG;
8657 }
8658
8659 if (GET_VM()->builtin_inline_index == INT_MAX) {
8660 rb_bug("builtin inline function index overflow:%s", builtin_func);
8661 }
8662 int inline_index = GET_VM()->builtin_inline_index++;
8663 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
8664 builtin_func = inline_func;
8665 args_node = NULL;
8666 goto retry;
8667 }
8668
8669 if (cconst) {
8670 typedef VALUE(*builtin_func0)(void *, VALUE);
8671 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
8672 ADD_INSN1(ret, line_node, putobject, const_val);
8673 return COMPILE_OK;
8674 }
8675
8676 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8677
8678 unsigned int flag = 0;
8679 struct rb_callinfo_kwarg *keywords = NULL;
8680 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8681
8682 if (FIX2INT(argc) != bf->argc) {
8683 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
8684 builtin_func, bf->argc, FIX2INT(argc));
8685 return COMPILE_NG;
8686 }
8687
8688 unsigned int start_index;
8689 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
8690 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
8691 }
8692 else {
8693 ADD_SEQ(ret, args);
8694 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8695 }
8696
8697 if (popped) ADD_INSN(ret, line_node, pop);
8698 return COMPILE_OK;
8699 }
8700}
8701
8702static int
8703compile_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)
8704{
8705 /* call: obj.method(...)
8706 * fcall: func(...)
8707 * vcall: func
8708 */
8709 DECL_ANCHOR(recv);
8710 DECL_ANCHOR(args);
8711 ID mid = get_node_call_nd_mid(node);
8712 VALUE argc;
8713 unsigned int flag = 0;
8714 struct rb_callinfo_kwarg *keywords = NULL;
8715 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8716 LABEL *else_label = NULL;
8717 VALUE branches = Qfalse;
8718
8719 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8720
8721 INIT_ANCHOR(recv);
8722 INIT_ANCHOR(args);
8723#if OPT_SUPPORT_JOKE
8724 if (nd_type_p(node, NODE_VCALL)) {
8725 ID id_bitblt;
8726 ID id_answer;
8727
8728 CONST_ID(id_bitblt, "bitblt");
8729 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
8730
8731 if (mid == id_bitblt) {
8732 ADD_INSN(ret, line_node, bitblt);
8733 return COMPILE_OK;
8734 }
8735 else if (mid == id_answer) {
8736 ADD_INSN(ret, line_node, answer);
8737 return COMPILE_OK;
8738 }
8739 }
8740 /* only joke */
8741 {
8742 ID goto_id;
8743 ID label_id;
8744
8745 CONST_ID(goto_id, "__goto__");
8746 CONST_ID(label_id, "__label__");
8747
8748 if (nd_type_p(node, NODE_FCALL) &&
8749 (mid == goto_id || mid == label_id)) {
8750 LABEL *label;
8751 st_data_t data;
8752 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8753 VALUE label_name;
8754
8755 if (!labels_table) {
8756 labels_table = st_init_numtable();
8757 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8758 }
8759 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8760 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8761
8762 label_name = node->nd_args->nd_head->nd_lit;
8763 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8764 label = NEW_LABEL(nd_line(line_node));
8765 label->position = nd_line(line_node);
8766 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8767 }
8768 else {
8769 label = (LABEL *)data;
8770 }
8771 }
8772 else {
8773 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
8774 return COMPILE_NG;
8775 }
8776
8777 if (mid == goto_id) {
8778 ADD_INSNL(ret, line_node, jump, label);
8779 }
8780 else {
8781 ADD_LABEL(ret, label);
8782 }
8783 return COMPILE_OK;
8784 }
8785 }
8786#endif
8787
8788 const char *builtin_func;
8789 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8790 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
8791 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8792 }
8793
8794 /* receiver */
8795 if (!assume_receiver) {
8796 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
8797 int idx, level;
8798
8799 if (mid == idCall &&
8800 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
8801 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
8802 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
8803 }
8804 else if (private_recv_p(node)) {
8805 ADD_INSN(recv, node, putself);
8806 flag |= VM_CALL_FCALL;
8807 }
8808 else {
8809 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
8810 }
8811
8812 if (type == NODE_QCALL) {
8813 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8814 }
8815 }
8816 else if (type == NODE_FCALL || type == NODE_VCALL) {
8817 ADD_CALL_RECEIVER(recv, line_node);
8818 }
8819 }
8820
8821 /* args */
8822 if (type != NODE_VCALL) {
8823 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
8824 CHECK(!NIL_P(argc));
8825 }
8826 else {
8827 argc = INT2FIX(0);
8828 }
8829
8830 ADD_SEQ(ret, recv);
8831 ADD_SEQ(ret, args);
8832
8833 debugp_param("call args argc", argc);
8834 debugp_param("call method", ID2SYM(mid));
8835
8836 switch ((int)type) {
8837 case NODE_VCALL:
8838 flag |= VM_CALL_VCALL;
8839 /* VCALL is funcall, so fall through */
8840 case NODE_FCALL:
8841 flag |= VM_CALL_FCALL;
8842 }
8843
8844 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
8845 ADD_INSN(ret, line_node, splatkw);
8846 }
8847 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
8848
8849 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8850 if (popped) {
8851 ADD_INSN(ret, line_node, pop);
8852 }
8853 return COMPILE_OK;
8854}
8855
8856static int
8857compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8858{
8859 const int line = nd_line(node);
8860 VALUE argc;
8861 unsigned int flag = 0;
8862 int asgnflag = 0;
8863 ID id = RNODE_OP_ASGN1(node)->nd_mid;
8864 int boff = 0;
8865 int keyword_len = 0;
8866 struct rb_callinfo_kwarg *keywords = NULL;
8867
8868 /*
8869 * a[x] (op)= y
8870 *
8871 * nil # nil
8872 * eval a # nil a
8873 * eval x # nil a x
8874 * dupn 2 # nil a x a x
8875 * send :[] # nil a x a[x]
8876 * eval y # nil a x a[x] y
8877 * send op # nil a x ret
8878 * setn 3 # ret a x ret
8879 * send []= # ret ?
8880 * pop # ret
8881 */
8882
8883 /*
8884 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
8885 * NODE_OP_ASGN nd_recv
8886 * nd_args->nd_head
8887 * nd_args->nd_body
8888 * nd_mid
8889 */
8890
8891 if (!popped) {
8892 ADD_INSN(ret, node, putnil);
8893 }
8894 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
8895 CHECK(asgnflag != -1);
8896 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
8897 case NODE_ZLIST:
8898 argc = INT2FIX(0);
8899 break;
8900 case NODE_BLOCK_PASS:
8901 boff = 1;
8902 /* fall through */
8903 default:
8904 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, &keywords);
8905 if (flag & VM_CALL_KW_SPLAT) {
8906 if (boff) {
8907 ADD_INSN(ret, node, splatkw);
8908 }
8909 else {
8910 /* Make sure to_hash is only called once and not twice */
8911 ADD_INSN(ret, node, dup);
8912 ADD_INSN(ret, node, splatkw);
8913 ADD_INSN(ret, node, pop);
8914 }
8915 }
8916 CHECK(!NIL_P(argc));
8917 }
8918 int dup_argn = FIX2INT(argc) + 1 + boff;
8919 if (keywords) {
8920 keyword_len = keywords->keyword_len;
8921 dup_argn += keyword_len;
8922 }
8923 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
8924 flag |= asgnflag;
8925 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_KW_SPLAT_MUT), keywords);
8926
8927 if (id == idOROP || id == idANDOP) {
8928 /* a[x] ||= y or a[x] &&= y
8929
8930 unless/if a[x]
8931 a[x]= y
8932 else
8933 nil
8934 end
8935 */
8936 LABEL *label = NEW_LABEL(line);
8937 LABEL *lfin = NEW_LABEL(line);
8938
8939 ADD_INSN(ret, node, dup);
8940 if (id == idOROP) {
8941 ADD_INSNL(ret, node, branchif, label);
8942 }
8943 else { /* idANDOP */
8944 ADD_INSNL(ret, node, branchunless, label);
8945 }
8946 ADD_INSN(ret, node, pop);
8947
8948 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
8949 if (!popped) {
8950 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8951 }
8952 if (flag & VM_CALL_ARGS_SPLAT) {
8953 if (flag & VM_CALL_KW_SPLAT) {
8954 ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
8955 ADD_INSN(ret, node, swap);
8956 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8957 ADD_INSN(ret, node, concatarray);
8958 ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
8959 ADD_INSN(ret, node, pop);
8960 }
8961 else {
8962 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8963 if (boff > 0) {
8964 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8965 ADD_INSN(ret, node, swap);
8966 ADD_INSN(ret, node, pop);
8967 }
8968 ADD_INSN(ret, node, concatarray);
8969 if (boff > 0) {
8970 ADD_INSN1(ret, node, setn, INT2FIX(3));
8971 ADD_INSN(ret, node, pop);
8972 ADD_INSN(ret, node, pop);
8973 }
8974 }
8975 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
8976 }
8977 else if (flag & VM_CALL_KW_SPLAT) {
8978 if (boff > 0) {
8979 ADD_INSN1(ret, node, topn, INT2FIX(2));
8980 ADD_INSN(ret, node, swap);
8981 ADD_INSN1(ret, node, setn, INT2FIX(3));
8982 ADD_INSN(ret, node, pop);
8983 }
8984 ADD_INSN(ret, node, swap);
8985 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8986 }
8987 else if (keyword_len) {
8988 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
8989 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+0));
8990 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8991 }
8992 else {
8993 if (boff > 0)
8994 ADD_INSN(ret, node, swap);
8995 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8996 }
8997 ADD_INSN(ret, node, pop);
8998 ADD_INSNL(ret, node, jump, lfin);
8999 ADD_LABEL(ret, label);
9000 if (!popped) {
9001 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9002 }
9003 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9004 ADD_LABEL(ret, lfin);
9005 }
9006 else {
9007 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9008 ADD_SEND(ret, node, id, INT2FIX(1));
9009 if (!popped) {
9010 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9011 }
9012 if (flag & VM_CALL_ARGS_SPLAT) {
9013 if (flag & VM_CALL_KW_SPLAT) {
9014 ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
9015 ADD_INSN(ret, node, swap);
9016 ADD_INSN1(ret, node, newarray, INT2FIX(1));
9017 ADD_INSN(ret, node, concatarray);
9018 ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
9019 ADD_INSN(ret, node, pop);
9020 }
9021 else {
9022 ADD_INSN1(ret, node, newarray, INT2FIX(1));
9023 if (boff > 0) {
9024 ADD_INSN1(ret, node, dupn, INT2FIX(3));
9025 ADD_INSN(ret, node, swap);
9026 ADD_INSN(ret, node, pop);
9027 }
9028 ADD_INSN(ret, node, concatarray);
9029 if (boff > 0) {
9030 ADD_INSN1(ret, node, setn, INT2FIX(3));
9031 ADD_INSN(ret, node, pop);
9032 ADD_INSN(ret, node, pop);
9033 }
9034 }
9035 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
9036 }
9037 else if (flag & VM_CALL_KW_SPLAT) {
9038 if (boff > 0) {
9039 ADD_INSN1(ret, node, topn, INT2FIX(2));
9040 ADD_INSN(ret, node, swap);
9041 ADD_INSN1(ret, node, setn, INT2FIX(3));
9042 ADD_INSN(ret, node, pop);
9043 }
9044 ADD_INSN(ret, node, swap);
9045 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9046 }
9047 else if (keyword_len) {
9048 ADD_INSN(ret, node, dup);
9049 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+2));
9050 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
9051 ADD_INSN(ret, node, pop);
9052 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9053 }
9054 else {
9055 if (boff > 0)
9056 ADD_INSN(ret, node, swap);
9057 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9058 }
9059 ADD_INSN(ret, node, pop);
9060 }
9061 return COMPILE_OK;
9062}
9063
9064static int
9065compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9066{
9067 const int line = nd_line(node);
9068 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9069 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9070 int asgnflag;
9071 LABEL *lfin = NEW_LABEL(line);
9072 LABEL *lcfin = NEW_LABEL(line);
9073 LABEL *lskip = 0;
9074 /*
9075 class C; attr_accessor :c; end
9076 r = C.new
9077 r.a &&= v # asgn2
9078
9079 eval r # r
9080 dup # r r
9081 eval r.a # r o
9082
9083 # or
9084 dup # r o o
9085 if lcfin # r o
9086 pop # r
9087 eval v # r v
9088 swap # v r
9089 topn 1 # v r v
9090 send a= # v ?
9091 jump lfin # v ?
9092
9093 lcfin: # r o
9094 swap # o r
9095
9096 lfin: # o ?
9097 pop # o
9098
9099 # or (popped)
9100 if lcfin # r
9101 eval v # r v
9102 send a= # ?
9103 jump lfin # ?
9104
9105 lcfin: # r
9106
9107 lfin: # ?
9108 pop #
9109
9110 # and
9111 dup # r o o
9112 unless lcfin
9113 pop # r
9114 eval v # r v
9115 swap # v r
9116 topn 1 # v r v
9117 send a= # v ?
9118 jump lfin # v ?
9119
9120 # others
9121 eval v # r o v
9122 send ?? # r w
9123 send a= # w
9124
9125 */
9126
9127 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9128 CHECK(asgnflag != -1);
9129 if (RNODE_OP_ASGN2(node)->nd_aid) {
9130 lskip = NEW_LABEL(line);
9131 ADD_INSN(ret, node, dup);
9132 ADD_INSNL(ret, node, branchnil, lskip);
9133 }
9134 ADD_INSN(ret, node, dup);
9135 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9136
9137 if (atype == idOROP || atype == idANDOP) {
9138 if (!popped) {
9139 ADD_INSN(ret, node, dup);
9140 }
9141 if (atype == idOROP) {
9142 ADD_INSNL(ret, node, branchif, lcfin);
9143 }
9144 else { /* idANDOP */
9145 ADD_INSNL(ret, node, branchunless, lcfin);
9146 }
9147 if (!popped) {
9148 ADD_INSN(ret, node, pop);
9149 }
9150 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9151 if (!popped) {
9152 ADD_INSN(ret, node, swap);
9153 ADD_INSN1(ret, node, topn, INT2FIX(1));
9154 }
9155 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9156 ADD_INSNL(ret, node, jump, lfin);
9157
9158 ADD_LABEL(ret, lcfin);
9159 if (!popped) {
9160 ADD_INSN(ret, node, swap);
9161 }
9162
9163 ADD_LABEL(ret, lfin);
9164 }
9165 else {
9166 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9167 ADD_SEND(ret, node, atype, INT2FIX(1));
9168 if (!popped) {
9169 ADD_INSN(ret, node, swap);
9170 ADD_INSN1(ret, node, topn, INT2FIX(1));
9171 }
9172 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9173 }
9174 if (lskip && popped) {
9175 ADD_LABEL(ret, lskip);
9176 }
9177 ADD_INSN(ret, node, pop);
9178 if (lskip && !popped) {
9179 ADD_LABEL(ret, lskip);
9180 }
9181 return COMPILE_OK;
9182}
9183
9184static int
9185compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9186{
9187 const int line = nd_line(node);
9188 LABEL *lfin = 0;
9189 LABEL *lassign = 0;
9190 ID mid;
9191
9192 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9193 case NODE_COLON3:
9194 ADD_INSN1(ret, node, putobject, rb_cObject);
9195 break;
9196 case NODE_COLON2:
9197 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9198 break;
9199 default:
9200 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9201 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9202 return COMPILE_NG;
9203 }
9204 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9205 /* cref */
9206 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9207 lassign = NEW_LABEL(line);
9208 ADD_INSN(ret, node, dup); /* cref cref */
9209 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9210 ID2SYM(mid), Qtrue); /* cref bool */
9211 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9212 }
9213 ADD_INSN(ret, node, dup); /* cref cref */
9214 ADD_INSN1(ret, node, putobject, Qtrue);
9215 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9216
9217 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9218 lfin = NEW_LABEL(line);
9219 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9220 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9221 ADD_INSNL(ret, node, branchif, lfin);
9222 else /* idANDOP */
9223 ADD_INSNL(ret, node, branchunless, lfin);
9224 /* cref [obj] */
9225 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9226 if (lassign) ADD_LABEL(ret, lassign);
9227 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
9228 /* cref value */
9229 if (popped)
9230 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9231 else {
9232 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9233 ADD_INSN(ret, node, swap); /* cref value value cref */
9234 }
9235 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9236 ADD_LABEL(ret, lfin); /* cref [value] */
9237 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9238 ADD_INSN(ret, node, pop); /* [value] */
9239 }
9240 else {
9241 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
9242 /* cref obj value */
9243 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9244 /* cref value */
9245 ADD_INSN(ret, node, swap); /* value cref */
9246 if (!popped) {
9247 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9248 ADD_INSN(ret, node, swap); /* value value cref */
9249 }
9250 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9251 }
9252 return COMPILE_OK;
9253}
9254
9255static int
9256compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9257{
9258 const int line = nd_line(node);
9259 LABEL *lfin = NEW_LABEL(line);
9260 LABEL *lassign;
9261
9262 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9263 LABEL *lfinish[2];
9264 lfinish[0] = lfin;
9265 lfinish[1] = 0;
9266 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse);
9267 lassign = lfinish[1];
9268 if (!lassign) {
9269 lassign = NEW_LABEL(line);
9270 }
9271 ADD_INSNL(ret, node, branchunless, lassign);
9272 }
9273 else {
9274 lassign = NEW_LABEL(line);
9275 }
9276
9277 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9278
9279 if (!popped) {
9280 ADD_INSN(ret, node, dup);
9281 }
9282
9283 if (type == NODE_OP_ASGN_AND) {
9284 ADD_INSNL(ret, node, branchunless, lfin);
9285 }
9286 else {
9287 ADD_INSNL(ret, node, branchif, lfin);
9288 }
9289
9290 if (!popped) {
9291 ADD_INSN(ret, node, pop);
9292 }
9293
9294 ADD_LABEL(ret, lassign);
9295 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9296 ADD_LABEL(ret, lfin);
9297 return COMPILE_OK;
9298}
9299
9300static int
9301compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9302{
9303 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9304 DECL_ANCHOR(args);
9305 int argc;
9306 unsigned int flag = 0;
9307 struct rb_callinfo_kwarg *keywords = NULL;
9308 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9309
9310 INIT_ANCHOR(args);
9311 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9312 if (type == NODE_SUPER) {
9313 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9314 CHECK(!NIL_P(vargc));
9315 argc = FIX2INT(vargc);
9316 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9317 ADD_INSN(args, node, splatkw);
9318 }
9319 }
9320 else {
9321 /* NODE_ZSUPER */
9322 int i;
9323 const rb_iseq_t *liseq = body->local_iseq;
9324 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9325 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9326 int lvar_level = get_lvar_level(iseq);
9327
9328 argc = local_body->param.lead_num;
9329
9330 /* normal arguments */
9331 for (i = 0; i < local_body->param.lead_num; i++) {
9332 int idx = local_body->local_table_size - i;
9333 ADD_GETLOCAL(args, node, idx, lvar_level);
9334 }
9335
9336 if (local_body->param.flags.has_opt) {
9337 /* optional arguments */
9338 int j;
9339 for (j = 0; j < local_body->param.opt_num; j++) {
9340 int idx = local_body->local_table_size - (i + j);
9341 ADD_GETLOCAL(args, node, idx, lvar_level);
9342 }
9343 i += j;
9344 argc = i;
9345 }
9346 if (local_body->param.flags.has_rest) {
9347 /* rest argument */
9348 int idx = local_body->local_table_size - local_body->param.rest_start;
9349 ADD_GETLOCAL(args, node, idx, lvar_level);
9350 ADD_INSN1(args, node, splatarray, Qfalse);
9351
9352 argc = local_body->param.rest_start + 1;
9353 flag |= VM_CALL_ARGS_SPLAT;
9354 }
9355 if (local_body->param.flags.has_post) {
9356 /* post arguments */
9357 int post_len = local_body->param.post_num;
9358 int post_start = local_body->param.post_start;
9359
9360 if (local_body->param.flags.has_rest) {
9361 int j;
9362 for (j=0; j<post_len; j++) {
9363 int idx = local_body->local_table_size - (post_start + j);
9364 ADD_GETLOCAL(args, node, idx, lvar_level);
9365 }
9366 ADD_INSN1(args, node, newarray, INT2FIX(j));
9367 ADD_INSN (args, node, concatarray);
9368 /* argc is settled at above */
9369 }
9370 else {
9371 int j;
9372 for (j=0; j<post_len; j++) {
9373 int idx = local_body->local_table_size - (post_start + j);
9374 ADD_GETLOCAL(args, node, idx, lvar_level);
9375 }
9376 argc = post_len + post_start;
9377 }
9378 }
9379
9380 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9381 int local_size = local_body->local_table_size;
9382 argc++;
9383
9384 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9385
9386 if (local_body->param.flags.has_kwrest) {
9387 int idx = local_body->local_table_size - local_kwd->rest_start;
9388 ADD_GETLOCAL(args, node, idx, lvar_level);
9389 assert(local_kwd->num > 0);
9390 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9391 }
9392 else {
9393 ADD_INSN1(args, node, newhash, INT2FIX(0));
9394 }
9395 for (i = 0; i < local_kwd->num; ++i) {
9396 ID id = local_kwd->table[i];
9397 int idx = local_size - get_local_var_idx(liseq, id);
9398 ADD_INSN1(args, node, putobject, ID2SYM(id));
9399 ADD_GETLOCAL(args, node, idx, lvar_level);
9400 }
9401 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9402 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9403 }
9404 else if (local_body->param.flags.has_kwrest) {
9405 int idx = local_body->local_table_size - local_kwd->rest_start;
9406 ADD_GETLOCAL(args, node, idx, lvar_level);
9407 argc++;
9408 flag |= VM_CALL_KW_SPLAT;
9409 }
9410 }
9411
9412 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9413 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9414 ADD_INSN(ret, node, putself);
9415 ADD_SEQ(ret, args);
9416 ADD_INSN2(ret, node, invokesuper,
9417 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9418 parent_block);
9419
9420 if (popped) {
9421 ADD_INSN(ret, node, pop);
9422 }
9423 return COMPILE_OK;
9424}
9425
9426static int
9427compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9428{
9429 DECL_ANCHOR(args);
9430 VALUE argc;
9431 unsigned int flag = 0;
9432 struct rb_callinfo_kwarg *keywords = NULL;
9433
9434 INIT_ANCHOR(args);
9435
9436 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9437 case ISEQ_TYPE_TOP:
9438 case ISEQ_TYPE_MAIN:
9439 case ISEQ_TYPE_CLASS:
9440 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9441 return COMPILE_NG;
9442 default: /* valid */;
9443 }
9444
9445 if (RNODE_YIELD(node)->nd_head) {
9446 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9447 CHECK(!NIL_P(argc));
9448 }
9449 else {
9450 argc = INT2FIX(0);
9451 }
9452
9453 ADD_SEQ(ret, args);
9454 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9455
9456 if (popped) {
9457 ADD_INSN(ret, node, pop);
9458 }
9459
9460 int level = 0;
9461 const rb_iseq_t *tmp_iseq = iseq;
9462 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9463 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9464 }
9465 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9466
9467 return COMPILE_OK;
9468}
9469
9470static int
9471compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9472{
9473 DECL_ANCHOR(recv);
9474 DECL_ANCHOR(val);
9475
9476 INIT_ANCHOR(recv);
9477 INIT_ANCHOR(val);
9478 switch ((int)type) {
9479 case NODE_MATCH:
9480 ADD_INSN1(recv, node, putobject, RNODE_MATCH(node)->nd_lit);
9481 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9482 INT2FIX(0));
9483 break;
9484 case NODE_MATCH2:
9485 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
9486 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
9487 break;
9488 case NODE_MATCH3:
9489 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
9490 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
9491 break;
9492 }
9493
9494 ADD_SEQ(ret, recv);
9495 ADD_SEQ(ret, val);
9496 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9497
9498 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
9499 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
9500 }
9501
9502 if (popped) {
9503 ADD_INSN(ret, node, pop);
9504 }
9505 return COMPILE_OK;
9506}
9507
9508static int
9509compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9510{
9511 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
9512 /* constant */
9513 VALUE segments;
9514 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
9515 (segments = collect_const_segments(iseq, node))) {
9516 ISEQ_BODY(iseq)->ic_size++;
9517 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9518 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9519 }
9520 else {
9521 /* constant */
9522 DECL_ANCHOR(pref);
9523 DECL_ANCHOR(body);
9524
9525 INIT_ANCHOR(pref);
9526 INIT_ANCHOR(body);
9527 CHECK(compile_const_prefix(iseq, node, pref, body));
9528 if (LIST_INSN_SIZE_ZERO(pref)) {
9529 ADD_INSN(ret, node, putnil);
9530 ADD_SEQ(ret, body);
9531 }
9532 else {
9533 ADD_SEQ(ret, pref);
9534 ADD_SEQ(ret, body);
9535 }
9536 }
9537 }
9538 else {
9539 /* function call */
9540 ADD_CALL_RECEIVER(ret, node);
9541 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
9542 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
9543 }
9544 if (popped) {
9545 ADD_INSN(ret, node, pop);
9546 }
9547 return COMPILE_OK;
9548}
9549
9550static int
9551compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9552{
9553 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
9554
9555 /* add cache insn */
9556 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9557 ISEQ_BODY(iseq)->ic_size++;
9558 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
9559 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9560 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9561 }
9562 else {
9563 ADD_INSN1(ret, node, putobject, rb_cObject);
9564 ADD_INSN1(ret, node, putobject, Qtrue);
9565 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
9566 }
9567
9568 if (popped) {
9569 ADD_INSN(ret, node, pop);
9570 }
9571 return COMPILE_OK;
9572}
9573
9574static int
9575compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
9576{
9577 VALUE flag = INT2FIX(excl);
9578 const NODE *b = RNODE_DOT2(node)->nd_beg;
9579 const NODE *e = RNODE_DOT2(node)->nd_end;
9580
9581 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
9582 if (!popped) {
9583 VALUE bv = nd_type_p(b, NODE_LIT) ? RNODE_LIT(b)->nd_lit : Qnil;
9584 VALUE ev = nd_type_p(e, NODE_LIT) ? RNODE_LIT(e)->nd_lit : Qnil;
9585 VALUE val = rb_range_new(bv, ev, excl);
9586 ADD_INSN1(ret, node, putobject, val);
9587 RB_OBJ_WRITTEN(iseq, Qundef, val);
9588 }
9589 }
9590 else {
9591 CHECK(COMPILE_(ret, "min", b, popped));
9592 CHECK(COMPILE_(ret, "max", e, popped));
9593 if (!popped) {
9594 ADD_INSN1(ret, node, newrange, flag);
9595 }
9596 }
9597 return COMPILE_OK;
9598}
9599
9600static int
9601compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9602{
9603 if (!popped) {
9604 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9605 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
9606 }
9607 else {
9608 const rb_iseq_t *ip = iseq;
9609 int level = 0;
9610 while (ip) {
9611 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
9612 break;
9613 }
9614 ip = ISEQ_BODY(ip)->parent_iseq;
9615 level++;
9616 }
9617 if (ip) {
9618 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
9619 }
9620 else {
9621 ADD_INSN(ret, node, putnil);
9622 }
9623 }
9624 }
9625 return COMPILE_OK;
9626}
9627
9628static int
9629compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9630{
9631 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9632 LABEL *end_label = NEW_LABEL(nd_line(node));
9633 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
9634
9635 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
9636 /* required argument. do nothing */
9637 COMPILE_ERROR(ERROR_ARGS "unreachable");
9638 return COMPILE_NG;
9639 }
9640 else if (nd_type_p(default_value, NODE_LIT) ||
9641 nd_type_p(default_value, NODE_NIL) ||
9642 nd_type_p(default_value, NODE_TRUE) ||
9643 nd_type_p(default_value, NODE_FALSE)) {
9644 COMPILE_ERROR(ERROR_ARGS "unreachable");
9645 return COMPILE_NG;
9646 }
9647 else {
9648 /* if keywordcheck(_kw_bits, nth_keyword)
9649 * kw = default_value
9650 * end
9651 */
9652 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
9653 int keyword_idx = body->param.keyword->num;
9654
9655 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
9656 ADD_INSNL(ret, node, branchif, end_label);
9657 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
9658 ADD_LABEL(ret, end_label);
9659 }
9660 return COMPILE_OK;
9661}
9662
9663static int
9664compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9665{
9666 DECL_ANCHOR(recv);
9667 DECL_ANCHOR(args);
9668 unsigned int flag = 0;
9669 ID mid = RNODE_ATTRASGN(node)->nd_mid;
9670 VALUE argc;
9671 LABEL *else_label = NULL;
9672 VALUE branches = Qfalse;
9673
9674 /* optimization shortcut
9675 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9676 */
9677 if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
9678 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
9679 nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) &&
9680 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9681 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
9682 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
9683 {
9684 VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head)->nd_lit);
9685 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
9686 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
9687 if (!popped) {
9688 ADD_INSN(ret, node, swap);
9689 ADD_INSN1(ret, node, topn, INT2FIX(1));
9690 }
9691 ADD_INSN2(ret, node, opt_aset_with, str,
9692 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9693 RB_OBJ_WRITTEN(iseq, Qundef, str);
9694 ADD_INSN(ret, node, pop);
9695 return COMPILE_OK;
9696 }
9697
9698 INIT_ANCHOR(recv);
9699 INIT_ANCHOR(args);
9700 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
9701 CHECK(!NIL_P(argc));
9702
9703 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
9704 CHECK(asgnflag != -1);
9705 flag |= (unsigned int)asgnflag;
9706
9707 debugp_param("argc", argc);
9708 debugp_param("nd_mid", ID2SYM(mid));
9709
9710 if (!rb_is_attrset_id(mid)) {
9711 /* safe nav attr */
9712 mid = rb_id_attrset(mid);
9713 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9714 }
9715 if (!popped) {
9716 ADD_INSN(ret, node, putnil);
9717 ADD_SEQ(ret, recv);
9718 ADD_SEQ(ret, args);
9719
9720 if (flag & VM_CALL_ARGS_BLOCKARG) {
9721 ADD_INSN1(ret, node, topn, INT2FIX(1));
9722 if (flag & VM_CALL_ARGS_SPLAT) {
9723 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9724 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9725 }
9726 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9727 ADD_INSN (ret, node, pop);
9728 }
9729 else if (flag & VM_CALL_ARGS_SPLAT) {
9730 ADD_INSN(ret, node, dup);
9731 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9732 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9733 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9734 ADD_INSN (ret, node, pop);
9735 }
9736 else {
9737 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9738 }
9739 }
9740 else {
9741 ADD_SEQ(ret, recv);
9742 ADD_SEQ(ret, args);
9743 }
9744 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
9745 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9746 ADD_INSN(ret, node, pop);
9747 return COMPILE_OK;
9748}
9749
9750static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
9758static int
9759iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
9760{
9761 if (node == 0) {
9762 if (!popped) {
9763 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9764 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
9765 debugs("node: NODE_NIL(implicit)\n");
9766 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9767 ADD_INSN(ret, &dummy_line_node, putnil);
9768 }
9769 return COMPILE_OK;
9770 }
9771 return iseq_compile_each0(iseq, ret, node, popped);
9772}
9773
9774static int
9775iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9776{
9777 const int line = (int)nd_line(node);
9778 const enum node_type type = nd_type(node);
9779 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9780
9781 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9782 /* ignore */
9783 }
9784 else {
9785 if (nd_fl_newline(node)) {
9786 int event = RUBY_EVENT_LINE;
9787 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9788 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9789 event |= RUBY_EVENT_COVERAGE_LINE;
9790 }
9791 ADD_TRACE(ret, event);
9792 }
9793 }
9794
9795 debug_node_start(node);
9796#undef BEFORE_RETURN
9797#define BEFORE_RETURN debug_node_end()
9798
9799 switch (type) {
9800 case NODE_BLOCK:
9801 CHECK(compile_block(iseq, ret, node, popped));
9802 break;
9803 case NODE_IF:
9804 case NODE_UNLESS:
9805 CHECK(compile_if(iseq, ret, node, popped, type));
9806 break;
9807 case NODE_CASE:
9808 CHECK(compile_case(iseq, ret, node, popped));
9809 break;
9810 case NODE_CASE2:
9811 CHECK(compile_case2(iseq, ret, node, popped));
9812 break;
9813 case NODE_CASE3:
9814 CHECK(compile_case3(iseq, ret, node, popped));
9815 break;
9816 case NODE_WHILE:
9817 case NODE_UNTIL:
9818 CHECK(compile_loop(iseq, ret, node, popped, type));
9819 break;
9820 case NODE_FOR:
9821 case NODE_ITER:
9822 CHECK(compile_iter(iseq, ret, node, popped));
9823 break;
9824 case NODE_FOR_MASGN:
9825 CHECK(compile_for_masgn(iseq, ret, node, popped));
9826 break;
9827 case NODE_BREAK:
9828 CHECK(compile_break(iseq, ret, node, popped));
9829 break;
9830 case NODE_NEXT:
9831 CHECK(compile_next(iseq, ret, node, popped));
9832 break;
9833 case NODE_REDO:
9834 CHECK(compile_redo(iseq, ret, node, popped));
9835 break;
9836 case NODE_RETRY:
9837 CHECK(compile_retry(iseq, ret, node, popped));
9838 break;
9839 case NODE_BEGIN:{
9840 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
9841 break;
9842 }
9843 case NODE_RESCUE:
9844 CHECK(compile_rescue(iseq, ret, node, popped));
9845 break;
9846 case NODE_RESBODY:
9847 CHECK(compile_resbody(iseq, ret, node, popped));
9848 break;
9849 case NODE_ENSURE:
9850 CHECK(compile_ensure(iseq, ret, node, popped));
9851 break;
9852
9853 case NODE_AND:
9854 case NODE_OR:{
9855 LABEL *end_label = NEW_LABEL(line);
9856 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
9857 if (!popped) {
9858 ADD_INSN(ret, node, dup);
9859 }
9860 if (type == NODE_AND) {
9861 ADD_INSNL(ret, node, branchunless, end_label);
9862 }
9863 else {
9864 ADD_INSNL(ret, node, branchif, end_label);
9865 }
9866 if (!popped) {
9867 ADD_INSN(ret, node, pop);
9868 }
9869 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
9870 ADD_LABEL(ret, end_label);
9871 break;
9872 }
9873
9874 case NODE_MASGN:{
9875 compile_massign(iseq, ret, node, popped);
9876 break;
9877 }
9878
9879 case NODE_LASGN:{
9880 ID id = RNODE_LASGN(node)->nd_vid;
9881 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9882
9883 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
9884 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
9885
9886 if (!popped) {
9887 ADD_INSN(ret, node, dup);
9888 }
9889 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9890 break;
9891 }
9892 case NODE_DASGN: {
9893 int idx, lv, ls;
9894 ID id = RNODE_DASGN(node)->nd_vid;
9895 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
9896 debugi("dassn id", rb_id2str(id) ? id : '*');
9897
9898 if (!popped) {
9899 ADD_INSN(ret, node, dup);
9900 }
9901
9902 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
9903
9904 if (idx < 0) {
9905 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
9906 rb_id2str(id));
9907 goto ng;
9908 }
9909 ADD_SETLOCAL(ret, node, ls - idx, lv);
9910 break;
9911 }
9912 case NODE_GASGN:{
9913 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
9914
9915 if (!popped) {
9916 ADD_INSN(ret, node, dup);
9917 }
9918 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
9919 break;
9920 }
9921 case NODE_IASGN:{
9922 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
9923 if (!popped) {
9924 ADD_INSN(ret, node, dup);
9925 }
9926 ADD_INSN2(ret, node, setinstancevariable,
9927 ID2SYM(RNODE_IASGN(node)->nd_vid),
9928 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
9929 break;
9930 }
9931 case NODE_CDECL:{
9932 if (RNODE_CDECL(node)->nd_vid) {
9933 CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
9934
9935 if (!popped) {
9936 ADD_INSN(ret, node, dup);
9937 }
9938
9939 ADD_INSN1(ret, node, putspecialobject,
9940 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9941 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
9942 }
9943 else {
9944 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
9945 CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
9946 ADD_INSN(ret, node, swap);
9947
9948 if (!popped) {
9949 ADD_INSN1(ret, node, topn, INT2FIX(1));
9950 ADD_INSN(ret, node, swap);
9951 }
9952
9953 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
9954 }
9955 break;
9956 }
9957 case NODE_CVASGN:{
9958 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
9959 if (!popped) {
9960 ADD_INSN(ret, node, dup);
9961 }
9962 ADD_INSN2(ret, node, setclassvariable,
9963 ID2SYM(RNODE_CVASGN(node)->nd_vid),
9964 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
9965 break;
9966 }
9967 case NODE_OP_ASGN1:
9968 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9969 break;
9970 case NODE_OP_ASGN2:
9971 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9972 break;
9973 case NODE_OP_CDECL:
9974 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9975 break;
9976 case NODE_OP_ASGN_AND:
9977 case NODE_OP_ASGN_OR:
9978 CHECK(compile_op_log(iseq, ret, node, popped, type));
9979 break;
9980 case NODE_CALL: /* obj.foo */
9981 case NODE_OPCALL: /* foo[] */
9982 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9983 break;
9984 }
9985 case NODE_QCALL: /* obj&.foo */
9986 case NODE_FCALL: /* foo() */
9987 case NODE_VCALL: /* foo (variable or call) */
9988 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
9989 goto ng;
9990 }
9991 break;
9992 case NODE_SUPER:
9993 case NODE_ZSUPER:
9994 CHECK(compile_super(iseq, ret, node, popped, type));
9995 break;
9996 case NODE_LIST:{
9997 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9998 break;
9999 }
10000 case NODE_ZLIST:{
10001 if (!popped) {
10002 ADD_INSN1(ret, node, newarray, INT2FIX(0));
10003 }
10004 break;
10005 }
10006 case NODE_HASH:
10007 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10008 break;
10009 case NODE_RETURN:
10010 CHECK(compile_return(iseq, ret, node, popped));
10011 break;
10012 case NODE_YIELD:
10013 CHECK(compile_yield(iseq, ret, node, popped));
10014 break;
10015 case NODE_LVAR:{
10016 if (!popped) {
10017 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10018 }
10019 break;
10020 }
10021 case NODE_DVAR:{
10022 int lv, idx, ls;
10023 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10024 if (!popped) {
10025 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10026 if (idx < 0) {
10027 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10028 rb_id2str(RNODE_DVAR(node)->nd_vid));
10029 goto ng;
10030 }
10031 ADD_GETLOCAL(ret, node, ls - idx, lv);
10032 }
10033 break;
10034 }
10035 case NODE_GVAR:{
10036 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10037 if (popped) {
10038 ADD_INSN(ret, node, pop);
10039 }
10040 break;
10041 }
10042 case NODE_IVAR:{
10043 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10044 if (!popped) {
10045 ADD_INSN2(ret, node, getinstancevariable,
10046 ID2SYM(RNODE_IVAR(node)->nd_vid),
10047 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10048 }
10049 break;
10050 }
10051 case NODE_CONST:{
10052 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10053
10054 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10055 body->ic_size++;
10056 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10057 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10058 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10059 }
10060 else {
10061 ADD_INSN(ret, node, putnil);
10062 ADD_INSN1(ret, node, putobject, Qtrue);
10063 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10064 }
10065
10066 if (popped) {
10067 ADD_INSN(ret, node, pop);
10068 }
10069 break;
10070 }
10071 case NODE_CVAR:{
10072 if (!popped) {
10073 ADD_INSN2(ret, node, getclassvariable,
10074 ID2SYM(RNODE_CVAR(node)->nd_vid),
10075 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10076 }
10077 break;
10078 }
10079 case NODE_NTH_REF:{
10080 if (!popped) {
10081 if (!RNODE_NTH_REF(node)->nd_nth) {
10082 ADD_INSN(ret, node, putnil);
10083 break;
10084 }
10085 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10086 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10087 }
10088 break;
10089 }
10090 case NODE_BACK_REF:{
10091 if (!popped) {
10092 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10093 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10094 }
10095 break;
10096 }
10097 case NODE_MATCH:
10098 case NODE_MATCH2:
10099 case NODE_MATCH3:
10100 CHECK(compile_match(iseq, ret, node, popped, type));
10101 break;
10102 case NODE_LIT:{
10103 debugp_param("lit", RNODE_LIT(node)->nd_lit);
10104 if (!popped) {
10105 if (UNLIKELY(RNODE_LIT(node)->nd_lit == rb_mRubyVMFrozenCore)) {
10106 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); // [Bug #20569]
10107 }
10108 else {
10109 ADD_INSN1(ret, node, putobject, RNODE_LIT(node)->nd_lit);
10110 }
10111 RB_OBJ_WRITTEN(iseq, Qundef, RNODE_LIT(node)->nd_lit);
10112 }
10113 break;
10114 }
10115 case NODE_STR:{
10116 debugp_param("nd_lit", RNODE_STR(node)->nd_lit);
10117 if (!popped) {
10118 VALUE lit = RNODE_STR(node)->nd_lit;
10119 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
10120 lit = rb_fstring(lit);
10121 ADD_INSN1(ret, node, putstring, lit);
10122 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10123 }
10124 else {
10125 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
10126 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
10127 lit = rb_str_dup(lit);
10128 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
10129 lit = rb_str_freeze(lit);
10130 }
10131 else {
10132 lit = rb_fstring(lit);
10133 }
10134 ADD_INSN1(ret, node, putobject, lit);
10135 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10136 }
10137 }
10138 break;
10139 }
10140 case NODE_DSTR:{
10141 compile_dstr(iseq, ret, node);
10142
10143 if (popped) {
10144 ADD_INSN(ret, node, pop);
10145 }
10146 break;
10147 }
10148 case NODE_XSTR:{
10149 ADD_CALL_RECEIVER(ret, node);
10150 VALUE str = rb_fstring(RNODE_XSTR(node)->nd_lit);
10151 ADD_INSN1(ret, node, putobject, str);
10152 RB_OBJ_WRITTEN(iseq, Qundef, str);
10153 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
10154
10155 if (popped) {
10156 ADD_INSN(ret, node, pop);
10157 }
10158 break;
10159 }
10160 case NODE_DXSTR:{
10161 ADD_CALL_RECEIVER(ret, node);
10162 compile_dstr(iseq, ret, node);
10163 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
10164
10165 if (popped) {
10166 ADD_INSN(ret, node, pop);
10167 }
10168 break;
10169 }
10170 case NODE_EVSTR:
10171 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
10172 break;
10173 case NODE_DREGX:
10174 compile_dregx(iseq, ret, node, popped);
10175 break;
10176 case NODE_ONCE:{
10177 int ic_index = body->ise_size++;
10178 const rb_iseq_t *block_iseq;
10179 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
10180
10181 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
10182 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
10183
10184 if (popped) {
10185 ADD_INSN(ret, node, pop);
10186 }
10187 break;
10188 }
10189 case NODE_ARGSCAT:{
10190 if (popped) {
10191 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
10192 ADD_INSN1(ret, node, splatarray, Qfalse);
10193 ADD_INSN(ret, node, pop);
10194 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
10195 ADD_INSN1(ret, node, splatarray, Qfalse);
10196 ADD_INSN(ret, node, pop);
10197 }
10198 else {
10199 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
10200 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
10201 ADD_INSN(ret, node, concatarray);
10202 }
10203 break;
10204 }
10205 case NODE_ARGSPUSH:{
10206 if (popped) {
10207 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
10208 ADD_INSN1(ret, node, splatarray, Qfalse);
10209 ADD_INSN(ret, node, pop);
10210 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
10211 }
10212 else {
10213 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
10214 CHECK(compile_array_1(iseq, ret, RNODE_ARGSPUSH(node)->nd_body));
10215 ADD_INSN(ret, node, concatarray);
10216 }
10217 break;
10218 }
10219 case NODE_SPLAT:{
10220 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
10221 ADD_INSN1(ret, node, splatarray, Qtrue);
10222
10223 if (popped) {
10224 ADD_INSN(ret, node, pop);
10225 }
10226 break;
10227 }
10228 case NODE_DEFN:{
10229 ID mid = RNODE_DEFN(node)->nd_mid;
10230 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
10231 rb_id2str(mid),
10232 ISEQ_TYPE_METHOD, line);
10233
10234 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
10235 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
10236 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
10237
10238 if (!popped) {
10239 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
10240 }
10241
10242 break;
10243 }
10244 case NODE_DEFS:{
10245 ID mid = RNODE_DEFS(node)->nd_mid;
10246 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
10247 rb_id2str(mid),
10248 ISEQ_TYPE_METHOD, line);
10249
10250 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
10251 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
10252 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
10253 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
10254
10255 if (!popped) {
10256 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
10257 }
10258 break;
10259 }
10260 case NODE_ALIAS:{
10261 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10262 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
10263 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
10264 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
10265 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
10266
10267 if (popped) {
10268 ADD_INSN(ret, node, pop);
10269 }
10270 break;
10271 }
10272 case NODE_VALIAS:{
10273 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10274 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
10275 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
10276 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
10277
10278 if (popped) {
10279 ADD_INSN(ret, node, pop);
10280 }
10281 break;
10282 }
10283 case NODE_UNDEF:{
10284 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10285 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
10286 CHECK(COMPILE(ret, "undef arg", RNODE_UNDEF(node)->nd_undef));
10287 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
10288
10289 if (popped) {
10290 ADD_INSN(ret, node, pop);
10291 }
10292 break;
10293 }
10294 case NODE_CLASS:{
10295 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
10296 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
10297 ISEQ_TYPE_CLASS, line);
10298 const int flags = VM_DEFINECLASS_TYPE_CLASS |
10299 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
10300 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
10301
10302 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
10303 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
10304 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
10305
10306 if (popped) {
10307 ADD_INSN(ret, node, pop);
10308 }
10309 break;
10310 }
10311 case NODE_MODULE:{
10312 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
10313 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
10314 ISEQ_TYPE_CLASS, line);
10315 const int flags = VM_DEFINECLASS_TYPE_MODULE |
10316 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
10317
10318 ADD_INSN (ret, node, putnil); /* dummy */
10319 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
10320 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
10321
10322 if (popped) {
10323 ADD_INSN(ret, node, pop);
10324 }
10325 break;
10326 }
10327 case NODE_SCLASS:{
10328 ID singletonclass;
10329 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
10330 ISEQ_TYPE_CLASS, line);
10331
10332 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
10333 ADD_INSN (ret, node, putnil);
10334 CONST_ID(singletonclass, "singletonclass");
10335 ADD_INSN3(ret, node, defineclass,
10336 ID2SYM(singletonclass), singleton_class,
10337 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
10338 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
10339
10340 if (popped) {
10341 ADD_INSN(ret, node, pop);
10342 }
10343 break;
10344 }
10345 case NODE_COLON2:
10346 CHECK(compile_colon2(iseq, ret, node, popped));
10347 break;
10348 case NODE_COLON3:
10349 CHECK(compile_colon3(iseq, ret, node, popped));
10350 break;
10351 case NODE_DOT2:
10352 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
10353 break;
10354 case NODE_DOT3:
10355 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
10356 break;
10357 case NODE_FLIP2:
10358 case NODE_FLIP3:{
10359 LABEL *lend = NEW_LABEL(line);
10360 LABEL *ltrue = NEW_LABEL(line);
10361 LABEL *lfalse = NEW_LABEL(line);
10362 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
10363 ltrue, lfalse));
10364 ADD_LABEL(ret, ltrue);
10365 ADD_INSN1(ret, node, putobject, Qtrue);
10366 ADD_INSNL(ret, node, jump, lend);
10367 ADD_LABEL(ret, lfalse);
10368 ADD_INSN1(ret, node, putobject, Qfalse);
10369 ADD_LABEL(ret, lend);
10370 break;
10371 }
10372 case NODE_SELF:{
10373 if (!popped) {
10374 ADD_INSN(ret, node, putself);
10375 }
10376 break;
10377 }
10378 case NODE_NIL:{
10379 if (!popped) {
10380 ADD_INSN(ret, node, putnil);
10381 }
10382 break;
10383 }
10384 case NODE_TRUE:{
10385 if (!popped) {
10386 ADD_INSN1(ret, node, putobject, Qtrue);
10387 }
10388 break;
10389 }
10390 case NODE_FALSE:{
10391 if (!popped) {
10392 ADD_INSN1(ret, node, putobject, Qfalse);
10393 }
10394 break;
10395 }
10396 case NODE_ERRINFO:
10397 CHECK(compile_errinfo(iseq, ret, node, popped));
10398 break;
10399 case NODE_DEFINED:
10400 if (!popped) {
10401 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
10402 }
10403 break;
10404 case NODE_POSTEXE:{
10405 /* compiled to:
10406 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10407 */
10408 int is_index = body->ise_size++;
10410 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
10411 const rb_iseq_t *once_iseq =
10412 new_child_iseq_with_callback(iseq, ifunc,
10413 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
10414
10415 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
10416 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
10417
10418 if (popped) {
10419 ADD_INSN(ret, node, pop);
10420 }
10421 break;
10422 }
10423 case NODE_KW_ARG:
10424 CHECK(compile_kw_arg(iseq, ret, node, popped));
10425 break;
10426 case NODE_DSYM:{
10427 compile_dstr(iseq, ret, node);
10428 if (!popped) {
10429 ADD_INSN(ret, node, intern);
10430 }
10431 else {
10432 ADD_INSN(ret, node, pop);
10433 }
10434 break;
10435 }
10436 case NODE_ATTRASGN:
10437 CHECK(compile_attrasgn(iseq, ret, node, popped));
10438 break;
10439 case NODE_LAMBDA:{
10440 /* compile same as lambda{...} */
10441 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
10442 VALUE argc = INT2FIX(0);
10443
10444 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10445 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
10446 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
10447
10448 if (popped) {
10449 ADD_INSN(ret, node, pop);
10450 }
10451 break;
10452 }
10453 default:
10454 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
10455 ng:
10456 debug_node_end();
10457 return COMPILE_NG;
10458 }
10459
10460 debug_node_end();
10461 return COMPILE_OK;
10462}
10463
10464/***************************/
10465/* instruction information */
10466/***************************/
10467
10468static int
10469insn_data_length(INSN *iobj)
10470{
10471 return insn_len(iobj->insn_id);
10472}
10473
10474static int
10475calc_sp_depth(int depth, INSN *insn)
10476{
10477 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
10478}
10479
10480static VALUE
10481opobj_inspect(VALUE obj)
10482{
10483 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
10484 switch (BUILTIN_TYPE(obj)) {
10485 case T_STRING:
10486 obj = rb_str_new_cstr(RSTRING_PTR(obj));
10487 break;
10488 case T_ARRAY:
10489 obj = rb_ary_dup(obj);
10490 break;
10491 default:
10492 break;
10493 }
10494 }
10495 return rb_inspect(obj);
10496}
10497
10498
10499
10500static VALUE
10501insn_data_to_s_detail(INSN *iobj)
10502{
10503 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
10504
10505 if (iobj->operands) {
10506 const char *types = insn_op_types(iobj->insn_id);
10507 int j;
10508
10509 for (j = 0; types[j]; j++) {
10510 char type = types[j];
10511
10512 switch (type) {
10513 case TS_OFFSET: /* label(destination position) */
10514 {
10515 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
10516 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
10517 break;
10518 }
10519 break;
10520 case TS_ISEQ: /* iseq */
10521 {
10522 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
10523 VALUE val = Qnil;
10524 if (0 && iseq) { /* TODO: invalidate now */
10525 val = (VALUE)iseq;
10526 }
10527 rb_str_concat(str, opobj_inspect(val));
10528 }
10529 break;
10530 case TS_LINDEX:
10531 case TS_NUM: /* ulong */
10532 case TS_VALUE: /* VALUE */
10533 {
10534 VALUE v = OPERAND_AT(iobj, j);
10535 if (!CLASS_OF(v))
10536 rb_str_cat2(str, "<hidden>");
10537 else {
10538 rb_str_concat(str, opobj_inspect(v));
10539 }
10540 break;
10541 }
10542 case TS_ID: /* ID */
10543 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10544 break;
10545 case TS_IC: /* inline cache */
10546 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10547 break;
10548 case TS_IVC: /* inline ivar cache */
10549 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10550 break;
10551 case TS_ICVARC: /* inline cvar cache */
10552 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10553 break;
10554 case TS_ISE: /* inline storage entry */
10555 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10556 break;
10557 case TS_CALLDATA: /* we store these as call infos at compile time */
10558 {
10559 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
10560 rb_str_cat2(str, "<calldata:");
10561 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
10562 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
10563 break;
10564 }
10565 case TS_CDHASH: /* case/when condition cache */
10566 rb_str_cat2(str, "<ch>");
10567 break;
10568 case TS_FUNCPTR:
10569 {
10570 void *func = (void *)OPERAND_AT(iobj, j);
10571#ifdef HAVE_DLADDR
10572 Dl_info info;
10573 if (dladdr(func, &info) && info.dli_sname) {
10574 rb_str_cat2(str, info.dli_sname);
10575 break;
10576 }
10577#endif
10578 rb_str_catf(str, "<%p>", func);
10579 }
10580 break;
10581 case TS_BUILTIN:
10582 rb_str_cat2(str, "<TS_BUILTIN>");
10583 break;
10584 default:{
10585 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
10586 }
10587 }
10588 if (types[j + 1]) {
10589 rb_str_cat2(str, ", ");
10590 }
10591 }
10592 }
10593 return str;
10594}
10595
10596static void
10597dump_disasm_list(const LINK_ELEMENT *link)
10598{
10599 dump_disasm_list_with_cursor(link, NULL, NULL);
10600}
10601
10602static void
10603dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
10604{
10605 int pos = 0;
10606 INSN *iobj;
10607 LABEL *lobj;
10608 VALUE str;
10609
10610 printf("-- raw disasm--------\n");
10611
10612 while (link) {
10613 if (curr) printf(curr == link ? "*" : " ");
10614 switch (link->type) {
10615 case ISEQ_ELEMENT_INSN:
10616 {
10617 iobj = (INSN *)link;
10618 str = insn_data_to_s_detail(iobj);
10619 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
10620 pos += insn_data_length(iobj);
10621 break;
10622 }
10623 case ISEQ_ELEMENT_LABEL:
10624 {
10625 lobj = (LABEL *)link;
10626 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
10627 dest == lobj ? " <---" : "");
10628 break;
10629 }
10630 case ISEQ_ELEMENT_TRACE:
10631 {
10632 TRACE *trace = (TRACE *)link;
10633 printf(" trace: %0x\n", trace->event);
10634 break;
10635 }
10636 case ISEQ_ELEMENT_ADJUST:
10637 {
10638 ADJUST *adjust = (ADJUST *)link;
10639 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
10640 break;
10641 }
10642 default:
10643 /* ignore */
10644 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
10645 }
10646 link = link->next;
10647 }
10648 printf("---------------------\n");
10649 fflush(stdout);
10650}
10651
10652int
10653rb_insn_len(VALUE insn)
10654{
10655 return insn_len(insn);
10656}
10657
10658const char *
10659rb_insns_name(int i)
10660{
10661 return insn_name(i);
10662}
10663
10664VALUE
10665rb_insns_name_array(void)
10666{
10667 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
10668 int i;
10669 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
10670 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
10671 }
10672 return rb_obj_freeze(ary);
10673}
10674
10675static LABEL *
10676register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
10677{
10678 LABEL *label = 0;
10679 st_data_t tmp;
10680 obj = rb_to_symbol_type(obj);
10681
10682 if (st_lookup(labels_table, obj, &tmp) == 0) {
10683 label = NEW_LABEL(0);
10684 st_insert(labels_table, obj, (st_data_t)label);
10685 }
10686 else {
10687 label = (LABEL *)tmp;
10688 }
10689 LABEL_REF(label);
10690 return label;
10691}
10692
10693static VALUE
10694get_exception_sym2type(VALUE sym)
10695{
10696 static VALUE symRescue, symEnsure, symRetry;
10697 static VALUE symBreak, symRedo, symNext;
10698
10699 if (symRescue == 0) {
10700 symRescue = ID2SYM(rb_intern_const("rescue"));
10701 symEnsure = ID2SYM(rb_intern_const("ensure"));
10702 symRetry = ID2SYM(rb_intern_const("retry"));
10703 symBreak = ID2SYM(rb_intern_const("break"));
10704 symRedo = ID2SYM(rb_intern_const("redo"));
10705 symNext = ID2SYM(rb_intern_const("next"));
10706 }
10707
10708 if (sym == symRescue) return CATCH_TYPE_RESCUE;
10709 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
10710 if (sym == symRetry) return CATCH_TYPE_RETRY;
10711 if (sym == symBreak) return CATCH_TYPE_BREAK;
10712 if (sym == symRedo) return CATCH_TYPE_REDO;
10713 if (sym == symNext) return CATCH_TYPE_NEXT;
10714 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
10715 return 0;
10716}
10717
10718static int
10719iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
10720 VALUE exception)
10721{
10722 int i;
10723
10724 for (i=0; i<RARRAY_LEN(exception); i++) {
10725 const rb_iseq_t *eiseq;
10726 VALUE v, type;
10727 LABEL *lstart, *lend, *lcont;
10728 unsigned int sp;
10729
10730 v = rb_to_array_type(RARRAY_AREF(exception, i));
10731 if (RARRAY_LEN(v) != 6) {
10732 rb_raise(rb_eSyntaxError, "wrong exception entry");
10733 }
10734 type = get_exception_sym2type(RARRAY_AREF(v, 0));
10735 if (NIL_P(RARRAY_AREF(v, 1))) {
10736 eiseq = NULL;
10737 }
10738 else {
10739 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
10740 }
10741
10742 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
10743 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
10744 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
10745 sp = NUM2UINT(RARRAY_AREF(v, 5));
10746
10747 /* TODO: Dirty Hack! Fix me */
10748 if (type == CATCH_TYPE_RESCUE ||
10749 type == CATCH_TYPE_BREAK ||
10750 type == CATCH_TYPE_NEXT) {
10751 ++sp;
10752 }
10753
10754 lcont->sp = sp;
10755
10756 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
10757
10758 RB_GC_GUARD(v);
10759 }
10760 return COMPILE_OK;
10761}
10762
10763static struct st_table *
10764insn_make_insn_table(void)
10765{
10766 struct st_table *table;
10767 int i;
10768 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10769
10770 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10771 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
10772 }
10773
10774 return table;
10775}
10776
10777static const rb_iseq_t *
10778iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
10779{
10780 VALUE iseqw;
10781 const rb_iseq_t *loaded_iseq;
10782
10783 if (RB_TYPE_P(op, T_ARRAY)) {
10784 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
10785 }
10786 else if (CLASS_OF(op) == rb_cISeq) {
10787 iseqw = op;
10788 }
10789 else {
10790 rb_raise(rb_eSyntaxError, "ISEQ is required");
10791 }
10792
10793 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10794 return loaded_iseq;
10795}
10796
10797static VALUE
10798iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
10799{
10800 ID mid = 0;
10801 int orig_argc = 0;
10802 unsigned int flag = 0;
10803 struct rb_callinfo_kwarg *kw_arg = 0;
10804
10805 if (!NIL_P(op)) {
10806 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
10807 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
10808 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
10809 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
10810
10811 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
10812 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
10813 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
10814
10815 if (!NIL_P(vkw_arg)) {
10816 int i;
10817 int len = RARRAY_LENINT(vkw_arg);
10818 size_t n = rb_callinfo_kwarg_bytes(len);
10819
10820 kw_arg = xmalloc(n);
10821 kw_arg->references = 0;
10822 kw_arg->keyword_len = len;
10823 for (i = 0; i < len; i++) {
10824 VALUE kw = RARRAY_AREF(vkw_arg, i);
10825 SYM2ID(kw); /* make immortal */
10826 kw_arg->keywords[i] = kw;
10827 }
10828 }
10829 }
10830
10831 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10832 RB_OBJ_WRITTEN(iseq, Qundef, ci);
10833 return (VALUE)ci;
10834}
10835
10836static rb_event_flag_t
10837event_name_to_flag(VALUE sym)
10838{
10839#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10840 CHECK_EVENT(RUBY_EVENT_LINE);
10841 CHECK_EVENT(RUBY_EVENT_CLASS);
10842 CHECK_EVENT(RUBY_EVENT_END);
10843 CHECK_EVENT(RUBY_EVENT_CALL);
10844 CHECK_EVENT(RUBY_EVENT_RETURN);
10845 CHECK_EVENT(RUBY_EVENT_B_CALL);
10846 CHECK_EVENT(RUBY_EVENT_B_RETURN);
10847 CHECK_EVENT(RUBY_EVENT_RESCUE);
10848#undef CHECK_EVENT
10849 return RUBY_EVENT_NONE;
10850}
10851
10852static int
10853iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
10854 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10855{
10856 /* TODO: body should be frozen */
10857 long i, len = RARRAY_LEN(body);
10858 struct st_table *labels_table = DATA_PTR(labels_wrapper);
10859 int j;
10860 int line_no = 0, node_id = -1, insn_idx = 0;
10861 int ret = COMPILE_OK;
10862
10863 /*
10864 * index -> LABEL *label
10865 */
10866 static struct st_table *insn_table;
10867
10868 if (insn_table == 0) {
10869 insn_table = insn_make_insn_table();
10870 }
10871
10872 for (i=0; i<len; i++) {
10873 VALUE obj = RARRAY_AREF(body, i);
10874
10875 if (SYMBOL_P(obj)) {
10876 rb_event_flag_t event;
10877 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
10878 ADD_TRACE(anchor, event);
10879 }
10880 else {
10881 LABEL *label = register_label(iseq, labels_table, obj);
10882 ADD_LABEL(anchor, label);
10883 }
10884 }
10885 else if (FIXNUM_P(obj)) {
10886 line_no = NUM2INT(obj);
10887 }
10888 else if (RB_TYPE_P(obj, T_ARRAY)) {
10889 VALUE *argv = 0;
10890 int argc = RARRAY_LENINT(obj) - 1;
10891 st_data_t insn_id;
10892 VALUE insn;
10893
10894 if (node_ids) {
10895 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
10896 }
10897
10898 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
10899 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10900 /* TODO: exception */
10901 COMPILE_ERROR(iseq, line_no,
10902 "unknown instruction: %+"PRIsVALUE, insn);
10903 ret = COMPILE_NG;
10904 break;
10905 }
10906
10907 if (argc != insn_len((VALUE)insn_id)-1) {
10908 COMPILE_ERROR(iseq, line_no,
10909 "operand size mismatch");
10910 ret = COMPILE_NG;
10911 break;
10912 }
10913
10914 if (argc > 0) {
10915 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
10916
10917 // add element before operand setup to make GC root
10918 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10919 ADD_ELEM(anchor,
10920 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10921 (enum ruby_vminsn_type)insn_id, argc, argv));
10922
10923 for (j=0; j<argc; j++) {
10924 VALUE op = rb_ary_entry(obj, j+1);
10925 switch (insn_op_type((VALUE)insn_id, j)) {
10926 case TS_OFFSET: {
10927 LABEL *label = register_label(iseq, labels_table, op);
10928 argv[j] = (VALUE)label;
10929 break;
10930 }
10931 case TS_LINDEX:
10932 case TS_NUM:
10933 (void)NUM2INT(op);
10934 argv[j] = op;
10935 break;
10936 case TS_VALUE:
10937 argv[j] = op;
10938 RB_OBJ_WRITTEN(iseq, Qundef, op);
10939 break;
10940 case TS_ISEQ:
10941 {
10942 if (op != Qnil) {
10943 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
10944 argv[j] = v;
10945 RB_OBJ_WRITTEN(iseq, Qundef, v);
10946 }
10947 else {
10948 argv[j] = 0;
10949 }
10950 }
10951 break;
10952 case TS_ISE:
10953 argv[j] = op;
10954 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
10955 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
10956 }
10957 break;
10958 case TS_IC:
10959 {
10960 VALUE segments = rb_ary_new();
10961 op = rb_to_array_type(op);
10962
10963 for (int i = 0; i < RARRAY_LEN(op); i++) {
10964 VALUE sym = RARRAY_AREF(op, i);
10965 sym = rb_to_symbol_type(sym);
10966 rb_ary_push(segments, sym);
10967 }
10968
10969 RB_GC_GUARD(op);
10970 argv[j] = segments;
10971 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10972 ISEQ_BODY(iseq)->ic_size++;
10973 }
10974 break;
10975 case TS_IVC: /* inline ivar cache */
10976 argv[j] = op;
10977 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
10978 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
10979 }
10980 break;
10981 case TS_ICVARC: /* inline cvar cache */
10982 argv[j] = op;
10983 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
10984 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
10985 }
10986 break;
10987 case TS_CALLDATA:
10988 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10989 break;
10990 case TS_ID:
10991 argv[j] = rb_to_symbol_type(op);
10992 break;
10993 case TS_CDHASH:
10994 {
10995 int i;
10996 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
10997
10998 RHASH_TBL_RAW(map)->type = &cdhash_type;
10999 op = rb_to_array_type(op);
11000 for (i=0; i<RARRAY_LEN(op); i+=2) {
11001 VALUE key = RARRAY_AREF(op, i);
11002 VALUE sym = RARRAY_AREF(op, i+1);
11003 LABEL *label =
11004 register_label(iseq, labels_table, sym);
11005 rb_hash_aset(map, key, (VALUE)label | 1);
11006 }
11007 RB_GC_GUARD(op);
11008 argv[j] = map;
11009 RB_OBJ_WRITTEN(iseq, Qundef, map);
11010 }
11011 break;
11012 case TS_FUNCPTR:
11013 {
11014#if SIZEOF_VALUE <= SIZEOF_LONG
11015 long funcptr = NUM2LONG(op);
11016#else
11017 LONG_LONG funcptr = NUM2LL(op);
11018#endif
11019 argv[j] = (VALUE)funcptr;
11020 }
11021 break;
11022 default:
11023 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11024 }
11025 }
11026 }
11027 else {
11028 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
11029 ADD_ELEM(anchor,
11030 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
11031 (enum ruby_vminsn_type)insn_id, argc, NULL));
11032 }
11033 }
11034 else {
11035 rb_raise(rb_eTypeError, "unexpected object for instruction");
11036 }
11037 }
11038 DATA_PTR(labels_wrapper) = 0;
11039 validate_labels(iseq, labels_table);
11040 if (!ret) return ret;
11041 return iseq_setup(iseq, anchor);
11042}
11043
11044#define CHECK_ARRAY(v) rb_to_array_type(v)
11045#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11046
11047static int
11048int_param(int *dst, VALUE param, VALUE sym)
11049{
11050 VALUE val = rb_hash_aref(param, sym);
11051 if (FIXNUM_P(val)) {
11052 *dst = FIX2INT(val);
11053 return TRUE;
11054 }
11055 else if (!NIL_P(val)) {
11056 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
11057 sym, val);
11058 }
11059 return FALSE;
11060}
11061
11062static const struct rb_iseq_param_keyword *
11063iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
11064{
11065 int i, j;
11066 int len = RARRAY_LENINT(keywords);
11067 int default_len;
11068 VALUE key, sym, default_val;
11069 VALUE *dvs;
11070 ID *ids;
11071 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
11072
11073 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
11074
11075 keyword->num = len;
11076#define SYM(s) ID2SYM(rb_intern_const(#s))
11077 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
11078 i = keyword->bits_start - keyword->num;
11079 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
11080#undef SYM
11081
11082 /* required args */
11083 for (i = 0; i < len; i++) {
11084 VALUE val = RARRAY_AREF(keywords, i);
11085
11086 if (!SYMBOL_P(val)) {
11087 goto default_values;
11088 }
11089 ids[i] = SYM2ID(val);
11090 keyword->required_num++;
11091 }
11092
11093 default_values: /* note: we intentionally preserve `i' from previous loop */
11094 default_len = len - i;
11095 if (default_len == 0) {
11096 keyword->table = ids;
11097 return keyword;
11098 }
11099 else if (default_len < 0) {
11101 }
11102
11103 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
11104
11105 for (j = 0; i < len; i++, j++) {
11106 key = RARRAY_AREF(keywords, i);
11107 CHECK_ARRAY(key);
11108
11109 switch (RARRAY_LEN(key)) {
11110 case 1:
11111 sym = RARRAY_AREF(key, 0);
11112 default_val = Qundef;
11113 break;
11114 case 2:
11115 sym = RARRAY_AREF(key, 0);
11116 default_val = RARRAY_AREF(key, 1);
11117 break;
11118 default:
11119 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
11120 }
11121 ids[i] = SYM2ID(sym);
11122 dvs[j] = default_val;
11123 }
11124
11125 keyword->table = ids;
11126 keyword->default_values = dvs;
11127
11128 return keyword;
11129}
11130
11131static void
11132iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
11133{
11134 rb_gc_mark(obj);
11135}
11136
11137void
11138rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
11139{
11140 INSN *iobj = 0;
11141 size_t size = sizeof(INSN);
11142 unsigned int pos = 0;
11143
11144 while (storage) {
11145#ifdef STRICT_ALIGNMENT
11146 size_t padding = calc_padding((void *)&storage->buff[pos], size);
11147#else
11148 const size_t padding = 0; /* expected to be optimized by compiler */
11149#endif /* STRICT_ALIGNMENT */
11150 size_t offset = pos + size + padding;
11151 if (offset > storage->size || offset > storage->pos) {
11152 pos = 0;
11153 storage = storage->next;
11154 }
11155 else {
11156#ifdef STRICT_ALIGNMENT
11157 pos += (int)padding;
11158#endif /* STRICT_ALIGNMENT */
11159
11160 iobj = (INSN *)&storage->buff[pos];
11161
11162 if (iobj->operands) {
11163 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
11164 }
11165 pos += (int)size;
11166 }
11167 }
11168}
11169
11170void
11171rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
11172 VALUE exception, VALUE body)
11173{
11174#define SYM(s) ID2SYM(rb_intern_const(#s))
11175 int i, len;
11176 unsigned int arg_size, local_size, stack_max;
11177 ID *tbl;
11178 struct st_table *labels_table = st_init_numtable();
11179 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
11180 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
11181 VALUE keywords = rb_hash_aref(params, SYM(keyword));
11182 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
11183 DECL_ANCHOR(anchor);
11184 INIT_ANCHOR(anchor);
11185
11186 len = RARRAY_LENINT(locals);
11187 ISEQ_BODY(iseq)->local_table_size = len;
11188 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
11189
11190 for (i = 0; i < len; i++) {
11191 VALUE lv = RARRAY_AREF(locals, i);
11192
11193 if (sym_arg_rest == lv) {
11194 tbl[i] = 0;
11195 }
11196 else {
11197 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
11198 }
11199 }
11200
11201#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
11202 if (INT_PARAM(lead_num)) {
11203 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
11204 }
11205 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
11206 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
11207 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
11208 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
11209#undef INT_PARAM
11210 {
11211#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
11212 int x;
11213 INT_PARAM(arg_size);
11214 INT_PARAM(local_size);
11215 INT_PARAM(stack_max);
11216#undef INT_PARAM
11217 }
11218
11219 VALUE node_ids = Qfalse;
11220#ifdef USE_ISEQ_NODE_ID
11221 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
11222 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
11223 rb_raise(rb_eTypeError, "node_ids is not an array");
11224 }
11225#endif
11226
11227 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
11228 len = RARRAY_LENINT(arg_opt_labels);
11229 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
11230
11231 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
11232 VALUE *opt_table = ALLOC_N(VALUE, len);
11233
11234 for (i = 0; i < len; i++) {
11235 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
11236 LABEL *label = register_label(iseq, labels_table, ent);
11237 opt_table[i] = (VALUE)label;
11238 }
11239
11240 ISEQ_BODY(iseq)->param.opt_num = len - 1;
11241 ISEQ_BODY(iseq)->param.opt_table = opt_table;
11242 }
11243 }
11244 else if (!NIL_P(arg_opt_labels)) {
11245 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
11246 arg_opt_labels);
11247 }
11248
11249 if (RB_TYPE_P(keywords, T_ARRAY)) {
11250 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
11251 }
11252 else if (!NIL_P(keywords)) {
11253 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
11254 keywords);
11255 }
11256
11257 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
11258 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
11259 }
11260
11261 if (int_param(&i, params, SYM(kwrest))) {
11262 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
11263 if (keyword == NULL) {
11264 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
11265 }
11266 keyword->rest_start = i;
11267 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
11268 }
11269#undef SYM
11270 iseq_calc_param_size(iseq);
11271
11272 /* exception */
11273 iseq_build_from_ary_exception(iseq, labels_table, exception);
11274
11275 /* body */
11276 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
11277
11278 ISEQ_BODY(iseq)->param.size = arg_size;
11279 ISEQ_BODY(iseq)->local_table_size = local_size;
11280 ISEQ_BODY(iseq)->stack_max = stack_max;
11281}
11282
11283/* for parser */
11284
11285int
11286rb_dvar_defined(ID id, const rb_iseq_t *iseq)
11287{
11288 if (iseq) {
11289 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
11290 while (body->type == ISEQ_TYPE_BLOCK ||
11291 body->type == ISEQ_TYPE_RESCUE ||
11292 body->type == ISEQ_TYPE_ENSURE ||
11293 body->type == ISEQ_TYPE_EVAL ||
11294 body->type == ISEQ_TYPE_MAIN
11295 ) {
11296 unsigned int i;
11297
11298 for (i = 0; i < body->local_table_size; i++) {
11299 if (body->local_table[i] == id) {
11300 return 1;
11301 }
11302 }
11303 iseq = body->parent_iseq;
11304 body = ISEQ_BODY(iseq);
11305 }
11306 }
11307 return 0;
11308}
11309
11310int
11311rb_local_defined(ID id, const rb_iseq_t *iseq)
11312{
11313 if (iseq) {
11314 unsigned int i;
11315 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
11316
11317 for (i=0; i<body->local_table_size; i++) {
11318 if (body->local_table[i] == id) {
11319 return 1;
11320 }
11321 }
11322 }
11323 return 0;
11324}
11325
11326/* ISeq binary format */
11327
11328#ifndef IBF_ISEQ_DEBUG
11329#define IBF_ISEQ_DEBUG 0
11330#endif
11331
11332#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
11333#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
11334#endif
11335
11336typedef uint32_t ibf_offset_t;
11337#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
11338
11339#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
11340#ifdef RUBY_DEVEL
11341#define IBF_DEVEL_VERSION 4
11342#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
11343#else
11344#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
11345#endif
11346
11347static const char IBF_ENDIAN_MARK =
11348#ifdef WORDS_BIGENDIAN
11349 'b'
11350#else
11351 'l'
11352#endif
11353 ;
11354
11356 char magic[4]; /* YARB */
11357 uint32_t major_version;
11358 uint32_t minor_version;
11359 uint32_t size;
11360 uint32_t extra_size;
11361
11362 uint32_t iseq_list_size;
11363 uint32_t global_object_list_size;
11364 ibf_offset_t iseq_list_offset;
11365 ibf_offset_t global_object_list_offset;
11366 uint8_t endian;
11367 uint8_t wordsize; /* assume no 2048-bit CPU */
11368};
11369
11371 VALUE str;
11372 st_table *obj_table; /* obj -> obj number */
11373};
11374
11375struct ibf_dump {
11376 st_table *iseq_table; /* iseq -> iseq number */
11377 struct ibf_dump_buffer global_buffer;
11378 struct ibf_dump_buffer *current_buffer;
11379};
11380
11382 const char *buff;
11383 ibf_offset_t size;
11384
11385 VALUE obj_list; /* [obj0, ...] */
11386 unsigned int obj_list_size;
11387 ibf_offset_t obj_list_offset;
11388};
11389
11390struct ibf_load {
11391 const struct ibf_header *header;
11392 VALUE iseq_list; /* [iseq0, ...] */
11393 struct ibf_load_buffer global_buffer;
11394 VALUE loader_obj;
11395 rb_iseq_t *iseq;
11396 VALUE str;
11397 struct ibf_load_buffer *current_buffer;
11398};
11399
11401 long size;
11402 VALUE buffer[1];
11403};
11404
11405static void
11406pinned_list_mark(void *ptr)
11407{
11408 long i;
11409 struct pinned_list *list = (struct pinned_list *)ptr;
11410 for (i = 0; i < list->size; i++) {
11411 if (list->buffer[i]) {
11412 rb_gc_mark(list->buffer[i]);
11413 }
11414 }
11415}
11416
11417static const rb_data_type_t pinned_list_type = {
11418 "pinned_list",
11419 {
11420 pinned_list_mark,
11422 NULL, // No external memory to report,
11423 },
11424 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
11425};
11426
11427static VALUE
11428pinned_list_fetch(VALUE list, long offset)
11429{
11430 struct pinned_list * ptr;
11431
11432 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11433
11434 if (offset >= ptr->size) {
11435 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11436 }
11437
11438 return ptr->buffer[offset];
11439}
11440
11441static void
11442pinned_list_store(VALUE list, long offset, VALUE object)
11443{
11444 struct pinned_list * ptr;
11445
11446 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11447
11448 if (offset >= ptr->size) {
11449 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11450 }
11451
11452 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
11453}
11454
11455static VALUE
11456pinned_list_new(long size)
11457{
11458 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
11459 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
11460 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
11461 ptr->size = size;
11462 return obj_list;
11463}
11464
11465static ibf_offset_t
11466ibf_dump_pos(struct ibf_dump *dump)
11467{
11468 long pos = RSTRING_LEN(dump->current_buffer->str);
11469#if SIZEOF_LONG > SIZEOF_INT
11470 if (pos >= UINT_MAX) {
11471 rb_raise(rb_eRuntimeError, "dump size exceeds");
11472 }
11473#endif
11474 return (unsigned int)pos;
11475}
11476
11477static void
11478ibf_dump_align(struct ibf_dump *dump, size_t align)
11479{
11480 ibf_offset_t pos = ibf_dump_pos(dump);
11481 if (pos % align) {
11482 static const char padding[sizeof(VALUE)];
11483 size_t size = align - ((size_t)pos % align);
11484#if SIZEOF_LONG > SIZEOF_INT
11485 if (pos + size >= UINT_MAX) {
11486 rb_raise(rb_eRuntimeError, "dump size exceeds");
11487 }
11488#endif
11489 for (; size > sizeof(padding); size -= sizeof(padding)) {
11490 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
11491 }
11492 rb_str_cat(dump->current_buffer->str, padding, size);
11493 }
11494}
11495
11496static ibf_offset_t
11497ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
11498{
11499 ibf_offset_t pos = ibf_dump_pos(dump);
11500 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
11501 /* TODO: overflow check */
11502 return pos;
11503}
11504
11505static ibf_offset_t
11506ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
11507{
11508 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
11509}
11510
11511static void
11512ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
11513{
11514 VALUE str = dump->current_buffer->str;
11515 char *ptr = RSTRING_PTR(str);
11516 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
11517 rb_bug("ibf_dump_overwrite: overflow");
11518 memcpy(ptr + offset, buff, size);
11519}
11520
11521static const void *
11522ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
11523{
11524 ibf_offset_t beg = *offset;
11525 *offset += size;
11526 return load->current_buffer->buff + beg;
11527}
11528
11529static void *
11530ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
11531{
11532 void *buff = ruby_xmalloc2(x, y);
11533 size_t size = x * y;
11534 memcpy(buff, load->current_buffer->buff + offset, size);
11535 return buff;
11536}
11537
11538#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
11539
11540#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
11541#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
11542#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
11543#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
11544#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
11545
11546static int
11547ibf_table_lookup(struct st_table *table, st_data_t key)
11548{
11549 st_data_t val;
11550
11551 if (st_lookup(table, key, &val)) {
11552 return (int)val;
11553 }
11554 else {
11555 return -1;
11556 }
11557}
11558
11559static int
11560ibf_table_find_or_insert(struct st_table *table, st_data_t key)
11561{
11562 int index = ibf_table_lookup(table, key);
11563
11564 if (index < 0) { /* not found */
11565 index = (int)table->num_entries;
11566 st_insert(table, key, (st_data_t)index);
11567 }
11568
11569 return index;
11570}
11571
11572/* dump/load generic */
11573
11574static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
11575
11576static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
11577static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
11578
11579static st_table *
11580ibf_dump_object_table_new(void)
11581{
11582 st_table *obj_table = st_init_numtable(); /* need free */
11583 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
11584
11585 return obj_table;
11586}
11587
11588static VALUE
11589ibf_dump_object(struct ibf_dump *dump, VALUE obj)
11590{
11591 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
11592}
11593
11594static VALUE
11595ibf_dump_id(struct ibf_dump *dump, ID id)
11596{
11597 if (id == 0 || rb_id2name(id) == NULL) {
11598 return 0;
11599 }
11600 return ibf_dump_object(dump, rb_id2sym(id));
11601}
11602
11603static ID
11604ibf_load_id(const struct ibf_load *load, const ID id_index)
11605{
11606 if (id_index == 0) {
11607 return 0;
11608 }
11609 VALUE sym = ibf_load_object(load, id_index);
11610 return rb_sym2id(sym);
11611}
11612
11613/* dump/load: code */
11614
11615static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
11616
11617static int
11618ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
11619{
11620 if (iseq == NULL) {
11621 return -1;
11622 }
11623 else {
11624 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
11625 }
11626}
11627
11628static unsigned char
11629ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
11630{
11631 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
11632 return (unsigned char)load->current_buffer->buff[(*offset)++];
11633}
11634
11635/*
11636 * Small uint serialization
11637 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
11638 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
11639 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
11640 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11641 * ...
11642 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11643 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11644 */
11645static void
11646ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
11647{
11648 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11649 ibf_dump_write(dump, &x, sizeof(VALUE));
11650 return;
11651 }
11652
11653 enum { max_byte_length = sizeof(VALUE) + 1 };
11654
11655 unsigned char bytes[max_byte_length];
11656 ibf_offset_t n;
11657
11658 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
11659 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11660 }
11661
11662 x <<= 1;
11663 x |= 1;
11664 x <<= n;
11665 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11666 n++;
11667
11668 ibf_dump_write(dump, bytes + max_byte_length - n, n);
11669}
11670
11671static VALUE
11672ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
11673{
11674 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11675 union { char s[sizeof(VALUE)]; VALUE v; } x;
11676
11677 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
11678 *offset += sizeof(VALUE);
11679
11680 return x.v;
11681 }
11682
11683 enum { max_byte_length = sizeof(VALUE) + 1 };
11684
11685 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
11686 const unsigned char c = buffer[*offset];
11687
11688 ibf_offset_t n =
11689 c & 1 ? 1 :
11690 c == 0 ? 9 : ntz_int32(c) + 1;
11691 VALUE x = (VALUE)c >> n;
11692
11693 if (*offset + n > load->current_buffer->size) {
11694 rb_raise(rb_eRuntimeError, "invalid byte sequence");
11695 }
11696
11697 ibf_offset_t i;
11698 for (i = 1; i < n; i++) {
11699 x <<= 8;
11700 x |= (VALUE)buffer[*offset + i];
11701 }
11702
11703 *offset += n;
11704 return x;
11705}
11706
11707static void
11708ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
11709{
11710 // short: index
11711 // short: name.length
11712 // bytes: name
11713 // // omit argc (only verify with name)
11714 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11715
11716 size_t len = strlen(bf->name);
11717 ibf_dump_write_small_value(dump, (VALUE)len);
11718 ibf_dump_write(dump, bf->name, len);
11719}
11720
11721static const struct rb_builtin_function *
11722ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
11723{
11724 int i = (int)ibf_load_small_value(load, offset);
11725 int len = (int)ibf_load_small_value(load, offset);
11726 const char *name = (char *)ibf_load_ptr(load, offset, len);
11727
11728 if (0) {
11729 fprintf(stderr, "%.*s!!\n", len, name);
11730 }
11731
11732 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
11733 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
11734 if (strncmp(table[i].name, name, len) != 0) {
11735 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11736 }
11737 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
11738
11739 return &table[i];
11740}
11741
11742static ibf_offset_t
11743ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
11744{
11745 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11746 const int iseq_size = body->iseq_size;
11747 int code_index;
11748 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11749
11750 ibf_offset_t offset = ibf_dump_pos(dump);
11751
11752 for (code_index=0; code_index<iseq_size;) {
11753 const VALUE insn = orig_code[code_index++];
11754 const char *types = insn_op_types(insn);
11755 int op_index;
11756
11757 /* opcode */
11758 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
11759 ibf_dump_write_small_value(dump, insn);
11760
11761 /* operands */
11762 for (op_index=0; types[op_index]; op_index++, code_index++) {
11763 VALUE op = orig_code[code_index];
11764 VALUE wv;
11765
11766 switch (types[op_index]) {
11767 case TS_CDHASH:
11768 case TS_VALUE:
11769 wv = ibf_dump_object(dump, op);
11770 break;
11771 case TS_ISEQ:
11772 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
11773 break;
11774 case TS_IC:
11775 {
11776 IC ic = (IC)op;
11777 VALUE arr = idlist_to_array(ic->segments);
11778 wv = ibf_dump_object(dump, arr);
11779 }
11780 break;
11781 case TS_ISE:
11782 case TS_IVC:
11783 case TS_ICVARC:
11784 {
11786 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
11787 }
11788 break;
11789 case TS_CALLDATA:
11790 {
11791 goto skip_wv;
11792 }
11793 case TS_ID:
11794 wv = ibf_dump_id(dump, (ID)op);
11795 break;
11796 case TS_FUNCPTR:
11797 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11798 goto skip_wv;
11799 case TS_BUILTIN:
11800 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
11801 goto skip_wv;
11802 default:
11803 wv = op;
11804 break;
11805 }
11806 ibf_dump_write_small_value(dump, wv);
11807 skip_wv:;
11808 }
11809 assert(insn_len(insn) == op_index+1);
11810 }
11811
11812 return offset;
11813}
11814
11815static VALUE *
11816ibf_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)
11817{
11818 VALUE iseqv = (VALUE)iseq;
11819 unsigned int code_index;
11820 ibf_offset_t reading_pos = bytecode_offset;
11821 VALUE *code = ALLOC_N(VALUE, iseq_size);
11822
11823 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
11824 struct rb_call_data *cd_entries = load_body->call_data;
11825 int ic_index = 0;
11826
11827 iseq_bits_t * mark_offset_bits;
11828
11829 iseq_bits_t tmp[1] = {0};
11830
11831 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
11832 mark_offset_bits = tmp;
11833 }
11834 else {
11835 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
11836 }
11837 bool needs_bitmap = false;
11838
11839 for (code_index=0; code_index<iseq_size;) {
11840 /* opcode */
11841 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11842 const char *types = insn_op_types(insn);
11843 int op_index;
11844
11845 code_index++;
11846
11847 /* operands */
11848 for (op_index=0; types[op_index]; op_index++, code_index++) {
11849 const char operand_type = types[op_index];
11850 switch (operand_type) {
11851 case TS_VALUE:
11852 {
11853 VALUE op = ibf_load_small_value(load, &reading_pos);
11854 VALUE v = ibf_load_object(load, op);
11855 code[code_index] = v;
11856 if (!SPECIAL_CONST_P(v)) {
11857 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11858 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11859 needs_bitmap = true;
11860 }
11861 break;
11862 }
11863 case TS_CDHASH:
11864 {
11865 VALUE op = ibf_load_small_value(load, &reading_pos);
11866 VALUE v = ibf_load_object(load, op);
11867 v = rb_hash_dup(v); // hash dumped as frozen
11868 RHASH_TBL_RAW(v)->type = &cdhash_type;
11869 rb_hash_rehash(v); // hash function changed
11870 freeze_hide_obj(v);
11871
11872 // Overwrite the existing hash in the object list. This
11873 // is to keep the object alive during load time.
11874 // [Bug #17984] [ruby-core:104259]
11875 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
11876
11877 code[code_index] = v;
11878 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11879 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11880 needs_bitmap = true;
11881 break;
11882 }
11883 case TS_ISEQ:
11884 {
11885 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
11886 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
11887 code[code_index] = v;
11888 if (!SPECIAL_CONST_P(v)) {
11889 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11890 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11891 needs_bitmap = true;
11892 }
11893 break;
11894 }
11895 case TS_IC:
11896 {
11897 VALUE op = ibf_load_small_value(load, &reading_pos);
11898 VALUE arr = ibf_load_object(load, op);
11899
11900 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
11901 ic->segments = array_to_idlist(arr);
11902
11903 code[code_index] = (VALUE)ic;
11904 }
11905 break;
11906 case TS_ISE:
11907 case TS_ICVARC:
11908 case TS_IVC:
11909 {
11910 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
11911
11912 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
11913 code[code_index] = (VALUE)ic;
11914
11915 if (operand_type == TS_IVC) {
11916 IVC cache = (IVC)ic;
11917
11918 if (insn == BIN(setinstancevariable)) {
11919 ID iv_name = (ID)code[code_index - 1];
11920 cache->iv_set_name = iv_name;
11921 }
11922 else {
11923 cache->iv_set_name = 0;
11924 }
11925
11926 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
11927 }
11928
11929 }
11930 break;
11931 case TS_CALLDATA:
11932 {
11933 code[code_index] = (VALUE)cd_entries++;
11934 }
11935 break;
11936 case TS_ID:
11937 {
11938 VALUE op = ibf_load_small_value(load, &reading_pos);
11939 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11940 }
11941 break;
11942 case TS_FUNCPTR:
11943 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11944 break;
11945 case TS_BUILTIN:
11946 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
11947 break;
11948 default:
11949 code[code_index] = ibf_load_small_value(load, &reading_pos);
11950 continue;
11951 }
11952 }
11953 if (insn_len(insn) != op_index+1) {
11954 rb_raise(rb_eRuntimeError, "operand size mismatch");
11955 }
11956 }
11957
11958 load_body->iseq_encoded = code;
11959 load_body->iseq_size = code_index;
11960
11961 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
11962 load_body->mark_bits.single = mark_offset_bits[0];
11963 }
11964 else {
11965 if (needs_bitmap) {
11966 load_body->mark_bits.list = mark_offset_bits;
11967 }
11968 else {
11969 load_body->mark_bits.list = 0;
11970 ruby_xfree(mark_offset_bits);
11971 }
11972 }
11973
11974 assert(code_index == iseq_size);
11975 assert(reading_pos == bytecode_offset + bytecode_size);
11976 return code;
11977}
11978
11979static ibf_offset_t
11980ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11981{
11982 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
11983
11984 if (opt_num > 0) {
11985 IBF_W_ALIGN(VALUE);
11986 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
11987 }
11988 else {
11989 return ibf_dump_pos(dump);
11990 }
11991}
11992
11993static VALUE *
11994ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
11995{
11996 if (opt_num > 0) {
11997 VALUE *table = ALLOC_N(VALUE, opt_num+1);
11998 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11999 return table;
12000 }
12001 else {
12002 return NULL;
12003 }
12004}
12005
12006static ibf_offset_t
12007ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
12008{
12009 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
12010
12011 if (kw) {
12012 struct rb_iseq_param_keyword dump_kw = *kw;
12013 int dv_num = kw->num - kw->required_num;
12014 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
12015 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
12016 int i;
12017
12018 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12019 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12020
12021 dump_kw.table = IBF_W(ids, ID, kw->num);
12022 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12023 IBF_W_ALIGN(struct rb_iseq_param_keyword);
12024 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12025 }
12026 else {
12027 return 0;
12028 }
12029}
12030
12031static const struct rb_iseq_param_keyword *
12032ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
12033{
12034 if (param_keyword_offset) {
12035 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
12036 ID *ids = IBF_R(kw->table, ID, kw->num);
12037 int dv_num = kw->num - kw->required_num;
12038 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
12039 int i;
12040
12041 for (i=0; i<kw->num; i++) {
12042 ids[i] = ibf_load_id(load, ids[i]);
12043 }
12044 for (i=0; i<dv_num; i++) {
12045 dvs[i] = ibf_load_object(load, dvs[i]);
12046 }
12047
12048 kw->table = ids;
12049 kw->default_values = dvs;
12050 return kw;
12051 }
12052 else {
12053 return NULL;
12054 }
12055}
12056
12057static ibf_offset_t
12058ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
12059{
12060 ibf_offset_t offset = ibf_dump_pos(dump);
12061 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
12062
12063 unsigned int i;
12064 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
12065 ibf_dump_write_small_value(dump, entries[i].line_no);
12066#ifdef USE_ISEQ_NODE_ID
12067 ibf_dump_write_small_value(dump, entries[i].node_id);
12068#endif
12069 ibf_dump_write_small_value(dump, entries[i].events);
12070 }
12071
12072 return offset;
12073}
12074
12075static struct iseq_insn_info_entry *
12076ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
12077{
12078 ibf_offset_t reading_pos = body_offset;
12079 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
12080
12081 unsigned int i;
12082 for (i = 0; i < size; i++) {
12083 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
12084#ifdef USE_ISEQ_NODE_ID
12085 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
12086#endif
12087 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
12088 }
12089
12090 return entries;
12091}
12092
12093static ibf_offset_t
12094ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
12095{
12096 ibf_offset_t offset = ibf_dump_pos(dump);
12097
12098 unsigned int last = 0;
12099 unsigned int i;
12100 for (i = 0; i < size; i++) {
12101 ibf_dump_write_small_value(dump, positions[i] - last);
12102 last = positions[i];
12103 }
12104
12105 return offset;
12106}
12107
12108static unsigned int *
12109ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
12110{
12111 ibf_offset_t reading_pos = positions_offset;
12112 unsigned int *positions = ALLOC_N(unsigned int, size);
12113
12114 unsigned int last = 0;
12115 unsigned int i;
12116 for (i = 0; i < size; i++) {
12117 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
12118 last = positions[i];
12119 }
12120
12121 return positions;
12122}
12123
12124static ibf_offset_t
12125ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12126{
12127 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12128 const int size = body->local_table_size;
12129 ID *table = ALLOCA_N(ID, size);
12130 int i;
12131
12132 for (i=0; i<size; i++) {
12133 table[i] = ibf_dump_id(dump, body->local_table[i]);
12134 }
12135
12136 IBF_W_ALIGN(ID);
12137 return ibf_dump_write(dump, table, sizeof(ID) * size);
12138}
12139
12140static ID *
12141ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
12142{
12143 if (size > 0) {
12144 ID *table = IBF_R(local_table_offset, ID, size);
12145 int i;
12146
12147 for (i=0; i<size; i++) {
12148 table[i] = ibf_load_id(load, table[i]);
12149 }
12150 return table;
12151 }
12152 else {
12153 return NULL;
12154 }
12155}
12156
12157static ibf_offset_t
12158ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12159{
12160 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
12161
12162 if (table) {
12163 int *iseq_indices = ALLOCA_N(int, table->size);
12164 unsigned int i;
12165
12166 for (i=0; i<table->size; i++) {
12167 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
12168 }
12169
12170 const ibf_offset_t offset = ibf_dump_pos(dump);
12171
12172 for (i=0; i<table->size; i++) {
12173 ibf_dump_write_small_value(dump, iseq_indices[i]);
12174 ibf_dump_write_small_value(dump, table->entries[i].type);
12175 ibf_dump_write_small_value(dump, table->entries[i].start);
12176 ibf_dump_write_small_value(dump, table->entries[i].end);
12177 ibf_dump_write_small_value(dump, table->entries[i].cont);
12178 ibf_dump_write_small_value(dump, table->entries[i].sp);
12179 }
12180 return offset;
12181 }
12182 else {
12183 return ibf_dump_pos(dump);
12184 }
12185}
12186
12187static struct iseq_catch_table *
12188ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
12189{
12190 if (size) {
12191 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
12192 table->size = size;
12193
12194 ibf_offset_t reading_pos = catch_table_offset;
12195
12196 unsigned int i;
12197 for (i=0; i<table->size; i++) {
12198 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12199 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
12200 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
12201 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
12202 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
12203 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
12204
12205 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
12206 }
12207 return table;
12208 }
12209 else {
12210 return NULL;
12211 }
12212}
12213
12214static ibf_offset_t
12215ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
12216{
12217 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12218 const unsigned int ci_size = body->ci_size;
12219 const struct rb_call_data *cds = body->call_data;
12220
12221 ibf_offset_t offset = ibf_dump_pos(dump);
12222
12223 unsigned int i;
12224
12225 for (i = 0; i < ci_size; i++) {
12226 const struct rb_callinfo *ci = cds[i].ci;
12227 if (ci != NULL) {
12228 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
12229 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
12230 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
12231
12232 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
12233 if (kwarg) {
12234 int len = kwarg->keyword_len;
12235 ibf_dump_write_small_value(dump, len);
12236 for (int j=0; j<len; j++) {
12237 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
12238 ibf_dump_write_small_value(dump, keyword);
12239 }
12240 }
12241 else {
12242 ibf_dump_write_small_value(dump, 0);
12243 }
12244 }
12245 else {
12246 // TODO: truncate NULL ci from call_data.
12247 ibf_dump_write_small_value(dump, (VALUE)-1);
12248 }
12249 }
12250
12251 return offset;
12252}
12253
12255 ID id;
12256 VALUE name;
12257 VALUE val;
12258};
12259
12261 size_t num;
12262 struct outer_variable_pair pairs[1];
12263};
12264
12265static enum rb_id_table_iterator_result
12266store_outer_variable(ID id, VALUE val, void *dump)
12267{
12268 struct outer_variable_list *ovlist = dump;
12269 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
12270 pair->id = id;
12271 pair->name = rb_id2str(id);
12272 pair->val = val;
12273 return ID_TABLE_CONTINUE;
12274}
12275
12276static int
12277outer_variable_cmp(const void *a, const void *b, void *arg)
12278{
12279 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
12280 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
12281 return rb_str_cmp(ap->name, bp->name);
12282}
12283
12284static ibf_offset_t
12285ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
12286{
12287 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
12288
12289 ibf_offset_t offset = ibf_dump_pos(dump);
12290
12291 size_t size = ovs ? rb_id_table_size(ovs) : 0;
12292 ibf_dump_write_small_value(dump, (VALUE)size);
12293 if (size > 0) {
12294 VALUE buff;
12295 size_t buffsize =
12296 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
12297 offsetof(struct outer_variable_list, pairs),
12298 rb_eArgError);
12299 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
12300 ovlist->num = 0;
12301 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
12302 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
12303 for (size_t i = 0; i < size; ++i) {
12304 ID id = ovlist->pairs[i].id;
12305 ID val = ovlist->pairs[i].val;
12306 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
12307 ibf_dump_write_small_value(dump, val);
12308 }
12309 }
12310
12311 return offset;
12312}
12313
12314/* note that we dump out rb_call_info but load back rb_call_data */
12315static void
12316ibf_load_ci_entries(const struct ibf_load *load,
12317 ibf_offset_t ci_entries_offset,
12318 unsigned int ci_size,
12319 struct rb_call_data **cd_ptr)
12320{
12321 ibf_offset_t reading_pos = ci_entries_offset;
12322
12323 unsigned int i;
12324
12325 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
12326 *cd_ptr = cds;
12327
12328 for (i = 0; i < ci_size; i++) {
12329 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
12330 if (mid_index != (VALUE)-1) {
12331 ID mid = ibf_load_id(load, mid_index);
12332 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
12333 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
12334
12335 struct rb_callinfo_kwarg *kwarg = NULL;
12336 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
12337 if (kwlen > 0) {
12338 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
12339 kwarg->references = 0;
12340 kwarg->keyword_len = kwlen;
12341 for (int j=0; j<kwlen; j++) {
12342 VALUE keyword = ibf_load_small_value(load, &reading_pos);
12343 kwarg->keywords[j] = ibf_load_object(load, keyword);
12344 }
12345 }
12346
12347 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
12348 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
12349 cds[i].cc = vm_cc_empty();
12350 }
12351 else {
12352 // NULL ci
12353 cds[i].ci = NULL;
12354 cds[i].cc = NULL;
12355 }
12356 }
12357}
12358
12359static struct rb_id_table *
12360ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
12361{
12362 ibf_offset_t reading_pos = outer_variables_offset;
12363
12364 struct rb_id_table *tbl = NULL;
12365
12366 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
12367
12368 if (table_size > 0) {
12369 tbl = rb_id_table_create(table_size);
12370 }
12371
12372 for (size_t i = 0; i < table_size; i++) {
12373 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
12374 VALUE value = ibf_load_small_value(load, &reading_pos);
12375 if (!key) key = rb_make_temporary_id(i);
12376 rb_id_table_insert(tbl, key, value);
12377 }
12378
12379 return tbl;
12380}
12381
12382static ibf_offset_t
12383ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
12384{
12385 assert(dump->current_buffer == &dump->global_buffer);
12386
12387 unsigned int *positions;
12388
12389 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12390
12391 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
12392 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
12393 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
12394
12395#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12396 ibf_offset_t iseq_start = ibf_dump_pos(dump);
12397
12398 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
12399 struct ibf_dump_buffer buffer;
12400 buffer.str = rb_str_new(0, 0);
12401 buffer.obj_table = ibf_dump_object_table_new();
12402 dump->current_buffer = &buffer;
12403#endif
12404
12405 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
12406 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
12407 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
12408 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
12409 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
12410
12411 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
12412 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
12413 ruby_xfree(positions);
12414
12415 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
12416 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
12417 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
12418 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
12419 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
12420 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
12421 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
12422 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
12423
12424#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12425 ibf_offset_t local_obj_list_offset;
12426 unsigned int local_obj_list_size;
12427
12428 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
12429#endif
12430
12431 ibf_offset_t body_offset = ibf_dump_pos(dump);
12432
12433 /* dump the constant body */
12434 unsigned int param_flags =
12435 (body->param.flags.has_lead << 0) |
12436 (body->param.flags.has_opt << 1) |
12437 (body->param.flags.has_rest << 2) |
12438 (body->param.flags.has_post << 3) |
12439 (body->param.flags.has_kw << 4) |
12440 (body->param.flags.has_kwrest << 5) |
12441 (body->param.flags.has_block << 6) |
12442 (body->param.flags.ambiguous_param0 << 7) |
12443 (body->param.flags.accepts_no_kwarg << 8) |
12444 (body->param.flags.ruby2_keywords << 9);
12445
12446#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12447# define IBF_BODY_OFFSET(x) (x)
12448#else
12449# define IBF_BODY_OFFSET(x) (body_offset - (x))
12450#endif
12451
12452 ibf_dump_write_small_value(dump, body->type);
12453 ibf_dump_write_small_value(dump, body->iseq_size);
12454 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
12455 ibf_dump_write_small_value(dump, bytecode_size);
12456 ibf_dump_write_small_value(dump, param_flags);
12457 ibf_dump_write_small_value(dump, body->param.size);
12458 ibf_dump_write_small_value(dump, body->param.lead_num);
12459 ibf_dump_write_small_value(dump, body->param.opt_num);
12460 ibf_dump_write_small_value(dump, body->param.rest_start);
12461 ibf_dump_write_small_value(dump, body->param.post_start);
12462 ibf_dump_write_small_value(dump, body->param.post_num);
12463 ibf_dump_write_small_value(dump, body->param.block_start);
12464 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
12465 ibf_dump_write_small_value(dump, param_keyword_offset);
12466 ibf_dump_write_small_value(dump, location_pathobj_index);
12467 ibf_dump_write_small_value(dump, location_base_label_index);
12468 ibf_dump_write_small_value(dump, location_label_index);
12469 ibf_dump_write_small_value(dump, body->location.first_lineno);
12470 ibf_dump_write_small_value(dump, body->location.node_id);
12471 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
12472 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
12473 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
12474 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
12475 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
12476 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
12477 ibf_dump_write_small_value(dump, body->insns_info.size);
12478 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
12479 ibf_dump_write_small_value(dump, catch_table_size);
12480 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
12481 ibf_dump_write_small_value(dump, parent_iseq_index);
12482 ibf_dump_write_small_value(dump, local_iseq_index);
12483 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
12484 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
12485 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
12486 ibf_dump_write_small_value(dump, body->variable.flip_count);
12487 ibf_dump_write_small_value(dump, body->local_table_size);
12488 ibf_dump_write_small_value(dump, body->ivc_size);
12489 ibf_dump_write_small_value(dump, body->icvarc_size);
12490 ibf_dump_write_small_value(dump, body->ise_size);
12491 ibf_dump_write_small_value(dump, body->ic_size);
12492 ibf_dump_write_small_value(dump, body->ci_size);
12493 ibf_dump_write_small_value(dump, body->stack_max);
12494 ibf_dump_write_small_value(dump, body->builtin_attrs);
12495
12496#undef IBF_BODY_OFFSET
12497
12498#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12499 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
12500
12501 dump->current_buffer = saved_buffer;
12502 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
12503
12504 ibf_offset_t offset = ibf_dump_pos(dump);
12505 ibf_dump_write_small_value(dump, iseq_start);
12506 ibf_dump_write_small_value(dump, iseq_length_bytes);
12507 ibf_dump_write_small_value(dump, body_offset);
12508
12509 ibf_dump_write_small_value(dump, local_obj_list_offset);
12510 ibf_dump_write_small_value(dump, local_obj_list_size);
12511
12512 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
12513
12514 return offset;
12515#else
12516 return body_offset;
12517#endif
12518}
12519
12520static VALUE
12521ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
12522{
12523 VALUE str = ibf_load_object(load, str_index);
12524 if (str != Qnil) {
12525 str = rb_fstring(str);
12526 }
12527 return str;
12528}
12529
12530static void
12531ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
12532{
12533 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
12534
12535 ibf_offset_t reading_pos = offset;
12536
12537#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12538 struct ibf_load_buffer *saved_buffer = load->current_buffer;
12539 load->current_buffer = &load->global_buffer;
12540
12541 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12542 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12543 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12544
12545 struct ibf_load_buffer buffer;
12546 buffer.buff = load->global_buffer.buff + iseq_start;
12547 buffer.size = iseq_length_bytes;
12548 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12549 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12550 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
12551
12552 load->current_buffer = &buffer;
12553 reading_pos = body_offset;
12554#endif
12555
12556#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12557# define IBF_BODY_OFFSET(x) (x)
12558#else
12559# define IBF_BODY_OFFSET(x) (offset - (x))
12560#endif
12561
12562 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
12563 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12564 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12565 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12566 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
12567 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12568 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
12569 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
12570 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
12571 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
12572 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
12573 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
12574 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12575 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12576 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
12577 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
12578 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
12579 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
12580 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
12581 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12582 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12583 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12584 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12585 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12586 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12587 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12588 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12589 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12590 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12591 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12592 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12593 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12594 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12595 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12596 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
12597 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12598
12599 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12600 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12601 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12602 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12603
12604 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12605 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
12606 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
12607
12608 // setup fname and dummy frame
12609 VALUE path = ibf_load_object(load, location_pathobj_index);
12610 {
12611 VALUE realpath = Qnil;
12612
12613 if (RB_TYPE_P(path, T_STRING)) {
12614 realpath = path = rb_fstring(path);
12615 }
12616 else if (RB_TYPE_P(path, T_ARRAY)) {
12617 VALUE pathobj = path;
12618 if (RARRAY_LEN(pathobj) != 2) {
12619 rb_raise(rb_eRuntimeError, "path object size mismatch");
12620 }
12621 path = rb_fstring(RARRAY_AREF(pathobj, 0));
12622 realpath = RARRAY_AREF(pathobj, 1);
12623 if (!NIL_P(realpath)) {
12624 if (!RB_TYPE_P(realpath, T_STRING)) {
12625 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
12626 "(%x), path=%+"PRIsVALUE,
12627 realpath, TYPE(realpath), path);
12628 }
12629 realpath = rb_fstring(realpath);
12630 }
12631 }
12632 else {
12633 rb_raise(rb_eRuntimeError, "unexpected path object");
12634 }
12635 rb_iseq_pathobj_set(iseq, path, realpath);
12636 }
12637
12638 // push dummy frame
12639 rb_execution_context_t *ec = GET_EC();
12640 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
12641
12642#undef IBF_BODY_OFFSET
12643
12644 load_body->type = type;
12645 load_body->stack_max = stack_max;
12646 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
12647 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
12648 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
12649 load_body->param.flags.has_post = (param_flags >> 3) & 1;
12650 load_body->param.flags.has_kw = FALSE;
12651 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
12652 load_body->param.flags.has_block = (param_flags >> 6) & 1;
12653 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
12654 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
12655 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
12656 load_body->param.size = param_size;
12657 load_body->param.lead_num = param_lead_num;
12658 load_body->param.opt_num = param_opt_num;
12659 load_body->param.rest_start = param_rest_start;
12660 load_body->param.post_start = param_post_start;
12661 load_body->param.post_num = param_post_num;
12662 load_body->param.block_start = param_block_start;
12663 load_body->local_table_size = local_table_size;
12664 load_body->ci_size = ci_size;
12665 load_body->insns_info.size = insns_info_size;
12666
12667 ISEQ_COVERAGE_SET(iseq, Qnil);
12668 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
12669 load_body->variable.flip_count = variable_flip_count;
12670 load_body->variable.script_lines = Qnil;
12671
12672 load_body->location.first_lineno = location_first_lineno;
12673 load_body->location.node_id = location_node_id;
12674 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
12675 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
12676 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
12677 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
12678 load_body->builtin_attrs = builtin_attrs;
12679
12680 load_body->ivc_size = ivc_size;
12681 load_body->icvarc_size = icvarc_size;
12682 load_body->ise_size = ise_size;
12683 load_body->ic_size = ic_size;
12684
12685 if (ISEQ_IS_SIZE(load_body)) {
12686 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
12687 }
12688 else {
12689 load_body->is_entries = NULL;
12690 }
12691 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
12692 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
12693 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
12694 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
12695 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
12696 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
12697 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
12698 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
12699 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
12700 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
12701 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
12702 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
12703
12704 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
12705#if VM_INSN_INFO_TABLE_IMPL == 2
12706 rb_iseq_insns_info_encode_positions(iseq);
12707#endif
12708
12709 rb_iseq_translate_threaded_code(iseq);
12710
12711#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12712 load->current_buffer = &load->global_buffer;
12713#endif
12714
12715 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
12716 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
12717
12718#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12719 load->current_buffer = saved_buffer;
12720#endif
12721 verify_call_cache(iseq);
12722
12723 RB_GC_GUARD(dummy_frame);
12724 rb_vm_pop_frame_no_int(ec);
12725}
12726
12728{
12729 struct ibf_dump *dump;
12730 VALUE offset_list;
12731};
12732
12733static int
12734ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12735{
12736 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
12737 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
12738
12739 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
12740 rb_ary_push(args->offset_list, UINT2NUM(offset));
12741
12742 return ST_CONTINUE;
12743}
12744
12745static void
12746ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
12747{
12748 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
12749
12750 struct ibf_dump_iseq_list_arg args;
12751 args.dump = dump;
12752 args.offset_list = offset_list;
12753
12754 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
12755
12756 st_index_t i;
12757 st_index_t size = dump->iseq_table->num_entries;
12758 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
12759
12760 for (i = 0; i < size; i++) {
12761 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
12762 }
12763
12764 ibf_dump_align(dump, sizeof(ibf_offset_t));
12765 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
12766 header->iseq_list_size = (unsigned int)size;
12767}
12768
12769#define IBF_OBJECT_INTERNAL FL_PROMOTED0
12770
12771/*
12772 * Binary format
12773 * - ibf_object_header
12774 * - ibf_object_xxx (xxx is type)
12775 */
12776
12778 unsigned int type: 5;
12779 unsigned int special_const: 1;
12780 unsigned int frozen: 1;
12781 unsigned int internal: 1;
12782};
12783
12784enum ibf_object_class_index {
12785 IBF_OBJECT_CLASS_OBJECT,
12786 IBF_OBJECT_CLASS_ARRAY,
12787 IBF_OBJECT_CLASS_STANDARD_ERROR,
12788 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
12789 IBF_OBJECT_CLASS_TYPE_ERROR,
12790 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
12791};
12792
12794 long srcstr;
12795 char option;
12796};
12797
12799 long len;
12800 long keyval[FLEX_ARY_LEN];
12801};
12802
12804 long class_index;
12805 long len;
12806 long beg;
12807 long end;
12808 int excl;
12809};
12810
12812 ssize_t slen;
12813 BDIGIT digits[FLEX_ARY_LEN];
12814};
12815
12816enum ibf_object_data_type {
12817 IBF_OBJECT_DATA_ENCODING,
12818};
12819
12821 long a, b;
12822};
12823
12825 long str;
12826};
12827
12828#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
12829 ((((offset) - 1) / (align) + 1) * (align))
12830#define IBF_OBJBODY(type, offset) (const type *)\
12831 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12832
12833static const void *
12834ibf_load_check_offset(const struct ibf_load *load, size_t offset)
12835{
12836 if (offset >= load->current_buffer->size) {
12837 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
12838 }
12839 return load->current_buffer->buff + offset;
12840}
12841
12842NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
12843
12844static void
12845ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
12846{
12847 char buff[0x100];
12848 rb_raw_obj_info(buff, sizeof(buff), obj);
12849 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
12850}
12851
12852NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
12853
12854static VALUE
12855ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12856{
12857 rb_raise(rb_eArgError, "unsupported");
12859}
12860
12861static void
12862ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
12863{
12864 enum ibf_object_class_index cindex;
12865 if (obj == rb_cObject) {
12866 cindex = IBF_OBJECT_CLASS_OBJECT;
12867 }
12868 else if (obj == rb_cArray) {
12869 cindex = IBF_OBJECT_CLASS_ARRAY;
12870 }
12871 else if (obj == rb_eStandardError) {
12872 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12873 }
12874 else if (obj == rb_eNoMatchingPatternError) {
12875 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12876 }
12877 else if (obj == rb_eTypeError) {
12878 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12879 }
12880 else if (obj == rb_eNoMatchingPatternKeyError) {
12881 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12882 }
12883 else {
12884 rb_obj_info_dump(obj);
12885 rb_p(obj);
12886 rb_bug("unsupported class");
12887 }
12888 ibf_dump_write_small_value(dump, (VALUE)cindex);
12889}
12890
12891static VALUE
12892ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12893{
12894 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12895
12896 switch (cindex) {
12897 case IBF_OBJECT_CLASS_OBJECT:
12898 return rb_cObject;
12899 case IBF_OBJECT_CLASS_ARRAY:
12900 return rb_cArray;
12901 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12902 return rb_eStandardError;
12903 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12905 case IBF_OBJECT_CLASS_TYPE_ERROR:
12906 return rb_eTypeError;
12907 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12909 }
12910
12911 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
12912}
12913
12914
12915static void
12916ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
12917{
12918 double dbl = RFLOAT_VALUE(obj);
12919 (void)IBF_W(&dbl, double, 1);
12920}
12921
12922static VALUE
12923ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12924{
12925 const double *dblp = IBF_OBJBODY(double, offset);
12926 return DBL2NUM(*dblp);
12927}
12928
12929static void
12930ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
12931{
12932 long encindex = (long)rb_enc_get_index(obj);
12933 long len = RSTRING_LEN(obj);
12934 const char *ptr = RSTRING_PTR(obj);
12935
12936 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12937 rb_encoding *enc = rb_enc_from_index((int)encindex);
12938 const char *enc_name = rb_enc_name(enc);
12939 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
12940 }
12941
12942 ibf_dump_write_small_value(dump, encindex);
12943 ibf_dump_write_small_value(dump, len);
12944 IBF_WP(ptr, char, len);
12945}
12946
12947static VALUE
12948ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12949{
12950 ibf_offset_t reading_pos = offset;
12951
12952 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12953 const long len = (long)ibf_load_small_value(load, &reading_pos);
12954 const char *ptr = load->current_buffer->buff + reading_pos;
12955
12956 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12957 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12958 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12959 }
12960
12961 VALUE str;
12962 if (header->frozen && !header->internal) {
12963 str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
12964 }
12965 else {
12966 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
12967
12968 if (header->internal) rb_obj_hide(str);
12969 if (header->frozen) str = rb_fstring(str);
12970 }
12971 return str;
12972}
12973
12974static void
12975ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
12976{
12977 VALUE srcstr = RREGEXP_SRC(obj);
12978 struct ibf_object_regexp regexp;
12979 regexp.option = (char)rb_reg_options(obj);
12980 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12981
12982 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
12983 ibf_dump_write_small_value(dump, regexp.srcstr);
12984}
12985
12986static VALUE
12987ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12988{
12989 struct ibf_object_regexp regexp;
12990 regexp.option = ibf_load_byte(load, &offset);
12991 regexp.srcstr = ibf_load_small_value(load, &offset);
12992
12993 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12994 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
12995
12996 if (header->internal) rb_obj_hide(reg);
12997 if (header->frozen) rb_obj_freeze(reg);
12998
12999 return reg;
13000}
13001
13002static void
13003ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
13004{
13005 long i, len = RARRAY_LEN(obj);
13006 ibf_dump_write_small_value(dump, len);
13007 for (i=0; i<len; i++) {
13008 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
13009 ibf_dump_write_small_value(dump, index);
13010 }
13011}
13012
13013static VALUE
13014ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13015{
13016 ibf_offset_t reading_pos = offset;
13017
13018 const long len = (long)ibf_load_small_value(load, &reading_pos);
13019
13020 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
13021 int i;
13022
13023 for (i=0; i<len; i++) {
13024 const VALUE index = ibf_load_small_value(load, &reading_pos);
13025 rb_ary_push(ary, ibf_load_object(load, index));
13026 }
13027
13028 if (header->frozen) rb_obj_freeze(ary);
13029
13030 return ary;
13031}
13032
13033static int
13034ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
13035{
13036 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13037
13038 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
13039 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
13040
13041 ibf_dump_write_small_value(dump, key_index);
13042 ibf_dump_write_small_value(dump, val_index);
13043 return ST_CONTINUE;
13044}
13045
13046static void
13047ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
13048{
13049 long len = RHASH_SIZE(obj);
13050 ibf_dump_write_small_value(dump, (VALUE)len);
13051
13052 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
13053}
13054
13055static VALUE
13056ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13057{
13058 long len = (long)ibf_load_small_value(load, &offset);
13059 VALUE obj = rb_hash_new_with_size(len);
13060 int i;
13061
13062 for (i = 0; i < len; i++) {
13063 VALUE key_index = ibf_load_small_value(load, &offset);
13064 VALUE val_index = ibf_load_small_value(load, &offset);
13065
13066 VALUE key = ibf_load_object(load, key_index);
13067 VALUE val = ibf_load_object(load, val_index);
13068 rb_hash_aset(obj, key, val);
13069 }
13070 rb_hash_rehash(obj);
13071
13072 if (header->internal) rb_obj_hide(obj);
13073 if (header->frozen) rb_obj_freeze(obj);
13074
13075 return obj;
13076}
13077
13078static void
13079ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
13080{
13081 if (rb_obj_is_kind_of(obj, rb_cRange)) {
13082 struct ibf_object_struct_range range;
13083 VALUE beg, end;
13084 IBF_ZERO(range);
13085 range.len = 3;
13086 range.class_index = 0;
13087
13088 rb_range_values(obj, &beg, &end, &range.excl);
13089 range.beg = (long)ibf_dump_object(dump, beg);
13090 range.end = (long)ibf_dump_object(dump, end);
13091
13092 IBF_W_ALIGN(struct ibf_object_struct_range);
13093 IBF_WV(range);
13094 }
13095 else {
13096 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
13097 rb_class_name(CLASS_OF(obj)));
13098 }
13099}
13100
13101static VALUE
13102ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13103{
13104 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
13105 VALUE beg = ibf_load_object(load, range->beg);
13106 VALUE end = ibf_load_object(load, range->end);
13107 VALUE obj = rb_range_new(beg, end, range->excl);
13108 if (header->internal) rb_obj_hide(obj);
13109 if (header->frozen) rb_obj_freeze(obj);
13110 return obj;
13111}
13112
13113static void
13114ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
13115{
13116 ssize_t len = BIGNUM_LEN(obj);
13117 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
13118 BDIGIT *d = BIGNUM_DIGITS(obj);
13119
13120 (void)IBF_W(&slen, ssize_t, 1);
13121 IBF_WP(d, BDIGIT, len);
13122}
13123
13124static VALUE
13125ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13126{
13127 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
13128 int sign = bignum->slen > 0;
13129 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
13130 const int big_unpack_flags = /* c.f. rb_big_unpack() */
13133 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
13134 big_unpack_flags |
13135 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
13136 if (header->internal) rb_obj_hide(obj);
13137 if (header->frozen) rb_obj_freeze(obj);
13138 return obj;
13139}
13140
13141static void
13142ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
13143{
13144 if (rb_data_is_encoding(obj)) {
13145 rb_encoding *enc = rb_to_encoding(obj);
13146 const char *name = rb_enc_name(enc);
13147 long len = strlen(name) + 1;
13148 long data[2];
13149 data[0] = IBF_OBJECT_DATA_ENCODING;
13150 data[1] = len;
13151 (void)IBF_W(data, long, 2);
13152 IBF_WP(name, char, len);
13153 }
13154 else {
13155 ibf_dump_object_unsupported(dump, obj);
13156 }
13157}
13158
13159static VALUE
13160ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13161{
13162 const long *body = IBF_OBJBODY(long, offset);
13163 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
13164 /* const long len = body[1]; */
13165 const char *data = (const char *)&body[2];
13166
13167 switch (type) {
13168 case IBF_OBJECT_DATA_ENCODING:
13169 {
13170 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
13171 return encobj;
13172 }
13173 }
13174
13175 return ibf_load_object_unsupported(load, header, offset);
13176}
13177
13178static void
13179ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
13180{
13181 long data[2];
13182 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
13183 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
13184
13185 (void)IBF_W(data, long, 2);
13186}
13187
13188static VALUE
13189ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13190{
13191 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
13192 VALUE a = ibf_load_object(load, nums->a);
13193 VALUE b = ibf_load_object(load, nums->b);
13194 VALUE obj = header->type == T_COMPLEX ?
13195 rb_complex_new(a, b) : rb_rational_new(a, b);
13196
13197 if (header->internal) rb_obj_hide(obj);
13198 if (header->frozen) rb_obj_freeze(obj);
13199 return obj;
13200}
13201
13202static void
13203ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
13204{
13205 ibf_dump_object_string(dump, rb_sym2str(obj));
13206}
13207
13208static VALUE
13209ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13210{
13211 ibf_offset_t reading_pos = offset;
13212
13213 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13214 const long len = (long)ibf_load_small_value(load, &reading_pos);
13215 const char *ptr = load->current_buffer->buff + reading_pos;
13216
13217 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13218 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13219 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13220 }
13221
13222 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
13223 return ID2SYM(id);
13224}
13225
13226typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
13227static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
13228 ibf_dump_object_unsupported, /* T_NONE */
13229 ibf_dump_object_unsupported, /* T_OBJECT */
13230 ibf_dump_object_class, /* T_CLASS */
13231 ibf_dump_object_unsupported, /* T_MODULE */
13232 ibf_dump_object_float, /* T_FLOAT */
13233 ibf_dump_object_string, /* T_STRING */
13234 ibf_dump_object_regexp, /* T_REGEXP */
13235 ibf_dump_object_array, /* T_ARRAY */
13236 ibf_dump_object_hash, /* T_HASH */
13237 ibf_dump_object_struct, /* T_STRUCT */
13238 ibf_dump_object_bignum, /* T_BIGNUM */
13239 ibf_dump_object_unsupported, /* T_FILE */
13240 ibf_dump_object_data, /* T_DATA */
13241 ibf_dump_object_unsupported, /* T_MATCH */
13242 ibf_dump_object_complex_rational, /* T_COMPLEX */
13243 ibf_dump_object_complex_rational, /* T_RATIONAL */
13244 ibf_dump_object_unsupported, /* 0x10 */
13245 ibf_dump_object_unsupported, /* 0x11 T_NIL */
13246 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
13247 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
13248 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
13249 ibf_dump_object_unsupported, /* T_FIXNUM */
13250 ibf_dump_object_unsupported, /* T_UNDEF */
13251 ibf_dump_object_unsupported, /* 0x17 */
13252 ibf_dump_object_unsupported, /* 0x18 */
13253 ibf_dump_object_unsupported, /* 0x19 */
13254 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
13255 ibf_dump_object_unsupported, /* T_NODE 0x1b */
13256 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
13257 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
13258 ibf_dump_object_unsupported, /* 0x1e */
13259 ibf_dump_object_unsupported, /* 0x1f */
13260};
13261
13262static void
13263ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
13264{
13265 unsigned char byte =
13266 (header.type << 0) |
13267 (header.special_const << 5) |
13268 (header.frozen << 6) |
13269 (header.internal << 7);
13270
13271 IBF_WV(byte);
13272}
13273
13274static struct ibf_object_header
13275ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
13276{
13277 unsigned char byte = ibf_load_byte(load, offset);
13278
13279 struct ibf_object_header header;
13280 header.type = (byte >> 0) & 0x1f;
13281 header.special_const = (byte >> 5) & 0x01;
13282 header.frozen = (byte >> 6) & 0x01;
13283 header.internal = (byte >> 7) & 0x01;
13284
13285 return header;
13286}
13287
13288static ibf_offset_t
13289ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
13290{
13291 struct ibf_object_header obj_header;
13292 ibf_offset_t current_offset;
13293 IBF_ZERO(obj_header);
13294 obj_header.type = TYPE(obj);
13295
13296 IBF_W_ALIGN(ibf_offset_t);
13297 current_offset = ibf_dump_pos(dump);
13298
13299 if (SPECIAL_CONST_P(obj) &&
13300 ! (SYMBOL_P(obj) ||
13301 RB_FLOAT_TYPE_P(obj))) {
13302 obj_header.special_const = TRUE;
13303 obj_header.frozen = TRUE;
13304 obj_header.internal = TRUE;
13305 ibf_dump_object_object_header(dump, obj_header);
13306 ibf_dump_write_small_value(dump, obj);
13307 }
13308 else {
13309 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
13310 obj_header.special_const = FALSE;
13311 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
13312 ibf_dump_object_object_header(dump, obj_header);
13313 (*dump_object_functions[obj_header.type])(dump, obj);
13314 }
13315
13316 return current_offset;
13317}
13318
13319typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
13320static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
13321 ibf_load_object_unsupported, /* T_NONE */
13322 ibf_load_object_unsupported, /* T_OBJECT */
13323 ibf_load_object_class, /* T_CLASS */
13324 ibf_load_object_unsupported, /* T_MODULE */
13325 ibf_load_object_float, /* T_FLOAT */
13326 ibf_load_object_string, /* T_STRING */
13327 ibf_load_object_regexp, /* T_REGEXP */
13328 ibf_load_object_array, /* T_ARRAY */
13329 ibf_load_object_hash, /* T_HASH */
13330 ibf_load_object_struct, /* T_STRUCT */
13331 ibf_load_object_bignum, /* T_BIGNUM */
13332 ibf_load_object_unsupported, /* T_FILE */
13333 ibf_load_object_data, /* T_DATA */
13334 ibf_load_object_unsupported, /* T_MATCH */
13335 ibf_load_object_complex_rational, /* T_COMPLEX */
13336 ibf_load_object_complex_rational, /* T_RATIONAL */
13337 ibf_load_object_unsupported, /* 0x10 */
13338 ibf_load_object_unsupported, /* T_NIL */
13339 ibf_load_object_unsupported, /* T_TRUE */
13340 ibf_load_object_unsupported, /* T_FALSE */
13341 ibf_load_object_symbol,
13342 ibf_load_object_unsupported, /* T_FIXNUM */
13343 ibf_load_object_unsupported, /* T_UNDEF */
13344 ibf_load_object_unsupported, /* 0x17 */
13345 ibf_load_object_unsupported, /* 0x18 */
13346 ibf_load_object_unsupported, /* 0x19 */
13347 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
13348 ibf_load_object_unsupported, /* T_NODE 0x1b */
13349 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
13350 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
13351 ibf_load_object_unsupported, /* 0x1e */
13352 ibf_load_object_unsupported, /* 0x1f */
13353};
13354
13355static VALUE
13356ibf_load_object(const struct ibf_load *load, VALUE object_index)
13357{
13358 if (object_index == 0) {
13359 return Qnil;
13360 }
13361 else {
13362 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
13363 if (!obj) {
13364 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
13365 ibf_offset_t offset = offsets[object_index];
13366 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
13367
13368#if IBF_ISEQ_DEBUG
13369 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
13370 load->current_buffer->obj_list_offset, (void *)offsets, offset);
13371 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
13372 header.type, header.special_const, header.frozen, header.internal);
13373#endif
13374 if (offset >= load->current_buffer->size) {
13375 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
13376 }
13377
13378 if (header.special_const) {
13379 ibf_offset_t reading_pos = offset;
13380
13381 obj = ibf_load_small_value(load, &reading_pos);
13382 }
13383 else {
13384 obj = (*load_object_functions[header.type])(load, &header, offset);
13385 }
13386
13387 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
13388 }
13389#if IBF_ISEQ_DEBUG
13390 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
13391 object_index, obj);
13392#endif
13393 return obj;
13394 }
13395}
13396
13398{
13399 struct ibf_dump *dump;
13400 VALUE offset_list;
13401};
13402
13403static int
13404ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13405{
13406 VALUE obj = (VALUE)key;
13407 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
13408
13409 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
13410 rb_ary_push(args->offset_list, UINT2NUM(offset));
13411
13412 return ST_CONTINUE;
13413}
13414
13415static void
13416ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
13417{
13418 st_table *obj_table = dump->current_buffer->obj_table;
13419 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
13420
13421 struct ibf_dump_object_list_arg args;
13422 args.dump = dump;
13423 args.offset_list = offset_list;
13424
13425 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
13426
13427 IBF_W_ALIGN(ibf_offset_t);
13428 *obj_list_offset = ibf_dump_pos(dump);
13429
13430 st_index_t size = obj_table->num_entries;
13431 st_index_t i;
13432
13433 for (i=0; i<size; i++) {
13434 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
13435 IBF_WV(offset);
13436 }
13437
13438 *obj_list_size = (unsigned int)size;
13439}
13440
13441static void
13442ibf_dump_mark(void *ptr)
13443{
13444 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13445 rb_gc_mark(dump->global_buffer.str);
13446
13447 rb_mark_set(dump->global_buffer.obj_table);
13448 rb_mark_set(dump->iseq_table);
13449}
13450
13451static void
13452ibf_dump_free(void *ptr)
13453{
13454 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13455 if (dump->global_buffer.obj_table) {
13456 st_free_table(dump->global_buffer.obj_table);
13457 dump->global_buffer.obj_table = 0;
13458 }
13459 if (dump->iseq_table) {
13460 st_free_table(dump->iseq_table);
13461 dump->iseq_table = 0;
13462 }
13463}
13464
13465static size_t
13466ibf_dump_memsize(const void *ptr)
13467{
13468 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13469 size_t size = 0;
13470 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
13471 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
13472 return size;
13473}
13474
13475static const rb_data_type_t ibf_dump_type = {
13476 "ibf_dump",
13477 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
13478 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
13479};
13480
13481static void
13482ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
13483{
13484 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
13485 dump->iseq_table = NULL;
13486
13487 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
13488 dump->global_buffer.obj_table = ibf_dump_object_table_new();
13489 dump->iseq_table = st_init_numtable(); /* need free */
13490
13491 dump->current_buffer = &dump->global_buffer;
13492}
13493
13494VALUE
13495rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
13496{
13497 struct ibf_dump *dump;
13498 struct ibf_header header = {{0}};
13499 VALUE dump_obj;
13500 VALUE str;
13501
13502 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
13503 ISEQ_BODY(iseq)->local_iseq != iseq) {
13504 rb_raise(rb_eRuntimeError, "should be top of iseq");
13505 }
13506 if (RTEST(ISEQ_COVERAGE(iseq))) {
13507 rb_raise(rb_eRuntimeError, "should not compile with coverage");
13508 }
13509
13510 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
13511 ibf_dump_setup(dump, dump_obj);
13512
13513 ibf_dump_write(dump, &header, sizeof(header));
13514 ibf_dump_iseq(dump, iseq);
13515
13516 header.magic[0] = 'Y'; /* YARB */
13517 header.magic[1] = 'A';
13518 header.magic[2] = 'R';
13519 header.magic[3] = 'B';
13520 header.major_version = IBF_MAJOR_VERSION;
13521 header.minor_version = IBF_MINOR_VERSION;
13522 header.endian = IBF_ENDIAN_MARK;
13523 header.wordsize = (uint8_t)SIZEOF_VALUE;
13524 ibf_dump_iseq_list(dump, &header);
13525 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
13526 header.size = ibf_dump_pos(dump);
13527
13528 if (RTEST(opt)) {
13529 VALUE opt_str = opt;
13530 const char *ptr = StringValuePtr(opt_str);
13531 header.extra_size = RSTRING_LENINT(opt_str);
13532 ibf_dump_write(dump, ptr, header.extra_size);
13533 }
13534 else {
13535 header.extra_size = 0;
13536 }
13537
13538 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
13539
13540 str = dump->global_buffer.str;
13541 RB_GC_GUARD(dump_obj);
13542 return str;
13543}
13544
13545static const ibf_offset_t *
13546ibf_iseq_list(const struct ibf_load *load)
13547{
13548 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
13549}
13550
13551void
13552rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
13553{
13554 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
13555 rb_iseq_t *prev_src_iseq = load->iseq;
13556 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
13557 load->iseq = iseq;
13558#if IBF_ISEQ_DEBUG
13559 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
13560 iseq->aux.loader.index, offset,
13561 load->header->size);
13562#endif
13563 ibf_load_iseq_each(load, iseq, offset);
13564 ISEQ_COMPILE_DATA_CLEAR(iseq);
13565 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13566 rb_iseq_init_trace(iseq);
13567 load->iseq = prev_src_iseq;
13568}
13569
13570#if USE_LAZY_LOAD
13571const rb_iseq_t *
13572rb_iseq_complete(const rb_iseq_t *iseq)
13573{
13574 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
13575 return iseq;
13576}
13577#endif
13578
13579static rb_iseq_t *
13580ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
13581{
13582 int iseq_index = (int)(VALUE)index_iseq;
13583
13584#if IBF_ISEQ_DEBUG
13585 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
13586 (void *)index_iseq, (void *)load->iseq_list);
13587#endif
13588 if (iseq_index == -1) {
13589 return NULL;
13590 }
13591 else {
13592 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
13593
13594#if IBF_ISEQ_DEBUG
13595 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
13596#endif
13597 if (iseqv) {
13598 return (rb_iseq_t *)iseqv;
13599 }
13600 else {
13601 rb_iseq_t *iseq = iseq_imemo_alloc();
13602#if IBF_ISEQ_DEBUG
13603 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
13604#endif
13605 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13606 iseq->aux.loader.obj = load->loader_obj;
13607 iseq->aux.loader.index = iseq_index;
13608#if IBF_ISEQ_DEBUG
13609 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
13610 (void *)iseq, (void *)load->loader_obj, iseq_index);
13611#endif
13612 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
13613
13614 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
13615#if IBF_ISEQ_DEBUG
13616 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
13617#endif
13618 rb_ibf_load_iseq_complete(iseq);
13619 }
13620
13621#if IBF_ISEQ_DEBUG
13622 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
13623 (void *)iseq, (void *)load->iseq);
13624#endif
13625 return iseq;
13626 }
13627 }
13628}
13629
13630static void
13631ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
13632{
13633 struct ibf_header *header = (struct ibf_header *)bytes;
13634 load->loader_obj = loader_obj;
13635 load->global_buffer.buff = bytes;
13636 load->header = header;
13637 load->global_buffer.size = header->size;
13638 load->global_buffer.obj_list_offset = header->global_object_list_offset;
13639 load->global_buffer.obj_list_size = header->global_object_list_size;
13640 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
13641 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
13642 load->iseq = NULL;
13643
13644 load->current_buffer = &load->global_buffer;
13645
13646 if (size < header->size) {
13647 rb_raise(rb_eRuntimeError, "broken binary format");
13648 }
13649 if (strncmp(header->magic, "YARB", 4) != 0) {
13650 rb_raise(rb_eRuntimeError, "unknown binary format");
13651 }
13652 if (header->major_version != IBF_MAJOR_VERSION ||
13653 header->minor_version != IBF_MINOR_VERSION) {
13654 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
13655 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
13656 }
13657 if (header->endian != IBF_ENDIAN_MARK) {
13658 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
13659 }
13660 if (header->wordsize != SIZEOF_VALUE) {
13661 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
13662 }
13663 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13664 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
13665 header->iseq_list_offset);
13666 }
13667 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13668 rb_raise(rb_eArgError, "unaligned object list offset: %u",
13669 load->global_buffer.obj_list_offset);
13670 }
13671}
13672
13673static void
13674ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
13675{
13676 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
13677 rb_raise(rb_eRuntimeError, "broken binary format");
13678 }
13679
13680 if (USE_LAZY_LOAD) {
13681 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
13682 }
13683
13684 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
13685 RB_OBJ_WRITE(loader_obj, &load->str, str);
13686}
13687
13688static void
13689ibf_loader_mark(void *ptr)
13690{
13691 struct ibf_load *load = (struct ibf_load *)ptr;
13692 rb_gc_mark(load->str);
13693 rb_gc_mark(load->iseq_list);
13694 rb_gc_mark(load->global_buffer.obj_list);
13695}
13696
13697static void
13698ibf_loader_free(void *ptr)
13699{
13700 struct ibf_load *load = (struct ibf_load *)ptr;
13701 ruby_xfree(load);
13702}
13703
13704static size_t
13705ibf_loader_memsize(const void *ptr)
13706{
13707 return sizeof(struct ibf_load);
13708}
13709
13710static const rb_data_type_t ibf_load_type = {
13711 "ibf_loader",
13712 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
13713 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13714};
13715
13716const rb_iseq_t *
13717rb_iseq_ibf_load(VALUE str)
13718{
13719 struct ibf_load *load;
13720 rb_iseq_t *iseq;
13721 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13722
13723 ibf_load_setup(load, loader_obj, str);
13724 iseq = ibf_load_iseq(load, 0);
13725
13726 RB_GC_GUARD(loader_obj);
13727 return iseq;
13728}
13729
13730const rb_iseq_t *
13731rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
13732{
13733 struct ibf_load *load;
13734 rb_iseq_t *iseq;
13735 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13736
13737 ibf_load_setup_bytes(load, loader_obj, bytes, size);
13738 iseq = ibf_load_iseq(load, 0);
13739
13740 RB_GC_GUARD(loader_obj);
13741 return iseq;
13742}
13743
13744VALUE
13745rb_iseq_ibf_load_extra_data(VALUE str)
13746{
13747 struct ibf_load *load;
13748 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13749 VALUE extra_str;
13750
13751 ibf_load_setup(load, loader_obj, str);
13752 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
13753 RB_GC_GUARD(loader_obj);
13754 return extra_str;
13755}
13756
13757#include "prism_compile.c"
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:177
#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:107
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:397
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:398
#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 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:396
#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:395
#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:393
#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:400
#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:482
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1354
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1341
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1357
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:699
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1358
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1346
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1361
VALUE rb_cArray
Array class.
Definition array.c:39
VALUE rb_cNumeric
Numeric class.
Definition numeric.c:196
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:645
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:830
#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:631
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:619
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
Definition string.c:12088
#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:1041
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1065
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1656
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:67
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4177
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
Definition string.c:11720
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1532
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:3629
#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:3618
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:3685
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:3500
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:2999
#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_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1854
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:402
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition symbol.c:953
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:900
int len
Length of the buffer.
Definition io.h:8
#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:366
#define ALLOCA_N(type, n)
Definition memory.h:286
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#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:298
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:152
#define Data_Wrap_Struct(klass, mark, free, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rdata.h:202
#define DATA_PTR(obj)
Convenient getter macro.
Definition rdata.h:71
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:82
#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 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_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:8974
#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:28
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:267
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:259
Definition vm_core.h:262
Definition iseq.h:238
This struct represents the overall parser.
Definition parser.h:489
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
struct rb_iseq_constant_body::@151 param
parameter information
Definition st.h:79
Definition vm_core.h:271
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:263
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:144