Ruby: compile.c Source File

Ruby 3.3.6p108 (2024-11-05 revision 75015d4c1f6965b5e85e96fb309f1f2129f933c0)

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