Ruby 3.3.2p78 (2024-05-30 revision e5a195edf62fe1bf7146a191da13fa1c4fecbd71)
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 ADD_INSN1(ret, node, newarray, INT2FIX(1));
4830 }
4831
4832 return 1;
4833}
4834
4835static inline int
4836static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4837{
4838 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);
4839}
4840
4841static int
4842compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4843{
4844 const NODE *line_node = node;
4845
4846 node = RNODE_HASH(node)->nd_head;
4847
4848 if (!node || nd_type_p(node, NODE_ZLIST)) {
4849 if (!popped) {
4850 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4851 }
4852 return 0;
4853 }
4854
4855 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4856
4857 if (popped) {
4858 for (; node; node = RNODE_LIST(node)->nd_next) {
4859 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
4860 }
4861 return 1;
4862 }
4863
4864 /* Compilation of a hash literal (or keyword arguments).
4865 * This is very similar to compile_array, but there are some differences:
4866 *
4867 * - It contains key-value pairs. So we need to take every two elements.
4868 * We can assume that the length is always even.
4869 *
4870 * - Merging is done by a method call (id_core_hash_merge_ptr).
4871 * Sometimes we need to insert the receiver, so "anchor" is needed.
4872 * In addition, a method call is much slower than concatarray.
4873 * So it pays only when the subsequence is really long.
4874 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4875 *
4876 * - We need to handle keyword splat: **kw.
4877 * For **kw, the key part (node->nd_head) is NULL, and the value part
4878 * (node->nd_next->nd_head) is "kw".
4879 * The code is a bit difficult to avoid hash allocation for **{}.
4880 */
4881
4882 const int max_stack_len = 0x100;
4883 const int min_tmp_hash_len = 0x800;
4884 int stack_len = 0;
4885 int first_chunk = 1;
4886 DECL_ANCHOR(anchor);
4887 INIT_ANCHOR(anchor);
4888
4889 /* Convert pushed elements to a hash, and merge if needed */
4890#define FLUSH_CHUNK() \
4891 if (stack_len) { \
4892 if (first_chunk) { \
4893 APPEND_LIST(ret, anchor); \
4894 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4895 } \
4896 else { \
4897 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4898 ADD_INSN(ret, line_node, swap); \
4899 APPEND_LIST(ret, anchor); \
4900 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4901 } \
4902 INIT_ANCHOR(anchor); \
4903 first_chunk = stack_len = 0; \
4904 }
4905
4906 while (node) {
4907 int count = 1;
4908
4909 /* pre-allocation check (this branch can be omittable) */
4910 if (static_literal_node_pair_p(node, iseq)) {
4911 /* count the elements that are optimizable */
4912 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
4913 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
4914 count++;
4915
4916 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4917 /* The literal contains only optimizable elements, or the subsequence is long enough */
4918 VALUE ary = rb_ary_hidden_new(count);
4919
4920 /* Create a hidden hash */
4921 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4922 VALUE elem[2];
4923 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
4924 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
4925 rb_ary_cat(ary, elem, 2);
4926 }
4927 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4928 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
4929 hash = rb_obj_hide(hash);
4930 OBJ_FREEZE(hash);
4931
4932 /* Emit optimized code */
4933 FLUSH_CHUNK();
4934 if (first_chunk) {
4935 ADD_INSN1(ret, line_node, duphash, hash);
4936 first_chunk = 0;
4937 }
4938 else {
4939 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4940 ADD_INSN(ret, line_node, swap);
4941
4942 ADD_INSN1(ret, line_node, putobject, hash);
4943
4944 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4945 }
4946 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4947 }
4948 }
4949
4950 /* Base case: Compile "count" elements */
4951 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4952
4953 if (CPDEBUG > 0) {
4954 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4955 }
4956
4957 if (RNODE_LIST(node)->nd_head) {
4958 /* Normal key-value pair */
4959 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
4960 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
4961 stack_len += 2;
4962
4963 /* If there are many pushed elements, flush them to avoid stack overflow */
4964 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4965 }
4966 else {
4967 /* kwsplat case: foo(..., **kw, ...) */
4968 FLUSH_CHUNK();
4969
4970 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4971 int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(RNODE_LIT(kw)->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4972 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4973 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
4974 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4975
4976 if (empty_kw) {
4977 if (only_kw && method_call_keywords) {
4978 /* **{} appears at the only keyword argument in method call,
4979 * so it won't be modified.
4980 * kw is a special NODE_LIT that contains a special empty hash,
4981 * so this emits: putobject {}.
4982 * This is only done for method calls and not for literal hashes,
4983 * because literal hashes should always result in a new hash.
4984 */
4985 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4986 }
4987 else if (first_kw) {
4988 /* **{} appears as the first keyword argument, so it may be modified.
4989 * We need to create a fresh hash object.
4990 */
4991 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4992 }
4993 /* Any empty keyword splats that are not the first can be ignored.
4994 * since merging an empty hash into the existing hash is the same
4995 * as not merging it. */
4996 }
4997 else {
4998 if (only_kw && method_call_keywords) {
4999 /* **kw is only keyword argument in method call.
5000 * Use directly. This will be not be flagged as mutable.
5001 * This is only done for method calls and not for literal hashes,
5002 * because literal hashes should always result in a new hash.
5003 */
5004 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5005 }
5006 else {
5007 /* There is more than one keyword argument, or this is not a method
5008 * call. In that case, we need to add an empty hash (if first keyword),
5009 * or merge the hash to the accumulated hash (if not the first keyword).
5010 */
5011 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5012 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5013 else ADD_INSN(ret, line_node, swap);
5014
5015 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5016
5017 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5018 }
5019 }
5020
5021 first_chunk = 0;
5022 }
5023 }
5024 }
5025
5026 FLUSH_CHUNK();
5027#undef FLUSH_CHUNK
5028 return 1;
5029}
5030
5031VALUE
5032rb_node_case_when_optimizable_literal(const NODE *const node)
5033{
5034 switch (nd_type(node)) {
5035 case NODE_LIT: {
5036 VALUE v = RNODE_LIT(node)->nd_lit;
5037 double ival;
5038 if (RB_FLOAT_TYPE_P(v) &&
5039 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5040 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5041 }
5042 if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
5043 return Qundef;
5044 }
5045 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
5046 return v;
5047 }
5048 break;
5049 }
5050 case NODE_NIL:
5051 return Qnil;
5052 case NODE_TRUE:
5053 return Qtrue;
5054 case NODE_FALSE:
5055 return Qfalse;
5056 case NODE_STR:
5057 return rb_fstring(RNODE_STR(node)->nd_lit);
5058 }
5059 return Qundef;
5060}
5061
5062static int
5063when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5064 LABEL *l1, int only_special_literals, VALUE literals)
5065{
5066 while (vals) {
5067 const NODE *val = RNODE_LIST(vals)->nd_head;
5068 VALUE lit = rb_node_case_when_optimizable_literal(val);
5069
5070 if (UNDEF_P(lit)) {
5071 only_special_literals = 0;
5072 }
5073 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5074 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5075 }
5076
5077 if (nd_type_p(val, NODE_STR)) {
5078 debugp_param("nd_lit", RNODE_STR(val)->nd_lit);
5079 lit = rb_fstring(RNODE_STR(val)->nd_lit);
5080 ADD_INSN1(cond_seq, val, putobject, lit);
5081 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5082 }
5083 else {
5084 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5085 }
5086
5087 // Emit pattern === target
5088 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5089 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5090 ADD_INSNL(cond_seq, val, branchif, l1);
5091 vals = RNODE_LIST(vals)->nd_next;
5092 }
5093 return only_special_literals;
5094}
5095
5096static int
5097when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5098 LABEL *l1, int only_special_literals, VALUE literals)
5099{
5100 const NODE *line_node = vals;
5101
5102 switch (nd_type(vals)) {
5103 case NODE_LIST:
5104 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5105 return COMPILE_NG;
5106 break;
5107 case NODE_SPLAT:
5108 ADD_INSN (cond_seq, line_node, dup);
5109 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5110 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5111 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5112 ADD_INSNL(cond_seq, line_node, branchif, l1);
5113 break;
5114 case NODE_ARGSCAT:
5115 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5116 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5117 break;
5118 case NODE_ARGSPUSH:
5119 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5120 ADD_INSN (cond_seq, line_node, dup);
5121 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5122 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5123 ADD_INSNL(cond_seq, line_node, branchif, l1);
5124 break;
5125 default:
5126 ADD_INSN (cond_seq, line_node, dup);
5127 CHECK(COMPILE(cond_seq, "when val", vals));
5128 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5129 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5130 ADD_INSNL(cond_seq, line_node, branchif, l1);
5131 break;
5132 }
5133 return COMPILE_OK;
5134}
5135
5136/* Multiple Assignment Handling
5137 *
5138 * In order to handle evaluation of multiple assignment such that the left hand side
5139 * is evaluated before the right hand side, we need to process the left hand side
5140 * and see if there are any attributes that need to be assigned, or constants set
5141 * on explicit objects. If so, we add instructions to evaluate the receiver of
5142 * any assigned attributes or constants before we process the right hand side.
5143 *
5144 * For a multiple assignment such as:
5145 *
5146 * l1.m1, l2[0] = r3, r4
5147 *
5148 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5149 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5150 * On the VM stack, this looks like:
5151 *
5152 * self # putself
5153 * l1 # send
5154 * l1, self # putself
5155 * l1, l2 # send
5156 * l1, l2, 0 # putobject 0
5157 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5158 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5159 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5160 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5161 * l1, l2, 0, [r3, r4], r4, m1= # send
5162 * l1, l2, 0, [r3, r4], r4 # pop
5163 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5164 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5165 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5166 * l1, l2, 0, [r3, r4], r4, []= # send
5167 * l1, l2, 0, [r3, r4], r4 # pop
5168 * l1, l2, 0, [r3, r4] # pop
5169 * [r3, r4], l2, 0, [r3, r4] # setn 3
5170 * [r3, r4], l2, 0 # pop
5171 * [r3, r4], l2 # pop
5172 * [r3, r4] # pop
5173 *
5174 * This is made more complex when you have to handle splats, post args,
5175 * and arbitrary levels of nesting. You need to keep track of the total
5176 * number of attributes to set, and for each attribute, how many entries
5177 * are on the stack before the final attribute, in order to correctly
5178 * calculate the topn value to use to get the receiver of the attribute
5179 * setter method.
5180 *
5181 * A brief description of the VM stack for simple multiple assignment
5182 * with no splat (rhs_array will not be present if the return value of
5183 * the multiple assignment is not needed):
5184 *
5185 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5186 *
5187 * For multiple assignment with splats, while processing the part before
5188 * the splat (splat+post here is an array of the splat and the post arguments):
5189 *
5190 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5191 *
5192 * When processing the splat and post arguments:
5193 *
5194 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5195 *
5196 * When processing nested multiple assignment, existing values on the stack
5197 * are kept. So for:
5198 *
5199 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5200 *
5201 * The stack layout would be the following before processing the nested
5202 * multiple assignment:
5203 *
5204 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5205 *
5206 * In order to handle this correctly, we need to keep track of the nesting
5207 * level for each attribute assignment, as well as the attribute number
5208 * (left hand side attributes are processed left to right) and number of
5209 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5210 * this information.
5211 *
5212 * We also need to track information for the entire multiple assignment, such
5213 * as the total number of arguments, and the current nesting level, to
5214 * handle both nested multiple assignment as well as cases where the
5215 * rhs is not needed. We also need to keep track of all attribute
5216 * assignments in this, which we do using a linked listed. struct masgn_state
5217 * tracks this information.
5218 */
5219
5221 INSN *before_insn;
5222 struct masgn_lhs_node *next;
5223 const NODE *line_node;
5224 int argn;
5225 int num_args;
5226 int lhs_pos;
5227};
5228
5230 struct masgn_lhs_node *first_memo;
5231 struct masgn_lhs_node *last_memo;
5232 int lhs_level;
5233 int num_args;
5234 bool nested;
5235};
5236
5237static int
5238add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5239{
5240 if (!state) {
5241 rb_bug("no masgn_state");
5242 }
5243
5244 struct masgn_lhs_node *memo;
5245 memo = malloc(sizeof(struct masgn_lhs_node));
5246 if (!memo) {
5247 return COMPILE_NG;
5248 }
5249
5250 memo->before_insn = before_insn;
5251 memo->line_node = line_node;
5252 memo->argn = state->num_args + 1;
5253 memo->num_args = argc;
5254 state->num_args += argc;
5255 memo->lhs_pos = lhs_pos;
5256 memo->next = NULL;
5257 if (!state->first_memo) {
5258 state->first_memo = memo;
5259 }
5260 else {
5261 state->last_memo->next = memo;
5262 }
5263 state->last_memo = memo;
5264
5265 return COMPILE_OK;
5266}
5267
5268static 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);
5269
5270static int
5271compile_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)
5272{
5273 switch (nd_type(node)) {
5274 case NODE_ATTRASGN: {
5275 INSN *iobj;
5276 const NODE *line_node = node;
5277
5278 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5279
5280 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5281 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5282 ASSUME(iobj);
5283 ELEM_REMOVE(LAST_ELEMENT(pre));
5284 ELEM_REMOVE((LINK_ELEMENT *)iobj);
5285 pre->last = iobj->link.prev;
5286
5287 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5288 int argc = vm_ci_argc(ci) + 1;
5289 ci = ci_argc_set(iseq, ci, argc);
5290 OPERAND_AT(iobj, 0) = (VALUE)ci;
5291 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5292
5293 if (argc == 1) {
5294 ADD_INSN(lhs, line_node, swap);
5295 }
5296 else {
5297 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5298 }
5299
5300 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5301 return COMPILE_NG;
5302 }
5303
5304 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5305 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5306 int argc = vm_ci_argc(ci);
5307 ci = ci_argc_set(iseq, ci, argc - 1);
5308 OPERAND_AT(iobj, 0) = (VALUE)ci;
5309 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5310 INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
5311 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
5312 }
5313 ADD_INSN(lhs, line_node, pop);
5314 if (argc != 1) {
5315 ADD_INSN(lhs, line_node, pop);
5316 }
5317 for (int i=0; i < argc; i++) {
5318 ADD_INSN(post, line_node, pop);
5319 }
5320 break;
5321 }
5322 case NODE_MASGN: {
5323 DECL_ANCHOR(nest_rhs);
5324 INIT_ANCHOR(nest_rhs);
5325 DECL_ANCHOR(nest_lhs);
5326 INIT_ANCHOR(nest_lhs);
5327
5328 int prev_level = state->lhs_level;
5329 bool prev_nested = state->nested;
5330 state->nested = 1;
5331 state->lhs_level = lhs_pos - 1;
5332 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5333 state->lhs_level = prev_level;
5334 state->nested = prev_nested;
5335
5336 ADD_SEQ(lhs, nest_rhs);
5337 ADD_SEQ(lhs, nest_lhs);
5338 break;
5339 }
5340 case NODE_CDECL:
5341 if (!RNODE_CDECL(node)->nd_vid) {
5342 /* Special handling only needed for expr::C, not for C */
5343 INSN *iobj;
5344
5345 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5346
5347 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5348 iobj = (INSN *)insn_element; /* setconstant insn */
5349 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5350 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5351 ELEM_REMOVE(insn_element);
5352 pre->last = iobj->link.prev;
5353 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5354
5355 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5356 return COMPILE_NG;
5357 }
5358
5359 ADD_INSN(post, node, pop);
5360 break;
5361 }
5362 /* Fallthrough */
5363 default: {
5364 DECL_ANCHOR(anchor);
5365 INIT_ANCHOR(anchor);
5366 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5367 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5368 ADD_SEQ(lhs, anchor);
5369 }
5370 }
5371
5372 return COMPILE_OK;
5373}
5374
5375static int
5376compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5377{
5378 if (lhsn) {
5379 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5380 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5381 }
5382 return COMPILE_OK;
5383}
5384
5385static int
5386compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5387 const NODE *rhsn, const NODE *orig_lhsn)
5388{
5389 VALUE mem[64];
5390 const int memsize = numberof(mem);
5391 int memindex = 0;
5392 int llen = 0, rlen = 0;
5393 int i;
5394 const NODE *lhsn = orig_lhsn;
5395
5396#define MEMORY(v) { \
5397 int i; \
5398 if (memindex == memsize) return 0; \
5399 for (i=0; i<memindex; i++) { \
5400 if (mem[i] == (v)) return 0; \
5401 } \
5402 mem[memindex++] = (v); \
5403}
5404
5405 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5406 return 0;
5407 }
5408
5409 while (lhsn) {
5410 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5411 switch (nd_type(ln)) {
5412 case NODE_LASGN:
5413 case NODE_DASGN:
5414 case NODE_IASGN:
5415 case NODE_CVASGN:
5416 MEMORY(get_nd_vid(ln));
5417 break;
5418 default:
5419 return 0;
5420 }
5421 lhsn = RNODE_LIST(lhsn)->nd_next;
5422 llen++;
5423 }
5424
5425 while (rhsn) {
5426 if (llen <= rlen) {
5427 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5428 }
5429 else {
5430 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5431 }
5432 rhsn = RNODE_LIST(rhsn)->nd_next;
5433 rlen++;
5434 }
5435
5436 if (llen > rlen) {
5437 for (i=0; i<llen-rlen; i++) {
5438 ADD_INSN(ret, orig_lhsn, putnil);
5439 }
5440 }
5441
5442 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5443 return 1;
5444}
5445
5446static int
5447compile_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)
5448{
5449 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5450 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5451 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5452 const NODE *lhsn_count = lhsn;
5453 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5454
5455 int llen = 0;
5456 int lpos = 0;
5457
5458 while (lhsn_count) {
5459 llen++;
5460 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5461 }
5462 while (lhsn) {
5463 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5464 lpos++;
5465 lhsn = RNODE_LIST(lhsn)->nd_next;
5466 }
5467
5468 if (lhs_splat) {
5469 if (nd_type_p(splatn, NODE_POSTARG)) {
5470 /*a, b, *r, p1, p2 */
5471 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5472 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5473 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5474 int ppos = 0;
5475 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5476
5477 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5478
5479 if (NODE_NAMED_REST_P(restn)) {
5480 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5481 }
5482 while (postn) {
5483 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5484 ppos++;
5485 postn = RNODE_LIST(postn)->nd_next;
5486 }
5487 }
5488 else {
5489 /* a, b, *r */
5490 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5491 }
5492 }
5493
5494 if (!state->nested) {
5495 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5496 }
5497
5498 if (!popped) {
5499 ADD_INSN(rhs, node, dup);
5500 }
5501 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5502 return COMPILE_OK;
5503}
5504
5505static int
5506compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5507{
5508 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5509 struct masgn_state state;
5510 state.lhs_level = popped ? 0 : 1;
5511 state.nested = 0;
5512 state.num_args = 0;
5513 state.first_memo = NULL;
5514 state.last_memo = NULL;
5515
5516 DECL_ANCHOR(pre);
5517 INIT_ANCHOR(pre);
5518 DECL_ANCHOR(rhs);
5519 INIT_ANCHOR(rhs);
5520 DECL_ANCHOR(lhs);
5521 INIT_ANCHOR(lhs);
5522 DECL_ANCHOR(post);
5523 INIT_ANCHOR(post);
5524 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5525
5526 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5527 while (memo) {
5528 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5529 for (int i = 0; i < memo->num_args; i++) {
5530 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5531 }
5532 tmp_memo = memo->next;
5533 free(memo);
5534 memo = tmp_memo;
5535 }
5536 CHECK(ok);
5537
5538 ADD_SEQ(ret, pre);
5539 ADD_SEQ(ret, rhs);
5540 ADD_SEQ(ret, lhs);
5541 if (!popped && state.num_args >= 1) {
5542 /* make sure rhs array is returned before popping */
5543 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5544 }
5545 ADD_SEQ(ret, post);
5546 }
5547 return COMPILE_OK;
5548}
5549
5550static VALUE
5551collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5552{
5553 VALUE arr = rb_ary_new();
5554 for (;;) {
5555 switch (nd_type(node)) {
5556 case NODE_CONST:
5557 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5558 return arr;
5559 case NODE_COLON3:
5560 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5561 rb_ary_unshift(arr, ID2SYM(idNULL));
5562 return arr;
5563 case NODE_COLON2:
5564 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5565 node = RNODE_COLON2(node)->nd_head;
5566 break;
5567 default:
5568 return Qfalse;
5569 }
5570 }
5571}
5572
5573static int
5574compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5575 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5576{
5577 switch (nd_type(node)) {
5578 case NODE_CONST:
5579 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5580 ADD_INSN1(body, node, putobject, Qtrue);
5581 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5582 break;
5583 case NODE_COLON3:
5584 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5585 ADD_INSN(body, node, pop);
5586 ADD_INSN1(body, node, putobject, rb_cObject);
5587 ADD_INSN1(body, node, putobject, Qtrue);
5588 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5589 break;
5590 case NODE_COLON2:
5591 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5592 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5593 ADD_INSN1(body, node, putobject, Qfalse);
5594 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5595 break;
5596 default:
5597 CHECK(COMPILE(pref, "const colon2 prefix", node));
5598 break;
5599 }
5600 return COMPILE_OK;
5601}
5602
5603static int
5604compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5605{
5606 if (nd_type_p(cpath, NODE_COLON3)) {
5607 /* toplevel class ::Foo */
5608 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5609 return VM_DEFINECLASS_FLAG_SCOPED;
5610 }
5611 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5612 /* Bar::Foo */
5613 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5614 return VM_DEFINECLASS_FLAG_SCOPED;
5615 }
5616 else {
5617 /* class at cbase Foo */
5618 ADD_INSN1(ret, cpath, putspecialobject,
5619 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5620 return 0;
5621 }
5622}
5623
5624static inline int
5625private_recv_p(const NODE *node)
5626{
5627 NODE *recv = get_nd_recv(node);
5628 if (recv && nd_type_p(recv, NODE_SELF)) {
5629 return RNODE_SELF(recv)->nd_state != 0;
5630 }
5631 return 0;
5632}
5633
5634static void
5635defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5636 const NODE *const node, LABEL **lfinish, VALUE needstr);
5637
5638static int
5639compile_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);
5640
5641static void
5642defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5643 const NODE *const node, LABEL **lfinish, VALUE needstr,
5644 bool keep_result)
5645{
5646 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5647 enum node_type type;
5648 const int line = nd_line(node);
5649 const NODE *line_node = node;
5650
5651 switch (type = nd_type(node)) {
5652
5653 /* easy literals */
5654 case NODE_NIL:
5655 expr_type = DEFINED_NIL;
5656 break;
5657 case NODE_SELF:
5658 expr_type = DEFINED_SELF;
5659 break;
5660 case NODE_TRUE:
5661 expr_type = DEFINED_TRUE;
5662 break;
5663 case NODE_FALSE:
5664 expr_type = DEFINED_FALSE;
5665 break;
5666
5667 case NODE_LIST:{
5668 const NODE *vals = node;
5669
5670 do {
5671 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
5672
5673 if (!lfinish[1]) {
5674 lfinish[1] = NEW_LABEL(line);
5675 }
5676 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5677 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
5678 }
5679 /* fall through */
5680 case NODE_STR:
5681 case NODE_LIT:
5682 case NODE_ZLIST:
5683 case NODE_AND:
5684 case NODE_OR:
5685 default:
5686 expr_type = DEFINED_EXPR;
5687 break;
5688
5689 /* variables */
5690 case NODE_LVAR:
5691 case NODE_DVAR:
5692 expr_type = DEFINED_LVAR;
5693 break;
5694
5695#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5696 case NODE_IVAR:
5697 ADD_INSN3(ret, line_node, definedivar,
5698 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
5699 return;
5700
5701 case NODE_GVAR:
5702 ADD_INSN(ret, line_node, putnil);
5703 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
5704 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
5705 return;
5706
5707 case NODE_CVAR:
5708 ADD_INSN(ret, line_node, putnil);
5709 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
5710 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
5711 return;
5712
5713 case NODE_CONST:
5714 ADD_INSN(ret, line_node, putnil);
5715 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
5716 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
5717 return;
5718 case NODE_COLON2:
5719 if (!lfinish[1]) {
5720 lfinish[1] = NEW_LABEL(line);
5721 }
5722 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
5723 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5724 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
5725
5726 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
5727 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
5728 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
5729 }
5730 else {
5731 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5732 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
5733 }
5734 return;
5735 case NODE_COLON3:
5736 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5737 ADD_INSN3(ret, line_node, defined,
5738 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
5739 return;
5740
5741 /* method dispatch */
5742 case NODE_CALL:
5743 case NODE_OPCALL:
5744 case NODE_VCALL:
5745 case NODE_FCALL:
5746 case NODE_ATTRASGN:{
5747 const int explicit_receiver =
5748 (type == NODE_CALL || type == NODE_OPCALL ||
5749 (type == NODE_ATTRASGN && !private_recv_p(node)));
5750
5751 if (get_nd_args(node) || explicit_receiver) {
5752 if (!lfinish[1]) {
5753 lfinish[1] = NEW_LABEL(line);
5754 }
5755 if (!lfinish[2]) {
5756 lfinish[2] = NEW_LABEL(line);
5757 }
5758 }
5759 if (get_nd_args(node)) {
5760 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
5761 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5762 }
5763 if (explicit_receiver) {
5764 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
5765 switch (nd_type(get_nd_recv(node))) {
5766 case NODE_CALL:
5767 case NODE_OPCALL:
5768 case NODE_VCALL:
5769 case NODE_FCALL:
5770 case NODE_ATTRASGN:
5771 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5772 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
5773 break;
5774 default:
5775 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5776 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
5777 break;
5778 }
5779 if (keep_result) {
5780 ADD_INSN(ret, line_node, dup);
5781 }
5782 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5783 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
5784 }
5785 else {
5786 ADD_INSN(ret, line_node, putself);
5787 if (keep_result) {
5788 ADD_INSN(ret, line_node, dup);
5789 }
5790 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
5791 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
5792 }
5793 return;
5794 }
5795
5796 case NODE_YIELD:
5797 ADD_INSN(ret, line_node, putnil);
5798 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
5799 PUSH_VAL(DEFINED_YIELD));
5800 return;
5801
5802 case NODE_BACK_REF:
5803 case NODE_NTH_REF:
5804 ADD_INSN(ret, line_node, putnil);
5805 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
5806 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
5807 PUSH_VAL(DEFINED_GVAR));
5808 return;
5809
5810 case NODE_SUPER:
5811 case NODE_ZSUPER:
5812 ADD_INSN(ret, line_node, putnil);
5813 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
5814 PUSH_VAL(DEFINED_ZSUPER));
5815 return;
5816
5817#undef PUSH_VAL
5818 case NODE_OP_ASGN1:
5819 case NODE_OP_ASGN2:
5820 case NODE_OP_ASGN_OR:
5821 case NODE_OP_ASGN_AND:
5822 case NODE_MASGN:
5823 case NODE_LASGN:
5824 case NODE_DASGN:
5825 case NODE_GASGN:
5826 case NODE_IASGN:
5827 case NODE_CDECL:
5828 case NODE_CVASGN:
5829 expr_type = DEFINED_ASGN;
5830 break;
5831 }
5832
5833 assert(expr_type != DEFINED_NOT_DEFINED);
5834
5835 if (needstr != Qfalse) {
5836 VALUE str = rb_iseq_defined_string(expr_type);
5837 ADD_INSN1(ret, line_node, putobject, str);
5838 }
5839 else {
5840 ADD_INSN1(ret, line_node, putobject, Qtrue);
5841 }
5842}
5843
5844static void
5845build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5846{
5847 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5848 ADD_INSN(ret, &dummy_line_node, putnil);
5849 iseq_set_exception_local_table(iseq);
5850}
5851
5852static void
5853defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5854 const NODE *const node, LABEL **lfinish, VALUE needstr)
5855{
5856 LINK_ELEMENT *lcur = ret->last;
5857 defined_expr0(iseq, ret, node, lfinish, needstr, false);
5858 if (lfinish[1]) {
5859 int line = nd_line(node);
5860 LABEL *lstart = NEW_LABEL(line);
5861 LABEL *lend = NEW_LABEL(line);
5862 const rb_iseq_t *rescue;
5864 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5865 rescue = new_child_iseq_with_callback(iseq, ifunc,
5866 rb_str_concat(rb_str_new2("defined guard in "),
5867 ISEQ_BODY(iseq)->location.label),
5868 iseq, ISEQ_TYPE_RESCUE, 0);
5869 lstart->rescued = LABEL_RESCUE_BEG;
5870 lend->rescued = LABEL_RESCUE_END;
5871 APPEND_LABEL(ret, lcur, lstart);
5872 ADD_LABEL(ret, lend);
5873 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5874 }
5875}
5876
5877static int
5878compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5879{
5880 const int line = nd_line(node);
5881 const NODE *line_node = node;
5882 if (!RNODE_DEFINED(node)->nd_head) {
5883 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5884 ADD_INSN1(ret, line_node, putobject, str);
5885 }
5886 else {
5887 LABEL *lfinish[3];
5888 LINK_ELEMENT *last = ret->last;
5889 lfinish[0] = NEW_LABEL(line);
5890 lfinish[1] = 0;
5891 lfinish[2] = 0;
5892 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr);
5893 if (lfinish[1]) {
5894 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5895 ADD_INSN(ret, line_node, swap);
5896 if (lfinish[2]) {
5897 ADD_LABEL(ret, lfinish[2]);
5898 }
5899 ADD_INSN(ret, line_node, pop);
5900 ADD_LABEL(ret, lfinish[1]);
5901 }
5902 ADD_LABEL(ret, lfinish[0]);
5903 }
5904 return COMPILE_OK;
5905}
5906
5907static VALUE
5908make_name_for_block(const rb_iseq_t *orig_iseq)
5909{
5910 int level = 1;
5911 const rb_iseq_t *iseq = orig_iseq;
5912
5913 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
5914 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
5915 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
5916 level++;
5917 }
5918 iseq = ISEQ_BODY(iseq)->parent_iseq;
5919 }
5920 }
5921
5922 if (level == 1) {
5923 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
5924 }
5925 else {
5926 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
5927 }
5928}
5929
5930static void
5931push_ensure_entry(rb_iseq_t *iseq,
5933 struct ensure_range *er, const void *const node)
5934{
5935 enl->ensure_node = node;
5936 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5937 enl->erange = er;
5938 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5939}
5940
5941static void
5942add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5943 LABEL *lstart, LABEL *lend)
5944{
5945 struct ensure_range *ne =
5946 compile_data_alloc(iseq, sizeof(struct ensure_range));
5947
5948 while (erange->next != 0) {
5949 erange = erange->next;
5950 }
5951 ne->next = 0;
5952 ne->begin = lend;
5953 ne->end = erange->end;
5954 erange->end = lstart;
5955
5956 erange->next = ne;
5957}
5958
5959static bool
5960can_add_ensure_iseq(const rb_iseq_t *iseq)
5961{
5963 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5964 while (e) {
5965 if (e->ensure_node) return false;
5966 e = e->prev;
5967 }
5968 }
5969 return true;
5970}
5971
5972static void
5973add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5974{
5975 assert(can_add_ensure_iseq(iseq));
5976
5978 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5979 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5980 DECL_ANCHOR(ensure);
5981
5982 INIT_ANCHOR(ensure);
5983 while (enlp) {
5984 if (enlp->erange != NULL) {
5985 DECL_ANCHOR(ensure_part);
5986 LABEL *lstart = NEW_LABEL(0);
5987 LABEL *lend = NEW_LABEL(0);
5988 INIT_ANCHOR(ensure_part);
5989
5990 add_ensure_range(iseq, enlp->erange, lstart, lend);
5991
5992 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5993 ADD_LABEL(ensure_part, lstart);
5994 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
5995 ADD_LABEL(ensure_part, lend);
5996 ADD_SEQ(ensure, ensure_part);
5997 }
5998 else {
5999 if (!is_return) {
6000 break;
6001 }
6002 }
6003 enlp = enlp->prev;
6004 }
6005 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6006 ADD_SEQ(ret, ensure);
6007}
6008
6009#if RUBY_DEBUG
6010static int
6011check_keyword(const NODE *node)
6012{
6013 /* This check is essentially a code clone of compile_keyword_arg. */
6014
6015 if (nd_type_p(node, NODE_LIST)) {
6016 while (RNODE_LIST(node)->nd_next) {
6017 node = RNODE_LIST(node)->nd_next;
6018 }
6019 node = RNODE_LIST(node)->nd_head;
6020 }
6021
6022 return keyword_node_p(node);
6023}
6024#endif
6025
6026static bool
6027keyword_node_single_splat_p(NODE *kwnode)
6028{
6029 RUBY_ASSERT(keyword_node_p(kwnode));
6030
6031 NODE *node = RNODE_HASH(kwnode)->nd_head;
6032 return RNODE_LIST(node)->nd_head == NULL &&
6033 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6034}
6035
6036static int
6037setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6038 int dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6039{
6040 if (!argn) return 0;
6041
6042 NODE *kwnode = NULL;
6043
6044 switch (nd_type(argn)) {
6045 case NODE_LIST: {
6046 // f(x, y, z)
6047 int len = compile_args(iseq, args, argn, &kwnode);
6048 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6049
6050 if (kwnode) {
6051 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6052 len -= 1;
6053 }
6054 else {
6055 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6056 }
6057 }
6058
6059 return len;
6060 }
6061 case NODE_SPLAT: {
6062 // f(*a)
6063 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6064 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
6065 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6066 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6067 return 1;
6068 }
6069 case NODE_ARGSCAT: {
6070 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6071 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, 1, NULL, NULL);
6072
6073 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6074 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6075 if (kwnode) rest_len--;
6076 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6077 }
6078 else {
6079 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6080 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6081 }
6082
6083 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6084 ADD_INSN1(args, argn, splatarray, Qtrue);
6085 argc += 1;
6086 }
6087 else {
6088 ADD_INSN1(args, argn, splatarray, Qfalse);
6089 ADD_INSN(args, argn, concatarray);
6090 }
6091
6092 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6093 if (kwnode) {
6094 // kwsplat
6095 *flag_ptr |= VM_CALL_KW_SPLAT;
6096 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6097 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6098 argc += 1;
6099 }
6100
6101 return argc;
6102 }
6103 case NODE_ARGSPUSH: {
6104 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6105 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, 1, NULL, NULL);
6106
6107 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6108 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6109 if (kwnode) rest_len--;
6110 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6111 ADD_INSN1(args, argn, newarray, INT2FIX(1));
6112 ADD_INSN(args, argn, concatarray);
6113 }
6114 else {
6115 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6116 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6117 }
6118 else {
6119 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6120 ADD_INSN1(args, argn, newarray, INT2FIX(1));
6121 ADD_INSN(args, argn, concatarray);
6122 }
6123 }
6124
6125 if (kwnode) {
6126 // f(*a, k:1)
6127 *flag_ptr |= VM_CALL_KW_SPLAT;
6128 if (!keyword_node_single_splat_p(kwnode)) {
6129 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6130 }
6131 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6132 argc += 1;
6133 }
6134
6135 return argc;
6136 }
6137 default: {
6138 UNKNOWN_NODE("setup_arg", argn, Qnil);
6139 }
6140 }
6141}
6142
6143static VALUE
6144setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6145 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6146{
6147 VALUE ret;
6148 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6149 unsigned int dup_rest = 1;
6150 DECL_ANCHOR(arg_block);
6151 INIT_ANCHOR(arg_block);
6152 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6153
6154 *flag |= VM_CALL_ARGS_BLOCKARG;
6155
6156 if (LIST_INSN_SIZE_ONE(arg_block)) {
6157 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6158 if (IS_INSN(elem)) {
6159 INSN *iobj = (INSN *)elem;
6160 if (iobj->insn_id == BIN(getblockparam)) {
6161 iobj->insn_id = BIN(getblockparamproxy);
6162 }
6163 dup_rest = 0;
6164 }
6165 }
6166 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, dup_rest, flag, keywords));
6167 ADD_SEQ(args, arg_block);
6168 }
6169 else {
6170 ret = INT2FIX(setup_args_core(iseq, args, argn, 0, flag, keywords));
6171 }
6172 return ret;
6173}
6174
6175static void
6176build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6177{
6178 const NODE *body = ptr;
6179 int line = nd_line(body);
6180 VALUE argc = INT2FIX(0);
6181 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6182
6183 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6184 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6185 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6186 iseq_set_local_table(iseq, 0);
6187}
6188
6189static void
6190compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6191{
6192 const NODE *vars;
6193 LINK_ELEMENT *last;
6194 int line = nd_line(node);
6195 const NODE *line_node = node;
6196 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6197
6198#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6199 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6200#else
6201 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6202#endif
6203 ADD_INSN(ret, line_node, dup);
6204 ADD_INSNL(ret, line_node, branchunless, fail_label);
6205
6206 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6207 INSN *cap;
6208 if (RNODE_BLOCK(vars)->nd_next) {
6209 ADD_INSN(ret, line_node, dup);
6210 }
6211 last = ret->last;
6212 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6213 last = last->next; /* putobject :var */
6214 cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
6215 NULL, INT2FIX(0), NULL);
6216 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6217#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6218 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6219 /* only one name */
6220 DECL_ANCHOR(nom);
6221
6222 INIT_ANCHOR(nom);
6223 ADD_INSNL(nom, line_node, jump, end_label);
6224 ADD_LABEL(nom, fail_label);
6225# if 0 /* $~ must be MatchData or nil */
6226 ADD_INSN(nom, line_node, pop);
6227 ADD_INSN(nom, line_node, putnil);
6228# endif
6229 ADD_LABEL(nom, end_label);
6230 (nom->last->next = cap->link.next)->prev = nom->last;
6231 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6232 return;
6233 }
6234#endif
6235 }
6236 ADD_INSNL(ret, line_node, jump, end_label);
6237 ADD_LABEL(ret, fail_label);
6238 ADD_INSN(ret, line_node, pop);
6239 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6240 last = ret->last;
6241 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6242 last = last->next; /* putobject :var */
6243 ((INSN*)last)->insn_id = BIN(putnil);
6244 ((INSN*)last)->operand_size = 0;
6245 }
6246 ADD_LABEL(ret, end_label);
6247}
6248
6249static int
6250optimizable_range_item_p(const NODE *n)
6251{
6252 if (!n) return FALSE;
6253 switch (nd_type(n)) {
6254 case NODE_LIT:
6255 return RB_INTEGER_TYPE_P(RNODE_LIT(n)->nd_lit);
6256 case NODE_NIL:
6257 return TRUE;
6258 default:
6259 return FALSE;
6260 }
6261}
6262
6263static int
6264compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6265{
6266 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6267 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6268
6269 const int line = nd_line(node);
6270 const NODE *line_node = node;
6271 DECL_ANCHOR(cond_seq);
6272 LABEL *then_label, *else_label, *end_label;
6273 VALUE branches = Qfalse;
6274
6275 INIT_ANCHOR(cond_seq);
6276 then_label = NEW_LABEL(line);
6277 else_label = NEW_LABEL(line);
6278 end_label = 0;
6279
6280 compile_branch_condition(iseq, cond_seq, RNODE_IF(node)->nd_cond, then_label, else_label);
6281 ADD_SEQ(ret, cond_seq);
6282
6283 if (then_label->refcnt && else_label->refcnt) {
6284 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
6285 }
6286
6287 if (then_label->refcnt) {
6288 ADD_LABEL(ret, then_label);
6289
6290 DECL_ANCHOR(then_seq);
6291 INIT_ANCHOR(then_seq);
6292 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6293
6294 if (else_label->refcnt) {
6295 add_trace_branch_coverage(
6296 iseq,
6297 ret,
6298 node_body ? node_body : node,
6299 0,
6300 type == NODE_IF ? "then" : "else",
6301 branches);
6302 end_label = NEW_LABEL(line);
6303 ADD_INSNL(then_seq, line_node, jump, end_label);
6304 if (!popped) {
6305 ADD_INSN(then_seq, line_node, pop);
6306 }
6307 }
6308 ADD_SEQ(ret, then_seq);
6309 }
6310
6311 if (else_label->refcnt) {
6312 ADD_LABEL(ret, else_label);
6313
6314 DECL_ANCHOR(else_seq);
6315 INIT_ANCHOR(else_seq);
6316 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6317
6318 if (then_label->refcnt) {
6319 add_trace_branch_coverage(
6320 iseq,
6321 ret,
6322 node_else ? node_else : node,
6323 1,
6324 type == NODE_IF ? "else" : "then",
6325 branches);
6326 }
6327 ADD_SEQ(ret, else_seq);
6328 }
6329
6330 if (end_label) {
6331 ADD_LABEL(ret, end_label);
6332 }
6333
6334 return COMPILE_OK;
6335}
6336
6337static int
6338compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6339{
6340 const NODE *vals;
6341 const NODE *node = orig_node;
6342 LABEL *endlabel, *elselabel;
6343 DECL_ANCHOR(head);
6344 DECL_ANCHOR(body_seq);
6345 DECL_ANCHOR(cond_seq);
6346 int only_special_literals = 1;
6347 VALUE literals = rb_hash_new();
6348 int line;
6349 enum node_type type;
6350 const NODE *line_node;
6351 VALUE branches = Qfalse;
6352 int branch_id = 0;
6353
6354 INIT_ANCHOR(head);
6355 INIT_ANCHOR(body_seq);
6356 INIT_ANCHOR(cond_seq);
6357
6358 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6359
6360 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6361
6362 branches = decl_branch_base(iseq, node, "case");
6363
6364 node = RNODE_CASE(node)->nd_body;
6365 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6366 type = nd_type(node);
6367 line = nd_line(node);
6368 line_node = node;
6369
6370 endlabel = NEW_LABEL(line);
6371 elselabel = NEW_LABEL(line);
6372
6373 ADD_SEQ(ret, head); /* case VAL */
6374
6375 while (type == NODE_WHEN) {
6376 LABEL *l1;
6377
6378 l1 = NEW_LABEL(line);
6379 ADD_LABEL(body_seq, l1);
6380 ADD_INSN(body_seq, line_node, pop);
6381 add_trace_branch_coverage(
6382 iseq,
6383 body_seq,
6384 RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
6385 branch_id++,
6386 "when",
6387 branches);
6388 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6389 ADD_INSNL(body_seq, line_node, jump, endlabel);
6390
6391 vals = RNODE_WHEN(node)->nd_head;
6392 if (vals) {
6393 switch (nd_type(vals)) {
6394 case NODE_LIST:
6395 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6396 if (only_special_literals < 0) return COMPILE_NG;
6397 break;
6398 case NODE_SPLAT:
6399 case NODE_ARGSCAT:
6400 case NODE_ARGSPUSH:
6401 only_special_literals = 0;
6402 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6403 break;
6404 default:
6405 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6406 }
6407 }
6408 else {
6409 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6410 }
6411
6412 node = RNODE_WHEN(node)->nd_next;
6413 if (!node) {
6414 break;
6415 }
6416 type = nd_type(node);
6417 line = nd_line(node);
6418 line_node = node;
6419 }
6420 /* else */
6421 if (node) {
6422 ADD_LABEL(cond_seq, elselabel);
6423 ADD_INSN(cond_seq, line_node, pop);
6424 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6425 CHECK(COMPILE_(cond_seq, "else", node, popped));
6426 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6427 }
6428 else {
6429 debugs("== else (implicit)\n");
6430 ADD_LABEL(cond_seq, elselabel);
6431 ADD_INSN(cond_seq, orig_node, pop);
6432 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6433 if (!popped) {
6434 ADD_INSN(cond_seq, orig_node, putnil);
6435 }
6436 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6437 }
6438
6439 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6440 ADD_INSN(ret, orig_node, dup);
6441 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6442 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6443 LABEL_REF(elselabel);
6444 }
6445
6446 ADD_SEQ(ret, cond_seq);
6447 ADD_SEQ(ret, body_seq);
6448 ADD_LABEL(ret, endlabel);
6449 return COMPILE_OK;
6450}
6451
6452static int
6453compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6454{
6455 const NODE *vals;
6456 const NODE *val;
6457 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6458 LABEL *endlabel;
6459 DECL_ANCHOR(body_seq);
6460 VALUE branches = Qfalse;
6461 int branch_id = 0;
6462
6463 branches = decl_branch_base(iseq, orig_node, "case");
6464
6465 INIT_ANCHOR(body_seq);
6466 endlabel = NEW_LABEL(nd_line(node));
6467
6468 while (node && nd_type_p(node, NODE_WHEN)) {
6469 const int line = nd_line(node);
6470 LABEL *l1 = NEW_LABEL(line);
6471 ADD_LABEL(body_seq, l1);
6472 add_trace_branch_coverage(
6473 iseq,
6474 body_seq,
6475 RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
6476 branch_id++,
6477 "when",
6478 branches);
6479 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
6480 ADD_INSNL(body_seq, node, jump, endlabel);
6481
6482 vals = RNODE_WHEN(node)->nd_head;
6483 if (!vals) {
6484 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
6485 }
6486 switch (nd_type(vals)) {
6487 case NODE_LIST:
6488 while (vals) {
6489 LABEL *lnext;
6490 val = RNODE_LIST(vals)->nd_head;
6491 lnext = NEW_LABEL(nd_line(val));
6492 debug_compile("== when2\n", (void)0);
6493 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
6494 ADD_LABEL(ret, lnext);
6495 vals = RNODE_LIST(vals)->nd_next;
6496 }
6497 break;
6498 case NODE_SPLAT:
6499 case NODE_ARGSCAT:
6500 case NODE_ARGSPUSH:
6501 ADD_INSN(ret, vals, putnil);
6502 CHECK(COMPILE(ret, "when2/cond splat", vals));
6503 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
6504 ADD_INSNL(ret, vals, branchif, l1);
6505 break;
6506 default:
6507 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
6508 }
6509 node = RNODE_WHEN(node)->nd_next;
6510 }
6511 /* else */
6512 add_trace_branch_coverage(
6513 iseq,
6514 ret,
6515 node ? node : orig_node,
6516 branch_id,
6517 "else",
6518 branches);
6519 CHECK(COMPILE_(ret, "else", node, popped));
6520 ADD_INSNL(ret, orig_node, jump, endlabel);
6521
6522 ADD_SEQ(ret, body_seq);
6523 ADD_LABEL(ret, endlabel);
6524 return COMPILE_OK;
6525}
6526
6527static 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);
6528
6529static 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);
6530static 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);
6531static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
6532static 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);
6533static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
6534
6535#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6536#define CASE3_BI_OFFSET_ERROR_STRING 1
6537#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6538#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6539#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6540
6541static int
6542iseq_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)
6543{
6544 const int line = nd_line(node);
6545 const NODE *line_node = node;
6546
6547 switch (nd_type(node)) {
6548 case NODE_ARYPTN: {
6549 /*
6550 * if pattern.use_rest_num?
6551 * rest_num = 0
6552 * end
6553 * if pattern.has_constant_node?
6554 * unless pattern.constant === obj
6555 * goto match_failed
6556 * end
6557 * end
6558 * unless obj.respond_to?(:deconstruct)
6559 * goto match_failed
6560 * end
6561 * d = obj.deconstruct
6562 * unless Array === d
6563 * goto type_error
6564 * end
6565 * min_argc = pattern.pre_args_num + pattern.post_args_num
6566 * if pattern.has_rest_arg?
6567 * unless d.length >= min_argc
6568 * goto match_failed
6569 * end
6570 * else
6571 * unless d.length == min_argc
6572 * goto match_failed
6573 * end
6574 * end
6575 * pattern.pre_args_num.each do |i|
6576 * unless pattern.pre_args[i].match?(d[i])
6577 * goto match_failed
6578 * end
6579 * end
6580 * if pattern.use_rest_num?
6581 * rest_num = d.length - min_argc
6582 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6583 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6584 * goto match_failed
6585 * end
6586 * end
6587 * end
6588 * pattern.post_args_num.each do |i|
6589 * j = pattern.pre_args_num + i
6590 * j += rest_num
6591 * unless pattern.post_args[i].match?(d[j])
6592 * goto match_failed
6593 * end
6594 * end
6595 * goto matched
6596 * type_error:
6597 * FrozenCore.raise TypeError
6598 * match_failed:
6599 * goto unmatched
6600 */
6601 const NODE *args = RNODE_ARYPTN(node)->pre_args;
6602 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
6603 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
6604
6605 const int min_argc = pre_args_num + post_args_num;
6606 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
6607 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
6608
6609 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6610 int i;
6611 match_failed = NEW_LABEL(line);
6612 type_error = NEW_LABEL(line);
6613 deconstruct = NEW_LABEL(line);
6614 deconstructed = NEW_LABEL(line);
6615
6616 if (use_rest_num) {
6617 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
6618 ADD_INSN(ret, line_node, swap);
6619 if (base_index) {
6620 base_index++;
6621 }
6622 }
6623
6624 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6625
6626 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6627
6628 ADD_INSN(ret, line_node, dup);
6629 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6630 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6631 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
6632 if (in_single_pattern) {
6633 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6634 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6635 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6636 INT2FIX(min_argc), base_index + 1 /* (1) */));
6637 }
6638 ADD_INSNL(ret, line_node, branchunless, match_failed);
6639
6640 for (i = 0; i < pre_args_num; i++) {
6641 ADD_INSN(ret, line_node, dup);
6642 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
6643 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
6644 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));
6645 args = RNODE_LIST(args)->nd_next;
6646 }
6647
6648 if (RNODE_ARYPTN(node)->rest_arg) {
6649 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
6650 ADD_INSN(ret, line_node, dup);
6651 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
6652 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6653 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6654 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6655 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6656 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
6657 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
6658
6659 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));
6660 }
6661 else {
6662 if (post_args_num > 0) {
6663 ADD_INSN(ret, line_node, dup);
6664 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6665 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6666 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6667 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
6668 ADD_INSN(ret, line_node, pop);
6669 }
6670 }
6671 }
6672
6673 args = RNODE_ARYPTN(node)->post_args;
6674 for (i = 0; i < post_args_num; i++) {
6675 ADD_INSN(ret, line_node, dup);
6676
6677 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
6678 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6679 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6680
6681 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
6682 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));
6683 args = RNODE_LIST(args)->nd_next;
6684 }
6685
6686 ADD_INSN(ret, line_node, pop);
6687 if (use_rest_num) {
6688 ADD_INSN(ret, line_node, pop);
6689 }
6690 ADD_INSNL(ret, line_node, jump, matched);
6691 ADD_INSN(ret, line_node, putnil);
6692 if (use_rest_num) {
6693 ADD_INSN(ret, line_node, putnil);
6694 }
6695
6696 ADD_LABEL(ret, type_error);
6697 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6698 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6699 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6700 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6701 ADD_INSN(ret, line_node, pop);
6702
6703 ADD_LABEL(ret, match_failed);
6704 ADD_INSN(ret, line_node, pop);
6705 if (use_rest_num) {
6706 ADD_INSN(ret, line_node, pop);
6707 }
6708 ADD_INSNL(ret, line_node, jump, unmatched);
6709
6710 break;
6711 }
6712 case NODE_FNDPTN: {
6713 /*
6714 * if pattern.has_constant_node?
6715 * unless pattern.constant === obj
6716 * goto match_failed
6717 * end
6718 * end
6719 * unless obj.respond_to?(:deconstruct)
6720 * goto match_failed
6721 * end
6722 * d = obj.deconstruct
6723 * unless Array === d
6724 * goto type_error
6725 * end
6726 * unless d.length >= pattern.args_num
6727 * goto match_failed
6728 * end
6729 *
6730 * begin
6731 * len = d.length
6732 * limit = d.length - pattern.args_num
6733 * i = 0
6734 * while i <= limit
6735 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6736 * if pattern.has_pre_rest_arg_id
6737 * unless pattern.pre_rest_arg.match?(d[0, i])
6738 * goto find_failed
6739 * end
6740 * end
6741 * if pattern.has_post_rest_arg_id
6742 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6743 * goto find_failed
6744 * end
6745 * end
6746 * goto find_succeeded
6747 * end
6748 * i+=1
6749 * end
6750 * find_failed:
6751 * goto match_failed
6752 * find_succeeded:
6753 * end
6754 *
6755 * goto matched
6756 * type_error:
6757 * FrozenCore.raise TypeError
6758 * match_failed:
6759 * goto unmatched
6760 */
6761 const NODE *args = RNODE_FNDPTN(node)->args;
6762 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
6763
6764 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6765 match_failed = NEW_LABEL(line);
6766 type_error = NEW_LABEL(line);
6767 deconstruct = NEW_LABEL(line);
6768 deconstructed = NEW_LABEL(line);
6769
6770 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6771
6772 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6773
6774 ADD_INSN(ret, line_node, dup);
6775 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6776 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6777 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
6778 if (in_single_pattern) {
6779 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) */));
6780 }
6781 ADD_INSNL(ret, line_node, branchunless, match_failed);
6782
6783 {
6784 LABEL *while_begin = NEW_LABEL(nd_line(node));
6785 LABEL *next_loop = NEW_LABEL(nd_line(node));
6786 LABEL *find_succeeded = NEW_LABEL(line);
6787 LABEL *find_failed = NEW_LABEL(nd_line(node));
6788 int j;
6789
6790 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
6791 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
6792
6793 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
6794 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6795 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
6796
6797 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
6798
6799 ADD_LABEL(ret, while_begin);
6800
6801 ADD_INSN(ret, line_node, dup);
6802 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6803 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
6804 ADD_INSNL(ret, line_node, branchunless, find_failed);
6805
6806 for (j = 0; j < args_num; j++) {
6807 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6808 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6809 if (j != 0) {
6810 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
6811 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6812 }
6813 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
6814
6815 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));
6816 args = RNODE_LIST(args)->nd_next;
6817 }
6818
6819 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
6820 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6821 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
6822 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6823 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
6824 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));
6825 }
6826 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
6827 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6828 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6829 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6830 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6831 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6832 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
6833 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));
6834 }
6835 ADD_INSNL(ret, line_node, jump, find_succeeded);
6836
6837 ADD_LABEL(ret, next_loop);
6838 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
6839 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6840 ADD_INSNL(ret, line_node, jump, while_begin);
6841
6842 ADD_LABEL(ret, find_failed);
6843 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6844 if (in_single_pattern) {
6845 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6846 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
6847 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6848 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
6849 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
6850
6851 ADD_INSN1(ret, line_node, putobject, Qfalse);
6852 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
6853
6854 ADD_INSN(ret, line_node, pop);
6855 ADD_INSN(ret, line_node, pop);
6856 }
6857 ADD_INSNL(ret, line_node, jump, match_failed);
6858 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
6859
6860 ADD_LABEL(ret, find_succeeded);
6861 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6862 }
6863
6864 ADD_INSN(ret, line_node, pop);
6865 ADD_INSNL(ret, line_node, jump, matched);
6866 ADD_INSN(ret, line_node, putnil);
6867
6868 ADD_LABEL(ret, type_error);
6869 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6870 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6871 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6872 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6873 ADD_INSN(ret, line_node, pop);
6874
6875 ADD_LABEL(ret, match_failed);
6876 ADD_INSN(ret, line_node, pop);
6877 ADD_INSNL(ret, line_node, jump, unmatched);
6878
6879 break;
6880 }
6881 case NODE_HSHPTN: {
6882 /*
6883 * keys = nil
6884 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6885 * keys = pattern.kw_args_node.keys
6886 * end
6887 * if pattern.has_constant_node?
6888 * unless pattern.constant === obj
6889 * goto match_failed
6890 * end
6891 * end
6892 * unless obj.respond_to?(:deconstruct_keys)
6893 * goto match_failed
6894 * end
6895 * d = obj.deconstruct_keys(keys)
6896 * unless Hash === d
6897 * goto type_error
6898 * end
6899 * if pattern.has_kw_rest_arg_node?
6900 * d = d.dup
6901 * end
6902 * if pattern.has_kw_args_node?
6903 * pattern.kw_args_node.each |k,|
6904 * unless d.key?(k)
6905 * goto match_failed
6906 * end
6907 * end
6908 * pattern.kw_args_node.each |k, pat|
6909 * if pattern.has_kw_rest_arg_node?
6910 * unless pat.match?(d.delete(k))
6911 * goto match_failed
6912 * end
6913 * else
6914 * unless pat.match?(d[k])
6915 * goto match_failed
6916 * end
6917 * end
6918 * end
6919 * else
6920 * unless d.empty?
6921 * goto match_failed
6922 * end
6923 * end
6924 * if pattern.has_kw_rest_arg_node?
6925 * if pattern.no_rest_keyword?
6926 * unless d.empty?
6927 * goto match_failed
6928 * end
6929 * else
6930 * unless pattern.kw_rest_arg_node.match?(d)
6931 * goto match_failed
6932 * end
6933 * end
6934 * end
6935 * goto matched
6936 * type_error:
6937 * FrozenCore.raise TypeError
6938 * match_failed:
6939 * goto unmatched
6940 */
6941 LABEL *match_failed, *type_error;
6942 VALUE keys = Qnil;
6943
6944 match_failed = NEW_LABEL(line);
6945 type_error = NEW_LABEL(line);
6946
6947 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
6948 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
6949 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
6950 while (kw_args) {
6951 rb_ary_push(keys, RNODE_LIT(RNODE_LIST(kw_args)->nd_head)->nd_lit);
6952 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
6953 }
6954 }
6955
6956 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6957
6958 ADD_INSN(ret, line_node, dup);
6959 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6960 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
6961 if (in_single_pattern) {
6962 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
6963 }
6964 ADD_INSNL(ret, line_node, branchunless, match_failed);
6965
6966 if (NIL_P(keys)) {
6967 ADD_INSN(ret, line_node, putnil);
6968 }
6969 else {
6970 ADD_INSN1(ret, line_node, duparray, keys);
6971 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6972 }
6973 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
6974
6975 ADD_INSN(ret, line_node, dup);
6976 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
6977 ADD_INSNL(ret, line_node, branchunless, type_error);
6978
6979 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
6980 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
6981 }
6982
6983 if (RNODE_HSHPTN(node)->nd_pkwargs) {
6984 int i;
6985 int keys_num;
6986 const NODE *args;
6987 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
6988 if (args) {
6989 DECL_ANCHOR(match_values);
6990 INIT_ANCHOR(match_values);
6991 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
6992 for (i = 0; i < keys_num; i++) {
6993 NODE *key_node = RNODE_LIST(args)->nd_head;
6994 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
6995 VALUE key;
6996
6997 if (!nd_type_p(key_node, NODE_LIT)) {
6998 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
6999 }
7000 key = RNODE_LIT(key_node)->nd_lit;
7001
7002 ADD_INSN(ret, line_node, dup);
7003 ADD_INSN1(ret, line_node, putobject, key);
7004 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7005 if (in_single_pattern) {
7006 LABEL *match_succeeded;
7007 match_succeeded = NEW_LABEL(line);
7008
7009 ADD_INSN(ret, line_node, dup);
7010 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7011
7012 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7013 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7014 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7015 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7016 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7017 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7018 ADD_INSN1(ret, line_node, putobject, key); // (7)
7019 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7020
7021 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7022
7023 ADD_LABEL(ret, match_succeeded);
7024 }
7025 ADD_INSNL(ret, line_node, branchunless, match_failed);
7026
7027 ADD_INSN(match_values, line_node, dup);
7028 ADD_INSN1(match_values, line_node, putobject, key);
7029 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7030 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7031 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7032 }
7033 ADD_SEQ(ret, match_values);
7034 }
7035 }
7036 else {
7037 ADD_INSN(ret, line_node, dup);
7038 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7039 if (in_single_pattern) {
7040 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7041 }
7042 ADD_INSNL(ret, line_node, branchunless, match_failed);
7043 }
7044
7045 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7046 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7047 ADD_INSN(ret, line_node, dup);
7048 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7049 if (in_single_pattern) {
7050 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7051 }
7052 ADD_INSNL(ret, line_node, branchunless, match_failed);
7053 }
7054 else {
7055 ADD_INSN(ret, line_node, dup); // (11)
7056 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));
7057 }
7058 }
7059
7060 ADD_INSN(ret, line_node, pop);
7061 ADD_INSNL(ret, line_node, jump, matched);
7062 ADD_INSN(ret, line_node, putnil);
7063
7064 ADD_LABEL(ret, type_error);
7065 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7066 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7067 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7068 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7069 ADD_INSN(ret, line_node, pop);
7070
7071 ADD_LABEL(ret, match_failed);
7072 ADD_INSN(ret, line_node, pop);
7073 ADD_INSNL(ret, line_node, jump, unmatched);
7074 break;
7075 }
7076 case NODE_LIT:
7077 case NODE_STR:
7078 case NODE_XSTR:
7079 case NODE_DSTR:
7080 case NODE_DSYM:
7081 case NODE_DREGX:
7082 case NODE_LIST:
7083 case NODE_ZLIST:
7084 case NODE_LAMBDA:
7085 case NODE_DOT2:
7086 case NODE_DOT3:
7087 case NODE_CONST:
7088 case NODE_LVAR:
7089 case NODE_DVAR:
7090 case NODE_IVAR:
7091 case NODE_CVAR:
7092 case NODE_GVAR:
7093 case NODE_TRUE:
7094 case NODE_FALSE:
7095 case NODE_SELF:
7096 case NODE_NIL:
7097 case NODE_COLON2:
7098 case NODE_COLON3:
7099 case NODE_BEGIN:
7100 case NODE_BLOCK:
7101 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7102 if (in_single_pattern) {
7103 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7104 }
7105 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7106 if (in_single_pattern) {
7107 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7108 }
7109 ADD_INSNL(ret, line_node, branchif, matched);
7110 ADD_INSNL(ret, line_node, jump, unmatched);
7111 break;
7112 case NODE_LASGN: {
7113 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7114 ID id = RNODE_LASGN(node)->nd_vid;
7115 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7116
7117 if (in_alt_pattern) {
7118 const char *name = rb_id2name(id);
7119 if (name && strlen(name) > 0 && name[0] != '_') {
7120 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7121 rb_id2str(id));
7122 return COMPILE_NG;
7123 }
7124 }
7125
7126 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7127 ADD_INSNL(ret, line_node, jump, matched);
7128 break;
7129 }
7130 case NODE_DASGN: {
7131 int idx, lv, ls;
7132 ID id = RNODE_DASGN(node)->nd_vid;
7133
7134 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7135
7136 if (in_alt_pattern) {
7137 const char *name = rb_id2name(id);
7138 if (name && strlen(name) > 0 && name[0] != '_') {
7139 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7140 rb_id2str(id));
7141 return COMPILE_NG;
7142 }
7143 }
7144
7145 if (idx < 0) {
7146 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7147 rb_id2str(id));
7148 return COMPILE_NG;
7149 }
7150 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7151 ADD_INSNL(ret, line_node, jump, matched);
7152 break;
7153 }
7154 case NODE_IF:
7155 case NODE_UNLESS: {
7156 LABEL *match_failed;
7157 match_failed = unmatched;
7158 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7159 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7160 if (in_single_pattern) {
7161 LABEL *match_succeeded;
7162 match_succeeded = NEW_LABEL(line);
7163
7164 ADD_INSN(ret, line_node, dup);
7165 if (nd_type_p(node, NODE_IF)) {
7166 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7167 }
7168 else {
7169 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7170 }
7171
7172 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7173 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7174 ADD_INSN1(ret, line_node, putobject, Qfalse);
7175 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7176
7177 ADD_INSN(ret, line_node, pop);
7178 ADD_INSN(ret, line_node, pop);
7179
7180 ADD_LABEL(ret, match_succeeded);
7181 }
7182 if (nd_type_p(node, NODE_IF)) {
7183 ADD_INSNL(ret, line_node, branchunless, match_failed);
7184 }
7185 else {
7186 ADD_INSNL(ret, line_node, branchif, match_failed);
7187 }
7188 ADD_INSNL(ret, line_node, jump, matched);
7189 break;
7190 }
7191 case NODE_HASH: {
7192 NODE *n;
7193 LABEL *match_failed;
7194 match_failed = NEW_LABEL(line);
7195
7196 n = RNODE_HASH(node)->nd_head;
7197 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7198 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7199 return COMPILE_NG;
7200 }
7201
7202 ADD_INSN(ret, line_node, dup); // (1)
7203 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));
7204 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));
7205 ADD_INSN(ret, line_node, putnil);
7206
7207 ADD_LABEL(ret, match_failed);
7208 ADD_INSN(ret, line_node, pop);
7209 ADD_INSNL(ret, line_node, jump, unmatched);
7210 break;
7211 }
7212 case NODE_OR: {
7213 LABEL *match_succeeded, *fin;
7214 match_succeeded = NEW_LABEL(line);
7215 fin = NEW_LABEL(line);
7216
7217 ADD_INSN(ret, line_node, dup); // (1)
7218 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));
7219 ADD_LABEL(ret, match_succeeded);
7220 ADD_INSN(ret, line_node, pop);
7221 ADD_INSNL(ret, line_node, jump, matched);
7222 ADD_INSN(ret, line_node, putnil);
7223 ADD_LABEL(ret, fin);
7224 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7225 break;
7226 }
7227 default:
7228 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7229 }
7230 return COMPILE_OK;
7231}
7232
7233static int
7234iseq_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)
7235{
7236 LABEL *fin = NEW_LABEL(nd_line(node));
7237 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7238 ADD_LABEL(ret, fin);
7239 return COMPILE_OK;
7240}
7241
7242static int
7243iseq_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)
7244{
7245 const NODE *line_node = node;
7246
7247 if (RNODE_ARYPTN(node)->nd_pconst) {
7248 ADD_INSN(ret, line_node, dup); // (1)
7249 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7250 if (in_single_pattern) {
7251 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7252 }
7253 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7254 if (in_single_pattern) {
7255 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7256 }
7257 ADD_INSNL(ret, line_node, branchunless, match_failed);
7258 }
7259 return COMPILE_OK;
7260}
7261
7262
7263static int
7264iseq_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)
7265{
7266 const NODE *line_node = node;
7267
7268 // NOTE: this optimization allows us to re-use the #deconstruct value
7269 // (or its absence).
7270 if (use_deconstructed_cache) {
7271 // If value is nil then we haven't tried to deconstruct
7272 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7273 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7274
7275 // If false then the value is not deconstructable
7276 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7277 ADD_INSNL(ret, line_node, branchunless, match_failed);
7278
7279 // Drop value, add deconstructed to the stack and jump
7280 ADD_INSN(ret, line_node, pop); // (1)
7281 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7282 ADD_INSNL(ret, line_node, jump, deconstructed);
7283 }
7284 else {
7285 ADD_INSNL(ret, line_node, jump, deconstruct);
7286 }
7287
7288 ADD_LABEL(ret, deconstruct);
7289 ADD_INSN(ret, line_node, dup);
7290 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7291 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7292
7293 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7294 if (use_deconstructed_cache) {
7295 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7296 }
7297
7298 if (in_single_pattern) {
7299 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7300 }
7301
7302 ADD_INSNL(ret, line_node, branchunless, match_failed);
7303
7304 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7305
7306 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7307 if (use_deconstructed_cache) {
7308 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7309 }
7310
7311 ADD_INSN(ret, line_node, dup);
7312 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7313 ADD_INSNL(ret, line_node, branchunless, type_error);
7314
7315 ADD_LABEL(ret, deconstructed);
7316
7317 return COMPILE_OK;
7318}
7319
7320static int
7321iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7322{
7323 /*
7324 * if match_succeeded?
7325 * goto match_succeeded
7326 * end
7327 * error_string = FrozenCore.sprintf(errmsg, matchee)
7328 * key_error_p = false
7329 * match_succeeded:
7330 */
7331 const int line = nd_line(node);
7332 const NODE *line_node = node;
7333 LABEL *match_succeeded = NEW_LABEL(line);
7334
7335 ADD_INSN(ret, line_node, dup);
7336 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7337
7338 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7339 ADD_INSN1(ret, line_node, putobject, errmsg);
7340 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7341 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7342 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7343
7344 ADD_INSN1(ret, line_node, putobject, Qfalse);
7345 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7346
7347 ADD_INSN(ret, line_node, pop);
7348 ADD_INSN(ret, line_node, pop);
7349 ADD_LABEL(ret, match_succeeded);
7350
7351 return COMPILE_OK;
7352}
7353
7354static int
7355iseq_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)
7356{
7357 /*
7358 * if match_succeeded?
7359 * goto match_succeeded
7360 * end
7361 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7362 * key_error_p = false
7363 * match_succeeded:
7364 */
7365 const int line = nd_line(node);
7366 const NODE *line_node = node;
7367 LABEL *match_succeeded = NEW_LABEL(line);
7368
7369 ADD_INSN(ret, line_node, dup);
7370 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7371
7372 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7373 ADD_INSN1(ret, line_node, putobject, errmsg);
7374 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7375 ADD_INSN(ret, line_node, dup);
7376 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7377 ADD_INSN1(ret, line_node, putobject, pattern_length);
7378 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7379 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7380
7381 ADD_INSN1(ret, line_node, putobject, Qfalse);
7382 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7383
7384 ADD_INSN(ret, line_node, pop);
7385 ADD_INSN(ret, line_node, pop);
7386 ADD_LABEL(ret, match_succeeded);
7387
7388 return COMPILE_OK;
7389}
7390
7391static int
7392iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7393{
7394 /*
7395 * if match_succeeded?
7396 * goto match_succeeded
7397 * end
7398 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7399 * key_error_p = false
7400 * match_succeeded:
7401 */
7402 const int line = nd_line(node);
7403 const NODE *line_node = node;
7404 LABEL *match_succeeded = NEW_LABEL(line);
7405
7406 ADD_INSN(ret, line_node, dup);
7407 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7408
7409 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7410 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7411 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7412 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7413 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7414 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7415
7416 ADD_INSN1(ret, line_node, putobject, Qfalse);
7417 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7418
7419 ADD_INSN(ret, line_node, pop);
7420 ADD_INSN(ret, line_node, pop);
7421
7422 ADD_LABEL(ret, match_succeeded);
7423 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7424 ADD_INSN(ret, line_node, pop);
7425 ADD_INSN(ret, line_node, pop);
7426
7427 return COMPILE_OK;
7428}
7429
7430static int
7431compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7432{
7433 const NODE *pattern;
7434 const NODE *node = orig_node;
7435 LABEL *endlabel, *elselabel;
7436 DECL_ANCHOR(head);
7437 DECL_ANCHOR(body_seq);
7438 DECL_ANCHOR(cond_seq);
7439 int line;
7440 enum node_type type;
7441 const NODE *line_node;
7442 VALUE branches = 0;
7443 int branch_id = 0;
7444 bool single_pattern;
7445
7446 INIT_ANCHOR(head);
7447 INIT_ANCHOR(body_seq);
7448 INIT_ANCHOR(cond_seq);
7449
7450 branches = decl_branch_base(iseq, node, "case");
7451
7452 node = RNODE_CASE3(node)->nd_body;
7453 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7454 type = nd_type(node);
7455 line = nd_line(node);
7456 line_node = node;
7457 single_pattern = !RNODE_IN(node)->nd_next;
7458
7459 endlabel = NEW_LABEL(line);
7460 elselabel = NEW_LABEL(line);
7461
7462 if (single_pattern) {
7463 /* allocate stack for ... */
7464 ADD_INSN(head, line_node, putnil); /* key_error_key */
7465 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7466 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7467 ADD_INSN(head, line_node, putnil); /* error_string */
7468 }
7469 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7470
7471 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
7472
7473 ADD_SEQ(ret, head); /* case VAL */
7474
7475 while (type == NODE_IN) {
7476 LABEL *l1;
7477
7478 if (branch_id) {
7479 ADD_INSN(body_seq, line_node, putnil);
7480 }
7481 l1 = NEW_LABEL(line);
7482 ADD_LABEL(body_seq, l1);
7483 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
7484 add_trace_branch_coverage(
7485 iseq,
7486 body_seq,
7487 RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node,
7488 branch_id++,
7489 "in",
7490 branches);
7491 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
7492 ADD_INSNL(body_seq, line_node, jump, endlabel);
7493
7494 pattern = RNODE_IN(node)->nd_head;
7495 if (pattern) {
7496 int pat_line = nd_line(pattern);
7497 LABEL *next_pat = NEW_LABEL(pat_line);
7498 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
7499 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7500 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
7501 ADD_LABEL(cond_seq, next_pat);
7502 LABEL_UNREMOVABLE(next_pat);
7503 }
7504 else {
7505 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7506 return COMPILE_NG;
7507 }
7508
7509 node = RNODE_IN(node)->nd_next;
7510 if (!node) {
7511 break;
7512 }
7513 type = nd_type(node);
7514 line = nd_line(node);
7515 line_node = node;
7516 }
7517 /* else */
7518 if (node) {
7519 ADD_LABEL(cond_seq, elselabel);
7520 ADD_INSN(cond_seq, line_node, pop);
7521 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
7522 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
7523 CHECK(COMPILE_(cond_seq, "else", node, popped));
7524 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7525 ADD_INSN(cond_seq, line_node, putnil);
7526 if (popped) {
7527 ADD_INSN(cond_seq, line_node, putnil);
7528 }
7529 }
7530 else {
7531 debugs("== else (implicit)\n");
7532 ADD_LABEL(cond_seq, elselabel);
7533 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
7534 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7535
7536 if (single_pattern) {
7537 /*
7538 * if key_error_p
7539 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7540 * else
7541 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7542 * end
7543 */
7544 LABEL *key_error, *fin;
7545 struct rb_callinfo_kwarg *kw_arg;
7546
7547 key_error = NEW_LABEL(line);
7548 fin = NEW_LABEL(line);
7549
7550 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
7551 kw_arg->references = 0;
7552 kw_arg->keyword_len = 2;
7553 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
7554 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
7555
7556 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7557 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7558 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7559 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7560 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7561 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7562 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7563 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7564 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7565 ADD_INSNL(cond_seq, orig_node, jump, fin);
7566
7567 ADD_LABEL(cond_seq, key_error);
7568 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7569 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7570 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7571 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7572 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7573 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7574 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7575 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7576 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
7577 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
7578
7579 ADD_LABEL(cond_seq, fin);
7580 }
7581 else {
7582 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7583 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
7584 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7585 }
7586 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
7587 if (!popped) {
7588 ADD_INSN(cond_seq, orig_node, putnil);
7589 }
7590 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7591 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
7592 if (popped) {
7593 ADD_INSN(cond_seq, line_node, putnil);
7594 }
7595 }
7596
7597 ADD_SEQ(ret, cond_seq);
7598 ADD_SEQ(ret, body_seq);
7599 ADD_LABEL(ret, endlabel);
7600 return COMPILE_OK;
7601}
7602
7603#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7604#undef CASE3_BI_OFFSET_ERROR_STRING
7605#undef CASE3_BI_OFFSET_KEY_ERROR_P
7606#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7607#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7608
7609static int
7610compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7611{
7612 const int line = (int)nd_line(node);
7613 const NODE *line_node = node;
7614
7615 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7616 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7617 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7618 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7619 VALUE branches = Qfalse;
7620
7622
7623 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
7624 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
7625 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
7626 LABEL *end_label = NEW_LABEL(line);
7627 LABEL *adjust_label = NEW_LABEL(line);
7628
7629 LABEL *next_catch_label = NEW_LABEL(line);
7630 LABEL *tmp_label = NULL;
7631
7632 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7633 push_ensure_entry(iseq, &enl, NULL, NULL);
7634
7635 if (RNODE_WHILE(node)->nd_state == 1) {
7636 ADD_INSNL(ret, line_node, jump, next_label);
7637 }
7638 else {
7639 tmp_label = NEW_LABEL(line);
7640 ADD_INSNL(ret, line_node, jump, tmp_label);
7641 }
7642 ADD_LABEL(ret, adjust_label);
7643 ADD_INSN(ret, line_node, putnil);
7644 ADD_LABEL(ret, next_catch_label);
7645 ADD_INSN(ret, line_node, pop);
7646 ADD_INSNL(ret, line_node, jump, next_label);
7647 if (tmp_label) ADD_LABEL(ret, tmp_label);
7648
7649 ADD_LABEL(ret, redo_label);
7650 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
7651 add_trace_branch_coverage(
7652 iseq,
7653 ret,
7654 RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node,
7655 0,
7656 "body",
7657 branches);
7658 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
7659 ADD_LABEL(ret, next_label); /* next */
7660
7661 if (type == NODE_WHILE) {
7662 compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
7663 redo_label, end_label);
7664 }
7665 else {
7666 /* until */
7667 compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
7668 end_label, redo_label);
7669 }
7670
7671 ADD_LABEL(ret, end_label);
7672 ADD_ADJUST_RESTORE(ret, adjust_label);
7673
7674 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
7675 /* ADD_INSN(ret, line_node, putundef); */
7676 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
7677 return COMPILE_NG;
7678 }
7679 else {
7680 ADD_INSN(ret, line_node, putnil);
7681 }
7682
7683 ADD_LABEL(ret, break_label); /* break */
7684
7685 if (popped) {
7686 ADD_INSN(ret, line_node, pop);
7687 }
7688
7689 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7690 break_label);
7691 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7692 next_catch_label);
7693 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7694 ISEQ_COMPILE_DATA(iseq)->redo_label);
7695
7696 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7697 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7698 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7699 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7700 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7701 return COMPILE_OK;
7702}
7703
7704static int
7705compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7706{
7707 const int line = nd_line(node);
7708 const NODE *line_node = node;
7709 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7710 LABEL *retry_label = NEW_LABEL(line);
7711 LABEL *retry_end_l = NEW_LABEL(line);
7712 const rb_iseq_t *child_iseq;
7713
7714 ADD_LABEL(ret, retry_label);
7715 if (nd_type_p(node, NODE_FOR)) {
7716 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
7717
7718 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7719 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
7720 ISEQ_TYPE_BLOCK, line);
7721 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
7722 }
7723 else {
7724 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7725 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
7726 ISEQ_TYPE_BLOCK, line);
7727 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
7728 }
7729
7730 {
7731 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7732 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7733 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7734 //
7735 // Normally, "send" instruction is at the last.
7736 // However, qcall under branch coverage measurement adds some instructions after the "send".
7737 //
7738 // Note that "invokesuper" appears instead of "send".
7739 INSN *iobj;
7740 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
7741 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
7742 while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
7743 iobj = (INSN*) get_prev_insn(iobj);
7744 }
7745 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
7746
7747 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7748 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7749 if (&iobj->link == LAST_ELEMENT(ret)) {
7750 ret->last = (LINK_ELEMENT*) retry_end_l;
7751 }
7752 }
7753
7754 if (popped) {
7755 ADD_INSN(ret, line_node, pop);
7756 }
7757
7758 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7759
7760 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7761 return COMPILE_OK;
7762}
7763
7764static int
7765compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7766{
7767 /* massign to var in "for"
7768 * (args.length == 1 && Array.try_convert(args[0])) || args
7769 */
7770 const NODE *line_node = node;
7771 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
7772 LABEL *not_single = NEW_LABEL(nd_line(var));
7773 LABEL *not_ary = NEW_LABEL(nd_line(var));
7774 CHECK(COMPILE(ret, "for var", var));
7775 ADD_INSN(ret, line_node, dup);
7776 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
7777 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7778 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
7779 ADD_INSNL(ret, line_node, branchunless, not_single);
7780 ADD_INSN(ret, line_node, dup);
7781 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7782 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
7783 ADD_INSN1(ret, line_node, putobject, rb_cArray);
7784 ADD_INSN(ret, line_node, swap);
7785 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
7786 ADD_INSN(ret, line_node, dup);
7787 ADD_INSNL(ret, line_node, branchunless, not_ary);
7788 ADD_INSN(ret, line_node, swap);
7789 ADD_LABEL(ret, not_ary);
7790 ADD_INSN(ret, line_node, pop);
7791 ADD_LABEL(ret, not_single);
7792 return COMPILE_OK;
7793}
7794
7795static int
7796compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7797{
7798 const NODE *line_node = node;
7799 unsigned long throw_flag = 0;
7800
7801 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7802 /* while/until */
7803 LABEL *splabel = NEW_LABEL(0);
7804 ADD_LABEL(ret, splabel);
7805 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7806 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
7807 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7808 add_ensure_iseq(ret, iseq, 0);
7809 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7810 ADD_ADJUST_RESTORE(ret, splabel);
7811
7812 if (!popped) {
7813 ADD_INSN(ret, line_node, putnil);
7814 }
7815 }
7816 else {
7817 const rb_iseq_t *ip = iseq;
7818
7819 while (ip) {
7820 if (!ISEQ_COMPILE_DATA(ip)) {
7821 ip = 0;
7822 break;
7823 }
7824
7825 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7826 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7827 }
7828 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7829 throw_flag = 0;
7830 }
7831 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7832 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
7833 return COMPILE_NG;
7834 }
7835 else {
7836 ip = ISEQ_BODY(ip)->parent_iseq;
7837 continue;
7838 }
7839
7840 /* escape from block */
7841 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
7842 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
7843 if (popped) {
7844 ADD_INSN(ret, line_node, pop);
7845 }
7846 return COMPILE_OK;
7847 }
7848 COMPILE_ERROR(ERROR_ARGS "Invalid break");
7849 return COMPILE_NG;
7850 }
7851 return COMPILE_OK;
7852}
7853
7854static int
7855compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7856{
7857 const NODE *line_node = node;
7858 unsigned long throw_flag = 0;
7859
7860 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7861 LABEL *splabel = NEW_LABEL(0);
7862 debugs("next in while loop\n");
7863 ADD_LABEL(ret, splabel);
7864 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
7865 add_ensure_iseq(ret, iseq, 0);
7866 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7867 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7868 ADD_ADJUST_RESTORE(ret, splabel);
7869 if (!popped) {
7870 ADD_INSN(ret, line_node, putnil);
7871 }
7872 }
7873 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7874 LABEL *splabel = NEW_LABEL(0);
7875 debugs("next in block\n");
7876 ADD_LABEL(ret, splabel);
7877 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7878 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
7879 add_ensure_iseq(ret, iseq, 0);
7880 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7881 ADD_ADJUST_RESTORE(ret, splabel);
7882 splabel->unremovable = FALSE;
7883
7884 if (!popped) {
7885 ADD_INSN(ret, line_node, putnil);
7886 }
7887 }
7888 else {
7889 const rb_iseq_t *ip = iseq;
7890
7891 while (ip) {
7892 if (!ISEQ_COMPILE_DATA(ip)) {
7893 ip = 0;
7894 break;
7895 }
7896
7897 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7898 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7899 /* while loop */
7900 break;
7901 }
7902 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7903 break;
7904 }
7905 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7906 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
7907 return COMPILE_NG;
7908 }
7909
7910 ip = ISEQ_BODY(ip)->parent_iseq;
7911 }
7912 if (ip != 0) {
7913 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
7914 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
7915
7916 if (popped) {
7917 ADD_INSN(ret, line_node, pop);
7918 }
7919 }
7920 else {
7921 COMPILE_ERROR(ERROR_ARGS "Invalid next");
7922 return COMPILE_NG;
7923 }
7924 }
7925 return COMPILE_OK;
7926}
7927
7928static int
7929compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7930{
7931 const NODE *line_node = node;
7932
7933 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7934 LABEL *splabel = NEW_LABEL(0);
7935 debugs("redo in while");
7936 ADD_LABEL(ret, splabel);
7937 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7938 add_ensure_iseq(ret, iseq, 0);
7939 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7940 ADD_ADJUST_RESTORE(ret, splabel);
7941 if (!popped) {
7942 ADD_INSN(ret, line_node, putnil);
7943 }
7944 }
7945 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7946 LABEL *splabel = NEW_LABEL(0);
7947
7948 debugs("redo in block");
7949 ADD_LABEL(ret, splabel);
7950 add_ensure_iseq(ret, iseq, 0);
7951 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7952 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7953 ADD_ADJUST_RESTORE(ret, splabel);
7954
7955 if (!popped) {
7956 ADD_INSN(ret, line_node, putnil);
7957 }
7958 }
7959 else {
7960 const rb_iseq_t *ip = iseq;
7961
7962 while (ip) {
7963 if (!ISEQ_COMPILE_DATA(ip)) {
7964 ip = 0;
7965 break;
7966 }
7967
7968 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7969 break;
7970 }
7971 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7972 break;
7973 }
7974 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7975 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
7976 return COMPILE_NG;
7977 }
7978
7979 ip = ISEQ_BODY(ip)->parent_iseq;
7980 }
7981 if (ip != 0) {
7982 ADD_INSN(ret, line_node, putnil);
7983 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7984
7985 if (popped) {
7986 ADD_INSN(ret, line_node, pop);
7987 }
7988 }
7989 else {
7990 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
7991 return COMPILE_NG;
7992 }
7993 }
7994 return COMPILE_OK;
7995}
7996
7997static int
7998compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7999{
8000 const NODE *line_node = node;
8001
8002 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8003 ADD_INSN(ret, line_node, putnil);
8004 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8005
8006 if (popped) {
8007 ADD_INSN(ret, line_node, pop);
8008 }
8009 }
8010 else {
8011 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8012 return COMPILE_NG;
8013 }
8014 return COMPILE_OK;
8015}
8016
8017static int
8018compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8019{
8020 const int line = nd_line(node);
8021 const NODE *line_node = node;
8022 LABEL *lstart = NEW_LABEL(line);
8023 LABEL *lend = NEW_LABEL(line);
8024 LABEL *lcont = NEW_LABEL(line);
8025 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8026 rb_str_concat(rb_str_new2("rescue in "),
8027 ISEQ_BODY(iseq)->location.label),
8028 ISEQ_TYPE_RESCUE, line);
8029
8030 lstart->rescued = LABEL_RESCUE_BEG;
8031 lend->rescued = LABEL_RESCUE_END;
8032 ADD_LABEL(ret, lstart);
8033
8034 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8035 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8036 {
8037 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8038 }
8039 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8040
8041 ADD_LABEL(ret, lend);
8042 if (RNODE_RESCUE(node)->nd_else) {
8043 ADD_INSN(ret, line_node, pop);
8044 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8045 }
8046 ADD_INSN(ret, line_node, nop);
8047 ADD_LABEL(ret, lcont);
8048
8049 if (popped) {
8050 ADD_INSN(ret, line_node, pop);
8051 }
8052
8053 /* register catch entry */
8054 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8055 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8056 return COMPILE_OK;
8057}
8058
8059static int
8060compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8061{
8062 const int line = nd_line(node);
8063 const NODE *line_node = node;
8064 const NODE *resq = node;
8065 const NODE *narg;
8066 LABEL *label_miss, *label_hit;
8067
8068 while (resq) {
8069 label_miss = NEW_LABEL(line);
8070 label_hit = NEW_LABEL(line);
8071
8072 narg = RNODE_RESBODY(resq)->nd_args;
8073 if (narg) {
8074 switch (nd_type(narg)) {
8075 case NODE_LIST:
8076 while (narg) {
8077 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8078 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8079 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8080 ADD_INSNL(ret, line_node, branchif, label_hit);
8081 narg = RNODE_LIST(narg)->nd_next;
8082 }
8083 break;
8084 case NODE_SPLAT:
8085 case NODE_ARGSCAT:
8086 case NODE_ARGSPUSH:
8087 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8088 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8089 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8090 ADD_INSNL(ret, line_node, branchif, label_hit);
8091 break;
8092 default:
8093 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8094 }
8095 }
8096 else {
8097 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8098 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8099 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8100 ADD_INSNL(ret, line_node, branchif, label_hit);
8101 }
8102 ADD_INSNL(ret, line_node, jump, label_miss);
8103 ADD_LABEL(ret, label_hit);
8104 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8105
8106 if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL) {
8107 // empty body
8108 int lineno = nd_line(RNODE_RESBODY(resq)->nd_body);
8109 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
8110 ADD_INSN(ret, &dummy_line_node, putnil);
8111 }
8112 else {
8113 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8114 }
8115
8116 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8117 ADD_INSN(ret, line_node, nop);
8118 }
8119 ADD_INSN(ret, line_node, leave);
8120 ADD_LABEL(ret, label_miss);
8121 resq = RNODE_RESBODY(resq)->nd_head;
8122 }
8123 return COMPILE_OK;
8124}
8125
8126static int
8127compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8128{
8129 const int line = nd_line(node);
8130 const NODE *line_node = node;
8131 DECL_ANCHOR(ensr);
8132 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8133 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8134 ISEQ_TYPE_ENSURE, line);
8135 LABEL *lstart = NEW_LABEL(line);
8136 LABEL *lend = NEW_LABEL(line);
8137 LABEL *lcont = NEW_LABEL(line);
8138 LINK_ELEMENT *last;
8139 int last_leave = 0;
8140 struct ensure_range er;
8142 struct ensure_range *erange;
8143
8144 INIT_ANCHOR(ensr);
8145 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8146 last = ensr->last;
8147 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8148
8149 er.begin = lstart;
8150 er.end = lend;
8151 er.next = 0;
8152 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8153
8154 ADD_LABEL(ret, lstart);
8155 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8156 ADD_LABEL(ret, lend);
8157 ADD_SEQ(ret, ensr);
8158 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8159 ADD_LABEL(ret, lcont);
8160 if (last_leave) ADD_INSN(ret, line_node, pop);
8161
8162 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8163 if (lstart->link.next != &lend->link) {
8164 while (erange) {
8165 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8166 ensure, lcont);
8167 erange = erange->next;
8168 }
8169 }
8170
8171 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8172 return COMPILE_OK;
8173}
8174
8175static int
8176compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8177{
8178 const NODE *line_node = node;
8179
8180 if (iseq) {
8181 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8182 const rb_iseq_t *is = iseq;
8183 enum rb_iseq_type t = type;
8184 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8185 LABEL *splabel = 0;
8186
8187 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8188 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8189 t = ISEQ_BODY(is)->type;
8190 }
8191 switch (t) {
8192 case ISEQ_TYPE_TOP:
8193 case ISEQ_TYPE_MAIN:
8194 if (retval) {
8195 rb_warn("argument of top-level return is ignored");
8196 }
8197 if (is == iseq) {
8198 /* plain top-level, leave directly */
8199 type = ISEQ_TYPE_METHOD;
8200 }
8201 break;
8202 default:
8203 break;
8204 }
8205
8206 if (type == ISEQ_TYPE_METHOD) {
8207 splabel = NEW_LABEL(0);
8208 ADD_LABEL(ret, splabel);
8209 ADD_ADJUST(ret, line_node, 0);
8210 }
8211
8212 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8213
8214 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8215 add_ensure_iseq(ret, iseq, 1);
8216 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8217 ADD_INSN(ret, line_node, leave);
8218 ADD_ADJUST_RESTORE(ret, splabel);
8219
8220 if (!popped) {
8221 ADD_INSN(ret, line_node, putnil);
8222 }
8223 }
8224 else {
8225 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8226 if (popped) {
8227 ADD_INSN(ret, line_node, pop);
8228 }
8229 }
8230 }
8231 return COMPILE_OK;
8232}
8233
8234static int
8235compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8236{
8237 CHECK(COMPILE_(ret, "nd_body", node, popped));
8238
8239 if (!popped && !all_string_result_p(node)) {
8240 const NODE *line_node = node;
8241 const unsigned int flag = VM_CALL_FCALL;
8242
8243 // Note, this dup could be removed if we are willing to change anytostring. It pops
8244 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8245 ADD_INSN(ret, line_node, dup);
8246 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8247 ADD_INSN(ret, line_node, anytostring);
8248 }
8249 return COMPILE_OK;
8250}
8251
8252static void
8253compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8254{
8255 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8256
8257 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8258 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8259}
8260
8261static LABEL *
8262qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8263{
8264 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8265 VALUE br = 0;
8266
8267 br = decl_branch_base(iseq, node, "&.");
8268 *branches = br;
8269 ADD_INSN(recv, line_node, dup);
8270 ADD_INSNL(recv, line_node, branchnil, else_label);
8271 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
8272 return else_label;
8273}
8274
8275static void
8276qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8277{
8278 LABEL *end_label;
8279 if (!else_label) return;
8280 end_label = NEW_LABEL(nd_line(line_node));
8281 ADD_INSNL(ret, line_node, jump, end_label);
8282 ADD_LABEL(ret, else_label);
8283 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
8284 ADD_LABEL(ret, end_label);
8285}
8286
8287static int
8288compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8289{
8290 /* optimization shortcut
8291 * "literal".freeze -> opt_str_freeze("literal")
8292 */
8293 if (get_nd_recv(node) && nd_type_p(get_nd_recv(node), NODE_STR) &&
8294 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8295 get_nd_args(node) == NULL &&
8296 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8297 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8298 VALUE str = rb_fstring(RNODE_STR(get_nd_recv(node))->nd_lit);
8299 if (get_node_call_nd_mid(node) == idUMinus) {
8300 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8301 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8302 }
8303 else {
8304 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8305 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8306 }
8307 RB_OBJ_WRITTEN(iseq, Qundef, str);
8308 if (popped) {
8309 ADD_INSN(ret, line_node, pop);
8310 }
8311 return TRUE;
8312 }
8313 /* optimization shortcut
8314 * obj["literal"] -> opt_aref_with(obj, "literal")
8315 */
8316 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8317 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8318 nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) &&
8319 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8320 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8321 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8322 VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(get_nd_args(node))->nd_head)->nd_lit);
8323 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8324 ADD_INSN2(ret, line_node, opt_aref_with, str,
8325 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8326 RB_OBJ_WRITTEN(iseq, Qundef, str);
8327 if (popped) {
8328 ADD_INSN(ret, line_node, pop);
8329 }
8330 return TRUE;
8331 }
8332 return FALSE;
8333}
8334
8335static int
8336iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8337{
8338 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8339}
8340
8341static const struct rb_builtin_function *
8342iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8343{
8344 int i;
8345 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8346 for (i=0; table[i].index != -1; i++) {
8347 if (strcmp(table[i].name, name) == 0) {
8348 return &table[i];
8349 }
8350 }
8351 return NULL;
8352}
8353
8354static const char *
8355iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8356{
8357 const char *name = rb_id2name(mid);
8358 static const char prefix[] = "__builtin_";
8359 const size_t prefix_len = sizeof(prefix) - 1;
8360
8361 switch (type) {
8362 case NODE_CALL:
8363 if (recv) {
8364 switch (nd_type(recv)) {
8365 case NODE_VCALL:
8366 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8367 return name;
8368 }
8369 break;
8370 case NODE_CONST:
8371 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8372 return name;
8373 }
8374 break;
8375 default: break;
8376 }
8377 }
8378 break;
8379 case NODE_VCALL:
8380 case NODE_FCALL:
8381 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8382 return &name[prefix_len];
8383 }
8384 break;
8385 default: break;
8386 }
8387 return NULL;
8388}
8389
8390static int
8391delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8392{
8393
8394 if (argc == 0) {
8395 *pstart_index = 0;
8396 return TRUE;
8397 }
8398 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8399 unsigned int start=0;
8400
8401 // local_table: [p1, p2, p3, l1, l2, l3]
8402 // arguments: [p3, l1, l2] -> 2
8403 for (start = 0;
8404 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8405 start++) {
8406 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8407
8408 for (unsigned int i=start; i-start<argc; i++) {
8409 if (IS_INSN(elem) &&
8410 INSN_OF(elem) == BIN(getlocal)) {
8411 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8412 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8413
8414 if (local_level == 0) {
8415 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8416 if (0) { // for debug
8417 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8418 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8419 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8420 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8421 }
8422 if (i == index) {
8423 elem = elem->next;
8424 continue; /* for */
8425 }
8426 else {
8427 goto next;
8428 }
8429 }
8430 else {
8431 goto fail; // level != 0 is unsupported
8432 }
8433 }
8434 else {
8435 goto fail; // insn is not a getlocal
8436 }
8437 }
8438 goto success;
8439 next:;
8440 }
8441 fail:
8442 return FALSE;
8443 success:
8444 *pstart_index = start;
8445 return TRUE;
8446 }
8447 else {
8448 return FALSE;
8449 }
8450}
8451
8452// Compile Primitive.attr! :leaf, ...
8453static int
8454compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
8455{
8456 VALUE symbol;
8457 VALUE string;
8458 if (!node) goto no_arg;
8459 while (node) {
8460 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8461 const NODE *next = RNODE_LIST(node)->nd_next;
8462
8463 node = RNODE_LIST(node)->nd_head;
8464 if (!node) goto no_arg;
8465 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8466
8467 symbol = RNODE_LIT(node)->nd_lit;
8468 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
8469
8470 string = rb_sym_to_s(symbol);
8471 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
8472 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
8473 }
8474 else if (strcmp(RSTRING_PTR(string), "no_gc") == 0) {
8475 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_NO_GC;
8476 }
8477 else {
8478 goto unknown_arg;
8479 }
8480 node = next;
8481 }
8482 return COMPILE_OK;
8483 no_arg:
8484 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
8485 return COMPILE_NG;
8486 non_symbol_arg:
8487 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
8488 return COMPILE_NG;
8489 unknown_arg:
8490 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
8491 return COMPILE_NG;
8492 bad_arg:
8493 UNKNOWN_NODE("attr!", node, COMPILE_NG);
8494}
8495
8496static int
8497compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
8498{
8499 if (!node) goto no_arg;
8500 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8501 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
8502 node = RNODE_LIST(node)->nd_head;
8503 if (!node) goto no_arg;
8504 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8505 VALUE name = RNODE_LIT(node)->nd_lit;
8506 if (!SYMBOL_P(name)) goto non_symbol_arg;
8507 if (!popped) {
8508 compile_lvar(iseq, ret, line_node, SYM2ID(name));
8509 }
8510 return COMPILE_OK;
8511 no_arg:
8512 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
8513 return COMPILE_NG;
8514 too_many_arg:
8515 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
8516 return COMPILE_NG;
8517 non_symbol_arg:
8518 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
8519 rb_builtin_class_name(name));
8520 return COMPILE_NG;
8521 bad_arg:
8522 UNKNOWN_NODE("arg!", node, COMPILE_NG);
8523}
8524
8525static NODE *
8526mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
8527{
8528 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
8529 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
8530 return RNODE_IF(node)->nd_body;
8531 }
8532 else {
8533 rb_bug("mandatory_node: can't find mandatory node");
8534 }
8535}
8536
8537static int
8538compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
8539{
8540 // arguments
8541 struct rb_args_info args = {
8542 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
8543 };
8544 rb_node_args_t args_node;
8545 rb_node_init(RNODE(&args_node), NODE_ARGS);
8546 args_node.nd_ainfo = args;
8547
8548 // local table without non-mandatory parameters
8549 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
8550 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
8551
8552 VALUE idtmp = 0;
8553 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
8554 tbl->size = table_size;
8555
8556 int i;
8557
8558 // lead parameters
8559 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
8560 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
8561 }
8562 // local variables
8563 for (; i<table_size; i++) {
8564 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
8565 }
8566
8567 rb_node_scope_t scope_node;
8568 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
8569 scope_node.nd_tbl = tbl;
8570 scope_node.nd_body = mandatory_node(iseq, node);
8571 scope_node.nd_args = &args_node;
8572
8573 rb_ast_body_t ast = {
8574 .root = RNODE(&scope_node),
8575 .frozen_string_literal = -1,
8576 .coverage_enabled = -1,
8577 .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
8578 };
8579
8580 ISEQ_BODY(iseq)->mandatory_only_iseq =
8581 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
8582 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
8583 nd_line(line_node), NULL, 0,
8584 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
8585
8586 ALLOCV_END(idtmp);
8587 return COMPILE_OK;
8588}
8589
8590static int
8591compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
8592 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
8593{
8594 NODE *args_node = get_nd_args(node);
8595
8596 if (parent_block != NULL) {
8597 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
8598 return COMPILE_NG;
8599 }
8600 else {
8601# define BUILTIN_INLINE_PREFIX "_bi"
8602 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
8603 bool cconst = false;
8604 retry:;
8605 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
8606
8607 if (bf == NULL) {
8608 if (strcmp("cstmt!", builtin_func) == 0 ||
8609 strcmp("cexpr!", builtin_func) == 0) {
8610 // ok
8611 }
8612 else if (strcmp("cconst!", builtin_func) == 0) {
8613 cconst = true;
8614 }
8615 else if (strcmp("cinit!", builtin_func) == 0) {
8616 // ignore
8617 GET_VM()->builtin_inline_index++;
8618 return COMPILE_OK;
8619 }
8620 else if (strcmp("attr!", builtin_func) == 0) {
8621 return compile_builtin_attr(iseq, args_node);
8622 }
8623 else if (strcmp("arg!", builtin_func) == 0) {
8624 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8625 }
8626 else if (strcmp("mandatory_only?", builtin_func) == 0) {
8627 if (popped) {
8628 rb_bug("mandatory_only? should be in if condition");
8629 }
8630 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8631 rb_bug("mandatory_only? should be put on top");
8632 }
8633
8634 ADD_INSN1(ret, line_node, putobject, Qfalse);
8635 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8636 }
8637 else if (1) {
8638 rb_bug("can't find builtin function:%s", builtin_func);
8639 }
8640 else {
8641 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
8642 return COMPILE_NG;
8643 }
8644
8645 if (GET_VM()->builtin_inline_index == INT_MAX) {
8646 rb_bug("builtin inline function index overflow:%s", builtin_func);
8647 }
8648 int inline_index = GET_VM()->builtin_inline_index++;
8649 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
8650 builtin_func = inline_func;
8651 args_node = NULL;
8652 goto retry;
8653 }
8654
8655 if (cconst) {
8656 typedef VALUE(*builtin_func0)(void *, VALUE);
8657 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
8658 ADD_INSN1(ret, line_node, putobject, const_val);
8659 return COMPILE_OK;
8660 }
8661
8662 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8663
8664 unsigned int flag = 0;
8665 struct rb_callinfo_kwarg *keywords = NULL;
8666 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8667
8668 if (FIX2INT(argc) != bf->argc) {
8669 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
8670 builtin_func, bf->argc, FIX2INT(argc));
8671 return COMPILE_NG;
8672 }
8673
8674 unsigned int start_index;
8675 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
8676 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
8677 }
8678 else {
8679 ADD_SEQ(ret, args);
8680 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8681 }
8682
8683 if (popped) ADD_INSN(ret, line_node, pop);
8684 return COMPILE_OK;
8685 }
8686}
8687
8688static int
8689compile_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)
8690{
8691 /* call: obj.method(...)
8692 * fcall: func(...)
8693 * vcall: func
8694 */
8695 DECL_ANCHOR(recv);
8696 DECL_ANCHOR(args);
8697 ID mid = get_node_call_nd_mid(node);
8698 VALUE argc;
8699 unsigned int flag = 0;
8700 struct rb_callinfo_kwarg *keywords = NULL;
8701 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8702 LABEL *else_label = NULL;
8703 VALUE branches = Qfalse;
8704
8705 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8706
8707 INIT_ANCHOR(recv);
8708 INIT_ANCHOR(args);
8709#if OPT_SUPPORT_JOKE
8710 if (nd_type_p(node, NODE_VCALL)) {
8711 ID id_bitblt;
8712 ID id_answer;
8713
8714 CONST_ID(id_bitblt, "bitblt");
8715 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
8716
8717 if (mid == id_bitblt) {
8718 ADD_INSN(ret, line_node, bitblt);
8719 return COMPILE_OK;
8720 }
8721 else if (mid == id_answer) {
8722 ADD_INSN(ret, line_node, answer);
8723 return COMPILE_OK;
8724 }
8725 }
8726 /* only joke */
8727 {
8728 ID goto_id;
8729 ID label_id;
8730
8731 CONST_ID(goto_id, "__goto__");
8732 CONST_ID(label_id, "__label__");
8733
8734 if (nd_type_p(node, NODE_FCALL) &&
8735 (mid == goto_id || mid == label_id)) {
8736 LABEL *label;
8737 st_data_t data;
8738 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8739 VALUE label_name;
8740
8741 if (!labels_table) {
8742 labels_table = st_init_numtable();
8743 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8744 }
8745 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8746 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8747
8748 label_name = node->nd_args->nd_head->nd_lit;
8749 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8750 label = NEW_LABEL(nd_line(line_node));
8751 label->position = nd_line(line_node);
8752 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8753 }
8754 else {
8755 label = (LABEL *)data;
8756 }
8757 }
8758 else {
8759 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
8760 return COMPILE_NG;
8761 }
8762
8763 if (mid == goto_id) {
8764 ADD_INSNL(ret, line_node, jump, label);
8765 }
8766 else {
8767 ADD_LABEL(ret, label);
8768 }
8769 return COMPILE_OK;
8770 }
8771 }
8772#endif
8773
8774 const char *builtin_func;
8775 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8776 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
8777 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8778 }
8779
8780 /* receiver */
8781 if (!assume_receiver) {
8782 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
8783 int idx, level;
8784
8785 if (mid == idCall &&
8786 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
8787 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
8788 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
8789 }
8790 else if (private_recv_p(node)) {
8791 ADD_INSN(recv, node, putself);
8792 flag |= VM_CALL_FCALL;
8793 }
8794 else {
8795 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
8796 }
8797
8798 if (type == NODE_QCALL) {
8799 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8800 }
8801 }
8802 else if (type == NODE_FCALL || type == NODE_VCALL) {
8803 ADD_CALL_RECEIVER(recv, line_node);
8804 }
8805 }
8806
8807 /* args */
8808 if (type != NODE_VCALL) {
8809 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
8810 CHECK(!NIL_P(argc));
8811 }
8812 else {
8813 argc = INT2FIX(0);
8814 }
8815
8816 ADD_SEQ(ret, recv);
8817 ADD_SEQ(ret, args);
8818
8819 debugp_param("call args argc", argc);
8820 debugp_param("call method", ID2SYM(mid));
8821
8822 switch ((int)type) {
8823 case NODE_VCALL:
8824 flag |= VM_CALL_VCALL;
8825 /* VCALL is funcall, so fall through */
8826 case NODE_FCALL:
8827 flag |= VM_CALL_FCALL;
8828 }
8829
8830 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
8831 ADD_INSN(ret, line_node, splatkw);
8832 }
8833 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
8834
8835 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8836 if (popped) {
8837 ADD_INSN(ret, line_node, pop);
8838 }
8839 return COMPILE_OK;
8840}
8841
8842static int
8843compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8844{
8845 const int line = nd_line(node);
8846 VALUE argc;
8847 unsigned int flag = 0;
8848 int asgnflag = 0;
8849 ID id = RNODE_OP_ASGN1(node)->nd_mid;
8850 int boff = 0;
8851 int keyword_len = 0;
8852 struct rb_callinfo_kwarg *keywords = NULL;
8853
8854 /*
8855 * a[x] (op)= y
8856 *
8857 * nil # nil
8858 * eval a # nil a
8859 * eval x # nil a x
8860 * dupn 2 # nil a x a x
8861 * send :[] # nil a x a[x]
8862 * eval y # nil a x a[x] y
8863 * send op # nil a x ret
8864 * setn 3 # ret a x ret
8865 * send []= # ret ?
8866 * pop # ret
8867 */
8868
8869 /*
8870 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
8871 * NODE_OP_ASGN nd_recv
8872 * nd_args->nd_head
8873 * nd_args->nd_body
8874 * nd_mid
8875 */
8876
8877 if (!popped) {
8878 ADD_INSN(ret, node, putnil);
8879 }
8880 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
8881 CHECK(asgnflag != -1);
8882 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
8883 case NODE_ZLIST:
8884 argc = INT2FIX(0);
8885 break;
8886 case NODE_BLOCK_PASS:
8887 boff = 1;
8888 /* fall through */
8889 default:
8890 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, &keywords);
8891 if (flag & VM_CALL_KW_SPLAT) {
8892 if (boff) {
8893 ADD_INSN(ret, node, splatkw);
8894 }
8895 else {
8896 /* Make sure to_hash is only called once and not twice */
8897 ADD_INSN(ret, node, dup);
8898 ADD_INSN(ret, node, splatkw);
8899 ADD_INSN(ret, node, pop);
8900 }
8901 }
8902 CHECK(!NIL_P(argc));
8903 }
8904 int dup_argn = FIX2INT(argc) + 1 + boff;
8905 if (keywords) {
8906 keyword_len = keywords->keyword_len;
8907 dup_argn += keyword_len;
8908 }
8909 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
8910 flag |= asgnflag;
8911 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_KW_SPLAT_MUT), keywords);
8912
8913 if (id == idOROP || id == idANDOP) {
8914 /* a[x] ||= y or a[x] &&= y
8915
8916 unless/if a[x]
8917 a[x]= y
8918 else
8919 nil
8920 end
8921 */
8922 LABEL *label = NEW_LABEL(line);
8923 LABEL *lfin = NEW_LABEL(line);
8924
8925 ADD_INSN(ret, node, dup);
8926 if (id == idOROP) {
8927 ADD_INSNL(ret, node, branchif, label);
8928 }
8929 else { /* idANDOP */
8930 ADD_INSNL(ret, node, branchunless, label);
8931 }
8932 ADD_INSN(ret, node, pop);
8933
8934 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
8935 if (!popped) {
8936 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8937 }
8938 if (flag & VM_CALL_ARGS_SPLAT) {
8939 if (flag & VM_CALL_KW_SPLAT) {
8940 ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
8941 ADD_INSN(ret, node, swap);
8942 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8943 ADD_INSN(ret, node, concatarray);
8944 ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
8945 ADD_INSN(ret, node, pop);
8946 }
8947 else {
8948 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8949 if (boff > 0) {
8950 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8951 ADD_INSN(ret, node, swap);
8952 ADD_INSN(ret, node, pop);
8953 }
8954 ADD_INSN(ret, node, concatarray);
8955 if (boff > 0) {
8956 ADD_INSN1(ret, node, setn, INT2FIX(3));
8957 ADD_INSN(ret, node, pop);
8958 ADD_INSN(ret, node, pop);
8959 }
8960 }
8961 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
8962 }
8963 else if (flag & VM_CALL_KW_SPLAT) {
8964 if (boff > 0) {
8965 ADD_INSN1(ret, node, topn, INT2FIX(2));
8966 ADD_INSN(ret, node, swap);
8967 ADD_INSN1(ret, node, setn, INT2FIX(3));
8968 ADD_INSN(ret, node, pop);
8969 }
8970 ADD_INSN(ret, node, swap);
8971 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8972 }
8973 else if (keyword_len) {
8974 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
8975 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+0));
8976 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8977 }
8978 else {
8979 if (boff > 0)
8980 ADD_INSN(ret, node, swap);
8981 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8982 }
8983 ADD_INSN(ret, node, pop);
8984 ADD_INSNL(ret, node, jump, lfin);
8985 ADD_LABEL(ret, label);
8986 if (!popped) {
8987 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8988 }
8989 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
8990 ADD_LABEL(ret, lfin);
8991 }
8992 else {
8993 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
8994 ADD_SEND(ret, node, id, INT2FIX(1));
8995 if (!popped) {
8996 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8997 }
8998 if (flag & VM_CALL_ARGS_SPLAT) {
8999 if (flag & VM_CALL_KW_SPLAT) {
9000 ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
9001 ADD_INSN(ret, node, swap);
9002 ADD_INSN1(ret, node, newarray, INT2FIX(1));
9003 ADD_INSN(ret, node, concatarray);
9004 ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
9005 ADD_INSN(ret, node, pop);
9006 }
9007 else {
9008 ADD_INSN1(ret, node, newarray, INT2FIX(1));
9009 if (boff > 0) {
9010 ADD_INSN1(ret, node, dupn, INT2FIX(3));
9011 ADD_INSN(ret, node, swap);
9012 ADD_INSN(ret, node, pop);
9013 }
9014 ADD_INSN(ret, node, concatarray);
9015 if (boff > 0) {
9016 ADD_INSN1(ret, node, setn, INT2FIX(3));
9017 ADD_INSN(ret, node, pop);
9018 ADD_INSN(ret, node, pop);
9019 }
9020 }
9021 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
9022 }
9023 else if (flag & VM_CALL_KW_SPLAT) {
9024 if (boff > 0) {
9025 ADD_INSN1(ret, node, topn, INT2FIX(2));
9026 ADD_INSN(ret, node, swap);
9027 ADD_INSN1(ret, node, setn, INT2FIX(3));
9028 ADD_INSN(ret, node, pop);
9029 }
9030 ADD_INSN(ret, node, swap);
9031 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9032 }
9033 else if (keyword_len) {
9034 ADD_INSN(ret, node, dup);
9035 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+2));
9036 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
9037 ADD_INSN(ret, node, pop);
9038 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9039 }
9040 else {
9041 if (boff > 0)
9042 ADD_INSN(ret, node, swap);
9043 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9044 }
9045 ADD_INSN(ret, node, pop);
9046 }
9047 return COMPILE_OK;
9048}
9049
9050static int
9051compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9052{
9053 const int line = nd_line(node);
9054 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9055 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9056 int asgnflag;
9057 LABEL *lfin = NEW_LABEL(line);
9058 LABEL *lcfin = NEW_LABEL(line);
9059 LABEL *lskip = 0;
9060 /*
9061 class C; attr_accessor :c; end
9062 r = C.new
9063 r.a &&= v # asgn2
9064
9065 eval r # r
9066 dup # r r
9067 eval r.a # r o
9068
9069 # or
9070 dup # r o o
9071 if lcfin # r o
9072 pop # r
9073 eval v # r v
9074 swap # v r
9075 topn 1 # v r v
9076 send a= # v ?
9077 jump lfin # v ?
9078
9079 lcfin: # r o
9080 swap # o r
9081
9082 lfin: # o ?
9083 pop # o
9084
9085 # or (popped)
9086 if lcfin # r
9087 eval v # r v
9088 send a= # ?
9089 jump lfin # ?
9090
9091 lcfin: # r
9092
9093 lfin: # ?
9094 pop #
9095
9096 # and
9097 dup # r o o
9098 unless lcfin
9099 pop # r
9100 eval v # r v
9101 swap # v r
9102 topn 1 # v r v
9103 send a= # v ?
9104 jump lfin # v ?
9105
9106 # others
9107 eval v # r o v
9108 send ?? # r w
9109 send a= # w
9110
9111 */
9112
9113 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9114 CHECK(asgnflag != -1);
9115 if (RNODE_OP_ASGN2(node)->nd_aid) {
9116 lskip = NEW_LABEL(line);
9117 ADD_INSN(ret, node, dup);
9118 ADD_INSNL(ret, node, branchnil, lskip);
9119 }
9120 ADD_INSN(ret, node, dup);
9121 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9122
9123 if (atype == idOROP || atype == idANDOP) {
9124 if (!popped) {
9125 ADD_INSN(ret, node, dup);
9126 }
9127 if (atype == idOROP) {
9128 ADD_INSNL(ret, node, branchif, lcfin);
9129 }
9130 else { /* idANDOP */
9131 ADD_INSNL(ret, node, branchunless, lcfin);
9132 }
9133 if (!popped) {
9134 ADD_INSN(ret, node, pop);
9135 }
9136 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9137 if (!popped) {
9138 ADD_INSN(ret, node, swap);
9139 ADD_INSN1(ret, node, topn, INT2FIX(1));
9140 }
9141 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9142 ADD_INSNL(ret, node, jump, lfin);
9143
9144 ADD_LABEL(ret, lcfin);
9145 if (!popped) {
9146 ADD_INSN(ret, node, swap);
9147 }
9148
9149 ADD_LABEL(ret, lfin);
9150 }
9151 else {
9152 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9153 ADD_SEND(ret, node, atype, INT2FIX(1));
9154 if (!popped) {
9155 ADD_INSN(ret, node, swap);
9156 ADD_INSN1(ret, node, topn, INT2FIX(1));
9157 }
9158 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9159 }
9160 if (lskip && popped) {
9161 ADD_LABEL(ret, lskip);
9162 }
9163 ADD_INSN(ret, node, pop);
9164 if (lskip && !popped) {
9165 ADD_LABEL(ret, lskip);
9166 }
9167 return COMPILE_OK;
9168}
9169
9170static int
9171compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9172{
9173 const int line = nd_line(node);
9174 LABEL *lfin = 0;
9175 LABEL *lassign = 0;
9176 ID mid;
9177
9178 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9179 case NODE_COLON3:
9180 ADD_INSN1(ret, node, putobject, rb_cObject);
9181 break;
9182 case NODE_COLON2:
9183 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9184 break;
9185 default:
9186 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9187 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9188 return COMPILE_NG;
9189 }
9190 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9191 /* cref */
9192 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9193 lassign = NEW_LABEL(line);
9194 ADD_INSN(ret, node, dup); /* cref cref */
9195 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9196 ID2SYM(mid), Qtrue); /* cref bool */
9197 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9198 }
9199 ADD_INSN(ret, node, dup); /* cref cref */
9200 ADD_INSN1(ret, node, putobject, Qtrue);
9201 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9202
9203 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9204 lfin = NEW_LABEL(line);
9205 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9206 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9207 ADD_INSNL(ret, node, branchif, lfin);
9208 else /* idANDOP */
9209 ADD_INSNL(ret, node, branchunless, lfin);
9210 /* cref [obj] */
9211 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9212 if (lassign) ADD_LABEL(ret, lassign);
9213 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
9214 /* cref value */
9215 if (popped)
9216 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9217 else {
9218 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9219 ADD_INSN(ret, node, swap); /* cref value value cref */
9220 }
9221 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9222 ADD_LABEL(ret, lfin); /* cref [value] */
9223 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9224 ADD_INSN(ret, node, pop); /* [value] */
9225 }
9226 else {
9227 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
9228 /* cref obj value */
9229 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9230 /* cref value */
9231 ADD_INSN(ret, node, swap); /* value cref */
9232 if (!popped) {
9233 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9234 ADD_INSN(ret, node, swap); /* value value cref */
9235 }
9236 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9237 }
9238 return COMPILE_OK;
9239}
9240
9241static int
9242compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9243{
9244 const int line = nd_line(node);
9245 LABEL *lfin = NEW_LABEL(line);
9246 LABEL *lassign;
9247
9248 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9249 LABEL *lfinish[2];
9250 lfinish[0] = lfin;
9251 lfinish[1] = 0;
9252 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse);
9253 lassign = lfinish[1];
9254 if (!lassign) {
9255 lassign = NEW_LABEL(line);
9256 }
9257 ADD_INSNL(ret, node, branchunless, lassign);
9258 }
9259 else {
9260 lassign = NEW_LABEL(line);
9261 }
9262
9263 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9264
9265 if (!popped) {
9266 ADD_INSN(ret, node, dup);
9267 }
9268
9269 if (type == NODE_OP_ASGN_AND) {
9270 ADD_INSNL(ret, node, branchunless, lfin);
9271 }
9272 else {
9273 ADD_INSNL(ret, node, branchif, lfin);
9274 }
9275
9276 if (!popped) {
9277 ADD_INSN(ret, node, pop);
9278 }
9279
9280 ADD_LABEL(ret, lassign);
9281 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9282 ADD_LABEL(ret, lfin);
9283 return COMPILE_OK;
9284}
9285
9286static int
9287compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9288{
9289 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9290 DECL_ANCHOR(args);
9291 int argc;
9292 unsigned int flag = 0;
9293 struct rb_callinfo_kwarg *keywords = NULL;
9294 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9295
9296 INIT_ANCHOR(args);
9297 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9298 if (type == NODE_SUPER) {
9299 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9300 CHECK(!NIL_P(vargc));
9301 argc = FIX2INT(vargc);
9302 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9303 ADD_INSN(args, node, splatkw);
9304 }
9305 }
9306 else {
9307 /* NODE_ZSUPER */
9308 int i;
9309 const rb_iseq_t *liseq = body->local_iseq;
9310 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9311 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9312 int lvar_level = get_lvar_level(iseq);
9313
9314 argc = local_body->param.lead_num;
9315
9316 /* normal arguments */
9317 for (i = 0; i < local_body->param.lead_num; i++) {
9318 int idx = local_body->local_table_size - i;
9319 ADD_GETLOCAL(args, node, idx, lvar_level);
9320 }
9321
9322 if (local_body->param.flags.has_opt) {
9323 /* optional arguments */
9324 int j;
9325 for (j = 0; j < local_body->param.opt_num; j++) {
9326 int idx = local_body->local_table_size - (i + j);
9327 ADD_GETLOCAL(args, node, idx, lvar_level);
9328 }
9329 i += j;
9330 argc = i;
9331 }
9332 if (local_body->param.flags.has_rest) {
9333 /* rest argument */
9334 int idx = local_body->local_table_size - local_body->param.rest_start;
9335 ADD_GETLOCAL(args, node, idx, lvar_level);
9336 ADD_INSN1(args, node, splatarray, Qfalse);
9337
9338 argc = local_body->param.rest_start + 1;
9339 flag |= VM_CALL_ARGS_SPLAT;
9340 }
9341 if (local_body->param.flags.has_post) {
9342 /* post arguments */
9343 int post_len = local_body->param.post_num;
9344 int post_start = local_body->param.post_start;
9345
9346 if (local_body->param.flags.has_rest) {
9347 int j;
9348 for (j=0; j<post_len; j++) {
9349 int idx = local_body->local_table_size - (post_start + j);
9350 ADD_GETLOCAL(args, node, idx, lvar_level);
9351 }
9352 ADD_INSN1(args, node, newarray, INT2FIX(j));
9353 ADD_INSN (args, node, concatarray);
9354 /* argc is settled at above */
9355 }
9356 else {
9357 int j;
9358 for (j=0; j<post_len; j++) {
9359 int idx = local_body->local_table_size - (post_start + j);
9360 ADD_GETLOCAL(args, node, idx, lvar_level);
9361 }
9362 argc = post_len + post_start;
9363 }
9364 }
9365
9366 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9367 int local_size = local_body->local_table_size;
9368 argc++;
9369
9370 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9371
9372 if (local_body->param.flags.has_kwrest) {
9373 int idx = local_body->local_table_size - local_kwd->rest_start;
9374 ADD_GETLOCAL(args, node, idx, lvar_level);
9375 assert(local_kwd->num > 0);
9376 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9377 }
9378 else {
9379 ADD_INSN1(args, node, newhash, INT2FIX(0));
9380 }
9381 for (i = 0; i < local_kwd->num; ++i) {
9382 ID id = local_kwd->table[i];
9383 int idx = local_size - get_local_var_idx(liseq, id);
9384 ADD_INSN1(args, node, putobject, ID2SYM(id));
9385 ADD_GETLOCAL(args, node, idx, lvar_level);
9386 }
9387 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9388 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9389 }
9390 else if (local_body->param.flags.has_kwrest) {
9391 int idx = local_body->local_table_size - local_kwd->rest_start;
9392 ADD_GETLOCAL(args, node, idx, lvar_level);
9393 argc++;
9394 flag |= VM_CALL_KW_SPLAT;
9395 }
9396 }
9397
9398 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9399 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9400 ADD_INSN(ret, node, putself);
9401 ADD_SEQ(ret, args);
9402 ADD_INSN2(ret, node, invokesuper,
9403 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9404 parent_block);
9405
9406 if (popped) {
9407 ADD_INSN(ret, node, pop);
9408 }
9409 return COMPILE_OK;
9410}
9411
9412static int
9413compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9414{
9415 DECL_ANCHOR(args);
9416 VALUE argc;
9417 unsigned int flag = 0;
9418 struct rb_callinfo_kwarg *keywords = NULL;
9419
9420 INIT_ANCHOR(args);
9421
9422 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9423 case ISEQ_TYPE_TOP:
9424 case ISEQ_TYPE_MAIN:
9425 case ISEQ_TYPE_CLASS:
9426 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9427 return COMPILE_NG;
9428 default: /* valid */;
9429 }
9430
9431 if (RNODE_YIELD(node)->nd_head) {
9432 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9433 CHECK(!NIL_P(argc));
9434 }
9435 else {
9436 argc = INT2FIX(0);
9437 }
9438
9439 ADD_SEQ(ret, args);
9440 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9441
9442 if (popped) {
9443 ADD_INSN(ret, node, pop);
9444 }
9445
9446 int level = 0;
9447 const rb_iseq_t *tmp_iseq = iseq;
9448 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9449 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9450 }
9451 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9452
9453 return COMPILE_OK;
9454}
9455
9456static int
9457compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9458{
9459 DECL_ANCHOR(recv);
9460 DECL_ANCHOR(val);
9461
9462 INIT_ANCHOR(recv);
9463 INIT_ANCHOR(val);
9464 switch ((int)type) {
9465 case NODE_MATCH:
9466 ADD_INSN1(recv, node, putobject, RNODE_MATCH(node)->nd_lit);
9467 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9468 INT2FIX(0));
9469 break;
9470 case NODE_MATCH2:
9471 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
9472 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
9473 break;
9474 case NODE_MATCH3:
9475 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
9476 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
9477 break;
9478 }
9479
9480 ADD_SEQ(ret, recv);
9481 ADD_SEQ(ret, val);
9482 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9483
9484 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
9485 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
9486 }
9487
9488 if (popped) {
9489 ADD_INSN(ret, node, pop);
9490 }
9491 return COMPILE_OK;
9492}
9493
9494static int
9495compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9496{
9497 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
9498 /* constant */
9499 VALUE segments;
9500 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
9501 (segments = collect_const_segments(iseq, node))) {
9502 ISEQ_BODY(iseq)->ic_size++;
9503 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9504 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9505 }
9506 else {
9507 /* constant */
9508 DECL_ANCHOR(pref);
9509 DECL_ANCHOR(body);
9510
9511 INIT_ANCHOR(pref);
9512 INIT_ANCHOR(body);
9513 CHECK(compile_const_prefix(iseq, node, pref, body));
9514 if (LIST_INSN_SIZE_ZERO(pref)) {
9515 ADD_INSN(ret, node, putnil);
9516 ADD_SEQ(ret, body);
9517 }
9518 else {
9519 ADD_SEQ(ret, pref);
9520 ADD_SEQ(ret, body);
9521 }
9522 }
9523 }
9524 else {
9525 /* function call */
9526 ADD_CALL_RECEIVER(ret, node);
9527 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
9528 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
9529 }
9530 if (popped) {
9531 ADD_INSN(ret, node, pop);
9532 }
9533 return COMPILE_OK;
9534}
9535
9536static int
9537compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9538{
9539 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
9540
9541 /* add cache insn */
9542 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9543 ISEQ_BODY(iseq)->ic_size++;
9544 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
9545 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9546 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9547 }
9548 else {
9549 ADD_INSN1(ret, node, putobject, rb_cObject);
9550 ADD_INSN1(ret, node, putobject, Qtrue);
9551 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
9552 }
9553
9554 if (popped) {
9555 ADD_INSN(ret, node, pop);
9556 }
9557 return COMPILE_OK;
9558}
9559
9560static int
9561compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
9562{
9563 VALUE flag = INT2FIX(excl);
9564 const NODE *b = RNODE_DOT2(node)->nd_beg;
9565 const NODE *e = RNODE_DOT2(node)->nd_end;
9566
9567 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
9568 if (!popped) {
9569 VALUE bv = nd_type_p(b, NODE_LIT) ? RNODE_LIT(b)->nd_lit : Qnil;
9570 VALUE ev = nd_type_p(e, NODE_LIT) ? RNODE_LIT(e)->nd_lit : Qnil;
9571 VALUE val = rb_range_new(bv, ev, excl);
9572 ADD_INSN1(ret, node, putobject, val);
9573 RB_OBJ_WRITTEN(iseq, Qundef, val);
9574 }
9575 }
9576 else {
9577 CHECK(COMPILE_(ret, "min", b, popped));
9578 CHECK(COMPILE_(ret, "max", e, popped));
9579 if (!popped) {
9580 ADD_INSN1(ret, node, newrange, flag);
9581 }
9582 }
9583 return COMPILE_OK;
9584}
9585
9586static int
9587compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9588{
9589 if (!popped) {
9590 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9591 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
9592 }
9593 else {
9594 const rb_iseq_t *ip = iseq;
9595 int level = 0;
9596 while (ip) {
9597 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
9598 break;
9599 }
9600 ip = ISEQ_BODY(ip)->parent_iseq;
9601 level++;
9602 }
9603 if (ip) {
9604 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
9605 }
9606 else {
9607 ADD_INSN(ret, node, putnil);
9608 }
9609 }
9610 }
9611 return COMPILE_OK;
9612}
9613
9614static int
9615compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9616{
9617 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9618 LABEL *end_label = NEW_LABEL(nd_line(node));
9619 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
9620
9621 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
9622 /* required argument. do nothing */
9623 COMPILE_ERROR(ERROR_ARGS "unreachable");
9624 return COMPILE_NG;
9625 }
9626 else if (nd_type_p(default_value, NODE_LIT) ||
9627 nd_type_p(default_value, NODE_NIL) ||
9628 nd_type_p(default_value, NODE_TRUE) ||
9629 nd_type_p(default_value, NODE_FALSE)) {
9630 COMPILE_ERROR(ERROR_ARGS "unreachable");
9631 return COMPILE_NG;
9632 }
9633 else {
9634 /* if keywordcheck(_kw_bits, nth_keyword)
9635 * kw = default_value
9636 * end
9637 */
9638 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
9639 int keyword_idx = body->param.keyword->num;
9640
9641 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
9642 ADD_INSNL(ret, node, branchif, end_label);
9643 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
9644 ADD_LABEL(ret, end_label);
9645 }
9646 return COMPILE_OK;
9647}
9648
9649static int
9650compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9651{
9652 DECL_ANCHOR(recv);
9653 DECL_ANCHOR(args);
9654 unsigned int flag = 0;
9655 ID mid = RNODE_ATTRASGN(node)->nd_mid;
9656 VALUE argc;
9657 LABEL *else_label = NULL;
9658 VALUE branches = Qfalse;
9659
9660 /* optimization shortcut
9661 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9662 */
9663 if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
9664 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
9665 nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) &&
9666 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9667 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
9668 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
9669 {
9670 VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head)->nd_lit);
9671 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
9672 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
9673 if (!popped) {
9674 ADD_INSN(ret, node, swap);
9675 ADD_INSN1(ret, node, topn, INT2FIX(1));
9676 }
9677 ADD_INSN2(ret, node, opt_aset_with, str,
9678 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9679 RB_OBJ_WRITTEN(iseq, Qundef, str);
9680 ADD_INSN(ret, node, pop);
9681 return COMPILE_OK;
9682 }
9683
9684 INIT_ANCHOR(recv);
9685 INIT_ANCHOR(args);
9686 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
9687 CHECK(!NIL_P(argc));
9688
9689 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
9690 CHECK(asgnflag != -1);
9691 flag |= (unsigned int)asgnflag;
9692
9693 debugp_param("argc", argc);
9694 debugp_param("nd_mid", ID2SYM(mid));
9695
9696 if (!rb_is_attrset_id(mid)) {
9697 /* safe nav attr */
9698 mid = rb_id_attrset(mid);
9699 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9700 }
9701 if (!popped) {
9702 ADD_INSN(ret, node, putnil);
9703 ADD_SEQ(ret, recv);
9704 ADD_SEQ(ret, args);
9705
9706 if (flag & VM_CALL_ARGS_BLOCKARG) {
9707 ADD_INSN1(ret, node, topn, INT2FIX(1));
9708 if (flag & VM_CALL_ARGS_SPLAT) {
9709 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9710 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9711 }
9712 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9713 ADD_INSN (ret, node, pop);
9714 }
9715 else if (flag & VM_CALL_ARGS_SPLAT) {
9716 ADD_INSN(ret, node, dup);
9717 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9718 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9719 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9720 ADD_INSN (ret, node, pop);
9721 }
9722 else {
9723 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9724 }
9725 }
9726 else {
9727 ADD_SEQ(ret, recv);
9728 ADD_SEQ(ret, args);
9729 }
9730 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
9731 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9732 ADD_INSN(ret, node, pop);
9733 return COMPILE_OK;
9734}
9735
9736static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
9744static int
9745iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
9746{
9747 if (node == 0) {
9748 if (!popped) {
9749 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9750 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
9751 debugs("node: NODE_NIL(implicit)\n");
9752 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9753 ADD_INSN(ret, &dummy_line_node, putnil);
9754 }
9755 return COMPILE_OK;
9756 }
9757 return iseq_compile_each0(iseq, ret, node, popped);
9758}
9759
9760static int
9761iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9762{
9763 const int line = (int)nd_line(node);
9764 const enum node_type type = nd_type(node);
9765 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9766
9767 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9768 /* ignore */
9769 }
9770 else {
9771 if (nd_fl_newline(node)) {
9772 int event = RUBY_EVENT_LINE;
9773 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9774 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9775 event |= RUBY_EVENT_COVERAGE_LINE;
9776 }
9777 ADD_TRACE(ret, event);
9778 }
9779 }
9780
9781 debug_node_start(node);
9782#undef BEFORE_RETURN
9783#define BEFORE_RETURN debug_node_end()
9784
9785 switch (type) {
9786 case NODE_BLOCK:
9787 CHECK(compile_block(iseq, ret, node, popped));
9788 break;
9789 case NODE_IF:
9790 case NODE_UNLESS:
9791 CHECK(compile_if(iseq, ret, node, popped, type));
9792 break;
9793 case NODE_CASE:
9794 CHECK(compile_case(iseq, ret, node, popped));
9795 break;
9796 case NODE_CASE2:
9797 CHECK(compile_case2(iseq, ret, node, popped));
9798 break;
9799 case NODE_CASE3:
9800 CHECK(compile_case3(iseq, ret, node, popped));
9801 break;
9802 case NODE_WHILE:
9803 case NODE_UNTIL:
9804 CHECK(compile_loop(iseq, ret, node, popped, type));
9805 break;
9806 case NODE_FOR:
9807 case NODE_ITER:
9808 CHECK(compile_iter(iseq, ret, node, popped));
9809 break;
9810 case NODE_FOR_MASGN:
9811 CHECK(compile_for_masgn(iseq, ret, node, popped));
9812 break;
9813 case NODE_BREAK:
9814 CHECK(compile_break(iseq, ret, node, popped));
9815 break;
9816 case NODE_NEXT:
9817 CHECK(compile_next(iseq, ret, node, popped));
9818 break;
9819 case NODE_REDO:
9820 CHECK(compile_redo(iseq, ret, node, popped));
9821 break;
9822 case NODE_RETRY:
9823 CHECK(compile_retry(iseq, ret, node, popped));
9824 break;
9825 case NODE_BEGIN:{
9826 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
9827 break;
9828 }
9829 case NODE_RESCUE:
9830 CHECK(compile_rescue(iseq, ret, node, popped));
9831 break;
9832 case NODE_RESBODY:
9833 CHECK(compile_resbody(iseq, ret, node, popped));
9834 break;
9835 case NODE_ENSURE:
9836 CHECK(compile_ensure(iseq, ret, node, popped));
9837 break;
9838
9839 case NODE_AND:
9840 case NODE_OR:{
9841 LABEL *end_label = NEW_LABEL(line);
9842 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
9843 if (!popped) {
9844 ADD_INSN(ret, node, dup);
9845 }
9846 if (type == NODE_AND) {
9847 ADD_INSNL(ret, node, branchunless, end_label);
9848 }
9849 else {
9850 ADD_INSNL(ret, node, branchif, end_label);
9851 }
9852 if (!popped) {
9853 ADD_INSN(ret, node, pop);
9854 }
9855 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
9856 ADD_LABEL(ret, end_label);
9857 break;
9858 }
9859
9860 case NODE_MASGN:{
9861 compile_massign(iseq, ret, node, popped);
9862 break;
9863 }
9864
9865 case NODE_LASGN:{
9866 ID id = RNODE_LASGN(node)->nd_vid;
9867 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9868
9869 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
9870 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
9871
9872 if (!popped) {
9873 ADD_INSN(ret, node, dup);
9874 }
9875 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9876 break;
9877 }
9878 case NODE_DASGN: {
9879 int idx, lv, ls;
9880 ID id = RNODE_DASGN(node)->nd_vid;
9881 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
9882 debugi("dassn id", rb_id2str(id) ? id : '*');
9883
9884 if (!popped) {
9885 ADD_INSN(ret, node, dup);
9886 }
9887
9888 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
9889
9890 if (idx < 0) {
9891 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
9892 rb_id2str(id));
9893 goto ng;
9894 }
9895 ADD_SETLOCAL(ret, node, ls - idx, lv);
9896 break;
9897 }
9898 case NODE_GASGN:{
9899 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
9900
9901 if (!popped) {
9902 ADD_INSN(ret, node, dup);
9903 }
9904 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
9905 break;
9906 }
9907 case NODE_IASGN:{
9908 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
9909 if (!popped) {
9910 ADD_INSN(ret, node, dup);
9911 }
9912 ADD_INSN2(ret, node, setinstancevariable,
9913 ID2SYM(RNODE_IASGN(node)->nd_vid),
9914 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
9915 break;
9916 }
9917 case NODE_CDECL:{
9918 if (RNODE_CDECL(node)->nd_vid) {
9919 CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
9920
9921 if (!popped) {
9922 ADD_INSN(ret, node, dup);
9923 }
9924
9925 ADD_INSN1(ret, node, putspecialobject,
9926 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9927 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
9928 }
9929 else {
9930 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
9931 CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
9932 ADD_INSN(ret, node, swap);
9933
9934 if (!popped) {
9935 ADD_INSN1(ret, node, topn, INT2FIX(1));
9936 ADD_INSN(ret, node, swap);
9937 }
9938
9939 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
9940 }
9941 break;
9942 }
9943 case NODE_CVASGN:{
9944 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
9945 if (!popped) {
9946 ADD_INSN(ret, node, dup);
9947 }
9948 ADD_INSN2(ret, node, setclassvariable,
9949 ID2SYM(RNODE_CVASGN(node)->nd_vid),
9950 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
9951 break;
9952 }
9953 case NODE_OP_ASGN1:
9954 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9955 break;
9956 case NODE_OP_ASGN2:
9957 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9958 break;
9959 case NODE_OP_CDECL:
9960 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9961 break;
9962 case NODE_OP_ASGN_AND:
9963 case NODE_OP_ASGN_OR:
9964 CHECK(compile_op_log(iseq, ret, node, popped, type));
9965 break;
9966 case NODE_CALL: /* obj.foo */
9967 case NODE_OPCALL: /* foo[] */
9968 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9969 break;
9970 }
9971 case NODE_QCALL: /* obj&.foo */
9972 case NODE_FCALL: /* foo() */
9973 case NODE_VCALL: /* foo (variable or call) */
9974 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
9975 goto ng;
9976 }
9977 break;
9978 case NODE_SUPER:
9979 case NODE_ZSUPER:
9980 CHECK(compile_super(iseq, ret, node, popped, type));
9981 break;
9982 case NODE_LIST:{
9983 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9984 break;
9985 }
9986 case NODE_ZLIST:{
9987 if (!popped) {
9988 ADD_INSN1(ret, node, newarray, INT2FIX(0));
9989 }
9990 break;
9991 }
9992 case NODE_HASH:
9993 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
9994 break;
9995 case NODE_RETURN:
9996 CHECK(compile_return(iseq, ret, node, popped));
9997 break;
9998 case NODE_YIELD:
9999 CHECK(compile_yield(iseq, ret, node, popped));
10000 break;
10001 case NODE_LVAR:{
10002 if (!popped) {
10003 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10004 }
10005 break;
10006 }
10007 case NODE_DVAR:{
10008 int lv, idx, ls;
10009 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10010 if (!popped) {
10011 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10012 if (idx < 0) {
10013 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10014 rb_id2str(RNODE_DVAR(node)->nd_vid));
10015 goto ng;
10016 }
10017 ADD_GETLOCAL(ret, node, ls - idx, lv);
10018 }
10019 break;
10020 }
10021 case NODE_GVAR:{
10022 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10023 if (popped) {
10024 ADD_INSN(ret, node, pop);
10025 }
10026 break;
10027 }
10028 case NODE_IVAR:{
10029 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10030 if (!popped) {
10031 ADD_INSN2(ret, node, getinstancevariable,
10032 ID2SYM(RNODE_IVAR(node)->nd_vid),
10033 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10034 }
10035 break;
10036 }
10037 case NODE_CONST:{
10038 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10039
10040 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10041 body->ic_size++;
10042 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10043 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10044 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10045 }
10046 else {
10047 ADD_INSN(ret, node, putnil);
10048 ADD_INSN1(ret, node, putobject, Qtrue);
10049 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10050 }
10051
10052 if (popped) {
10053 ADD_INSN(ret, node, pop);
10054 }
10055 break;
10056 }
10057 case NODE_CVAR:{
10058 if (!popped) {
10059 ADD_INSN2(ret, node, getclassvariable,
10060 ID2SYM(RNODE_CVAR(node)->nd_vid),
10061 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10062 }
10063 break;
10064 }
10065 case NODE_NTH_REF:{
10066 if (!popped) {
10067 if (!RNODE_NTH_REF(node)->nd_nth) {
10068 ADD_INSN(ret, node, putnil);
10069 break;
10070 }
10071 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10072 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10073 }
10074 break;
10075 }
10076 case NODE_BACK_REF:{
10077 if (!popped) {
10078 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10079 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10080 }
10081 break;
10082 }
10083 case NODE_MATCH:
10084 case NODE_MATCH2:
10085 case NODE_MATCH3:
10086 CHECK(compile_match(iseq, ret, node, popped, type));
10087 break;
10088 case NODE_LIT:{
10089 debugp_param("lit", RNODE_LIT(node)->nd_lit);
10090 if (!popped) {
10091 ADD_INSN1(ret, node, putobject, RNODE_LIT(node)->nd_lit);
10092 RB_OBJ_WRITTEN(iseq, Qundef, RNODE_LIT(node)->nd_lit);
10093 }
10094 break;
10095 }
10096 case NODE_STR:{
10097 debugp_param("nd_lit", RNODE_STR(node)->nd_lit);
10098 if (!popped) {
10099 VALUE lit = RNODE_STR(node)->nd_lit;
10100 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
10101 lit = rb_fstring(lit);
10102 ADD_INSN1(ret, node, putstring, lit);
10103 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10104 }
10105 else {
10106 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
10107 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
10108 lit = rb_str_dup(lit);
10109 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
10110 lit = rb_str_freeze(lit);
10111 }
10112 else {
10113 lit = rb_fstring(lit);
10114 }
10115 ADD_INSN1(ret, node, putobject, lit);
10116 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10117 }
10118 }
10119 break;
10120 }
10121 case NODE_DSTR:{
10122 compile_dstr(iseq, ret, node);
10123
10124 if (popped) {
10125 ADD_INSN(ret, node, pop);
10126 }
10127 break;
10128 }
10129 case NODE_XSTR:{
10130 ADD_CALL_RECEIVER(ret, node);
10131 VALUE str = rb_fstring(RNODE_XSTR(node)->nd_lit);
10132 ADD_INSN1(ret, node, putobject, str);
10133 RB_OBJ_WRITTEN(iseq, Qundef, str);
10134 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
10135
10136 if (popped) {
10137 ADD_INSN(ret, node, pop);
10138 }
10139 break;
10140 }
10141 case NODE_DXSTR:{
10142 ADD_CALL_RECEIVER(ret, node);
10143 compile_dstr(iseq, ret, node);
10144 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
10145
10146 if (popped) {
10147 ADD_INSN(ret, node, pop);
10148 }
10149 break;
10150 }
10151 case NODE_EVSTR:
10152 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
10153 break;
10154 case NODE_DREGX:
10155 compile_dregx(iseq, ret, node, popped);
10156 break;
10157 case NODE_ONCE:{
10158 int ic_index = body->ise_size++;
10159 const rb_iseq_t *block_iseq;
10160 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
10161
10162 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
10163 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
10164
10165 if (popped) {
10166 ADD_INSN(ret, node, pop);
10167 }
10168 break;
10169 }
10170 case NODE_ARGSCAT:{
10171 if (popped) {
10172 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
10173 ADD_INSN1(ret, node, splatarray, Qfalse);
10174 ADD_INSN(ret, node, pop);
10175 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
10176 ADD_INSN1(ret, node, splatarray, Qfalse);
10177 ADD_INSN(ret, node, pop);
10178 }
10179 else {
10180 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
10181 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
10182 ADD_INSN(ret, node, concatarray);
10183 }
10184 break;
10185 }
10186 case NODE_ARGSPUSH:{
10187 if (popped) {
10188 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
10189 ADD_INSN1(ret, node, splatarray, Qfalse);
10190 ADD_INSN(ret, node, pop);
10191 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
10192 }
10193 else {
10194 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
10195 CHECK(compile_array_1(iseq, ret, RNODE_ARGSPUSH(node)->nd_body));
10196 ADD_INSN(ret, node, concatarray);
10197 }
10198 break;
10199 }
10200 case NODE_SPLAT:{
10201 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
10202 ADD_INSN1(ret, node, splatarray, Qtrue);
10203
10204 if (popped) {
10205 ADD_INSN(ret, node, pop);
10206 }
10207 break;
10208 }
10209 case NODE_DEFN:{
10210 ID mid = RNODE_DEFN(node)->nd_mid;
10211 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
10212 rb_id2str(mid),
10213 ISEQ_TYPE_METHOD, line);
10214
10215 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
10216 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
10217 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
10218
10219 if (!popped) {
10220 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
10221 }
10222
10223 break;
10224 }
10225 case NODE_DEFS:{
10226 ID mid = RNODE_DEFS(node)->nd_mid;
10227 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
10228 rb_id2str(mid),
10229 ISEQ_TYPE_METHOD, line);
10230
10231 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
10232 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
10233 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
10234 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
10235
10236 if (!popped) {
10237 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
10238 }
10239 break;
10240 }
10241 case NODE_ALIAS:{
10242 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10243 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
10244 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
10245 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
10246 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
10247
10248 if (popped) {
10249 ADD_INSN(ret, node, pop);
10250 }
10251 break;
10252 }
10253 case NODE_VALIAS:{
10254 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10255 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
10256 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
10257 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
10258
10259 if (popped) {
10260 ADD_INSN(ret, node, pop);
10261 }
10262 break;
10263 }
10264 case NODE_UNDEF:{
10265 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10266 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
10267 CHECK(COMPILE(ret, "undef arg", RNODE_UNDEF(node)->nd_undef));
10268 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
10269
10270 if (popped) {
10271 ADD_INSN(ret, node, pop);
10272 }
10273 break;
10274 }
10275 case NODE_CLASS:{
10276 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
10277 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
10278 ISEQ_TYPE_CLASS, line);
10279 const int flags = VM_DEFINECLASS_TYPE_CLASS |
10280 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
10281 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
10282
10283 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
10284 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
10285 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
10286
10287 if (popped) {
10288 ADD_INSN(ret, node, pop);
10289 }
10290 break;
10291 }
10292 case NODE_MODULE:{
10293 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
10294 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
10295 ISEQ_TYPE_CLASS, line);
10296 const int flags = VM_DEFINECLASS_TYPE_MODULE |
10297 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
10298
10299 ADD_INSN (ret, node, putnil); /* dummy */
10300 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
10301 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
10302
10303 if (popped) {
10304 ADD_INSN(ret, node, pop);
10305 }
10306 break;
10307 }
10308 case NODE_SCLASS:{
10309 ID singletonclass;
10310 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
10311 ISEQ_TYPE_CLASS, line);
10312
10313 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
10314 ADD_INSN (ret, node, putnil);
10315 CONST_ID(singletonclass, "singletonclass");
10316 ADD_INSN3(ret, node, defineclass,
10317 ID2SYM(singletonclass), singleton_class,
10318 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
10319 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
10320
10321 if (popped) {
10322 ADD_INSN(ret, node, pop);
10323 }
10324 break;
10325 }
10326 case NODE_COLON2:
10327 CHECK(compile_colon2(iseq, ret, node, popped));
10328 break;
10329 case NODE_COLON3:
10330 CHECK(compile_colon3(iseq, ret, node, popped));
10331 break;
10332 case NODE_DOT2:
10333 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
10334 break;
10335 case NODE_DOT3:
10336 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
10337 break;
10338 case NODE_FLIP2:
10339 case NODE_FLIP3:{
10340 LABEL *lend = NEW_LABEL(line);
10341 LABEL *ltrue = NEW_LABEL(line);
10342 LABEL *lfalse = NEW_LABEL(line);
10343 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
10344 ltrue, lfalse));
10345 ADD_LABEL(ret, ltrue);
10346 ADD_INSN1(ret, node, putobject, Qtrue);
10347 ADD_INSNL(ret, node, jump, lend);
10348 ADD_LABEL(ret, lfalse);
10349 ADD_INSN1(ret, node, putobject, Qfalse);
10350 ADD_LABEL(ret, lend);
10351 break;
10352 }
10353 case NODE_SELF:{
10354 if (!popped) {
10355 ADD_INSN(ret, node, putself);
10356 }
10357 break;
10358 }
10359 case NODE_NIL:{
10360 if (!popped) {
10361 ADD_INSN(ret, node, putnil);
10362 }
10363 break;
10364 }
10365 case NODE_TRUE:{
10366 if (!popped) {
10367 ADD_INSN1(ret, node, putobject, Qtrue);
10368 }
10369 break;
10370 }
10371 case NODE_FALSE:{
10372 if (!popped) {
10373 ADD_INSN1(ret, node, putobject, Qfalse);
10374 }
10375 break;
10376 }
10377 case NODE_ERRINFO:
10378 CHECK(compile_errinfo(iseq, ret, node, popped));
10379 break;
10380 case NODE_DEFINED:
10381 if (!popped) {
10382 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
10383 }
10384 break;
10385 case NODE_POSTEXE:{
10386 /* compiled to:
10387 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10388 */
10389 int is_index = body->ise_size++;
10391 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
10392 const rb_iseq_t *once_iseq =
10393 new_child_iseq_with_callback(iseq, ifunc,
10394 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
10395
10396 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
10397 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
10398
10399 if (popped) {
10400 ADD_INSN(ret, node, pop);
10401 }
10402 break;
10403 }
10404 case NODE_KW_ARG:
10405 CHECK(compile_kw_arg(iseq, ret, node, popped));
10406 break;
10407 case NODE_DSYM:{
10408 compile_dstr(iseq, ret, node);
10409 if (!popped) {
10410 ADD_INSN(ret, node, intern);
10411 }
10412 else {
10413 ADD_INSN(ret, node, pop);
10414 }
10415 break;
10416 }
10417 case NODE_ATTRASGN:
10418 CHECK(compile_attrasgn(iseq, ret, node, popped));
10419 break;
10420 case NODE_LAMBDA:{
10421 /* compile same as lambda{...} */
10422 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
10423 VALUE argc = INT2FIX(0);
10424
10425 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10426 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
10427 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
10428
10429 if (popped) {
10430 ADD_INSN(ret, node, pop);
10431 }
10432 break;
10433 }
10434 default:
10435 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
10436 ng:
10437 debug_node_end();
10438 return COMPILE_NG;
10439 }
10440
10441 debug_node_end();
10442 return COMPILE_OK;
10443}
10444
10445/***************************/
10446/* instruction information */
10447/***************************/
10448
10449static int
10450insn_data_length(INSN *iobj)
10451{
10452 return insn_len(iobj->insn_id);
10453}
10454
10455static int
10456calc_sp_depth(int depth, INSN *insn)
10457{
10458 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
10459}
10460
10461static VALUE
10462opobj_inspect(VALUE obj)
10463{
10464 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
10465 switch (BUILTIN_TYPE(obj)) {
10466 case T_STRING:
10467 obj = rb_str_new_cstr(RSTRING_PTR(obj));
10468 break;
10469 case T_ARRAY:
10470 obj = rb_ary_dup(obj);
10471 break;
10472 default:
10473 break;
10474 }
10475 }
10476 return rb_inspect(obj);
10477}
10478
10479
10480
10481static VALUE
10482insn_data_to_s_detail(INSN *iobj)
10483{
10484 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
10485
10486 if (iobj->operands) {
10487 const char *types = insn_op_types(iobj->insn_id);
10488 int j;
10489
10490 for (j = 0; types[j]; j++) {
10491 char type = types[j];
10492
10493 switch (type) {
10494 case TS_OFFSET: /* label(destination position) */
10495 {
10496 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
10497 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
10498 break;
10499 }
10500 break;
10501 case TS_ISEQ: /* iseq */
10502 {
10503 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
10504 VALUE val = Qnil;
10505 if (0 && iseq) { /* TODO: invalidate now */
10506 val = (VALUE)iseq;
10507 }
10508 rb_str_concat(str, opobj_inspect(val));
10509 }
10510 break;
10511 case TS_LINDEX:
10512 case TS_NUM: /* ulong */
10513 case TS_VALUE: /* VALUE */
10514 {
10515 VALUE v = OPERAND_AT(iobj, j);
10516 if (!CLASS_OF(v))
10517 rb_str_cat2(str, "<hidden>");
10518 else {
10519 rb_str_concat(str, opobj_inspect(v));
10520 }
10521 break;
10522 }
10523 case TS_ID: /* ID */
10524 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10525 break;
10526 case TS_IC: /* inline cache */
10527 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10528 break;
10529 case TS_IVC: /* inline ivar cache */
10530 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10531 break;
10532 case TS_ICVARC: /* inline cvar cache */
10533 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10534 break;
10535 case TS_ISE: /* inline storage entry */
10536 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10537 break;
10538 case TS_CALLDATA: /* we store these as call infos at compile time */
10539 {
10540 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
10541 rb_str_cat2(str, "<calldata:");
10542 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
10543 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
10544 break;
10545 }
10546 case TS_CDHASH: /* case/when condition cache */
10547 rb_str_cat2(str, "<ch>");
10548 break;
10549 case TS_FUNCPTR:
10550 {
10551 void *func = (void *)OPERAND_AT(iobj, j);
10552#ifdef HAVE_DLADDR
10553 Dl_info info;
10554 if (dladdr(func, &info) && info.dli_sname) {
10555 rb_str_cat2(str, info.dli_sname);
10556 break;
10557 }
10558#endif
10559 rb_str_catf(str, "<%p>", func);
10560 }
10561 break;
10562 case TS_BUILTIN:
10563 rb_str_cat2(str, "<TS_BUILTIN>");
10564 break;
10565 default:{
10566 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
10567 }
10568 }
10569 if (types[j + 1]) {
10570 rb_str_cat2(str, ", ");
10571 }
10572 }
10573 }
10574 return str;
10575}
10576
10577static void
10578dump_disasm_list(const LINK_ELEMENT *link)
10579{
10580 dump_disasm_list_with_cursor(link, NULL, NULL);
10581}
10582
10583static void
10584dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
10585{
10586 int pos = 0;
10587 INSN *iobj;
10588 LABEL *lobj;
10589 VALUE str;
10590
10591 printf("-- raw disasm--------\n");
10592
10593 while (link) {
10594 if (curr) printf(curr == link ? "*" : " ");
10595 switch (link->type) {
10596 case ISEQ_ELEMENT_INSN:
10597 {
10598 iobj = (INSN *)link;
10599 str = insn_data_to_s_detail(iobj);
10600 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
10601 pos += insn_data_length(iobj);
10602 break;
10603 }
10604 case ISEQ_ELEMENT_LABEL:
10605 {
10606 lobj = (LABEL *)link;
10607 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
10608 dest == lobj ? " <---" : "");
10609 break;
10610 }
10611 case ISEQ_ELEMENT_TRACE:
10612 {
10613 TRACE *trace = (TRACE *)link;
10614 printf(" trace: %0x\n", trace->event);
10615 break;
10616 }
10617 case ISEQ_ELEMENT_ADJUST:
10618 {
10619 ADJUST *adjust = (ADJUST *)link;
10620 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
10621 break;
10622 }
10623 default:
10624 /* ignore */
10625 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
10626 }
10627 link = link->next;
10628 }
10629 printf("---------------------\n");
10630 fflush(stdout);
10631}
10632
10633int
10634rb_insn_len(VALUE insn)
10635{
10636 return insn_len(insn);
10637}
10638
10639const char *
10640rb_insns_name(int i)
10641{
10642 return insn_name(i);
10643}
10644
10645VALUE
10646rb_insns_name_array(void)
10647{
10648 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
10649 int i;
10650 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
10651 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
10652 }
10653 return rb_obj_freeze(ary);
10654}
10655
10656static LABEL *
10657register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
10658{
10659 LABEL *label = 0;
10660 st_data_t tmp;
10661 obj = rb_to_symbol_type(obj);
10662
10663 if (st_lookup(labels_table, obj, &tmp) == 0) {
10664 label = NEW_LABEL(0);
10665 st_insert(labels_table, obj, (st_data_t)label);
10666 }
10667 else {
10668 label = (LABEL *)tmp;
10669 }
10670 LABEL_REF(label);
10671 return label;
10672}
10673
10674static VALUE
10675get_exception_sym2type(VALUE sym)
10676{
10677 static VALUE symRescue, symEnsure, symRetry;
10678 static VALUE symBreak, symRedo, symNext;
10679
10680 if (symRescue == 0) {
10681 symRescue = ID2SYM(rb_intern_const("rescue"));
10682 symEnsure = ID2SYM(rb_intern_const("ensure"));
10683 symRetry = ID2SYM(rb_intern_const("retry"));
10684 symBreak = ID2SYM(rb_intern_const("break"));
10685 symRedo = ID2SYM(rb_intern_const("redo"));
10686 symNext = ID2SYM(rb_intern_const("next"));
10687 }
10688
10689 if (sym == symRescue) return CATCH_TYPE_RESCUE;
10690 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
10691 if (sym == symRetry) return CATCH_TYPE_RETRY;
10692 if (sym == symBreak) return CATCH_TYPE_BREAK;
10693 if (sym == symRedo) return CATCH_TYPE_REDO;
10694 if (sym == symNext) return CATCH_TYPE_NEXT;
10695 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
10696 return 0;
10697}
10698
10699static int
10700iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
10701 VALUE exception)
10702{
10703 int i;
10704
10705 for (i=0; i<RARRAY_LEN(exception); i++) {
10706 const rb_iseq_t *eiseq;
10707 VALUE v, type;
10708 LABEL *lstart, *lend, *lcont;
10709 unsigned int sp;
10710
10711 v = rb_to_array_type(RARRAY_AREF(exception, i));
10712 if (RARRAY_LEN(v) != 6) {
10713 rb_raise(rb_eSyntaxError, "wrong exception entry");
10714 }
10715 type = get_exception_sym2type(RARRAY_AREF(v, 0));
10716 if (NIL_P(RARRAY_AREF(v, 1))) {
10717 eiseq = NULL;
10718 }
10719 else {
10720 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
10721 }
10722
10723 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
10724 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
10725 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
10726 sp = NUM2UINT(RARRAY_AREF(v, 5));
10727
10728 /* TODO: Dirty Hack! Fix me */
10729 if (type == CATCH_TYPE_RESCUE ||
10730 type == CATCH_TYPE_BREAK ||
10731 type == CATCH_TYPE_NEXT) {
10732 ++sp;
10733 }
10734
10735 lcont->sp = sp;
10736
10737 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
10738
10739 RB_GC_GUARD(v);
10740 }
10741 return COMPILE_OK;
10742}
10743
10744static struct st_table *
10745insn_make_insn_table(void)
10746{
10747 struct st_table *table;
10748 int i;
10749 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10750
10751 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10752 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
10753 }
10754
10755 return table;
10756}
10757
10758static const rb_iseq_t *
10759iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
10760{
10761 VALUE iseqw;
10762 const rb_iseq_t *loaded_iseq;
10763
10764 if (RB_TYPE_P(op, T_ARRAY)) {
10765 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
10766 }
10767 else if (CLASS_OF(op) == rb_cISeq) {
10768 iseqw = op;
10769 }
10770 else {
10771 rb_raise(rb_eSyntaxError, "ISEQ is required");
10772 }
10773
10774 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10775 return loaded_iseq;
10776}
10777
10778static VALUE
10779iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
10780{
10781 ID mid = 0;
10782 int orig_argc = 0;
10783 unsigned int flag = 0;
10784 struct rb_callinfo_kwarg *kw_arg = 0;
10785
10786 if (!NIL_P(op)) {
10787 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
10788 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
10789 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
10790 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
10791
10792 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
10793 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
10794 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
10795
10796 if (!NIL_P(vkw_arg)) {
10797 int i;
10798 int len = RARRAY_LENINT(vkw_arg);
10799 size_t n = rb_callinfo_kwarg_bytes(len);
10800
10801 kw_arg = xmalloc(n);
10802 kw_arg->references = 0;
10803 kw_arg->keyword_len = len;
10804 for (i = 0; i < len; i++) {
10805 VALUE kw = RARRAY_AREF(vkw_arg, i);
10806 SYM2ID(kw); /* make immortal */
10807 kw_arg->keywords[i] = kw;
10808 }
10809 }
10810 }
10811
10812 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10813 RB_OBJ_WRITTEN(iseq, Qundef, ci);
10814 return (VALUE)ci;
10815}
10816
10817static rb_event_flag_t
10818event_name_to_flag(VALUE sym)
10819{
10820#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10821 CHECK_EVENT(RUBY_EVENT_LINE);
10822 CHECK_EVENT(RUBY_EVENT_CLASS);
10823 CHECK_EVENT(RUBY_EVENT_END);
10824 CHECK_EVENT(RUBY_EVENT_CALL);
10825 CHECK_EVENT(RUBY_EVENT_RETURN);
10826 CHECK_EVENT(RUBY_EVENT_B_CALL);
10827 CHECK_EVENT(RUBY_EVENT_B_RETURN);
10828 CHECK_EVENT(RUBY_EVENT_RESCUE);
10829#undef CHECK_EVENT
10830 return RUBY_EVENT_NONE;
10831}
10832
10833static int
10834iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
10835 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10836{
10837 /* TODO: body should be frozen */
10838 long i, len = RARRAY_LEN(body);
10839 struct st_table *labels_table = DATA_PTR(labels_wrapper);
10840 int j;
10841 int line_no = 0, node_id = -1, insn_idx = 0;
10842 int ret = COMPILE_OK;
10843
10844 /*
10845 * index -> LABEL *label
10846 */
10847 static struct st_table *insn_table;
10848
10849 if (insn_table == 0) {
10850 insn_table = insn_make_insn_table();
10851 }
10852
10853 for (i=0; i<len; i++) {
10854 VALUE obj = RARRAY_AREF(body, i);
10855
10856 if (SYMBOL_P(obj)) {
10857 rb_event_flag_t event;
10858 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
10859 ADD_TRACE(anchor, event);
10860 }
10861 else {
10862 LABEL *label = register_label(iseq, labels_table, obj);
10863 ADD_LABEL(anchor, label);
10864 }
10865 }
10866 else if (FIXNUM_P(obj)) {
10867 line_no = NUM2INT(obj);
10868 }
10869 else if (RB_TYPE_P(obj, T_ARRAY)) {
10870 VALUE *argv = 0;
10871 int argc = RARRAY_LENINT(obj) - 1;
10872 st_data_t insn_id;
10873 VALUE insn;
10874
10875 if (node_ids) {
10876 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
10877 }
10878
10879 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
10880 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10881 /* TODO: exception */
10882 COMPILE_ERROR(iseq, line_no,
10883 "unknown instruction: %+"PRIsVALUE, insn);
10884 ret = COMPILE_NG;
10885 break;
10886 }
10887
10888 if (argc != insn_len((VALUE)insn_id)-1) {
10889 COMPILE_ERROR(iseq, line_no,
10890 "operand size mismatch");
10891 ret = COMPILE_NG;
10892 break;
10893 }
10894
10895 if (argc > 0) {
10896 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
10897
10898 // add element before operand setup to make GC root
10899 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10900 ADD_ELEM(anchor,
10901 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10902 (enum ruby_vminsn_type)insn_id, argc, argv));
10903
10904 for (j=0; j<argc; j++) {
10905 VALUE op = rb_ary_entry(obj, j+1);
10906 switch (insn_op_type((VALUE)insn_id, j)) {
10907 case TS_OFFSET: {
10908 LABEL *label = register_label(iseq, labels_table, op);
10909 argv[j] = (VALUE)label;
10910 break;
10911 }
10912 case TS_LINDEX:
10913 case TS_NUM:
10914 (void)NUM2INT(op);
10915 argv[j] = op;
10916 break;
10917 case TS_VALUE:
10918 argv[j] = op;
10919 RB_OBJ_WRITTEN(iseq, Qundef, op);
10920 break;
10921 case TS_ISEQ:
10922 {
10923 if (op != Qnil) {
10924 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
10925 argv[j] = v;
10926 RB_OBJ_WRITTEN(iseq, Qundef, v);
10927 }
10928 else {
10929 argv[j] = 0;
10930 }
10931 }
10932 break;
10933 case TS_ISE:
10934 argv[j] = op;
10935 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
10936 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
10937 }
10938 break;
10939 case TS_IC:
10940 {
10941 VALUE segments = rb_ary_new();
10942 op = rb_to_array_type(op);
10943
10944 for (int i = 0; i < RARRAY_LEN(op); i++) {
10945 VALUE sym = RARRAY_AREF(op, i);
10946 sym = rb_to_symbol_type(sym);
10947 rb_ary_push(segments, sym);
10948 }
10949
10950 RB_GC_GUARD(op);
10951 argv[j] = segments;
10952 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10953 ISEQ_BODY(iseq)->ic_size++;
10954 }
10955 break;
10956 case TS_IVC: /* inline ivar cache */
10957 argv[j] = op;
10958 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
10959 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
10960 }
10961 break;
10962 case TS_ICVARC: /* inline cvar cache */
10963 argv[j] = op;
10964 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
10965 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
10966 }
10967 break;
10968 case TS_CALLDATA:
10969 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10970 break;
10971 case TS_ID:
10972 argv[j] = rb_to_symbol_type(op);
10973 break;
10974 case TS_CDHASH:
10975 {
10976 int i;
10977 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
10978
10979 RHASH_TBL_RAW(map)->type = &cdhash_type;
10980 op = rb_to_array_type(op);
10981 for (i=0; i<RARRAY_LEN(op); i+=2) {
10982 VALUE key = RARRAY_AREF(op, i);
10983 VALUE sym = RARRAY_AREF(op, i+1);
10984 LABEL *label =
10985 register_label(iseq, labels_table, sym);
10986 rb_hash_aset(map, key, (VALUE)label | 1);
10987 }
10988 RB_GC_GUARD(op);
10989 argv[j] = map;
10990 RB_OBJ_WRITTEN(iseq, Qundef, map);
10991 }
10992 break;
10993 case TS_FUNCPTR:
10994 {
10995#if SIZEOF_VALUE <= SIZEOF_LONG
10996 long funcptr = NUM2LONG(op);
10997#else
10998 LONG_LONG funcptr = NUM2LL(op);
10999#endif
11000 argv[j] = (VALUE)funcptr;
11001 }
11002 break;
11003 default:
11004 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11005 }
11006 }
11007 }
11008 else {
11009 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
11010 ADD_ELEM(anchor,
11011 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
11012 (enum ruby_vminsn_type)insn_id, argc, NULL));
11013 }
11014 }
11015 else {
11016 rb_raise(rb_eTypeError, "unexpected object for instruction");
11017 }
11018 }
11019 DATA_PTR(labels_wrapper) = 0;
11020 validate_labels(iseq, labels_table);
11021 if (!ret) return ret;
11022 return iseq_setup(iseq, anchor);
11023}
11024
11025#define CHECK_ARRAY(v) rb_to_array_type(v)
11026#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11027
11028static int
11029int_param(int *dst, VALUE param, VALUE sym)
11030{
11031 VALUE val = rb_hash_aref(param, sym);
11032 if (FIXNUM_P(val)) {
11033 *dst = FIX2INT(val);
11034 return TRUE;
11035 }
11036 else if (!NIL_P(val)) {
11037 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
11038 sym, val);
11039 }
11040 return FALSE;
11041}
11042
11043static const struct rb_iseq_param_keyword *
11044iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
11045{
11046 int i, j;
11047 int len = RARRAY_LENINT(keywords);
11048 int default_len;
11049 VALUE key, sym, default_val;
11050 VALUE *dvs;
11051 ID *ids;
11052 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
11053
11054 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
11055
11056 keyword->num = len;
11057#define SYM(s) ID2SYM(rb_intern_const(#s))
11058 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
11059 i = keyword->bits_start - keyword->num;
11060 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
11061#undef SYM
11062
11063 /* required args */
11064 for (i = 0; i < len; i++) {
11065 VALUE val = RARRAY_AREF(keywords, i);
11066
11067 if (!SYMBOL_P(val)) {
11068 goto default_values;
11069 }
11070 ids[i] = SYM2ID(val);
11071 keyword->required_num++;
11072 }
11073
11074 default_values: /* note: we intentionally preserve `i' from previous loop */
11075 default_len = len - i;
11076 if (default_len == 0) {
11077 keyword->table = ids;
11078 return keyword;
11079 }
11080 else if (default_len < 0) {
11082 }
11083
11084 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
11085
11086 for (j = 0; i < len; i++, j++) {
11087 key = RARRAY_AREF(keywords, i);
11088 CHECK_ARRAY(key);
11089
11090 switch (RARRAY_LEN(key)) {
11091 case 1:
11092 sym = RARRAY_AREF(key, 0);
11093 default_val = Qundef;
11094 break;
11095 case 2:
11096 sym = RARRAY_AREF(key, 0);
11097 default_val = RARRAY_AREF(key, 1);
11098 break;
11099 default:
11100 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
11101 }
11102 ids[i] = SYM2ID(sym);
11103 dvs[j] = default_val;
11104 }
11105
11106 keyword->table = ids;
11107 keyword->default_values = dvs;
11108
11109 return keyword;
11110}
11111
11112static void
11113iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
11114{
11115 rb_gc_mark(obj);
11116}
11117
11118void
11119rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
11120{
11121 INSN *iobj = 0;
11122 size_t size = sizeof(INSN);
11123 unsigned int pos = 0;
11124
11125 while (storage) {
11126#ifdef STRICT_ALIGNMENT
11127 size_t padding = calc_padding((void *)&storage->buff[pos], size);
11128#else
11129 const size_t padding = 0; /* expected to be optimized by compiler */
11130#endif /* STRICT_ALIGNMENT */
11131 size_t offset = pos + size + padding;
11132 if (offset > storage->size || offset > storage->pos) {
11133 pos = 0;
11134 storage = storage->next;
11135 }
11136 else {
11137#ifdef STRICT_ALIGNMENT
11138 pos += (int)padding;
11139#endif /* STRICT_ALIGNMENT */
11140
11141 iobj = (INSN *)&storage->buff[pos];
11142
11143 if (iobj->operands) {
11144 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
11145 }
11146 pos += (int)size;
11147 }
11148 }
11149}
11150
11151void
11152rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
11153 VALUE exception, VALUE body)
11154{
11155#define SYM(s) ID2SYM(rb_intern_const(#s))
11156 int i, len;
11157 unsigned int arg_size, local_size, stack_max;
11158 ID *tbl;
11159 struct st_table *labels_table = st_init_numtable();
11160 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
11161 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
11162 VALUE keywords = rb_hash_aref(params, SYM(keyword));
11163 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
11164 DECL_ANCHOR(anchor);
11165 INIT_ANCHOR(anchor);
11166
11167 len = RARRAY_LENINT(locals);
11168 ISEQ_BODY(iseq)->local_table_size = len;
11169 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
11170
11171 for (i = 0; i < len; i++) {
11172 VALUE lv = RARRAY_AREF(locals, i);
11173
11174 if (sym_arg_rest == lv) {
11175 tbl[i] = 0;
11176 }
11177 else {
11178 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
11179 }
11180 }
11181
11182#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
11183 if (INT_PARAM(lead_num)) {
11184 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
11185 }
11186 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
11187 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
11188 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
11189 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
11190#undef INT_PARAM
11191 {
11192#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
11193 int x;
11194 INT_PARAM(arg_size);
11195 INT_PARAM(local_size);
11196 INT_PARAM(stack_max);
11197#undef INT_PARAM
11198 }
11199
11200 VALUE node_ids = Qfalse;
11201#ifdef USE_ISEQ_NODE_ID
11202 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
11203 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
11204 rb_raise(rb_eTypeError, "node_ids is not an array");
11205 }
11206#endif
11207
11208 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
11209 len = RARRAY_LENINT(arg_opt_labels);
11210 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
11211
11212 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
11213 VALUE *opt_table = ALLOC_N(VALUE, len);
11214
11215 for (i = 0; i < len; i++) {
11216 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
11217 LABEL *label = register_label(iseq, labels_table, ent);
11218 opt_table[i] = (VALUE)label;
11219 }
11220
11221 ISEQ_BODY(iseq)->param.opt_num = len - 1;
11222 ISEQ_BODY(iseq)->param.opt_table = opt_table;
11223 }
11224 }
11225 else if (!NIL_P(arg_opt_labels)) {
11226 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
11227 arg_opt_labels);
11228 }
11229
11230 if (RB_TYPE_P(keywords, T_ARRAY)) {
11231 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
11232 }
11233 else if (!NIL_P(keywords)) {
11234 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
11235 keywords);
11236 }
11237
11238 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
11239 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
11240 }
11241
11242 if (int_param(&i, params, SYM(kwrest))) {
11243 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
11244 if (keyword == NULL) {
11245 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
11246 }
11247 keyword->rest_start = i;
11248 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
11249 }
11250#undef SYM
11251 iseq_calc_param_size(iseq);
11252
11253 /* exception */
11254 iseq_build_from_ary_exception(iseq, labels_table, exception);
11255
11256 /* body */
11257 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
11258
11259 ISEQ_BODY(iseq)->param.size = arg_size;
11260 ISEQ_BODY(iseq)->local_table_size = local_size;
11261 ISEQ_BODY(iseq)->stack_max = stack_max;
11262}
11263
11264/* for parser */
11265
11266int
11267rb_dvar_defined(ID id, const rb_iseq_t *iseq)
11268{
11269 if (iseq) {
11270 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
11271 while (body->type == ISEQ_TYPE_BLOCK ||
11272 body->type == ISEQ_TYPE_RESCUE ||
11273 body->type == ISEQ_TYPE_ENSURE ||
11274 body->type == ISEQ_TYPE_EVAL ||
11275 body->type == ISEQ_TYPE_MAIN
11276 ) {
11277 unsigned int i;
11278
11279 for (i = 0; i < body->local_table_size; i++) {
11280 if (body->local_table[i] == id) {
11281 return 1;
11282 }
11283 }
11284 iseq = body->parent_iseq;
11285 body = ISEQ_BODY(iseq);
11286 }
11287 }
11288 return 0;
11289}
11290
11291int
11292rb_local_defined(ID id, const rb_iseq_t *iseq)
11293{
11294 if (iseq) {
11295 unsigned int i;
11296 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
11297
11298 for (i=0; i<body->local_table_size; i++) {
11299 if (body->local_table[i] == id) {
11300 return 1;
11301 }
11302 }
11303 }
11304 return 0;
11305}
11306
11307/* ISeq binary format */
11308
11309#ifndef IBF_ISEQ_DEBUG
11310#define IBF_ISEQ_DEBUG 0
11311#endif
11312
11313#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
11314#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
11315#endif
11316
11317typedef uint32_t ibf_offset_t;
11318#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
11319
11320#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
11321#ifdef RUBY_DEVEL
11322#define IBF_DEVEL_VERSION 4
11323#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
11324#else
11325#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
11326#endif
11327
11328static const char IBF_ENDIAN_MARK =
11329#ifdef WORDS_BIGENDIAN
11330 'b'
11331#else
11332 'l'
11333#endif
11334 ;
11335
11337 char magic[4]; /* YARB */
11338 uint32_t major_version;
11339 uint32_t minor_version;
11340 uint32_t size;
11341 uint32_t extra_size;
11342
11343 uint32_t iseq_list_size;
11344 uint32_t global_object_list_size;
11345 ibf_offset_t iseq_list_offset;
11346 ibf_offset_t global_object_list_offset;
11347 uint8_t endian;
11348 uint8_t wordsize; /* assume no 2048-bit CPU */
11349};
11350
11352 VALUE str;
11353 st_table *obj_table; /* obj -> obj number */
11354};
11355
11356struct ibf_dump {
11357 st_table *iseq_table; /* iseq -> iseq number */
11358 struct ibf_dump_buffer global_buffer;
11359 struct ibf_dump_buffer *current_buffer;
11360};
11361
11363 const char *buff;
11364 ibf_offset_t size;
11365
11366 VALUE obj_list; /* [obj0, ...] */
11367 unsigned int obj_list_size;
11368 ibf_offset_t obj_list_offset;
11369};
11370
11371struct ibf_load {
11372 const struct ibf_header *header;
11373 VALUE iseq_list; /* [iseq0, ...] */
11374 struct ibf_load_buffer global_buffer;
11375 VALUE loader_obj;
11376 rb_iseq_t *iseq;
11377 VALUE str;
11378 struct ibf_load_buffer *current_buffer;
11379};
11380
11382 long size;
11383 VALUE buffer[1];
11384};
11385
11386static void
11387pinned_list_mark(void *ptr)
11388{
11389 long i;
11390 struct pinned_list *list = (struct pinned_list *)ptr;
11391 for (i = 0; i < list->size; i++) {
11392 if (list->buffer[i]) {
11393 rb_gc_mark(list->buffer[i]);
11394 }
11395 }
11396}
11397
11398static const rb_data_type_t pinned_list_type = {
11399 "pinned_list",
11400 {
11401 pinned_list_mark,
11403 NULL, // No external memory to report,
11404 },
11405 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
11406};
11407
11408static VALUE
11409pinned_list_fetch(VALUE list, long offset)
11410{
11411 struct pinned_list * ptr;
11412
11413 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11414
11415 if (offset >= ptr->size) {
11416 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11417 }
11418
11419 return ptr->buffer[offset];
11420}
11421
11422static void
11423pinned_list_store(VALUE list, long offset, VALUE object)
11424{
11425 struct pinned_list * ptr;
11426
11427 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11428
11429 if (offset >= ptr->size) {
11430 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11431 }
11432
11433 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
11434}
11435
11436static VALUE
11437pinned_list_new(long size)
11438{
11439 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
11440 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
11441 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
11442 ptr->size = size;
11443 return obj_list;
11444}
11445
11446static ibf_offset_t
11447ibf_dump_pos(struct ibf_dump *dump)
11448{
11449 long pos = RSTRING_LEN(dump->current_buffer->str);
11450#if SIZEOF_LONG > SIZEOF_INT
11451 if (pos >= UINT_MAX) {
11452 rb_raise(rb_eRuntimeError, "dump size exceeds");
11453 }
11454#endif
11455 return (unsigned int)pos;
11456}
11457
11458static void
11459ibf_dump_align(struct ibf_dump *dump, size_t align)
11460{
11461 ibf_offset_t pos = ibf_dump_pos(dump);
11462 if (pos % align) {
11463 static const char padding[sizeof(VALUE)];
11464 size_t size = align - ((size_t)pos % align);
11465#if SIZEOF_LONG > SIZEOF_INT
11466 if (pos + size >= UINT_MAX) {
11467 rb_raise(rb_eRuntimeError, "dump size exceeds");
11468 }
11469#endif
11470 for (; size > sizeof(padding); size -= sizeof(padding)) {
11471 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
11472 }
11473 rb_str_cat(dump->current_buffer->str, padding, size);
11474 }
11475}
11476
11477static ibf_offset_t
11478ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
11479{
11480 ibf_offset_t pos = ibf_dump_pos(dump);
11481 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
11482 /* TODO: overflow check */
11483 return pos;
11484}
11485
11486static ibf_offset_t
11487ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
11488{
11489 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
11490}
11491
11492static void
11493ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
11494{
11495 VALUE str = dump->current_buffer->str;
11496 char *ptr = RSTRING_PTR(str);
11497 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
11498 rb_bug("ibf_dump_overwrite: overflow");
11499 memcpy(ptr + offset, buff, size);
11500}
11501
11502static const void *
11503ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
11504{
11505 ibf_offset_t beg = *offset;
11506 *offset += size;
11507 return load->current_buffer->buff + beg;
11508}
11509
11510static void *
11511ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
11512{
11513 void *buff = ruby_xmalloc2(x, y);
11514 size_t size = x * y;
11515 memcpy(buff, load->current_buffer->buff + offset, size);
11516 return buff;
11517}
11518
11519#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
11520
11521#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
11522#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
11523#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
11524#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
11525#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
11526
11527static int
11528ibf_table_lookup(struct st_table *table, st_data_t key)
11529{
11530 st_data_t val;
11531
11532 if (st_lookup(table, key, &val)) {
11533 return (int)val;
11534 }
11535 else {
11536 return -1;
11537 }
11538}
11539
11540static int
11541ibf_table_find_or_insert(struct st_table *table, st_data_t key)
11542{
11543 int index = ibf_table_lookup(table, key);
11544
11545 if (index < 0) { /* not found */
11546 index = (int)table->num_entries;
11547 st_insert(table, key, (st_data_t)index);
11548 }
11549
11550 return index;
11551}
11552
11553/* dump/load generic */
11554
11555static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
11556
11557static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
11558static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
11559
11560static st_table *
11561ibf_dump_object_table_new(void)
11562{
11563 st_table *obj_table = st_init_numtable(); /* need free */
11564 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
11565
11566 return obj_table;
11567}
11568
11569static VALUE
11570ibf_dump_object(struct ibf_dump *dump, VALUE obj)
11571{
11572 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
11573}
11574
11575static VALUE
11576ibf_dump_id(struct ibf_dump *dump, ID id)
11577{
11578 if (id == 0 || rb_id2name(id) == NULL) {
11579 return 0;
11580 }
11581 return ibf_dump_object(dump, rb_id2sym(id));
11582}
11583
11584static ID
11585ibf_load_id(const struct ibf_load *load, const ID id_index)
11586{
11587 if (id_index == 0) {
11588 return 0;
11589 }
11590 VALUE sym = ibf_load_object(load, id_index);
11591 return rb_sym2id(sym);
11592}
11593
11594/* dump/load: code */
11595
11596static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
11597
11598static int
11599ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
11600{
11601 if (iseq == NULL) {
11602 return -1;
11603 }
11604 else {
11605 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
11606 }
11607}
11608
11609static unsigned char
11610ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
11611{
11612 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
11613 return (unsigned char)load->current_buffer->buff[(*offset)++];
11614}
11615
11616/*
11617 * Small uint serialization
11618 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
11619 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
11620 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
11621 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11622 * ...
11623 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11624 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11625 */
11626static void
11627ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
11628{
11629 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11630 ibf_dump_write(dump, &x, sizeof(VALUE));
11631 return;
11632 }
11633
11634 enum { max_byte_length = sizeof(VALUE) + 1 };
11635
11636 unsigned char bytes[max_byte_length];
11637 ibf_offset_t n;
11638
11639 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
11640 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11641 }
11642
11643 x <<= 1;
11644 x |= 1;
11645 x <<= n;
11646 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11647 n++;
11648
11649 ibf_dump_write(dump, bytes + max_byte_length - n, n);
11650}
11651
11652static VALUE
11653ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
11654{
11655 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11656 union { char s[sizeof(VALUE)]; VALUE v; } x;
11657
11658 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
11659 *offset += sizeof(VALUE);
11660
11661 return x.v;
11662 }
11663
11664 enum { max_byte_length = sizeof(VALUE) + 1 };
11665
11666 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
11667 const unsigned char c = buffer[*offset];
11668
11669 ibf_offset_t n =
11670 c & 1 ? 1 :
11671 c == 0 ? 9 : ntz_int32(c) + 1;
11672 VALUE x = (VALUE)c >> n;
11673
11674 if (*offset + n > load->current_buffer->size) {
11675 rb_raise(rb_eRuntimeError, "invalid byte sequence");
11676 }
11677
11678 ibf_offset_t i;
11679 for (i = 1; i < n; i++) {
11680 x <<= 8;
11681 x |= (VALUE)buffer[*offset + i];
11682 }
11683
11684 *offset += n;
11685 return x;
11686}
11687
11688static void
11689ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
11690{
11691 // short: index
11692 // short: name.length
11693 // bytes: name
11694 // // omit argc (only verify with name)
11695 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11696
11697 size_t len = strlen(bf->name);
11698 ibf_dump_write_small_value(dump, (VALUE)len);
11699 ibf_dump_write(dump, bf->name, len);
11700}
11701
11702static const struct rb_builtin_function *
11703ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
11704{
11705 int i = (int)ibf_load_small_value(load, offset);
11706 int len = (int)ibf_load_small_value(load, offset);
11707 const char *name = (char *)ibf_load_ptr(load, offset, len);
11708
11709 if (0) {
11710 fprintf(stderr, "%.*s!!\n", len, name);
11711 }
11712
11713 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
11714 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
11715 if (strncmp(table[i].name, name, len) != 0) {
11716 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11717 }
11718 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
11719
11720 return &table[i];
11721}
11722
11723static ibf_offset_t
11724ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
11725{
11726 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11727 const int iseq_size = body->iseq_size;
11728 int code_index;
11729 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11730
11731 ibf_offset_t offset = ibf_dump_pos(dump);
11732
11733 for (code_index=0; code_index<iseq_size;) {
11734 const VALUE insn = orig_code[code_index++];
11735 const char *types = insn_op_types(insn);
11736 int op_index;
11737
11738 /* opcode */
11739 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
11740 ibf_dump_write_small_value(dump, insn);
11741
11742 /* operands */
11743 for (op_index=0; types[op_index]; op_index++, code_index++) {
11744 VALUE op = orig_code[code_index];
11745 VALUE wv;
11746
11747 switch (types[op_index]) {
11748 case TS_CDHASH:
11749 case TS_VALUE:
11750 wv = ibf_dump_object(dump, op);
11751 break;
11752 case TS_ISEQ:
11753 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
11754 break;
11755 case TS_IC:
11756 {
11757 IC ic = (IC)op;
11758 VALUE arr = idlist_to_array(ic->segments);
11759 wv = ibf_dump_object(dump, arr);
11760 }
11761 break;
11762 case TS_ISE:
11763 case TS_IVC:
11764 case TS_ICVARC:
11765 {
11767 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
11768 }
11769 break;
11770 case TS_CALLDATA:
11771 {
11772 goto skip_wv;
11773 }
11774 case TS_ID:
11775 wv = ibf_dump_id(dump, (ID)op);
11776 break;
11777 case TS_FUNCPTR:
11778 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11779 goto skip_wv;
11780 case TS_BUILTIN:
11781 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
11782 goto skip_wv;
11783 default:
11784 wv = op;
11785 break;
11786 }
11787 ibf_dump_write_small_value(dump, wv);
11788 skip_wv:;
11789 }
11790 assert(insn_len(insn) == op_index+1);
11791 }
11792
11793 return offset;
11794}
11795
11796static VALUE *
11797ibf_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)
11798{
11799 VALUE iseqv = (VALUE)iseq;
11800 unsigned int code_index;
11801 ibf_offset_t reading_pos = bytecode_offset;
11802 VALUE *code = ALLOC_N(VALUE, iseq_size);
11803
11804 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
11805 struct rb_call_data *cd_entries = load_body->call_data;
11806 int ic_index = 0;
11807
11808 iseq_bits_t * mark_offset_bits;
11809
11810 iseq_bits_t tmp[1] = {0};
11811
11812 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
11813 mark_offset_bits = tmp;
11814 }
11815 else {
11816 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
11817 }
11818 bool needs_bitmap = false;
11819
11820 for (code_index=0; code_index<iseq_size;) {
11821 /* opcode */
11822 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11823 const char *types = insn_op_types(insn);
11824 int op_index;
11825
11826 code_index++;
11827
11828 /* operands */
11829 for (op_index=0; types[op_index]; op_index++, code_index++) {
11830 const char operand_type = types[op_index];
11831 switch (operand_type) {
11832 case TS_VALUE:
11833 {
11834 VALUE op = ibf_load_small_value(load, &reading_pos);
11835 VALUE v = ibf_load_object(load, op);
11836 code[code_index] = v;
11837 if (!SPECIAL_CONST_P(v)) {
11838 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11839 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11840 needs_bitmap = true;
11841 }
11842 break;
11843 }
11844 case TS_CDHASH:
11845 {
11846 VALUE op = ibf_load_small_value(load, &reading_pos);
11847 VALUE v = ibf_load_object(load, op);
11848 v = rb_hash_dup(v); // hash dumped as frozen
11849 RHASH_TBL_RAW(v)->type = &cdhash_type;
11850 rb_hash_rehash(v); // hash function changed
11851 freeze_hide_obj(v);
11852
11853 // Overwrite the existing hash in the object list. This
11854 // is to keep the object alive during load time.
11855 // [Bug #17984] [ruby-core:104259]
11856 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
11857
11858 code[code_index] = v;
11859 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11860 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11861 needs_bitmap = true;
11862 break;
11863 }
11864 case TS_ISEQ:
11865 {
11866 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
11867 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
11868 code[code_index] = v;
11869 if (!SPECIAL_CONST_P(v)) {
11870 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11871 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11872 needs_bitmap = true;
11873 }
11874 break;
11875 }
11876 case TS_IC:
11877 {
11878 VALUE op = ibf_load_small_value(load, &reading_pos);
11879 VALUE arr = ibf_load_object(load, op);
11880
11881 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
11882 ic->segments = array_to_idlist(arr);
11883
11884 code[code_index] = (VALUE)ic;
11885 }
11886 break;
11887 case TS_ISE:
11888 case TS_ICVARC:
11889 case TS_IVC:
11890 {
11891 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
11892
11893 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
11894 code[code_index] = (VALUE)ic;
11895
11896 if (operand_type == TS_IVC) {
11897 IVC cache = (IVC)ic;
11898
11899 if (insn == BIN(setinstancevariable)) {
11900 ID iv_name = (ID)code[code_index - 1];
11901 cache->iv_set_name = iv_name;
11902 }
11903 else {
11904 cache->iv_set_name = 0;
11905 }
11906
11907 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
11908 }
11909
11910 }
11911 break;
11912 case TS_CALLDATA:
11913 {
11914 code[code_index] = (VALUE)cd_entries++;
11915 }
11916 break;
11917 case TS_ID:
11918 {
11919 VALUE op = ibf_load_small_value(load, &reading_pos);
11920 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11921 }
11922 break;
11923 case TS_FUNCPTR:
11924 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11925 break;
11926 case TS_BUILTIN:
11927 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
11928 break;
11929 default:
11930 code[code_index] = ibf_load_small_value(load, &reading_pos);
11931 continue;
11932 }
11933 }
11934 if (insn_len(insn) != op_index+1) {
11935 rb_raise(rb_eRuntimeError, "operand size mismatch");
11936 }
11937 }
11938
11939 load_body->iseq_encoded = code;
11940 load_body->iseq_size = code_index;
11941
11942 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
11943 load_body->mark_bits.single = mark_offset_bits[0];
11944 }
11945 else {
11946 if (needs_bitmap) {
11947 load_body->mark_bits.list = mark_offset_bits;
11948 }
11949 else {
11950 load_body->mark_bits.list = 0;
11951 ruby_xfree(mark_offset_bits);
11952 }
11953 }
11954
11955 assert(code_index == iseq_size);
11956 assert(reading_pos == bytecode_offset + bytecode_size);
11957 return code;
11958}
11959
11960static ibf_offset_t
11961ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11962{
11963 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
11964
11965 if (opt_num > 0) {
11966 IBF_W_ALIGN(VALUE);
11967 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
11968 }
11969 else {
11970 return ibf_dump_pos(dump);
11971 }
11972}
11973
11974static VALUE *
11975ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
11976{
11977 if (opt_num > 0) {
11978 VALUE *table = ALLOC_N(VALUE, opt_num+1);
11979 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11980 return table;
11981 }
11982 else {
11983 return NULL;
11984 }
11985}
11986
11987static ibf_offset_t
11988ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
11989{
11990 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
11991
11992 if (kw) {
11993 struct rb_iseq_param_keyword dump_kw = *kw;
11994 int dv_num = kw->num - kw->required_num;
11995 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
11996 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
11997 int i;
11998
11999 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12000 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12001
12002 dump_kw.table = IBF_W(ids, ID, kw->num);
12003 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12004 IBF_W_ALIGN(struct rb_iseq_param_keyword);
12005 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12006 }
12007 else {
12008 return 0;
12009 }
12010}
12011
12012static const struct rb_iseq_param_keyword *
12013ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
12014{
12015 if (param_keyword_offset) {
12016 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
12017 ID *ids = IBF_R(kw->table, ID, kw->num);
12018 int dv_num = kw->num - kw->required_num;
12019 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
12020 int i;
12021
12022 for (i=0; i<kw->num; i++) {
12023 ids[i] = ibf_load_id(load, ids[i]);
12024 }
12025 for (i=0; i<dv_num; i++) {
12026 dvs[i] = ibf_load_object(load, dvs[i]);
12027 }
12028
12029 kw->table = ids;
12030 kw->default_values = dvs;
12031 return kw;
12032 }
12033 else {
12034 return NULL;
12035 }
12036}
12037
12038static ibf_offset_t
12039ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
12040{
12041 ibf_offset_t offset = ibf_dump_pos(dump);
12042 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
12043
12044 unsigned int i;
12045 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
12046 ibf_dump_write_small_value(dump, entries[i].line_no);
12047#ifdef USE_ISEQ_NODE_ID
12048 ibf_dump_write_small_value(dump, entries[i].node_id);
12049#endif
12050 ibf_dump_write_small_value(dump, entries[i].events);
12051 }
12052
12053 return offset;
12054}
12055
12056static struct iseq_insn_info_entry *
12057ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
12058{
12059 ibf_offset_t reading_pos = body_offset;
12060 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
12061
12062 unsigned int i;
12063 for (i = 0; i < size; i++) {
12064 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
12065#ifdef USE_ISEQ_NODE_ID
12066 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
12067#endif
12068 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
12069 }
12070
12071 return entries;
12072}
12073
12074static ibf_offset_t
12075ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
12076{
12077 ibf_offset_t offset = ibf_dump_pos(dump);
12078
12079 unsigned int last = 0;
12080 unsigned int i;
12081 for (i = 0; i < size; i++) {
12082 ibf_dump_write_small_value(dump, positions[i] - last);
12083 last = positions[i];
12084 }
12085
12086 return offset;
12087}
12088
12089static unsigned int *
12090ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
12091{
12092 ibf_offset_t reading_pos = positions_offset;
12093 unsigned int *positions = ALLOC_N(unsigned int, size);
12094
12095 unsigned int last = 0;
12096 unsigned int i;
12097 for (i = 0; i < size; i++) {
12098 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
12099 last = positions[i];
12100 }
12101
12102 return positions;
12103}
12104
12105static ibf_offset_t
12106ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12107{
12108 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12109 const int size = body->local_table_size;
12110 ID *table = ALLOCA_N(ID, size);
12111 int i;
12112
12113 for (i=0; i<size; i++) {
12114 table[i] = ibf_dump_id(dump, body->local_table[i]);
12115 }
12116
12117 IBF_W_ALIGN(ID);
12118 return ibf_dump_write(dump, table, sizeof(ID) * size);
12119}
12120
12121static ID *
12122ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
12123{
12124 if (size > 0) {
12125 ID *table = IBF_R(local_table_offset, ID, size);
12126 int i;
12127
12128 for (i=0; i<size; i++) {
12129 table[i] = ibf_load_id(load, table[i]);
12130 }
12131 return table;
12132 }
12133 else {
12134 return NULL;
12135 }
12136}
12137
12138static ibf_offset_t
12139ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12140{
12141 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
12142
12143 if (table) {
12144 int *iseq_indices = ALLOCA_N(int, table->size);
12145 unsigned int i;
12146
12147 for (i=0; i<table->size; i++) {
12148 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
12149 }
12150
12151 const ibf_offset_t offset = ibf_dump_pos(dump);
12152
12153 for (i=0; i<table->size; i++) {
12154 ibf_dump_write_small_value(dump, iseq_indices[i]);
12155 ibf_dump_write_small_value(dump, table->entries[i].type);
12156 ibf_dump_write_small_value(dump, table->entries[i].start);
12157 ibf_dump_write_small_value(dump, table->entries[i].end);
12158 ibf_dump_write_small_value(dump, table->entries[i].cont);
12159 ibf_dump_write_small_value(dump, table->entries[i].sp);
12160 }
12161 return offset;
12162 }
12163 else {
12164 return ibf_dump_pos(dump);
12165 }
12166}
12167
12168static struct iseq_catch_table *
12169ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
12170{
12171 if (size) {
12172 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
12173 table->size = size;
12174
12175 ibf_offset_t reading_pos = catch_table_offset;
12176
12177 unsigned int i;
12178 for (i=0; i<table->size; i++) {
12179 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12180 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
12181 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
12182 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
12183 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
12184 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
12185
12186 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
12187 }
12188 return table;
12189 }
12190 else {
12191 return NULL;
12192 }
12193}
12194
12195static ibf_offset_t
12196ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
12197{
12198 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12199 const unsigned int ci_size = body->ci_size;
12200 const struct rb_call_data *cds = body->call_data;
12201
12202 ibf_offset_t offset = ibf_dump_pos(dump);
12203
12204 unsigned int i;
12205
12206 for (i = 0; i < ci_size; i++) {
12207 const struct rb_callinfo *ci = cds[i].ci;
12208 if (ci != NULL) {
12209 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
12210 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
12211 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
12212
12213 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
12214 if (kwarg) {
12215 int len = kwarg->keyword_len;
12216 ibf_dump_write_small_value(dump, len);
12217 for (int j=0; j<len; j++) {
12218 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
12219 ibf_dump_write_small_value(dump, keyword);
12220 }
12221 }
12222 else {
12223 ibf_dump_write_small_value(dump, 0);
12224 }
12225 }
12226 else {
12227 // TODO: truncate NULL ci from call_data.
12228 ibf_dump_write_small_value(dump, (VALUE)-1);
12229 }
12230 }
12231
12232 return offset;
12233}
12234
12236 ID id;
12237 VALUE name;
12238 VALUE val;
12239};
12240
12242 size_t num;
12243 struct outer_variable_pair pairs[1];
12244};
12245
12246static enum rb_id_table_iterator_result
12247store_outer_variable(ID id, VALUE val, void *dump)
12248{
12249 struct outer_variable_list *ovlist = dump;
12250 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
12251 pair->id = id;
12252 pair->name = rb_id2str(id);
12253 pair->val = val;
12254 return ID_TABLE_CONTINUE;
12255}
12256
12257static int
12258outer_variable_cmp(const void *a, const void *b, void *arg)
12259{
12260 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
12261 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
12262 return rb_str_cmp(ap->name, bp->name);
12263}
12264
12265static ibf_offset_t
12266ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
12267{
12268 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
12269
12270 ibf_offset_t offset = ibf_dump_pos(dump);
12271
12272 size_t size = ovs ? rb_id_table_size(ovs) : 0;
12273 ibf_dump_write_small_value(dump, (VALUE)size);
12274 if (size > 0) {
12275 VALUE buff;
12276 size_t buffsize =
12277 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
12278 offsetof(struct outer_variable_list, pairs),
12279 rb_eArgError);
12280 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
12281 ovlist->num = 0;
12282 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
12283 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
12284 for (size_t i = 0; i < size; ++i) {
12285 ID id = ovlist->pairs[i].id;
12286 ID val = ovlist->pairs[i].val;
12287 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
12288 ibf_dump_write_small_value(dump, val);
12289 }
12290 }
12291
12292 return offset;
12293}
12294
12295/* note that we dump out rb_call_info but load back rb_call_data */
12296static void
12297ibf_load_ci_entries(const struct ibf_load *load,
12298 ibf_offset_t ci_entries_offset,
12299 unsigned int ci_size,
12300 struct rb_call_data **cd_ptr)
12301{
12302 ibf_offset_t reading_pos = ci_entries_offset;
12303
12304 unsigned int i;
12305
12306 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
12307 *cd_ptr = cds;
12308
12309 for (i = 0; i < ci_size; i++) {
12310 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
12311 if (mid_index != (VALUE)-1) {
12312 ID mid = ibf_load_id(load, mid_index);
12313 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
12314 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
12315
12316 struct rb_callinfo_kwarg *kwarg = NULL;
12317 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
12318 if (kwlen > 0) {
12319 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
12320 kwarg->references = 0;
12321 kwarg->keyword_len = kwlen;
12322 for (int j=0; j<kwlen; j++) {
12323 VALUE keyword = ibf_load_small_value(load, &reading_pos);
12324 kwarg->keywords[j] = ibf_load_object(load, keyword);
12325 }
12326 }
12327
12328 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
12329 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
12330 cds[i].cc = vm_cc_empty();
12331 }
12332 else {
12333 // NULL ci
12334 cds[i].ci = NULL;
12335 cds[i].cc = NULL;
12336 }
12337 }
12338}
12339
12340static struct rb_id_table *
12341ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
12342{
12343 ibf_offset_t reading_pos = outer_variables_offset;
12344
12345 struct rb_id_table *tbl = NULL;
12346
12347 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
12348
12349 if (table_size > 0) {
12350 tbl = rb_id_table_create(table_size);
12351 }
12352
12353 for (size_t i = 0; i < table_size; i++) {
12354 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
12355 VALUE value = ibf_load_small_value(load, &reading_pos);
12356 if (!key) key = rb_make_temporary_id(i);
12357 rb_id_table_insert(tbl, key, value);
12358 }
12359
12360 return tbl;
12361}
12362
12363static ibf_offset_t
12364ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
12365{
12366 assert(dump->current_buffer == &dump->global_buffer);
12367
12368 unsigned int *positions;
12369
12370 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12371
12372 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
12373 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
12374 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
12375
12376#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12377 ibf_offset_t iseq_start = ibf_dump_pos(dump);
12378
12379 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
12380 struct ibf_dump_buffer buffer;
12381 buffer.str = rb_str_new(0, 0);
12382 buffer.obj_table = ibf_dump_object_table_new();
12383 dump->current_buffer = &buffer;
12384#endif
12385
12386 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
12387 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
12388 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
12389 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
12390 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
12391
12392 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
12393 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
12394 ruby_xfree(positions);
12395
12396 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
12397 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
12398 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
12399 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
12400 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
12401 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
12402 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
12403 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
12404
12405#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12406 ibf_offset_t local_obj_list_offset;
12407 unsigned int local_obj_list_size;
12408
12409 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
12410#endif
12411
12412 ibf_offset_t body_offset = ibf_dump_pos(dump);
12413
12414 /* dump the constant body */
12415 unsigned int param_flags =
12416 (body->param.flags.has_lead << 0) |
12417 (body->param.flags.has_opt << 1) |
12418 (body->param.flags.has_rest << 2) |
12419 (body->param.flags.has_post << 3) |
12420 (body->param.flags.has_kw << 4) |
12421 (body->param.flags.has_kwrest << 5) |
12422 (body->param.flags.has_block << 6) |
12423 (body->param.flags.ambiguous_param0 << 7) |
12424 (body->param.flags.accepts_no_kwarg << 8) |
12425 (body->param.flags.ruby2_keywords << 9);
12426
12427#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12428# define IBF_BODY_OFFSET(x) (x)
12429#else
12430# define IBF_BODY_OFFSET(x) (body_offset - (x))
12431#endif
12432
12433 ibf_dump_write_small_value(dump, body->type);
12434 ibf_dump_write_small_value(dump, body->iseq_size);
12435 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
12436 ibf_dump_write_small_value(dump, bytecode_size);
12437 ibf_dump_write_small_value(dump, param_flags);
12438 ibf_dump_write_small_value(dump, body->param.size);
12439 ibf_dump_write_small_value(dump, body->param.lead_num);
12440 ibf_dump_write_small_value(dump, body->param.opt_num);
12441 ibf_dump_write_small_value(dump, body->param.rest_start);
12442 ibf_dump_write_small_value(dump, body->param.post_start);
12443 ibf_dump_write_small_value(dump, body->param.post_num);
12444 ibf_dump_write_small_value(dump, body->param.block_start);
12445 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
12446 ibf_dump_write_small_value(dump, param_keyword_offset);
12447 ibf_dump_write_small_value(dump, location_pathobj_index);
12448 ibf_dump_write_small_value(dump, location_base_label_index);
12449 ibf_dump_write_small_value(dump, location_label_index);
12450 ibf_dump_write_small_value(dump, body->location.first_lineno);
12451 ibf_dump_write_small_value(dump, body->location.node_id);
12452 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
12453 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
12454 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
12455 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
12456 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
12457 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
12458 ibf_dump_write_small_value(dump, body->insns_info.size);
12459 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
12460 ibf_dump_write_small_value(dump, catch_table_size);
12461 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
12462 ibf_dump_write_small_value(dump, parent_iseq_index);
12463 ibf_dump_write_small_value(dump, local_iseq_index);
12464 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
12465 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
12466 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
12467 ibf_dump_write_small_value(dump, body->variable.flip_count);
12468 ibf_dump_write_small_value(dump, body->local_table_size);
12469 ibf_dump_write_small_value(dump, body->ivc_size);
12470 ibf_dump_write_small_value(dump, body->icvarc_size);
12471 ibf_dump_write_small_value(dump, body->ise_size);
12472 ibf_dump_write_small_value(dump, body->ic_size);
12473 ibf_dump_write_small_value(dump, body->ci_size);
12474 ibf_dump_write_small_value(dump, body->stack_max);
12475 ibf_dump_write_small_value(dump, body->builtin_attrs);
12476
12477#undef IBF_BODY_OFFSET
12478
12479#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12480 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
12481
12482 dump->current_buffer = saved_buffer;
12483 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
12484
12485 ibf_offset_t offset = ibf_dump_pos(dump);
12486 ibf_dump_write_small_value(dump, iseq_start);
12487 ibf_dump_write_small_value(dump, iseq_length_bytes);
12488 ibf_dump_write_small_value(dump, body_offset);
12489
12490 ibf_dump_write_small_value(dump, local_obj_list_offset);
12491 ibf_dump_write_small_value(dump, local_obj_list_size);
12492
12493 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
12494
12495 return offset;
12496#else
12497 return body_offset;
12498#endif
12499}
12500
12501static VALUE
12502ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
12503{
12504 VALUE str = ibf_load_object(load, str_index);
12505 if (str != Qnil) {
12506 str = rb_fstring(str);
12507 }
12508 return str;
12509}
12510
12511static void
12512ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
12513{
12514 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
12515
12516 ibf_offset_t reading_pos = offset;
12517
12518#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12519 struct ibf_load_buffer *saved_buffer = load->current_buffer;
12520 load->current_buffer = &load->global_buffer;
12521
12522 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12523 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12524 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12525
12526 struct ibf_load_buffer buffer;
12527 buffer.buff = load->global_buffer.buff + iseq_start;
12528 buffer.size = iseq_length_bytes;
12529 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12530 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12531 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
12532
12533 load->current_buffer = &buffer;
12534 reading_pos = body_offset;
12535#endif
12536
12537#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12538# define IBF_BODY_OFFSET(x) (x)
12539#else
12540# define IBF_BODY_OFFSET(x) (offset - (x))
12541#endif
12542
12543 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
12544 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12545 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12546 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12547 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
12548 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12549 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
12550 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
12551 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
12552 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
12553 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
12554 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
12555 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12556 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12557 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
12558 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
12559 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
12560 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
12561 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
12562 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12563 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12564 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12565 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12566 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12567 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12568 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12569 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12570 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12571 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12572 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12573 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12574 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12575 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12576 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12577 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
12578 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12579
12580 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12581 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12582 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12583 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12584
12585 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12586 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
12587 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
12588
12589 // setup fname and dummy frame
12590 VALUE path = ibf_load_object(load, location_pathobj_index);
12591 {
12592 VALUE realpath = Qnil;
12593
12594 if (RB_TYPE_P(path, T_STRING)) {
12595 realpath = path = rb_fstring(path);
12596 }
12597 else if (RB_TYPE_P(path, T_ARRAY)) {
12598 VALUE pathobj = path;
12599 if (RARRAY_LEN(pathobj) != 2) {
12600 rb_raise(rb_eRuntimeError, "path object size mismatch");
12601 }
12602 path = rb_fstring(RARRAY_AREF(pathobj, 0));
12603 realpath = RARRAY_AREF(pathobj, 1);
12604 if (!NIL_P(realpath)) {
12605 if (!RB_TYPE_P(realpath, T_STRING)) {
12606 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
12607 "(%x), path=%+"PRIsVALUE,
12608 realpath, TYPE(realpath), path);
12609 }
12610 realpath = rb_fstring(realpath);
12611 }
12612 }
12613 else {
12614 rb_raise(rb_eRuntimeError, "unexpected path object");
12615 }
12616 rb_iseq_pathobj_set(iseq, path, realpath);
12617 }
12618
12619 // push dummy frame
12620 rb_execution_context_t *ec = GET_EC();
12621 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
12622
12623#undef IBF_BODY_OFFSET
12624
12625 load_body->type = type;
12626 load_body->stack_max = stack_max;
12627 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
12628 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
12629 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
12630 load_body->param.flags.has_post = (param_flags >> 3) & 1;
12631 load_body->param.flags.has_kw = FALSE;
12632 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
12633 load_body->param.flags.has_block = (param_flags >> 6) & 1;
12634 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
12635 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
12636 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
12637 load_body->param.size = param_size;
12638 load_body->param.lead_num = param_lead_num;
12639 load_body->param.opt_num = param_opt_num;
12640 load_body->param.rest_start = param_rest_start;
12641 load_body->param.post_start = param_post_start;
12642 load_body->param.post_num = param_post_num;
12643 load_body->param.block_start = param_block_start;
12644 load_body->local_table_size = local_table_size;
12645 load_body->ci_size = ci_size;
12646 load_body->insns_info.size = insns_info_size;
12647
12648 ISEQ_COVERAGE_SET(iseq, Qnil);
12649 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
12650 load_body->variable.flip_count = variable_flip_count;
12651 load_body->variable.script_lines = Qnil;
12652
12653 load_body->location.first_lineno = location_first_lineno;
12654 load_body->location.node_id = location_node_id;
12655 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
12656 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
12657 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
12658 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
12659 load_body->builtin_attrs = builtin_attrs;
12660
12661 load_body->ivc_size = ivc_size;
12662 load_body->icvarc_size = icvarc_size;
12663 load_body->ise_size = ise_size;
12664 load_body->ic_size = ic_size;
12665
12666 if (ISEQ_IS_SIZE(load_body)) {
12667 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
12668 }
12669 else {
12670 load_body->is_entries = NULL;
12671 }
12672 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
12673 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
12674 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
12675 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
12676 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
12677 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
12678 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
12679 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
12680 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
12681 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
12682 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
12683 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
12684
12685 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
12686#if VM_INSN_INFO_TABLE_IMPL == 2
12687 rb_iseq_insns_info_encode_positions(iseq);
12688#endif
12689
12690 rb_iseq_translate_threaded_code(iseq);
12691
12692#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12693 load->current_buffer = &load->global_buffer;
12694#endif
12695
12696 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
12697 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
12698
12699#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12700 load->current_buffer = saved_buffer;
12701#endif
12702 verify_call_cache(iseq);
12703
12704 RB_GC_GUARD(dummy_frame);
12705 rb_vm_pop_frame_no_int(ec);
12706}
12707
12709{
12710 struct ibf_dump *dump;
12711 VALUE offset_list;
12712};
12713
12714static int
12715ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12716{
12717 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
12718 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
12719
12720 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
12721 rb_ary_push(args->offset_list, UINT2NUM(offset));
12722
12723 return ST_CONTINUE;
12724}
12725
12726static void
12727ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
12728{
12729 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
12730
12731 struct ibf_dump_iseq_list_arg args;
12732 args.dump = dump;
12733 args.offset_list = offset_list;
12734
12735 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
12736
12737 st_index_t i;
12738 st_index_t size = dump->iseq_table->num_entries;
12739 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
12740
12741 for (i = 0; i < size; i++) {
12742 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
12743 }
12744
12745 ibf_dump_align(dump, sizeof(ibf_offset_t));
12746 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
12747 header->iseq_list_size = (unsigned int)size;
12748}
12749
12750#define IBF_OBJECT_INTERNAL FL_PROMOTED0
12751
12752/*
12753 * Binary format
12754 * - ibf_object_header
12755 * - ibf_object_xxx (xxx is type)
12756 */
12757
12759 unsigned int type: 5;
12760 unsigned int special_const: 1;
12761 unsigned int frozen: 1;
12762 unsigned int internal: 1;
12763};
12764
12765enum ibf_object_class_index {
12766 IBF_OBJECT_CLASS_OBJECT,
12767 IBF_OBJECT_CLASS_ARRAY,
12768 IBF_OBJECT_CLASS_STANDARD_ERROR,
12769 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
12770 IBF_OBJECT_CLASS_TYPE_ERROR,
12771 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
12772};
12773
12775 long srcstr;
12776 char option;
12777};
12778
12780 long len;
12781 long keyval[FLEX_ARY_LEN];
12782};
12783
12785 long class_index;
12786 long len;
12787 long beg;
12788 long end;
12789 int excl;
12790};
12791
12793 ssize_t slen;
12794 BDIGIT digits[FLEX_ARY_LEN];
12795};
12796
12797enum ibf_object_data_type {
12798 IBF_OBJECT_DATA_ENCODING,
12799};
12800
12802 long a, b;
12803};
12804
12806 long str;
12807};
12808
12809#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
12810 ((((offset) - 1) / (align) + 1) * (align))
12811#define IBF_OBJBODY(type, offset) (const type *)\
12812 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12813
12814static const void *
12815ibf_load_check_offset(const struct ibf_load *load, size_t offset)
12816{
12817 if (offset >= load->current_buffer->size) {
12818 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
12819 }
12820 return load->current_buffer->buff + offset;
12821}
12822
12823NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
12824
12825static void
12826ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
12827{
12828 char buff[0x100];
12829 rb_raw_obj_info(buff, sizeof(buff), obj);
12830 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
12831}
12832
12833NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
12834
12835static VALUE
12836ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12837{
12838 rb_raise(rb_eArgError, "unsupported");
12840}
12841
12842static void
12843ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
12844{
12845 enum ibf_object_class_index cindex;
12846 if (obj == rb_cObject) {
12847 cindex = IBF_OBJECT_CLASS_OBJECT;
12848 }
12849 else if (obj == rb_cArray) {
12850 cindex = IBF_OBJECT_CLASS_ARRAY;
12851 }
12852 else if (obj == rb_eStandardError) {
12853 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12854 }
12855 else if (obj == rb_eNoMatchingPatternError) {
12856 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12857 }
12858 else if (obj == rb_eTypeError) {
12859 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12860 }
12861 else if (obj == rb_eNoMatchingPatternKeyError) {
12862 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12863 }
12864 else {
12865 rb_obj_info_dump(obj);
12866 rb_p(obj);
12867 rb_bug("unsupported class");
12868 }
12869 ibf_dump_write_small_value(dump, (VALUE)cindex);
12870}
12871
12872static VALUE
12873ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12874{
12875 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12876
12877 switch (cindex) {
12878 case IBF_OBJECT_CLASS_OBJECT:
12879 return rb_cObject;
12880 case IBF_OBJECT_CLASS_ARRAY:
12881 return rb_cArray;
12882 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12883 return rb_eStandardError;
12884 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12886 case IBF_OBJECT_CLASS_TYPE_ERROR:
12887 return rb_eTypeError;
12888 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12890 }
12891
12892 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
12893}
12894
12895
12896static void
12897ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
12898{
12899 double dbl = RFLOAT_VALUE(obj);
12900 (void)IBF_W(&dbl, double, 1);
12901}
12902
12903static VALUE
12904ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12905{
12906 const double *dblp = IBF_OBJBODY(double, offset);
12907 return DBL2NUM(*dblp);
12908}
12909
12910static void
12911ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
12912{
12913 long encindex = (long)rb_enc_get_index(obj);
12914 long len = RSTRING_LEN(obj);
12915 const char *ptr = RSTRING_PTR(obj);
12916
12917 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12918 rb_encoding *enc = rb_enc_from_index((int)encindex);
12919 const char *enc_name = rb_enc_name(enc);
12920 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
12921 }
12922
12923 ibf_dump_write_small_value(dump, encindex);
12924 ibf_dump_write_small_value(dump, len);
12925 IBF_WP(ptr, char, len);
12926}
12927
12928static VALUE
12929ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12930{
12931 ibf_offset_t reading_pos = offset;
12932
12933 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12934 const long len = (long)ibf_load_small_value(load, &reading_pos);
12935 const char *ptr = load->current_buffer->buff + reading_pos;
12936
12937 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12938 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12939 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12940 }
12941
12942 VALUE str;
12943 if (header->frozen && !header->internal) {
12944 str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
12945 }
12946 else {
12947 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
12948
12949 if (header->internal) rb_obj_hide(str);
12950 if (header->frozen) str = rb_fstring(str);
12951 }
12952 return str;
12953}
12954
12955static void
12956ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
12957{
12958 VALUE srcstr = RREGEXP_SRC(obj);
12959 struct ibf_object_regexp regexp;
12960 regexp.option = (char)rb_reg_options(obj);
12961 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12962
12963 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
12964 ibf_dump_write_small_value(dump, regexp.srcstr);
12965}
12966
12967static VALUE
12968ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12969{
12970 struct ibf_object_regexp regexp;
12971 regexp.option = ibf_load_byte(load, &offset);
12972 regexp.srcstr = ibf_load_small_value(load, &offset);
12973
12974 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12975 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
12976
12977 if (header->internal) rb_obj_hide(reg);
12978 if (header->frozen) rb_obj_freeze(reg);
12979
12980 return reg;
12981}
12982
12983static void
12984ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
12985{
12986 long i, len = RARRAY_LEN(obj);
12987 ibf_dump_write_small_value(dump, len);
12988 for (i=0; i<len; i++) {
12989 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
12990 ibf_dump_write_small_value(dump, index);
12991 }
12992}
12993
12994static VALUE
12995ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12996{
12997 ibf_offset_t reading_pos = offset;
12998
12999 const long len = (long)ibf_load_small_value(load, &reading_pos);
13000
13001 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
13002 int i;
13003
13004 for (i=0; i<len; i++) {
13005 const VALUE index = ibf_load_small_value(load, &reading_pos);
13006 rb_ary_push(ary, ibf_load_object(load, index));
13007 }
13008
13009 if (header->frozen) rb_obj_freeze(ary);
13010
13011 return ary;
13012}
13013
13014static int
13015ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
13016{
13017 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13018
13019 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
13020 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
13021
13022 ibf_dump_write_small_value(dump, key_index);
13023 ibf_dump_write_small_value(dump, val_index);
13024 return ST_CONTINUE;
13025}
13026
13027static void
13028ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
13029{
13030 long len = RHASH_SIZE(obj);
13031 ibf_dump_write_small_value(dump, (VALUE)len);
13032
13033 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
13034}
13035
13036static VALUE
13037ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13038{
13039 long len = (long)ibf_load_small_value(load, &offset);
13040 VALUE obj = rb_hash_new_with_size(len);
13041 int i;
13042
13043 for (i = 0; i < len; i++) {
13044 VALUE key_index = ibf_load_small_value(load, &offset);
13045 VALUE val_index = ibf_load_small_value(load, &offset);
13046
13047 VALUE key = ibf_load_object(load, key_index);
13048 VALUE val = ibf_load_object(load, val_index);
13049 rb_hash_aset(obj, key, val);
13050 }
13051 rb_hash_rehash(obj);
13052
13053 if (header->internal) rb_obj_hide(obj);
13054 if (header->frozen) rb_obj_freeze(obj);
13055
13056 return obj;
13057}
13058
13059static void
13060ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
13061{
13062 if (rb_obj_is_kind_of(obj, rb_cRange)) {
13063 struct ibf_object_struct_range range;
13064 VALUE beg, end;
13065 IBF_ZERO(range);
13066 range.len = 3;
13067 range.class_index = 0;
13068
13069 rb_range_values(obj, &beg, &end, &range.excl);
13070 range.beg = (long)ibf_dump_object(dump, beg);
13071 range.end = (long)ibf_dump_object(dump, end);
13072
13073 IBF_W_ALIGN(struct ibf_object_struct_range);
13074 IBF_WV(range);
13075 }
13076 else {
13077 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
13078 rb_class_name(CLASS_OF(obj)));
13079 }
13080}
13081
13082static VALUE
13083ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13084{
13085 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
13086 VALUE beg = ibf_load_object(load, range->beg);
13087 VALUE end = ibf_load_object(load, range->end);
13088 VALUE obj = rb_range_new(beg, end, range->excl);
13089 if (header->internal) rb_obj_hide(obj);
13090 if (header->frozen) rb_obj_freeze(obj);
13091 return obj;
13092}
13093
13094static void
13095ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
13096{
13097 ssize_t len = BIGNUM_LEN(obj);
13098 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
13099 BDIGIT *d = BIGNUM_DIGITS(obj);
13100
13101 (void)IBF_W(&slen, ssize_t, 1);
13102 IBF_WP(d, BDIGIT, len);
13103}
13104
13105static VALUE
13106ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13107{
13108 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
13109 int sign = bignum->slen > 0;
13110 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
13111 const int big_unpack_flags = /* c.f. rb_big_unpack() */
13114 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
13115 big_unpack_flags |
13116 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
13117 if (header->internal) rb_obj_hide(obj);
13118 if (header->frozen) rb_obj_freeze(obj);
13119 return obj;
13120}
13121
13122static void
13123ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
13124{
13125 if (rb_data_is_encoding(obj)) {
13126 rb_encoding *enc = rb_to_encoding(obj);
13127 const char *name = rb_enc_name(enc);
13128 long len = strlen(name) + 1;
13129 long data[2];
13130 data[0] = IBF_OBJECT_DATA_ENCODING;
13131 data[1] = len;
13132 (void)IBF_W(data, long, 2);
13133 IBF_WP(name, char, len);
13134 }
13135 else {
13136 ibf_dump_object_unsupported(dump, obj);
13137 }
13138}
13139
13140static VALUE
13141ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13142{
13143 const long *body = IBF_OBJBODY(long, offset);
13144 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
13145 /* const long len = body[1]; */
13146 const char *data = (const char *)&body[2];
13147
13148 switch (type) {
13149 case IBF_OBJECT_DATA_ENCODING:
13150 {
13151 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
13152 return encobj;
13153 }
13154 }
13155
13156 return ibf_load_object_unsupported(load, header, offset);
13157}
13158
13159static void
13160ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
13161{
13162 long data[2];
13163 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
13164 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
13165
13166 (void)IBF_W(data, long, 2);
13167}
13168
13169static VALUE
13170ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13171{
13172 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
13173 VALUE a = ibf_load_object(load, nums->a);
13174 VALUE b = ibf_load_object(load, nums->b);
13175 VALUE obj = header->type == T_COMPLEX ?
13176 rb_complex_new(a, b) : rb_rational_new(a, b);
13177
13178 if (header->internal) rb_obj_hide(obj);
13179 if (header->frozen) rb_obj_freeze(obj);
13180 return obj;
13181}
13182
13183static void
13184ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
13185{
13186 ibf_dump_object_string(dump, rb_sym2str(obj));
13187}
13188
13189static VALUE
13190ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13191{
13192 ibf_offset_t reading_pos = offset;
13193
13194 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13195 const long len = (long)ibf_load_small_value(load, &reading_pos);
13196 const char *ptr = load->current_buffer->buff + reading_pos;
13197
13198 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13199 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13200 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13201 }
13202
13203 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
13204 return ID2SYM(id);
13205}
13206
13207typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
13208static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
13209 ibf_dump_object_unsupported, /* T_NONE */
13210 ibf_dump_object_unsupported, /* T_OBJECT */
13211 ibf_dump_object_class, /* T_CLASS */
13212 ibf_dump_object_unsupported, /* T_MODULE */
13213 ibf_dump_object_float, /* T_FLOAT */
13214 ibf_dump_object_string, /* T_STRING */
13215 ibf_dump_object_regexp, /* T_REGEXP */
13216 ibf_dump_object_array, /* T_ARRAY */
13217 ibf_dump_object_hash, /* T_HASH */
13218 ibf_dump_object_struct, /* T_STRUCT */
13219 ibf_dump_object_bignum, /* T_BIGNUM */
13220 ibf_dump_object_unsupported, /* T_FILE */
13221 ibf_dump_object_data, /* T_DATA */
13222 ibf_dump_object_unsupported, /* T_MATCH */
13223 ibf_dump_object_complex_rational, /* T_COMPLEX */
13224 ibf_dump_object_complex_rational, /* T_RATIONAL */
13225 ibf_dump_object_unsupported, /* 0x10 */
13226 ibf_dump_object_unsupported, /* 0x11 T_NIL */
13227 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
13228 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
13229 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
13230 ibf_dump_object_unsupported, /* T_FIXNUM */
13231 ibf_dump_object_unsupported, /* T_UNDEF */
13232 ibf_dump_object_unsupported, /* 0x17 */
13233 ibf_dump_object_unsupported, /* 0x18 */
13234 ibf_dump_object_unsupported, /* 0x19 */
13235 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
13236 ibf_dump_object_unsupported, /* T_NODE 0x1b */
13237 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
13238 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
13239 ibf_dump_object_unsupported, /* 0x1e */
13240 ibf_dump_object_unsupported, /* 0x1f */
13241};
13242
13243static void
13244ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
13245{
13246 unsigned char byte =
13247 (header.type << 0) |
13248 (header.special_const << 5) |
13249 (header.frozen << 6) |
13250 (header.internal << 7);
13251
13252 IBF_WV(byte);
13253}
13254
13255static struct ibf_object_header
13256ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
13257{
13258 unsigned char byte = ibf_load_byte(load, offset);
13259
13260 struct ibf_object_header header;
13261 header.type = (byte >> 0) & 0x1f;
13262 header.special_const = (byte >> 5) & 0x01;
13263 header.frozen = (byte >> 6) & 0x01;
13264 header.internal = (byte >> 7) & 0x01;
13265
13266 return header;
13267}
13268
13269static ibf_offset_t
13270ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
13271{
13272 struct ibf_object_header obj_header;
13273 ibf_offset_t current_offset;
13274 IBF_ZERO(obj_header);
13275 obj_header.type = TYPE(obj);
13276
13277 IBF_W_ALIGN(ibf_offset_t);
13278 current_offset = ibf_dump_pos(dump);
13279
13280 if (SPECIAL_CONST_P(obj) &&
13281 ! (SYMBOL_P(obj) ||
13282 RB_FLOAT_TYPE_P(obj))) {
13283 obj_header.special_const = TRUE;
13284 obj_header.frozen = TRUE;
13285 obj_header.internal = TRUE;
13286 ibf_dump_object_object_header(dump, obj_header);
13287 ibf_dump_write_small_value(dump, obj);
13288 }
13289 else {
13290 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
13291 obj_header.special_const = FALSE;
13292 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
13293 ibf_dump_object_object_header(dump, obj_header);
13294 (*dump_object_functions[obj_header.type])(dump, obj);
13295 }
13296
13297 return current_offset;
13298}
13299
13300typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
13301static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
13302 ibf_load_object_unsupported, /* T_NONE */
13303 ibf_load_object_unsupported, /* T_OBJECT */
13304 ibf_load_object_class, /* T_CLASS */
13305 ibf_load_object_unsupported, /* T_MODULE */
13306 ibf_load_object_float, /* T_FLOAT */
13307 ibf_load_object_string, /* T_STRING */
13308 ibf_load_object_regexp, /* T_REGEXP */
13309 ibf_load_object_array, /* T_ARRAY */
13310 ibf_load_object_hash, /* T_HASH */
13311 ibf_load_object_struct, /* T_STRUCT */
13312 ibf_load_object_bignum, /* T_BIGNUM */
13313 ibf_load_object_unsupported, /* T_FILE */
13314 ibf_load_object_data, /* T_DATA */
13315 ibf_load_object_unsupported, /* T_MATCH */
13316 ibf_load_object_complex_rational, /* T_COMPLEX */
13317 ibf_load_object_complex_rational, /* T_RATIONAL */
13318 ibf_load_object_unsupported, /* 0x10 */
13319 ibf_load_object_unsupported, /* T_NIL */
13320 ibf_load_object_unsupported, /* T_TRUE */
13321 ibf_load_object_unsupported, /* T_FALSE */
13322 ibf_load_object_symbol,
13323 ibf_load_object_unsupported, /* T_FIXNUM */
13324 ibf_load_object_unsupported, /* T_UNDEF */
13325 ibf_load_object_unsupported, /* 0x17 */
13326 ibf_load_object_unsupported, /* 0x18 */
13327 ibf_load_object_unsupported, /* 0x19 */
13328 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
13329 ibf_load_object_unsupported, /* T_NODE 0x1b */
13330 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
13331 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
13332 ibf_load_object_unsupported, /* 0x1e */
13333 ibf_load_object_unsupported, /* 0x1f */
13334};
13335
13336static VALUE
13337ibf_load_object(const struct ibf_load *load, VALUE object_index)
13338{
13339 if (object_index == 0) {
13340 return Qnil;
13341 }
13342 else {
13343 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
13344 if (!obj) {
13345 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
13346 ibf_offset_t offset = offsets[object_index];
13347 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
13348
13349#if IBF_ISEQ_DEBUG
13350 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
13351 load->current_buffer->obj_list_offset, (void *)offsets, offset);
13352 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
13353 header.type, header.special_const, header.frozen, header.internal);
13354#endif
13355 if (offset >= load->current_buffer->size) {
13356 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
13357 }
13358
13359 if (header.special_const) {
13360 ibf_offset_t reading_pos = offset;
13361
13362 obj = ibf_load_small_value(load, &reading_pos);
13363 }
13364 else {
13365 obj = (*load_object_functions[header.type])(load, &header, offset);
13366 }
13367
13368 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
13369 }
13370#if IBF_ISEQ_DEBUG
13371 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
13372 object_index, obj);
13373#endif
13374 return obj;
13375 }
13376}
13377
13379{
13380 struct ibf_dump *dump;
13381 VALUE offset_list;
13382};
13383
13384static int
13385ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13386{
13387 VALUE obj = (VALUE)key;
13388 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
13389
13390 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
13391 rb_ary_push(args->offset_list, UINT2NUM(offset));
13392
13393 return ST_CONTINUE;
13394}
13395
13396static void
13397ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
13398{
13399 st_table *obj_table = dump->current_buffer->obj_table;
13400 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
13401
13402 struct ibf_dump_object_list_arg args;
13403 args.dump = dump;
13404 args.offset_list = offset_list;
13405
13406 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
13407
13408 IBF_W_ALIGN(ibf_offset_t);
13409 *obj_list_offset = ibf_dump_pos(dump);
13410
13411 st_index_t size = obj_table->num_entries;
13412 st_index_t i;
13413
13414 for (i=0; i<size; i++) {
13415 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
13416 IBF_WV(offset);
13417 }
13418
13419 *obj_list_size = (unsigned int)size;
13420}
13421
13422static void
13423ibf_dump_mark(void *ptr)
13424{
13425 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13426 rb_gc_mark(dump->global_buffer.str);
13427
13428 rb_mark_set(dump->global_buffer.obj_table);
13429 rb_mark_set(dump->iseq_table);
13430}
13431
13432static void
13433ibf_dump_free(void *ptr)
13434{
13435 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13436 if (dump->global_buffer.obj_table) {
13437 st_free_table(dump->global_buffer.obj_table);
13438 dump->global_buffer.obj_table = 0;
13439 }
13440 if (dump->iseq_table) {
13441 st_free_table(dump->iseq_table);
13442 dump->iseq_table = 0;
13443 }
13444}
13445
13446static size_t
13447ibf_dump_memsize(const void *ptr)
13448{
13449 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13450 size_t size = 0;
13451 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
13452 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
13453 return size;
13454}
13455
13456static const rb_data_type_t ibf_dump_type = {
13457 "ibf_dump",
13458 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
13459 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
13460};
13461
13462static void
13463ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
13464{
13465 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
13466 dump->iseq_table = NULL;
13467
13468 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
13469 dump->global_buffer.obj_table = ibf_dump_object_table_new();
13470 dump->iseq_table = st_init_numtable(); /* need free */
13471
13472 dump->current_buffer = &dump->global_buffer;
13473}
13474
13475VALUE
13476rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
13477{
13478 struct ibf_dump *dump;
13479 struct ibf_header header = {{0}};
13480 VALUE dump_obj;
13481 VALUE str;
13482
13483 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
13484 ISEQ_BODY(iseq)->local_iseq != iseq) {
13485 rb_raise(rb_eRuntimeError, "should be top of iseq");
13486 }
13487 if (RTEST(ISEQ_COVERAGE(iseq))) {
13488 rb_raise(rb_eRuntimeError, "should not compile with coverage");
13489 }
13490
13491 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
13492 ibf_dump_setup(dump, dump_obj);
13493
13494 ibf_dump_write(dump, &header, sizeof(header));
13495 ibf_dump_iseq(dump, iseq);
13496
13497 header.magic[0] = 'Y'; /* YARB */
13498 header.magic[1] = 'A';
13499 header.magic[2] = 'R';
13500 header.magic[3] = 'B';
13501 header.major_version = IBF_MAJOR_VERSION;
13502 header.minor_version = IBF_MINOR_VERSION;
13503 header.endian = IBF_ENDIAN_MARK;
13504 header.wordsize = (uint8_t)SIZEOF_VALUE;
13505 ibf_dump_iseq_list(dump, &header);
13506 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
13507 header.size = ibf_dump_pos(dump);
13508
13509 if (RTEST(opt)) {
13510 VALUE opt_str = opt;
13511 const char *ptr = StringValuePtr(opt_str);
13512 header.extra_size = RSTRING_LENINT(opt_str);
13513 ibf_dump_write(dump, ptr, header.extra_size);
13514 }
13515 else {
13516 header.extra_size = 0;
13517 }
13518
13519 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
13520
13521 str = dump->global_buffer.str;
13522 RB_GC_GUARD(dump_obj);
13523 return str;
13524}
13525
13526static const ibf_offset_t *
13527ibf_iseq_list(const struct ibf_load *load)
13528{
13529 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
13530}
13531
13532void
13533rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
13534{
13535 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
13536 rb_iseq_t *prev_src_iseq = load->iseq;
13537 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
13538 load->iseq = iseq;
13539#if IBF_ISEQ_DEBUG
13540 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
13541 iseq->aux.loader.index, offset,
13542 load->header->size);
13543#endif
13544 ibf_load_iseq_each(load, iseq, offset);
13545 ISEQ_COMPILE_DATA_CLEAR(iseq);
13546 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13547 rb_iseq_init_trace(iseq);
13548 load->iseq = prev_src_iseq;
13549}
13550
13551#if USE_LAZY_LOAD
13552const rb_iseq_t *
13553rb_iseq_complete(const rb_iseq_t *iseq)
13554{
13555 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
13556 return iseq;
13557}
13558#endif
13559
13560static rb_iseq_t *
13561ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
13562{
13563 int iseq_index = (int)(VALUE)index_iseq;
13564
13565#if IBF_ISEQ_DEBUG
13566 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
13567 (void *)index_iseq, (void *)load->iseq_list);
13568#endif
13569 if (iseq_index == -1) {
13570 return NULL;
13571 }
13572 else {
13573 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
13574
13575#if IBF_ISEQ_DEBUG
13576 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
13577#endif
13578 if (iseqv) {
13579 return (rb_iseq_t *)iseqv;
13580 }
13581 else {
13582 rb_iseq_t *iseq = iseq_imemo_alloc();
13583#if IBF_ISEQ_DEBUG
13584 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
13585#endif
13586 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13587 iseq->aux.loader.obj = load->loader_obj;
13588 iseq->aux.loader.index = iseq_index;
13589#if IBF_ISEQ_DEBUG
13590 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
13591 (void *)iseq, (void *)load->loader_obj, iseq_index);
13592#endif
13593 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
13594
13595 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
13596#if IBF_ISEQ_DEBUG
13597 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
13598#endif
13599 rb_ibf_load_iseq_complete(iseq);
13600 }
13601
13602#if IBF_ISEQ_DEBUG
13603 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
13604 (void *)iseq, (void *)load->iseq);
13605#endif
13606 return iseq;
13607 }
13608 }
13609}
13610
13611static void
13612ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
13613{
13614 struct ibf_header *header = (struct ibf_header *)bytes;
13615 load->loader_obj = loader_obj;
13616 load->global_buffer.buff = bytes;
13617 load->header = header;
13618 load->global_buffer.size = header->size;
13619 load->global_buffer.obj_list_offset = header->global_object_list_offset;
13620 load->global_buffer.obj_list_size = header->global_object_list_size;
13621 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
13622 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
13623 load->iseq = NULL;
13624
13625 load->current_buffer = &load->global_buffer;
13626
13627 if (size < header->size) {
13628 rb_raise(rb_eRuntimeError, "broken binary format");
13629 }
13630 if (strncmp(header->magic, "YARB", 4) != 0) {
13631 rb_raise(rb_eRuntimeError, "unknown binary format");
13632 }
13633 if (header->major_version != IBF_MAJOR_VERSION ||
13634 header->minor_version != IBF_MINOR_VERSION) {
13635 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
13636 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
13637 }
13638 if (header->endian != IBF_ENDIAN_MARK) {
13639 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
13640 }
13641 if (header->wordsize != SIZEOF_VALUE) {
13642 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
13643 }
13644 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13645 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
13646 header->iseq_list_offset);
13647 }
13648 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13649 rb_raise(rb_eArgError, "unaligned object list offset: %u",
13650 load->global_buffer.obj_list_offset);
13651 }
13652}
13653
13654static void
13655ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
13656{
13657 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
13658 rb_raise(rb_eRuntimeError, "broken binary format");
13659 }
13660
13661 if (USE_LAZY_LOAD) {
13662 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
13663 }
13664
13665 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
13666 RB_OBJ_WRITE(loader_obj, &load->str, str);
13667}
13668
13669static void
13670ibf_loader_mark(void *ptr)
13671{
13672 struct ibf_load *load = (struct ibf_load *)ptr;
13673 rb_gc_mark(load->str);
13674 rb_gc_mark(load->iseq_list);
13675 rb_gc_mark(load->global_buffer.obj_list);
13676}
13677
13678static void
13679ibf_loader_free(void *ptr)
13680{
13681 struct ibf_load *load = (struct ibf_load *)ptr;
13682 ruby_xfree(load);
13683}
13684
13685static size_t
13686ibf_loader_memsize(const void *ptr)
13687{
13688 return sizeof(struct ibf_load);
13689}
13690
13691static const rb_data_type_t ibf_load_type = {
13692 "ibf_loader",
13693 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
13694 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13695};
13696
13697const rb_iseq_t *
13698rb_iseq_ibf_load(VALUE str)
13699{
13700 struct ibf_load *load;
13701 rb_iseq_t *iseq;
13702 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13703
13704 ibf_load_setup(load, loader_obj, str);
13705 iseq = ibf_load_iseq(load, 0);
13706
13707 RB_GC_GUARD(loader_obj);
13708 return iseq;
13709}
13710
13711const rb_iseq_t *
13712rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
13713{
13714 struct ibf_load *load;
13715 rb_iseq_t *iseq;
13716 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13717
13718 ibf_load_setup_bytes(load, loader_obj, bytes, size);
13719 iseq = ibf_load_iseq(load, 0);
13720
13721 RB_GC_GUARD(loader_obj);
13722 return iseq;
13723}
13724
13725VALUE
13726rb_iseq_ibf_load_extra_data(VALUE str)
13727{
13728 struct ibf_load *load;
13729 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13730 VALUE extra_str;
13731
13732 ibf_load_setup(load, loader_obj, str);
13733 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
13734 RB_GC_GUARD(loader_obj);
13735 return extra_str;
13736}
13737
13738#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:12093
#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:11725
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:3634
#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:3623
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:3690
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:3505
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3004
#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