Ruby 3.3.0p0 (2023-12-25 revision 5124f9ac7513eb590c37717337c430cb93caa151)
compile.c
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/numeric.h"
30#include "internal/object.h"
31#include "internal/rational.h"
32#include "internal/re.h"
33#include "internal/symbol.h"
34#include "internal/thread.h"
35#include "internal/variable.h"
36#include "iseq.h"
37#include "ruby/re.h"
38#include "ruby/util.h"
39#include "vm_core.h"
40#include "vm_callinfo.h"
41#include "vm_debug.h"
42#include "yjit.h"
43
44#include "builtin.h"
45#include "insns.inc"
46#include "insns_info.inc"
47
48#undef RUBY_UNTYPED_DATA_WARNING
49#define RUBY_UNTYPED_DATA_WARNING 0
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
53
54typedef struct iseq_link_element {
55 enum {
56 ISEQ_ELEMENT_ANCHOR,
57 ISEQ_ELEMENT_LABEL,
58 ISEQ_ELEMENT_INSN,
59 ISEQ_ELEMENT_ADJUST,
60 ISEQ_ELEMENT_TRACE,
61 } type;
62 struct iseq_link_element *next;
63 struct iseq_link_element *prev;
65
66typedef struct iseq_link_anchor {
67 LINK_ELEMENT anchor;
68 LINK_ELEMENT *last;
70
71typedef enum {
72 LABEL_RESCUE_NONE,
73 LABEL_RESCUE_BEG,
74 LABEL_RESCUE_END,
75 LABEL_RESCUE_TYPE_MAX
76} LABEL_RESCUE_TYPE;
77
78typedef struct iseq_label_data {
79 LINK_ELEMENT link;
80 int label_no;
81 int position;
82 int sc_state;
83 int sp;
84 int refcnt;
85 unsigned int set: 1;
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
88} LABEL;
89
90typedef struct iseq_insn_data {
91 LINK_ELEMENT link;
92 enum ruby_vminsn_type insn_id;
93 int operand_size;
94 int sc_state;
95 VALUE *operands;
96 struct {
97 int line_no;
98 int node_id;
99 rb_event_flag_t events;
100 } insn_info;
101} INSN;
102
103typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
122 const void *ensure_node;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
142#ifndef CPDEBUG
143#define CPDEBUG 0
144#endif
145
146#if CPDEBUG >= 0
147#define compile_debug CPDEBUG
148#else
149#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
150#endif
151
152#if CPDEBUG
153
154#define compile_debug_print_indent(level) \
155 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156
157#define debugp(header, value) (void) \
158 (compile_debug_print_indent(1) && \
159 ruby_debug_print_value(1, compile_debug, (header), (value)))
160
161#define debugi(header, id) (void) \
162 (compile_debug_print_indent(1) && \
163 ruby_debug_print_id(1, compile_debug, (header), (id)))
164
165#define debugp_param(header, value) (void) \
166 (compile_debug_print_indent(1) && \
167 ruby_debug_print_value(1, compile_debug, (header), (value)))
168
169#define debugp_verbose(header, value) (void) \
170 (compile_debug_print_indent(2) && \
171 ruby_debug_print_value(2, compile_debug, (header), (value)))
172
173#define debugp_verbose_node(header, value) (void) \
174 (compile_debug_print_indent(10) && \
175 ruby_debug_print_value(10, compile_debug, (header), (value)))
176
177#define debug_node_start(node) ((void) \
178 (compile_debug_print_indent(1) && \
179 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
180 gl_node_level++)
181
182#define debug_node_end() gl_node_level --
183
184#else
185
186#define debugi(header, id) ((void)0)
187#define debugp(header, value) ((void)0)
188#define debugp_verbose(header, value) ((void)0)
189#define debugp_verbose_node(header, value) ((void)0)
190#define debugp_param(header, value) ((void)0)
191#define debug_node_start(node) ((void)0)
192#define debug_node_end() ((void)0)
193#endif
194
195#if CPDEBUG > 1 || CPDEBUG < 0
196#undef printf
197#define printf ruby_debug_printf
198#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#else
201#define debugs if(0)printf
202#define debug_compile(msg, v) (v)
203#endif
204
205#define LVAR_ERRINFO (1)
206
207/* create new label */
208#define NEW_LABEL(l) new_label_body(iseq, (l))
209#define LABEL_FORMAT "<L%03d>"
210
211#define NEW_ISEQ(node, name, type, line_no) \
212 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213
214#define NEW_CHILD_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216
217/* add instructions */
218#define ADD_SEQ(seq1, seq2) \
219 APPEND_LIST((seq1), (seq2))
220
221/* add an instruction */
222#define ADD_INSN(seq, line_node, insn) \
223 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
224
225/* insert an instruction before next */
226#define INSERT_BEFORE_INSN(next, line_node, insn) \
227 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
228
229/* insert an instruction after prev */
230#define INSERT_AFTER_INSN(prev, line_node, insn) \
231 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
232
233/* add an instruction with some operands (1, 2, 3, 5) */
234#define ADD_INSN1(seq, line_node, insn, op1) \
235 ADD_ELEM((seq), (LINK_ELEMENT *) \
236 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
237
238/* insert an instruction with some operands (1, 2, 3, 5) before next */
239#define INSERT_BEFORE_INSN1(next, line_node, insn, op1) \
240 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
241 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
242
243/* insert an instruction with some operands (1, 2, 3, 5) after prev */
244#define INSERT_AFTER_INSN1(prev, line_node, insn, op1) \
245 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
246 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
247
248#define LABEL_REF(label) ((label)->refcnt++)
249
250/* add an instruction with label operand (alias of ADD_INSN1) */
251#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
252
253#define ADD_INSN2(seq, line_node, insn, op1, op2) \
254 ADD_ELEM((seq), (LINK_ELEMENT *) \
255 new_insn_body(iseq, (line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
256
257#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
258 ADD_ELEM((seq), (LINK_ELEMENT *) \
259 new_insn_body(iseq, (line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
260
261/* Specific Insn factory */
262#define ADD_SEND(seq, line_node, id, argc) \
263 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
264
265#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
266 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
267
268#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
270
271#define ADD_CALL_RECEIVER(seq, line_node) \
272 ADD_INSN((seq), (line_node), putself)
273
274#define ADD_CALL(seq, line_node, id, argc) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
276
277#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
278 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
279
280#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
281 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
282
283#define ADD_TRACE(seq, event) \
284 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
285#define ADD_TRACE_WITH_DATA(seq, event, data) \
286 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
287
288static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
289static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
290
291#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
292#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
293
294/* add label */
295#define ADD_LABEL(seq, label) \
296 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
297
298#define APPEND_LABEL(seq, before, label) \
299 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
300
301#define ADD_ADJUST(seq, line_node, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
303
304#define ADD_ADJUST_RESTORE(seq, label) \
305 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
306
307#define LABEL_UNREMOVABLE(label) \
308 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
309#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
310 VALUE _e = rb_ary_new3(5, (type), \
311 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
312 (VALUE)(iseqv), (VALUE)(lc) | 1); \
313 LABEL_UNREMOVABLE(ls); \
314 LABEL_REF(le); \
315 LABEL_REF(lc); \
316 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
317 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
318 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
319} while (0)
320
321/* compile node */
322#define COMPILE(anchor, desc, node) \
323 (debug_compile("== " desc "\n", \
324 iseq_compile_each(iseq, (anchor), (node), 0)))
325
326/* compile node, this node's value will be popped */
327#define COMPILE_POPPED(anchor, desc, node) \
328 (debug_compile("== " desc "\n", \
329 iseq_compile_each(iseq, (anchor), (node), 1)))
330
331/* compile node, which is popped when 'popped' is true */
332#define COMPILE_(anchor, desc, node, popped) \
333 (debug_compile("== " desc "\n", \
334 iseq_compile_each(iseq, (anchor), (node), (popped))))
335
336#define COMPILE_RECV(anchor, desc, node, recv) \
337 (private_recv_p(node) ? \
338 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
339 COMPILE(anchor, desc, recv) ? 0 : -1)
340
341#define OPERAND_AT(insn, idx) \
342 (((INSN*)(insn))->operands[(idx)])
343
344#define INSN_OF(insn) \
345 (((INSN*)(insn))->insn_id)
346
347#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
348#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
349#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
350#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
351#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
352#define IS_NEXT_INSN_ID(link, insn) \
353 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
354
355/* error */
356#if CPDEBUG > 0
358#endif
359RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
360static void
361append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
362{
363 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
364 VALUE file = rb_iseq_path(iseq);
365 VALUE err = err_info == Qtrue ? Qfalse : err_info;
366 va_list args;
367
368 va_start(args, fmt);
369 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
370 va_end(args);
371 if (NIL_P(err_info)) {
372 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
373 rb_set_errinfo(err);
374 }
375 else if (!err_info) {
376 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
377 }
378 if (compile_debug) {
379 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
380 rb_exc_fatal(err);
381 }
382}
383
384#if 0
385static void
386compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
387{
388 va_list args;
389 va_start(args, fmt);
390 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
391 va_end(args);
392 abort();
393}
394#endif
395
396#define COMPILE_ERROR append_compile_error
397
398#define ERROR_ARGS_AT(n) iseq, nd_line(n),
399#define ERROR_ARGS ERROR_ARGS_AT(node)
400
401#define EXPECT_NODE(prefix, node, ndtype, errval) \
402do { \
403 const NODE *error_node = (node); \
404 enum node_type error_type = nd_type(error_node); \
405 if (error_type != (ndtype)) { \
406 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
407 prefix ": " #ndtype " is expected, but %s", \
408 ruby_node_name(error_type)); \
409 return errval; \
410 } \
411} while (0)
412
413#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
414do { \
415 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
416 prefix ": must be " #ndtype ", but 0"); \
417 return errval; \
418} while (0)
419
420#define UNKNOWN_NODE(prefix, node, errval) \
421do { \
422 const NODE *error_node = (node); \
423 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
424 ruby_node_name(nd_type(error_node))); \
425 return errval; \
426} while (0)
427
428#define COMPILE_OK 1
429#define COMPILE_NG 0
430
431#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
432#define NO_CHECK(sub) (void)(sub)
433#define BEFORE_RETURN
434
435/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
436 * missing */
437#define DECL_ANCHOR(name) \
438 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
439#define INIT_ANCHOR(name) \
440 (name->last = &name->anchor)
441
442static inline VALUE
443freeze_hide_obj(VALUE obj)
444{
445 OBJ_FREEZE(obj);
446 RBASIC_CLEAR_CLASS(obj);
447 return obj;
448}
449
450#include "optinsn.inc"
451#if OPT_INSTRUCTIONS_UNIFICATION
452#include "optunifs.inc"
453#endif
454
455/* for debug */
456#if CPDEBUG < 0
457#define ISEQ_ARG iseq,
458#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
459#else
460#define ISEQ_ARG
461#define ISEQ_ARG_DECLARE
462#endif
463
464#if CPDEBUG
465#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
466#endif
467
468static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
469static void dump_disasm_list(const LINK_ELEMENT *elem);
470
471static int insn_data_length(INSN *iobj);
472static int calc_sp_depth(int depth, INSN *iobj);
473
474static INSN *new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...);
475static LABEL *new_label_body(rb_iseq_t *iseq, long line);
476static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
477static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
478
479
480static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
481static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
482static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
483static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
484static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
485
486static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl);
487static int iseq_set_exception_local_table(rb_iseq_t *iseq);
488static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
489
490static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
491static int iseq_set_exception_table(rb_iseq_t *iseq);
492static int iseq_set_optargs_table(rb_iseq_t *iseq);
493
494static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
495static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
496
497/*
498 * To make Array to LinkedList, use link_anchor
499 */
500
501static void
502verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
503{
504#if CPDEBUG
505 int flag = 0;
506 LINK_ELEMENT *list, *plist;
507
508 if (!compile_debug) return;
509
510 list = anchor->anchor.next;
511 plist = &anchor->anchor;
512 while (list) {
513 if (plist != list->prev) {
514 flag += 1;
515 }
516 plist = list;
517 list = list->next;
518 }
519
520 if (anchor->last != plist && anchor->last != 0) {
521 flag |= 0x70000;
522 }
523
524 if (flag != 0) {
525 rb_bug("list verify error: %08x (%s)", flag, info);
526 }
527#endif
528}
529#if CPDEBUG < 0
530#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
531#endif
532
533static void
534verify_call_cache(rb_iseq_t *iseq)
535{
536#if CPDEBUG
537 VALUE *original = rb_iseq_original_iseq(iseq);
538 size_t i = 0;
539 while (i < ISEQ_BODY(iseq)->iseq_size) {
540 VALUE insn = original[i];
541 const char *types = insn_op_types(insn);
542
543 for (int j=0; types[j]; j++) {
544 if (types[j] == TS_CALLDATA) {
545 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
546 const struct rb_callinfo *ci = cd->ci;
547 const struct rb_callcache *cc = cd->cc;
548 if (cc != vm_cc_empty()) {
549 vm_ci_dump(ci);
550 rb_bug("call cache is not initialized by vm_cc_empty()");
551 }
552 }
553 }
554 i += insn_len(insn);
555 }
556
557 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
558 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
559 const struct rb_callinfo *ci = cd->ci;
560 const struct rb_callcache *cc = cd->cc;
561 if (cc != NULL && cc != vm_cc_empty()) {
562 vm_ci_dump(ci);
563 rb_bug("call cache is not initialized by vm_cc_empty()");
564 }
565 }
566#endif
567}
568
569/*
570 * elem1, elem2 => elem1, elem2, elem
571 */
572static void
573ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
574{
575 elem->prev = anchor->last;
576 anchor->last->next = elem;
577 anchor->last = elem;
578 verify_list("add", anchor);
579}
580
581/*
582 * elem1, before, elem2 => elem1, before, elem, elem2
583 */
584static void
585APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
586{
587 elem->prev = before;
588 elem->next = before->next;
589 elem->next->prev = elem;
590 before->next = elem;
591 if (before == anchor->last) anchor->last = elem;
592 verify_list("add", anchor);
593}
594#if CPDEBUG < 0
595#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
596#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
597#endif
598
599static int
600branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
601{
602 if (!ISEQ_COVERAGE(iseq)) return 0;
603 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
604 if (first_line <= 0) return 0;
605 return 1;
606}
607
608static VALUE
609decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
610{
611 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
612 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
613
614 if (!branch_coverage_valid_p(iseq, first_lineno)) return Qundef;
615
616 /*
617 * if !structure[node]
618 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
619 * else
620 * branches = structure[node][5]
621 * end
622 */
623
624 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
625 VALUE key = (VALUE)node | 1; // FIXNUM for hash key
626 VALUE branch_base = rb_hash_aref(structure, key);
627 VALUE branches;
628
629 if (NIL_P(branch_base)) {
630 branch_base = rb_ary_hidden_new(6);
631 rb_hash_aset(structure, key, branch_base);
632 rb_ary_push(branch_base, ID2SYM(rb_intern(type)));
633 rb_ary_push(branch_base, INT2FIX(first_lineno));
634 rb_ary_push(branch_base, INT2FIX(first_column));
635 rb_ary_push(branch_base, INT2FIX(last_lineno));
636 rb_ary_push(branch_base, INT2FIX(last_column));
637 branches = rb_hash_new();
638 rb_obj_hide(branches);
639 rb_ary_push(branch_base, branches);
640 }
641 else {
642 branches = RARRAY_AREF(branch_base, 5);
643 }
644
645 return branches;
646}
647
648static NODE
649generate_dummy_line_node(int lineno, int node_id)
650{
651 NODE dummy = { 0 };
652 nd_set_line(&dummy, lineno);
653 nd_set_node_id(&dummy, node_id);
654 return dummy;
655}
656
657static void
658add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *node, int branch_id, const char *type, VALUE branches)
659{
660 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
661 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
662
663 if (!branch_coverage_valid_p(iseq, first_lineno)) return;
664
665 /*
666 * if !branches[branch_id]
667 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
668 * else
669 * counter_idx= branches[branch_id][5]
670 * end
671 */
672
673 VALUE key = INT2FIX(branch_id);
674 VALUE branch = rb_hash_aref(branches, key);
675 long counter_idx;
676
677 if (NIL_P(branch)) {
678 branch = rb_ary_hidden_new(6);
679 rb_hash_aset(branches, key, branch);
680 rb_ary_push(branch, ID2SYM(rb_intern(type)));
681 rb_ary_push(branch, INT2FIX(first_lineno));
682 rb_ary_push(branch, INT2FIX(first_column));
683 rb_ary_push(branch, INT2FIX(last_lineno));
684 rb_ary_push(branch, INT2FIX(last_column));
685 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
686 counter_idx = RARRAY_LEN(counters);
687 rb_ary_push(branch, LONG2FIX(counter_idx));
688 rb_ary_push(counters, INT2FIX(0));
689 }
690 else {
691 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
692 }
693
694 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
695
696 NODE dummy_line_node = generate_dummy_line_node(last_lineno, nd_node_id(node));
697 ADD_INSN(seq, &dummy_line_node, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724static NODE *
725get_nd_recv(const NODE *node)
726{
727 switch (nd_type(node)) {
728 case NODE_CALL:
729 return RNODE_CALL(node)->nd_recv;
730 case NODE_OPCALL:
731 return RNODE_OPCALL(node)->nd_recv;
732 case NODE_FCALL:
733 return 0;
734 case NODE_QCALL:
735 return RNODE_QCALL(node)->nd_recv;
736 case NODE_VCALL:
737 return 0;
738 case NODE_ATTRASGN:
739 return RNODE_ATTRASGN(node)->nd_recv;
740 case NODE_OP_ASGN1:
741 return RNODE_OP_ASGN1(node)->nd_recv;
742 case NODE_OP_ASGN2:
743 return RNODE_OP_ASGN2(node)->nd_recv;
744 default:
745 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
746 }
747}
748
749static ID
750get_node_call_nd_mid(const NODE *node)
751{
752 switch (nd_type(node)) {
753 case NODE_CALL:
754 return RNODE_CALL(node)->nd_mid;
755 case NODE_OPCALL:
756 return RNODE_OPCALL(node)->nd_mid;
757 case NODE_FCALL:
758 return RNODE_FCALL(node)->nd_mid;
759 case NODE_QCALL:
760 return RNODE_QCALL(node)->nd_mid;
761 case NODE_VCALL:
762 return RNODE_VCALL(node)->nd_mid;
763 case NODE_ATTRASGN:
764 return RNODE_ATTRASGN(node)->nd_mid;
765 default:
766 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
767 }
768}
769
770static NODE *
771get_nd_args(const NODE *node)
772{
773 switch (nd_type(node)) {
774 case NODE_CALL:
775 return RNODE_CALL(node)->nd_args;
776 case NODE_OPCALL:
777 return RNODE_OPCALL(node)->nd_args;
778 case NODE_FCALL:
779 return RNODE_FCALL(node)->nd_args;
780 case NODE_QCALL:
781 return RNODE_QCALL(node)->nd_args;
782 case NODE_VCALL:
783 return 0;
784 case NODE_ATTRASGN:
785 return RNODE_ATTRASGN(node)->nd_args;
786 default:
787 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
788 }
789}
790
791static ID
792get_node_colon_nd_mid(const NODE *node)
793{
794 switch (nd_type(node)) {
795 case NODE_COLON2:
796 return RNODE_COLON2(node)->nd_mid;
797 case NODE_COLON3:
798 return RNODE_COLON3(node)->nd_mid;
799 default:
800 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
801 }
802}
803
804static ID
805get_nd_vid(const NODE *node)
806{
807 switch (nd_type(node)) {
808 case NODE_LASGN:
809 return RNODE_LASGN(node)->nd_vid;
810 case NODE_DASGN:
811 return RNODE_DASGN(node)->nd_vid;
812 case NODE_IASGN:
813 return RNODE_IASGN(node)->nd_vid;
814 case NODE_CVASGN:
815 return RNODE_CVASGN(node)->nd_vid;
816 default:
817 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
818 }
819}
820
821
822static NODE *
823get_nd_value(const NODE *node)
824{
825 switch (nd_type(node)) {
826 case NODE_LASGN:
827 return RNODE_LASGN(node)->nd_value;
828 case NODE_DASGN:
829 return RNODE_DASGN(node)->nd_value;
830 default:
831 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
832 }
833}
834
835VALUE
836rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
837{
838 DECL_ANCHOR(ret);
839 INIT_ANCHOR(ret);
840
841 (*ifunc->func)(iseq, ret, ifunc->data);
842
843 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
844 ADD_INSN(ret, &dummy_line_node, leave);
845
846 CHECK(iseq_setup_insn(iseq, ret));
847 return iseq_setup(iseq, ret);
848}
849
850VALUE
851rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
852{
853 DECL_ANCHOR(ret);
854 INIT_ANCHOR(ret);
855
856 if (IMEMO_TYPE_P(node, imemo_ifunc)) {
857 rb_raise(rb_eArgError, "unexpected imemo_ifunc");
858 }
859
860 if (node == 0) {
861 NO_CHECK(COMPILE(ret, "nil", node));
862 iseq_set_local_table(iseq, 0);
863 }
864 /* assume node is T_NODE */
865 else if (nd_type_p(node, NODE_SCOPE)) {
866 /* iseq type of top, method, class, block */
867 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl);
868 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
869
870 switch (ISEQ_BODY(iseq)->type) {
871 case ISEQ_TYPE_BLOCK:
872 {
873 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
874 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
875
876 start->rescued = LABEL_RESCUE_BEG;
877 end->rescued = LABEL_RESCUE_END;
878
879 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
880 NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
881 ADD_INSN (ret, &dummy_line_node, nop);
882 ADD_LABEL(ret, start);
883 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
884 ADD_LABEL(ret, end);
885 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
886 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
887
888 /* wide range catch handler must put at last */
889 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
890 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
891 break;
892 }
893 case ISEQ_TYPE_CLASS:
894 {
895 ADD_TRACE(ret, RUBY_EVENT_CLASS);
896 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
897 ADD_TRACE(ret, RUBY_EVENT_END);
898 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
899 break;
900 }
901 case ISEQ_TYPE_METHOD:
902 {
903 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
904 ADD_TRACE(ret, RUBY_EVENT_CALL);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
907 ADD_TRACE(ret, RUBY_EVENT_RETURN);
908 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
909 break;
910 }
911 default: {
912 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
913 break;
914 }
915 }
916 }
917 else {
918 const char *m;
919#define INVALID_ISEQ_TYPE(type) \
920 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
921 switch (ISEQ_BODY(iseq)->type) {
922 case INVALID_ISEQ_TYPE(METHOD);
923 case INVALID_ISEQ_TYPE(CLASS);
924 case INVALID_ISEQ_TYPE(BLOCK);
925 case INVALID_ISEQ_TYPE(EVAL);
926 case INVALID_ISEQ_TYPE(MAIN);
927 case INVALID_ISEQ_TYPE(TOP);
928#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
929 case ISEQ_TYPE_RESCUE:
930 iseq_set_exception_local_table(iseq);
931 CHECK(COMPILE(ret, "rescue", node));
932 break;
933 case ISEQ_TYPE_ENSURE:
934 iseq_set_exception_local_table(iseq);
935 CHECK(COMPILE_POPPED(ret, "ensure", node));
936 break;
937 case ISEQ_TYPE_PLAIN:
938 CHECK(COMPILE(ret, "ensure", node));
939 break;
940 default:
941 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
942 return COMPILE_NG;
943 invalid_iseq_type:
944 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
945 return COMPILE_NG;
946 }
947 }
948
949 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
950 NODE dummy_line_node = generate_dummy_line_node(0, -1);
951 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
952 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
953 }
954 else {
955 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
956 ADD_INSN(ret, &dummy_line_node, leave);
957 }
958
959#if OPT_SUPPORT_JOKE
960 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
961 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
962 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
963 validate_labels(iseq, labels_table);
964 }
965#endif
966 CHECK(iseq_setup_insn(iseq, ret));
967 return iseq_setup(iseq, ret);
968}
969
970static VALUE rb_translate_prism(pm_parser_t *parser, rb_iseq_t *iseq, pm_scope_node_t *scope_node, LINK_ANCHOR *const ret);
971
972VALUE
973rb_iseq_compile_prism_node(rb_iseq_t * iseq, pm_scope_node_t *scope_node, pm_parser_t *parser)
974{
975 DECL_ANCHOR(ret);
976 INIT_ANCHOR(ret);
977
978 CHECK(rb_translate_prism(parser, iseq, scope_node, ret));
979
980 CHECK(iseq_setup_insn(iseq, ret));
981 return iseq_setup(iseq, ret);
982}
983
984static int
985rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
986{
987#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
988 const void * const *table = rb_vm_get_insns_address_table();
989 unsigned int i;
990 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
991
992 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
993 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
994 int len = insn_len(insn);
995 encoded[i] = (VALUE)table[insn];
996 i += len;
997 }
998 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
999#endif
1000
1001#if USE_YJIT
1002 rb_yjit_live_iseq_count++;
1003#endif
1004
1005 return COMPILE_OK;
1006}
1007
1008VALUE *
1009rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1010{
1011 VALUE *original_code;
1012
1013 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1014 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1015 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1016
1017#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1018 {
1019 unsigned int i;
1020
1021 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1022 const void *addr = (const void *)original_code[i];
1023 const int insn = rb_vm_insn_addr2insn(addr);
1024
1025 original_code[i] = insn;
1026 i += insn_len(insn);
1027 }
1028 }
1029#endif
1030 return original_code;
1031}
1032
1033/*********************************************/
1034/* definition of data structure for compiler */
1035/*********************************************/
1036
1037/*
1038 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1039 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1040 * generate SPARCV8PLUS code with unaligned memory access instructions.
1041 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1042 */
1043#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1044 #define STRICT_ALIGNMENT
1045#endif
1046
1047/*
1048 * Some OpenBSD platforms (including sparc64) require strict alignment.
1049 */
1050#if defined(__OpenBSD__)
1051 #include <sys/endian.h>
1052 #ifdef __STRICT_ALIGNMENT
1053 #define STRICT_ALIGNMENT
1054 #endif
1055#endif
1056
1057#ifdef STRICT_ALIGNMENT
1058 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1059 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1060 #else
1061 #define ALIGNMENT_SIZE SIZEOF_VALUE
1062 #endif
1063 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1064 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1065 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1066#else
1067 #define PADDING_SIZE_MAX 0
1068#endif /* STRICT_ALIGNMENT */
1069
1070#ifdef STRICT_ALIGNMENT
1071/* calculate padding size for aligned memory access */
1072static size_t
1073calc_padding(void *ptr, size_t size)
1074{
1075 size_t mis;
1076 size_t padding = 0;
1077
1078 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1079 if (mis > 0) {
1080 padding = ALIGNMENT_SIZE - mis;
1081 }
1082/*
1083 * On 32-bit sparc or equivalents, when a single VALUE is requested
1084 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1085 */
1086#if ALIGNMENT_SIZE > SIZEOF_VALUE
1087 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1088 padding = 0;
1089 }
1090#endif
1091
1092 return padding;
1093}
1094#endif /* STRICT_ALIGNMENT */
1095
1096static void *
1097compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1098{
1099 void *ptr = 0;
1100 struct iseq_compile_data_storage *storage = *arena;
1101#ifdef STRICT_ALIGNMENT
1102 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1103#else
1104 const size_t padding = 0; /* expected to be optimized by compiler */
1105#endif /* STRICT_ALIGNMENT */
1106
1107 if (size >= INT_MAX - padding) rb_memerror();
1108 if (storage->pos + size + padding > storage->size) {
1109 unsigned int alloc_size = storage->size;
1110
1111 while (alloc_size < size + PADDING_SIZE_MAX) {
1112 if (alloc_size >= INT_MAX / 2) rb_memerror();
1113 alloc_size *= 2;
1114 }
1115 storage->next = (void *)ALLOC_N(char, alloc_size +
1116 offsetof(struct iseq_compile_data_storage, buff));
1117 storage = *arena = storage->next;
1118 storage->next = 0;
1119 storage->pos = 0;
1120 storage->size = alloc_size;
1121#ifdef STRICT_ALIGNMENT
1122 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1123#endif /* STRICT_ALIGNMENT */
1124 }
1125
1126#ifdef STRICT_ALIGNMENT
1127 storage->pos += (int)padding;
1128#endif /* STRICT_ALIGNMENT */
1129
1130 ptr = (void *)&storage->buff[storage->pos];
1131 storage->pos += (int)size;
1132 return ptr;
1133}
1134
1135static void *
1136compile_data_alloc(rb_iseq_t *iseq, size_t size)
1137{
1138 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1139 return compile_data_alloc_with_arena(arena, size);
1140}
1141
1142static inline void *
1143compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1144{
1145 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1146 return compile_data_alloc(iseq, size);
1147}
1148
1149static inline void *
1150compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1151{
1152 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1153 void *p = compile_data_alloc(iseq, size);
1154 memset(p, 0, size);
1155 return p;
1156}
1157
1158static INSN *
1159compile_data_alloc_insn(rb_iseq_t *iseq)
1160{
1161 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1162 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1163}
1164
1165static LABEL *
1166compile_data_alloc_label(rb_iseq_t *iseq)
1167{
1168 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1169}
1170
1171static ADJUST *
1172compile_data_alloc_adjust(rb_iseq_t *iseq)
1173{
1174 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1175}
1176
1177static TRACE *
1178compile_data_alloc_trace(rb_iseq_t *iseq)
1179{
1180 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1181}
1182
1183/*
1184 * elem1, elemX => elem1, elem2, elemX
1185 */
1186static void
1187ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1188{
1189 elem2->next = elem1->next;
1190 elem2->prev = elem1;
1191 elem1->next = elem2;
1192 if (elem2->next) {
1193 elem2->next->prev = elem2;
1194 }
1195}
1196
1197/*
1198 * elem1, elemX => elemX, elem2, elem1
1199 */
1200static void
1201ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1202{
1203 elem2->prev = elem1->prev;
1204 elem2->next = elem1;
1205 elem1->prev = elem2;
1206 if (elem2->prev) {
1207 elem2->prev->next = elem2;
1208 }
1209}
1210
1211/*
1212 * elemX, elem1, elemY => elemX, elem2, elemY
1213 */
1214static void
1215ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1216{
1217 elem2->prev = elem1->prev;
1218 elem2->next = elem1->next;
1219 if (elem1->prev) {
1220 elem1->prev->next = elem2;
1221 }
1222 if (elem1->next) {
1223 elem1->next->prev = elem2;
1224 }
1225}
1226
1227static void
1228ELEM_REMOVE(LINK_ELEMENT *elem)
1229{
1230 elem->prev->next = elem->next;
1231 if (elem->next) {
1232 elem->next->prev = elem->prev;
1233 }
1234}
1235
1236static LINK_ELEMENT *
1237FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1238{
1239 return anchor->anchor.next;
1240}
1241
1242static LINK_ELEMENT *
1243LAST_ELEMENT(LINK_ANCHOR *const anchor)
1244{
1245 return anchor->last;
1246}
1247
1248static LINK_ELEMENT *
1249ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1250{
1251 while (elem) {
1252 switch (elem->type) {
1253 case ISEQ_ELEMENT_INSN:
1254 case ISEQ_ELEMENT_ADJUST:
1255 return elem;
1256 default:
1257 elem = elem->next;
1258 }
1259 }
1260 return NULL;
1261}
1262
1263static int
1264LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1265{
1266 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1267 if (first_insn != NULL &&
1268 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1269 return TRUE;
1270 }
1271 else {
1272 return FALSE;
1273 }
1274}
1275
1276static int
1277LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1278{
1279 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1280 return TRUE;
1281 }
1282 else {
1283 return FALSE;
1284 }
1285}
1286
1287/*
1288 * anc1: e1, e2, e3
1289 * anc2: e4, e5
1290 *#=>
1291 * anc1: e1, e2, e3, e4, e5
1292 * anc2: e4, e5 (broken)
1293 */
1294static void
1295APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1296{
1297 if (anc2->anchor.next) {
1298 anc1->last->next = anc2->anchor.next;
1299 anc2->anchor.next->prev = anc1->last;
1300 anc1->last = anc2->last;
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 return labelobj;
1362}
1363
1364static ADJUST *
1365new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1366{
1367 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1368 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1369 adjust->link.next = 0;
1370 adjust->label = label;
1371 adjust->line_no = line;
1372 LABEL_UNREMOVABLE(label);
1373 return adjust;
1374}
1375
1376static void
1377iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
1378{
1379 const char *types = insn_op_types(insn->insn_id);
1380 for (int j = 0; types[j]; j++) {
1381 char type = types[j];
1382 switch (type) {
1383 case TS_CDHASH:
1384 case TS_ISEQ:
1385 case TS_VALUE:
1386 case TS_IC: // constant path array
1387 case TS_CALLDATA: // ci is stored.
1388 func(OPERAND_AT(insn, j), data);
1389 break;
1390 default:
1391 break;
1392 }
1393 }
1394}
1395
1396static void
1397iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
1398{
1399 RB_OBJ_WRITTEN(iseq, Qundef, obj);
1400}
1401
1402static INSN *
1403new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
1404 int insn_id, int argc, VALUE *argv)
1405{
1406 INSN *iobj = compile_data_alloc_insn(iseq);
1407
1408 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1409
1410 iobj->link.type = ISEQ_ELEMENT_INSN;
1411 iobj->link.next = 0;
1412 iobj->insn_id = insn_id;
1413 iobj->insn_info.line_no = nd_line(line_node);
1414 iobj->insn_info.node_id = nd_node_id(line_node);
1415 iobj->insn_info.events = 0;
1416 iobj->operands = argv;
1417 iobj->operand_size = argc;
1418 iobj->sc_state = 0;
1419
1420 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1421
1422 return iobj;
1423}
1424
1425static INSN *
1426new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...)
1427{
1428 VALUE *operands = 0;
1429 va_list argv;
1430 if (argc > 0) {
1431 int i;
1432 va_start(argv, argc);
1433 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1434 for (i = 0; i < argc; i++) {
1435 VALUE v = va_arg(argv, VALUE);
1436 operands[i] = v;
1437 }
1438 va_end(argv);
1439 }
1440 return new_insn_core(iseq, line_node, insn_id, argc, operands);
1441}
1442
1443static const struct rb_callinfo *
1444new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1445{
1446 VM_ASSERT(argc >= 0);
1447
1448 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
1449 kw_arg == NULL && !has_blockiseq) {
1450 flag |= VM_CALL_ARGS_SIMPLE;
1451 }
1452
1453 if (kw_arg) {
1454 flag |= VM_CALL_KWARG;
1455 argc += kw_arg->keyword_len;
1456 }
1457
1458 ISEQ_BODY(iseq)->ci_size++;
1459 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1460 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1461 return ci;
1462}
1463
1464static INSN *
1465new_insn_send(rb_iseq_t *iseq, const NODE *const line_node, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1466{
1467 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1468 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1469 operands[0] = ci;
1470 operands[1] = (VALUE)blockiseq;
1471 if (blockiseq) {
1472 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1473 }
1474 INSN *insn = new_insn_core(iseq, line_node, BIN(send), 2, operands);
1475 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1476 RB_GC_GUARD(ci);
1477 return insn;
1478}
1479
1480static rb_iseq_t *
1481new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1482 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1483{
1484 rb_iseq_t *ret_iseq;
1485 rb_ast_body_t ast;
1486
1487 ast.root = node;
1488 ast.frozen_string_literal = -1;
1489 ast.coverage_enabled = -1;
1490 ast.script_lines = ISEQ_BODY(iseq)->variable.script_lines;
1491
1492 debugs("[new_child_iseq]> ---------------------------------------\n");
1493 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1494 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1495 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1496 line_no, parent,
1497 isolated_depth ? isolated_depth + 1 : 0,
1498 type, ISEQ_COMPILE_DATA(iseq)->option);
1499 debugs("[new_child_iseq]< ---------------------------------------\n");
1500 return ret_iseq;
1501}
1502
1503static rb_iseq_t *
1504new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1505 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1506{
1507 rb_iseq_t *ret_iseq;
1508
1509 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1510 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1511 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1512 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1513 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1514 return ret_iseq;
1515}
1516
1517static void
1518set_catch_except_p(rb_iseq_t *iseq)
1519{
1520 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1521 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1522 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1523 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1524 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1525 }
1526 }
1527}
1528
1529/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1530 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1531 if catch table exists. But we want to optimize while loop, which always has catch
1532 table entries for break/next/redo.
1533
1534 So this function sets true for limited ISeqs with break/next/redo catch table entries
1535 whose child ISeq would really raise an exception. */
1536static void
1537update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1538{
1539 unsigned int pos;
1540 size_t i;
1541 int insn;
1542 const struct iseq_catch_table *ct = body->catch_table;
1543
1544 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1545 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1546 pos = 0;
1547 while (pos < body->iseq_size) {
1548 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1549 if (insn == BIN(throw)) {
1550 set_catch_except_p(iseq);
1551 break;
1552 }
1553 pos += insn_len(insn);
1554 }
1555
1556 if (ct == NULL)
1557 return;
1558
1559 for (i = 0; i < ct->size; i++) {
1560 const struct iseq_catch_table_entry *entry =
1561 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1562 if (entry->type != CATCH_TYPE_BREAK
1563 && entry->type != CATCH_TYPE_NEXT
1564 && entry->type != CATCH_TYPE_REDO) {
1565 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1566 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1567 break;
1568 }
1569 }
1570}
1571
1572static void
1573iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1574{
1575 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1576 if (NIL_P(catch_table_ary)) return;
1577 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1578 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1579 for (i = 0; i < tlen; i++) {
1580 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1581 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1582 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1583 LINK_ELEMENT *e;
1584
1585 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1586
1587 if (ct != CATCH_TYPE_BREAK
1588 && ct != CATCH_TYPE_NEXT
1589 && ct != CATCH_TYPE_REDO) {
1590
1591 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1592 if (e == cont) {
1593 NODE dummy_line_node = generate_dummy_line_node(0, -1);
1594 INSN *nop = new_insn_core(iseq, &dummy_line_node, BIN(nop), 0, 0);
1595 ELEM_INSERT_NEXT(end, &nop->link);
1596 break;
1597 }
1598 }
1599 }
1600 }
1601}
1602
1603static int
1604iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1605{
1606 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1607 return COMPILE_NG;
1608
1609 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1610
1611 if (compile_debug > 5)
1612 dump_disasm_list(FIRST_ELEMENT(anchor));
1613
1614 debugs("[compile step 3.1 (iseq_optimize)]\n");
1615 iseq_optimize(iseq, anchor);
1616
1617 if (compile_debug > 5)
1618 dump_disasm_list(FIRST_ELEMENT(anchor));
1619
1620 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1621 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1622 iseq_insns_unification(iseq, anchor);
1623 if (compile_debug > 5)
1624 dump_disasm_list(FIRST_ELEMENT(anchor));
1625 }
1626
1627 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1628 iseq_insert_nop_between_end_and_cont(iseq);
1629 if (compile_debug > 5)
1630 dump_disasm_list(FIRST_ELEMENT(anchor));
1631
1632 return COMPILE_OK;
1633}
1634
1635static int
1636iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1637{
1638 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1639 return COMPILE_NG;
1640
1641 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1642 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1643 if (compile_debug > 5)
1644 dump_disasm_list(FIRST_ELEMENT(anchor));
1645
1646 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1647 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1648
1649 debugs("[compile step 4.3 (set_optargs_table)] \n");
1650 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1651
1652 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1653 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1654
1655 debugs("[compile step 6 (update_catch_except_flags)] \n");
1656 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1657 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1658
1659 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1660 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1661 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1662 xfree(ISEQ_BODY(iseq)->catch_table);
1663 ISEQ_BODY(iseq)->catch_table = NULL;
1664 }
1665
1666#if VM_INSN_INFO_TABLE_IMPL == 2
1667 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1668 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1669 rb_iseq_insns_info_encode_positions(iseq);
1670 }
1671#endif
1672
1673 if (compile_debug > 1) {
1674 VALUE str = rb_iseq_disasm(iseq);
1675 printf("%s\n", StringValueCStr(str));
1676 }
1677 verify_call_cache(iseq);
1678 debugs("[compile step: finish]\n");
1679
1680 return COMPILE_OK;
1681}
1682
1683static int
1684iseq_set_exception_local_table(rb_iseq_t *iseq)
1685{
1686 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1687 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1688 return COMPILE_OK;
1689}
1690
1691static int
1692get_lvar_level(const rb_iseq_t *iseq)
1693{
1694 int lev = 0;
1695 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1696 lev++;
1697 iseq = ISEQ_BODY(iseq)->parent_iseq;
1698 }
1699 return lev;
1700}
1701
1702static int
1703get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1704{
1705 unsigned int i;
1706
1707 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1708 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1709 return (int)i;
1710 }
1711 }
1712 return -1;
1713}
1714
1715static int
1716get_local_var_idx(const rb_iseq_t *iseq, ID id)
1717{
1718 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1719
1720 if (idx < 0) {
1721 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1722 "get_local_var_idx: %d", idx);
1723 }
1724
1725 return idx;
1726}
1727
1728static int
1729get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1730{
1731 int lv = 0, idx = -1;
1732 const rb_iseq_t *const topmost_iseq = iseq;
1733
1734 while (iseq) {
1735 idx = get_dyna_var_idx_at_raw(iseq, id);
1736 if (idx >= 0) {
1737 break;
1738 }
1739 iseq = ISEQ_BODY(iseq)->parent_iseq;
1740 lv++;
1741 }
1742
1743 if (idx < 0) {
1744 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1745 "get_dyna_var_idx: -1");
1746 }
1747
1748 *level = lv;
1749 *ls = ISEQ_BODY(iseq)->local_table_size;
1750 return idx;
1751}
1752
1753static int
1754iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1755{
1756 const struct rb_iseq_constant_body *body;
1757 while (level > 0) {
1758 iseq = ISEQ_BODY(iseq)->parent_iseq;
1759 level--;
1760 }
1761 body = ISEQ_BODY(iseq);
1762 if (body->local_iseq == iseq && /* local variables */
1763 body->param.flags.has_block &&
1764 body->local_table_size - body->param.block_start == idx) {
1765 return TRUE;
1766 }
1767 else {
1768 return FALSE;
1769 }
1770}
1771
1772static int
1773iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1774{
1775 int level, ls;
1776 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1777 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1778 *pidx = ls - idx;
1779 *plevel = level;
1780 return TRUE;
1781 }
1782 else {
1783 return FALSE;
1784 }
1785}
1786
1787static void
1788access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1789{
1790 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1791
1792 if (isolated_depth && level >= isolated_depth) {
1793 if (id == rb_intern("yield")) {
1794 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1795 }
1796 else {
1797 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
1798 }
1799 }
1800
1801 for (int i=0; i<level; i++) {
1802 VALUE val;
1803 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1804
1805 if (!ovs) {
1806 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1807 }
1808
1809 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1810 if (write && !val) {
1811 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1812 }
1813 }
1814 else {
1815 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1816 }
1817
1818 iseq = ISEQ_BODY(iseq)->parent_iseq;
1819 }
1820}
1821
1822static ID
1823iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1824{
1825 for (int i=0; i<level; i++) {
1826 iseq = ISEQ_BODY(iseq)->parent_iseq;
1827 }
1828
1829 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1830 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1831 return id;
1832}
1833
1834static void
1835iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1836{
1837 if (iseq_local_block_param_p(iseq, idx, level)) {
1838 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1839 }
1840 else {
1841 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1842 }
1843 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1844}
1845
1846static void
1847iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1848{
1849 if (iseq_local_block_param_p(iseq, idx, level)) {
1850 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1851 }
1852 else {
1853 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1854 }
1855 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1856}
1857
1858
1859
1860static void
1861iseq_calc_param_size(rb_iseq_t *iseq)
1862{
1863 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1864 if (body->param.flags.has_opt ||
1865 body->param.flags.has_post ||
1866 body->param.flags.has_rest ||
1867 body->param.flags.has_block ||
1868 body->param.flags.has_kw ||
1869 body->param.flags.has_kwrest) {
1870
1871 if (body->param.flags.has_block) {
1872 body->param.size = body->param.block_start + 1;
1873 }
1874 else if (body->param.flags.has_kwrest) {
1875 body->param.size = body->param.keyword->rest_start + 1;
1876 }
1877 else if (body->param.flags.has_kw) {
1878 body->param.size = body->param.keyword->bits_start + 1;
1879 }
1880 else if (body->param.flags.has_post) {
1881 body->param.size = body->param.post_start + body->param.post_num;
1882 }
1883 else if (body->param.flags.has_rest) {
1884 body->param.size = body->param.rest_start + 1;
1885 }
1886 else if (body->param.flags.has_opt) {
1887 body->param.size = body->param.lead_num + body->param.opt_num;
1888 }
1889 else {
1891 }
1892 }
1893 else {
1894 body->param.size = body->param.lead_num;
1895 }
1896}
1897
1898static int
1899iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1900 const struct rb_args_info *args, int arg_size)
1901{
1902 const rb_node_kw_arg_t *node = args->kw_args;
1903 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1904 struct rb_iseq_param_keyword *keyword;
1905 const VALUE default_values = rb_ary_hidden_new(1);
1906 const VALUE complex_mark = rb_str_tmp_new(0);
1907 int kw = 0, rkw = 0, di = 0, i;
1908
1909 body->param.flags.has_kw = TRUE;
1910 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1911
1912 while (node) {
1913 kw++;
1914 node = node->nd_next;
1915 }
1916 arg_size += kw;
1917 keyword->bits_start = arg_size++;
1918
1919 node = args->kw_args;
1920 while (node) {
1921 const NODE *val_node = get_nd_value(node->nd_body);
1922 VALUE dv;
1923
1924 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1925 ++rkw;
1926 }
1927 else {
1928 switch (nd_type(val_node)) {
1929 case NODE_LIT:
1930 dv = RNODE_LIT(val_node)->nd_lit;
1931 break;
1932 case NODE_NIL:
1933 dv = Qnil;
1934 break;
1935 case NODE_TRUE:
1936 dv = Qtrue;
1937 break;
1938 case NODE_FALSE:
1939 dv = Qfalse;
1940 break;
1941 default:
1942 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1943 dv = complex_mark;
1944 }
1945
1946 keyword->num = ++di;
1947 rb_ary_push(default_values, dv);
1948 }
1949
1950 node = node->nd_next;
1951 }
1952
1953 keyword->num = kw;
1954
1955 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1956 keyword->rest_start = arg_size++;
1957 body->param.flags.has_kwrest = TRUE;
1958 }
1959 keyword->required_num = rkw;
1960 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1961
1962 {
1963 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1964
1965 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1966 VALUE dv = RARRAY_AREF(default_values, i);
1967 if (dv == complex_mark) dv = Qundef;
1968 if (!SPECIAL_CONST_P(dv)) {
1969 RB_OBJ_WRITTEN(iseq, Qundef, dv);
1970 }
1971 dvs[i] = dv;
1972 }
1973
1974 keyword->default_values = dvs;
1975 }
1976 return arg_size;
1977}
1978
1979static int
1980iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1981{
1982 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1983
1984 if (node_args) {
1985 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1986 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
1987 ID rest_id = 0;
1988 int last_comma = 0;
1989 ID block_id = 0;
1990 int arg_size;
1991
1992 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1993
1994 body->param.flags.ruby2_keywords = args->ruby2_keywords;
1995 body->param.lead_num = arg_size = (int)args->pre_args_num;
1996 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1997 debugs(" - argc: %d\n", body->param.lead_num);
1998
1999 rest_id = args->rest_arg;
2000 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2001 last_comma = 1;
2002 rest_id = 0;
2003 }
2004 block_id = args->block_arg;
2005
2006 if (args->opt_args) {
2007 const rb_node_opt_arg_t *node = args->opt_args;
2008 LABEL *label;
2009 VALUE labels = rb_ary_hidden_new(1);
2010 VALUE *opt_table;
2011 int i = 0, j;
2012
2013 while (node) {
2014 label = NEW_LABEL(nd_line(RNODE(node)));
2015 rb_ary_push(labels, (VALUE)label | 1);
2016 ADD_LABEL(optargs, label);
2017 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2018 node = node->nd_next;
2019 i += 1;
2020 }
2021
2022 /* last label */
2023 label = NEW_LABEL(nd_line(node_args));
2024 rb_ary_push(labels, (VALUE)label | 1);
2025 ADD_LABEL(optargs, label);
2026
2027 opt_table = ALLOC_N(VALUE, i+1);
2028
2029 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2030 for (j = 0; j < i+1; j++) {
2031 opt_table[j] &= ~1;
2032 }
2033 rb_ary_clear(labels);
2034
2035 body->param.flags.has_opt = TRUE;
2036 body->param.opt_num = i;
2037 body->param.opt_table = opt_table;
2038 arg_size += i;
2039 }
2040
2041 if (rest_id) {
2042 body->param.rest_start = arg_size++;
2043 body->param.flags.has_rest = TRUE;
2044 assert(body->param.rest_start != -1);
2045 }
2046
2047 if (args->first_post_arg) {
2048 body->param.post_start = arg_size;
2049 body->param.post_num = args->post_args_num;
2050 body->param.flags.has_post = TRUE;
2051 arg_size += args->post_args_num;
2052
2053 if (body->param.flags.has_rest) { /* TODO: why that? */
2054 body->param.post_start = body->param.rest_start + 1;
2055 }
2056 }
2057
2058 if (args->kw_args) {
2059 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2060 }
2061 else if (args->kw_rest_arg) {
2062 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2063 keyword->rest_start = arg_size++;
2064 body->param.keyword = keyword;
2065 body->param.flags.has_kwrest = TRUE;
2066 }
2067 else if (args->no_kwarg) {
2068 body->param.flags.accepts_no_kwarg = TRUE;
2069 }
2070
2071 if (block_id) {
2072 body->param.block_start = arg_size++;
2073 body->param.flags.has_block = TRUE;
2074 }
2075
2076 iseq_calc_param_size(iseq);
2077 body->param.size = arg_size;
2078
2079 if (args->pre_init) { /* m_init */
2080 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2081 }
2082 if (args->post_init) { /* p_init */
2083 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2084 }
2085
2086 if (body->type == ISEQ_TYPE_BLOCK) {
2087 if (body->param.flags.has_opt == FALSE &&
2088 body->param.flags.has_post == FALSE &&
2089 body->param.flags.has_rest == FALSE &&
2090 body->param.flags.has_kw == FALSE &&
2091 body->param.flags.has_kwrest == FALSE) {
2092
2093 if (body->param.lead_num == 1 && last_comma == 0) {
2094 /* {|a|} */
2095 body->param.flags.ambiguous_param0 = TRUE;
2096 }
2097 }
2098 }
2099 }
2100
2101 return COMPILE_OK;
2102}
2103
2104static int
2105iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl)
2106{
2107 unsigned int size = tbl ? tbl->size : 0;
2108
2109 if (size > 0) {
2110 ID *ids = (ID *)ALLOC_N(ID, size);
2111 MEMCPY(ids, tbl->ids, ID, size);
2112 ISEQ_BODY(iseq)->local_table = ids;
2113 }
2114 ISEQ_BODY(iseq)->local_table_size = size;
2115
2116 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2117 return COMPILE_OK;
2118}
2119
2120int
2121rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2122{
2123 int tval, tlit;
2124
2125 if (val == lit) {
2126 return 0;
2127 }
2128 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2129 return val != lit;
2130 }
2131 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2132 return -1;
2133 }
2134 else if (tlit != tval) {
2135 return -1;
2136 }
2137 else if (tlit == T_SYMBOL) {
2138 return val != lit;
2139 }
2140 else if (tlit == T_STRING) {
2141 return rb_str_hash_cmp(lit, val);
2142 }
2143 else if (tlit == T_BIGNUM) {
2144 long x = FIX2LONG(rb_big_cmp(lit, val));
2145
2146 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2147 * There is no need to call rb_fix2int here. */
2148 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2149 return (int)x;
2150 }
2151 else if (tlit == T_FLOAT) {
2152 return rb_float_cmp(lit, val);
2153 }
2154 else if (tlit == T_RATIONAL) {
2155 const struct RRational *rat1 = RRATIONAL(val);
2156 const struct RRational *rat2 = RRATIONAL(lit);
2157 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2158 }
2159 else if (tlit == T_COMPLEX) {
2160 const struct RComplex *comp1 = RCOMPLEX(val);
2161 const struct RComplex *comp2 = RCOMPLEX(lit);
2162 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2163 }
2164 else if (tlit == T_REGEXP) {
2165 return rb_reg_equal(val, lit) ? 0 : -1;
2166 }
2167 else {
2169 }
2170}
2171
2172st_index_t
2173rb_iseq_cdhash_hash(VALUE a)
2174{
2175 switch (OBJ_BUILTIN_TYPE(a)) {
2176 case -1:
2177 case T_SYMBOL:
2178 return (st_index_t)a;
2179 case T_STRING:
2180 return rb_str_hash(a);
2181 case T_BIGNUM:
2182 return FIX2LONG(rb_big_hash(a));
2183 case T_FLOAT:
2184 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2185 case T_RATIONAL:
2186 return rb_rational_hash(a);
2187 case T_COMPLEX:
2188 return rb_complex_hash(a);
2189 case T_REGEXP:
2190 return NUM2LONG(rb_reg_hash(a));
2191 default:
2193 }
2194}
2195
2196static const struct st_hash_type cdhash_type = {
2197 rb_iseq_cdhash_cmp,
2198 rb_iseq_cdhash_hash,
2199};
2200
2202 VALUE hash;
2203 int pos;
2204 int len;
2205};
2206
2207static int
2208cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2209{
2210 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2211 LABEL *lobj = (LABEL *)(val & ~1);
2212 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2213 return ST_CONTINUE;
2214}
2215
2216
2217static inline VALUE
2218get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2219{
2220 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2221}
2222
2223static inline VALUE
2224get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2225{
2226 VALUE val;
2227 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2228 if (tbl) {
2229 if (rb_id_table_lookup(tbl,id,&val)) {
2230 return val;
2231 }
2232 }
2233 else {
2234 tbl = rb_id_table_create(1);
2235 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2236 }
2237 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2238 rb_id_table_insert(tbl,id,val);
2239 return val;
2240}
2241
2242#define BADINSN_DUMP(anchor, list, dest) \
2243 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2244
2245#define BADINSN_ERROR \
2246 (xfree(generated_iseq), \
2247 xfree(insns_info), \
2248 BADINSN_DUMP(anchor, list, NULL), \
2249 COMPILE_ERROR)
2250
2251static int
2252fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2253{
2254 int stack_max = 0, sp = 0, line = 0;
2255 LINK_ELEMENT *list;
2256
2257 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2258 if (IS_LABEL(list)) {
2259 LABEL *lobj = (LABEL *)list;
2260 lobj->set = TRUE;
2261 }
2262 }
2263
2264 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2265 switch (list->type) {
2266 case ISEQ_ELEMENT_INSN:
2267 {
2268 int j, len, insn;
2269 const char *types;
2270 VALUE *operands;
2271 INSN *iobj = (INSN *)list;
2272
2273 /* update sp */
2274 sp = calc_sp_depth(sp, iobj);
2275 if (sp < 0) {
2276 BADINSN_DUMP(anchor, list, NULL);
2277 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2278 "argument stack underflow (%d)", sp);
2279 return -1;
2280 }
2281 if (sp > stack_max) {
2282 stack_max = sp;
2283 }
2284
2285 line = iobj->insn_info.line_no;
2286 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2287 operands = iobj->operands;
2288 insn = iobj->insn_id;
2289 types = insn_op_types(insn);
2290 len = insn_len(insn);
2291
2292 /* operand check */
2293 if (iobj->operand_size != len - 1) {
2294 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2295 BADINSN_DUMP(anchor, list, NULL);
2296 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2297 "operand size miss! (%d for %d)",
2298 iobj->operand_size, len - 1);
2299 return -1;
2300 }
2301
2302 for (j = 0; types[j]; j++) {
2303 if (types[j] == TS_OFFSET) {
2304 /* label(destination position) */
2305 LABEL *lobj = (LABEL *)operands[j];
2306 if (!lobj->set) {
2307 BADINSN_DUMP(anchor, list, NULL);
2308 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2309 "unknown label: "LABEL_FORMAT, lobj->label_no);
2310 return -1;
2311 }
2312 if (lobj->sp == -1) {
2313 lobj->sp = sp;
2314 }
2315 else if (lobj->sp != sp) {
2316 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2317 RSTRING_PTR(rb_iseq_path(iseq)), line,
2318 lobj->label_no, lobj->sp, sp);
2319 }
2320 }
2321 }
2322 break;
2323 }
2324 case ISEQ_ELEMENT_LABEL:
2325 {
2326 LABEL *lobj = (LABEL *)list;
2327 if (lobj->sp == -1) {
2328 lobj->sp = sp;
2329 }
2330 else {
2331 if (lobj->sp != sp) {
2332 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2333 RSTRING_PTR(rb_iseq_path(iseq)), line,
2334 lobj->label_no, lobj->sp, sp);
2335 }
2336 sp = lobj->sp;
2337 }
2338 break;
2339 }
2340 case ISEQ_ELEMENT_TRACE:
2341 {
2342 /* ignore */
2343 break;
2344 }
2345 case ISEQ_ELEMENT_ADJUST:
2346 {
2347 ADJUST *adjust = (ADJUST *)list;
2348 int orig_sp = sp;
2349
2350 sp = adjust->label ? adjust->label->sp : 0;
2351 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2352 BADINSN_DUMP(anchor, list, NULL);
2353 COMPILE_ERROR(iseq, adjust->line_no,
2354 "iseq_set_sequence: adjust bug %d < %d",
2355 orig_sp, sp);
2356 return -1;
2357 }
2358 break;
2359 }
2360 default:
2361 BADINSN_DUMP(anchor, list, NULL);
2362 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2363 return -1;
2364 }
2365 }
2366 return stack_max;
2367}
2368
2369static int
2370add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2371 int insns_info_index, int code_index, const INSN *iobj)
2372{
2373 if (insns_info_index == 0 ||
2374 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2375#ifdef USE_ISEQ_NODE_ID
2376 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2377#endif
2378 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2379 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2380#ifdef USE_ISEQ_NODE_ID
2381 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2382#endif
2383 insns_info[insns_info_index].events = iobj->insn_info.events;
2384 positions[insns_info_index] = code_index;
2385 return TRUE;
2386 }
2387 return FALSE;
2388}
2389
2390static int
2391add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2392 int insns_info_index, int code_index, const ADJUST *adjust)
2393{
2394 insns_info[insns_info_index].line_no = adjust->line_no;
2395 insns_info[insns_info_index].events = 0;
2396 positions[insns_info_index] = code_index;
2397 return TRUE;
2398}
2399
2400static ID *
2401array_to_idlist(VALUE arr)
2402{
2403 RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2404 long size = RARRAY_LEN(arr);
2405 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2406 for (int i = 0; i < size; i++) {
2407 VALUE sym = RARRAY_AREF(arr, i);
2408 ids[i] = SYM2ID(sym);
2409 }
2410 ids[size] = 0;
2411 return ids;
2412}
2413
2414static VALUE
2415idlist_to_array(const ID *ids)
2416{
2417 VALUE arr = rb_ary_new();
2418 while (*ids) {
2419 rb_ary_push(arr, ID2SYM(*ids++));
2420 }
2421 return arr;
2422}
2423
2427static int
2428iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2429{
2430 struct iseq_insn_info_entry *insns_info;
2431 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2432 unsigned int *positions;
2433 LINK_ELEMENT *list;
2434 VALUE *generated_iseq;
2435 rb_event_flag_t events = 0;
2436 long data = 0;
2437
2438 int insn_num, code_index, insns_info_index, sp = 0;
2439 int stack_max = fix_sp_depth(iseq, anchor);
2440
2441 if (stack_max < 0) return COMPILE_NG;
2442
2443 /* fix label position */
2444 insn_num = code_index = 0;
2445 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2446 switch (list->type) {
2447 case ISEQ_ELEMENT_INSN:
2448 {
2449 INSN *iobj = (INSN *)list;
2450 /* update sp */
2451 sp = calc_sp_depth(sp, iobj);
2452 insn_num++;
2453 events = iobj->insn_info.events |= events;
2454 if (ISEQ_COVERAGE(iseq)) {
2455 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2456 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2457 int line = iobj->insn_info.line_no - 1;
2458 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2459 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2460 }
2461 }
2462 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2463 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2464 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2465 }
2466 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2467 }
2468 }
2469 code_index += insn_data_length(iobj);
2470 events = 0;
2471 data = 0;
2472 break;
2473 }
2474 case ISEQ_ELEMENT_LABEL:
2475 {
2476 LABEL *lobj = (LABEL *)list;
2477 lobj->position = code_index;
2478 if (lobj->sp != sp) {
2479 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2480 RSTRING_PTR(rb_iseq_path(iseq)),
2481 lobj->label_no, lobj->sp, sp);
2482 }
2483 sp = lobj->sp;
2484 break;
2485 }
2486 case ISEQ_ELEMENT_TRACE:
2487 {
2488 TRACE *trace = (TRACE *)list;
2489 events |= trace->event;
2490 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2491 break;
2492 }
2493 case ISEQ_ELEMENT_ADJUST:
2494 {
2495 ADJUST *adjust = (ADJUST *)list;
2496 if (adjust->line_no != -1) {
2497 int orig_sp = sp;
2498 sp = adjust->label ? adjust->label->sp : 0;
2499 if (orig_sp - sp > 0) {
2500 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2501 code_index++; /* insn */
2502 insn_num++;
2503 }
2504 }
2505 break;
2506 }
2507 default: break;
2508 }
2509 }
2510
2511 /* make instruction sequence */
2512 generated_iseq = ALLOC_N(VALUE, code_index);
2513 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2514 positions = ALLOC_N(unsigned int, insn_num);
2515 if (ISEQ_IS_SIZE(body)) {
2516 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2517 }
2518 else {
2519 body->is_entries = NULL;
2520 }
2521 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2522 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2523
2524 // Calculate the bitmask buffer size.
2525 // Round the generated_iseq size up to the nearest multiple
2526 // of the number of bits in an unsigned long.
2527
2528 // Allocate enough room for the bitmask list
2529 iseq_bits_t * mark_offset_bits;
2530 int code_size = code_index;
2531
2532 iseq_bits_t tmp[1] = {0};
2533 bool needs_bitmap = false;
2534
2535 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2536 mark_offset_bits = tmp;
2537 }
2538 else {
2539 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2540 }
2541
2542 list = FIRST_ELEMENT(anchor);
2543 insns_info_index = code_index = sp = 0;
2544
2545 while (list) {
2546 switch (list->type) {
2547 case ISEQ_ELEMENT_INSN:
2548 {
2549 int j, len, insn;
2550 const char *types;
2551 VALUE *operands;
2552 INSN *iobj = (INSN *)list;
2553
2554 /* update sp */
2555 sp = calc_sp_depth(sp, iobj);
2556 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2557 operands = iobj->operands;
2558 insn = iobj->insn_id;
2559 generated_iseq[code_index] = insn;
2560 types = insn_op_types(insn);
2561 len = insn_len(insn);
2562
2563 for (j = 0; types[j]; j++) {
2564 char type = types[j];
2565
2566 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2567 switch (type) {
2568 case TS_OFFSET:
2569 {
2570 /* label(destination position) */
2571 LABEL *lobj = (LABEL *)operands[j];
2572 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2573 break;
2574 }
2575 case TS_CDHASH:
2576 {
2577 VALUE map = operands[j];
2578 struct cdhash_set_label_struct data;
2579 data.hash = map;
2580 data.pos = code_index;
2581 data.len = len;
2582 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2583
2584 rb_hash_rehash(map);
2585 freeze_hide_obj(map);
2586 generated_iseq[code_index + 1 + j] = map;
2587 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2588 RB_OBJ_WRITTEN(iseq, Qundef, map);
2589 needs_bitmap = true;
2590 break;
2591 }
2592 case TS_LINDEX:
2593 case TS_NUM: /* ulong */
2594 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2595 break;
2596 case TS_ISEQ: /* iseq */
2597 case TS_VALUE: /* VALUE */
2598 {
2599 VALUE v = operands[j];
2600 generated_iseq[code_index + 1 + j] = v;
2601 /* to mark ruby object */
2602 if (!SPECIAL_CONST_P(v)) {
2603 RB_OBJ_WRITTEN(iseq, Qundef, v);
2604 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2605 needs_bitmap = true;
2606 }
2607 break;
2608 }
2609 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2610 case TS_IC: /* inline cache: constants */
2611 {
2612 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2613 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2614 if (UNLIKELY(ic_index >= body->ic_size)) {
2615 BADINSN_DUMP(anchor, &iobj->link, 0);
2616 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2617 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2618 ic_index, ISEQ_IS_SIZE(body));
2619 }
2620
2621 ic->segments = array_to_idlist(operands[j]);
2622
2623 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2624 }
2625 break;
2626 case TS_IVC: /* inline ivar cache */
2627 {
2628 unsigned int ic_index = FIX2UINT(operands[j]);
2629
2630 IVC cache = ((IVC)&body->is_entries[ic_index]);
2631
2632 if (insn == BIN(setinstancevariable)) {
2633 cache->iv_set_name = SYM2ID(operands[j - 1]);
2634 }
2635 else {
2636 cache->iv_set_name = 0;
2637 }
2638
2639 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2640 }
2641 case TS_ISE: /* inline storage entry: `once` insn */
2642 case TS_ICVARC: /* inline cvar cache */
2643 {
2644 unsigned int ic_index = FIX2UINT(operands[j]);
2645 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2646 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2647 BADINSN_DUMP(anchor, &iobj->link, 0);
2648 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2649 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2650 ic_index, ISEQ_IS_SIZE(body));
2651 }
2652 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2653
2654 break;
2655 }
2656 case TS_CALLDATA:
2657 {
2658 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2659 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2660 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2661 cd->ci = source_ci;
2662 cd->cc = vm_cc_empty();
2663 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2664 break;
2665 }
2666 case TS_ID: /* ID */
2667 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2668 break;
2669 case TS_FUNCPTR:
2670 generated_iseq[code_index + 1 + j] = operands[j];
2671 break;
2672 case TS_BUILTIN:
2673 generated_iseq[code_index + 1 + j] = operands[j];
2674 break;
2675 default:
2676 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2677 "unknown operand type: %c", type);
2678 return COMPILE_NG;
2679 }
2680 }
2681 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2682 code_index += len;
2683 break;
2684 }
2685 case ISEQ_ELEMENT_LABEL:
2686 {
2687 LABEL *lobj = (LABEL *)list;
2688 if (lobj->sp != sp) {
2689 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2690 RSTRING_PTR(rb_iseq_path(iseq)),
2691 lobj->label_no, lobj->sp, sp);
2692 }
2693 sp = lobj->sp;
2694 break;
2695 }
2696 case ISEQ_ELEMENT_ADJUST:
2697 {
2698 ADJUST *adjust = (ADJUST *)list;
2699 int orig_sp = sp;
2700
2701 if (adjust->label) {
2702 sp = adjust->label->sp;
2703 }
2704 else {
2705 sp = 0;
2706 }
2707
2708 if (adjust->line_no != -1) {
2709 const int diff = orig_sp - sp;
2710 if (diff > 0) {
2711 if (insns_info_index == 0) {
2712 COMPILE_ERROR(iseq, adjust->line_no,
2713 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2714 }
2715 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2716 }
2717 if (diff > 1) {
2718 generated_iseq[code_index++] = BIN(adjuststack);
2719 generated_iseq[code_index++] = orig_sp - sp;
2720 }
2721 else if (diff == 1) {
2722 generated_iseq[code_index++] = BIN(pop);
2723 }
2724 else if (diff < 0) {
2725 int label_no = adjust->label ? adjust->label->label_no : -1;
2726 xfree(generated_iseq);
2727 xfree(insns_info);
2728 xfree(positions);
2729 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2730 xfree(mark_offset_bits);
2731 }
2732 debug_list(anchor, list);
2733 COMPILE_ERROR(iseq, adjust->line_no,
2734 "iseq_set_sequence: adjust bug to %d %d < %d",
2735 label_no, orig_sp, sp);
2736 return COMPILE_NG;
2737 }
2738 }
2739 break;
2740 }
2741 default:
2742 /* ignore */
2743 break;
2744 }
2745 list = list->next;
2746 }
2747
2748 body->iseq_encoded = (void *)generated_iseq;
2749 body->iseq_size = code_index;
2750 body->stack_max = stack_max;
2751
2752 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2753 body->mark_bits.single = mark_offset_bits[0];
2754 }
2755 else {
2756 if (needs_bitmap) {
2757 body->mark_bits.list = mark_offset_bits;
2758 }
2759 else {
2760 body->mark_bits.list = 0;
2761 ruby_xfree(mark_offset_bits);
2762 }
2763 }
2764
2765 /* get rid of memory leak when REALLOC failed */
2766 body->insns_info.body = insns_info;
2767 body->insns_info.positions = positions;
2768
2769 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2770 body->insns_info.body = insns_info;
2771 REALLOC_N(positions, unsigned int, insns_info_index);
2772 body->insns_info.positions = positions;
2773 body->insns_info.size = insns_info_index;
2774
2775 return COMPILE_OK;
2776}
2777
2778static int
2779label_get_position(LABEL *lobj)
2780{
2781 return lobj->position;
2782}
2783
2784static int
2785label_get_sp(LABEL *lobj)
2786{
2787 return lobj->sp;
2788}
2789
2790static int
2791iseq_set_exception_table(rb_iseq_t *iseq)
2792{
2793 const VALUE *tptr, *ptr;
2794 unsigned int tlen, i;
2795 struct iseq_catch_table_entry *entry;
2796
2797 ISEQ_BODY(iseq)->catch_table = NULL;
2798
2799 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2800 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2801 tlen = (int)RARRAY_LEN(catch_table_ary);
2802 tptr = RARRAY_CONST_PTR(catch_table_ary);
2803
2804 if (tlen > 0) {
2805 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2806 table->size = tlen;
2807
2808 for (i = 0; i < table->size; i++) {
2809 ptr = RARRAY_CONST_PTR(tptr[i]);
2810 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2811 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2812 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2813 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2814 entry->iseq = (rb_iseq_t *)ptr[3];
2815 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2816
2817 /* stack depth */
2818 if (ptr[4]) {
2819 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2820 entry->cont = label_get_position(lobj);
2821 entry->sp = label_get_sp(lobj);
2822
2823 /* TODO: Dirty Hack! Fix me */
2824 if (entry->type == CATCH_TYPE_RESCUE ||
2825 entry->type == CATCH_TYPE_BREAK ||
2826 entry->type == CATCH_TYPE_NEXT) {
2827 entry->sp--;
2828 }
2829 }
2830 else {
2831 entry->cont = 0;
2832 }
2833 }
2834 ISEQ_BODY(iseq)->catch_table = table;
2835 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2836 }
2837
2838 RB_GC_GUARD(catch_table_ary);
2839
2840 return COMPILE_OK;
2841}
2842
2843/*
2844 * set optional argument table
2845 * def foo(a, b=expr1, c=expr2)
2846 * =>
2847 * b:
2848 * expr1
2849 * c:
2850 * expr2
2851 */
2852static int
2853iseq_set_optargs_table(rb_iseq_t *iseq)
2854{
2855 int i;
2856 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2857
2858 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2859 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2860 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2861 }
2862 }
2863 return COMPILE_OK;
2864}
2865
2866static LINK_ELEMENT *
2867get_destination_insn(INSN *iobj)
2868{
2869 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2870 LINK_ELEMENT *list;
2871 rb_event_flag_t events = 0;
2872
2873 list = lobj->link.next;
2874 while (list) {
2875 switch (list->type) {
2876 case ISEQ_ELEMENT_INSN:
2877 case ISEQ_ELEMENT_ADJUST:
2878 goto found;
2879 case ISEQ_ELEMENT_LABEL:
2880 /* ignore */
2881 break;
2882 case ISEQ_ELEMENT_TRACE:
2883 {
2884 TRACE *trace = (TRACE *)list;
2885 events |= trace->event;
2886 }
2887 break;
2888 default: break;
2889 }
2890 list = list->next;
2891 }
2892 found:
2893 if (list && IS_INSN(list)) {
2894 INSN *iobj = (INSN *)list;
2895 iobj->insn_info.events |= events;
2896 }
2897 return list;
2898}
2899
2900static LINK_ELEMENT *
2901get_next_insn(INSN *iobj)
2902{
2903 LINK_ELEMENT *list = iobj->link.next;
2904
2905 while (list) {
2906 if (IS_INSN(list) || IS_ADJUST(list)) {
2907 return list;
2908 }
2909 list = list->next;
2910 }
2911 return 0;
2912}
2913
2914static LINK_ELEMENT *
2915get_prev_insn(INSN *iobj)
2916{
2917 LINK_ELEMENT *list = iobj->link.prev;
2918
2919 while (list) {
2920 if (IS_INSN(list) || IS_ADJUST(list)) {
2921 return list;
2922 }
2923 list = list->prev;
2924 }
2925 return 0;
2926}
2927
2928static void
2929unref_destination(INSN *iobj, int pos)
2930{
2931 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2932 --lobj->refcnt;
2933 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2934}
2935
2936static void
2937replace_destination(INSN *dobj, INSN *nobj)
2938{
2939 VALUE n = OPERAND_AT(nobj, 0);
2940 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2941 LABEL *nl = (LABEL *)n;
2942 --dl->refcnt;
2943 ++nl->refcnt;
2944 OPERAND_AT(dobj, 0) = n;
2945 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2946}
2947
2948static LABEL*
2949find_destination(INSN *i)
2950{
2951 int pos, len = insn_len(i->insn_id);
2952 for (pos = 0; pos < len; ++pos) {
2953 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2954 return (LABEL *)OPERAND_AT(i, pos);
2955 }
2956 }
2957 return 0;
2958}
2959
2960static int
2961remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2962{
2963 LINK_ELEMENT *first = i, *end;
2964 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2965
2966 if (!i) return 0;
2967 unref_counts = ALLOCA_N(int, nlabels);
2968 MEMZERO(unref_counts, int, nlabels);
2969 end = i;
2970 do {
2971 LABEL *lab;
2972 if (IS_INSN(i)) {
2973 if (IS_INSN_ID(i, leave)) {
2974 end = i;
2975 break;
2976 }
2977 else if ((lab = find_destination((INSN *)i)) != 0) {
2978 if (lab->unremovable) break;
2979 unref_counts[lab->label_no]++;
2980 }
2981 }
2982 else if (IS_LABEL(i)) {
2983 lab = (LABEL *)i;
2984 if (lab->unremovable) return 0;
2985 if (lab->refcnt > unref_counts[lab->label_no]) {
2986 if (i == first) return 0;
2987 break;
2988 }
2989 continue;
2990 }
2991 else if (IS_TRACE(i)) {
2992 /* do nothing */
2993 }
2994 else if (IS_ADJUST(i)) {
2995 LABEL *dest = ((ADJUST *)i)->label;
2996 if (dest && dest->unremovable) return 0;
2997 }
2998 end = i;
2999 } while ((i = i->next) != 0);
3000 i = first;
3001 do {
3002 if (IS_INSN(i)) {
3003 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3004 VALUE insn = INSN_OF(i);
3005 int pos, len = insn_len(insn);
3006 for (pos = 0; pos < len; ++pos) {
3007 switch (insn_op_types(insn)[pos]) {
3008 case TS_OFFSET:
3009 unref_destination((INSN *)i, pos);
3010 break;
3011 case TS_CALLDATA:
3012 --(body->ci_size);
3013 break;
3014 }
3015 }
3016 }
3017 ELEM_REMOVE(i);
3018 } while ((i != end) && (i = i->next) != 0);
3019 return 1;
3020}
3021
3022static int
3023iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3024{
3025 switch (OPERAND_AT(iobj, 0)) {
3026 case INT2FIX(0): /* empty array */
3027 ELEM_REMOVE(&iobj->link);
3028 return TRUE;
3029 case INT2FIX(1): /* single element array */
3030 ELEM_REMOVE(&iobj->link);
3031 return FALSE;
3032 default:
3033 iobj->insn_id = BIN(adjuststack);
3034 return TRUE;
3035 }
3036}
3037
3038static int
3039is_frozen_putstring(INSN *insn, VALUE *op)
3040{
3041 if (IS_INSN_ID(insn, putstring)) {
3042 *op = OPERAND_AT(insn, 0);
3043 return 1;
3044 }
3045 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3046 *op = OPERAND_AT(insn, 0);
3047 return RB_TYPE_P(*op, T_STRING);
3048 }
3049 return 0;
3050}
3051
3052static int
3053optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3054{
3055 /*
3056 * putobject obj
3057 * dup
3058 * checktype T_XXX
3059 * branchif l1
3060 * l2:
3061 * ...
3062 * l1:
3063 *
3064 * => obj is a T_XXX
3065 *
3066 * putobject obj (T_XXX)
3067 * jump L1
3068 * L1:
3069 *
3070 * => obj is not a T_XXX
3071 *
3072 * putobject obj (T_XXX)
3073 * jump L2
3074 * L2:
3075 */
3076 int line, node_id;
3077 INSN *niobj, *ciobj, *dup = 0;
3078 LABEL *dest = 0;
3079 VALUE type;
3080
3081 switch (INSN_OF(iobj)) {
3082 case BIN(putstring):
3084 break;
3085 case BIN(putnil):
3086 type = INT2FIX(T_NIL);
3087 break;
3088 case BIN(putobject):
3089 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3090 break;
3091 default: return FALSE;
3092 }
3093
3094 ciobj = (INSN *)get_next_insn(iobj);
3095 if (IS_INSN_ID(ciobj, jump)) {
3096 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3097 }
3098 if (IS_INSN_ID(ciobj, dup)) {
3099 ciobj = (INSN *)get_next_insn(dup = ciobj);
3100 }
3101 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3102 niobj = (INSN *)get_next_insn(ciobj);
3103 if (!niobj) {
3104 /* TODO: putobject true/false */
3105 return FALSE;
3106 }
3107 switch (INSN_OF(niobj)) {
3108 case BIN(branchif):
3109 if (OPERAND_AT(ciobj, 0) == type) {
3110 dest = (LABEL *)OPERAND_AT(niobj, 0);
3111 }
3112 break;
3113 case BIN(branchunless):
3114 if (OPERAND_AT(ciobj, 0) != type) {
3115 dest = (LABEL *)OPERAND_AT(niobj, 0);
3116 }
3117 break;
3118 default:
3119 return FALSE;
3120 }
3121 line = ciobj->insn_info.line_no;
3122 node_id = ciobj->insn_info.node_id;
3123 NODE dummy_line_node = generate_dummy_line_node(line, node_id);
3124 if (!dest) {
3125 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3126 dest = (LABEL *)niobj->link.next; /* reuse label */
3127 }
3128 else {
3129 dest = NEW_LABEL(line);
3130 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3131 }
3132 }
3133 INSERT_AFTER_INSN1(iobj, &dummy_line_node, jump, dest);
3134 LABEL_REF(dest);
3135 if (!dup) INSERT_AFTER_INSN(iobj, &dummy_line_node, pop);
3136 return TRUE;
3137}
3138
3139static const struct rb_callinfo *
3140ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3141{
3142 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3143 vm_ci_flag(ci) | add,
3144 vm_ci_argc(ci),
3145 vm_ci_kwarg(ci));
3146 RB_OBJ_WRITTEN(iseq, ci, nci);
3147 return nci;
3148}
3149
3150static const struct rb_callinfo *
3151ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3152{
3153 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3154 vm_ci_flag(ci),
3155 argc,
3156 vm_ci_kwarg(ci));
3157 RB_OBJ_WRITTEN(iseq, ci, nci);
3158 return nci;
3159}
3160
3161static int
3162iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3163{
3164 INSN *const iobj = (INSN *)list;
3165
3166 again:
3167 optimize_checktype(iseq, iobj);
3168
3169 if (IS_INSN_ID(iobj, jump)) {
3170 INSN *niobj, *diobj, *piobj;
3171 diobj = (INSN *)get_destination_insn(iobj);
3172 niobj = (INSN *)get_next_insn(iobj);
3173
3174 if (diobj == niobj) {
3175 /*
3176 * jump LABEL
3177 * LABEL:
3178 * =>
3179 * LABEL:
3180 */
3181 unref_destination(iobj, 0);
3182 ELEM_REMOVE(&iobj->link);
3183 return COMPILE_OK;
3184 }
3185 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3186 IS_INSN_ID(diobj, jump) &&
3187 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3188 diobj->insn_info.events == 0) {
3189 /*
3190 * useless jump elimination:
3191 * jump LABEL1
3192 * ...
3193 * LABEL1:
3194 * jump LABEL2
3195 *
3196 * => in this case, first jump instruction should jump to
3197 * LABEL2 directly
3198 */
3199 replace_destination(iobj, diobj);
3200 remove_unreachable_chunk(iseq, iobj->link.next);
3201 goto again;
3202 }
3203 else if (IS_INSN_ID(diobj, leave)) {
3204 /*
3205 * jump LABEL
3206 * ...
3207 * LABEL:
3208 * leave
3209 * =>
3210 * leave
3211 * ...
3212 * LABEL:
3213 * leave
3214 */
3215 /* replace */
3216 unref_destination(iobj, 0);
3217 iobj->insn_id = BIN(leave);
3218 iobj->operand_size = 0;
3219 iobj->insn_info = diobj->insn_info;
3220 goto again;
3221 }
3222 else if (IS_INSN(iobj->link.prev) &&
3223 (piobj = (INSN *)iobj->link.prev) &&
3224 (IS_INSN_ID(piobj, branchif) ||
3225 IS_INSN_ID(piobj, branchunless))) {
3226 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3227 if (niobj == pdiobj) {
3228 int refcnt = IS_LABEL(piobj->link.next) ?
3229 ((LABEL *)piobj->link.next)->refcnt : 0;
3230 /*
3231 * useless jump elimination (if/unless destination):
3232 * if L1
3233 * jump L2
3234 * L1:
3235 * ...
3236 * L2:
3237 *
3238 * ==>
3239 * unless L2
3240 * L1:
3241 * ...
3242 * L2:
3243 */
3244 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3245 ? BIN(branchunless) : BIN(branchif);
3246 replace_destination(piobj, iobj);
3247 if (refcnt <= 1) {
3248 ELEM_REMOVE(&iobj->link);
3249 }
3250 else {
3251 /* TODO: replace other branch destinations too */
3252 }
3253 return COMPILE_OK;
3254 }
3255 else if (diobj == pdiobj) {
3256 /*
3257 * useless jump elimination (if/unless before jump):
3258 * L1:
3259 * ...
3260 * if L1
3261 * jump L1
3262 *
3263 * ==>
3264 * L1:
3265 * ...
3266 * pop
3267 * jump L1
3268 */
3269 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3270 INSN *popiobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, 0);
3271 ELEM_REPLACE(&piobj->link, &popiobj->link);
3272 }
3273 }
3274 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3275 goto again;
3276 }
3277 }
3278
3279 /*
3280 * putstring "beg"
3281 * putstring "end"
3282 * newrange excl
3283 *
3284 * ==>
3285 *
3286 * putobject "beg".."end"
3287 */
3288 if (IS_INSN_ID(iobj, newrange)) {
3289 INSN *const range = iobj;
3290 INSN *beg, *end;
3291 VALUE str_beg, str_end;
3292
3293 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3294 is_frozen_putstring(end, &str_end) &&
3295 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3296 is_frozen_putstring(beg, &str_beg)) {
3297 int excl = FIX2INT(OPERAND_AT(range, 0));
3298 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3299
3300 ELEM_REMOVE(&beg->link);
3301 ELEM_REMOVE(&end->link);
3302 range->insn_id = BIN(putobject);
3303 OPERAND_AT(range, 0) = lit_range;
3304 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3305 }
3306 }
3307
3308 if (IS_INSN_ID(iobj, leave)) {
3309 remove_unreachable_chunk(iseq, iobj->link.next);
3310 }
3311
3312 /*
3313 * ...
3314 * duparray [...]
3315 * concatarray
3316 * =>
3317 * ...
3318 * putobject [...]
3319 * concatarray
3320 */
3321 if (IS_INSN_ID(iobj, duparray)) {
3322 LINK_ELEMENT *next = iobj->link.next;
3323 if (IS_INSN(next) && IS_INSN_ID(next, concatarray)) {
3324 iobj->insn_id = BIN(putobject);
3325 }
3326 }
3327
3328 if (IS_INSN_ID(iobj, branchif) ||
3329 IS_INSN_ID(iobj, branchnil) ||
3330 IS_INSN_ID(iobj, branchunless)) {
3331 /*
3332 * if L1
3333 * ...
3334 * L1:
3335 * jump L2
3336 * =>
3337 * if L2
3338 */
3339 INSN *nobj = (INSN *)get_destination_insn(iobj);
3340
3341 /* This is super nasty hack!!!
3342 *
3343 * This jump-jump optimization may ignore event flags of the jump
3344 * instruction being skipped. Actually, Line 2 TracePoint event
3345 * is never fired in the following code:
3346 *
3347 * 1: raise if 1 == 2
3348 * 2: while true
3349 * 3: break
3350 * 4: end
3351 *
3352 * This is critical for coverage measurement. [Bug #15980]
3353 *
3354 * This is a stopgap measure: stop the jump-jump optimization if
3355 * coverage measurement is enabled and if the skipped instruction
3356 * has any event flag.
3357 *
3358 * Note that, still, TracePoint Line event does not occur on Line 2.
3359 * This should be fixed in future.
3360 */
3361 int stop_optimization =
3362 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3363 nobj->link.type == ISEQ_ELEMENT_INSN &&
3364 nobj->insn_info.events;
3365 if (!stop_optimization) {
3366 INSN *pobj = (INSN *)iobj->link.prev;
3367 int prev_dup = 0;
3368 if (pobj) {
3369 if (!IS_INSN(&pobj->link))
3370 pobj = 0;
3371 else if (IS_INSN_ID(pobj, dup))
3372 prev_dup = 1;
3373 }
3374
3375 for (;;) {
3376 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3377 replace_destination(iobj, nobj);
3378 }
3379 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3380 !!(nobj = (INSN *)nobj->link.next) &&
3381 /* basic blocks, with no labels in the middle */
3382 nobj->insn_id == iobj->insn_id) {
3383 /*
3384 * dup
3385 * if L1
3386 * ...
3387 * L1:
3388 * dup
3389 * if L2
3390 * =>
3391 * dup
3392 * if L2
3393 * ...
3394 * L1:
3395 * dup
3396 * if L2
3397 */
3398 replace_destination(iobj, nobj);
3399 }
3400 else if (pobj) {
3401 /*
3402 * putnil
3403 * if L1
3404 * =>
3405 * # nothing
3406 *
3407 * putobject true
3408 * if L1
3409 * =>
3410 * jump L1
3411 *
3412 * putstring ".."
3413 * if L1
3414 * =>
3415 * jump L1
3416 *
3417 * putstring ".."
3418 * dup
3419 * if L1
3420 * =>
3421 * putstring ".."
3422 * jump L1
3423 *
3424 */
3425 int cond;
3426 if (prev_dup && IS_INSN(pobj->link.prev)) {
3427 pobj = (INSN *)pobj->link.prev;
3428 }
3429 if (IS_INSN_ID(pobj, putobject)) {
3430 cond = (IS_INSN_ID(iobj, branchif) ?
3431 OPERAND_AT(pobj, 0) != Qfalse :
3432 IS_INSN_ID(iobj, branchunless) ?
3433 OPERAND_AT(pobj, 0) == Qfalse :
3434 FALSE);
3435 }
3436 else if (IS_INSN_ID(pobj, putstring) ||
3437 IS_INSN_ID(pobj, duparray) ||
3438 IS_INSN_ID(pobj, newarray)) {
3439 cond = IS_INSN_ID(iobj, branchif);
3440 }
3441 else if (IS_INSN_ID(pobj, putnil)) {
3442 cond = !IS_INSN_ID(iobj, branchif);
3443 }
3444 else break;
3445 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3446 ELEM_REMOVE(iobj->link.prev);
3447 }
3448 else if (!iseq_pop_newarray(iseq, pobj)) {
3449 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3450 pobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, NULL);
3451 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3452 }
3453 if (cond) {
3454 if (prev_dup) {
3455 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3456 pobj = new_insn_core(iseq, &dummy_line_node, BIN(putnil), 0, NULL);
3457 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3458 }
3459 iobj->insn_id = BIN(jump);
3460 goto again;
3461 }
3462 else {
3463 unref_destination(iobj, 0);
3464 ELEM_REMOVE(&iobj->link);
3465 }
3466 break;
3467 }
3468 else break;
3469 nobj = (INSN *)get_destination_insn(nobj);
3470 }
3471 }
3472 }
3473
3474 if (IS_INSN_ID(iobj, pop)) {
3475 /*
3476 * putself / putnil / putobject obj / putstring "..."
3477 * pop
3478 * =>
3479 * # do nothing
3480 */
3481 LINK_ELEMENT *prev = iobj->link.prev;
3482 if (IS_INSN(prev)) {
3483 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3484 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3485 previ == BIN(putself) || previ == BIN(putstring) ||
3486 previ == BIN(dup) ||
3487 previ == BIN(getlocal) ||
3488 previ == BIN(getblockparam) ||
3489 previ == BIN(getblockparamproxy) ||
3490 previ == BIN(getinstancevariable) ||
3491 previ == BIN(duparray)) {
3492 /* just push operand or static value and pop soon, no
3493 * side effects */
3494 ELEM_REMOVE(prev);
3495 ELEM_REMOVE(&iobj->link);
3496 }
3497 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3498 ELEM_REMOVE(&iobj->link);
3499 }
3500 else if (previ == BIN(concatarray)) {
3501 INSN *piobj = (INSN *)prev;
3502 NODE dummy_line_node = generate_dummy_line_node(piobj->insn_info.line_no, piobj->insn_info.node_id);
3503 INSERT_BEFORE_INSN1(piobj, &dummy_line_node, splatarray, Qfalse);
3504 INSN_OF(piobj) = BIN(pop);
3505 }
3506 else if (previ == BIN(concatstrings)) {
3507 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3508 ELEM_REMOVE(prev);
3509 }
3510 else {
3511 ELEM_REMOVE(&iobj->link);
3512 INSN_OF(prev) = BIN(adjuststack);
3513 }
3514 }
3515 }
3516 }
3517
3518 if (IS_INSN_ID(iobj, newarray) ||
3519 IS_INSN_ID(iobj, duparray) ||
3520 IS_INSN_ID(iobj, expandarray) ||
3521 IS_INSN_ID(iobj, concatarray) ||
3522 IS_INSN_ID(iobj, splatarray) ||
3523 0) {
3524 /*
3525 * newarray N
3526 * splatarray
3527 * =>
3528 * newarray N
3529 * newarray always puts an array
3530 */
3531 LINK_ELEMENT *next = iobj->link.next;
3532 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3533 /* remove splatarray following always-array insn */
3534 ELEM_REMOVE(next);
3535 }
3536 }
3537
3538 if (IS_INSN_ID(iobj, newarray)) {
3539 LINK_ELEMENT *next = iobj->link.next;
3540 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3541 OPERAND_AT(next, 1) == INT2FIX(0)) {
3542 VALUE op1, op2;
3543 op1 = OPERAND_AT(iobj, 0);
3544 op2 = OPERAND_AT(next, 0);
3545 ELEM_REMOVE(next);
3546
3547 if (op1 == op2) {
3548 /*
3549 * newarray 2
3550 * expandarray 2, 0
3551 * =>
3552 * swap
3553 */
3554 if (op1 == INT2FIX(2)) {
3555 INSN_OF(iobj) = BIN(swap);
3556 iobj->operand_size = 0;
3557 }
3558 /*
3559 * newarray X
3560 * expandarray X, 0
3561 * =>
3562 * opt_reverse X
3563 */
3564 else {
3565 INSN_OF(iobj) = BIN(opt_reverse);
3566 }
3567 }
3568 else {
3569 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3570 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3571 INSN_OF(iobj) = BIN(opt_reverse);
3572 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3573
3574 if (op1 > op2) {
3575 /* X > Y
3576 * newarray X
3577 * expandarray Y, 0
3578 * =>
3579 * pop * (Y-X)
3580 * opt_reverse Y
3581 */
3582 for (; diff > 0; diff--) {
3583 INSERT_BEFORE_INSN(iobj, &dummy_line_node, pop);
3584 }
3585 }
3586 else { /* (op1 < op2) */
3587 /* X < Y
3588 * newarray X
3589 * expandarray Y, 0
3590 * =>
3591 * putnil * (Y-X)
3592 * opt_reverse Y
3593 */
3594 for (; diff < 0; diff++) {
3595 INSERT_BEFORE_INSN(iobj, &dummy_line_node, putnil);
3596 }
3597 }
3598 }
3599 }
3600 }
3601
3602 if (IS_INSN_ID(iobj, duparray)) {
3603 LINK_ELEMENT *next = iobj->link.next;
3604 /*
3605 * duparray obj
3606 * expandarray X, 0
3607 * =>
3608 * putobject obj
3609 * expandarray X, 0
3610 */
3611 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3612 INSN_OF(iobj) = BIN(putobject);
3613 }
3614 }
3615
3616 if (IS_INSN_ID(iobj, anytostring)) {
3617 LINK_ELEMENT *next = iobj->link.next;
3618 /*
3619 * anytostring
3620 * concatstrings 1
3621 * =>
3622 * anytostring
3623 */
3624 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3625 OPERAND_AT(next, 0) == INT2FIX(1)) {
3626 ELEM_REMOVE(next);
3627 }
3628 }
3629
3630 if (IS_INSN_ID(iobj, putstring) ||
3631 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3632 /*
3633 * putstring ""
3634 * concatstrings N
3635 * =>
3636 * concatstrings N-1
3637 */
3638 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3639 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3640 INSN *next = (INSN *)iobj->link.next;
3641 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3642 ELEM_REMOVE(&next->link);
3643 }
3644 ELEM_REMOVE(&iobj->link);
3645 }
3646 }
3647
3648 if (IS_INSN_ID(iobj, concatstrings)) {
3649 /*
3650 * concatstrings N
3651 * concatstrings M
3652 * =>
3653 * concatstrings N+M-1
3654 */
3655 LINK_ELEMENT *next = iobj->link.next;
3656 INSN *jump = 0;
3657 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3658 next = get_destination_insn(jump = (INSN *)next);
3659 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3660 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3661 OPERAND_AT(iobj, 0) = INT2FIX(n);
3662 if (jump) {
3663 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3664 if (!--label->refcnt) {
3665 ELEM_REMOVE(&label->link);
3666 }
3667 else {
3668 label = NEW_LABEL(0);
3669 OPERAND_AT(jump, 0) = (VALUE)label;
3670 }
3671 label->refcnt++;
3672 ELEM_INSERT_NEXT(next, &label->link);
3673 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3674 }
3675 else {
3676 ELEM_REMOVE(next);
3677 }
3678 }
3679 }
3680
3681 if (do_tailcallopt &&
3682 (IS_INSN_ID(iobj, send) ||
3683 IS_INSN_ID(iobj, opt_aref_with) ||
3684 IS_INSN_ID(iobj, opt_aset_with) ||
3685 IS_INSN_ID(iobj, invokesuper))) {
3686 /*
3687 * send ...
3688 * leave
3689 * =>
3690 * send ..., ... | VM_CALL_TAILCALL, ...
3691 * leave # unreachable
3692 */
3693 INSN *piobj = NULL;
3694 if (iobj->link.next) {
3695 LINK_ELEMENT *next = iobj->link.next;
3696 do {
3697 if (!IS_INSN(next)) {
3698 next = next->next;
3699 continue;
3700 }
3701 switch (INSN_OF(next)) {
3702 case BIN(nop):
3703 next = next->next;
3704 break;
3705 case BIN(jump):
3706 /* if cond
3707 * return tailcall
3708 * end
3709 */
3710 next = get_destination_insn((INSN *)next);
3711 break;
3712 case BIN(leave):
3713 piobj = iobj;
3714 /* fall through */
3715 default:
3716 next = NULL;
3717 break;
3718 }
3719 } while (next);
3720 }
3721
3722 if (piobj) {
3723 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3724 if (IS_INSN_ID(piobj, send) ||
3725 IS_INSN_ID(piobj, invokesuper)) {
3726 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3727 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3728 OPERAND_AT(piobj, 0) = (VALUE)ci;
3729 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3730 }
3731 }
3732 else {
3733 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3734 OPERAND_AT(piobj, 0) = (VALUE)ci;
3735 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3736 }
3737 }
3738 }
3739
3740 if (IS_INSN_ID(iobj, dup)) {
3741 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3742 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3743
3744 /*
3745 * dup
3746 * setlocal x, y
3747 * setlocal x, y
3748 * =>
3749 * dup
3750 * setlocal x, y
3751 */
3752 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3753 set2 = set1->next;
3754 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3755 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3756 ELEM_REMOVE(set1);
3757 ELEM_REMOVE(&iobj->link);
3758 }
3759 }
3760
3761 /*
3762 * dup
3763 * setlocal x, y
3764 * dup
3765 * setlocal x, y
3766 * =>
3767 * dup
3768 * setlocal x, y
3769 */
3770 else if (IS_NEXT_INSN_ID(set1, dup) &&
3771 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3772 set2 = set1->next->next;
3773 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3774 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3775 ELEM_REMOVE(set1->next);
3776 ELEM_REMOVE(set2);
3777 }
3778 }
3779 }
3780 }
3781
3782 /*
3783 * getlocal x, y
3784 * dup
3785 * setlocal x, y
3786 * =>
3787 * dup
3788 */
3789 if (IS_INSN_ID(iobj, getlocal)) {
3790 LINK_ELEMENT *niobj = &iobj->link;
3791 if (IS_NEXT_INSN_ID(niobj, dup)) {
3792 niobj = niobj->next;
3793 }
3794 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3795 LINK_ELEMENT *set1 = niobj->next;
3796 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3797 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3798 ELEM_REMOVE(set1);
3799 ELEM_REMOVE(niobj);
3800 }
3801 }
3802 }
3803
3804 /*
3805 * opt_invokebuiltin_delegate
3806 * trace
3807 * leave
3808 * =>
3809 * opt_invokebuiltin_delegate_leave
3810 * trace
3811 * leave
3812 */
3813 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3814 if (IS_TRACE(iobj->link.next)) {
3815 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3816 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3817 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
3818 if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
3819 iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_INLINE;
3820 }
3821 }
3822 }
3823 }
3824
3825 /*
3826 * getblockparam
3827 * branchif / branchunless
3828 * =>
3829 * getblockparamproxy
3830 * branchif / branchunless
3831 */
3832 if (IS_INSN_ID(iobj, getblockparam)) {
3833 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
3834 iobj->insn_id = BIN(getblockparamproxy);
3835 }
3836 }
3837
3838 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == Qtrue) {
3839 LINK_ELEMENT *niobj = &iobj->link;
3840
3841 /*
3842 * Eliminate array allocation for f(1, *a)
3843 *
3844 * splatarray true
3845 * send ARGS_SPLAT and not KW_SPLAT|ARGS_BLOCKARG
3846 * =>
3847 * splatarray false
3848 * send
3849 */
3850 if (IS_NEXT_INSN_ID(niobj, send)) {
3851 niobj = niobj->next;
3852 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3853 if ((flag & VM_CALL_ARGS_SPLAT) && !(flag & (VM_CALL_KW_SPLAT|VM_CALL_ARGS_BLOCKARG))) {
3854 OPERAND_AT(iobj, 0) = Qfalse;
3855 }
3856 } else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable)) {
3857 niobj = niobj->next;
3858
3859 if (IS_NEXT_INSN_ID(niobj, send)) {
3860 niobj = niobj->next;
3861 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3862
3863 if ((flag & VM_CALL_ARGS_SPLAT)) {
3864 /*
3865 * Eliminate array allocation for f(1, *a, &lvar) and f(1, *a, &@iv)
3866 *
3867 * splatarray true
3868 * getlocal / getinstancevariable
3869 * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
3870 * =>
3871 * splatarray false
3872 * getlocal / getinstancevariable
3873 * send
3874 */
3875 if ((flag & VM_CALL_ARGS_BLOCKARG) && !(flag & VM_CALL_KW_SPLAT)) {
3876 OPERAND_AT(iobj, 0) = Qfalse;
3877 }
3878
3879 /*
3880 * Eliminate array allocation for f(*a, **lvar) and f(*a, **@iv)
3881 *
3882 * splatarray true
3883 * getlocal / getinstancevariable
3884 * send ARGS_SPLAT|KW_SPLAT and not ARGS_BLOCKARG
3885 * =>
3886 * splatarray false
3887 * getlocal / getinstancevariable
3888 * send
3889 */
3890 else if (!(flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT)) {
3891 OPERAND_AT(iobj, 0) = Qfalse;
3892 }
3893 }
3894 }
3895 else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
3896 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
3897 niobj = niobj->next;
3898
3899 /*
3900 * Eliminate array allocation for f(*a, **lvar, &lvar) and f(*a, **@iv, &@iv)
3901 *
3902 * splatarray true
3903 * getlocal / getinstancevariable
3904 * getlocal / getinstancevariable / getblockparamproxy
3905 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
3906 * =>
3907 * splatarray false
3908 * getlocal / getinstancevariable
3909 * getlocal / getinstancevariable / getblockparamproxy
3910 * send
3911 */
3912 if (IS_NEXT_INSN_ID(niobj, send)) {
3913 niobj = niobj->next;
3914 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3915
3916 if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) && (flag & VM_CALL_ARGS_BLOCKARG)) {
3917 OPERAND_AT(iobj, 0) = Qfalse;
3918 }
3919 }
3920 }
3921 }
3922 else if (IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
3923 niobj = niobj->next;
3924
3925 if (IS_NEXT_INSN_ID(niobj, send)) {
3926 niobj = niobj->next;
3927 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3928
3929 /*
3930 * Eliminate array allocation for f(1, *a, &arg)
3931 *
3932 * splatarray true
3933 * getblockparamproxy
3934 * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
3935 * =>
3936 * splatarray false
3937 * getblockparamproxy
3938 * send
3939 */
3940 if ((flag & VM_CALL_ARGS_BLOCKARG) & (flag & VM_CALL_ARGS_SPLAT) && !(flag & VM_CALL_KW_SPLAT)) {
3941 OPERAND_AT(iobj, 0) = Qfalse;
3942 }
3943 }
3944 }
3945 else if (IS_NEXT_INSN_ID(niobj, duphash)) {
3946 niobj = niobj->next;
3947
3948 /*
3949 * Eliminate array allocation for f(*a, kw: 1)
3950 *
3951 * splatarray true
3952 * duphash
3953 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
3954 * =>
3955 * splatarray false
3956 * duphash
3957 * send
3958 */
3959 if (IS_NEXT_INSN_ID(niobj, send)) {
3960 niobj = niobj->next;
3961 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3962
3963 if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) &&
3964 (flag & VM_CALL_KW_SPLAT_MUT) && !(flag & VM_CALL_ARGS_BLOCKARG)) {
3965 OPERAND_AT(iobj, 0) = Qfalse;
3966 }
3967 }
3968 else if (IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
3969 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) {
3970 niobj = niobj->next;
3971
3972 /*
3973 * Eliminate array allocation for f(*a, kw: 1, &lvar) and f(*a, kw: 1, &@iv)
3974 *
3975 * splatarray true
3976 * duphash
3977 * getlocal / getinstancevariable / getblockparamproxy
3978 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
3979 * =>
3980 * splatarray false
3981 * duphash
3982 * getlocal / getinstancevariable / getblockparamproxy
3983 * send
3984 */
3985 if (IS_NEXT_INSN_ID(niobj, send)) {
3986 niobj = niobj->next;
3987 unsigned int flag = vm_ci_flag((const struct rb_callinfo *)OPERAND_AT(niobj, 0));
3988
3989 if ((flag & VM_CALL_ARGS_SPLAT) && (flag & VM_CALL_KW_SPLAT) &&
3990 (flag & VM_CALL_KW_SPLAT_MUT) && (flag & VM_CALL_ARGS_BLOCKARG)) {
3991 OPERAND_AT(iobj, 0) = Qfalse;
3992 }
3993 }
3994 }
3995 }
3996 }
3997
3998 return COMPILE_OK;
3999}
4000
4001static int
4002insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4003{
4004 iobj->insn_id = insn_id;
4005 iobj->operand_size = insn_len(insn_id) - 1;
4006 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4007
4008 if (insn_id == BIN(opt_neq)) {
4009 VALUE original_ci = iobj->operands[0];
4010 iobj->operand_size = 2;
4011 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4012 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4013 iobj->operands[1] = original_ci;
4014 }
4015
4016 return COMPILE_OK;
4017}
4018
4019static int
4020iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4021{
4022 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4023 IS_INSN(iobj->link.next)) {
4024 /*
4025 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
4026 */
4027 INSN *niobj = (INSN *)iobj->link.next;
4028 if (IS_INSN_ID(niobj, send)) {
4029 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4030 if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
4031 switch (vm_ci_mid(ci)) {
4032 case idMax:
4033 case idMin:
4034 case idHash:
4035 {
4036 VALUE num = iobj->operands[0];
4037 iobj->insn_id = BIN(opt_newarray_send);
4038 iobj->operands = compile_data_calloc2(iseq, insn_len(iobj->insn_id) - 1, sizeof(VALUE));
4039 iobj->operands[0] = num;
4040 iobj->operands[1] = rb_id2sym(vm_ci_mid(ci));
4041 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4042 ELEM_REMOVE(&niobj->link);
4043 return COMPILE_OK;
4044 }
4045 }
4046 }
4047 }
4048 }
4049
4050 if (IS_INSN_ID(iobj, send)) {
4051 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4052 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4053
4054#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4055 if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
4056 switch (vm_ci_argc(ci)) {
4057 case 0:
4058 switch (vm_ci_mid(ci)) {
4059 case idLength: SP_INSN(length); return COMPILE_OK;
4060 case idSize: SP_INSN(size); return COMPILE_OK;
4061 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4062 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4063 case idSucc: SP_INSN(succ); return COMPILE_OK;
4064 case idNot: SP_INSN(not); return COMPILE_OK;
4065 }
4066 break;
4067 case 1:
4068 switch (vm_ci_mid(ci)) {
4069 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4070 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4071 case idMULT: SP_INSN(mult); return COMPILE_OK;
4072 case idDIV: SP_INSN(div); return COMPILE_OK;
4073 case idMOD: SP_INSN(mod); return COMPILE_OK;
4074 case idEq: SP_INSN(eq); return COMPILE_OK;
4075 case idNeq: SP_INSN(neq); return COMPILE_OK;
4076 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4077 case idLT: SP_INSN(lt); return COMPILE_OK;
4078 case idLE: SP_INSN(le); return COMPILE_OK;
4079 case idGT: SP_INSN(gt); return COMPILE_OK;
4080 case idGE: SP_INSN(ge); return COMPILE_OK;
4081 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4082 case idAREF: SP_INSN(aref); return COMPILE_OK;
4083 case idAnd: SP_INSN(and); return COMPILE_OK;
4084 case idOr: SP_INSN(or); return COMPILE_OK;
4085 }
4086 break;
4087 case 2:
4088 switch (vm_ci_mid(ci)) {
4089 case idASET: SP_INSN(aset); return COMPILE_OK;
4090 }
4091 break;
4092 }
4093 }
4094
4095 if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
4096 iobj->insn_id = BIN(opt_send_without_block);
4097 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4098 }
4099 }
4100#undef SP_INSN
4101
4102 return COMPILE_OK;
4103}
4104
4105static inline int
4106tailcallable_p(rb_iseq_t *iseq)
4107{
4108 switch (ISEQ_BODY(iseq)->type) {
4109 case ISEQ_TYPE_TOP:
4110 case ISEQ_TYPE_EVAL:
4111 case ISEQ_TYPE_MAIN:
4112 /* not tail callable because cfp will be over popped */
4113 case ISEQ_TYPE_RESCUE:
4114 case ISEQ_TYPE_ENSURE:
4115 /* rescue block can't tail call because of errinfo */
4116 return FALSE;
4117 default:
4118 return TRUE;
4119 }
4120}
4121
4122static int
4123iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4124{
4125 LINK_ELEMENT *list;
4126 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4127 const int do_tailcallopt = tailcallable_p(iseq) &&
4128 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4129 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4130 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4131 int rescue_level = 0;
4132 int tailcallopt = do_tailcallopt;
4133
4134 list = FIRST_ELEMENT(anchor);
4135
4136 int do_block_optimization = 0;
4137
4138 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4139 do_block_optimization = 1;
4140 }
4141
4142 while (list) {
4143 if (IS_INSN(list)) {
4144 if (do_peepholeopt) {
4145 iseq_peephole_optimize(iseq, list, tailcallopt);
4146 }
4147 if (do_si) {
4148 iseq_specialized_instruction(iseq, (INSN *)list);
4149 }
4150 if (do_ou) {
4151 insn_operands_unification((INSN *)list);
4152 }
4153
4154 if (do_block_optimization) {
4155 INSN * item = (INSN *)list;
4156 if (IS_INSN_ID(item, jump)) {
4157 do_block_optimization = 0;
4158 }
4159 }
4160 }
4161 if (IS_LABEL(list)) {
4162 switch (((LABEL *)list)->rescued) {
4163 case LABEL_RESCUE_BEG:
4164 rescue_level++;
4165 tailcallopt = FALSE;
4166 break;
4167 case LABEL_RESCUE_END:
4168 if (!--rescue_level) tailcallopt = do_tailcallopt;
4169 break;
4170 }
4171 }
4172 list = list->next;
4173 }
4174
4175 if (do_block_optimization) {
4176 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4177 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4178 ELEM_REMOVE(le);
4179 }
4180 }
4181 return COMPILE_OK;
4182}
4183
4184#if OPT_INSTRUCTIONS_UNIFICATION
4185static INSN *
4186new_unified_insn(rb_iseq_t *iseq,
4187 int insn_id, int size, LINK_ELEMENT *seq_list)
4188{
4189 INSN *iobj = 0;
4190 LINK_ELEMENT *list = seq_list;
4191 int i, argc = 0;
4192 VALUE *operands = 0, *ptr = 0;
4193
4194
4195 /* count argc */
4196 for (i = 0; i < size; i++) {
4197 iobj = (INSN *)list;
4198 argc += iobj->operand_size;
4199 list = list->next;
4200 }
4201
4202 if (argc > 0) {
4203 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4204 }
4205
4206 /* copy operands */
4207 list = seq_list;
4208 for (i = 0; i < size; i++) {
4209 iobj = (INSN *)list;
4210 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4211 ptr += iobj->operand_size;
4212 list = list->next;
4213 }
4214
4215 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
4216 return new_insn_core(iseq, &dummy_line_node, insn_id, argc, operands);
4217}
4218#endif
4219
4220/*
4221 * This scheme can get more performance if do this optimize with
4222 * label address resolving.
4223 * It's future work (if compile time was bottle neck).
4224 */
4225static int
4226iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4227{
4228#if OPT_INSTRUCTIONS_UNIFICATION
4229 LINK_ELEMENT *list;
4230 INSN *iobj, *niobj;
4231 int id, k;
4232 intptr_t j;
4233
4234 list = FIRST_ELEMENT(anchor);
4235 while (list) {
4236 if (IS_INSN(list)) {
4237 iobj = (INSN *)list;
4238 id = iobj->insn_id;
4239 if (unified_insns_data[id] != 0) {
4240 const int *const *entry = unified_insns_data[id];
4241 for (j = 1; j < (intptr_t)entry[0]; j++) {
4242 const int *unified = entry[j];
4243 LINK_ELEMENT *li = list->next;
4244 for (k = 2; k < unified[1]; k++) {
4245 if (!IS_INSN(li) ||
4246 ((INSN *)li)->insn_id != unified[k]) {
4247 goto miss;
4248 }
4249 li = li->next;
4250 }
4251 /* matched */
4252 niobj =
4253 new_unified_insn(iseq, unified[0], unified[1] - 1,
4254 list);
4255
4256 /* insert to list */
4257 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4258 niobj->link.next = li;
4259 if (li) {
4260 li->prev = (LINK_ELEMENT *)niobj;
4261 }
4262
4263 list->prev->next = (LINK_ELEMENT *)niobj;
4264 list = (LINK_ELEMENT *)niobj;
4265 break;
4266 miss:;
4267 }
4268 }
4269 }
4270 list = list->next;
4271 }
4272#endif
4273 return COMPILE_OK;
4274}
4275
4276static int
4277all_string_result_p(const NODE *node)
4278{
4279 if (!node) return FALSE;
4280 switch (nd_type(node)) {
4281 case NODE_STR: case NODE_DSTR:
4282 return TRUE;
4283 case NODE_IF: case NODE_UNLESS:
4284 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4285 if (all_string_result_p(RNODE_IF(node)->nd_body))
4286 return all_string_result_p(RNODE_IF(node)->nd_else);
4287 return FALSE;
4288 case NODE_AND: case NODE_OR:
4289 if (!RNODE_AND(node)->nd_2nd)
4290 return all_string_result_p(RNODE_AND(node)->nd_1st);
4291 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4292 return FALSE;
4293 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4294 default:
4295 return FALSE;
4296 }
4297}
4298
4299static int
4300compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4301{
4302 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4303 VALUE lit = RNODE_DSTR(node)->nd_lit;
4304 LINK_ELEMENT *first_lit = 0;
4305 int cnt = 0;
4306
4307 debugp_param("nd_lit", lit);
4308 if (!NIL_P(lit)) {
4309 cnt++;
4310 if (!RB_TYPE_P(lit, T_STRING)) {
4311 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4312 rb_builtin_type_name(TYPE(lit)));
4313 return COMPILE_NG;
4314 }
4315 lit = rb_fstring(lit);
4316 ADD_INSN1(ret, node, putobject, lit);
4317 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4318 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4319 }
4320
4321 while (list) {
4322 const NODE *const head = list->nd_head;
4323 if (nd_type_p(head, NODE_STR)) {
4324 lit = rb_fstring(RNODE_STR(head)->nd_lit);
4325 ADD_INSN1(ret, head, putobject, lit);
4326 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4327 lit = Qnil;
4328 }
4329 else {
4330 CHECK(COMPILE(ret, "each string", head));
4331 }
4332 cnt++;
4333 list = (struct RNode_LIST *)list->nd_next;
4334 }
4335 if (NIL_P(lit) && first_lit) {
4336 ELEM_REMOVE(first_lit);
4337 --cnt;
4338 }
4339 *cntp = cnt;
4340
4341 return COMPILE_OK;
4342}
4343
4344static int
4345compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4346{
4347 while (node && nd_type_p(node, NODE_BLOCK)) {
4348 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4349 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4350 node = RNODE_BLOCK(node)->nd_next;
4351 }
4352 if (node) {
4353 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4354 }
4355 return COMPILE_OK;
4356}
4357
4358static int
4359compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4360{
4361 int cnt;
4362 if (!RNODE_DSTR(node)->nd_next) {
4363 VALUE lit = rb_fstring(RNODE_DSTR(node)->nd_lit);
4364 ADD_INSN1(ret, node, putstring, lit);
4365 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4366 }
4367 else {
4368 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4369 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4370 }
4371 return COMPILE_OK;
4372}
4373
4374static int
4375compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4376{
4377 int cnt;
4378
4379 if (!RNODE_DREGX(node)->nd_next) {
4380 VALUE match = RNODE_DREGX(node)->nd_lit;
4381 if (RB_TYPE_P(match, T_REGEXP)) {
4382 if (!popped) {
4383 ADD_INSN1(ret, node, putobject, match);
4384 RB_OBJ_WRITTEN(iseq, Qundef, match);
4385 }
4386 return COMPILE_OK;
4387 }
4388 }
4389
4390 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4391 ADD_INSN2(ret, node, toregexp, INT2FIX(RNODE_DREGX(node)->nd_cflag), INT2FIX(cnt));
4392
4393 if (popped) {
4394 ADD_INSN(ret, node, pop);
4395 }
4396
4397 return COMPILE_OK;
4398}
4399
4400static int
4401compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4402 LABEL *then_label, LABEL *else_label)
4403{
4404 const int line = nd_line(node);
4405 LABEL *lend = NEW_LABEL(line);
4406 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4407 + VM_SVAR_FLIPFLOP_START;
4408 VALUE key = INT2FIX(cnt);
4409
4410 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4411 ADD_INSNL(ret, node, branchif, lend);
4412
4413 /* *flip == 0 */
4414 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4415 ADD_INSNL(ret, node, branchunless, else_label);
4416 ADD_INSN1(ret, node, putobject, Qtrue);
4417 ADD_INSN1(ret, node, setspecial, key);
4418 if (!again) {
4419 ADD_INSNL(ret, node, jump, then_label);
4420 }
4421
4422 /* *flip == 1 */
4423 ADD_LABEL(ret, lend);
4424 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4425 ADD_INSNL(ret, node, branchunless, then_label);
4426 ADD_INSN1(ret, node, putobject, Qfalse);
4427 ADD_INSN1(ret, node, setspecial, key);
4428 ADD_INSNL(ret, node, jump, then_label);
4429
4430 return COMPILE_OK;
4431}
4432
4433static int
4434compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4435 LABEL *then_label, LABEL *else_label);
4436
4437#define COMPILE_SINGLE 2
4438static int
4439compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4440 LABEL *then_label, LABEL *else_label)
4441{
4442 DECL_ANCHOR(seq);
4443 INIT_ANCHOR(seq);
4444 LABEL *label = NEW_LABEL(nd_line(cond));
4445 if (!then_label) then_label = label;
4446 else if (!else_label) else_label = label;
4447
4448 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4449
4450 if (LIST_INSN_SIZE_ONE(seq)) {
4451 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4452 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4453 return COMPILE_OK;
4454 }
4455 if (!label->refcnt) {
4456 return COMPILE_SINGLE;
4457 }
4458 ADD_LABEL(seq, label);
4459 ADD_SEQ(ret, seq);
4460 return COMPILE_OK;
4461}
4462
4463static int
4464compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4465 LABEL *then_label, LABEL *else_label)
4466{
4467 int ok;
4468 DECL_ANCHOR(ignore);
4469
4470 again:
4471 switch (nd_type(cond)) {
4472 case NODE_AND:
4473 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4474 cond = RNODE_AND(cond)->nd_2nd;
4475 if (ok == COMPILE_SINGLE) {
4476 INIT_ANCHOR(ignore);
4477 ret = ignore;
4478 then_label = NEW_LABEL(nd_line(cond));
4479 }
4480 goto again;
4481 case NODE_OR:
4482 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4483 cond = RNODE_OR(cond)->nd_2nd;
4484 if (ok == COMPILE_SINGLE) {
4485 INIT_ANCHOR(ignore);
4486 ret = ignore;
4487 else_label = NEW_LABEL(nd_line(cond));
4488 }
4489 goto again;
4490 case NODE_LIT: /* NODE_LIT is always true */
4491 case NODE_TRUE:
4492 case NODE_STR:
4493 case NODE_ZLIST:
4494 case NODE_LAMBDA:
4495 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4496 ADD_INSNL(ret, cond, jump, then_label);
4497 return COMPILE_OK;
4498 case NODE_FALSE:
4499 case NODE_NIL:
4500 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4501 ADD_INSNL(ret, cond, jump, else_label);
4502 return COMPILE_OK;
4503 case NODE_LIST:
4504 case NODE_ARGSCAT:
4505 case NODE_DREGX:
4506 case NODE_DSTR:
4507 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4508 ADD_INSNL(ret, cond, jump, then_label);
4509 return COMPILE_OK;
4510 case NODE_FLIP2:
4511 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4512 return COMPILE_OK;
4513 case NODE_FLIP3:
4514 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4515 return COMPILE_OK;
4516 case NODE_DEFINED:
4517 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
4518 break;
4519 default:
4520 {
4521 DECL_ANCHOR(cond_seq);
4522 INIT_ANCHOR(cond_seq);
4523
4524 CHECK(COMPILE(cond_seq, "branch condition", cond));
4525
4526 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4527 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4528 if (insn->insn_id == BIN(putobject)) {
4529 if (RTEST(insn->operands[0])) {
4530 ADD_INSNL(ret, cond, jump, then_label);
4531 // maybe unreachable
4532 return COMPILE_OK;
4533 }
4534 else {
4535 ADD_INSNL(ret, cond, jump, else_label);
4536 return COMPILE_OK;
4537 }
4538 }
4539 }
4540 ADD_SEQ(ret, cond_seq);
4541 }
4542 break;
4543 }
4544
4545 ADD_INSNL(ret, cond, branchunless, else_label);
4546 ADD_INSNL(ret, cond, jump, then_label);
4547 return COMPILE_OK;
4548}
4549
4550#define HASH_BRACE 1
4551
4552static int
4553keyword_node_p(const NODE *const node)
4554{
4555 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4556}
4557
4558static int
4559compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4560 const NODE *const root_node,
4561 struct rb_callinfo_kwarg **const kw_arg_ptr,
4562 unsigned int *flag)
4563{
4564 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4565 RUBY_ASSERT(kw_arg_ptr != NULL);
4566 RUBY_ASSERT(flag != NULL);
4567
4568 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4569 const NODE *node = RNODE_HASH(root_node)->nd_head;
4570 int seen_nodes = 0;
4571
4572 while (node) {
4573 const NODE *key_node = RNODE_LIST(node)->nd_head;
4574 seen_nodes++;
4575
4576 assert(nd_type_p(node, NODE_LIST));
4577 if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(RNODE_LIT(key_node)->nd_lit)) {
4578 /* can be keywords */
4579 }
4580 else {
4581 if (flag) {
4582 *flag |= VM_CALL_KW_SPLAT;
4583 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4584 /* A new hash will be created for the keyword arguments
4585 * in this case, so mark the method as passing mutable
4586 * keyword splat.
4587 */
4588 *flag |= VM_CALL_KW_SPLAT_MUT;
4589 }
4590 }
4591 return FALSE;
4592 }
4593 node = RNODE_LIST(node)->nd_next; /* skip value node */
4594 node = RNODE_LIST(node)->nd_next;
4595 }
4596
4597 /* may be keywords */
4598 node = RNODE_HASH(root_node)->nd_head;
4599 {
4600 int len = (int)RNODE_LIST(node)->as.nd_alen / 2;
4601 struct rb_callinfo_kwarg *kw_arg =
4602 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4603 VALUE *keywords = kw_arg->keywords;
4604 int i = 0;
4605 kw_arg->references = 0;
4606 kw_arg->keyword_len = len;
4607
4608 *kw_arg_ptr = kw_arg;
4609
4610 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4611 const NODE *key_node = RNODE_LIST(node)->nd_head;
4612 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4613 keywords[i] = RNODE_LIT(key_node)->nd_lit;
4614 NO_CHECK(COMPILE(ret, "keyword values", val_node));
4615 }
4616 assert(i == len);
4617 return TRUE;
4618 }
4619 }
4620 return FALSE;
4621}
4622
4623static int
4624compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4625{
4626 int len = 0;
4627
4628 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4629 if (CPDEBUG > 0) {
4630 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4631 }
4632
4633 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4634 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4635 }
4636 else {
4637 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4638 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4639 }
4640 }
4641
4642 return len;
4643}
4644
4645static inline int
4646static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
4647{
4648 switch (nd_type(node)) {
4649 case NODE_LIT:
4650 case NODE_NIL:
4651 case NODE_TRUE:
4652 case NODE_FALSE:
4653 return TRUE;
4654 case NODE_STR:
4655 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
4656 default:
4657 return FALSE;
4658 }
4659}
4660
4661static inline VALUE
4662static_literal_value(const NODE *node, rb_iseq_t *iseq)
4663{
4664 switch (nd_type(node)) {
4665 case NODE_NIL:
4666 return Qnil;
4667 case NODE_TRUE:
4668 return Qtrue;
4669 case NODE_FALSE:
4670 return Qfalse;
4671 case NODE_STR:
4672 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4673 VALUE lit;
4674 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
4675 lit = rb_str_dup(RNODE_STR(node)->nd_lit);
4676 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
4677 return rb_str_freeze(lit);
4678 }
4679 else {
4680 return rb_fstring(RNODE_STR(node)->nd_lit);
4681 }
4682 default:
4683 return RNODE_LIT(node)->nd_lit;
4684 }
4685}
4686
4687static int
4688compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4689{
4690 const NODE *line_node = node;
4691
4692 if (nd_type_p(node, NODE_ZLIST)) {
4693 if (!popped) {
4694 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4695 }
4696 return 0;
4697 }
4698
4699 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4700
4701 if (popped) {
4702 for (; node; node = RNODE_LIST(node)->nd_next) {
4703 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
4704 }
4705 return 1;
4706 }
4707
4708 /* Compilation of an array literal.
4709 * The following code is essentially the same as:
4710 *
4711 * for (int count = 0; node; count++; node->nd_next) {
4712 * compile(node->nd_head);
4713 * }
4714 * ADD_INSN(newarray, count);
4715 *
4716 * However, there are three points.
4717 *
4718 * - The code above causes stack overflow for a big string literal.
4719 * The following limits the stack length up to max_stack_len.
4720 *
4721 * [x1,x2,...,x10000] =>
4722 * push x1 ; push x2 ; ...; push x256; newarray 256;
4723 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4724 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4725 * ...
4726 *
4727 * - Long subarray can be optimized by pre-allocating a hidden array.
4728 *
4729 * [1,2,3,...,100] =>
4730 * duparray [1,2,3,...,100]
4731 *
4732 * [x, 1,2,3,...,100, z] =>
4733 * push x; newarray 1;
4734 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4735 * push z; newarray 1; concatarray
4736 *
4737 * - If the last element is a keyword, newarraykwsplat should be emitted
4738 * to check and remove empty keyword arguments hash from array.
4739 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4740 *
4741 * [1,2,3,**kw] =>
4742 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4743 */
4744
4745 const int max_stack_len = 0x100;
4746 const int min_tmp_ary_len = 0x40;
4747 int stack_len = 0;
4748 int first_chunk = 1;
4749
4750 /* Convert pushed elements to an array, and concatarray if needed */
4751#define FLUSH_CHUNK(newarrayinsn) \
4752 if (stack_len) { \
4753 ADD_INSN1(ret, line_node, newarrayinsn, INT2FIX(stack_len)); \
4754 if (!first_chunk) ADD_INSN(ret, line_node, concatarray); \
4755 first_chunk = stack_len = 0; \
4756 }
4757
4758 while (node) {
4759 int count = 1;
4760
4761 /* pre-allocation check (this branch can be omittable) */
4762 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq)) {
4763 /* count the elements that are optimizable */
4764 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
4765 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq); node_tmp = RNODE_LIST(node_tmp)->nd_next)
4766 count++;
4767
4768 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4769 /* The literal contains only optimizable elements, or the subarray is long enough */
4770 VALUE ary = rb_ary_hidden_new(count);
4771
4772 /* Create a hidden array */
4773 for (; count; count--, node = RNODE_LIST(node)->nd_next)
4774 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
4775 OBJ_FREEZE(ary);
4776
4777 /* Emit optimized code */
4778 FLUSH_CHUNK(newarray);
4779 if (first_chunk) {
4780 ADD_INSN1(ret, line_node, duparray, ary);
4781 first_chunk = 0;
4782 }
4783 else {
4784 ADD_INSN1(ret, line_node, putobject, ary);
4785 ADD_INSN(ret, line_node, concatarray);
4786 }
4787 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4788 }
4789 }
4790
4791 /* Base case: Compile "count" elements */
4792 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
4793 if (CPDEBUG > 0) {
4794 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4795 }
4796
4797 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
4798 stack_len++;
4799
4800 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
4801 /* Reached the end, and the last element is a keyword */
4802 FLUSH_CHUNK(newarraykwsplat);
4803 return 1;
4804 }
4805
4806 /* If there are many pushed elements, flush them to avoid stack overflow */
4807 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4808 }
4809 }
4810
4811 FLUSH_CHUNK(newarray);
4812#undef FLUSH_CHUNK
4813 return 1;
4814}
4815
4816/* Compile an array containing the single element represented by node */
4817static int
4818compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
4819{
4820 if (static_literal_node_p(node, iseq)) {
4821 VALUE ary = rb_ary_hidden_new(1);
4822 rb_ary_push(ary, static_literal_value(node, iseq));
4823 OBJ_FREEZE(ary);
4824
4825 ADD_INSN1(ret, node, duparray, ary);
4826 }
4827 else {
4828 CHECK(COMPILE_(ret, "array element", node, FALSE));
4829 ADD_INSN1(ret, node, newarray, INT2FIX(1));
4830 }
4831
4832 return 1;
4833}
4834
4835static inline int
4836static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4837{
4838 return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
4839}
4840
4841static int
4842compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4843{
4844 const NODE *line_node = node;
4845
4846 node = RNODE_HASH(node)->nd_head;
4847
4848 if (!node || nd_type_p(node, NODE_ZLIST)) {
4849 if (!popped) {
4850 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4851 }
4852 return 0;
4853 }
4854
4855 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4856
4857 if (popped) {
4858 for (; node; node = RNODE_LIST(node)->nd_next) {
4859 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
4860 }
4861 return 1;
4862 }
4863
4864 /* Compilation of a hash literal (or keyword arguments).
4865 * This is very similar to compile_array, but there are some differences:
4866 *
4867 * - It contains key-value pairs. So we need to take every two elements.
4868 * We can assume that the length is always even.
4869 *
4870 * - Merging is done by a method call (id_core_hash_merge_ptr).
4871 * Sometimes we need to insert the receiver, so "anchor" is needed.
4872 * In addition, a method call is much slower than concatarray.
4873 * So it pays only when the subsequence is really long.
4874 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4875 *
4876 * - We need to handle keyword splat: **kw.
4877 * For **kw, the key part (node->nd_head) is NULL, and the value part
4878 * (node->nd_next->nd_head) is "kw".
4879 * The code is a bit difficult to avoid hash allocation for **{}.
4880 */
4881
4882 const int max_stack_len = 0x100;
4883 const int min_tmp_hash_len = 0x800;
4884 int stack_len = 0;
4885 int first_chunk = 1;
4886 DECL_ANCHOR(anchor);
4887 INIT_ANCHOR(anchor);
4888
4889 /* Convert pushed elements to a hash, and merge if needed */
4890#define FLUSH_CHUNK() \
4891 if (stack_len) { \
4892 if (first_chunk) { \
4893 APPEND_LIST(ret, anchor); \
4894 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4895 } \
4896 else { \
4897 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4898 ADD_INSN(ret, line_node, swap); \
4899 APPEND_LIST(ret, anchor); \
4900 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4901 } \
4902 INIT_ANCHOR(anchor); \
4903 first_chunk = stack_len = 0; \
4904 }
4905
4906 while (node) {
4907 int count = 1;
4908
4909 /* pre-allocation check (this branch can be omittable) */
4910 if (static_literal_node_pair_p(node, iseq)) {
4911 /* count the elements that are optimizable */
4912 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
4913 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
4914 count++;
4915
4916 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4917 /* The literal contains only optimizable elements, or the subsequence is long enough */
4918 VALUE ary = rb_ary_hidden_new(count);
4919
4920 /* Create a hidden hash */
4921 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4922 VALUE elem[2];
4923 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
4924 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
4925 rb_ary_cat(ary, elem, 2);
4926 }
4927 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4928 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
4929 hash = rb_obj_hide(hash);
4930 OBJ_FREEZE(hash);
4931
4932 /* Emit optimized code */
4933 FLUSH_CHUNK();
4934 if (first_chunk) {
4935 ADD_INSN1(ret, line_node, duphash, hash);
4936 first_chunk = 0;
4937 }
4938 else {
4939 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4940 ADD_INSN(ret, line_node, swap);
4941
4942 ADD_INSN1(ret, line_node, putobject, hash);
4943
4944 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4945 }
4946 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4947 }
4948 }
4949
4950 /* Base case: Compile "count" elements */
4951 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4952
4953 if (CPDEBUG > 0) {
4954 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4955 }
4956
4957 if (RNODE_LIST(node)->nd_head) {
4958 /* Normal key-value pair */
4959 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
4960 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
4961 stack_len += 2;
4962
4963 /* If there are many pushed elements, flush them to avoid stack overflow */
4964 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4965 }
4966 else {
4967 /* kwsplat case: foo(..., **kw, ...) */
4968 FLUSH_CHUNK();
4969
4970 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4971 int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(RNODE_LIT(kw)->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4972 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4973 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
4974 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4975
4976 if (empty_kw) {
4977 if (only_kw && method_call_keywords) {
4978 /* **{} appears at the only keyword argument in method call,
4979 * so it won't be modified.
4980 * kw is a special NODE_LIT that contains a special empty hash,
4981 * so this emits: putobject {}.
4982 * This is only done for method calls and not for literal hashes,
4983 * because literal hashes should always result in a new hash.
4984 */
4985 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4986 }
4987 else if (first_kw) {
4988 /* **{} appears as the first keyword argument, so it may be modified.
4989 * We need to create a fresh hash object.
4990 */
4991 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4992 }
4993 /* Any empty keyword splats that are not the first can be ignored.
4994 * since merging an empty hash into the existing hash is the same
4995 * as not merging it. */
4996 }
4997 else {
4998 if (only_kw && method_call_keywords) {
4999 /* **kw is only keyword argument in method call.
5000 * Use directly. This will be not be flagged as mutable.
5001 * This is only done for method calls and not for literal hashes,
5002 * because literal hashes should always result in a new hash.
5003 */
5004 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5005 }
5006 else {
5007 /* There is more than one keyword argument, or this is not a method
5008 * call. In that case, we need to add an empty hash (if first keyword),
5009 * or merge the hash to the accumulated hash (if not the first keyword).
5010 */
5011 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5012 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5013 else ADD_INSN(ret, line_node, swap);
5014
5015 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5016
5017 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5018 }
5019 }
5020
5021 first_chunk = 0;
5022 }
5023 }
5024 }
5025
5026 FLUSH_CHUNK();
5027#undef FLUSH_CHUNK
5028 return 1;
5029}
5030
5031VALUE
5032rb_node_case_when_optimizable_literal(const NODE *const node)
5033{
5034 switch (nd_type(node)) {
5035 case NODE_LIT: {
5036 VALUE v = RNODE_LIT(node)->nd_lit;
5037 double ival;
5038 if (RB_FLOAT_TYPE_P(v) &&
5039 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5040 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5041 }
5042 if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
5043 return Qundef;
5044 }
5045 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
5046 return v;
5047 }
5048 break;
5049 }
5050 case NODE_NIL:
5051 return Qnil;
5052 case NODE_TRUE:
5053 return Qtrue;
5054 case NODE_FALSE:
5055 return Qfalse;
5056 case NODE_STR:
5057 return rb_fstring(RNODE_STR(node)->nd_lit);
5058 }
5059 return Qundef;
5060}
5061
5062static int
5063when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5064 LABEL *l1, int only_special_literals, VALUE literals)
5065{
5066 while (vals) {
5067 const NODE *val = RNODE_LIST(vals)->nd_head;
5068 VALUE lit = rb_node_case_when_optimizable_literal(val);
5069
5070 if (UNDEF_P(lit)) {
5071 only_special_literals = 0;
5072 }
5073 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5074 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5075 }
5076
5077 if (nd_type_p(val, NODE_STR)) {
5078 debugp_param("nd_lit", RNODE_STR(val)->nd_lit);
5079 lit = rb_fstring(RNODE_STR(val)->nd_lit);
5080 ADD_INSN1(cond_seq, val, putobject, lit);
5081 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5082 }
5083 else {
5084 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5085 }
5086
5087 // Emit pattern === target
5088 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5089 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5090 ADD_INSNL(cond_seq, val, branchif, l1);
5091 vals = RNODE_LIST(vals)->nd_next;
5092 }
5093 return only_special_literals;
5094}
5095
5096static int
5097when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5098 LABEL *l1, int only_special_literals, VALUE literals)
5099{
5100 const NODE *line_node = vals;
5101
5102 switch (nd_type(vals)) {
5103 case NODE_LIST:
5104 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5105 return COMPILE_NG;
5106 break;
5107 case NODE_SPLAT:
5108 ADD_INSN (cond_seq, line_node, dup);
5109 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5110 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5111 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5112 ADD_INSNL(cond_seq, line_node, branchif, l1);
5113 break;
5114 case NODE_ARGSCAT:
5115 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5116 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5117 break;
5118 case NODE_ARGSPUSH:
5119 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5120 ADD_INSN (cond_seq, line_node, dup);
5121 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5122 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5123 ADD_INSNL(cond_seq, line_node, branchif, l1);
5124 break;
5125 default:
5126 ADD_INSN (cond_seq, line_node, dup);
5127 CHECK(COMPILE(cond_seq, "when val", vals));
5128 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5129 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5130 ADD_INSNL(cond_seq, line_node, branchif, l1);
5131 break;
5132 }
5133 return COMPILE_OK;
5134}
5135
5136/* Multiple Assignment Handling
5137 *
5138 * In order to handle evaluation of multiple assignment such that the left hand side
5139 * is evaluated before the right hand side, we need to process the left hand side
5140 * and see if there are any attributes that need to be assigned, or constants set
5141 * on explicit objects. If so, we add instructions to evaluate the receiver of
5142 * any assigned attributes or constants before we process the right hand side.
5143 *
5144 * For a multiple assignment such as:
5145 *
5146 * l1.m1, l2[0] = r3, r4
5147 *
5148 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5149 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5150 * On the VM stack, this looks like:
5151 *
5152 * self # putself
5153 * l1 # send
5154 * l1, self # putself
5155 * l1, l2 # send
5156 * l1, l2, 0 # putobject 0
5157 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5158 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5159 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5160 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5161 * l1, l2, 0, [r3, r4], r4, m1= # send
5162 * l1, l2, 0, [r3, r4], r4 # pop
5163 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5164 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5165 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5166 * l1, l2, 0, [r3, r4], r4, []= # send
5167 * l1, l2, 0, [r3, r4], r4 # pop
5168 * l1, l2, 0, [r3, r4] # pop
5169 * [r3, r4], l2, 0, [r3, r4] # setn 3
5170 * [r3, r4], l2, 0 # pop
5171 * [r3, r4], l2 # pop
5172 * [r3, r4] # pop
5173 *
5174 * This is made more complex when you have to handle splats, post args,
5175 * and arbitrary levels of nesting. You need to keep track of the total
5176 * number of attributes to set, and for each attribute, how many entries
5177 * are on the stack before the final attribute, in order to correctly
5178 * calculate the topn value to use to get the receiver of the attribute
5179 * setter method.
5180 *
5181 * A brief description of the VM stack for simple multiple assignment
5182 * with no splat (rhs_array will not be present if the return value of
5183 * the multiple assignment is not needed):
5184 *
5185 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5186 *
5187 * For multiple assignment with splats, while processing the part before
5188 * the splat (splat+post here is an array of the splat and the post arguments):
5189 *
5190 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5191 *
5192 * When processing the splat and post arguments:
5193 *
5194 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5195 *
5196 * When processing nested multiple assignment, existing values on the stack
5197 * are kept. So for:
5198 *
5199 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5200 *
5201 * The stack layout would be the following before processing the nested
5202 * multiple assignment:
5203 *
5204 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5205 *
5206 * In order to handle this correctly, we need to keep track of the nesting
5207 * level for each attribute assignment, as well as the attribute number
5208 * (left hand side attributes are processed left to right) and number of
5209 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5210 * this information.
5211 *
5212 * We also need to track information for the entire multiple assignment, such
5213 * as the total number of arguments, and the current nesting level, to
5214 * handle both nested multiple assignment as well as cases where the
5215 * rhs is not needed. We also need to keep track of all attribute
5216 * assignments in this, which we do using a linked listed. struct masgn_state
5217 * tracks this information.
5218 */
5219
5221 INSN *before_insn;
5222 struct masgn_lhs_node *next;
5223 const NODE *line_node;
5224 int argn;
5225 int num_args;
5226 int lhs_pos;
5227};
5228
5230 struct masgn_lhs_node *first_memo;
5231 struct masgn_lhs_node *last_memo;
5232 int lhs_level;
5233 int num_args;
5234 bool nested;
5235};
5236
5237static int
5238add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5239{
5240 if (!state) {
5241 rb_bug("no masgn_state");
5242 }
5243
5244 struct masgn_lhs_node *memo;
5245 memo = malloc(sizeof(struct masgn_lhs_node));
5246 if (!memo) {
5247 return COMPILE_NG;
5248 }
5249
5250 memo->before_insn = before_insn;
5251 memo->line_node = line_node;
5252 memo->argn = state->num_args + 1;
5253 memo->num_args = argc;
5254 state->num_args += argc;
5255 memo->lhs_pos = lhs_pos;
5256 memo->next = NULL;
5257 if (!state->first_memo) {
5258 state->first_memo = memo;
5259 }
5260 else {
5261 state->last_memo->next = memo;
5262 }
5263 state->last_memo = memo;
5264
5265 return COMPILE_OK;
5266}
5267
5268static int compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped);
5269
5270static int
5271compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int lhs_pos)
5272{
5273 switch (nd_type(node)) {
5274 case NODE_ATTRASGN: {
5275 INSN *iobj;
5276 const NODE *line_node = node;
5277
5278 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5279
5280 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5281 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5282 ASSUME(iobj);
5283 ELEM_REMOVE(LAST_ELEMENT(pre));
5284 ELEM_REMOVE((LINK_ELEMENT *)iobj);
5285 pre->last = iobj->link.prev;
5286
5287 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5288 int argc = vm_ci_argc(ci) + 1;
5289 ci = ci_argc_set(iseq, ci, argc);
5290 OPERAND_AT(iobj, 0) = (VALUE)ci;
5291 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5292
5293 if (argc == 1) {
5294 ADD_INSN(lhs, line_node, swap);
5295 }
5296 else {
5297 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5298 }
5299
5300 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5301 return COMPILE_NG;
5302 }
5303
5304 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5305 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5306 int argc = vm_ci_argc(ci);
5307 ci = ci_argc_set(iseq, ci, argc - 1);
5308 OPERAND_AT(iobj, 0) = (VALUE)ci;
5309 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5310 INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
5311 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
5312 }
5313 ADD_INSN(lhs, line_node, pop);
5314 if (argc != 1) {
5315 ADD_INSN(lhs, line_node, pop);
5316 }
5317 for (int i=0; i < argc; i++) {
5318 ADD_INSN(post, line_node, pop);
5319 }
5320 break;
5321 }
5322 case NODE_MASGN: {
5323 DECL_ANCHOR(nest_rhs);
5324 INIT_ANCHOR(nest_rhs);
5325 DECL_ANCHOR(nest_lhs);
5326 INIT_ANCHOR(nest_lhs);
5327
5328 int prev_level = state->lhs_level;
5329 bool prev_nested = state->nested;
5330 state->nested = 1;
5331 state->lhs_level = lhs_pos - 1;
5332 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5333 state->lhs_level = prev_level;
5334 state->nested = prev_nested;
5335
5336 ADD_SEQ(lhs, nest_rhs);
5337 ADD_SEQ(lhs, nest_lhs);
5338 break;
5339 }
5340 case NODE_CDECL:
5341 if (!RNODE_CDECL(node)->nd_vid) {
5342 /* Special handling only needed for expr::C, not for C */
5343 INSN *iobj;
5344
5345 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5346
5347 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5348 iobj = (INSN *)insn_element; /* setconstant insn */
5349 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5350 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5351 ELEM_REMOVE(insn_element);
5352 pre->last = iobj->link.prev;
5353 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5354
5355 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5356 return COMPILE_NG;
5357 }
5358
5359 ADD_INSN(post, node, pop);
5360 break;
5361 }
5362 /* Fallthrough */
5363 default: {
5364 DECL_ANCHOR(anchor);
5365 INIT_ANCHOR(anchor);
5366 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5367 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5368 ADD_SEQ(lhs, anchor);
5369 }
5370 }
5371
5372 return COMPILE_OK;
5373}
5374
5375static int
5376compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5377{
5378 if (lhsn) {
5379 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5380 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5381 }
5382 return COMPILE_OK;
5383}
5384
5385static int
5386compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5387 const NODE *rhsn, const NODE *orig_lhsn)
5388{
5389 VALUE mem[64];
5390 const int memsize = numberof(mem);
5391 int memindex = 0;
5392 int llen = 0, rlen = 0;
5393 int i;
5394 const NODE *lhsn = orig_lhsn;
5395
5396#define MEMORY(v) { \
5397 int i; \
5398 if (memindex == memsize) return 0; \
5399 for (i=0; i<memindex; i++) { \
5400 if (mem[i] == (v)) return 0; \
5401 } \
5402 mem[memindex++] = (v); \
5403}
5404
5405 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5406 return 0;
5407 }
5408
5409 while (lhsn) {
5410 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5411 switch (nd_type(ln)) {
5412 case NODE_LASGN:
5413 case NODE_DASGN:
5414 case NODE_IASGN:
5415 case NODE_CVASGN:
5416 MEMORY(get_nd_vid(ln));
5417 break;
5418 default:
5419 return 0;
5420 }
5421 lhsn = RNODE_LIST(lhsn)->nd_next;
5422 llen++;
5423 }
5424
5425 while (rhsn) {
5426 if (llen <= rlen) {
5427 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5428 }
5429 else {
5430 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5431 }
5432 rhsn = RNODE_LIST(rhsn)->nd_next;
5433 rlen++;
5434 }
5435
5436 if (llen > rlen) {
5437 for (i=0; i<llen-rlen; i++) {
5438 ADD_INSN(ret, orig_lhsn, putnil);
5439 }
5440 }
5441
5442 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5443 return 1;
5444}
5445
5446static int
5447compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped)
5448{
5449 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5450 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5451 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5452 const NODE *lhsn_count = lhsn;
5453 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5454
5455 int llen = 0;
5456 int lpos = 0;
5457
5458 while (lhsn_count) {
5459 llen++;
5460 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5461 }
5462 while (lhsn) {
5463 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5464 lpos++;
5465 lhsn = RNODE_LIST(lhsn)->nd_next;
5466 }
5467
5468 if (lhs_splat) {
5469 if (nd_type_p(splatn, NODE_POSTARG)) {
5470 /*a, b, *r, p1, p2 */
5471 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5472 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5473 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5474 int ppos = 0;
5475 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5476
5477 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5478
5479 if (NODE_NAMED_REST_P(restn)) {
5480 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5481 }
5482 while (postn) {
5483 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5484 ppos++;
5485 postn = RNODE_LIST(postn)->nd_next;
5486 }
5487 }
5488 else {
5489 /* a, b, *r */
5490 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5491 }
5492 }
5493
5494 if (!state->nested) {
5495 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5496 }
5497
5498 if (!popped) {
5499 ADD_INSN(rhs, node, dup);
5500 }
5501 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5502 return COMPILE_OK;
5503}
5504
5505static int
5506compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5507{
5508 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5509 struct masgn_state state;
5510 state.lhs_level = popped ? 0 : 1;
5511 state.nested = 0;
5512 state.num_args = 0;
5513 state.first_memo = NULL;
5514 state.last_memo = NULL;
5515
5516 DECL_ANCHOR(pre);
5517 INIT_ANCHOR(pre);
5518 DECL_ANCHOR(rhs);
5519 INIT_ANCHOR(rhs);
5520 DECL_ANCHOR(lhs);
5521 INIT_ANCHOR(lhs);
5522 DECL_ANCHOR(post);
5523 INIT_ANCHOR(post);
5524 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5525
5526 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5527 while (memo) {
5528 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5529 for (int i = 0; i < memo->num_args; i++) {
5530 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5531 }
5532 tmp_memo = memo->next;
5533 free(memo);
5534 memo = tmp_memo;
5535 }
5536 CHECK(ok);
5537
5538 ADD_SEQ(ret, pre);
5539 ADD_SEQ(ret, rhs);
5540 ADD_SEQ(ret, lhs);
5541 if (!popped && state.num_args >= 1) {
5542 /* make sure rhs array is returned before popping */
5543 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5544 }
5545 ADD_SEQ(ret, post);
5546 }
5547 return COMPILE_OK;
5548}
5549
5550static VALUE
5551collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5552{
5553 VALUE arr = rb_ary_new();
5554 for (;;) {
5555 switch (nd_type(node)) {
5556 case NODE_CONST:
5557 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5558 return arr;
5559 case NODE_COLON3:
5560 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5561 rb_ary_unshift(arr, ID2SYM(idNULL));
5562 return arr;
5563 case NODE_COLON2:
5564 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5565 node = RNODE_COLON2(node)->nd_head;
5566 break;
5567 default:
5568 return Qfalse;
5569 }
5570 }
5571}
5572
5573static int
5574compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5575 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5576{
5577 switch (nd_type(node)) {
5578 case NODE_CONST:
5579 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5580 ADD_INSN1(body, node, putobject, Qtrue);
5581 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5582 break;
5583 case NODE_COLON3:
5584 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5585 ADD_INSN(body, node, pop);
5586 ADD_INSN1(body, node, putobject, rb_cObject);
5587 ADD_INSN1(body, node, putobject, Qtrue);
5588 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5589 break;
5590 case NODE_COLON2:
5591 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5592 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5593 ADD_INSN1(body, node, putobject, Qfalse);
5594 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5595 break;
5596 default:
5597 CHECK(COMPILE(pref, "const colon2 prefix", node));
5598 break;
5599 }
5600 return COMPILE_OK;
5601}
5602
5603static int
5604compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5605{
5606 if (nd_type_p(cpath, NODE_COLON3)) {
5607 /* toplevel class ::Foo */
5608 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5609 return VM_DEFINECLASS_FLAG_SCOPED;
5610 }
5611 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5612 /* Bar::Foo */
5613 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5614 return VM_DEFINECLASS_FLAG_SCOPED;
5615 }
5616 else {
5617 /* class at cbase Foo */
5618 ADD_INSN1(ret, cpath, putspecialobject,
5619 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5620 return 0;
5621 }
5622}
5623
5624static inline int
5625private_recv_p(const NODE *node)
5626{
5627 NODE *recv = get_nd_recv(node);
5628 if (recv && nd_type_p(recv, NODE_SELF)) {
5629 return RNODE_SELF(recv)->nd_state != 0;
5630 }
5631 return 0;
5632}
5633
5634static void
5635defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5636 const NODE *const node, LABEL **lfinish, VALUE needstr);
5637
5638static int
5639compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver);
5640
5641static void
5642defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5643 const NODE *const node, LABEL **lfinish, VALUE needstr,
5644 bool keep_result)
5645{
5646 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5647 enum node_type type;
5648 const int line = nd_line(node);
5649 const NODE *line_node = node;
5650
5651 switch (type = nd_type(node)) {
5652
5653 /* easy literals */
5654 case NODE_NIL:
5655 expr_type = DEFINED_NIL;
5656 break;
5657 case NODE_SELF:
5658 expr_type = DEFINED_SELF;
5659 break;
5660 case NODE_TRUE:
5661 expr_type = DEFINED_TRUE;
5662 break;
5663 case NODE_FALSE:
5664 expr_type = DEFINED_FALSE;
5665 break;
5666
5667 case NODE_LIST:{
5668 const NODE *vals = node;
5669
5670 do {
5671 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
5672
5673 if (!lfinish[1]) {
5674 lfinish[1] = NEW_LABEL(line);
5675 }
5676 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5677 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
5678 }
5679 /* fall through */
5680 case NODE_STR:
5681 case NODE_LIT:
5682 case NODE_ZLIST:
5683 case NODE_AND:
5684 case NODE_OR:
5685 default:
5686 expr_type = DEFINED_EXPR;
5687 break;
5688
5689 /* variables */
5690 case NODE_LVAR:
5691 case NODE_DVAR:
5692 expr_type = DEFINED_LVAR;
5693 break;
5694
5695#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5696 case NODE_IVAR:
5697 ADD_INSN3(ret, line_node, definedivar,
5698 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
5699 return;
5700
5701 case NODE_GVAR:
5702 ADD_INSN(ret, line_node, putnil);
5703 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
5704 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
5705 return;
5706
5707 case NODE_CVAR:
5708 ADD_INSN(ret, line_node, putnil);
5709 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
5710 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
5711 return;
5712
5713 case NODE_CONST:
5714 ADD_INSN(ret, line_node, putnil);
5715 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
5716 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
5717 return;
5718 case NODE_COLON2:
5719 if (!lfinish[1]) {
5720 lfinish[1] = NEW_LABEL(line);
5721 }
5722 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
5723 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5724 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
5725
5726 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
5727 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
5728 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
5729 }
5730 else {
5731 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5732 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
5733 }
5734 return;
5735 case NODE_COLON3:
5736 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5737 ADD_INSN3(ret, line_node, defined,
5738 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
5739 return;
5740
5741 /* method dispatch */
5742 case NODE_CALL:
5743 case NODE_OPCALL:
5744 case NODE_VCALL:
5745 case NODE_FCALL:
5746 case NODE_ATTRASGN:{
5747 const int explicit_receiver =
5748 (type == NODE_CALL || type == NODE_OPCALL ||
5749 (type == NODE_ATTRASGN && !private_recv_p(node)));
5750
5751 if (get_nd_args(node) || explicit_receiver) {
5752 if (!lfinish[1]) {
5753 lfinish[1] = NEW_LABEL(line);
5754 }
5755 if (!lfinish[2]) {
5756 lfinish[2] = NEW_LABEL(line);
5757 }
5758 }
5759 if (get_nd_args(node)) {
5760 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
5761 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5762 }
5763 if (explicit_receiver) {
5764 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
5765 switch (nd_type(get_nd_recv(node))) {
5766 case NODE_CALL:
5767 case NODE_OPCALL:
5768 case NODE_VCALL:
5769 case NODE_FCALL:
5770 case NODE_ATTRASGN:
5771 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5772 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
5773 break;
5774 default:
5775 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5776 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
5777 break;
5778 }
5779 if (keep_result) {
5780 ADD_INSN(ret, line_node, dup);
5781 }
5782 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5783 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
5784 }
5785 else {
5786 ADD_INSN(ret, line_node, putself);
5787 if (keep_result) {
5788 ADD_INSN(ret, line_node, dup);
5789 }
5790 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
5791 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
5792 }
5793 return;
5794 }
5795
5796 case NODE_YIELD:
5797 ADD_INSN(ret, line_node, putnil);
5798 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
5799 PUSH_VAL(DEFINED_YIELD));
5800 return;
5801
5802 case NODE_BACK_REF:
5803 case NODE_NTH_REF:
5804 ADD_INSN(ret, line_node, putnil);
5805 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
5806 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
5807 PUSH_VAL(DEFINED_GVAR));
5808 return;
5809
5810 case NODE_SUPER:
5811 case NODE_ZSUPER:
5812 ADD_INSN(ret, line_node, putnil);
5813 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
5814 PUSH_VAL(DEFINED_ZSUPER));
5815 return;
5816
5817#undef PUSH_VAL
5818 case NODE_OP_ASGN1:
5819 case NODE_OP_ASGN2:
5820 case NODE_OP_ASGN_OR:
5821 case NODE_OP_ASGN_AND:
5822 case NODE_MASGN:
5823 case NODE_LASGN:
5824 case NODE_DASGN:
5825 case NODE_GASGN:
5826 case NODE_IASGN:
5827 case NODE_CDECL:
5828 case NODE_CVASGN:
5829 expr_type = DEFINED_ASGN;
5830 break;
5831 }
5832
5833 assert(expr_type != DEFINED_NOT_DEFINED);
5834
5835 if (needstr != Qfalse) {
5836 VALUE str = rb_iseq_defined_string(expr_type);
5837 ADD_INSN1(ret, line_node, putobject, str);
5838 }
5839 else {
5840 ADD_INSN1(ret, line_node, putobject, Qtrue);
5841 }
5842}
5843
5844static void
5845build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5846{
5847 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5848 ADD_INSN(ret, &dummy_line_node, putnil);
5849 iseq_set_exception_local_table(iseq);
5850}
5851
5852static void
5853defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5854 const NODE *const node, LABEL **lfinish, VALUE needstr)
5855{
5856 LINK_ELEMENT *lcur = ret->last;
5857 defined_expr0(iseq, ret, node, lfinish, needstr, false);
5858 if (lfinish[1]) {
5859 int line = nd_line(node);
5860 LABEL *lstart = NEW_LABEL(line);
5861 LABEL *lend = NEW_LABEL(line);
5862 const rb_iseq_t *rescue;
5864 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5865 rescue = new_child_iseq_with_callback(iseq, ifunc,
5866 rb_str_concat(rb_str_new2("defined guard in "),
5867 ISEQ_BODY(iseq)->location.label),
5868 iseq, ISEQ_TYPE_RESCUE, 0);
5869 lstart->rescued = LABEL_RESCUE_BEG;
5870 lend->rescued = LABEL_RESCUE_END;
5871 APPEND_LABEL(ret, lcur, lstart);
5872 ADD_LABEL(ret, lend);
5873 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5874 }
5875}
5876
5877static int
5878compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5879{
5880 const int line = nd_line(node);
5881 const NODE *line_node = node;
5882 if (!RNODE_DEFINED(node)->nd_head) {
5883 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5884 ADD_INSN1(ret, line_node, putobject, str);
5885 }
5886 else {
5887 LABEL *lfinish[3];
5888 LINK_ELEMENT *last = ret->last;
5889 lfinish[0] = NEW_LABEL(line);
5890 lfinish[1] = 0;
5891 lfinish[2] = 0;
5892 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr);
5893 if (lfinish[1]) {
5894 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5895 ADD_INSN(ret, line_node, swap);
5896 if (lfinish[2]) {
5897 ADD_LABEL(ret, lfinish[2]);
5898 }
5899 ADD_INSN(ret, line_node, pop);
5900 ADD_LABEL(ret, lfinish[1]);
5901 }
5902 ADD_LABEL(ret, lfinish[0]);
5903 }
5904 return COMPILE_OK;
5905}
5906
5907static VALUE
5908make_name_for_block(const rb_iseq_t *orig_iseq)
5909{
5910 int level = 1;
5911 const rb_iseq_t *iseq = orig_iseq;
5912
5913 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
5914 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
5915 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
5916 level++;
5917 }
5918 iseq = ISEQ_BODY(iseq)->parent_iseq;
5919 }
5920 }
5921
5922 if (level == 1) {
5923 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
5924 }
5925 else {
5926 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
5927 }
5928}
5929
5930static void
5931push_ensure_entry(rb_iseq_t *iseq,
5933 struct ensure_range *er, const void *const node)
5934{
5935 enl->ensure_node = node;
5936 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5937 enl->erange = er;
5938 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5939}
5940
5941static void
5942add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5943 LABEL *lstart, LABEL *lend)
5944{
5945 struct ensure_range *ne =
5946 compile_data_alloc(iseq, sizeof(struct ensure_range));
5947
5948 while (erange->next != 0) {
5949 erange = erange->next;
5950 }
5951 ne->next = 0;
5952 ne->begin = lend;
5953 ne->end = erange->end;
5954 erange->end = lstart;
5955
5956 erange->next = ne;
5957}
5958
5959static bool
5960can_add_ensure_iseq(const rb_iseq_t *iseq)
5961{
5963 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5964 while (e) {
5965 if (e->ensure_node) return false;
5966 e = e->prev;
5967 }
5968 }
5969 return true;
5970}
5971
5972static void
5973add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5974{
5975 assert(can_add_ensure_iseq(iseq));
5976
5978 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5979 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5980 DECL_ANCHOR(ensure);
5981
5982 INIT_ANCHOR(ensure);
5983 while (enlp) {
5984 if (enlp->erange != NULL) {
5985 DECL_ANCHOR(ensure_part);
5986 LABEL *lstart = NEW_LABEL(0);
5987 LABEL *lend = NEW_LABEL(0);
5988 INIT_ANCHOR(ensure_part);
5989
5990 add_ensure_range(iseq, enlp->erange, lstart, lend);
5991
5992 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5993 ADD_LABEL(ensure_part, lstart);
5994 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
5995 ADD_LABEL(ensure_part, lend);
5996 ADD_SEQ(ensure, ensure_part);
5997 }
5998 else {
5999 if (!is_return) {
6000 break;
6001 }
6002 }
6003 enlp = enlp->prev;
6004 }
6005 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6006 ADD_SEQ(ret, ensure);
6007}
6008
6009#if RUBY_DEBUG
6010static int
6011check_keyword(const NODE *node)
6012{
6013 /* This check is essentially a code clone of compile_keyword_arg. */
6014
6015 if (nd_type_p(node, NODE_LIST)) {
6016 while (RNODE_LIST(node)->nd_next) {
6017 node = RNODE_LIST(node)->nd_next;
6018 }
6019 node = RNODE_LIST(node)->nd_head;
6020 }
6021
6022 return keyword_node_p(node);
6023}
6024#endif
6025
6026static bool
6027keyword_node_single_splat_p(NODE *kwnode)
6028{
6029 RUBY_ASSERT(keyword_node_p(kwnode));
6030
6031 NODE *node = RNODE_HASH(kwnode)->nd_head;
6032 return RNODE_LIST(node)->nd_head == NULL &&
6033 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6034}
6035
6036static int
6037setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6038 int dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6039{
6040 if (!argn) return 0;
6041
6042 NODE *kwnode = NULL;
6043
6044 switch (nd_type(argn)) {
6045 case NODE_LIST: {
6046 // f(x, y, z)
6047 int len = compile_args(iseq, args, argn, &kwnode);
6048 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6049
6050 if (kwnode) {
6051 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6052 len -= 1;
6053 }
6054 else {
6055 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6056 }
6057 }
6058
6059 return len;
6060 }
6061 case NODE_SPLAT: {
6062 // f(*a)
6063 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6064 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
6065 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6066 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6067 return 1;
6068 }
6069 case NODE_ARGSCAT: {
6070 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6071 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, 1, NULL, NULL);
6072
6073 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6074 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6075 if (kwnode) rest_len--;
6076 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6077 }
6078 else {
6079 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6080 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6081 }
6082
6083 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6084 ADD_INSN1(args, argn, splatarray, Qtrue);
6085 argc += 1;
6086 }
6087 else {
6088 ADD_INSN1(args, argn, splatarray, Qfalse);
6089 ADD_INSN(args, argn, concatarray);
6090 }
6091
6092 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6093 if (kwnode) {
6094 // kwsplat
6095 *flag_ptr |= VM_CALL_KW_SPLAT;
6096 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6097 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6098 argc += 1;
6099 }
6100
6101 return argc;
6102 }
6103 case NODE_ARGSPUSH: {
6104 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6105 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, 1, NULL, NULL);
6106
6107 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6108 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6109 if (kwnode) rest_len--;
6110 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6111 ADD_INSN1(args, argn, newarray, INT2FIX(1));
6112 ADD_INSN(args, argn, concatarray);
6113 }
6114 else {
6115 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6116 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6117 }
6118 else {
6119 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6120 ADD_INSN1(args, argn, newarray, INT2FIX(1));
6121 ADD_INSN(args, argn, concatarray);
6122 }
6123 }
6124
6125 if (kwnode) {
6126 // f(*a, k:1)
6127 *flag_ptr |= VM_CALL_KW_SPLAT;
6128 if (!keyword_node_single_splat_p(kwnode)) {
6129 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6130 }
6131 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6132 argc += 1;
6133 }
6134
6135 return argc;
6136 }
6137 default: {
6138 UNKNOWN_NODE("setup_arg", argn, Qnil);
6139 }
6140 }
6141}
6142
6143static VALUE
6144setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6145 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6146{
6147 VALUE ret;
6148 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6149 unsigned int dup_rest = 1;
6150 DECL_ANCHOR(arg_block);
6151 INIT_ANCHOR(arg_block);
6152 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6153
6154 *flag |= VM_CALL_ARGS_BLOCKARG;
6155
6156 if (LIST_INSN_SIZE_ONE(arg_block)) {
6157 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6158 if (IS_INSN(elem)) {
6159 INSN *iobj = (INSN *)elem;
6160 if (iobj->insn_id == BIN(getblockparam)) {
6161 iobj->insn_id = BIN(getblockparamproxy);
6162 }
6163 dup_rest = 0;
6164 }
6165 }
6166 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, dup_rest, flag, keywords));
6167 ADD_SEQ(args, arg_block);
6168 }
6169 else {
6170 ret = INT2FIX(setup_args_core(iseq, args, argn, 0, flag, keywords));
6171 }
6172 return ret;
6173}
6174
6175static void
6176build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6177{
6178 const NODE *body = ptr;
6179 int line = nd_line(body);
6180 VALUE argc = INT2FIX(0);
6181 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6182
6183 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6184 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6185 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6186 iseq_set_local_table(iseq, 0);
6187}
6188
6189static void
6190compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6191{
6192 const NODE *vars;
6193 LINK_ELEMENT *last;
6194 int line = nd_line(node);
6195 const NODE *line_node = node;
6196 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6197
6198#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6199 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6200#else
6201 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6202#endif
6203 ADD_INSN(ret, line_node, dup);
6204 ADD_INSNL(ret, line_node, branchunless, fail_label);
6205
6206 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6207 INSN *cap;
6208 if (RNODE_BLOCK(vars)->nd_next) {
6209 ADD_INSN(ret, line_node, dup);
6210 }
6211 last = ret->last;
6212 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6213 last = last->next; /* putobject :var */
6214 cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
6215 NULL, INT2FIX(0), NULL);
6216 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6217#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6218 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6219 /* only one name */
6220 DECL_ANCHOR(nom);
6221
6222 INIT_ANCHOR(nom);
6223 ADD_INSNL(nom, line_node, jump, end_label);
6224 ADD_LABEL(nom, fail_label);
6225# if 0 /* $~ must be MatchData or nil */
6226 ADD_INSN(nom, line_node, pop);
6227 ADD_INSN(nom, line_node, putnil);
6228# endif
6229 ADD_LABEL(nom, end_label);
6230 (nom->last->next = cap->link.next)->prev = nom->last;
6231 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6232 return;
6233 }
6234#endif
6235 }
6236 ADD_INSNL(ret, line_node, jump, end_label);
6237 ADD_LABEL(ret, fail_label);
6238 ADD_INSN(ret, line_node, pop);
6239 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6240 last = ret->last;
6241 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6242 last = last->next; /* putobject :var */
6243 ((INSN*)last)->insn_id = BIN(putnil);
6244 ((INSN*)last)->operand_size = 0;
6245 }
6246 ADD_LABEL(ret, end_label);
6247}
6248
6249static int
6250optimizable_range_item_p(const NODE *n)
6251{
6252 if (!n) return FALSE;
6253 switch (nd_type(n)) {
6254 case NODE_LIT:
6255 return RB_INTEGER_TYPE_P(RNODE_LIT(n)->nd_lit);
6256 case NODE_NIL:
6257 return TRUE;
6258 default:
6259 return FALSE;
6260 }
6261}
6262
6263static int
6264compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6265{
6266 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6267 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6268
6269 const int line = nd_line(node);
6270 const NODE *line_node = node;
6271 DECL_ANCHOR(cond_seq);
6272 LABEL *then_label, *else_label, *end_label;
6273 VALUE branches = Qfalse;
6274
6275 INIT_ANCHOR(cond_seq);
6276 then_label = NEW_LABEL(line);
6277 else_label = NEW_LABEL(line);
6278 end_label = 0;
6279
6280 compile_branch_condition(iseq, cond_seq, RNODE_IF(node)->nd_cond, then_label, else_label);
6281 ADD_SEQ(ret, cond_seq);
6282
6283 if (then_label->refcnt && else_label->refcnt) {
6284 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
6285 }
6286
6287 if (then_label->refcnt) {
6288 ADD_LABEL(ret, then_label);
6289
6290 DECL_ANCHOR(then_seq);
6291 INIT_ANCHOR(then_seq);
6292 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6293
6294 if (else_label->refcnt) {
6295 add_trace_branch_coverage(
6296 iseq,
6297 ret,
6298 node_body ? node_body : node,
6299 0,
6300 type == NODE_IF ? "then" : "else",
6301 branches);
6302 end_label = NEW_LABEL(line);
6303 ADD_INSNL(then_seq, line_node, jump, end_label);
6304 if (!popped) {
6305 ADD_INSN(then_seq, line_node, pop);
6306 }
6307 }
6308 ADD_SEQ(ret, then_seq);
6309 }
6310
6311 if (else_label->refcnt) {
6312 ADD_LABEL(ret, else_label);
6313
6314 DECL_ANCHOR(else_seq);
6315 INIT_ANCHOR(else_seq);
6316 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6317
6318 if (then_label->refcnt) {
6319 add_trace_branch_coverage(
6320 iseq,
6321 ret,
6322 node_else ? node_else : node,
6323 1,
6324 type == NODE_IF ? "else" : "then",
6325 branches);
6326 }
6327 ADD_SEQ(ret, else_seq);
6328 }
6329
6330 if (end_label) {
6331 ADD_LABEL(ret, end_label);
6332 }
6333
6334 return COMPILE_OK;
6335}
6336
6337static int
6338compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6339{
6340 const NODE *vals;
6341 const NODE *node = orig_node;
6342 LABEL *endlabel, *elselabel;
6343 DECL_ANCHOR(head);
6344 DECL_ANCHOR(body_seq);
6345 DECL_ANCHOR(cond_seq);
6346 int only_special_literals = 1;
6347 VALUE literals = rb_hash_new();
6348 int line;
6349 enum node_type type;
6350 const NODE *line_node;
6351 VALUE branches = Qfalse;
6352 int branch_id = 0;
6353
6354 INIT_ANCHOR(head);
6355 INIT_ANCHOR(body_seq);
6356 INIT_ANCHOR(cond_seq);
6357
6358 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6359
6360 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6361
6362 branches = decl_branch_base(iseq, node, "case");
6363
6364 node = RNODE_CASE(node)->nd_body;
6365 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6366 type = nd_type(node);
6367 line = nd_line(node);
6368 line_node = node;
6369
6370 endlabel = NEW_LABEL(line);
6371 elselabel = NEW_LABEL(line);
6372
6373 ADD_SEQ(ret, head); /* case VAL */
6374
6375 while (type == NODE_WHEN) {
6376 LABEL *l1;
6377
6378 l1 = NEW_LABEL(line);
6379 ADD_LABEL(body_seq, l1);
6380 ADD_INSN(body_seq, line_node, pop);
6381 add_trace_branch_coverage(
6382 iseq,
6383 body_seq,
6384 RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
6385 branch_id++,
6386 "when",
6387 branches);
6388 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6389 ADD_INSNL(body_seq, line_node, jump, endlabel);
6390
6391 vals = RNODE_WHEN(node)->nd_head;
6392 if (vals) {
6393 switch (nd_type(vals)) {
6394 case NODE_LIST:
6395 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6396 if (only_special_literals < 0) return COMPILE_NG;
6397 break;
6398 case NODE_SPLAT:
6399 case NODE_ARGSCAT:
6400 case NODE_ARGSPUSH:
6401 only_special_literals = 0;
6402 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6403 break;
6404 default:
6405 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6406 }
6407 }
6408 else {
6409 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6410 }
6411
6412 node = RNODE_WHEN(node)->nd_next;
6413 if (!node) {
6414 break;
6415 }
6416 type = nd_type(node);
6417 line = nd_line(node);
6418 line_node = node;
6419 }
6420 /* else */
6421 if (node) {
6422 ADD_LABEL(cond_seq, elselabel);
6423 ADD_INSN(cond_seq, line_node, pop);
6424 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6425 CHECK(COMPILE_(cond_seq, "else", node, popped));
6426 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6427 }
6428 else {
6429 debugs("== else (implicit)\n");
6430 ADD_LABEL(cond_seq, elselabel);
6431 ADD_INSN(cond_seq, orig_node, pop);
6432 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6433 if (!popped) {
6434 ADD_INSN(cond_seq, orig_node, putnil);
6435 }
6436 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6437 }
6438
6439 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6440 ADD_INSN(ret, orig_node, dup);
6441 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6442 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6443 LABEL_REF(elselabel);
6444 }
6445
6446 ADD_SEQ(ret, cond_seq);
6447 ADD_SEQ(ret, body_seq);
6448 ADD_LABEL(ret, endlabel);
6449 return COMPILE_OK;
6450}
6451
6452static int
6453compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6454{
6455 const NODE *vals;
6456 const NODE *val;
6457 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6458 LABEL *endlabel;
6459 DECL_ANCHOR(body_seq);
6460 VALUE branches = Qfalse;
6461 int branch_id = 0;
6462
6463 branches = decl_branch_base(iseq, orig_node, "case");
6464
6465 INIT_ANCHOR(body_seq);
6466 endlabel = NEW_LABEL(nd_line(node));
6467
6468 while (node && nd_type_p(node, NODE_WHEN)) {
6469 const int line = nd_line(node);
6470 LABEL *l1 = NEW_LABEL(line);
6471 ADD_LABEL(body_seq, l1);
6472 add_trace_branch_coverage(
6473 iseq,
6474 body_seq,
6475 RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node,
6476 branch_id++,
6477 "when",
6478 branches);
6479 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
6480 ADD_INSNL(body_seq, node, jump, endlabel);
6481
6482 vals = RNODE_WHEN(node)->nd_head;
6483 if (!vals) {
6484 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
6485 }
6486 switch (nd_type(vals)) {
6487 case NODE_LIST:
6488 while (vals) {
6489 LABEL *lnext;
6490 val = RNODE_LIST(vals)->nd_head;
6491 lnext = NEW_LABEL(nd_line(val));
6492 debug_compile("== when2\n", (void)0);
6493 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
6494 ADD_LABEL(ret, lnext);
6495 vals = RNODE_LIST(vals)->nd_next;
6496 }
6497 break;
6498 case NODE_SPLAT:
6499 case NODE_ARGSCAT:
6500 case NODE_ARGSPUSH:
6501 ADD_INSN(ret, vals, putnil);
6502 CHECK(COMPILE(ret, "when2/cond splat", vals));
6503 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
6504 ADD_INSNL(ret, vals, branchif, l1);
6505 break;
6506 default:
6507 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
6508 }
6509 node = RNODE_WHEN(node)->nd_next;
6510 }
6511 /* else */
6512 add_trace_branch_coverage(
6513 iseq,
6514 ret,
6515 node ? node : orig_node,
6516 branch_id,
6517 "else",
6518 branches);
6519 CHECK(COMPILE_(ret, "else", node, popped));
6520 ADD_INSNL(ret, orig_node, jump, endlabel);
6521
6522 ADD_SEQ(ret, body_seq);
6523 ADD_LABEL(ret, endlabel);
6524 return COMPILE_OK;
6525}
6526
6527static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache);
6528
6529static int iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index);
6530static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache);
6531static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
6532static int iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index);
6533static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
6534
6535#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6536#define CASE3_BI_OFFSET_ERROR_STRING 1
6537#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6538#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6539#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6540
6541static int
6542iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
6543{
6544 const int line = nd_line(node);
6545 const NODE *line_node = node;
6546
6547 switch (nd_type(node)) {
6548 case NODE_ARYPTN: {
6549 /*
6550 * if pattern.use_rest_num?
6551 * rest_num = 0
6552 * end
6553 * if pattern.has_constant_node?
6554 * unless pattern.constant === obj
6555 * goto match_failed
6556 * end
6557 * end
6558 * unless obj.respond_to?(:deconstruct)
6559 * goto match_failed
6560 * end
6561 * d = obj.deconstruct
6562 * unless Array === d
6563 * goto type_error
6564 * end
6565 * min_argc = pattern.pre_args_num + pattern.post_args_num
6566 * if pattern.has_rest_arg?
6567 * unless d.length >= min_argc
6568 * goto match_failed
6569 * end
6570 * else
6571 * unless d.length == min_argc
6572 * goto match_failed
6573 * end
6574 * end
6575 * pattern.pre_args_num.each do |i|
6576 * unless pattern.pre_args[i].match?(d[i])
6577 * goto match_failed
6578 * end
6579 * end
6580 * if pattern.use_rest_num?
6581 * rest_num = d.length - min_argc
6582 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6583 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6584 * goto match_failed
6585 * end
6586 * end
6587 * end
6588 * pattern.post_args_num.each do |i|
6589 * j = pattern.pre_args_num + i
6590 * j += rest_num
6591 * unless pattern.post_args[i].match?(d[j])
6592 * goto match_failed
6593 * end
6594 * end
6595 * goto matched
6596 * type_error:
6597 * FrozenCore.raise TypeError
6598 * match_failed:
6599 * goto unmatched
6600 */
6601 const NODE *args = RNODE_ARYPTN(node)->pre_args;
6602 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
6603 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
6604
6605 const int min_argc = pre_args_num + post_args_num;
6606 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
6607 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
6608
6609 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6610 int i;
6611 match_failed = NEW_LABEL(line);
6612 type_error = NEW_LABEL(line);
6613 deconstruct = NEW_LABEL(line);
6614 deconstructed = NEW_LABEL(line);
6615
6616 if (use_rest_num) {
6617 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
6618 ADD_INSN(ret, line_node, swap);
6619 if (base_index) {
6620 base_index++;
6621 }
6622 }
6623
6624 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6625
6626 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6627
6628 ADD_INSN(ret, line_node, dup);
6629 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6630 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6631 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
6632 if (in_single_pattern) {
6633 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6634 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6635 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6636 INT2FIX(min_argc), base_index + 1 /* (1) */));
6637 }
6638 ADD_INSNL(ret, line_node, branchunless, match_failed);
6639
6640 for (i = 0; i < pre_args_num; i++) {
6641 ADD_INSN(ret, line_node, dup);
6642 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
6643 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
6644 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
6645 args = RNODE_LIST(args)->nd_next;
6646 }
6647
6648 if (RNODE_ARYPTN(node)->rest_arg) {
6649 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
6650 ADD_INSN(ret, line_node, dup);
6651 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
6652 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6653 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6654 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6655 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6656 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
6657 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
6658
6659 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
6660 }
6661 else {
6662 if (post_args_num > 0) {
6663 ADD_INSN(ret, line_node, dup);
6664 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6665 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6666 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6667 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
6668 ADD_INSN(ret, line_node, pop);
6669 }
6670 }
6671 }
6672
6673 args = RNODE_ARYPTN(node)->post_args;
6674 for (i = 0; i < post_args_num; i++) {
6675 ADD_INSN(ret, line_node, dup);
6676
6677 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
6678 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6679 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6680
6681 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
6682 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
6683 args = RNODE_LIST(args)->nd_next;
6684 }
6685
6686 ADD_INSN(ret, line_node, pop);
6687 if (use_rest_num) {
6688 ADD_INSN(ret, line_node, pop);
6689 }
6690 ADD_INSNL(ret, line_node, jump, matched);
6691 ADD_INSN(ret, line_node, putnil);
6692 if (use_rest_num) {
6693 ADD_INSN(ret, line_node, putnil);
6694 }
6695
6696 ADD_LABEL(ret, type_error);
6697 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6698 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6699 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6700 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6701 ADD_INSN(ret, line_node, pop);
6702
6703 ADD_LABEL(ret, match_failed);
6704 ADD_INSN(ret, line_node, pop);
6705 if (use_rest_num) {
6706 ADD_INSN(ret, line_node, pop);
6707 }
6708 ADD_INSNL(ret, line_node, jump, unmatched);
6709
6710 break;
6711 }
6712 case NODE_FNDPTN: {
6713 /*
6714 * if pattern.has_constant_node?
6715 * unless pattern.constant === obj
6716 * goto match_failed
6717 * end
6718 * end
6719 * unless obj.respond_to?(:deconstruct)
6720 * goto match_failed
6721 * end
6722 * d = obj.deconstruct
6723 * unless Array === d
6724 * goto type_error
6725 * end
6726 * unless d.length >= pattern.args_num
6727 * goto match_failed
6728 * end
6729 *
6730 * begin
6731 * len = d.length
6732 * limit = d.length - pattern.args_num
6733 * i = 0
6734 * while i <= limit
6735 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6736 * if pattern.has_pre_rest_arg_id
6737 * unless pattern.pre_rest_arg.match?(d[0, i])
6738 * goto find_failed
6739 * end
6740 * end
6741 * if pattern.has_post_rest_arg_id
6742 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6743 * goto find_failed
6744 * end
6745 * end
6746 * goto find_succeeded
6747 * end
6748 * i+=1
6749 * end
6750 * find_failed:
6751 * goto match_failed
6752 * find_succeeded:
6753 * end
6754 *
6755 * goto matched
6756 * type_error:
6757 * FrozenCore.raise TypeError
6758 * match_failed:
6759 * goto unmatched
6760 */
6761 const NODE *args = RNODE_FNDPTN(node)->args;
6762 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
6763
6764 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6765 match_failed = NEW_LABEL(line);
6766 type_error = NEW_LABEL(line);
6767 deconstruct = NEW_LABEL(line);
6768 deconstructed = NEW_LABEL(line);
6769
6770 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6771
6772 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6773
6774 ADD_INSN(ret, line_node, dup);
6775 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6776 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6777 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
6778 if (in_single_pattern) {
6779 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(args_num), base_index + 1 /* (1) */));
6780 }
6781 ADD_INSNL(ret, line_node, branchunless, match_failed);
6782
6783 {
6784 LABEL *while_begin = NEW_LABEL(nd_line(node));
6785 LABEL *next_loop = NEW_LABEL(nd_line(node));
6786 LABEL *find_succeeded = NEW_LABEL(line);
6787 LABEL *find_failed = NEW_LABEL(nd_line(node));
6788 int j;
6789
6790 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
6791 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
6792
6793 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
6794 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6795 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
6796
6797 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
6798
6799 ADD_LABEL(ret, while_begin);
6800
6801 ADD_INSN(ret, line_node, dup);
6802 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6803 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
6804 ADD_INSNL(ret, line_node, branchunless, find_failed);
6805
6806 for (j = 0; j < args_num; j++) {
6807 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6808 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6809 if (j != 0) {
6810 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
6811 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6812 }
6813 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
6814
6815 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
6816 args = RNODE_LIST(args)->nd_next;
6817 }
6818
6819 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
6820 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6821 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
6822 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6823 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
6824 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
6825 }
6826 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
6827 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6828 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6829 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6830 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6831 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6832 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
6833 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
6834 }
6835 ADD_INSNL(ret, line_node, jump, find_succeeded);
6836
6837 ADD_LABEL(ret, next_loop);
6838 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
6839 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6840 ADD_INSNL(ret, line_node, jump, while_begin);
6841
6842 ADD_LABEL(ret, find_failed);
6843 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6844 if (in_single_pattern) {
6845 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6846 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
6847 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6848 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
6849 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
6850
6851 ADD_INSN1(ret, line_node, putobject, Qfalse);
6852 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
6853
6854 ADD_INSN(ret, line_node, pop);
6855 ADD_INSN(ret, line_node, pop);
6856 }
6857 ADD_INSNL(ret, line_node, jump, match_failed);
6858 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
6859
6860 ADD_LABEL(ret, find_succeeded);
6861 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6862 }
6863
6864 ADD_INSN(ret, line_node, pop);
6865 ADD_INSNL(ret, line_node, jump, matched);
6866 ADD_INSN(ret, line_node, putnil);
6867
6868 ADD_LABEL(ret, type_error);
6869 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6870 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6871 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6872 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6873 ADD_INSN(ret, line_node, pop);
6874
6875 ADD_LABEL(ret, match_failed);
6876 ADD_INSN(ret, line_node, pop);
6877 ADD_INSNL(ret, line_node, jump, unmatched);
6878
6879 break;
6880 }
6881 case NODE_HSHPTN: {
6882 /*
6883 * keys = nil
6884 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6885 * keys = pattern.kw_args_node.keys
6886 * end
6887 * if pattern.has_constant_node?
6888 * unless pattern.constant === obj
6889 * goto match_failed
6890 * end
6891 * end
6892 * unless obj.respond_to?(:deconstruct_keys)
6893 * goto match_failed
6894 * end
6895 * d = obj.deconstruct_keys(keys)
6896 * unless Hash === d
6897 * goto type_error
6898 * end
6899 * if pattern.has_kw_rest_arg_node?
6900 * d = d.dup
6901 * end
6902 * if pattern.has_kw_args_node?
6903 * pattern.kw_args_node.each |k,|
6904 * unless d.key?(k)
6905 * goto match_failed
6906 * end
6907 * end
6908 * pattern.kw_args_node.each |k, pat|
6909 * if pattern.has_kw_rest_arg_node?
6910 * unless pat.match?(d.delete(k))
6911 * goto match_failed
6912 * end
6913 * else
6914 * unless pat.match?(d[k])
6915 * goto match_failed
6916 * end
6917 * end
6918 * end
6919 * else
6920 * unless d.empty?
6921 * goto match_failed
6922 * end
6923 * end
6924 * if pattern.has_kw_rest_arg_node?
6925 * if pattern.no_rest_keyword?
6926 * unless d.empty?
6927 * goto match_failed
6928 * end
6929 * else
6930 * unless pattern.kw_rest_arg_node.match?(d)
6931 * goto match_failed
6932 * end
6933 * end
6934 * end
6935 * goto matched
6936 * type_error:
6937 * FrozenCore.raise TypeError
6938 * match_failed:
6939 * goto unmatched
6940 */
6941 LABEL *match_failed, *type_error;
6942 VALUE keys = Qnil;
6943
6944 match_failed = NEW_LABEL(line);
6945 type_error = NEW_LABEL(line);
6946
6947 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
6948 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
6949 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
6950 while (kw_args) {
6951 rb_ary_push(keys, RNODE_LIT(RNODE_LIST(kw_args)->nd_head)->nd_lit);
6952 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
6953 }
6954 }
6955
6956 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6957
6958 ADD_INSN(ret, line_node, dup);
6959 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6960 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
6961 if (in_single_pattern) {
6962 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
6963 }
6964 ADD_INSNL(ret, line_node, branchunless, match_failed);
6965
6966 if (NIL_P(keys)) {
6967 ADD_INSN(ret, line_node, putnil);
6968 }
6969 else {
6970 ADD_INSN1(ret, line_node, duparray, keys);
6971 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6972 }
6973 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
6974
6975 ADD_INSN(ret, line_node, dup);
6976 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
6977 ADD_INSNL(ret, line_node, branchunless, type_error);
6978
6979 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
6980 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
6981 }
6982
6983 if (RNODE_HSHPTN(node)->nd_pkwargs) {
6984 int i;
6985 int keys_num;
6986 const NODE *args;
6987 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
6988 if (args) {
6989 DECL_ANCHOR(match_values);
6990 INIT_ANCHOR(match_values);
6991 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
6992 for (i = 0; i < keys_num; i++) {
6993 NODE *key_node = RNODE_LIST(args)->nd_head;
6994 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
6995 VALUE key;
6996
6997 if (!nd_type_p(key_node, NODE_LIT)) {
6998 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
6999 }
7000 key = RNODE_LIT(key_node)->nd_lit;
7001
7002 ADD_INSN(ret, line_node, dup);
7003 ADD_INSN1(ret, line_node, putobject, key);
7004 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7005 if (in_single_pattern) {
7006 LABEL *match_succeeded;
7007 match_succeeded = NEW_LABEL(line);
7008
7009 ADD_INSN(ret, line_node, dup);
7010 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7011
7012 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7013 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7014 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7015 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7016 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7017 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7018 ADD_INSN1(ret, line_node, putobject, key); // (7)
7019 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7020
7021 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7022
7023 ADD_LABEL(ret, match_succeeded);
7024 }
7025 ADD_INSNL(ret, line_node, branchunless, match_failed);
7026
7027 ADD_INSN(match_values, line_node, dup);
7028 ADD_INSN1(match_values, line_node, putobject, key);
7029 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7030 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7031 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7032 }
7033 ADD_SEQ(ret, match_values);
7034 }
7035 }
7036 else {
7037 ADD_INSN(ret, line_node, dup);
7038 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7039 if (in_single_pattern) {
7040 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7041 }
7042 ADD_INSNL(ret, line_node, branchunless, match_failed);
7043 }
7044
7045 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7046 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7047 ADD_INSN(ret, line_node, dup);
7048 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7049 if (in_single_pattern) {
7050 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7051 }
7052 ADD_INSNL(ret, line_node, branchunless, match_failed);
7053 }
7054 else {
7055 ADD_INSN(ret, line_node, dup); // (11)
7056 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
7057 }
7058 }
7059
7060 ADD_INSN(ret, line_node, pop);
7061 ADD_INSNL(ret, line_node, jump, matched);
7062 ADD_INSN(ret, line_node, putnil);
7063
7064 ADD_LABEL(ret, type_error);
7065 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7066 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7067 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7068 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7069 ADD_INSN(ret, line_node, pop);
7070
7071 ADD_LABEL(ret, match_failed);
7072 ADD_INSN(ret, line_node, pop);
7073 ADD_INSNL(ret, line_node, jump, unmatched);
7074 break;
7075 }
7076 case NODE_LIT:
7077 case NODE_STR:
7078 case NODE_XSTR:
7079 case NODE_DSTR:
7080 case NODE_DSYM:
7081 case NODE_DREGX:
7082 case NODE_LIST:
7083 case NODE_ZLIST:
7084 case NODE_LAMBDA:
7085 case NODE_DOT2:
7086 case NODE_DOT3:
7087 case NODE_CONST:
7088 case NODE_LVAR:
7089 case NODE_DVAR:
7090 case NODE_IVAR:
7091 case NODE_CVAR:
7092 case NODE_GVAR:
7093 case NODE_TRUE:
7094 case NODE_FALSE:
7095 case NODE_SELF:
7096 case NODE_NIL:
7097 case NODE_COLON2:
7098 case NODE_COLON3:
7099 case NODE_BEGIN:
7100 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7101 if (in_single_pattern) {
7102 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7103 }
7104 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7105 if (in_single_pattern) {
7106 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7107 }
7108 ADD_INSNL(ret, line_node, branchif, matched);
7109 ADD_INSNL(ret, line_node, jump, unmatched);
7110 break;
7111 case NODE_LASGN: {
7112 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7113 ID id = RNODE_LASGN(node)->nd_vid;
7114 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7115
7116 if (in_alt_pattern) {
7117 const char *name = rb_id2name(id);
7118 if (name && strlen(name) > 0 && name[0] != '_') {
7119 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7120 rb_id2str(id));
7121 return COMPILE_NG;
7122 }
7123 }
7124
7125 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7126 ADD_INSNL(ret, line_node, jump, matched);
7127 break;
7128 }
7129 case NODE_DASGN: {
7130 int idx, lv, ls;
7131 ID id = RNODE_DASGN(node)->nd_vid;
7132
7133 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7134
7135 if (in_alt_pattern) {
7136 const char *name = rb_id2name(id);
7137 if (name && strlen(name) > 0 && name[0] != '_') {
7138 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7139 rb_id2str(id));
7140 return COMPILE_NG;
7141 }
7142 }
7143
7144 if (idx < 0) {
7145 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7146 rb_id2str(id));
7147 return COMPILE_NG;
7148 }
7149 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7150 ADD_INSNL(ret, line_node, jump, matched);
7151 break;
7152 }
7153 case NODE_IF:
7154 case NODE_UNLESS: {
7155 LABEL *match_failed;
7156 match_failed = unmatched;
7157 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7158 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7159 if (in_single_pattern) {
7160 LABEL *match_succeeded;
7161 match_succeeded = NEW_LABEL(line);
7162
7163 ADD_INSN(ret, line_node, dup);
7164 if (nd_type_p(node, NODE_IF)) {
7165 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7166 }
7167 else {
7168 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7169 }
7170
7171 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7172 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7173 ADD_INSN1(ret, line_node, putobject, Qfalse);
7174 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7175
7176 ADD_INSN(ret, line_node, pop);
7177 ADD_INSN(ret, line_node, pop);
7178
7179 ADD_LABEL(ret, match_succeeded);
7180 }
7181 if (nd_type_p(node, NODE_IF)) {
7182 ADD_INSNL(ret, line_node, branchunless, match_failed);
7183 }
7184 else {
7185 ADD_INSNL(ret, line_node, branchif, match_failed);
7186 }
7187 ADD_INSNL(ret, line_node, jump, matched);
7188 break;
7189 }
7190 case NODE_HASH: {
7191 NODE *n;
7192 LABEL *match_failed;
7193 match_failed = NEW_LABEL(line);
7194
7195 n = RNODE_HASH(node)->nd_head;
7196 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7197 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7198 return COMPILE_NG;
7199 }
7200
7201 ADD_INSN(ret, line_node, dup); // (1)
7202 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));
7203 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));
7204 ADD_INSN(ret, line_node, putnil);
7205
7206 ADD_LABEL(ret, match_failed);
7207 ADD_INSN(ret, line_node, pop);
7208 ADD_INSNL(ret, line_node, jump, unmatched);
7209 break;
7210 }
7211 case NODE_OR: {
7212 LABEL *match_succeeded, *fin;
7213 match_succeeded = NEW_LABEL(line);
7214 fin = NEW_LABEL(line);
7215
7216 ADD_INSN(ret, line_node, dup); // (1)
7217 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));
7218 ADD_LABEL(ret, match_succeeded);
7219 ADD_INSN(ret, line_node, pop);
7220 ADD_INSNL(ret, line_node, jump, matched);
7221 ADD_INSN(ret, line_node, putnil);
7222 ADD_LABEL(ret, fin);
7223 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7224 break;
7225 }
7226 default:
7227 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7228 }
7229 return COMPILE_OK;
7230}
7231
7232static int
7233iseq_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)
7234{
7235 LABEL *fin = NEW_LABEL(nd_line(node));
7236 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7237 ADD_LABEL(ret, fin);
7238 return COMPILE_OK;
7239}
7240
7241static int
7242iseq_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)
7243{
7244 const NODE *line_node = node;
7245
7246 if (RNODE_ARYPTN(node)->nd_pconst) {
7247 ADD_INSN(ret, line_node, dup); // (1)
7248 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7249 if (in_single_pattern) {
7250 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7251 }
7252 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7253 if (in_single_pattern) {
7254 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7255 }
7256 ADD_INSNL(ret, line_node, branchunless, match_failed);
7257 }
7258 return COMPILE_OK;
7259}
7260
7261
7262static int
7263iseq_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)
7264{
7265 const NODE *line_node = node;
7266
7267 // NOTE: this optimization allows us to re-use the #deconstruct value
7268 // (or its absence).
7269 if (use_deconstructed_cache) {
7270 // If value is nil then we haven't tried to deconstruct
7271 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7272 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7273
7274 // If false then the value is not deconstructable
7275 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7276 ADD_INSNL(ret, line_node, branchunless, match_failed);
7277
7278 // Drop value, add deconstructed to the stack and jump
7279 ADD_INSN(ret, line_node, pop); // (1)
7280 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7281 ADD_INSNL(ret, line_node, jump, deconstructed);
7282 }
7283 else {
7284 ADD_INSNL(ret, line_node, jump, deconstruct);
7285 }
7286
7287 ADD_LABEL(ret, deconstruct);
7288 ADD_INSN(ret, line_node, dup);
7289 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7290 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7291
7292 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7293 if (use_deconstructed_cache) {
7294 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7295 }
7296
7297 if (in_single_pattern) {
7298 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7299 }
7300
7301 ADD_INSNL(ret, line_node, branchunless, match_failed);
7302
7303 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7304
7305 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7306 if (use_deconstructed_cache) {
7307 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7308 }
7309
7310 ADD_INSN(ret, line_node, dup);
7311 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7312 ADD_INSNL(ret, line_node, branchunless, type_error);
7313
7314 ADD_LABEL(ret, deconstructed);
7315
7316 return COMPILE_OK;
7317}
7318
7319static int
7320iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7321{
7322 /*
7323 * if match_succeeded?
7324 * goto match_succeeded
7325 * end
7326 * error_string = FrozenCore.sprintf(errmsg, matchee)
7327 * key_error_p = false
7328 * match_succeeded:
7329 */
7330 const int line = nd_line(node);
7331 const NODE *line_node = node;
7332 LABEL *match_succeeded = NEW_LABEL(line);
7333
7334 ADD_INSN(ret, line_node, dup);
7335 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7336
7337 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7338 ADD_INSN1(ret, line_node, putobject, errmsg);
7339 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7340 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7341 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7342
7343 ADD_INSN1(ret, line_node, putobject, Qfalse);
7344 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7345
7346 ADD_INSN(ret, line_node, pop);
7347 ADD_INSN(ret, line_node, pop);
7348 ADD_LABEL(ret, match_succeeded);
7349
7350 return COMPILE_OK;
7351}
7352
7353static int
7354iseq_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)
7355{
7356 /*
7357 * if match_succeeded?
7358 * goto match_succeeded
7359 * end
7360 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7361 * key_error_p = false
7362 * match_succeeded:
7363 */
7364 const int line = nd_line(node);
7365 const NODE *line_node = node;
7366 LABEL *match_succeeded = NEW_LABEL(line);
7367
7368 ADD_INSN(ret, line_node, dup);
7369 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7370
7371 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7372 ADD_INSN1(ret, line_node, putobject, errmsg);
7373 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7374 ADD_INSN(ret, line_node, dup);
7375 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7376 ADD_INSN1(ret, line_node, putobject, pattern_length);
7377 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7378 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7379
7380 ADD_INSN1(ret, line_node, putobject, Qfalse);
7381 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7382
7383 ADD_INSN(ret, line_node, pop);
7384 ADD_INSN(ret, line_node, pop);
7385 ADD_LABEL(ret, match_succeeded);
7386
7387 return COMPILE_OK;
7388}
7389
7390static int
7391iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7392{
7393 /*
7394 * if match_succeeded?
7395 * goto match_succeeded
7396 * end
7397 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7398 * key_error_p = false
7399 * match_succeeded:
7400 */
7401 const int line = nd_line(node);
7402 const NODE *line_node = node;
7403 LABEL *match_succeeded = NEW_LABEL(line);
7404
7405 ADD_INSN(ret, line_node, dup);
7406 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7407
7408 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7409 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7410 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7411 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7412 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7413 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7414
7415 ADD_INSN1(ret, line_node, putobject, Qfalse);
7416 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7417
7418 ADD_INSN(ret, line_node, pop);
7419 ADD_INSN(ret, line_node, pop);
7420
7421 ADD_LABEL(ret, match_succeeded);
7422 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7423 ADD_INSN(ret, line_node, pop);
7424 ADD_INSN(ret, line_node, pop);
7425
7426 return COMPILE_OK;
7427}
7428
7429static int
7430compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7431{
7432 const NODE *pattern;
7433 const NODE *node = orig_node;
7434 LABEL *endlabel, *elselabel;
7435 DECL_ANCHOR(head);
7436 DECL_ANCHOR(body_seq);
7437 DECL_ANCHOR(cond_seq);
7438 int line;
7439 enum node_type type;
7440 const NODE *line_node;
7441 VALUE branches = 0;
7442 int branch_id = 0;
7443 bool single_pattern;
7444
7445 INIT_ANCHOR(head);
7446 INIT_ANCHOR(body_seq);
7447 INIT_ANCHOR(cond_seq);
7448
7449 branches = decl_branch_base(iseq, node, "case");
7450
7451 node = RNODE_CASE3(node)->nd_body;
7452 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7453 type = nd_type(node);
7454 line = nd_line(node);
7455 line_node = node;
7456 single_pattern = !RNODE_IN(node)->nd_next;
7457
7458 endlabel = NEW_LABEL(line);
7459 elselabel = NEW_LABEL(line);
7460
7461 if (single_pattern) {
7462 /* allocate stack for ... */
7463 ADD_INSN(head, line_node, putnil); /* key_error_key */
7464 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7465 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7466 ADD_INSN(head, line_node, putnil); /* error_string */
7467 }
7468 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7469
7470 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
7471
7472 ADD_SEQ(ret, head); /* case VAL */
7473
7474 while (type == NODE_IN) {
7475 LABEL *l1;
7476
7477 if (branch_id) {
7478 ADD_INSN(body_seq, line_node, putnil);
7479 }
7480 l1 = NEW_LABEL(line);
7481 ADD_LABEL(body_seq, l1);
7482 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
7483 add_trace_branch_coverage(
7484 iseq,
7485 body_seq,
7486 RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node,
7487 branch_id++,
7488 "in",
7489 branches);
7490 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
7491 ADD_INSNL(body_seq, line_node, jump, endlabel);
7492
7493 pattern = RNODE_IN(node)->nd_head;
7494 if (pattern) {
7495 int pat_line = nd_line(pattern);
7496 LABEL *next_pat = NEW_LABEL(pat_line);
7497 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
7498 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7499 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
7500 ADD_LABEL(cond_seq, next_pat);
7501 LABEL_UNREMOVABLE(next_pat);
7502 }
7503 else {
7504 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7505 return COMPILE_NG;
7506 }
7507
7508 node = RNODE_IN(node)->nd_next;
7509 if (!node) {
7510 break;
7511 }
7512 type = nd_type(node);
7513 line = nd_line(node);
7514 line_node = node;
7515 }
7516 /* else */
7517 if (node) {
7518 ADD_LABEL(cond_seq, elselabel);
7519 ADD_INSN(cond_seq, line_node, pop);
7520 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
7521 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
7522 CHECK(COMPILE_(cond_seq, "else", node, popped));
7523 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7524 ADD_INSN(cond_seq, line_node, putnil);
7525 if (popped) {
7526 ADD_INSN(cond_seq, line_node, putnil);
7527 }
7528 }
7529 else {
7530 debugs("== else (implicit)\n");
7531 ADD_LABEL(cond_seq, elselabel);
7532 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
7533 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7534
7535 if (single_pattern) {
7536 /*
7537 * if key_error_p
7538 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7539 * else
7540 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7541 * end
7542 */
7543 LABEL *key_error, *fin;
7544 struct rb_callinfo_kwarg *kw_arg;
7545
7546 key_error = NEW_LABEL(line);
7547 fin = NEW_LABEL(line);
7548
7549 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
7550 kw_arg->references = 0;
7551 kw_arg->keyword_len = 2;
7552 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
7553 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
7554
7555 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7556 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7557 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7558 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7559 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7560 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7561 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7562 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7563 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7564 ADD_INSNL(cond_seq, orig_node, jump, fin);
7565
7566 ADD_LABEL(cond_seq, key_error);
7567 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7568 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7569 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7570 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7571 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7572 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7573 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7574 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7575 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
7576 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
7577
7578 ADD_LABEL(cond_seq, fin);
7579 }
7580 else {
7581 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7582 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
7583 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7584 }
7585 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
7586 if (!popped) {
7587 ADD_INSN(cond_seq, orig_node, putnil);
7588 }
7589 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7590 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
7591 if (popped) {
7592 ADD_INSN(cond_seq, line_node, putnil);
7593 }
7594 }
7595
7596 ADD_SEQ(ret, cond_seq);
7597 ADD_SEQ(ret, body_seq);
7598 ADD_LABEL(ret, endlabel);
7599 return COMPILE_OK;
7600}
7601
7602#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7603#undef CASE3_BI_OFFSET_ERROR_STRING
7604#undef CASE3_BI_OFFSET_KEY_ERROR_P
7605#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7606#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7607
7608static int
7609compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7610{
7611 const int line = (int)nd_line(node);
7612 const NODE *line_node = node;
7613
7614 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7615 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7616 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7617 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7618 VALUE branches = Qfalse;
7619
7621
7622 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
7623 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
7624 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
7625 LABEL *end_label = NEW_LABEL(line);
7626 LABEL *adjust_label = NEW_LABEL(line);
7627
7628 LABEL *next_catch_label = NEW_LABEL(line);
7629 LABEL *tmp_label = NULL;
7630
7631 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7632 push_ensure_entry(iseq, &enl, NULL, NULL);
7633
7634 if (RNODE_WHILE(node)->nd_state == 1) {
7635 ADD_INSNL(ret, line_node, jump, next_label);
7636 }
7637 else {
7638 tmp_label = NEW_LABEL(line);
7639 ADD_INSNL(ret, line_node, jump, tmp_label);
7640 }
7641 ADD_LABEL(ret, adjust_label);
7642 ADD_INSN(ret, line_node, putnil);
7643 ADD_LABEL(ret, next_catch_label);
7644 ADD_INSN(ret, line_node, pop);
7645 ADD_INSNL(ret, line_node, jump, next_label);
7646 if (tmp_label) ADD_LABEL(ret, tmp_label);
7647
7648 ADD_LABEL(ret, redo_label);
7649 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
7650 add_trace_branch_coverage(
7651 iseq,
7652 ret,
7653 RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node,
7654 0,
7655 "body",
7656 branches);
7657 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
7658 ADD_LABEL(ret, next_label); /* next */
7659
7660 if (type == NODE_WHILE) {
7661 compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
7662 redo_label, end_label);
7663 }
7664 else {
7665 /* until */
7666 compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
7667 end_label, redo_label);
7668 }
7669
7670 ADD_LABEL(ret, end_label);
7671 ADD_ADJUST_RESTORE(ret, adjust_label);
7672
7673 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
7674 /* ADD_INSN(ret, line_node, putundef); */
7675 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
7676 return COMPILE_NG;
7677 }
7678 else {
7679 ADD_INSN(ret, line_node, putnil);
7680 }
7681
7682 ADD_LABEL(ret, break_label); /* break */
7683
7684 if (popped) {
7685 ADD_INSN(ret, line_node, pop);
7686 }
7687
7688 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7689 break_label);
7690 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7691 next_catch_label);
7692 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7693 ISEQ_COMPILE_DATA(iseq)->redo_label);
7694
7695 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7696 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7697 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7698 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7699 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7700 return COMPILE_OK;
7701}
7702
7703static int
7704compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7705{
7706 const int line = nd_line(node);
7707 const NODE *line_node = node;
7708 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7709 LABEL *retry_label = NEW_LABEL(line);
7710 LABEL *retry_end_l = NEW_LABEL(line);
7711 const rb_iseq_t *child_iseq;
7712
7713 ADD_LABEL(ret, retry_label);
7714 if (nd_type_p(node, NODE_FOR)) {
7715 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
7716
7717 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7718 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
7719 ISEQ_TYPE_BLOCK, line);
7720 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
7721 }
7722 else {
7723 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7724 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
7725 ISEQ_TYPE_BLOCK, line);
7726 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
7727 }
7728
7729 {
7730 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7731 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7732 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7733 //
7734 // Normally, "send" instruction is at the last.
7735 // However, qcall under branch coverage measurement adds some instructions after the "send".
7736 //
7737 // Note that "invokesuper" appears instead of "send".
7738 INSN *iobj;
7739 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
7740 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
7741 while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
7742 iobj = (INSN*) get_prev_insn(iobj);
7743 }
7744 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
7745
7746 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7747 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7748 if (&iobj->link == LAST_ELEMENT(ret)) {
7749 ret->last = (LINK_ELEMENT*) retry_end_l;
7750 }
7751 }
7752
7753 if (popped) {
7754 ADD_INSN(ret, line_node, pop);
7755 }
7756
7757 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7758
7759 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7760 return COMPILE_OK;
7761}
7762
7763static int
7764compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7765{
7766 /* massign to var in "for"
7767 * (args.length == 1 && Array.try_convert(args[0])) || args
7768 */
7769 const NODE *line_node = node;
7770 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
7771 LABEL *not_single = NEW_LABEL(nd_line(var));
7772 LABEL *not_ary = NEW_LABEL(nd_line(var));
7773 CHECK(COMPILE(ret, "for var", var));
7774 ADD_INSN(ret, line_node, dup);
7775 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
7776 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7777 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
7778 ADD_INSNL(ret, line_node, branchunless, not_single);
7779 ADD_INSN(ret, line_node, dup);
7780 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7781 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
7782 ADD_INSN1(ret, line_node, putobject, rb_cArray);
7783 ADD_INSN(ret, line_node, swap);
7784 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
7785 ADD_INSN(ret, line_node, dup);
7786 ADD_INSNL(ret, line_node, branchunless, not_ary);
7787 ADD_INSN(ret, line_node, swap);
7788 ADD_LABEL(ret, not_ary);
7789 ADD_INSN(ret, line_node, pop);
7790 ADD_LABEL(ret, not_single);
7791 return COMPILE_OK;
7792}
7793
7794static int
7795compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7796{
7797 const NODE *line_node = node;
7798 unsigned long throw_flag = 0;
7799
7800 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7801 /* while/until */
7802 LABEL *splabel = NEW_LABEL(0);
7803 ADD_LABEL(ret, splabel);
7804 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7805 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
7806 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7807 add_ensure_iseq(ret, iseq, 0);
7808 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7809 ADD_ADJUST_RESTORE(ret, splabel);
7810
7811 if (!popped) {
7812 ADD_INSN(ret, line_node, putnil);
7813 }
7814 }
7815 else {
7816 const rb_iseq_t *ip = iseq;
7817
7818 while (ip) {
7819 if (!ISEQ_COMPILE_DATA(ip)) {
7820 ip = 0;
7821 break;
7822 }
7823
7824 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7825 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7826 }
7827 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7828 throw_flag = 0;
7829 }
7830 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7831 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
7832 return COMPILE_NG;
7833 }
7834 else {
7835 ip = ISEQ_BODY(ip)->parent_iseq;
7836 continue;
7837 }
7838
7839 /* escape from block */
7840 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
7841 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
7842 if (popped) {
7843 ADD_INSN(ret, line_node, pop);
7844 }
7845 return COMPILE_OK;
7846 }
7847 COMPILE_ERROR(ERROR_ARGS "Invalid break");
7848 return COMPILE_NG;
7849 }
7850 return COMPILE_OK;
7851}
7852
7853static int
7854compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7855{
7856 const NODE *line_node = node;
7857 unsigned long throw_flag = 0;
7858
7859 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7860 LABEL *splabel = NEW_LABEL(0);
7861 debugs("next in while loop\n");
7862 ADD_LABEL(ret, splabel);
7863 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
7864 add_ensure_iseq(ret, iseq, 0);
7865 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7866 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7867 ADD_ADJUST_RESTORE(ret, splabel);
7868 if (!popped) {
7869 ADD_INSN(ret, line_node, putnil);
7870 }
7871 }
7872 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7873 LABEL *splabel = NEW_LABEL(0);
7874 debugs("next in block\n");
7875 ADD_LABEL(ret, splabel);
7876 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7877 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
7878 add_ensure_iseq(ret, iseq, 0);
7879 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7880 ADD_ADJUST_RESTORE(ret, splabel);
7881 splabel->unremovable = FALSE;
7882
7883 if (!popped) {
7884 ADD_INSN(ret, line_node, putnil);
7885 }
7886 }
7887 else {
7888 const rb_iseq_t *ip = iseq;
7889
7890 while (ip) {
7891 if (!ISEQ_COMPILE_DATA(ip)) {
7892 ip = 0;
7893 break;
7894 }
7895
7896 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7897 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7898 /* while loop */
7899 break;
7900 }
7901 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7902 break;
7903 }
7904 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7905 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
7906 return COMPILE_NG;
7907 }
7908
7909 ip = ISEQ_BODY(ip)->parent_iseq;
7910 }
7911 if (ip != 0) {
7912 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
7913 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
7914
7915 if (popped) {
7916 ADD_INSN(ret, line_node, pop);
7917 }
7918 }
7919 else {
7920 COMPILE_ERROR(ERROR_ARGS "Invalid next");
7921 return COMPILE_NG;
7922 }
7923 }
7924 return COMPILE_OK;
7925}
7926
7927static int
7928compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7929{
7930 const NODE *line_node = node;
7931
7932 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7933 LABEL *splabel = NEW_LABEL(0);
7934 debugs("redo in while");
7935 ADD_LABEL(ret, splabel);
7936 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7937 add_ensure_iseq(ret, iseq, 0);
7938 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7939 ADD_ADJUST_RESTORE(ret, splabel);
7940 if (!popped) {
7941 ADD_INSN(ret, line_node, putnil);
7942 }
7943 }
7944 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7945 LABEL *splabel = NEW_LABEL(0);
7946
7947 debugs("redo in block");
7948 ADD_LABEL(ret, splabel);
7949 add_ensure_iseq(ret, iseq, 0);
7950 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7951 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7952 ADD_ADJUST_RESTORE(ret, splabel);
7953
7954 if (!popped) {
7955 ADD_INSN(ret, line_node, putnil);
7956 }
7957 }
7958 else {
7959 const rb_iseq_t *ip = iseq;
7960
7961 while (ip) {
7962 if (!ISEQ_COMPILE_DATA(ip)) {
7963 ip = 0;
7964 break;
7965 }
7966
7967 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7968 break;
7969 }
7970 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7971 break;
7972 }
7973 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7974 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
7975 return COMPILE_NG;
7976 }
7977
7978 ip = ISEQ_BODY(ip)->parent_iseq;
7979 }
7980 if (ip != 0) {
7981 ADD_INSN(ret, line_node, putnil);
7982 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7983
7984 if (popped) {
7985 ADD_INSN(ret, line_node, pop);
7986 }
7987 }
7988 else {
7989 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
7990 return COMPILE_NG;
7991 }
7992 }
7993 return COMPILE_OK;
7994}
7995
7996static int
7997compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7998{
7999 const NODE *line_node = node;
8000
8001 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8002 ADD_INSN(ret, line_node, putnil);
8003 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8004
8005 if (popped) {
8006 ADD_INSN(ret, line_node, pop);
8007 }
8008 }
8009 else {
8010 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8011 return COMPILE_NG;
8012 }
8013 return COMPILE_OK;
8014}
8015
8016static int
8017compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8018{
8019 const int line = nd_line(node);
8020 const NODE *line_node = node;
8021 LABEL *lstart = NEW_LABEL(line);
8022 LABEL *lend = NEW_LABEL(line);
8023 LABEL *lcont = NEW_LABEL(line);
8024 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8025 rb_str_concat(rb_str_new2("rescue in "),
8026 ISEQ_BODY(iseq)->location.label),
8027 ISEQ_TYPE_RESCUE, line);
8028
8029 lstart->rescued = LABEL_RESCUE_BEG;
8030 lend->rescued = LABEL_RESCUE_END;
8031 ADD_LABEL(ret, lstart);
8032
8033 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8034 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8035 {
8036 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8037 }
8038 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8039
8040 ADD_LABEL(ret, lend);
8041 if (RNODE_RESCUE(node)->nd_else) {
8042 ADD_INSN(ret, line_node, pop);
8043 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8044 }
8045 ADD_INSN(ret, line_node, nop);
8046 ADD_LABEL(ret, lcont);
8047
8048 if (popped) {
8049 ADD_INSN(ret, line_node, pop);
8050 }
8051
8052 /* register catch entry */
8053 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8054 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8055 return COMPILE_OK;
8056}
8057
8058static int
8059compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8060{
8061 const int line = nd_line(node);
8062 const NODE *line_node = node;
8063 const NODE *resq = node;
8064 const NODE *narg;
8065 LABEL *label_miss, *label_hit;
8066
8067 while (resq) {
8068 label_miss = NEW_LABEL(line);
8069 label_hit = NEW_LABEL(line);
8070
8071 narg = RNODE_RESBODY(resq)->nd_args;
8072 if (narg) {
8073 switch (nd_type(narg)) {
8074 case NODE_LIST:
8075 while (narg) {
8076 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8077 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8078 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8079 ADD_INSNL(ret, line_node, branchif, label_hit);
8080 narg = RNODE_LIST(narg)->nd_next;
8081 }
8082 break;
8083 case NODE_SPLAT:
8084 case NODE_ARGSCAT:
8085 case NODE_ARGSPUSH:
8086 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8087 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8088 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8089 ADD_INSNL(ret, line_node, branchif, label_hit);
8090 break;
8091 default:
8092 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8093 }
8094 }
8095 else {
8096 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8097 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8098 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8099 ADD_INSNL(ret, line_node, branchif, label_hit);
8100 }
8101 ADD_INSNL(ret, line_node, jump, label_miss);
8102 ADD_LABEL(ret, label_hit);
8103 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8104
8105 if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL) {
8106 // empty body
8107 int lineno = nd_line(RNODE_RESBODY(resq)->nd_body);
8108 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
8109 ADD_INSN(ret, &dummy_line_node, putnil);
8110 }
8111 else {
8112 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8113 }
8114
8115 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8116 ADD_INSN(ret, line_node, nop);
8117 }
8118 ADD_INSN(ret, line_node, leave);
8119 ADD_LABEL(ret, label_miss);
8120 resq = RNODE_RESBODY(resq)->nd_head;
8121 }
8122 return COMPILE_OK;
8123}
8124
8125static int
8126compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8127{
8128 const int line = nd_line(node);
8129 const NODE *line_node = node;
8130 DECL_ANCHOR(ensr);
8131 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8132 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8133 ISEQ_TYPE_ENSURE, line);
8134 LABEL *lstart = NEW_LABEL(line);
8135 LABEL *lend = NEW_LABEL(line);
8136 LABEL *lcont = NEW_LABEL(line);
8137 LINK_ELEMENT *last;
8138 int last_leave = 0;
8139 struct ensure_range er;
8141 struct ensure_range *erange;
8142
8143 INIT_ANCHOR(ensr);
8144 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8145 last = ensr->last;
8146 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8147
8148 er.begin = lstart;
8149 er.end = lend;
8150 er.next = 0;
8151 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8152
8153 ADD_LABEL(ret, lstart);
8154 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8155 ADD_LABEL(ret, lend);
8156 ADD_SEQ(ret, ensr);
8157 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8158 ADD_LABEL(ret, lcont);
8159 if (last_leave) ADD_INSN(ret, line_node, pop);
8160
8161 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8162 if (lstart->link.next != &lend->link) {
8163 while (erange) {
8164 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8165 ensure, lcont);
8166 erange = erange->next;
8167 }
8168 }
8169
8170 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8171 return COMPILE_OK;
8172}
8173
8174static int
8175compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8176{
8177 const NODE *line_node = node;
8178
8179 if (iseq) {
8180 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8181 const rb_iseq_t *is = iseq;
8182 enum rb_iseq_type t = type;
8183 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8184 LABEL *splabel = 0;
8185
8186 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8187 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8188 t = ISEQ_BODY(is)->type;
8189 }
8190 switch (t) {
8191 case ISEQ_TYPE_TOP:
8192 case ISEQ_TYPE_MAIN:
8193 if (retval) {
8194 rb_warn("argument of top-level return is ignored");
8195 }
8196 if (is == iseq) {
8197 /* plain top-level, leave directly */
8198 type = ISEQ_TYPE_METHOD;
8199 }
8200 break;
8201 default:
8202 break;
8203 }
8204
8205 if (type == ISEQ_TYPE_METHOD) {
8206 splabel = NEW_LABEL(0);
8207 ADD_LABEL(ret, splabel);
8208 ADD_ADJUST(ret, line_node, 0);
8209 }
8210
8211 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8212
8213 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8214 add_ensure_iseq(ret, iseq, 1);
8215 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8216 ADD_INSN(ret, line_node, leave);
8217 ADD_ADJUST_RESTORE(ret, splabel);
8218
8219 if (!popped) {
8220 ADD_INSN(ret, line_node, putnil);
8221 }
8222 }
8223 else {
8224 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8225 if (popped) {
8226 ADD_INSN(ret, line_node, pop);
8227 }
8228 }
8229 }
8230 return COMPILE_OK;
8231}
8232
8233static int
8234compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8235{
8236 CHECK(COMPILE_(ret, "nd_body", node, popped));
8237
8238 if (!popped && !all_string_result_p(node)) {
8239 const NODE *line_node = node;
8240 const unsigned int flag = VM_CALL_FCALL;
8241
8242 // Note, this dup could be removed if we are willing to change anytostring. It pops
8243 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8244 ADD_INSN(ret, line_node, dup);
8245 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8246 ADD_INSN(ret, line_node, anytostring);
8247 }
8248 return COMPILE_OK;
8249}
8250
8251static void
8252compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8253{
8254 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8255
8256 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8257 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8258}
8259
8260static LABEL *
8261qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8262{
8263 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8264 VALUE br = 0;
8265
8266 br = decl_branch_base(iseq, node, "&.");
8267 *branches = br;
8268 ADD_INSN(recv, line_node, dup);
8269 ADD_INSNL(recv, line_node, branchnil, else_label);
8270 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
8271 return else_label;
8272}
8273
8274static void
8275qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8276{
8277 LABEL *end_label;
8278 if (!else_label) return;
8279 end_label = NEW_LABEL(nd_line(line_node));
8280 ADD_INSNL(ret, line_node, jump, end_label);
8281 ADD_LABEL(ret, else_label);
8282 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
8283 ADD_LABEL(ret, end_label);
8284}
8285
8286static int
8287compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8288{
8289 /* optimization shortcut
8290 * "literal".freeze -> opt_str_freeze("literal")
8291 */
8292 if (get_nd_recv(node) && nd_type_p(get_nd_recv(node), NODE_STR) &&
8293 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8294 get_nd_args(node) == NULL &&
8295 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8296 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8297 VALUE str = rb_fstring(RNODE_STR(get_nd_recv(node))->nd_lit);
8298 if (get_node_call_nd_mid(node) == idUMinus) {
8299 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8300 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8301 }
8302 else {
8303 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8304 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8305 }
8306 RB_OBJ_WRITTEN(iseq, Qundef, str);
8307 if (popped) {
8308 ADD_INSN(ret, line_node, pop);
8309 }
8310 return TRUE;
8311 }
8312 /* optimization shortcut
8313 * obj["literal"] -> opt_aref_with(obj, "literal")
8314 */
8315 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8316 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8317 nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) &&
8318 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8319 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8320 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8321 VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(get_nd_args(node))->nd_head)->nd_lit);
8322 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8323 ADD_INSN2(ret, line_node, opt_aref_with, str,
8324 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8325 RB_OBJ_WRITTEN(iseq, Qundef, str);
8326 if (popped) {
8327 ADD_INSN(ret, line_node, pop);
8328 }
8329 return TRUE;
8330 }
8331 return FALSE;
8332}
8333
8334static int
8335iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8336{
8337 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8338}
8339
8340static const struct rb_builtin_function *
8341iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8342{
8343 int i;
8344 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8345 for (i=0; table[i].index != -1; i++) {
8346 if (strcmp(table[i].name, name) == 0) {
8347 return &table[i];
8348 }
8349 }
8350 return NULL;
8351}
8352
8353static const char *
8354iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8355{
8356 const char *name = rb_id2name(mid);
8357 static const char prefix[] = "__builtin_";
8358 const size_t prefix_len = sizeof(prefix) - 1;
8359
8360 switch (type) {
8361 case NODE_CALL:
8362 if (recv) {
8363 switch (nd_type(recv)) {
8364 case NODE_VCALL:
8365 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8366 return name;
8367 }
8368 break;
8369 case NODE_CONST:
8370 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8371 return name;
8372 }
8373 break;
8374 default: break;
8375 }
8376 }
8377 break;
8378 case NODE_VCALL:
8379 case NODE_FCALL:
8380 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8381 return &name[prefix_len];
8382 }
8383 break;
8384 default: break;
8385 }
8386 return NULL;
8387}
8388
8389static int
8390delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8391{
8392
8393 if (argc == 0) {
8394 *pstart_index = 0;
8395 return TRUE;
8396 }
8397 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8398 unsigned int start=0;
8399
8400 // local_table: [p1, p2, p3, l1, l2, l3]
8401 // arguments: [p3, l1, l2] -> 2
8402 for (start = 0;
8403 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8404 start++) {
8405 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8406
8407 for (unsigned int i=start; i-start<argc; i++) {
8408 if (IS_INSN(elem) &&
8409 INSN_OF(elem) == BIN(getlocal)) {
8410 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8411 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8412
8413 if (local_level == 0) {
8414 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8415 if (0) { // for debug
8416 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8417 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8418 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8419 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8420 }
8421 if (i == index) {
8422 elem = elem->next;
8423 continue; /* for */
8424 }
8425 else {
8426 goto next;
8427 }
8428 }
8429 else {
8430 goto fail; // level != 0 is unsupported
8431 }
8432 }
8433 else {
8434 goto fail; // insn is not a getlocal
8435 }
8436 }
8437 goto success;
8438 next:;
8439 }
8440 fail:
8441 return FALSE;
8442 success:
8443 *pstart_index = start;
8444 return TRUE;
8445 }
8446 else {
8447 return FALSE;
8448 }
8449}
8450
8451// Compile Primitive.attr! :leaf, ...
8452static int
8453compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
8454{
8455 VALUE symbol;
8456 VALUE string;
8457 if (!node) goto no_arg;
8458 while (node) {
8459 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8460 const NODE *next = RNODE_LIST(node)->nd_next;
8461
8462 node = RNODE_LIST(node)->nd_head;
8463 if (!node) goto no_arg;
8464 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8465
8466 symbol = RNODE_LIT(node)->nd_lit;
8467 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
8468
8469 string = rb_sym_to_s(symbol);
8470 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
8471 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
8472 }
8473 else if (strcmp(RSTRING_PTR(string), "no_gc") == 0) {
8474 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_NO_GC;
8475 }
8476 else {
8477 goto unknown_arg;
8478 }
8479 node = next;
8480 }
8481 return COMPILE_OK;
8482 no_arg:
8483 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
8484 return COMPILE_NG;
8485 non_symbol_arg:
8486 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
8487 return COMPILE_NG;
8488 unknown_arg:
8489 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
8490 return COMPILE_NG;
8491 bad_arg:
8492 UNKNOWN_NODE("attr!", node, COMPILE_NG);
8493}
8494
8495static int
8496compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
8497{
8498 if (!node) goto no_arg;
8499 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8500 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
8501 node = RNODE_LIST(node)->nd_head;
8502 if (!node) goto no_arg;
8503 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8504 VALUE name = RNODE_LIT(node)->nd_lit;
8505 if (!SYMBOL_P(name)) goto non_symbol_arg;
8506 if (!popped) {
8507 compile_lvar(iseq, ret, line_node, SYM2ID(name));
8508 }
8509 return COMPILE_OK;
8510 no_arg:
8511 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
8512 return COMPILE_NG;
8513 too_many_arg:
8514 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
8515 return COMPILE_NG;
8516 non_symbol_arg:
8517 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
8518 rb_builtin_class_name(name));
8519 return COMPILE_NG;
8520 bad_arg:
8521 UNKNOWN_NODE("arg!", node, COMPILE_NG);
8522}
8523
8524static NODE *
8525mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
8526{
8527 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
8528 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
8529 return RNODE_IF(node)->nd_body;
8530 }
8531 else {
8532 rb_bug("mandatory_node: can't find mandatory node");
8533 }
8534}
8535
8536static int
8537compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
8538{
8539 // arguments
8540 struct rb_args_info args = {
8541 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
8542 };
8543 rb_node_args_t args_node;
8544 rb_node_init(RNODE(&args_node), NODE_ARGS);
8545 args_node.nd_ainfo = args;
8546
8547 // local table without non-mandatory parameters
8548 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
8549 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
8550
8551 VALUE idtmp = 0;
8552 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
8553 tbl->size = table_size;
8554
8555 int i;
8556
8557 // lead parameters
8558 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
8559 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
8560 }
8561 // local variables
8562 for (; i<table_size; i++) {
8563 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
8564 }
8565
8566 rb_node_scope_t scope_node;
8567 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
8568 scope_node.nd_tbl = tbl;
8569 scope_node.nd_body = mandatory_node(iseq, node);
8570 scope_node.nd_args = &args_node;
8571
8572 rb_ast_body_t ast = {
8573 .root = RNODE(&scope_node),
8574 .frozen_string_literal = -1,
8575 .coverage_enabled = -1,
8576 .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
8577 };
8578
8579 ISEQ_BODY(iseq)->mandatory_only_iseq =
8580 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
8581 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
8582 nd_line(line_node), NULL, 0,
8583 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
8584
8585 ALLOCV_END(idtmp);
8586 return COMPILE_OK;
8587}
8588
8589static int
8590compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
8591 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
8592{
8593 NODE *args_node = get_nd_args(node);
8594
8595 if (parent_block != NULL) {
8596 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
8597 return COMPILE_NG;
8598 }
8599 else {
8600# define BUILTIN_INLINE_PREFIX "_bi"
8601 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
8602 bool cconst = false;
8603 retry:;
8604 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
8605
8606 if (bf == NULL) {
8607 if (strcmp("cstmt!", builtin_func) == 0 ||
8608 strcmp("cexpr!", builtin_func) == 0) {
8609 // ok
8610 }
8611 else if (strcmp("cconst!", builtin_func) == 0) {
8612 cconst = true;
8613 }
8614 else if (strcmp("cinit!", builtin_func) == 0) {
8615 // ignore
8616 GET_VM()->builtin_inline_index++;
8617 return COMPILE_OK;
8618 }
8619 else if (strcmp("attr!", builtin_func) == 0) {
8620 return compile_builtin_attr(iseq, args_node);
8621 }
8622 else if (strcmp("arg!", builtin_func) == 0) {
8623 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8624 }
8625 else if (strcmp("mandatory_only?", builtin_func) == 0) {
8626 if (popped) {
8627 rb_bug("mandatory_only? should be in if condition");
8628 }
8629 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8630 rb_bug("mandatory_only? should be put on top");
8631 }
8632
8633 ADD_INSN1(ret, line_node, putobject, Qfalse);
8634 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8635 }
8636 else if (1) {
8637 rb_bug("can't find builtin function:%s", builtin_func);
8638 }
8639 else {
8640 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
8641 return COMPILE_NG;
8642 }
8643
8644 if (GET_VM()->builtin_inline_index == INT_MAX) {
8645 rb_bug("builtin inline function index overflow:%s", builtin_func);
8646 }
8647 int inline_index = GET_VM()->builtin_inline_index++;
8648 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
8649 builtin_func = inline_func;
8650 args_node = NULL;
8651 goto retry;
8652 }
8653
8654 if (cconst) {
8655 typedef VALUE(*builtin_func0)(void *, VALUE);
8656 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
8657 ADD_INSN1(ret, line_node, putobject, const_val);
8658 return COMPILE_OK;
8659 }
8660
8661 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8662
8663 unsigned int flag = 0;
8664 struct rb_callinfo_kwarg *keywords = NULL;
8665 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8666
8667 if (FIX2INT(argc) != bf->argc) {
8668 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
8669 builtin_func, bf->argc, FIX2INT(argc));
8670 return COMPILE_NG;
8671 }
8672
8673 unsigned int start_index;
8674 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
8675 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
8676 }
8677 else {
8678 ADD_SEQ(ret, args);
8679 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8680 }
8681
8682 if (popped) ADD_INSN(ret, line_node, pop);
8683 return COMPILE_OK;
8684 }
8685}
8686
8687static int
8688compile_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)
8689{
8690 /* call: obj.method(...)
8691 * fcall: func(...)
8692 * vcall: func
8693 */
8694 DECL_ANCHOR(recv);
8695 DECL_ANCHOR(args);
8696 ID mid = get_node_call_nd_mid(node);
8697 VALUE argc;
8698 unsigned int flag = 0;
8699 struct rb_callinfo_kwarg *keywords = NULL;
8700 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8701 LABEL *else_label = NULL;
8702 VALUE branches = Qfalse;
8703
8704 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8705
8706 INIT_ANCHOR(recv);
8707 INIT_ANCHOR(args);
8708#if OPT_SUPPORT_JOKE
8709 if (nd_type_p(node, NODE_VCALL)) {
8710 ID id_bitblt;
8711 ID id_answer;
8712
8713 CONST_ID(id_bitblt, "bitblt");
8714 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
8715
8716 if (mid == id_bitblt) {
8717 ADD_INSN(ret, line_node, bitblt);
8718 return COMPILE_OK;
8719 }
8720 else if (mid == id_answer) {
8721 ADD_INSN(ret, line_node, answer);
8722 return COMPILE_OK;
8723 }
8724 }
8725 /* only joke */
8726 {
8727 ID goto_id;
8728 ID label_id;
8729
8730 CONST_ID(goto_id, "__goto__");
8731 CONST_ID(label_id, "__label__");
8732
8733 if (nd_type_p(node, NODE_FCALL) &&
8734 (mid == goto_id || mid == label_id)) {
8735 LABEL *label;
8736 st_data_t data;
8737 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8738 VALUE label_name;
8739
8740 if (!labels_table) {
8741 labels_table = st_init_numtable();
8742 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8743 }
8744 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8745 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8746
8747 label_name = node->nd_args->nd_head->nd_lit;
8748 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8749 label = NEW_LABEL(nd_line(line_node));
8750 label->position = nd_line(line_node);
8751 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8752 }
8753 else {
8754 label = (LABEL *)data;
8755 }
8756 }
8757 else {
8758 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
8759 return COMPILE_NG;
8760 }
8761
8762 if (mid == goto_id) {
8763 ADD_INSNL(ret, line_node, jump, label);
8764 }
8765 else {
8766 ADD_LABEL(ret, label);
8767 }
8768 return COMPILE_OK;
8769 }
8770 }
8771#endif
8772
8773 const char *builtin_func;
8774 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8775 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
8776 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8777 }
8778
8779 /* receiver */
8780 if (!assume_receiver) {
8781 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
8782 int idx, level;
8783
8784 if (mid == idCall &&
8785 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
8786 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
8787 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
8788 }
8789 else if (private_recv_p(node)) {
8790 ADD_INSN(recv, node, putself);
8791 flag |= VM_CALL_FCALL;
8792 }
8793 else {
8794 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
8795 }
8796
8797 if (type == NODE_QCALL) {
8798 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8799 }
8800 }
8801 else if (type == NODE_FCALL || type == NODE_VCALL) {
8802 ADD_CALL_RECEIVER(recv, line_node);
8803 }
8804 }
8805
8806 /* args */
8807 if (type != NODE_VCALL) {
8808 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
8809 CHECK(!NIL_P(argc));
8810 }
8811 else {
8812 argc = INT2FIX(0);
8813 }
8814
8815 ADD_SEQ(ret, recv);
8816 ADD_SEQ(ret, args);
8817
8818 debugp_param("call args argc", argc);
8819 debugp_param("call method", ID2SYM(mid));
8820
8821 switch ((int)type) {
8822 case NODE_VCALL:
8823 flag |= VM_CALL_VCALL;
8824 /* VCALL is funcall, so fall through */
8825 case NODE_FCALL:
8826 flag |= VM_CALL_FCALL;
8827 }
8828
8829 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
8830 ADD_INSN(ret, line_node, splatkw);
8831 }
8832 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
8833
8834 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8835 if (popped) {
8836 ADD_INSN(ret, line_node, pop);
8837 }
8838 return COMPILE_OK;
8839}
8840
8841static int
8842compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8843{
8844 const int line = nd_line(node);
8845 VALUE argc;
8846 unsigned int flag = 0;
8847 int asgnflag = 0;
8848 ID id = RNODE_OP_ASGN1(node)->nd_mid;
8849 int boff = 0;
8850 int keyword_len = 0;
8851 struct rb_callinfo_kwarg *keywords = NULL;
8852
8853 /*
8854 * a[x] (op)= y
8855 *
8856 * nil # nil
8857 * eval a # nil a
8858 * eval x # nil a x
8859 * dupn 2 # nil a x a x
8860 * send :[] # nil a x a[x]
8861 * eval y # nil a x a[x] y
8862 * send op # nil a x ret
8863 * setn 3 # ret a x ret
8864 * send []= # ret ?
8865 * pop # ret
8866 */
8867
8868 /*
8869 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
8870 * NODE_OP_ASGN nd_recv
8871 * nd_args->nd_head
8872 * nd_args->nd_body
8873 * nd_mid
8874 */
8875
8876 if (!popped) {
8877 ADD_INSN(ret, node, putnil);
8878 }
8879 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
8880 CHECK(asgnflag != -1);
8881 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
8882 case NODE_ZLIST:
8883 argc = INT2FIX(0);
8884 break;
8885 case NODE_BLOCK_PASS:
8886 boff = 1;
8887 /* fall through */
8888 default:
8889 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, &keywords);
8890 if (flag & VM_CALL_KW_SPLAT) {
8891 if (boff) {
8892 ADD_INSN(ret, node, splatkw);
8893 }
8894 else {
8895 /* Make sure to_hash is only called once and not twice */
8896 ADD_INSN(ret, node, dup);
8897 ADD_INSN(ret, node, splatkw);
8898 ADD_INSN(ret, node, pop);
8899 }
8900 }
8901 CHECK(!NIL_P(argc));
8902 }
8903 int dup_argn = FIX2INT(argc) + 1 + boff;
8904 if (keywords) {
8905 keyword_len = keywords->keyword_len;
8906 dup_argn += keyword_len;
8907 }
8908 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
8909 flag |= asgnflag;
8910 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_KW_SPLAT_MUT), keywords);
8911
8912 if (id == idOROP || id == idANDOP) {
8913 /* a[x] ||= y or a[x] &&= y
8914
8915 unless/if a[x]
8916 a[x]= y
8917 else
8918 nil
8919 end
8920 */
8921 LABEL *label = NEW_LABEL(line);
8922 LABEL *lfin = NEW_LABEL(line);
8923
8924 ADD_INSN(ret, node, dup);
8925 if (id == idOROP) {
8926 ADD_INSNL(ret, node, branchif, label);
8927 }
8928 else { /* idANDOP */
8929 ADD_INSNL(ret, node, branchunless, label);
8930 }
8931 ADD_INSN(ret, node, pop);
8932
8933 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
8934 if (!popped) {
8935 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8936 }
8937 if (flag & VM_CALL_ARGS_SPLAT) {
8938 if (flag & VM_CALL_KW_SPLAT) {
8939 ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
8940 ADD_INSN(ret, node, swap);
8941 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8942 ADD_INSN(ret, node, concatarray);
8943 ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
8944 ADD_INSN(ret, node, pop);
8945 }
8946 else {
8947 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8948 if (boff > 0) {
8949 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8950 ADD_INSN(ret, node, swap);
8951 ADD_INSN(ret, node, pop);
8952 }
8953 ADD_INSN(ret, node, concatarray);
8954 if (boff > 0) {
8955 ADD_INSN1(ret, node, setn, INT2FIX(3));
8956 ADD_INSN(ret, node, pop);
8957 ADD_INSN(ret, node, pop);
8958 }
8959 }
8960 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
8961 }
8962 else if (flag & VM_CALL_KW_SPLAT) {
8963 if (boff > 0) {
8964 ADD_INSN1(ret, node, topn, INT2FIX(2));
8965 ADD_INSN(ret, node, swap);
8966 ADD_INSN1(ret, node, setn, INT2FIX(3));
8967 ADD_INSN(ret, node, pop);
8968 }
8969 ADD_INSN(ret, node, swap);
8970 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8971 }
8972 else if (keyword_len) {
8973 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
8974 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+0));
8975 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8976 }
8977 else {
8978 if (boff > 0)
8979 ADD_INSN(ret, node, swap);
8980 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
8981 }
8982 ADD_INSN(ret, node, pop);
8983 ADD_INSNL(ret, node, jump, lfin);
8984 ADD_LABEL(ret, label);
8985 if (!popped) {
8986 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8987 }
8988 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
8989 ADD_LABEL(ret, lfin);
8990 }
8991 else {
8992 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
8993 ADD_SEND(ret, node, id, INT2FIX(1));
8994 if (!popped) {
8995 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
8996 }
8997 if (flag & VM_CALL_ARGS_SPLAT) {
8998 if (flag & VM_CALL_KW_SPLAT) {
8999 ADD_INSN1(ret, node, topn, INT2FIX(2 + boff));
9000 ADD_INSN(ret, node, swap);
9001 ADD_INSN1(ret, node, newarray, INT2FIX(1));
9002 ADD_INSN(ret, node, concatarray);
9003 ADD_INSN1(ret, node, setn, INT2FIX(2 + boff));
9004 ADD_INSN(ret, node, pop);
9005 }
9006 else {
9007 ADD_INSN1(ret, node, newarray, INT2FIX(1));
9008 if (boff > 0) {
9009 ADD_INSN1(ret, node, dupn, INT2FIX(3));
9010 ADD_INSN(ret, node, swap);
9011 ADD_INSN(ret, node, pop);
9012 }
9013 ADD_INSN(ret, node, concatarray);
9014 if (boff > 0) {
9015 ADD_INSN1(ret, node, setn, INT2FIX(3));
9016 ADD_INSN(ret, node, pop);
9017 ADD_INSN(ret, node, pop);
9018 }
9019 }
9020 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), keywords);
9021 }
9022 else if (flag & VM_CALL_KW_SPLAT) {
9023 if (boff > 0) {
9024 ADD_INSN1(ret, node, topn, INT2FIX(2));
9025 ADD_INSN(ret, node, swap);
9026 ADD_INSN1(ret, node, setn, INT2FIX(3));
9027 ADD_INSN(ret, node, pop);
9028 }
9029 ADD_INSN(ret, node, swap);
9030 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9031 }
9032 else if (keyword_len) {
9033 ADD_INSN(ret, node, dup);
9034 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+2));
9035 ADD_INSN1(ret, node, opt_reverse, INT2FIX(keyword_len+boff+1));
9036 ADD_INSN(ret, node, pop);
9037 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9038 }
9039 else {
9040 if (boff > 0)
9041 ADD_INSN(ret, node, swap);
9042 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), keywords);
9043 }
9044 ADD_INSN(ret, node, pop);
9045 }
9046 return COMPILE_OK;
9047}
9048
9049static int
9050compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9051{
9052 const int line = nd_line(node);
9053 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9054 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9055 int asgnflag;
9056 LABEL *lfin = NEW_LABEL(line);
9057 LABEL *lcfin = NEW_LABEL(line);
9058 LABEL *lskip = 0;
9059 /*
9060 class C; attr_accessor :c; end
9061 r = C.new
9062 r.a &&= v # asgn2
9063
9064 eval r # r
9065 dup # r r
9066 eval r.a # r o
9067
9068 # or
9069 dup # r o o
9070 if lcfin # r o
9071 pop # r
9072 eval v # r v
9073 swap # v r
9074 topn 1 # v r v
9075 send a= # v ?
9076 jump lfin # v ?
9077
9078 lcfin: # r o
9079 swap # o r
9080
9081 lfin: # o ?
9082 pop # o
9083
9084 # or (popped)
9085 if lcfin # r
9086 eval v # r v
9087 send a= # ?
9088 jump lfin # ?
9089
9090 lcfin: # r
9091
9092 lfin: # ?
9093 pop #
9094
9095 # and
9096 dup # r o o
9097 unless lcfin
9098 pop # r
9099 eval v # r v
9100 swap # v r
9101 topn 1 # v r v
9102 send a= # v ?
9103 jump lfin # v ?
9104
9105 # others
9106 eval v # r o v
9107 send ?? # r w
9108 send a= # w
9109
9110 */
9111
9112 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9113 CHECK(asgnflag != -1);
9114 if (RNODE_OP_ASGN2(node)->nd_aid) {
9115 lskip = NEW_LABEL(line);
9116 ADD_INSN(ret, node, dup);
9117 ADD_INSNL(ret, node, branchnil, lskip);
9118 }
9119 ADD_INSN(ret, node, dup);
9120 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9121
9122 if (atype == idOROP || atype == idANDOP) {
9123 if (!popped) {
9124 ADD_INSN(ret, node, dup);
9125 }
9126 if (atype == idOROP) {
9127 ADD_INSNL(ret, node, branchif, lcfin);
9128 }
9129 else { /* idANDOP */
9130 ADD_INSNL(ret, node, branchunless, lcfin);
9131 }
9132 if (!popped) {
9133 ADD_INSN(ret, node, pop);
9134 }
9135 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9136 if (!popped) {
9137 ADD_INSN(ret, node, swap);
9138 ADD_INSN1(ret, node, topn, INT2FIX(1));
9139 }
9140 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9141 ADD_INSNL(ret, node, jump, lfin);
9142
9143 ADD_LABEL(ret, lcfin);
9144 if (!popped) {
9145 ADD_INSN(ret, node, swap);
9146 }
9147
9148 ADD_LABEL(ret, lfin);
9149 }
9150 else {
9151 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9152 ADD_SEND(ret, node, atype, INT2FIX(1));
9153 if (!popped) {
9154 ADD_INSN(ret, node, swap);
9155 ADD_INSN1(ret, node, topn, INT2FIX(1));
9156 }
9157 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9158 }
9159 if (lskip && popped) {
9160 ADD_LABEL(ret, lskip);
9161 }
9162 ADD_INSN(ret, node, pop);
9163 if (lskip && !popped) {
9164 ADD_LABEL(ret, lskip);
9165 }
9166 return COMPILE_OK;
9167}
9168
9169static int
9170compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9171{
9172 const int line = nd_line(node);
9173 LABEL *lfin = 0;
9174 LABEL *lassign = 0;
9175 ID mid;
9176
9177 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9178 case NODE_COLON3:
9179 ADD_INSN1(ret, node, putobject, rb_cObject);
9180 break;
9181 case NODE_COLON2:
9182 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9183 break;
9184 default:
9185 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9186 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9187 return COMPILE_NG;
9188 }
9189 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9190 /* cref */
9191 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9192 lassign = NEW_LABEL(line);
9193 ADD_INSN(ret, node, dup); /* cref cref */
9194 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9195 ID2SYM(mid), Qtrue); /* cref bool */
9196 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9197 }
9198 ADD_INSN(ret, node, dup); /* cref cref */
9199 ADD_INSN1(ret, node, putobject, Qtrue);
9200 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9201
9202 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9203 lfin = NEW_LABEL(line);
9204 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9205 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9206 ADD_INSNL(ret, node, branchif, lfin);
9207 else /* idANDOP */
9208 ADD_INSNL(ret, node, branchunless, lfin);
9209 /* cref [obj] */
9210 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9211 if (lassign) ADD_LABEL(ret, lassign);
9212 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
9213 /* cref value */
9214 if (popped)
9215 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9216 else {
9217 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9218 ADD_INSN(ret, node, swap); /* cref value value cref */
9219 }
9220 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9221 ADD_LABEL(ret, lfin); /* cref [value] */
9222 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9223 ADD_INSN(ret, node, pop); /* [value] */
9224 }
9225 else {
9226 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
9227 /* cref obj value */
9228 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9229 /* cref value */
9230 ADD_INSN(ret, node, swap); /* value cref */
9231 if (!popped) {
9232 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9233 ADD_INSN(ret, node, swap); /* value value cref */
9234 }
9235 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9236 }
9237 return COMPILE_OK;
9238}
9239
9240static int
9241compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9242{
9243 const int line = nd_line(node);
9244 LABEL *lfin = NEW_LABEL(line);
9245 LABEL *lassign;
9246
9247 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9248 LABEL *lfinish[2];
9249 lfinish[0] = lfin;
9250 lfinish[1] = 0;
9251 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse);
9252 lassign = lfinish[1];
9253 if (!lassign) {
9254 lassign = NEW_LABEL(line);
9255 }
9256 ADD_INSNL(ret, node, branchunless, lassign);
9257 }
9258 else {
9259 lassign = NEW_LABEL(line);
9260 }
9261
9262 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9263
9264 if (!popped) {
9265 ADD_INSN(ret, node, dup);
9266 }
9267
9268 if (type == NODE_OP_ASGN_AND) {
9269 ADD_INSNL(ret, node, branchunless, lfin);
9270 }
9271 else {
9272 ADD_INSNL(ret, node, branchif, lfin);
9273 }
9274
9275 if (!popped) {
9276 ADD_INSN(ret, node, pop);
9277 }
9278
9279 ADD_LABEL(ret, lassign);
9280 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9281 ADD_LABEL(ret, lfin);
9282 return COMPILE_OK;
9283}
9284
9285static int
9286compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9287{
9288 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9289 DECL_ANCHOR(args);
9290 int argc;
9291 unsigned int flag = 0;
9292 struct rb_callinfo_kwarg *keywords = NULL;
9293 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9294
9295 INIT_ANCHOR(args);
9296 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9297 if (type == NODE_SUPER) {
9298 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9299 CHECK(!NIL_P(vargc));
9300 argc = FIX2INT(vargc);
9301 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9302 ADD_INSN(args, node, splatkw);
9303 }
9304 }
9305 else {
9306 /* NODE_ZSUPER */
9307 int i;
9308 const rb_iseq_t *liseq = body->local_iseq;
9309 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9310 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9311 int lvar_level = get_lvar_level(iseq);
9312
9313 argc = local_body->param.lead_num;
9314
9315 /* normal arguments */
9316 for (i = 0; i < local_body->param.lead_num; i++) {
9317 int idx = local_body->local_table_size - i;
9318 ADD_GETLOCAL(args, node, idx, lvar_level);
9319 }
9320
9321 if (local_body->param.flags.has_opt) {
9322 /* optional arguments */
9323 int j;
9324 for (j = 0; j < local_body->param.opt_num; j++) {
9325 int idx = local_body->local_table_size - (i + j);
9326 ADD_GETLOCAL(args, node, idx, lvar_level);
9327 }
9328 i += j;
9329 argc = i;
9330 }
9331 if (local_body->param.flags.has_rest) {
9332 /* rest argument */
9333 int idx = local_body->local_table_size - local_body->param.rest_start;
9334 ADD_GETLOCAL(args, node, idx, lvar_level);
9335 ADD_INSN1(args, node, splatarray, Qfalse);
9336
9337 argc = local_body->param.rest_start + 1;
9338 flag |= VM_CALL_ARGS_SPLAT;
9339 }
9340 if (local_body->param.flags.has_post) {
9341 /* post arguments */
9342 int post_len = local_body->param.post_num;
9343 int post_start = local_body->param.post_start;
9344
9345 if (local_body->param.flags.has_rest) {
9346 int j;
9347 for (j=0; j<post_len; j++) {
9348 int idx = local_body->local_table_size - (post_start + j);
9349 ADD_GETLOCAL(args, node, idx, lvar_level);
9350 }
9351 ADD_INSN1(args, node, newarray, INT2FIX(j));
9352 ADD_INSN (args, node, concatarray);
9353 /* argc is settled at above */
9354 }
9355 else {
9356 int j;
9357 for (j=0; j<post_len; j++) {
9358 int idx = local_body->local_table_size - (post_start + j);
9359 ADD_GETLOCAL(args, node, idx, lvar_level);
9360 }
9361 argc = post_len + post_start;
9362 }
9363 }
9364
9365 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9366 int local_size = local_body->local_table_size;
9367 argc++;
9368
9369 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9370
9371 if (local_body->param.flags.has_kwrest) {
9372 int idx = local_body->local_table_size - local_kwd->rest_start;
9373 ADD_GETLOCAL(args, node, idx, lvar_level);
9374 if (local_kwd->num > 0) {
9375 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9376 flag |= VM_CALL_KW_SPLAT_MUT;
9377 }
9378 }
9379 else {
9380 ADD_INSN1(args, node, newhash, INT2FIX(0));
9381 flag |= VM_CALL_KW_SPLAT_MUT;
9382 }
9383 for (i = 0; i < local_kwd->num; ++i) {
9384 ID id = local_kwd->table[i];
9385 int idx = local_size - get_local_var_idx(liseq, id);
9386 ADD_INSN1(args, node, putobject, ID2SYM(id));
9387 ADD_GETLOCAL(args, node, idx, lvar_level);
9388 }
9389 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9390 flag |= VM_CALL_KW_SPLAT;
9391 }
9392 else if (local_body->param.flags.has_kwrest) {
9393 int idx = local_body->local_table_size - local_kwd->rest_start;
9394 ADD_GETLOCAL(args, node, idx, lvar_level);
9395 argc++;
9396 flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
9397 }
9398 }
9399
9400 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9401 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9402 ADD_INSN(ret, node, putself);
9403 ADD_SEQ(ret, args);
9404 ADD_INSN2(ret, node, invokesuper,
9405 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9406 parent_block);
9407
9408 if (popped) {
9409 ADD_INSN(ret, node, pop);
9410 }
9411 return COMPILE_OK;
9412}
9413
9414static int
9415compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9416{
9417 DECL_ANCHOR(args);
9418 VALUE argc;
9419 unsigned int flag = 0;
9420 struct rb_callinfo_kwarg *keywords = NULL;
9421
9422 INIT_ANCHOR(args);
9423
9424 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9425 case ISEQ_TYPE_TOP:
9426 case ISEQ_TYPE_MAIN:
9427 case ISEQ_TYPE_CLASS:
9428 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9429 return COMPILE_NG;
9430 default: /* valid */;
9431 }
9432
9433 if (RNODE_YIELD(node)->nd_head) {
9434 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9435 CHECK(!NIL_P(argc));
9436 }
9437 else {
9438 argc = INT2FIX(0);
9439 }
9440
9441 ADD_SEQ(ret, args);
9442 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9443
9444 if (popped) {
9445 ADD_INSN(ret, node, pop);
9446 }
9447
9448 int level = 0;
9449 const rb_iseq_t *tmp_iseq = iseq;
9450 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9451 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9452 }
9453 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9454
9455 return COMPILE_OK;
9456}
9457
9458static int
9459compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9460{
9461 DECL_ANCHOR(recv);
9462 DECL_ANCHOR(val);
9463
9464 INIT_ANCHOR(recv);
9465 INIT_ANCHOR(val);
9466 switch ((int)type) {
9467 case NODE_MATCH:
9468 ADD_INSN1(recv, node, putobject, RNODE_MATCH(node)->nd_lit);
9469 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9470 INT2FIX(0));
9471 break;
9472 case NODE_MATCH2:
9473 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
9474 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
9475 break;
9476 case NODE_MATCH3:
9477 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
9478 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
9479 break;
9480 }
9481
9482 ADD_SEQ(ret, recv);
9483 ADD_SEQ(ret, val);
9484 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9485
9486 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
9487 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
9488 }
9489
9490 if (popped) {
9491 ADD_INSN(ret, node, pop);
9492 }
9493 return COMPILE_OK;
9494}
9495
9496static int
9497compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9498{
9499 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
9500 /* constant */
9501 VALUE segments;
9502 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
9503 (segments = collect_const_segments(iseq, node))) {
9504 ISEQ_BODY(iseq)->ic_size++;
9505 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9506 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9507 }
9508 else {
9509 /* constant */
9510 DECL_ANCHOR(pref);
9511 DECL_ANCHOR(body);
9512
9513 INIT_ANCHOR(pref);
9514 INIT_ANCHOR(body);
9515 CHECK(compile_const_prefix(iseq, node, pref, body));
9516 if (LIST_INSN_SIZE_ZERO(pref)) {
9517 ADD_INSN(ret, node, putnil);
9518 ADD_SEQ(ret, body);
9519 }
9520 else {
9521 ADD_SEQ(ret, pref);
9522 ADD_SEQ(ret, body);
9523 }
9524 }
9525 }
9526 else {
9527 /* function call */
9528 ADD_CALL_RECEIVER(ret, node);
9529 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
9530 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
9531 }
9532 if (popped) {
9533 ADD_INSN(ret, node, pop);
9534 }
9535 return COMPILE_OK;
9536}
9537
9538static int
9539compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9540{
9541 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
9542
9543 /* add cache insn */
9544 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9545 ISEQ_BODY(iseq)->ic_size++;
9546 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
9547 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9548 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9549 }
9550 else {
9551 ADD_INSN1(ret, node, putobject, rb_cObject);
9552 ADD_INSN1(ret, node, putobject, Qtrue);
9553 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
9554 }
9555
9556 if (popped) {
9557 ADD_INSN(ret, node, pop);
9558 }
9559 return COMPILE_OK;
9560}
9561
9562static int
9563compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
9564{
9565 VALUE flag = INT2FIX(excl);
9566 const NODE *b = RNODE_DOT2(node)->nd_beg;
9567 const NODE *e = RNODE_DOT2(node)->nd_end;
9568
9569 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
9570 if (!popped) {
9571 VALUE bv = nd_type_p(b, NODE_LIT) ? RNODE_LIT(b)->nd_lit : Qnil;
9572 VALUE ev = nd_type_p(e, NODE_LIT) ? RNODE_LIT(e)->nd_lit : Qnil;
9573 VALUE val = rb_range_new(bv, ev, excl);
9574 ADD_INSN1(ret, node, putobject, val);
9575 RB_OBJ_WRITTEN(iseq, Qundef, val);
9576 }
9577 }
9578 else {
9579 CHECK(COMPILE_(ret, "min", b, popped));
9580 CHECK(COMPILE_(ret, "max", e, popped));
9581 if (!popped) {
9582 ADD_INSN1(ret, node, newrange, flag);
9583 }
9584 }
9585 return COMPILE_OK;
9586}
9587
9588static int
9589compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9590{
9591 if (!popped) {
9592 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9593 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
9594 }
9595 else {
9596 const rb_iseq_t *ip = iseq;
9597 int level = 0;
9598 while (ip) {
9599 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
9600 break;
9601 }
9602 ip = ISEQ_BODY(ip)->parent_iseq;
9603 level++;
9604 }
9605 if (ip) {
9606 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
9607 }
9608 else {
9609 ADD_INSN(ret, node, putnil);
9610 }
9611 }
9612 }
9613 return COMPILE_OK;
9614}
9615
9616static int
9617compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9618{
9619 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9620 LABEL *end_label = NEW_LABEL(nd_line(node));
9621 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
9622
9623 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
9624 /* required argument. do nothing */
9625 COMPILE_ERROR(ERROR_ARGS "unreachable");
9626 return COMPILE_NG;
9627 }
9628 else if (nd_type_p(default_value, NODE_LIT) ||
9629 nd_type_p(default_value, NODE_NIL) ||
9630 nd_type_p(default_value, NODE_TRUE) ||
9631 nd_type_p(default_value, NODE_FALSE)) {
9632 COMPILE_ERROR(ERROR_ARGS "unreachable");
9633 return COMPILE_NG;
9634 }
9635 else {
9636 /* if keywordcheck(_kw_bits, nth_keyword)
9637 * kw = default_value
9638 * end
9639 */
9640 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
9641 int keyword_idx = body->param.keyword->num;
9642
9643 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
9644 ADD_INSNL(ret, node, branchif, end_label);
9645 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
9646 ADD_LABEL(ret, end_label);
9647 }
9648 return COMPILE_OK;
9649}
9650
9651static int
9652compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9653{
9654 DECL_ANCHOR(recv);
9655 DECL_ANCHOR(args);
9656 unsigned int flag = 0;
9657 ID mid = RNODE_ATTRASGN(node)->nd_mid;
9658 VALUE argc;
9659 LABEL *else_label = NULL;
9660 VALUE branches = Qfalse;
9661
9662 /* optimization shortcut
9663 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9664 */
9665 if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
9666 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
9667 nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) &&
9668 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9669 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
9670 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
9671 {
9672 VALUE str = rb_fstring(RNODE_STR(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head)->nd_lit);
9673 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
9674 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
9675 if (!popped) {
9676 ADD_INSN(ret, node, swap);
9677 ADD_INSN1(ret, node, topn, INT2FIX(1));
9678 }
9679 ADD_INSN2(ret, node, opt_aset_with, str,
9680 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9681 RB_OBJ_WRITTEN(iseq, Qundef, str);
9682 ADD_INSN(ret, node, pop);
9683 return COMPILE_OK;
9684 }
9685
9686 INIT_ANCHOR(recv);
9687 INIT_ANCHOR(args);
9688 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
9689 CHECK(!NIL_P(argc));
9690
9691 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
9692 CHECK(asgnflag != -1);
9693 flag |= (unsigned int)asgnflag;
9694
9695 debugp_param("argc", argc);
9696 debugp_param("nd_mid", ID2SYM(mid));
9697
9698 if (!rb_is_attrset_id(mid)) {
9699 /* safe nav attr */
9700 mid = rb_id_attrset(mid);
9701 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9702 }
9703 if (!popped) {
9704 ADD_INSN(ret, node, putnil);
9705 ADD_SEQ(ret, recv);
9706 ADD_SEQ(ret, args);
9707
9708 if (flag & VM_CALL_ARGS_BLOCKARG) {
9709 ADD_INSN1(ret, node, topn, INT2FIX(1));
9710 if (flag & VM_CALL_ARGS_SPLAT) {
9711 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9712 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9713 }
9714 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9715 ADD_INSN (ret, node, pop);
9716 }
9717 else if (flag & VM_CALL_ARGS_SPLAT) {
9718 ADD_INSN(ret, node, dup);
9719 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9720 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9721 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9722 ADD_INSN (ret, node, pop);
9723 }
9724 else {
9725 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9726 }
9727 }
9728 else {
9729 ADD_SEQ(ret, recv);
9730 ADD_SEQ(ret, args);
9731 }
9732 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
9733 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9734 ADD_INSN(ret, node, pop);
9735 return COMPILE_OK;
9736}
9737
9738static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
9746static int
9747iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
9748{
9749 if (node == 0) {
9750 if (!popped) {
9751 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9752 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
9753 debugs("node: NODE_NIL(implicit)\n");
9754 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9755 ADD_INSN(ret, &dummy_line_node, putnil);
9756 }
9757 return COMPILE_OK;
9758 }
9759 return iseq_compile_each0(iseq, ret, node, popped);
9760}
9761
9762static int
9763iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9764{
9765 const int line = (int)nd_line(node);
9766 const enum node_type type = nd_type(node);
9767 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9768
9769 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9770 /* ignore */
9771 }
9772 else {
9773 if (nd_fl_newline(node)) {
9774 int event = RUBY_EVENT_LINE;
9775 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9776 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9777 event |= RUBY_EVENT_COVERAGE_LINE;
9778 }
9779 ADD_TRACE(ret, event);
9780 }
9781 }
9782
9783 debug_node_start(node);
9784#undef BEFORE_RETURN
9785#define BEFORE_RETURN debug_node_end()
9786
9787 switch (type) {
9788 case NODE_BLOCK:
9789 CHECK(compile_block(iseq, ret, node, popped));
9790 break;
9791 case NODE_IF:
9792 case NODE_UNLESS:
9793 CHECK(compile_if(iseq, ret, node, popped, type));
9794 break;
9795 case NODE_CASE:
9796 CHECK(compile_case(iseq, ret, node, popped));
9797 break;
9798 case NODE_CASE2:
9799 CHECK(compile_case2(iseq, ret, node, popped));
9800 break;
9801 case NODE_CASE3:
9802 CHECK(compile_case3(iseq, ret, node, popped));
9803 break;
9804 case NODE_WHILE:
9805 case NODE_UNTIL:
9806 CHECK(compile_loop(iseq, ret, node, popped, type));
9807 break;
9808 case NODE_FOR:
9809 case NODE_ITER:
9810 CHECK(compile_iter(iseq, ret, node, popped));
9811 break;
9812 case NODE_FOR_MASGN:
9813 CHECK(compile_for_masgn(iseq, ret, node, popped));
9814 break;
9815 case NODE_BREAK:
9816 CHECK(compile_break(iseq, ret, node, popped));
9817 break;
9818 case NODE_NEXT:
9819 CHECK(compile_next(iseq, ret, node, popped));
9820 break;
9821 case NODE_REDO:
9822 CHECK(compile_redo(iseq, ret, node, popped));
9823 break;
9824 case NODE_RETRY:
9825 CHECK(compile_retry(iseq, ret, node, popped));
9826 break;
9827 case NODE_BEGIN:{
9828 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
9829 break;
9830 }
9831 case NODE_RESCUE:
9832 CHECK(compile_rescue(iseq, ret, node, popped));
9833 break;
9834 case NODE_RESBODY:
9835 CHECK(compile_resbody(iseq, ret, node, popped));
9836 break;
9837 case NODE_ENSURE:
9838 CHECK(compile_ensure(iseq, ret, node, popped));
9839 break;
9840
9841 case NODE_AND:
9842 case NODE_OR:{
9843 LABEL *end_label = NEW_LABEL(line);
9844 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
9845 if (!popped) {
9846 ADD_INSN(ret, node, dup);
9847 }
9848 if (type == NODE_AND) {
9849 ADD_INSNL(ret, node, branchunless, end_label);
9850 }
9851 else {
9852 ADD_INSNL(ret, node, branchif, end_label);
9853 }
9854 if (!popped) {
9855 ADD_INSN(ret, node, pop);
9856 }
9857 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
9858 ADD_LABEL(ret, end_label);
9859 break;
9860 }
9861
9862 case NODE_MASGN:{
9863 compile_massign(iseq, ret, node, popped);
9864 break;
9865 }
9866
9867 case NODE_LASGN:{
9868 ID id = RNODE_LASGN(node)->nd_vid;
9869 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9870
9871 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
9872 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
9873
9874 if (!popped) {
9875 ADD_INSN(ret, node, dup);
9876 }
9877 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9878 break;
9879 }
9880 case NODE_DASGN: {
9881 int idx, lv, ls;
9882 ID id = RNODE_DASGN(node)->nd_vid;
9883 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
9884 debugi("dassn id", rb_id2str(id) ? id : '*');
9885
9886 if (!popped) {
9887 ADD_INSN(ret, node, dup);
9888 }
9889
9890 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
9891
9892 if (idx < 0) {
9893 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
9894 rb_id2str(id));
9895 goto ng;
9896 }
9897 ADD_SETLOCAL(ret, node, ls - idx, lv);
9898 break;
9899 }
9900 case NODE_GASGN:{
9901 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
9902
9903 if (!popped) {
9904 ADD_INSN(ret, node, dup);
9905 }
9906 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
9907 break;
9908 }
9909 case NODE_IASGN:{
9910 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
9911 if (!popped) {
9912 ADD_INSN(ret, node, dup);
9913 }
9914 ADD_INSN2(ret, node, setinstancevariable,
9915 ID2SYM(RNODE_IASGN(node)->nd_vid),
9916 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
9917 break;
9918 }
9919 case NODE_CDECL:{
9920 if (RNODE_CDECL(node)->nd_vid) {
9921 CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
9922
9923 if (!popped) {
9924 ADD_INSN(ret, node, dup);
9925 }
9926
9927 ADD_INSN1(ret, node, putspecialobject,
9928 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9929 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
9930 }
9931 else {
9932 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
9933 CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
9934 ADD_INSN(ret, node, swap);
9935
9936 if (!popped) {
9937 ADD_INSN1(ret, node, topn, INT2FIX(1));
9938 ADD_INSN(ret, node, swap);
9939 }
9940
9941 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
9942 }
9943 break;
9944 }
9945 case NODE_CVASGN:{
9946 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
9947 if (!popped) {
9948 ADD_INSN(ret, node, dup);
9949 }
9950 ADD_INSN2(ret, node, setclassvariable,
9951 ID2SYM(RNODE_CVASGN(node)->nd_vid),
9952 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
9953 break;
9954 }
9955 case NODE_OP_ASGN1:
9956 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9957 break;
9958 case NODE_OP_ASGN2:
9959 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9960 break;
9961 case NODE_OP_CDECL:
9962 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9963 break;
9964 case NODE_OP_ASGN_AND:
9965 case NODE_OP_ASGN_OR:
9966 CHECK(compile_op_log(iseq, ret, node, popped, type));
9967 break;
9968 case NODE_CALL: /* obj.foo */
9969 case NODE_OPCALL: /* foo[] */
9970 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9971 break;
9972 }
9973 case NODE_QCALL: /* obj&.foo */
9974 case NODE_FCALL: /* foo() */
9975 case NODE_VCALL: /* foo (variable or call) */
9976 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
9977 goto ng;
9978 }
9979 break;
9980 case NODE_SUPER:
9981 case NODE_ZSUPER:
9982 CHECK(compile_super(iseq, ret, node, popped, type));
9983 break;
9984 case NODE_LIST:{
9985 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9986 break;
9987 }
9988 case NODE_ZLIST:{
9989 if (!popped) {
9990 ADD_INSN1(ret, node, newarray, INT2FIX(0));
9991 }
9992 break;
9993 }
9994 case NODE_HASH:
9995 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
9996 break;
9997 case NODE_RETURN:
9998 CHECK(compile_return(iseq, ret, node, popped));
9999 break;
10000 case NODE_YIELD:
10001 CHECK(compile_yield(iseq, ret, node, popped));
10002 break;
10003 case NODE_LVAR:{
10004 if (!popped) {
10005 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10006 }
10007 break;
10008 }
10009 case NODE_DVAR:{
10010 int lv, idx, ls;
10011 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10012 if (!popped) {
10013 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10014 if (idx < 0) {
10015 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10016 rb_id2str(RNODE_DVAR(node)->nd_vid));
10017 goto ng;
10018 }
10019 ADD_GETLOCAL(ret, node, ls - idx, lv);
10020 }
10021 break;
10022 }
10023 case NODE_GVAR:{
10024 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10025 if (popped) {
10026 ADD_INSN(ret, node, pop);
10027 }
10028 break;
10029 }
10030 case NODE_IVAR:{
10031 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10032 if (!popped) {
10033 ADD_INSN2(ret, node, getinstancevariable,
10034 ID2SYM(RNODE_IVAR(node)->nd_vid),
10035 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10036 }
10037 break;
10038 }
10039 case NODE_CONST:{
10040 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10041
10042 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10043 body->ic_size++;
10044 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10045 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10046 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10047 }
10048 else {
10049 ADD_INSN(ret, node, putnil);
10050 ADD_INSN1(ret, node, putobject, Qtrue);
10051 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10052 }
10053
10054 if (popped) {
10055 ADD_INSN(ret, node, pop);
10056 }
10057 break;
10058 }
10059 case NODE_CVAR:{
10060 if (!popped) {
10061 ADD_INSN2(ret, node, getclassvariable,
10062 ID2SYM(RNODE_CVAR(node)->nd_vid),
10063 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10064 }
10065 break;
10066 }
10067 case NODE_NTH_REF:{
10068 if (!popped) {
10069 if (!RNODE_NTH_REF(node)->nd_nth) {
10070 ADD_INSN(ret, node, putnil);
10071 break;
10072 }
10073 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10074 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10075 }
10076 break;
10077 }
10078 case NODE_BACK_REF:{
10079 if (!popped) {
10080 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
10081 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10082 }
10083 break;
10084 }
10085 case NODE_MATCH:
10086 case NODE_MATCH2:
10087 case NODE_MATCH3:
10088 CHECK(compile_match(iseq, ret, node, popped, type));
10089 break;
10090 case NODE_LIT:{
10091 debugp_param("lit", RNODE_LIT(node)->nd_lit);
10092 if (!popped) {
10093 ADD_INSN1(ret, node, putobject, RNODE_LIT(node)->nd_lit);
10094 RB_OBJ_WRITTEN(iseq, Qundef, RNODE_LIT(node)->nd_lit);
10095 }
10096 break;
10097 }
10098 case NODE_STR:{
10099 debugp_param("nd_lit", RNODE_STR(node)->nd_lit);
10100 if (!popped) {
10101 VALUE lit = RNODE_STR(node)->nd_lit;
10102 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
10103 lit = rb_fstring(lit);
10104 ADD_INSN1(ret, node, putstring, lit);
10105 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10106 }
10107 else {
10108 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
10109 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
10110 lit = rb_str_dup(lit);
10111 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
10112 lit = rb_str_freeze(lit);
10113 }
10114 else {
10115 lit = rb_fstring(lit);
10116 }
10117 ADD_INSN1(ret, node, putobject, lit);
10118 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10119 }
10120 }
10121 break;
10122 }
10123 case NODE_DSTR:{
10124 compile_dstr(iseq, ret, node);
10125
10126 if (popped) {
10127 ADD_INSN(ret, node, pop);
10128 }
10129 break;
10130 }
10131 case NODE_XSTR:{
10132 ADD_CALL_RECEIVER(ret, node);
10133 VALUE str = rb_fstring(RNODE_XSTR(node)->nd_lit);
10134 ADD_INSN1(ret, node, putobject, str);
10135 RB_OBJ_WRITTEN(iseq, Qundef, str);
10136 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
10137
10138 if (popped) {
10139 ADD_INSN(ret, node, pop);
10140 }
10141 break;
10142 }
10143 case NODE_DXSTR:{
10144 ADD_CALL_RECEIVER(ret, node);
10145 compile_dstr(iseq, ret, node);
10146 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
10147
10148 if (popped) {
10149 ADD_INSN(ret, node, pop);
10150 }
10151 break;
10152 }
10153 case NODE_EVSTR:
10154 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
10155 break;
10156 case NODE_DREGX:
10157 compile_dregx(iseq, ret, node, popped);
10158 break;
10159 case NODE_ONCE:{
10160 int ic_index = body->ise_size++;
10161 const rb_iseq_t *block_iseq;
10162 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
10163
10164 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
10165 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
10166
10167 if (popped) {
10168 ADD_INSN(ret, node, pop);
10169 }
10170 break;
10171 }
10172 case NODE_ARGSCAT:{
10173 if (popped) {
10174 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
10175 ADD_INSN1(ret, node, splatarray, Qfalse);
10176 ADD_INSN(ret, node, pop);
10177 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
10178 ADD_INSN1(ret, node, splatarray, Qfalse);
10179 ADD_INSN(ret, node, pop);
10180 }
10181 else {
10182 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
10183 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
10184 ADD_INSN(ret, node, concatarray);
10185 }
10186 break;
10187 }
10188 case NODE_ARGSPUSH:{
10189 if (popped) {
10190 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
10191 ADD_INSN1(ret, node, splatarray, Qfalse);
10192 ADD_INSN(ret, node, pop);
10193 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
10194 }
10195 else {
10196 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
10197 CHECK(compile_array_1(iseq, ret, RNODE_ARGSPUSH(node)->nd_body));
10198 ADD_INSN(ret, node, concatarray);
10199 }
10200 break;
10201 }
10202 case NODE_SPLAT:{
10203 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
10204 ADD_INSN1(ret, node, splatarray, Qtrue);
10205
10206 if (popped) {
10207 ADD_INSN(ret, node, pop);
10208 }
10209 break;
10210 }
10211 case NODE_DEFN:{
10212 ID mid = RNODE_DEFN(node)->nd_mid;
10213 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
10214 rb_id2str(mid),
10215 ISEQ_TYPE_METHOD, line);
10216
10217 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
10218 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
10219 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
10220
10221 if (!popped) {
10222 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
10223 }
10224
10225 break;
10226 }
10227 case NODE_DEFS:{
10228 ID mid = RNODE_DEFS(node)->nd_mid;
10229 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
10230 rb_id2str(mid),
10231 ISEQ_TYPE_METHOD, line);
10232
10233 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
10234 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
10235 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
10236 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
10237
10238 if (!popped) {
10239 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
10240 }
10241 break;
10242 }
10243 case NODE_ALIAS:{
10244 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10245 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
10246 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
10247 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
10248 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
10249
10250 if (popped) {
10251 ADD_INSN(ret, node, pop);
10252 }
10253 break;
10254 }
10255 case NODE_VALIAS:{
10256 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10257 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
10258 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
10259 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
10260
10261 if (popped) {
10262 ADD_INSN(ret, node, pop);
10263 }
10264 break;
10265 }
10266 case NODE_UNDEF:{
10267 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10268 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
10269 CHECK(COMPILE(ret, "undef arg", RNODE_UNDEF(node)->nd_undef));
10270 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
10271
10272 if (popped) {
10273 ADD_INSN(ret, node, pop);
10274 }
10275 break;
10276 }
10277 case NODE_CLASS:{
10278 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
10279 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
10280 ISEQ_TYPE_CLASS, line);
10281 const int flags = VM_DEFINECLASS_TYPE_CLASS |
10282 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
10283 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
10284
10285 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
10286 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
10287 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
10288
10289 if (popped) {
10290 ADD_INSN(ret, node, pop);
10291 }
10292 break;
10293 }
10294 case NODE_MODULE:{
10295 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
10296 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
10297 ISEQ_TYPE_CLASS, line);
10298 const int flags = VM_DEFINECLASS_TYPE_MODULE |
10299 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
10300
10301 ADD_INSN (ret, node, putnil); /* dummy */
10302 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
10303 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
10304
10305 if (popped) {
10306 ADD_INSN(ret, node, pop);
10307 }
10308 break;
10309 }
10310 case NODE_SCLASS:{
10311 ID singletonclass;
10312 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
10313 ISEQ_TYPE_CLASS, line);
10314
10315 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
10316 ADD_INSN (ret, node, putnil);
10317 CONST_ID(singletonclass, "singletonclass");
10318 ADD_INSN3(ret, node, defineclass,
10319 ID2SYM(singletonclass), singleton_class,
10320 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
10321 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
10322
10323 if (popped) {
10324 ADD_INSN(ret, node, pop);
10325 }
10326 break;
10327 }
10328 case NODE_COLON2:
10329 CHECK(compile_colon2(iseq, ret, node, popped));
10330 break;
10331 case NODE_COLON3:
10332 CHECK(compile_colon3(iseq, ret, node, popped));
10333 break;
10334 case NODE_DOT2:
10335 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
10336 break;
10337 case NODE_DOT3:
10338 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
10339 break;
10340 case NODE_FLIP2:
10341 case NODE_FLIP3:{
10342 LABEL *lend = NEW_LABEL(line);
10343 LABEL *ltrue = NEW_LABEL(line);
10344 LABEL *lfalse = NEW_LABEL(line);
10345 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
10346 ltrue, lfalse));
10347 ADD_LABEL(ret, ltrue);
10348 ADD_INSN1(ret, node, putobject, Qtrue);
10349 ADD_INSNL(ret, node, jump, lend);
10350 ADD_LABEL(ret, lfalse);
10351 ADD_INSN1(ret, node, putobject, Qfalse);
10352 ADD_LABEL(ret, lend);
10353 break;
10354 }
10355 case NODE_SELF:{
10356 if (!popped) {
10357 ADD_INSN(ret, node, putself);
10358 }
10359 break;
10360 }
10361 case NODE_NIL:{
10362 if (!popped) {
10363 ADD_INSN(ret, node, putnil);
10364 }
10365 break;
10366 }
10367 case NODE_TRUE:{
10368 if (!popped) {
10369 ADD_INSN1(ret, node, putobject, Qtrue);
10370 }
10371 break;
10372 }
10373 case NODE_FALSE:{
10374 if (!popped) {
10375 ADD_INSN1(ret, node, putobject, Qfalse);
10376 }
10377 break;
10378 }
10379 case NODE_ERRINFO:
10380 CHECK(compile_errinfo(iseq, ret, node, popped));
10381 break;
10382 case NODE_DEFINED:
10383 if (!popped) {
10384 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
10385 }
10386 break;
10387 case NODE_POSTEXE:{
10388 /* compiled to:
10389 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10390 */
10391 int is_index = body->ise_size++;
10393 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
10394 const rb_iseq_t *once_iseq =
10395 new_child_iseq_with_callback(iseq, ifunc,
10396 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
10397
10398 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
10399 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
10400
10401 if (popped) {
10402 ADD_INSN(ret, node, pop);
10403 }
10404 break;
10405 }
10406 case NODE_KW_ARG:
10407 CHECK(compile_kw_arg(iseq, ret, node, popped));
10408 break;
10409 case NODE_DSYM:{
10410 compile_dstr(iseq, ret, node);
10411 if (!popped) {
10412 ADD_INSN(ret, node, intern);
10413 }
10414 else {
10415 ADD_INSN(ret, node, pop);
10416 }
10417 break;
10418 }
10419 case NODE_ATTRASGN:
10420 CHECK(compile_attrasgn(iseq, ret, node, popped));
10421 break;
10422 case NODE_LAMBDA:{
10423 /* compile same as lambda{...} */
10424 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
10425 VALUE argc = INT2FIX(0);
10426
10427 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10428 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
10429 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
10430
10431 if (popped) {
10432 ADD_INSN(ret, node, pop);
10433 }
10434 break;
10435 }
10436 default:
10437 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
10438 ng:
10439 debug_node_end();
10440 return COMPILE_NG;
10441 }
10442
10443 debug_node_end();
10444 return COMPILE_OK;
10445}
10446
10447/***************************/
10448/* instruction information */
10449/***************************/
10450
10451static int
10452insn_data_length(INSN *iobj)
10453{
10454 return insn_len(iobj->insn_id);
10455}
10456
10457static int
10458calc_sp_depth(int depth, INSN *insn)
10459{
10460 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
10461}
10462
10463static VALUE
10464opobj_inspect(VALUE obj)
10465{
10466 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
10467 switch (BUILTIN_TYPE(obj)) {
10468 case T_STRING:
10469 obj = rb_str_new_cstr(RSTRING_PTR(obj));
10470 break;
10471 case T_ARRAY:
10472 obj = rb_ary_dup(obj);
10473 break;
10474 default:
10475 break;
10476 }
10477 }
10478 return rb_inspect(obj);
10479}
10480
10481
10482
10483static VALUE
10484insn_data_to_s_detail(INSN *iobj)
10485{
10486 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
10487
10488 if (iobj->operands) {
10489 const char *types = insn_op_types(iobj->insn_id);
10490 int j;
10491
10492 for (j = 0; types[j]; j++) {
10493 char type = types[j];
10494
10495 switch (type) {
10496 case TS_OFFSET: /* label(destination position) */
10497 {
10498 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
10499 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
10500 break;
10501 }
10502 break;
10503 case TS_ISEQ: /* iseq */
10504 {
10505 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
10506 VALUE val = Qnil;
10507 if (0 && iseq) { /* TODO: invalidate now */
10508 val = (VALUE)iseq;
10509 }
10510 rb_str_concat(str, opobj_inspect(val));
10511 }
10512 break;
10513 case TS_LINDEX:
10514 case TS_NUM: /* ulong */
10515 case TS_VALUE: /* VALUE */
10516 {
10517 VALUE v = OPERAND_AT(iobj, j);
10518 if (!CLASS_OF(v))
10519 rb_str_cat2(str, "<hidden>");
10520 else {
10521 rb_str_concat(str, opobj_inspect(v));
10522 }
10523 break;
10524 }
10525 case TS_ID: /* ID */
10526 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10527 break;
10528 case TS_IC: /* inline cache */
10529 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10530 break;
10531 case TS_IVC: /* inline ivar cache */
10532 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10533 break;
10534 case TS_ICVARC: /* inline cvar cache */
10535 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10536 break;
10537 case TS_ISE: /* inline storage entry */
10538 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10539 break;
10540 case TS_CALLDATA: /* we store these as call infos at compile time */
10541 {
10542 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
10543 rb_str_cat2(str, "<calldata:");
10544 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
10545 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
10546 break;
10547 }
10548 case TS_CDHASH: /* case/when condition cache */
10549 rb_str_cat2(str, "<ch>");
10550 break;
10551 case TS_FUNCPTR:
10552 {
10553 void *func = (void *)OPERAND_AT(iobj, j);
10554#ifdef HAVE_DLADDR
10555 Dl_info info;
10556 if (dladdr(func, &info) && info.dli_sname) {
10557 rb_str_cat2(str, info.dli_sname);
10558 break;
10559 }
10560#endif
10561 rb_str_catf(str, "<%p>", func);
10562 }
10563 break;
10564 case TS_BUILTIN:
10565 rb_str_cat2(str, "<TS_BUILTIN>");
10566 break;
10567 default:{
10568 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
10569 }
10570 }
10571 if (types[j + 1]) {
10572 rb_str_cat2(str, ", ");
10573 }
10574 }
10575 }
10576 return str;
10577}
10578
10579static void
10580dump_disasm_list(const LINK_ELEMENT *link)
10581{
10582 dump_disasm_list_with_cursor(link, NULL, NULL);
10583}
10584
10585static void
10586dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
10587{
10588 int pos = 0;
10589 INSN *iobj;
10590 LABEL *lobj;
10591 VALUE str;
10592
10593 printf("-- raw disasm--------\n");
10594
10595 while (link) {
10596 if (curr) printf(curr == link ? "*" : " ");
10597 switch (link->type) {
10598 case ISEQ_ELEMENT_INSN:
10599 {
10600 iobj = (INSN *)link;
10601 str = insn_data_to_s_detail(iobj);
10602 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
10603 pos += insn_data_length(iobj);
10604 break;
10605 }
10606 case ISEQ_ELEMENT_LABEL:
10607 {
10608 lobj = (LABEL *)link;
10609 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
10610 dest == lobj ? " <---" : "");
10611 break;
10612 }
10613 case ISEQ_ELEMENT_TRACE:
10614 {
10615 TRACE *trace = (TRACE *)link;
10616 printf(" trace: %0x\n", trace->event);
10617 break;
10618 }
10619 case ISEQ_ELEMENT_ADJUST:
10620 {
10621 ADJUST *adjust = (ADJUST *)link;
10622 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
10623 break;
10624 }
10625 default:
10626 /* ignore */
10627 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
10628 }
10629 link = link->next;
10630 }
10631 printf("---------------------\n");
10632 fflush(stdout);
10633}
10634
10635int
10636rb_insn_len(VALUE insn)
10637{
10638 return insn_len(insn);
10639}
10640
10641const char *
10642rb_insns_name(int i)
10643{
10644 return insn_name(i);
10645}
10646
10647VALUE
10648rb_insns_name_array(void)
10649{
10650 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
10651 int i;
10652 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
10653 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
10654 }
10655 return rb_obj_freeze(ary);
10656}
10657
10658static LABEL *
10659register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
10660{
10661 LABEL *label = 0;
10662 st_data_t tmp;
10663 obj = rb_to_symbol_type(obj);
10664
10665 if (st_lookup(labels_table, obj, &tmp) == 0) {
10666 label = NEW_LABEL(0);
10667 st_insert(labels_table, obj, (st_data_t)label);
10668 }
10669 else {
10670 label = (LABEL *)tmp;
10671 }
10672 LABEL_REF(label);
10673 return label;
10674}
10675
10676static VALUE
10677get_exception_sym2type(VALUE sym)
10678{
10679 static VALUE symRescue, symEnsure, symRetry;
10680 static VALUE symBreak, symRedo, symNext;
10681
10682 if (symRescue == 0) {
10683 symRescue = ID2SYM(rb_intern_const("rescue"));
10684 symEnsure = ID2SYM(rb_intern_const("ensure"));
10685 symRetry = ID2SYM(rb_intern_const("retry"));
10686 symBreak = ID2SYM(rb_intern_const("break"));
10687 symRedo = ID2SYM(rb_intern_const("redo"));
10688 symNext = ID2SYM(rb_intern_const("next"));
10689 }
10690
10691 if (sym == symRescue) return CATCH_TYPE_RESCUE;
10692 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
10693 if (sym == symRetry) return CATCH_TYPE_RETRY;
10694 if (sym == symBreak) return CATCH_TYPE_BREAK;
10695 if (sym == symRedo) return CATCH_TYPE_REDO;
10696 if (sym == symNext) return CATCH_TYPE_NEXT;
10697 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
10698 return 0;
10699}
10700
10701static int
10702iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
10703 VALUE exception)
10704{
10705 int i;
10706
10707 for (i=0; i<RARRAY_LEN(exception); i++) {
10708 const rb_iseq_t *eiseq;
10709 VALUE v, type;
10710 LABEL *lstart, *lend, *lcont;
10711 unsigned int sp;
10712
10713 v = rb_to_array_type(RARRAY_AREF(exception, i));
10714 if (RARRAY_LEN(v) != 6) {
10715 rb_raise(rb_eSyntaxError, "wrong exception entry");
10716 }
10717 type = get_exception_sym2type(RARRAY_AREF(v, 0));
10718 if (NIL_P(RARRAY_AREF(v, 1))) {
10719 eiseq = NULL;
10720 }
10721 else {
10722 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
10723 }
10724
10725 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
10726 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
10727 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
10728 sp = NUM2UINT(RARRAY_AREF(v, 5));
10729
10730 /* TODO: Dirty Hack! Fix me */
10731 if (type == CATCH_TYPE_RESCUE ||
10732 type == CATCH_TYPE_BREAK ||
10733 type == CATCH_TYPE_NEXT) {
10734 ++sp;
10735 }
10736
10737 lcont->sp = sp;
10738
10739 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
10740
10741 RB_GC_GUARD(v);
10742 }
10743 return COMPILE_OK;
10744}
10745
10746static struct st_table *
10747insn_make_insn_table(void)
10748{
10749 struct st_table *table;
10750 int i;
10751 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10752
10753 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10754 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
10755 }
10756
10757 return table;
10758}
10759
10760static const rb_iseq_t *
10761iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
10762{
10763 VALUE iseqw;
10764 const rb_iseq_t *loaded_iseq;
10765
10766 if (RB_TYPE_P(op, T_ARRAY)) {
10767 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
10768 }
10769 else if (CLASS_OF(op) == rb_cISeq) {
10770 iseqw = op;
10771 }
10772 else {
10773 rb_raise(rb_eSyntaxError, "ISEQ is required");
10774 }
10775
10776 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10777 return loaded_iseq;
10778}
10779
10780static VALUE
10781iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
10782{
10783 ID mid = 0;
10784 int orig_argc = 0;
10785 unsigned int flag = 0;
10786 struct rb_callinfo_kwarg *kw_arg = 0;
10787
10788 if (!NIL_P(op)) {
10789 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
10790 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
10791 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
10792 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
10793
10794 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
10795 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
10796 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
10797
10798 if (!NIL_P(vkw_arg)) {
10799 int i;
10800 int len = RARRAY_LENINT(vkw_arg);
10801 size_t n = rb_callinfo_kwarg_bytes(len);
10802
10803 kw_arg = xmalloc(n);
10804 kw_arg->references = 0;
10805 kw_arg->keyword_len = len;
10806 for (i = 0; i < len; i++) {
10807 VALUE kw = RARRAY_AREF(vkw_arg, i);
10808 SYM2ID(kw); /* make immortal */
10809 kw_arg->keywords[i] = kw;
10810 }
10811 }
10812 }
10813
10814 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10815 RB_OBJ_WRITTEN(iseq, Qundef, ci);
10816 return (VALUE)ci;
10817}
10818
10819static rb_event_flag_t
10820event_name_to_flag(VALUE sym)
10821{
10822#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10823 CHECK_EVENT(RUBY_EVENT_LINE);
10824 CHECK_EVENT(RUBY_EVENT_CLASS);
10825 CHECK_EVENT(RUBY_EVENT_END);
10826 CHECK_EVENT(RUBY_EVENT_CALL);
10827 CHECK_EVENT(RUBY_EVENT_RETURN);
10828 CHECK_EVENT(RUBY_EVENT_B_CALL);
10829 CHECK_EVENT(RUBY_EVENT_B_RETURN);
10830 CHECK_EVENT(RUBY_EVENT_RESCUE);
10831#undef CHECK_EVENT
10832 return RUBY_EVENT_NONE;
10833}
10834
10835static int
10836iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
10837 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10838{
10839 /* TODO: body should be frozen */
10840 long i, len = RARRAY_LEN(body);
10841 struct st_table *labels_table = DATA_PTR(labels_wrapper);
10842 int j;
10843 int line_no = 0, node_id = -1, insn_idx = 0;
10844 int ret = COMPILE_OK;
10845
10846 /*
10847 * index -> LABEL *label
10848 */
10849 static struct st_table *insn_table;
10850
10851 if (insn_table == 0) {
10852 insn_table = insn_make_insn_table();
10853 }
10854
10855 for (i=0; i<len; i++) {
10856 VALUE obj = RARRAY_AREF(body, i);
10857
10858 if (SYMBOL_P(obj)) {
10859 rb_event_flag_t event;
10860 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
10861 ADD_TRACE(anchor, event);
10862 }
10863 else {
10864 LABEL *label = register_label(iseq, labels_table, obj);
10865 ADD_LABEL(anchor, label);
10866 }
10867 }
10868 else if (FIXNUM_P(obj)) {
10869 line_no = NUM2INT(obj);
10870 }
10871 else if (RB_TYPE_P(obj, T_ARRAY)) {
10872 VALUE *argv = 0;
10873 int argc = RARRAY_LENINT(obj) - 1;
10874 st_data_t insn_id;
10875 VALUE insn;
10876
10877 if (node_ids) {
10878 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
10879 }
10880
10881 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
10882 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10883 /* TODO: exception */
10884 COMPILE_ERROR(iseq, line_no,
10885 "unknown instruction: %+"PRIsVALUE, insn);
10886 ret = COMPILE_NG;
10887 break;
10888 }
10889
10890 if (argc != insn_len((VALUE)insn_id)-1) {
10891 COMPILE_ERROR(iseq, line_no,
10892 "operand size mismatch");
10893 ret = COMPILE_NG;
10894 break;
10895 }
10896
10897 if (argc > 0) {
10898 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
10899
10900 // add element before operand setup to make GC root
10901 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10902 ADD_ELEM(anchor,
10903 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10904 (enum ruby_vminsn_type)insn_id, argc, argv));
10905
10906 for (j=0; j<argc; j++) {
10907 VALUE op = rb_ary_entry(obj, j+1);
10908 switch (insn_op_type((VALUE)insn_id, j)) {
10909 case TS_OFFSET: {
10910 LABEL *label = register_label(iseq, labels_table, op);
10911 argv[j] = (VALUE)label;
10912 break;
10913 }
10914 case TS_LINDEX:
10915 case TS_NUM:
10916 (void)NUM2INT(op);
10917 argv[j] = op;
10918 break;
10919 case TS_VALUE:
10920 argv[j] = op;
10921 RB_OBJ_WRITTEN(iseq, Qundef, op);
10922 break;
10923 case TS_ISEQ:
10924 {
10925 if (op != Qnil) {
10926 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
10927 argv[j] = v;
10928 RB_OBJ_WRITTEN(iseq, Qundef, v);
10929 }
10930 else {
10931 argv[j] = 0;
10932 }
10933 }
10934 break;
10935 case TS_ISE:
10936 argv[j] = op;
10937 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
10938 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
10939 }
10940 break;
10941 case TS_IC:
10942 {
10943 VALUE segments = rb_ary_new();
10944 op = rb_to_array_type(op);
10945
10946 for (int i = 0; i < RARRAY_LEN(op); i++) {
10947 VALUE sym = RARRAY_AREF(op, i);
10948 sym = rb_to_symbol_type(sym);
10949 rb_ary_push(segments, sym);
10950 }
10951
10952 RB_GC_GUARD(op);
10953 argv[j] = segments;
10954 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10955 ISEQ_BODY(iseq)->ic_size++;
10956 }
10957 break;
10958 case TS_IVC: /* inline ivar cache */
10959 argv[j] = op;
10960 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
10961 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
10962 }
10963 break;
10964 case TS_ICVARC: /* inline cvar cache */
10965 argv[j] = op;
10966 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
10967 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
10968 }
10969 break;
10970 case TS_CALLDATA:
10971 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10972 break;
10973 case TS_ID:
10974 argv[j] = rb_to_symbol_type(op);
10975 break;
10976 case TS_CDHASH:
10977 {
10978 int i;
10979 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
10980
10981 RHASH_TBL_RAW(map)->type = &cdhash_type;
10982 op = rb_to_array_type(op);
10983 for (i=0; i<RARRAY_LEN(op); i+=2) {
10984 VALUE key = RARRAY_AREF(op, i);
10985 VALUE sym = RARRAY_AREF(op, i+1);
10986 LABEL *label =
10987 register_label(iseq, labels_table, sym);
10988 rb_hash_aset(map, key, (VALUE)label | 1);
10989 }
10990 RB_GC_GUARD(op);
10991 argv[j] = map;
10992 RB_OBJ_WRITTEN(iseq, Qundef, map);
10993 }
10994 break;
10995 case TS_FUNCPTR:
10996 {
10997#if SIZEOF_VALUE <= SIZEOF_LONG
10998 long funcptr = NUM2LONG(op);
10999#else
11000 LONG_LONG funcptr = NUM2LL(op);
11001#endif
11002 argv[j] = (VALUE)funcptr;
11003 }
11004 break;
11005 default:
11006 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
11007 }
11008 }
11009 }
11010 else {
11011 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
11012 ADD_ELEM(anchor,
11013 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
11014 (enum ruby_vminsn_type)insn_id, argc, NULL));
11015 }
11016 }
11017 else {
11018 rb_raise(rb_eTypeError, "unexpected object for instruction");
11019 }
11020 }
11021 DATA_PTR(labels_wrapper) = 0;
11022 validate_labels(iseq, labels_table);
11023 if (!ret) return ret;
11024 return iseq_setup(iseq, anchor);
11025}
11026
11027#define CHECK_ARRAY(v) rb_to_array_type(v)
11028#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11029
11030static int
11031int_param(int *dst, VALUE param, VALUE sym)
11032{
11033 VALUE val = rb_hash_aref(param, sym);
11034 if (FIXNUM_P(val)) {
11035 *dst = FIX2INT(val);
11036 return TRUE;
11037 }
11038 else if (!NIL_P(val)) {
11039 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
11040 sym, val);
11041 }
11042 return FALSE;
11043}
11044
11045static const struct rb_iseq_param_keyword *
11046iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
11047{
11048 int i, j;
11049 int len = RARRAY_LENINT(keywords);
11050 int default_len;
11051 VALUE key, sym, default_val;
11052 VALUE *dvs;
11053 ID *ids;
11054 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
11055
11056 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
11057
11058 keyword->num = len;
11059#define SYM(s) ID2SYM(rb_intern_const(#s))
11060 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
11061 i = keyword->bits_start - keyword->num;
11062 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
11063#undef SYM
11064
11065 /* required args */
11066 for (i = 0; i < len; i++) {
11067 VALUE val = RARRAY_AREF(keywords, i);
11068
11069 if (!SYMBOL_P(val)) {
11070 goto default_values;
11071 }
11072 ids[i] = SYM2ID(val);
11073 keyword->required_num++;
11074 }
11075
11076 default_values: /* note: we intentionally preserve `i' from previous loop */
11077 default_len = len - i;
11078 if (default_len == 0) {
11079 keyword->table = ids;
11080 return keyword;
11081 }
11082 else if (default_len < 0) {
11084 }
11085
11086 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
11087
11088 for (j = 0; i < len; i++, j++) {
11089 key = RARRAY_AREF(keywords, i);
11090 CHECK_ARRAY(key);
11091
11092 switch (RARRAY_LEN(key)) {
11093 case 1:
11094 sym = RARRAY_AREF(key, 0);
11095 default_val = Qundef;
11096 break;
11097 case 2:
11098 sym = RARRAY_AREF(key, 0);
11099 default_val = RARRAY_AREF(key, 1);
11100 break;
11101 default:
11102 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
11103 }
11104 ids[i] = SYM2ID(sym);
11105 dvs[j] = default_val;
11106 }
11107
11108 keyword->table = ids;
11109 keyword->default_values = dvs;
11110
11111 return keyword;
11112}
11113
11114static void
11115iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
11116{
11117 rb_gc_mark(obj);
11118}
11119
11120void
11121rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
11122{
11123 INSN *iobj = 0;
11124 size_t size = sizeof(INSN);
11125 unsigned int pos = 0;
11126
11127 while (storage) {
11128#ifdef STRICT_ALIGNMENT
11129 size_t padding = calc_padding((void *)&storage->buff[pos], size);
11130#else
11131 const size_t padding = 0; /* expected to be optimized by compiler */
11132#endif /* STRICT_ALIGNMENT */
11133 size_t offset = pos + size + padding;
11134 if (offset > storage->size || offset > storage->pos) {
11135 pos = 0;
11136 storage = storage->next;
11137 }
11138 else {
11139#ifdef STRICT_ALIGNMENT
11140 pos += (int)padding;
11141#endif /* STRICT_ALIGNMENT */
11142
11143 iobj = (INSN *)&storage->buff[pos];
11144
11145 if (iobj->operands) {
11146 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
11147 }
11148 pos += (int)size;
11149 }
11150 }
11151}
11152
11153void
11154rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
11155 VALUE exception, VALUE body)
11156{
11157#define SYM(s) ID2SYM(rb_intern_const(#s))
11158 int i, len;
11159 unsigned int arg_size, local_size, stack_max;
11160 ID *tbl;
11161 struct st_table *labels_table = st_init_numtable();
11162 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
11163 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
11164 VALUE keywords = rb_hash_aref(params, SYM(keyword));
11165 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
11166 DECL_ANCHOR(anchor);
11167 INIT_ANCHOR(anchor);
11168
11169 len = RARRAY_LENINT(locals);
11170 ISEQ_BODY(iseq)->local_table_size = len;
11171 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
11172
11173 for (i = 0; i < len; i++) {
11174 VALUE lv = RARRAY_AREF(locals, i);
11175
11176 if (sym_arg_rest == lv) {
11177 tbl[i] = 0;
11178 }
11179 else {
11180 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
11181 }
11182 }
11183
11184#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
11185 if (INT_PARAM(lead_num)) {
11186 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
11187 }
11188 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
11189 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
11190 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
11191 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
11192#undef INT_PARAM
11193 {
11194#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
11195 int x;
11196 INT_PARAM(arg_size);
11197 INT_PARAM(local_size);
11198 INT_PARAM(stack_max);
11199#undef INT_PARAM
11200 }
11201
11202 VALUE node_ids = Qfalse;
11203#ifdef USE_ISEQ_NODE_ID
11204 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
11205 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
11206 rb_raise(rb_eTypeError, "node_ids is not an array");
11207 }
11208#endif
11209
11210 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
11211 len = RARRAY_LENINT(arg_opt_labels);
11212 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
11213
11214 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
11215 VALUE *opt_table = ALLOC_N(VALUE, len);
11216
11217 for (i = 0; i < len; i++) {
11218 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
11219 LABEL *label = register_label(iseq, labels_table, ent);
11220 opt_table[i] = (VALUE)label;
11221 }
11222
11223 ISEQ_BODY(iseq)->param.opt_num = len - 1;
11224 ISEQ_BODY(iseq)->param.opt_table = opt_table;
11225 }
11226 }
11227 else if (!NIL_P(arg_opt_labels)) {
11228 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
11229 arg_opt_labels);
11230 }
11231
11232 if (RB_TYPE_P(keywords, T_ARRAY)) {
11233 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
11234 }
11235 else if (!NIL_P(keywords)) {
11236 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
11237 keywords);
11238 }
11239
11240 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
11241 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
11242 }
11243
11244 if (int_param(&i, params, SYM(kwrest))) {
11245 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
11246 if (keyword == NULL) {
11247 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
11248 }
11249 keyword->rest_start = i;
11250 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
11251 }
11252#undef SYM
11253 iseq_calc_param_size(iseq);
11254
11255 /* exception */
11256 iseq_build_from_ary_exception(iseq, labels_table, exception);
11257
11258 /* body */
11259 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
11260
11261 ISEQ_BODY(iseq)->param.size = arg_size;
11262 ISEQ_BODY(iseq)->local_table_size = local_size;
11263 ISEQ_BODY(iseq)->stack_max = stack_max;
11264}
11265
11266/* for parser */
11267
11268int
11269rb_dvar_defined(ID id, const rb_iseq_t *iseq)
11270{
11271 if (iseq) {
11272 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
11273 while (body->type == ISEQ_TYPE_BLOCK ||
11274 body->type == ISEQ_TYPE_RESCUE ||
11275 body->type == ISEQ_TYPE_ENSURE ||
11276 body->type == ISEQ_TYPE_EVAL ||
11277 body->type == ISEQ_TYPE_MAIN
11278 ) {
11279 unsigned int i;
11280
11281 for (i = 0; i < body->local_table_size; i++) {
11282 if (body->local_table[i] == id) {
11283 return 1;
11284 }
11285 }
11286 iseq = body->parent_iseq;
11287 body = ISEQ_BODY(iseq);
11288 }
11289 }
11290 return 0;
11291}
11292
11293int
11294rb_local_defined(ID id, const rb_iseq_t *iseq)
11295{
11296 if (iseq) {
11297 unsigned int i;
11298 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
11299
11300 for (i=0; i<body->local_table_size; i++) {
11301 if (body->local_table[i] == id) {
11302 return 1;
11303 }
11304 }
11305 }
11306 return 0;
11307}
11308
11309/* ISeq binary format */
11310
11311#ifndef IBF_ISEQ_DEBUG
11312#define IBF_ISEQ_DEBUG 0
11313#endif
11314
11315#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
11316#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
11317#endif
11318
11319typedef uint32_t ibf_offset_t;
11320#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
11321
11322#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
11323#ifdef RUBY_DEVEL
11324#define IBF_DEVEL_VERSION 4
11325#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
11326#else
11327#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
11328#endif
11329
11330static const char IBF_ENDIAN_MARK =
11331#ifdef WORDS_BIGENDIAN
11332 'b'
11333#else
11334 'l'
11335#endif
11336 ;
11337
11339 char magic[4]; /* YARB */
11340 uint32_t major_version;
11341 uint32_t minor_version;
11342 uint32_t size;
11343 uint32_t extra_size;
11344
11345 uint32_t iseq_list_size;
11346 uint32_t global_object_list_size;
11347 ibf_offset_t iseq_list_offset;
11348 ibf_offset_t global_object_list_offset;
11349 uint8_t endian;
11350 uint8_t wordsize; /* assume no 2048-bit CPU */
11351};
11352
11354 VALUE str;
11355 st_table *obj_table; /* obj -> obj number */
11356};
11357
11358struct ibf_dump {
11359 st_table *iseq_table; /* iseq -> iseq number */
11360 struct ibf_dump_buffer global_buffer;
11361 struct ibf_dump_buffer *current_buffer;
11362};
11363
11365 const char *buff;
11366 ibf_offset_t size;
11367
11368 VALUE obj_list; /* [obj0, ...] */
11369 unsigned int obj_list_size;
11370 ibf_offset_t obj_list_offset;
11371};
11372
11373struct ibf_load {
11374 const struct ibf_header *header;
11375 VALUE iseq_list; /* [iseq0, ...] */
11376 struct ibf_load_buffer global_buffer;
11377 VALUE loader_obj;
11378 rb_iseq_t *iseq;
11379 VALUE str;
11380 struct ibf_load_buffer *current_buffer;
11381};
11382
11384 long size;
11385 VALUE buffer[1];
11386};
11387
11388static void
11389pinned_list_mark(void *ptr)
11390{
11391 long i;
11392 struct pinned_list *list = (struct pinned_list *)ptr;
11393 for (i = 0; i < list->size; i++) {
11394 if (list->buffer[i]) {
11395 rb_gc_mark(list->buffer[i]);
11396 }
11397 }
11398}
11399
11400static const rb_data_type_t pinned_list_type = {
11401 "pinned_list",
11402 {
11403 pinned_list_mark,
11405 NULL, // No external memory to report,
11406 },
11407 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
11408};
11409
11410static VALUE
11411pinned_list_fetch(VALUE list, long offset)
11412{
11413 struct pinned_list * ptr;
11414
11415 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11416
11417 if (offset >= ptr->size) {
11418 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11419 }
11420
11421 return ptr->buffer[offset];
11422}
11423
11424static void
11425pinned_list_store(VALUE list, long offset, VALUE object)
11426{
11427 struct pinned_list * ptr;
11428
11429 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11430
11431 if (offset >= ptr->size) {
11432 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11433 }
11434
11435 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
11436}
11437
11438static VALUE
11439pinned_list_new(long size)
11440{
11441 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
11442 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
11443 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
11444 ptr->size = size;
11445 return obj_list;
11446}
11447
11448static ibf_offset_t
11449ibf_dump_pos(struct ibf_dump *dump)
11450{
11451 long pos = RSTRING_LEN(dump->current_buffer->str);
11452#if SIZEOF_LONG > SIZEOF_INT
11453 if (pos >= UINT_MAX) {
11454 rb_raise(rb_eRuntimeError, "dump size exceeds");
11455 }
11456#endif
11457 return (unsigned int)pos;
11458}
11459
11460static void
11461ibf_dump_align(struct ibf_dump *dump, size_t align)
11462{
11463 ibf_offset_t pos = ibf_dump_pos(dump);
11464 if (pos % align) {
11465 static const char padding[sizeof(VALUE)];
11466 size_t size = align - ((size_t)pos % align);
11467#if SIZEOF_LONG > SIZEOF_INT
11468 if (pos + size >= UINT_MAX) {
11469 rb_raise(rb_eRuntimeError, "dump size exceeds");
11470 }
11471#endif
11472 for (; size > sizeof(padding); size -= sizeof(padding)) {
11473 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
11474 }
11475 rb_str_cat(dump->current_buffer->str, padding, size);
11476 }
11477}
11478
11479static ibf_offset_t
11480ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
11481{
11482 ibf_offset_t pos = ibf_dump_pos(dump);
11483 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
11484 /* TODO: overflow check */
11485 return pos;
11486}
11487
11488static ibf_offset_t
11489ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
11490{
11491 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
11492}
11493
11494static void
11495ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
11496{
11497 VALUE str = dump->current_buffer->str;
11498 char *ptr = RSTRING_PTR(str);
11499 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
11500 rb_bug("ibf_dump_overwrite: overflow");
11501 memcpy(ptr + offset, buff, size);
11502}
11503
11504static const void *
11505ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
11506{
11507 ibf_offset_t beg = *offset;
11508 *offset += size;
11509 return load->current_buffer->buff + beg;
11510}
11511
11512static void *
11513ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
11514{
11515 void *buff = ruby_xmalloc2(x, y);
11516 size_t size = x * y;
11517 memcpy(buff, load->current_buffer->buff + offset, size);
11518 return buff;
11519}
11520
11521#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
11522
11523#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
11524#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
11525#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
11526#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
11527#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
11528
11529static int
11530ibf_table_lookup(struct st_table *table, st_data_t key)
11531{
11532 st_data_t val;
11533
11534 if (st_lookup(table, key, &val)) {
11535 return (int)val;
11536 }
11537 else {
11538 return -1;
11539 }
11540}
11541
11542static int
11543ibf_table_find_or_insert(struct st_table *table, st_data_t key)
11544{
11545 int index = ibf_table_lookup(table, key);
11546
11547 if (index < 0) { /* not found */
11548 index = (int)table->num_entries;
11549 st_insert(table, key, (st_data_t)index);
11550 }
11551
11552 return index;
11553}
11554
11555/* dump/load generic */
11556
11557static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
11558
11559static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
11560static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
11561
11562static st_table *
11563ibf_dump_object_table_new(void)
11564{
11565 st_table *obj_table = st_init_numtable(); /* need free */
11566 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
11567
11568 return obj_table;
11569}
11570
11571static VALUE
11572ibf_dump_object(struct ibf_dump *dump, VALUE obj)
11573{
11574 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
11575}
11576
11577static VALUE
11578ibf_dump_id(struct ibf_dump *dump, ID id)
11579{
11580 if (id == 0 || rb_id2name(id) == NULL) {
11581 return 0;
11582 }
11583 return ibf_dump_object(dump, rb_id2sym(id));
11584}
11585
11586static ID
11587ibf_load_id(const struct ibf_load *load, const ID id_index)
11588{
11589 if (id_index == 0) {
11590 return 0;
11591 }
11592 VALUE sym = ibf_load_object(load, id_index);
11593 return rb_sym2id(sym);
11594}
11595
11596/* dump/load: code */
11597
11598static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
11599
11600static int
11601ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
11602{
11603 if (iseq == NULL) {
11604 return -1;
11605 }
11606 else {
11607 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
11608 }
11609}
11610
11611static unsigned char
11612ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
11613{
11614 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
11615 return (unsigned char)load->current_buffer->buff[(*offset)++];
11616}
11617
11618/*
11619 * Small uint serialization
11620 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
11621 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
11622 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
11623 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11624 * ...
11625 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11626 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11627 */
11628static void
11629ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
11630{
11631 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11632 ibf_dump_write(dump, &x, sizeof(VALUE));
11633 return;
11634 }
11635
11636 enum { max_byte_length = sizeof(VALUE) + 1 };
11637
11638 unsigned char bytes[max_byte_length];
11639 ibf_offset_t n;
11640
11641 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
11642 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11643 }
11644
11645 x <<= 1;
11646 x |= 1;
11647 x <<= n;
11648 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11649 n++;
11650
11651 ibf_dump_write(dump, bytes + max_byte_length - n, n);
11652}
11653
11654static VALUE
11655ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
11656{
11657 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11658 union { char s[sizeof(VALUE)]; VALUE v; } x;
11659
11660 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
11661 *offset += sizeof(VALUE);
11662
11663 return x.v;
11664 }
11665
11666 enum { max_byte_length = sizeof(VALUE) + 1 };
11667
11668 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
11669 const unsigned char c = buffer[*offset];
11670
11671 ibf_offset_t n =
11672 c & 1 ? 1 :
11673 c == 0 ? 9 : ntz_int32(c) + 1;
11674 VALUE x = (VALUE)c >> n;
11675
11676 if (*offset + n > load->current_buffer->size) {
11677 rb_raise(rb_eRuntimeError, "invalid byte sequence");
11678 }
11679
11680 ibf_offset_t i;
11681 for (i = 1; i < n; i++) {
11682 x <<= 8;
11683 x |= (VALUE)buffer[*offset + i];
11684 }
11685
11686 *offset += n;
11687 return x;
11688}
11689
11690static void
11691ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
11692{
11693 // short: index
11694 // short: name.length
11695 // bytes: name
11696 // // omit argc (only verify with name)
11697 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11698
11699 size_t len = strlen(bf->name);
11700 ibf_dump_write_small_value(dump, (VALUE)len);
11701 ibf_dump_write(dump, bf->name, len);
11702}
11703
11704static const struct rb_builtin_function *
11705ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
11706{
11707 int i = (int)ibf_load_small_value(load, offset);
11708 int len = (int)ibf_load_small_value(load, offset);
11709 const char *name = (char *)ibf_load_ptr(load, offset, len);
11710
11711 if (0) {
11712 fprintf(stderr, "%.*s!!\n", len, name);
11713 }
11714
11715 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
11716 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
11717 if (strncmp(table[i].name, name, len) != 0) {
11718 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11719 }
11720 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
11721
11722 return &table[i];
11723}
11724
11725static ibf_offset_t
11726ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
11727{
11728 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11729 const int iseq_size = body->iseq_size;
11730 int code_index;
11731 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11732
11733 ibf_offset_t offset = ibf_dump_pos(dump);
11734
11735 for (code_index=0; code_index<iseq_size;) {
11736 const VALUE insn = orig_code[code_index++];
11737 const char *types = insn_op_types(insn);
11738 int op_index;
11739
11740 /* opcode */
11741 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
11742 ibf_dump_write_small_value(dump, insn);
11743
11744 /* operands */
11745 for (op_index=0; types[op_index]; op_index++, code_index++) {
11746 VALUE op = orig_code[code_index];
11747 VALUE wv;
11748
11749 switch (types[op_index]) {
11750 case TS_CDHASH:
11751 case TS_VALUE:
11752 wv = ibf_dump_object(dump, op);
11753 break;
11754 case TS_ISEQ:
11755 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
11756 break;
11757 case TS_IC:
11758 {
11759 IC ic = (IC)op;
11760 VALUE arr = idlist_to_array(ic->segments);
11761 wv = ibf_dump_object(dump, arr);
11762 }
11763 break;
11764 case TS_ISE:
11765 case TS_IVC:
11766 case TS_ICVARC:
11767 {
11769 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
11770 }
11771 break;
11772 case TS_CALLDATA:
11773 {
11774 goto skip_wv;
11775 }
11776 case TS_ID:
11777 wv = ibf_dump_id(dump, (ID)op);
11778 break;
11779 case TS_FUNCPTR:
11780 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11781 goto skip_wv;
11782 case TS_BUILTIN:
11783 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
11784 goto skip_wv;
11785 default:
11786 wv = op;
11787 break;
11788 }
11789 ibf_dump_write_small_value(dump, wv);
11790 skip_wv:;
11791 }
11792 assert(insn_len(insn) == op_index+1);
11793 }
11794
11795 return offset;
11796}
11797
11798static VALUE *
11799ibf_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)
11800{
11801 VALUE iseqv = (VALUE)iseq;
11802 unsigned int code_index;
11803 ibf_offset_t reading_pos = bytecode_offset;
11804 VALUE *code = ALLOC_N(VALUE, iseq_size);
11805
11806 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
11807 struct rb_call_data *cd_entries = load_body->call_data;
11808 int ic_index = 0;
11809
11810 iseq_bits_t * mark_offset_bits;
11811
11812 iseq_bits_t tmp[1] = {0};
11813
11814 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
11815 mark_offset_bits = tmp;
11816 }
11817 else {
11818 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
11819 }
11820 bool needs_bitmap = false;
11821
11822 for (code_index=0; code_index<iseq_size;) {
11823 /* opcode */
11824 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11825 const char *types = insn_op_types(insn);
11826 int op_index;
11827
11828 code_index++;
11829
11830 /* operands */
11831 for (op_index=0; types[op_index]; op_index++, code_index++) {
11832 const char operand_type = types[op_index];
11833 switch (operand_type) {
11834 case TS_VALUE:
11835 {
11836 VALUE op = ibf_load_small_value(load, &reading_pos);
11837 VALUE v = ibf_load_object(load, op);
11838 code[code_index] = v;
11839 if (!SPECIAL_CONST_P(v)) {
11840 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11841 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11842 needs_bitmap = true;
11843 }
11844 break;
11845 }
11846 case TS_CDHASH:
11847 {
11848 VALUE op = ibf_load_small_value(load, &reading_pos);
11849 VALUE v = ibf_load_object(load, op);
11850 v = rb_hash_dup(v); // hash dumped as frozen
11851 RHASH_TBL_RAW(v)->type = &cdhash_type;
11852 rb_hash_rehash(v); // hash function changed
11853 freeze_hide_obj(v);
11854
11855 // Overwrite the existing hash in the object list. This
11856 // is to keep the object alive during load time.
11857 // [Bug #17984] [ruby-core:104259]
11858 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
11859
11860 code[code_index] = v;
11861 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11862 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11863 needs_bitmap = true;
11864 break;
11865 }
11866 case TS_ISEQ:
11867 {
11868 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
11869 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
11870 code[code_index] = v;
11871 if (!SPECIAL_CONST_P(v)) {
11872 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11873 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11874 needs_bitmap = true;
11875 }
11876 break;
11877 }
11878 case TS_IC:
11879 {
11880 VALUE op = ibf_load_small_value(load, &reading_pos);
11881 VALUE arr = ibf_load_object(load, op);
11882
11883 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
11884 ic->segments = array_to_idlist(arr);
11885
11886 code[code_index] = (VALUE)ic;
11887 }
11888 break;
11889 case TS_ISE:
11890 case TS_ICVARC:
11891 case TS_IVC:
11892 {
11893 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
11894
11895 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
11896 code[code_index] = (VALUE)ic;
11897
11898 if (operand_type == TS_IVC) {
11899 IVC cache = (IVC)ic;
11900
11901 if (insn == BIN(setinstancevariable)) {
11902 ID iv_name = (ID)code[code_index - 1];
11903 cache->iv_set_name = iv_name;
11904 }
11905 else {
11906 cache->iv_set_name = 0;
11907 }
11908
11909 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
11910 }
11911
11912 }
11913 break;
11914 case TS_CALLDATA:
11915 {
11916 code[code_index] = (VALUE)cd_entries++;
11917 }
11918 break;
11919 case TS_ID:
11920 {
11921 VALUE op = ibf_load_small_value(load, &reading_pos);
11922 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11923 }
11924 break;
11925 case TS_FUNCPTR:
11926 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11927 break;
11928 case TS_BUILTIN:
11929 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
11930 break;
11931 default:
11932 code[code_index] = ibf_load_small_value(load, &reading_pos);
11933 continue;
11934 }
11935 }
11936 if (insn_len(insn) != op_index+1) {
11937 rb_raise(rb_eRuntimeError, "operand size mismatch");
11938 }
11939 }
11940
11941 load_body->iseq_encoded = code;
11942 load_body->iseq_size = code_index;
11943
11944 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
11945 load_body->mark_bits.single = mark_offset_bits[0];
11946 }
11947 else {
11948 if (needs_bitmap) {
11949 load_body->mark_bits.list = mark_offset_bits;
11950 }
11951 else {
11952 load_body->mark_bits.list = 0;
11953 ruby_xfree(mark_offset_bits);
11954 }
11955 }
11956
11957 assert(code_index == iseq_size);
11958 assert(reading_pos == bytecode_offset + bytecode_size);
11959 return code;
11960}
11961
11962static ibf_offset_t
11963ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11964{
11965 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
11966
11967 if (opt_num > 0) {
11968 IBF_W_ALIGN(VALUE);
11969 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
11970 }
11971 else {
11972 return ibf_dump_pos(dump);
11973 }
11974}
11975
11976static VALUE *
11977ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
11978{
11979 if (opt_num > 0) {
11980 VALUE *table = ALLOC_N(VALUE, opt_num+1);
11981 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11982 return table;
11983 }
11984 else {
11985 return NULL;
11986 }
11987}
11988
11989static ibf_offset_t
11990ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
11991{
11992 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
11993
11994 if (kw) {
11995 struct rb_iseq_param_keyword dump_kw = *kw;
11996 int dv_num = kw->num - kw->required_num;
11997 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
11998 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
11999 int i;
12000
12001 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
12002 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
12003
12004 dump_kw.table = IBF_W(ids, ID, kw->num);
12005 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
12006 IBF_W_ALIGN(struct rb_iseq_param_keyword);
12007 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
12008 }
12009 else {
12010 return 0;
12011 }
12012}
12013
12014static const struct rb_iseq_param_keyword *
12015ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
12016{
12017 if (param_keyword_offset) {
12018 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
12019 ID *ids = IBF_R(kw->table, ID, kw->num);
12020 int dv_num = kw->num - kw->required_num;
12021 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
12022 int i;
12023
12024 for (i=0; i<kw->num; i++) {
12025 ids[i] = ibf_load_id(load, ids[i]);
12026 }
12027 for (i=0; i<dv_num; i++) {
12028 dvs[i] = ibf_load_object(load, dvs[i]);
12029 }
12030
12031 kw->table = ids;
12032 kw->default_values = dvs;
12033 return kw;
12034 }
12035 else {
12036 return NULL;
12037 }
12038}
12039
12040static ibf_offset_t
12041ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
12042{
12043 ibf_offset_t offset = ibf_dump_pos(dump);
12044 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
12045
12046 unsigned int i;
12047 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
12048 ibf_dump_write_small_value(dump, entries[i].line_no);
12049#ifdef USE_ISEQ_NODE_ID
12050 ibf_dump_write_small_value(dump, entries[i].node_id);
12051#endif
12052 ibf_dump_write_small_value(dump, entries[i].events);
12053 }
12054
12055 return offset;
12056}
12057
12058static struct iseq_insn_info_entry *
12059ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
12060{
12061 ibf_offset_t reading_pos = body_offset;
12062 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
12063
12064 unsigned int i;
12065 for (i = 0; i < size; i++) {
12066 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
12067#ifdef USE_ISEQ_NODE_ID
12068 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
12069#endif
12070 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
12071 }
12072
12073 return entries;
12074}
12075
12076static ibf_offset_t
12077ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
12078{
12079 ibf_offset_t offset = ibf_dump_pos(dump);
12080
12081 unsigned int last = 0;
12082 unsigned int i;
12083 for (i = 0; i < size; i++) {
12084 ibf_dump_write_small_value(dump, positions[i] - last);
12085 last = positions[i];
12086 }
12087
12088 return offset;
12089}
12090
12091static unsigned int *
12092ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
12093{
12094 ibf_offset_t reading_pos = positions_offset;
12095 unsigned int *positions = ALLOC_N(unsigned int, size);
12096
12097 unsigned int last = 0;
12098 unsigned int i;
12099 for (i = 0; i < size; i++) {
12100 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
12101 last = positions[i];
12102 }
12103
12104 return positions;
12105}
12106
12107static ibf_offset_t
12108ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12109{
12110 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12111 const int size = body->local_table_size;
12112 ID *table = ALLOCA_N(ID, size);
12113 int i;
12114
12115 for (i=0; i<size; i++) {
12116 table[i] = ibf_dump_id(dump, body->local_table[i]);
12117 }
12118
12119 IBF_W_ALIGN(ID);
12120 return ibf_dump_write(dump, table, sizeof(ID) * size);
12121}
12122
12123static ID *
12124ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
12125{
12126 if (size > 0) {
12127 ID *table = IBF_R(local_table_offset, ID, size);
12128 int i;
12129
12130 for (i=0; i<size; i++) {
12131 table[i] = ibf_load_id(load, table[i]);
12132 }
12133 return table;
12134 }
12135 else {
12136 return NULL;
12137 }
12138}
12139
12140static ibf_offset_t
12141ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12142{
12143 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
12144
12145 if (table) {
12146 int *iseq_indices = ALLOCA_N(int, table->size);
12147 unsigned int i;
12148
12149 for (i=0; i<table->size; i++) {
12150 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
12151 }
12152
12153 const ibf_offset_t offset = ibf_dump_pos(dump);
12154
12155 for (i=0; i<table->size; i++) {
12156 ibf_dump_write_small_value(dump, iseq_indices[i]);
12157 ibf_dump_write_small_value(dump, table->entries[i].type);
12158 ibf_dump_write_small_value(dump, table->entries[i].start);
12159 ibf_dump_write_small_value(dump, table->entries[i].end);
12160 ibf_dump_write_small_value(dump, table->entries[i].cont);
12161 ibf_dump_write_small_value(dump, table->entries[i].sp);
12162 }
12163 return offset;
12164 }
12165 else {
12166 return ibf_dump_pos(dump);
12167 }
12168}
12169
12170static struct iseq_catch_table *
12171ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
12172{
12173 if (size) {
12174 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
12175 table->size = size;
12176
12177 ibf_offset_t reading_pos = catch_table_offset;
12178
12179 unsigned int i;
12180 for (i=0; i<table->size; i++) {
12181 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12182 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
12183 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
12184 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
12185 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
12186 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
12187
12188 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
12189 }
12190 return table;
12191 }
12192 else {
12193 return NULL;
12194 }
12195}
12196
12197static ibf_offset_t
12198ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
12199{
12200 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12201 const unsigned int ci_size = body->ci_size;
12202 const struct rb_call_data *cds = body->call_data;
12203
12204 ibf_offset_t offset = ibf_dump_pos(dump);
12205
12206 unsigned int i;
12207
12208 for (i = 0; i < ci_size; i++) {
12209 const struct rb_callinfo *ci = cds[i].ci;
12210 if (ci != NULL) {
12211 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
12212 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
12213 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
12214
12215 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
12216 if (kwarg) {
12217 int len = kwarg->keyword_len;
12218 ibf_dump_write_small_value(dump, len);
12219 for (int j=0; j<len; j++) {
12220 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
12221 ibf_dump_write_small_value(dump, keyword);
12222 }
12223 }
12224 else {
12225 ibf_dump_write_small_value(dump, 0);
12226 }
12227 }
12228 else {
12229 // TODO: truncate NULL ci from call_data.
12230 ibf_dump_write_small_value(dump, (VALUE)-1);
12231 }
12232 }
12233
12234 return offset;
12235}
12236
12238 ID id;
12239 VALUE name;
12240 VALUE val;
12241};
12242
12244 size_t num;
12245 struct outer_variable_pair pairs[1];
12246};
12247
12248static enum rb_id_table_iterator_result
12249store_outer_variable(ID id, VALUE val, void *dump)
12250{
12251 struct outer_variable_list *ovlist = dump;
12252 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
12253 pair->id = id;
12254 pair->name = rb_id2str(id);
12255 pair->val = val;
12256 return ID_TABLE_CONTINUE;
12257}
12258
12259static int
12260outer_variable_cmp(const void *a, const void *b, void *arg)
12261{
12262 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
12263 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
12264 return rb_str_cmp(ap->name, bp->name);
12265}
12266
12267static ibf_offset_t
12268ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
12269{
12270 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
12271
12272 ibf_offset_t offset = ibf_dump_pos(dump);
12273
12274 size_t size = ovs ? rb_id_table_size(ovs) : 0;
12275 ibf_dump_write_small_value(dump, (VALUE)size);
12276 if (size > 0) {
12277 VALUE buff;
12278 size_t buffsize =
12279 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
12280 offsetof(struct outer_variable_list, pairs),
12281 rb_eArgError);
12282 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
12283 ovlist->num = 0;
12284 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
12285 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
12286 for (size_t i = 0; i < size; ++i) {
12287 ID id = ovlist->pairs[i].id;
12288 ID val = ovlist->pairs[i].val;
12289 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
12290 ibf_dump_write_small_value(dump, val);
12291 }
12292 }
12293
12294 return offset;
12295}
12296
12297/* note that we dump out rb_call_info but load back rb_call_data */
12298static void
12299ibf_load_ci_entries(const struct ibf_load *load,
12300 ibf_offset_t ci_entries_offset,
12301 unsigned int ci_size,
12302 struct rb_call_data **cd_ptr)
12303{
12304 ibf_offset_t reading_pos = ci_entries_offset;
12305
12306 unsigned int i;
12307
12308 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
12309 *cd_ptr = cds;
12310
12311 for (i = 0; i < ci_size; i++) {
12312 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
12313 if (mid_index != (VALUE)-1) {
12314 ID mid = ibf_load_id(load, mid_index);
12315 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
12316 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
12317
12318 struct rb_callinfo_kwarg *kwarg = NULL;
12319 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
12320 if (kwlen > 0) {
12321 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
12322 kwarg->references = 0;
12323 kwarg->keyword_len = kwlen;
12324 for (int j=0; j<kwlen; j++) {
12325 VALUE keyword = ibf_load_small_value(load, &reading_pos);
12326 kwarg->keywords[j] = ibf_load_object(load, keyword);
12327 }
12328 }
12329
12330 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
12331 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
12332 cds[i].cc = vm_cc_empty();
12333 }
12334 else {
12335 // NULL ci
12336 cds[i].ci = NULL;
12337 cds[i].cc = NULL;
12338 }
12339 }
12340}
12341
12342static struct rb_id_table *
12343ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
12344{
12345 ibf_offset_t reading_pos = outer_variables_offset;
12346
12347 struct rb_id_table *tbl = NULL;
12348
12349 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
12350
12351 if (table_size > 0) {
12352 tbl = rb_id_table_create(table_size);
12353 }
12354
12355 for (size_t i = 0; i < table_size; i++) {
12356 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
12357 VALUE value = ibf_load_small_value(load, &reading_pos);
12358 if (!key) key = rb_make_temporary_id(i);
12359 rb_id_table_insert(tbl, key, value);
12360 }
12361
12362 return tbl;
12363}
12364
12365static ibf_offset_t
12366ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
12367{
12368 assert(dump->current_buffer == &dump->global_buffer);
12369
12370 unsigned int *positions;
12371
12372 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12373
12374 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
12375 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
12376 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
12377
12378#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12379 ibf_offset_t iseq_start = ibf_dump_pos(dump);
12380
12381 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
12382 struct ibf_dump_buffer buffer;
12383 buffer.str = rb_str_new(0, 0);
12384 buffer.obj_table = ibf_dump_object_table_new();
12385 dump->current_buffer = &buffer;
12386#endif
12387
12388 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
12389 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
12390 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
12391 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
12392 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
12393
12394 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
12395 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
12396 ruby_xfree(positions);
12397
12398 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
12399 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
12400 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
12401 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
12402 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
12403 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
12404 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
12405 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
12406
12407#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12408 ibf_offset_t local_obj_list_offset;
12409 unsigned int local_obj_list_size;
12410
12411 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
12412#endif
12413
12414 ibf_offset_t body_offset = ibf_dump_pos(dump);
12415
12416 /* dump the constant body */
12417 unsigned int param_flags =
12418 (body->param.flags.has_lead << 0) |
12419 (body->param.flags.has_opt << 1) |
12420 (body->param.flags.has_rest << 2) |
12421 (body->param.flags.has_post << 3) |
12422 (body->param.flags.has_kw << 4) |
12423 (body->param.flags.has_kwrest << 5) |
12424 (body->param.flags.has_block << 6) |
12425 (body->param.flags.ambiguous_param0 << 7) |
12426 (body->param.flags.accepts_no_kwarg << 8) |
12427 (body->param.flags.ruby2_keywords << 9);
12428
12429#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12430# define IBF_BODY_OFFSET(x) (x)
12431#else
12432# define IBF_BODY_OFFSET(x) (body_offset - (x))
12433#endif
12434
12435 ibf_dump_write_small_value(dump, body->type);
12436 ibf_dump_write_small_value(dump, body->iseq_size);
12437 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
12438 ibf_dump_write_small_value(dump, bytecode_size);
12439 ibf_dump_write_small_value(dump, param_flags);
12440 ibf_dump_write_small_value(dump, body->param.size);
12441 ibf_dump_write_small_value(dump, body->param.lead_num);
12442 ibf_dump_write_small_value(dump, body->param.opt_num);
12443 ibf_dump_write_small_value(dump, body->param.rest_start);
12444 ibf_dump_write_small_value(dump, body->param.post_start);
12445 ibf_dump_write_small_value(dump, body->param.post_num);
12446 ibf_dump_write_small_value(dump, body->param.block_start);
12447 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
12448 ibf_dump_write_small_value(dump, param_keyword_offset);
12449 ibf_dump_write_small_value(dump, location_pathobj_index);
12450 ibf_dump_write_small_value(dump, location_base_label_index);
12451 ibf_dump_write_small_value(dump, location_label_index);
12452 ibf_dump_write_small_value(dump, body->location.first_lineno);
12453 ibf_dump_write_small_value(dump, body->location.node_id);
12454 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
12455 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
12456 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
12457 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
12458 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
12459 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
12460 ibf_dump_write_small_value(dump, body->insns_info.size);
12461 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
12462 ibf_dump_write_small_value(dump, catch_table_size);
12463 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
12464 ibf_dump_write_small_value(dump, parent_iseq_index);
12465 ibf_dump_write_small_value(dump, local_iseq_index);
12466 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
12467 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
12468 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
12469 ibf_dump_write_small_value(dump, body->variable.flip_count);
12470 ibf_dump_write_small_value(dump, body->local_table_size);
12471 ibf_dump_write_small_value(dump, body->ivc_size);
12472 ibf_dump_write_small_value(dump, body->icvarc_size);
12473 ibf_dump_write_small_value(dump, body->ise_size);
12474 ibf_dump_write_small_value(dump, body->ic_size);
12475 ibf_dump_write_small_value(dump, body->ci_size);
12476 ibf_dump_write_small_value(dump, body->stack_max);
12477 ibf_dump_write_small_value(dump, body->builtin_attrs);
12478
12479#undef IBF_BODY_OFFSET
12480
12481#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12482 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
12483
12484 dump->current_buffer = saved_buffer;
12485 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
12486
12487 ibf_offset_t offset = ibf_dump_pos(dump);
12488 ibf_dump_write_small_value(dump, iseq_start);
12489 ibf_dump_write_small_value(dump, iseq_length_bytes);
12490 ibf_dump_write_small_value(dump, body_offset);
12491
12492 ibf_dump_write_small_value(dump, local_obj_list_offset);
12493 ibf_dump_write_small_value(dump, local_obj_list_size);
12494
12495 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
12496
12497 return offset;
12498#else
12499 return body_offset;
12500#endif
12501}
12502
12503static VALUE
12504ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
12505{
12506 VALUE str = ibf_load_object(load, str_index);
12507 if (str != Qnil) {
12508 str = rb_fstring(str);
12509 }
12510 return str;
12511}
12512
12513static void
12514ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
12515{
12516 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
12517
12518 ibf_offset_t reading_pos = offset;
12519
12520#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12521 struct ibf_load_buffer *saved_buffer = load->current_buffer;
12522 load->current_buffer = &load->global_buffer;
12523
12524 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12525 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12526 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12527
12528 struct ibf_load_buffer buffer;
12529 buffer.buff = load->global_buffer.buff + iseq_start;
12530 buffer.size = iseq_length_bytes;
12531 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12532 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12533 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
12534
12535 load->current_buffer = &buffer;
12536 reading_pos = body_offset;
12537#endif
12538
12539#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12540# define IBF_BODY_OFFSET(x) (x)
12541#else
12542# define IBF_BODY_OFFSET(x) (offset - (x))
12543#endif
12544
12545 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
12546 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12547 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12548 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12549 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
12550 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12551 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
12552 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
12553 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
12554 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
12555 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
12556 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
12557 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12558 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12559 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
12560 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
12561 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
12562 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
12563 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
12564 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12565 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12566 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12567 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12568 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12569 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12570 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12571 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12572 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12573 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12574 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12575 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12576 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12577 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12578 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12579 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
12580 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12581
12582 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12583 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12584 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12585 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12586
12587 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12588 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
12589 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
12590
12591 // setup fname and dummy frame
12592 VALUE path = ibf_load_object(load, location_pathobj_index);
12593 {
12594 VALUE realpath = Qnil;
12595
12596 if (RB_TYPE_P(path, T_STRING)) {
12597 realpath = path = rb_fstring(path);
12598 }
12599 else if (RB_TYPE_P(path, T_ARRAY)) {
12600 VALUE pathobj = path;
12601 if (RARRAY_LEN(pathobj) != 2) {
12602 rb_raise(rb_eRuntimeError, "path object size mismatch");
12603 }
12604 path = rb_fstring(RARRAY_AREF(pathobj, 0));
12605 realpath = RARRAY_AREF(pathobj, 1);
12606 if (!NIL_P(realpath)) {
12607 if (!RB_TYPE_P(realpath, T_STRING)) {
12608 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
12609 "(%x), path=%+"PRIsVALUE,
12610 realpath, TYPE(realpath), path);
12611 }
12612 realpath = rb_fstring(realpath);
12613 }
12614 }
12615 else {
12616 rb_raise(rb_eRuntimeError, "unexpected path object");
12617 }
12618 rb_iseq_pathobj_set(iseq, path, realpath);
12619 }
12620
12621 // push dummy frame
12622 rb_execution_context_t *ec = GET_EC();
12623 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
12624
12625#undef IBF_BODY_OFFSET
12626
12627 load_body->type = type;
12628 load_body->stack_max = stack_max;
12629 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
12630 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
12631 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
12632 load_body->param.flags.has_post = (param_flags >> 3) & 1;
12633 load_body->param.flags.has_kw = FALSE;
12634 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
12635 load_body->param.flags.has_block = (param_flags >> 6) & 1;
12636 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
12637 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
12638 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
12639 load_body->param.size = param_size;
12640 load_body->param.lead_num = param_lead_num;
12641 load_body->param.opt_num = param_opt_num;
12642 load_body->param.rest_start = param_rest_start;
12643 load_body->param.post_start = param_post_start;
12644 load_body->param.post_num = param_post_num;
12645 load_body->param.block_start = param_block_start;
12646 load_body->local_table_size = local_table_size;
12647 load_body->ci_size = ci_size;
12648 load_body->insns_info.size = insns_info_size;
12649
12650 ISEQ_COVERAGE_SET(iseq, Qnil);
12651 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
12652 load_body->variable.flip_count = variable_flip_count;
12653 load_body->variable.script_lines = Qnil;
12654
12655 load_body->location.first_lineno = location_first_lineno;
12656 load_body->location.node_id = location_node_id;
12657 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
12658 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
12659 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
12660 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
12661 load_body->builtin_attrs = builtin_attrs;
12662
12663 load_body->ivc_size = ivc_size;
12664 load_body->icvarc_size = icvarc_size;
12665 load_body->ise_size = ise_size;
12666 load_body->ic_size = ic_size;
12667
12668 if (ISEQ_IS_SIZE(load_body)) {
12669 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
12670 }
12671 else {
12672 load_body->is_entries = NULL;
12673 }
12674 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
12675 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
12676 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
12677 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
12678 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
12679 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
12680 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
12681 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
12682 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
12683 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
12684 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
12685 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
12686
12687 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
12688#if VM_INSN_INFO_TABLE_IMPL == 2
12689 rb_iseq_insns_info_encode_positions(iseq);
12690#endif
12691
12692 rb_iseq_translate_threaded_code(iseq);
12693
12694#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12695 load->current_buffer = &load->global_buffer;
12696#endif
12697
12698 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
12699 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
12700
12701#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12702 load->current_buffer = saved_buffer;
12703#endif
12704 verify_call_cache(iseq);
12705
12706 RB_GC_GUARD(dummy_frame);
12707 rb_vm_pop_frame_no_int(ec);
12708}
12709
12711{
12712 struct ibf_dump *dump;
12713 VALUE offset_list;
12714};
12715
12716static int
12717ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12718{
12719 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
12720 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
12721
12722 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
12723 rb_ary_push(args->offset_list, UINT2NUM(offset));
12724
12725 return ST_CONTINUE;
12726}
12727
12728static void
12729ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
12730{
12731 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
12732
12733 struct ibf_dump_iseq_list_arg args;
12734 args.dump = dump;
12735 args.offset_list = offset_list;
12736
12737 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
12738
12739 st_index_t i;
12740 st_index_t size = dump->iseq_table->num_entries;
12741 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
12742
12743 for (i = 0; i < size; i++) {
12744 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
12745 }
12746
12747 ibf_dump_align(dump, sizeof(ibf_offset_t));
12748 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
12749 header->iseq_list_size = (unsigned int)size;
12750}
12751
12752#define IBF_OBJECT_INTERNAL FL_PROMOTED0
12753
12754/*
12755 * Binary format
12756 * - ibf_object_header
12757 * - ibf_object_xxx (xxx is type)
12758 */
12759
12761 unsigned int type: 5;
12762 unsigned int special_const: 1;
12763 unsigned int frozen: 1;
12764 unsigned int internal: 1;
12765};
12766
12767enum ibf_object_class_index {
12768 IBF_OBJECT_CLASS_OBJECT,
12769 IBF_OBJECT_CLASS_ARRAY,
12770 IBF_OBJECT_CLASS_STANDARD_ERROR,
12771 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
12772 IBF_OBJECT_CLASS_TYPE_ERROR,
12773 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
12774};
12775
12777 long srcstr;
12778 char option;
12779};
12780
12782 long len;
12783 long keyval[FLEX_ARY_LEN];
12784};
12785
12787 long class_index;
12788 long len;
12789 long beg;
12790 long end;
12791 int excl;
12792};
12793
12795 ssize_t slen;
12796 BDIGIT digits[FLEX_ARY_LEN];
12797};
12798
12799enum ibf_object_data_type {
12800 IBF_OBJECT_DATA_ENCODING,
12801};
12802
12804 long a, b;
12805};
12806
12808 long str;
12809};
12810
12811#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
12812 ((((offset) - 1) / (align) + 1) * (align))
12813#define IBF_OBJBODY(type, offset) (const type *)\
12814 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12815
12816static const void *
12817ibf_load_check_offset(const struct ibf_load *load, size_t offset)
12818{
12819 if (offset >= load->current_buffer->size) {
12820 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
12821 }
12822 return load->current_buffer->buff + offset;
12823}
12824
12825NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
12826
12827static void
12828ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
12829{
12830 char buff[0x100];
12831 rb_raw_obj_info(buff, sizeof(buff), obj);
12832 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
12833}
12834
12835NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
12836
12837static VALUE
12838ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12839{
12840 rb_raise(rb_eArgError, "unsupported");
12842}
12843
12844static void
12845ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
12846{
12847 enum ibf_object_class_index cindex;
12848 if (obj == rb_cObject) {
12849 cindex = IBF_OBJECT_CLASS_OBJECT;
12850 }
12851 else if (obj == rb_cArray) {
12852 cindex = IBF_OBJECT_CLASS_ARRAY;
12853 }
12854 else if (obj == rb_eStandardError) {
12855 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12856 }
12857 else if (obj == rb_eNoMatchingPatternError) {
12858 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12859 }
12860 else if (obj == rb_eTypeError) {
12861 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12862 }
12863 else if (obj == rb_eNoMatchingPatternKeyError) {
12864 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12865 }
12866 else {
12867 rb_obj_info_dump(obj);
12868 rb_p(obj);
12869 rb_bug("unsupported class");
12870 }
12871 ibf_dump_write_small_value(dump, (VALUE)cindex);
12872}
12873
12874static VALUE
12875ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12876{
12877 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12878
12879 switch (cindex) {
12880 case IBF_OBJECT_CLASS_OBJECT:
12881 return rb_cObject;
12882 case IBF_OBJECT_CLASS_ARRAY:
12883 return rb_cArray;
12884 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12885 return rb_eStandardError;
12886 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12888 case IBF_OBJECT_CLASS_TYPE_ERROR:
12889 return rb_eTypeError;
12890 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12892 }
12893
12894 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
12895}
12896
12897
12898static void
12899ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
12900{
12901 double dbl = RFLOAT_VALUE(obj);
12902 (void)IBF_W(&dbl, double, 1);
12903}
12904
12905static VALUE
12906ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12907{
12908 const double *dblp = IBF_OBJBODY(double, offset);
12909 return DBL2NUM(*dblp);
12910}
12911
12912static void
12913ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
12914{
12915 long encindex = (long)rb_enc_get_index(obj);
12916 long len = RSTRING_LEN(obj);
12917 const char *ptr = RSTRING_PTR(obj);
12918
12919 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12920 rb_encoding *enc = rb_enc_from_index((int)encindex);
12921 const char *enc_name = rb_enc_name(enc);
12922 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
12923 }
12924
12925 ibf_dump_write_small_value(dump, encindex);
12926 ibf_dump_write_small_value(dump, len);
12927 IBF_WP(ptr, char, len);
12928}
12929
12930static VALUE
12931ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12932{
12933 ibf_offset_t reading_pos = offset;
12934
12935 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12936 const long len = (long)ibf_load_small_value(load, &reading_pos);
12937 const char *ptr = load->current_buffer->buff + reading_pos;
12938
12939 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12940 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12941 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12942 }
12943
12944 VALUE str;
12945 if (header->frozen && !header->internal) {
12946 str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
12947 }
12948 else {
12949 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
12950
12951 if (header->internal) rb_obj_hide(str);
12952 if (header->frozen) str = rb_fstring(str);
12953 }
12954 return str;
12955}
12956
12957static void
12958ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
12959{
12960 VALUE srcstr = RREGEXP_SRC(obj);
12961 struct ibf_object_regexp regexp;
12962 regexp.option = (char)rb_reg_options(obj);
12963 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12964
12965 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
12966 ibf_dump_write_small_value(dump, regexp.srcstr);
12967}
12968
12969static VALUE
12970ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12971{
12972 struct ibf_object_regexp regexp;
12973 regexp.option = ibf_load_byte(load, &offset);
12974 regexp.srcstr = ibf_load_small_value(load, &offset);
12975
12976 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12977 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
12978
12979 if (header->internal) rb_obj_hide(reg);
12980 if (header->frozen) rb_obj_freeze(reg);
12981
12982 return reg;
12983}
12984
12985static void
12986ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
12987{
12988 long i, len = RARRAY_LEN(obj);
12989 ibf_dump_write_small_value(dump, len);
12990 for (i=0; i<len; i++) {
12991 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
12992 ibf_dump_write_small_value(dump, index);
12993 }
12994}
12995
12996static VALUE
12997ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12998{
12999 ibf_offset_t reading_pos = offset;
13000
13001 const long len = (long)ibf_load_small_value(load, &reading_pos);
13002
13003 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
13004 int i;
13005
13006 for (i=0; i<len; i++) {
13007 const VALUE index = ibf_load_small_value(load, &reading_pos);
13008 rb_ary_push(ary, ibf_load_object(load, index));
13009 }
13010
13011 if (header->frozen) rb_obj_freeze(ary);
13012
13013 return ary;
13014}
13015
13016static int
13017ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
13018{
13019 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13020
13021 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
13022 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
13023
13024 ibf_dump_write_small_value(dump, key_index);
13025 ibf_dump_write_small_value(dump, val_index);
13026 return ST_CONTINUE;
13027}
13028
13029static void
13030ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
13031{
13032 long len = RHASH_SIZE(obj);
13033 ibf_dump_write_small_value(dump, (VALUE)len);
13034
13035 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
13036}
13037
13038static VALUE
13039ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13040{
13041 long len = (long)ibf_load_small_value(load, &offset);
13042 VALUE obj = rb_hash_new_with_size(len);
13043 int i;
13044
13045 for (i = 0; i < len; i++) {
13046 VALUE key_index = ibf_load_small_value(load, &offset);
13047 VALUE val_index = ibf_load_small_value(load, &offset);
13048
13049 VALUE key = ibf_load_object(load, key_index);
13050 VALUE val = ibf_load_object(load, val_index);
13051 rb_hash_aset(obj, key, val);
13052 }
13053 rb_hash_rehash(obj);
13054
13055 if (header->internal) rb_obj_hide(obj);
13056 if (header->frozen) rb_obj_freeze(obj);
13057
13058 return obj;
13059}
13060
13061static void
13062ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
13063{
13064 if (rb_obj_is_kind_of(obj, rb_cRange)) {
13065 struct ibf_object_struct_range range;
13066 VALUE beg, end;
13067 IBF_ZERO(range);
13068 range.len = 3;
13069 range.class_index = 0;
13070
13071 rb_range_values(obj, &beg, &end, &range.excl);
13072 range.beg = (long)ibf_dump_object(dump, beg);
13073 range.end = (long)ibf_dump_object(dump, end);
13074
13075 IBF_W_ALIGN(struct ibf_object_struct_range);
13076 IBF_WV(range);
13077 }
13078 else {
13079 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
13080 rb_class_name(CLASS_OF(obj)));
13081 }
13082}
13083
13084static VALUE
13085ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13086{
13087 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
13088 VALUE beg = ibf_load_object(load, range->beg);
13089 VALUE end = ibf_load_object(load, range->end);
13090 VALUE obj = rb_range_new(beg, end, range->excl);
13091 if (header->internal) rb_obj_hide(obj);
13092 if (header->frozen) rb_obj_freeze(obj);
13093 return obj;
13094}
13095
13096static void
13097ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
13098{
13099 ssize_t len = BIGNUM_LEN(obj);
13100 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
13101 BDIGIT *d = BIGNUM_DIGITS(obj);
13102
13103 (void)IBF_W(&slen, ssize_t, 1);
13104 IBF_WP(d, BDIGIT, len);
13105}
13106
13107static VALUE
13108ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13109{
13110 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
13111 int sign = bignum->slen > 0;
13112 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
13113 const int big_unpack_flags = /* c.f. rb_big_unpack() */
13116 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
13117 big_unpack_flags |
13118 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
13119 if (header->internal) rb_obj_hide(obj);
13120 if (header->frozen) rb_obj_freeze(obj);
13121 return obj;
13122}
13123
13124static void
13125ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
13126{
13127 if (rb_data_is_encoding(obj)) {
13128 rb_encoding *enc = rb_to_encoding(obj);
13129 const char *name = rb_enc_name(enc);
13130 long len = strlen(name) + 1;
13131 long data[2];
13132 data[0] = IBF_OBJECT_DATA_ENCODING;
13133 data[1] = len;
13134 (void)IBF_W(data, long, 2);
13135 IBF_WP(name, char, len);
13136 }
13137 else {
13138 ibf_dump_object_unsupported(dump, obj);
13139 }
13140}
13141
13142static VALUE
13143ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13144{
13145 const long *body = IBF_OBJBODY(long, offset);
13146 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
13147 /* const long len = body[1]; */
13148 const char *data = (const char *)&body[2];
13149
13150 switch (type) {
13151 case IBF_OBJECT_DATA_ENCODING:
13152 {
13153 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
13154 return encobj;
13155 }
13156 }
13157
13158 return ibf_load_object_unsupported(load, header, offset);
13159}
13160
13161static void
13162ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
13163{
13164 long data[2];
13165 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
13166 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
13167
13168 (void)IBF_W(data, long, 2);
13169}
13170
13171static VALUE
13172ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13173{
13174 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
13175 VALUE a = ibf_load_object(load, nums->a);
13176 VALUE b = ibf_load_object(load, nums->b);
13177 VALUE obj = header->type == T_COMPLEX ?
13178 rb_complex_new(a, b) : rb_rational_new(a, b);
13179
13180 if (header->internal) rb_obj_hide(obj);
13181 if (header->frozen) rb_obj_freeze(obj);
13182 return obj;
13183}
13184
13185static void
13186ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
13187{
13188 ibf_dump_object_string(dump, rb_sym2str(obj));
13189}
13190
13191static VALUE
13192ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13193{
13194 ibf_offset_t reading_pos = offset;
13195
13196 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13197 const long len = (long)ibf_load_small_value(load, &reading_pos);
13198 const char *ptr = load->current_buffer->buff + reading_pos;
13199
13200 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13201 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13202 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13203 }
13204
13205 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
13206 return ID2SYM(id);
13207}
13208
13209typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
13210static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
13211 ibf_dump_object_unsupported, /* T_NONE */
13212 ibf_dump_object_unsupported, /* T_OBJECT */
13213 ibf_dump_object_class, /* T_CLASS */
13214 ibf_dump_object_unsupported, /* T_MODULE */
13215 ibf_dump_object_float, /* T_FLOAT */
13216 ibf_dump_object_string, /* T_STRING */
13217 ibf_dump_object_regexp, /* T_REGEXP */
13218 ibf_dump_object_array, /* T_ARRAY */
13219 ibf_dump_object_hash, /* T_HASH */
13220 ibf_dump_object_struct, /* T_STRUCT */
13221 ibf_dump_object_bignum, /* T_BIGNUM */
13222 ibf_dump_object_unsupported, /* T_FILE */
13223 ibf_dump_object_data, /* T_DATA */
13224 ibf_dump_object_unsupported, /* T_MATCH */
13225 ibf_dump_object_complex_rational, /* T_COMPLEX */
13226 ibf_dump_object_complex_rational, /* T_RATIONAL */
13227 ibf_dump_object_unsupported, /* 0x10 */
13228 ibf_dump_object_unsupported, /* 0x11 T_NIL */
13229 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
13230 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
13231 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
13232 ibf_dump_object_unsupported, /* T_FIXNUM */
13233 ibf_dump_object_unsupported, /* T_UNDEF */
13234 ibf_dump_object_unsupported, /* 0x17 */
13235 ibf_dump_object_unsupported, /* 0x18 */
13236 ibf_dump_object_unsupported, /* 0x19 */
13237 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
13238 ibf_dump_object_unsupported, /* T_NODE 0x1b */
13239 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
13240 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
13241 ibf_dump_object_unsupported, /* 0x1e */
13242 ibf_dump_object_unsupported, /* 0x1f */
13243};
13244
13245static void
13246ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
13247{
13248 unsigned char byte =
13249 (header.type << 0) |
13250 (header.special_const << 5) |
13251 (header.frozen << 6) |
13252 (header.internal << 7);
13253
13254 IBF_WV(byte);
13255}
13256
13257static struct ibf_object_header
13258ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
13259{
13260 unsigned char byte = ibf_load_byte(load, offset);
13261
13262 struct ibf_object_header header;
13263 header.type = (byte >> 0) & 0x1f;
13264 header.special_const = (byte >> 5) & 0x01;
13265 header.frozen = (byte >> 6) & 0x01;
13266 header.internal = (byte >> 7) & 0x01;
13267
13268 return header;
13269}
13270
13271static ibf_offset_t
13272ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
13273{
13274 struct ibf_object_header obj_header;
13275 ibf_offset_t current_offset;
13276 IBF_ZERO(obj_header);
13277 obj_header.type = TYPE(obj);
13278
13279 IBF_W_ALIGN(ibf_offset_t);
13280 current_offset = ibf_dump_pos(dump);
13281
13282 if (SPECIAL_CONST_P(obj) &&
13283 ! (SYMBOL_P(obj) ||
13284 RB_FLOAT_TYPE_P(obj))) {
13285 obj_header.special_const = TRUE;
13286 obj_header.frozen = TRUE;
13287 obj_header.internal = TRUE;
13288 ibf_dump_object_object_header(dump, obj_header);
13289 ibf_dump_write_small_value(dump, obj);
13290 }
13291 else {
13292 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
13293 obj_header.special_const = FALSE;
13294 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
13295 ibf_dump_object_object_header(dump, obj_header);
13296 (*dump_object_functions[obj_header.type])(dump, obj);
13297 }
13298
13299 return current_offset;
13300}
13301
13302typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
13303static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
13304 ibf_load_object_unsupported, /* T_NONE */
13305 ibf_load_object_unsupported, /* T_OBJECT */
13306 ibf_load_object_class, /* T_CLASS */
13307 ibf_load_object_unsupported, /* T_MODULE */
13308 ibf_load_object_float, /* T_FLOAT */
13309 ibf_load_object_string, /* T_STRING */
13310 ibf_load_object_regexp, /* T_REGEXP */
13311 ibf_load_object_array, /* T_ARRAY */
13312 ibf_load_object_hash, /* T_HASH */
13313 ibf_load_object_struct, /* T_STRUCT */
13314 ibf_load_object_bignum, /* T_BIGNUM */
13315 ibf_load_object_unsupported, /* T_FILE */
13316 ibf_load_object_data, /* T_DATA */
13317 ibf_load_object_unsupported, /* T_MATCH */
13318 ibf_load_object_complex_rational, /* T_COMPLEX */
13319 ibf_load_object_complex_rational, /* T_RATIONAL */
13320 ibf_load_object_unsupported, /* 0x10 */
13321 ibf_load_object_unsupported, /* T_NIL */
13322 ibf_load_object_unsupported, /* T_TRUE */
13323 ibf_load_object_unsupported, /* T_FALSE */
13324 ibf_load_object_symbol,
13325 ibf_load_object_unsupported, /* T_FIXNUM */
13326 ibf_load_object_unsupported, /* T_UNDEF */
13327 ibf_load_object_unsupported, /* 0x17 */
13328 ibf_load_object_unsupported, /* 0x18 */
13329 ibf_load_object_unsupported, /* 0x19 */
13330 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
13331 ibf_load_object_unsupported, /* T_NODE 0x1b */
13332 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
13333 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
13334 ibf_load_object_unsupported, /* 0x1e */
13335 ibf_load_object_unsupported, /* 0x1f */
13336};
13337
13338static VALUE
13339ibf_load_object(const struct ibf_load *load, VALUE object_index)
13340{
13341 if (object_index == 0) {
13342 return Qnil;
13343 }
13344 else {
13345 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
13346 if (!obj) {
13347 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
13348 ibf_offset_t offset = offsets[object_index];
13349 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
13350
13351#if IBF_ISEQ_DEBUG
13352 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
13353 load->current_buffer->obj_list_offset, (void *)offsets, offset);
13354 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
13355 header.type, header.special_const, header.frozen, header.internal);
13356#endif
13357 if (offset >= load->current_buffer->size) {
13358 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
13359 }
13360
13361 if (header.special_const) {
13362 ibf_offset_t reading_pos = offset;
13363
13364 obj = ibf_load_small_value(load, &reading_pos);
13365 }
13366 else {
13367 obj = (*load_object_functions[header.type])(load, &header, offset);
13368 }
13369
13370 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
13371 }
13372#if IBF_ISEQ_DEBUG
13373 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
13374 object_index, obj);
13375#endif
13376 return obj;
13377 }
13378}
13379
13381{
13382 struct ibf_dump *dump;
13383 VALUE offset_list;
13384};
13385
13386static int
13387ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13388{
13389 VALUE obj = (VALUE)key;
13390 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
13391
13392 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
13393 rb_ary_push(args->offset_list, UINT2NUM(offset));
13394
13395 return ST_CONTINUE;
13396}
13397
13398static void
13399ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
13400{
13401 st_table *obj_table = dump->current_buffer->obj_table;
13402 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
13403
13404 struct ibf_dump_object_list_arg args;
13405 args.dump = dump;
13406 args.offset_list = offset_list;
13407
13408 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
13409
13410 IBF_W_ALIGN(ibf_offset_t);
13411 *obj_list_offset = ibf_dump_pos(dump);
13412
13413 st_index_t size = obj_table->num_entries;
13414 st_index_t i;
13415
13416 for (i=0; i<size; i++) {
13417 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
13418 IBF_WV(offset);
13419 }
13420
13421 *obj_list_size = (unsigned int)size;
13422}
13423
13424static void
13425ibf_dump_mark(void *ptr)
13426{
13427 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13428 rb_gc_mark(dump->global_buffer.str);
13429
13430 rb_mark_set(dump->global_buffer.obj_table);
13431 rb_mark_set(dump->iseq_table);
13432}
13433
13434static void
13435ibf_dump_free(void *ptr)
13436{
13437 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13438 if (dump->global_buffer.obj_table) {
13439 st_free_table(dump->global_buffer.obj_table);
13440 dump->global_buffer.obj_table = 0;
13441 }
13442 if (dump->iseq_table) {
13443 st_free_table(dump->iseq_table);
13444 dump->iseq_table = 0;
13445 }
13446}
13447
13448static size_t
13449ibf_dump_memsize(const void *ptr)
13450{
13451 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13452 size_t size = 0;
13453 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
13454 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
13455 return size;
13456}
13457
13458static const rb_data_type_t ibf_dump_type = {
13459 "ibf_dump",
13460 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
13461 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
13462};
13463
13464static void
13465ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
13466{
13467 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
13468 dump->iseq_table = NULL;
13469
13470 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
13471 dump->global_buffer.obj_table = ibf_dump_object_table_new();
13472 dump->iseq_table = st_init_numtable(); /* need free */
13473
13474 dump->current_buffer = &dump->global_buffer;
13475}
13476
13477VALUE
13478rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
13479{
13480 struct ibf_dump *dump;
13481 struct ibf_header header = {{0}};
13482 VALUE dump_obj;
13483 VALUE str;
13484
13485 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
13486 ISEQ_BODY(iseq)->local_iseq != iseq) {
13487 rb_raise(rb_eRuntimeError, "should be top of iseq");
13488 }
13489 if (RTEST(ISEQ_COVERAGE(iseq))) {
13490 rb_raise(rb_eRuntimeError, "should not compile with coverage");
13491 }
13492
13493 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
13494 ibf_dump_setup(dump, dump_obj);
13495
13496 ibf_dump_write(dump, &header, sizeof(header));
13497 ibf_dump_iseq(dump, iseq);
13498
13499 header.magic[0] = 'Y'; /* YARB */
13500 header.magic[1] = 'A';
13501 header.magic[2] = 'R';
13502 header.magic[3] = 'B';
13503 header.major_version = IBF_MAJOR_VERSION;
13504 header.minor_version = IBF_MINOR_VERSION;
13505 header.endian = IBF_ENDIAN_MARK;
13506 header.wordsize = (uint8_t)SIZEOF_VALUE;
13507 ibf_dump_iseq_list(dump, &header);
13508 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
13509 header.size = ibf_dump_pos(dump);
13510
13511 if (RTEST(opt)) {
13512 VALUE opt_str = opt;
13513 const char *ptr = StringValuePtr(opt_str);
13514 header.extra_size = RSTRING_LENINT(opt_str);
13515 ibf_dump_write(dump, ptr, header.extra_size);
13516 }
13517 else {
13518 header.extra_size = 0;
13519 }
13520
13521 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
13522
13523 str = dump->global_buffer.str;
13524 RB_GC_GUARD(dump_obj);
13525 return str;
13526}
13527
13528static const ibf_offset_t *
13529ibf_iseq_list(const struct ibf_load *load)
13530{
13531 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
13532}
13533
13534void
13535rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
13536{
13537 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
13538 rb_iseq_t *prev_src_iseq = load->iseq;
13539 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
13540 load->iseq = iseq;
13541#if IBF_ISEQ_DEBUG
13542 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
13543 iseq->aux.loader.index, offset,
13544 load->header->size);
13545#endif
13546 ibf_load_iseq_each(load, iseq, offset);
13547 ISEQ_COMPILE_DATA_CLEAR(iseq);
13548 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13549 rb_iseq_init_trace(iseq);
13550 load->iseq = prev_src_iseq;
13551}
13552
13553#if USE_LAZY_LOAD
13554const rb_iseq_t *
13555rb_iseq_complete(const rb_iseq_t *iseq)
13556{
13557 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
13558 return iseq;
13559}
13560#endif
13561
13562static rb_iseq_t *
13563ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
13564{
13565 int iseq_index = (int)(VALUE)index_iseq;
13566
13567#if IBF_ISEQ_DEBUG
13568 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
13569 (void *)index_iseq, (void *)load->iseq_list);
13570#endif
13571 if (iseq_index == -1) {
13572 return NULL;
13573 }
13574 else {
13575 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
13576
13577#if IBF_ISEQ_DEBUG
13578 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
13579#endif
13580 if (iseqv) {
13581 return (rb_iseq_t *)iseqv;
13582 }
13583 else {
13584 rb_iseq_t *iseq = iseq_imemo_alloc();
13585#if IBF_ISEQ_DEBUG
13586 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
13587#endif
13588 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13589 iseq->aux.loader.obj = load->loader_obj;
13590 iseq->aux.loader.index = iseq_index;
13591#if IBF_ISEQ_DEBUG
13592 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
13593 (void *)iseq, (void *)load->loader_obj, iseq_index);
13594#endif
13595 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
13596
13597 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
13598#if IBF_ISEQ_DEBUG
13599 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
13600#endif
13601 rb_ibf_load_iseq_complete(iseq);
13602 }
13603
13604#if IBF_ISEQ_DEBUG
13605 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
13606 (void *)iseq, (void *)load->iseq);
13607#endif
13608 return iseq;
13609 }
13610 }
13611}
13612
13613static void
13614ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
13615{
13616 struct ibf_header *header = (struct ibf_header *)bytes;
13617 load->loader_obj = loader_obj;
13618 load->global_buffer.buff = bytes;
13619 load->header = header;
13620 load->global_buffer.size = header->size;
13621 load->global_buffer.obj_list_offset = header->global_object_list_offset;
13622 load->global_buffer.obj_list_size = header->global_object_list_size;
13623 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
13624 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
13625 load->iseq = NULL;
13626
13627 load->current_buffer = &load->global_buffer;
13628
13629 if (size < header->size) {
13630 rb_raise(rb_eRuntimeError, "broken binary format");
13631 }
13632 if (strncmp(header->magic, "YARB", 4) != 0) {
13633 rb_raise(rb_eRuntimeError, "unknown binary format");
13634 }
13635 if (header->major_version != IBF_MAJOR_VERSION ||
13636 header->minor_version != IBF_MINOR_VERSION) {
13637 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
13638 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
13639 }
13640 if (header->endian != IBF_ENDIAN_MARK) {
13641 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
13642 }
13643 if (header->wordsize != SIZEOF_VALUE) {
13644 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
13645 }
13646 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13647 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
13648 header->iseq_list_offset);
13649 }
13650 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13651 rb_raise(rb_eArgError, "unaligned object list offset: %u",
13652 load->global_buffer.obj_list_offset);
13653 }
13654}
13655
13656static void
13657ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
13658{
13659 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
13660 rb_raise(rb_eRuntimeError, "broken binary format");
13661 }
13662
13663 if (USE_LAZY_LOAD) {
13664 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
13665 }
13666
13667 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
13668 RB_OBJ_WRITE(loader_obj, &load->str, str);
13669}
13670
13671static void
13672ibf_loader_mark(void *ptr)
13673{
13674 struct ibf_load *load = (struct ibf_load *)ptr;
13675 rb_gc_mark(load->str);
13676 rb_gc_mark(load->iseq_list);
13677 rb_gc_mark(load->global_buffer.obj_list);
13678}
13679
13680static void
13681ibf_loader_free(void *ptr)
13682{
13683 struct ibf_load *load = (struct ibf_load *)ptr;
13684 ruby_xfree(load);
13685}
13686
13687static size_t
13688ibf_loader_memsize(const void *ptr)
13689{
13690 return sizeof(struct ibf_load);
13691}
13692
13693static const rb_data_type_t ibf_load_type = {
13694 "ibf_loader",
13695 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
13696 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13697};
13698
13699const rb_iseq_t *
13700rb_iseq_ibf_load(VALUE str)
13701{
13702 struct ibf_load *load;
13703 rb_iseq_t *iseq;
13704 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13705
13706 ibf_load_setup(load, loader_obj, str);
13707 iseq = ibf_load_iseq(load, 0);
13708
13709 RB_GC_GUARD(loader_obj);
13710 return iseq;
13711}
13712
13713const rb_iseq_t *
13714rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
13715{
13716 struct ibf_load *load;
13717 rb_iseq_t *iseq;
13718 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13719
13720 ibf_load_setup_bytes(load, loader_obj, bytes, size);
13721 iseq = ibf_load_iseq(load, 0);
13722
13723 RB_GC_GUARD(loader_obj);
13724 return iseq;
13725}
13726
13727VALUE
13728rb_iseq_ibf_load_extra_data(VALUE str)
13729{
13730 struct ibf_load *load;
13731 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13732 VALUE extra_str;
13733
13734 ibf_load_setup(load, loader_obj, str);
13735 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
13736 RB_GC_GUARD(loader_obj);
13737 return extra_str;
13738}
13739
13740#include "prism_compile.c"
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:177
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:107
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:397
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:398
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:396
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:395
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:129
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:67
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:133
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:400
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:482
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1354
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1341
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1357
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:699
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1358
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1346
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1361
VALUE rb_cArray
Array class.
Definition array.c:39
VALUE rb_cNumeric
Numeric class.
Definition numeric.c:196
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:636
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:821
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:631
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:619
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
Definition string.c:12027
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1038
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1062
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1656
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:67
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4138
VALUE rb_sym_to_s(VALUE sym)
This is an rb_sym2str() + rb_str_dup() combo.
Definition string.c:11659
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1496
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:3598
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:3587
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:3654
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:3473
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:2972
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1854
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:402
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition symbol.c:950
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:897
int len
Length of the buffer.
Definition io.h:8
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:366
#define ALLOCA_N(type, n)
Definition memory.h:286
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:298
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:152
#define Data_Wrap_Struct(klass, mark, free, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rdata.h:202
#define DATA_PTR(obj)
Convenient getter macro.
Definition rdata.h:71
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:82
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8976
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:28
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:267
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:259
Definition vm_core.h:262
Definition iseq.h:238
This struct represents the overall parser.
Definition parser.h:489
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
struct rb_iseq_constant_body::@152 param
parameter information
Definition st.h:79
Definition vm_core.h:271
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:263
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:144