Ruby 3.5.0dev (2025-10-09 revision fa409d5f3af507a1e4f31642924dd694f37b1c33)
compile.c (fa409d5f3af507a1e4f31642924dd694f37b1c33)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
498
499static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
500static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
501
502/*
503 * To make Array to LinkedList, use link_anchor
504 */
505
506static void
507verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
508{
509#if CPDEBUG
510 int flag = 0;
511 LINK_ELEMENT *list, *plist;
512
513 if (!compile_debug) return;
514
515 list = anchor->anchor.next;
516 plist = &anchor->anchor;
517 while (list) {
518 if (plist != list->prev) {
519 flag += 1;
520 }
521 plist = list;
522 list = list->next;
523 }
524
525 if (anchor->last != plist && anchor->last != 0) {
526 flag |= 0x70000;
527 }
528
529 if (flag != 0) {
530 rb_bug("list verify error: %08x (%s)", flag, info);
531 }
532#endif
533}
534#if CPDEBUG < 0
535#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
536#endif
537
538static void
539verify_call_cache(rb_iseq_t *iseq)
540{
541#if CPDEBUG
542 VALUE *original = rb_iseq_original_iseq(iseq);
543 size_t i = 0;
544 while (i < ISEQ_BODY(iseq)->iseq_size) {
545 VALUE insn = original[i];
546 const char *types = insn_op_types(insn);
547
548 for (int j=0; types[j]; j++) {
549 if (types[j] == TS_CALLDATA) {
550 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
551 const struct rb_callinfo *ci = cd->ci;
552 const struct rb_callcache *cc = cd->cc;
553 if (cc != vm_cc_empty()) {
554 vm_ci_dump(ci);
555 rb_bug("call cache is not initialized by vm_cc_empty()");
556 }
557 }
558 }
559 i += insn_len(insn);
560 }
561
562 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
563 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
564 const struct rb_callinfo *ci = cd->ci;
565 const struct rb_callcache *cc = cd->cc;
566 if (cc != NULL && cc != vm_cc_empty()) {
567 vm_ci_dump(ci);
568 rb_bug("call cache is not initialized by vm_cc_empty()");
569 }
570 }
571#endif
572}
573
574/*
575 * elem1, elem2 => elem1, elem2, elem
576 */
577static void
578ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
579{
580 elem->prev = anchor->last;
581 anchor->last->next = elem;
582 anchor->last = elem;
583 verify_list("add", anchor);
584}
585
586/*
587 * elem1, before, elem2 => elem1, before, elem, elem2
588 */
589static void
590APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
591{
592 elem->prev = before;
593 elem->next = before->next;
594 elem->next->prev = elem;
595 before->next = elem;
596 if (before == anchor->last) anchor->last = elem;
597 verify_list("add", anchor);
598}
599#if CPDEBUG < 0
600#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
601#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
602#endif
603
604static int
605branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
606{
607 if (!ISEQ_COVERAGE(iseq)) return 0;
608 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
609 if (first_line <= 0) return 0;
610 return 1;
611}
612
613#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
614
615static VALUE
616setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
617{
618 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
619 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
620 VALUE branch = rb_ary_hidden_new(6);
621
622 rb_hash_aset(structure, key, branch);
623 rb_ary_push(branch, ID2SYM(rb_intern(type)));
624 rb_ary_push(branch, INT2FIX(first_lineno));
625 rb_ary_push(branch, INT2FIX(first_column));
626 rb_ary_push(branch, INT2FIX(last_lineno));
627 rb_ary_push(branch, INT2FIX(last_column));
628 return branch;
629}
630
631static VALUE
632decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
633{
634 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
635
636 /*
637 * if !structure[node]
638 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
639 * else
640 * branches = structure[node][5]
641 * end
642 */
643
644 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
645 VALUE branch_base = rb_hash_aref(structure, key);
646 VALUE branches;
647
648 if (NIL_P(branch_base)) {
649 branch_base = setup_branch(loc, type, structure, key);
650 branches = rb_hash_new();
651 rb_obj_hide(branches);
652 rb_ary_push(branch_base, branches);
653 }
654 else {
655 branches = RARRAY_AREF(branch_base, 5);
656 }
657
658 return branches;
659}
660
661static NODE
662generate_dummy_line_node(int lineno, int node_id)
663{
664 NODE dummy = { 0 };
665 nd_set_line(&dummy, lineno);
666 nd_set_node_id(&dummy, node_id);
667 return dummy;
668}
669
670static void
671add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
672{
673 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
674
675 /*
676 * if !branches[branch_id]
677 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
678 * else
679 * counter_idx= branches[branch_id][5]
680 * end
681 */
682
683 VALUE key = INT2FIX(branch_id);
684 VALUE branch = rb_hash_aref(branches, key);
685 long counter_idx;
686
687 if (NIL_P(branch)) {
688 branch = setup_branch(loc, type, branches, key);
689 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
690 counter_idx = RARRAY_LEN(counters);
691 rb_ary_push(branch, LONG2FIX(counter_idx));
692 rb_ary_push(counters, INT2FIX(0));
693 }
694 else {
695 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
696 }
697
698 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
699 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
700}
701
702#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
703
704static int
705validate_label(st_data_t name, st_data_t label, st_data_t arg)
706{
707 rb_iseq_t *iseq = (rb_iseq_t *)arg;
708 LABEL *lobj = (LABEL *)label;
709 if (!lobj->link.next) {
710 do {
711 COMPILE_ERROR(iseq, lobj->position,
712 "%"PRIsVALUE": undefined label",
713 rb_sym2str((VALUE)name));
714 } while (0);
715 }
716 return ST_CONTINUE;
717}
718
719static void
720validate_labels(rb_iseq_t *iseq, st_table *labels_table)
721{
722 st_foreach(labels_table, validate_label, (st_data_t)iseq);
723 st_free_table(labels_table);
724}
725
726static NODE *
727get_nd_recv(const NODE *node)
728{
729 switch (nd_type(node)) {
730 case NODE_CALL:
731 return RNODE_CALL(node)->nd_recv;
732 case NODE_OPCALL:
733 return RNODE_OPCALL(node)->nd_recv;
734 case NODE_FCALL:
735 return 0;
736 case NODE_QCALL:
737 return RNODE_QCALL(node)->nd_recv;
738 case NODE_VCALL:
739 return 0;
740 case NODE_ATTRASGN:
741 return RNODE_ATTRASGN(node)->nd_recv;
742 case NODE_OP_ASGN1:
743 return RNODE_OP_ASGN1(node)->nd_recv;
744 case NODE_OP_ASGN2:
745 return RNODE_OP_ASGN2(node)->nd_recv;
746 default:
747 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
748 }
749}
750
751static ID
752get_node_call_nd_mid(const NODE *node)
753{
754 switch (nd_type(node)) {
755 case NODE_CALL:
756 return RNODE_CALL(node)->nd_mid;
757 case NODE_OPCALL:
758 return RNODE_OPCALL(node)->nd_mid;
759 case NODE_FCALL:
760 return RNODE_FCALL(node)->nd_mid;
761 case NODE_QCALL:
762 return RNODE_QCALL(node)->nd_mid;
763 case NODE_VCALL:
764 return RNODE_VCALL(node)->nd_mid;
765 case NODE_ATTRASGN:
766 return RNODE_ATTRASGN(node)->nd_mid;
767 default:
768 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
769 }
770}
771
772static NODE *
773get_nd_args(const NODE *node)
774{
775 switch (nd_type(node)) {
776 case NODE_CALL:
777 return RNODE_CALL(node)->nd_args;
778 case NODE_OPCALL:
779 return RNODE_OPCALL(node)->nd_args;
780 case NODE_FCALL:
781 return RNODE_FCALL(node)->nd_args;
782 case NODE_QCALL:
783 return RNODE_QCALL(node)->nd_args;
784 case NODE_VCALL:
785 return 0;
786 case NODE_ATTRASGN:
787 return RNODE_ATTRASGN(node)->nd_args;
788 default:
789 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
790 }
791}
792
793static ID
794get_node_colon_nd_mid(const NODE *node)
795{
796 switch (nd_type(node)) {
797 case NODE_COLON2:
798 return RNODE_COLON2(node)->nd_mid;
799 case NODE_COLON3:
800 return RNODE_COLON3(node)->nd_mid;
801 default:
802 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
803 }
804}
805
806static ID
807get_nd_vid(const NODE *node)
808{
809 switch (nd_type(node)) {
810 case NODE_LASGN:
811 return RNODE_LASGN(node)->nd_vid;
812 case NODE_DASGN:
813 return RNODE_DASGN(node)->nd_vid;
814 case NODE_IASGN:
815 return RNODE_IASGN(node)->nd_vid;
816 case NODE_CVASGN:
817 return RNODE_CVASGN(node)->nd_vid;
818 default:
819 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
820 }
821}
822
823static NODE *
824get_nd_value(const NODE *node)
825{
826 switch (nd_type(node)) {
827 case NODE_LASGN:
828 return RNODE_LASGN(node)->nd_value;
829 case NODE_DASGN:
830 return RNODE_DASGN(node)->nd_value;
831 default:
832 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
833 }
834}
835
836static VALUE
837get_string_value(const NODE *node)
838{
839 switch (nd_type(node)) {
840 case NODE_STR:
841 return rb_node_str_string_val(node);
842 case NODE_FILE:
843 return rb_node_file_path_val(node);
844 default:
845 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
846 }
847}
848
849VALUE
850rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
851{
852 DECL_ANCHOR(ret);
853 INIT_ANCHOR(ret);
854
855 (*ifunc->func)(iseq, ret, ifunc->data);
856
857 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
858
859 CHECK(iseq_setup_insn(iseq, ret));
860 return iseq_setup(iseq, ret);
861}
862
863static bool drop_unreachable_return(LINK_ANCHOR *ret);
864
865VALUE
866rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
867{
868 DECL_ANCHOR(ret);
869 INIT_ANCHOR(ret);
870
871 if (node == 0) {
872 NO_CHECK(COMPILE(ret, "nil", node));
873 iseq_set_local_table(iseq, 0, 0);
874 }
875 /* assume node is T_NODE */
876 else if (nd_type_p(node, NODE_SCOPE)) {
877 /* iseq type of top, method, class, block */
878 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
879 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
880 iseq_set_parameters_lvar_state(iseq);
881
882 switch (ISEQ_BODY(iseq)->type) {
883 case ISEQ_TYPE_BLOCK:
884 {
885 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
886 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
887
888 start->rescued = LABEL_RESCUE_BEG;
889 end->rescued = LABEL_RESCUE_END;
890
891 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
892 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
893 ADD_LABEL(ret, start);
894 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
895 ADD_LABEL(ret, end);
896 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
897 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
898
899 /* wide range catch handler must put at last */
900 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
901 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
902 break;
903 }
904 case ISEQ_TYPE_CLASS:
905 {
906 ADD_TRACE(ret, RUBY_EVENT_CLASS);
907 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
908 ADD_TRACE(ret, RUBY_EVENT_END);
909 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
910 break;
911 }
912 case ISEQ_TYPE_METHOD:
913 {
914 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
915 ADD_TRACE(ret, RUBY_EVENT_CALL);
916 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
917 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
918 ADD_TRACE(ret, RUBY_EVENT_RETURN);
919 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
920 break;
921 }
922 default: {
923 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
924 break;
925 }
926 }
927 }
928 else {
929 const char *m;
930#define INVALID_ISEQ_TYPE(type) \
931 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
932 switch (ISEQ_BODY(iseq)->type) {
933 case INVALID_ISEQ_TYPE(METHOD);
934 case INVALID_ISEQ_TYPE(CLASS);
935 case INVALID_ISEQ_TYPE(BLOCK);
936 case INVALID_ISEQ_TYPE(EVAL);
937 case INVALID_ISEQ_TYPE(MAIN);
938 case INVALID_ISEQ_TYPE(TOP);
939#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
940 case ISEQ_TYPE_RESCUE:
941 iseq_set_exception_local_table(iseq);
942 CHECK(COMPILE(ret, "rescue", node));
943 break;
944 case ISEQ_TYPE_ENSURE:
945 iseq_set_exception_local_table(iseq);
946 CHECK(COMPILE_POPPED(ret, "ensure", node));
947 break;
948 case ISEQ_TYPE_PLAIN:
949 CHECK(COMPILE(ret, "ensure", node));
950 break;
951 default:
952 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
953 return COMPILE_NG;
954 invalid_iseq_type:
955 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
956 return COMPILE_NG;
957 }
958 }
959
960 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
961 NODE dummy_line_node = generate_dummy_line_node(0, -1);
962 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
963 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
964 }
965 else if (!drop_unreachable_return(ret)) {
966 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
967 }
968
969#if OPT_SUPPORT_JOKE
970 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
971 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
972 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
973 validate_labels(iseq, labels_table);
974 }
975#endif
976 CHECK(iseq_setup_insn(iseq, ret));
977 return iseq_setup(iseq, ret);
978}
979
980static int
981rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
982{
983#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
984 const void * const *table = rb_vm_get_insns_address_table();
985 unsigned int i;
986 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
987
988 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
989 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
990 int len = insn_len(insn);
991 encoded[i] = (VALUE)table[insn];
992 i += len;
993 }
994 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
995#endif
996
997#if USE_YJIT
998 rb_yjit_live_iseq_count++;
999 rb_yjit_iseq_alloc_count++;
1000#endif
1001
1002 return COMPILE_OK;
1003}
1004
1005VALUE *
1006rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1007{
1008 VALUE *original_code;
1009
1010 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1011 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1012 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1013
1014#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1015 {
1016 unsigned int i;
1017
1018 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1019 const void *addr = (const void *)original_code[i];
1020 const int insn = rb_vm_insn_addr2insn(addr);
1021
1022 original_code[i] = insn;
1023 i += insn_len(insn);
1024 }
1025 }
1026#endif
1027 return original_code;
1028}
1029
1030/*********************************************/
1031/* definition of data structure for compiler */
1032/*********************************************/
1033
1034/*
1035 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1036 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1037 * generate SPARCV8PLUS code with unaligned memory access instructions.
1038 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1039 */
1040#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1041 #define STRICT_ALIGNMENT
1042#endif
1043
1044/*
1045 * Some OpenBSD platforms (including sparc64) require strict alignment.
1046 */
1047#if defined(__OpenBSD__)
1048 #include <sys/endian.h>
1049 #ifdef __STRICT_ALIGNMENT
1050 #define STRICT_ALIGNMENT
1051 #endif
1052#endif
1053
1054#ifdef STRICT_ALIGNMENT
1055 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1056 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1057 #else
1058 #define ALIGNMENT_SIZE SIZEOF_VALUE
1059 #endif
1060 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1061 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1062 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1063#else
1064 #define PADDING_SIZE_MAX 0
1065#endif /* STRICT_ALIGNMENT */
1066
1067#ifdef STRICT_ALIGNMENT
1068/* calculate padding size for aligned memory access */
1069static size_t
1070calc_padding(void *ptr, size_t size)
1071{
1072 size_t mis;
1073 size_t padding = 0;
1074
1075 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1076 if (mis > 0) {
1077 padding = ALIGNMENT_SIZE - mis;
1078 }
1079/*
1080 * On 32-bit sparc or equivalents, when a single VALUE is requested
1081 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1082 */
1083#if ALIGNMENT_SIZE > SIZEOF_VALUE
1084 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1085 padding = 0;
1086 }
1087#endif
1088
1089 return padding;
1090}
1091#endif /* STRICT_ALIGNMENT */
1092
1093static void *
1094compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1095{
1096 void *ptr = 0;
1097 struct iseq_compile_data_storage *storage = *arena;
1098#ifdef STRICT_ALIGNMENT
1099 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1100#else
1101 const size_t padding = 0; /* expected to be optimized by compiler */
1102#endif /* STRICT_ALIGNMENT */
1103
1104 if (size >= INT_MAX - padding) rb_memerror();
1105 if (storage->pos + size + padding > storage->size) {
1106 unsigned int alloc_size = storage->size;
1107
1108 while (alloc_size < size + PADDING_SIZE_MAX) {
1109 if (alloc_size >= INT_MAX / 2) rb_memerror();
1110 alloc_size *= 2;
1111 }
1112 storage->next = (void *)ALLOC_N(char, alloc_size +
1113 offsetof(struct iseq_compile_data_storage, buff));
1114 storage = *arena = storage->next;
1115 storage->next = 0;
1116 storage->pos = 0;
1117 storage->size = alloc_size;
1118#ifdef STRICT_ALIGNMENT
1119 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1120#endif /* STRICT_ALIGNMENT */
1121 }
1122
1123#ifdef STRICT_ALIGNMENT
1124 storage->pos += (int)padding;
1125#endif /* STRICT_ALIGNMENT */
1126
1127 ptr = (void *)&storage->buff[storage->pos];
1128 storage->pos += (int)size;
1129 return ptr;
1130}
1131
1132static void *
1133compile_data_alloc(rb_iseq_t *iseq, size_t size)
1134{
1135 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1136 return compile_data_alloc_with_arena(arena, size);
1137}
1138
1139static inline void *
1140compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1141{
1142 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1143 return compile_data_alloc(iseq, size);
1144}
1145
1146static inline void *
1147compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1148{
1149 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1150 void *p = compile_data_alloc(iseq, size);
1151 memset(p, 0, size);
1152 return p;
1153}
1154
1155static INSN *
1156compile_data_alloc_insn(rb_iseq_t *iseq)
1157{
1158 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1159 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1160}
1161
1162static LABEL *
1163compile_data_alloc_label(rb_iseq_t *iseq)
1164{
1165 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1166}
1167
1168static ADJUST *
1169compile_data_alloc_adjust(rb_iseq_t *iseq)
1170{
1171 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1172}
1173
1174static TRACE *
1175compile_data_alloc_trace(rb_iseq_t *iseq)
1176{
1177 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1178}
1179
1180/*
1181 * elem1, elemX => elem1, elem2, elemX
1182 */
1183static void
1184ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1185{
1186 elem2->next = elem1->next;
1187 elem2->prev = elem1;
1188 elem1->next = elem2;
1189 if (elem2->next) {
1190 elem2->next->prev = elem2;
1191 }
1192}
1193
1194/*
1195 * elem1, elemX => elemX, elem2, elem1
1196 */
1197static void
1198ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1199{
1200 elem2->prev = elem1->prev;
1201 elem2->next = elem1;
1202 elem1->prev = elem2;
1203 if (elem2->prev) {
1204 elem2->prev->next = elem2;
1205 }
1206}
1207
1208/*
1209 * elemX, elem1, elemY => elemX, elem2, elemY
1210 */
1211static void
1212ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1213{
1214 elem2->prev = elem1->prev;
1215 elem2->next = elem1->next;
1216 if (elem1->prev) {
1217 elem1->prev->next = elem2;
1218 }
1219 if (elem1->next) {
1220 elem1->next->prev = elem2;
1221 }
1222}
1223
1224static void
1225ELEM_REMOVE(LINK_ELEMENT *elem)
1226{
1227 elem->prev->next = elem->next;
1228 if (elem->next) {
1229 elem->next->prev = elem->prev;
1230 }
1231}
1232
1233static LINK_ELEMENT *
1234FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1235{
1236 return anchor->anchor.next;
1237}
1238
1239static LINK_ELEMENT *
1240LAST_ELEMENT(LINK_ANCHOR *const anchor)
1241{
1242 return anchor->last;
1243}
1244
1245static LINK_ELEMENT *
1246ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1247{
1248 while (elem) {
1249 switch (elem->type) {
1250 case ISEQ_ELEMENT_INSN:
1251 case ISEQ_ELEMENT_ADJUST:
1252 return elem;
1253 default:
1254 elem = elem->next;
1255 }
1256 }
1257 return NULL;
1258}
1259
1260static int
1261LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1262{
1263 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1264 if (first_insn != NULL &&
1265 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1266 return TRUE;
1267 }
1268 else {
1269 return FALSE;
1270 }
1271}
1272
1273static int
1274LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1275{
1276 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1277 return TRUE;
1278 }
1279 else {
1280 return FALSE;
1281 }
1282}
1283
1284/*
1285 * anc1: e1, e2, e3
1286 * anc2: e4, e5
1287 *#=>
1288 * anc1: e1, e2, e3, e4, e5
1289 * anc2: e4, e5 (broken)
1290 */
1291static void
1292APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1293{
1294 if (anc2->anchor.next) {
1295 /* LINK_ANCHOR must not loop */
1296 RUBY_ASSERT(anc2->last != &anc2->anchor);
1297 anc1->last->next = anc2->anchor.next;
1298 anc2->anchor.next->prev = anc1->last;
1299 anc1->last = anc2->last;
1300 }
1301 else {
1302 RUBY_ASSERT(anc2->last == &anc2->anchor);
1303 }
1304 verify_list("append", anc1);
1305}
1306#if CPDEBUG < 0
1307#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1308#endif
1309
1310#if CPDEBUG && 0
1311static void
1312debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1313{
1314 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1315 printf("----\n");
1316 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1317 (void *)anchor->anchor.next, (void *)anchor->last);
1318 while (list) {
1319 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1320 (void *)list->prev, (int)list->type);
1321 list = list->next;
1322 }
1323 printf("----\n");
1324
1325 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1326 verify_list("debug list", anchor);
1327}
1328#if CPDEBUG < 0
1329#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1330#endif
1331#else
1332#define debug_list(anc, cur) ((void)0)
1333#endif
1334
1335static TRACE *
1336new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1337{
1338 TRACE *trace = compile_data_alloc_trace(iseq);
1339
1340 trace->link.type = ISEQ_ELEMENT_TRACE;
1341 trace->link.next = NULL;
1342 trace->event = event;
1343 trace->data = data;
1344
1345 return trace;
1346}
1347
1348static LABEL *
1349new_label_body(rb_iseq_t *iseq, long line)
1350{
1351 LABEL *labelobj = compile_data_alloc_label(iseq);
1352
1353 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1354 labelobj->link.next = 0;
1355
1356 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1357 labelobj->sc_state = 0;
1358 labelobj->sp = -1;
1359 labelobj->refcnt = 0;
1360 labelobj->set = 0;
1361 labelobj->rescued = LABEL_RESCUE_NONE;
1362 labelobj->unremovable = 0;
1363 labelobj->position = -1;
1364 return labelobj;
1365}
1366
1367static ADJUST *
1368new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1369{
1370 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1371 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1372 adjust->link.next = 0;
1373 adjust->label = label;
1374 adjust->line_no = line;
1375 LABEL_UNREMOVABLE(label);
1376 return adjust;
1377}
1378
1379static void
1380iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1381{
1382 const char *types = insn_op_types(insn->insn_id);
1383 for (int j = 0; types[j]; j++) {
1384 char type = types[j];
1385 switch (type) {
1386 case TS_CDHASH:
1387 case TS_ISEQ:
1388 case TS_VALUE:
1389 case TS_IC: // constant path array
1390 case TS_CALLDATA: // ci is stored.
1391 func(&OPERAND_AT(insn, j), data);
1392 break;
1393 default:
1394 break;
1395 }
1396 }
1397}
1398
1399static void
1400iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1401{
1402 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1403}
1404
1405static INSN *
1406new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1407{
1408 INSN *iobj = compile_data_alloc_insn(iseq);
1409
1410 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1411
1412 iobj->link.type = ISEQ_ELEMENT_INSN;
1413 iobj->link.next = 0;
1414 iobj->insn_id = insn_id;
1415 iobj->insn_info.line_no = line_no;
1416 iobj->insn_info.node_id = node_id;
1417 iobj->insn_info.events = 0;
1418 iobj->operands = argv;
1419 iobj->operand_size = argc;
1420 iobj->sc_state = 0;
1421
1422 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1423
1424 return iobj;
1425}
1426
1427static INSN *
1428new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1429{
1430 VALUE *operands = 0;
1431 va_list argv;
1432 if (argc > 0) {
1433 int i;
1434 va_start(argv, argc);
1435 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1436 for (i = 0; i < argc; i++) {
1437 VALUE v = va_arg(argv, VALUE);
1438 operands[i] = v;
1439 }
1440 va_end(argv);
1441 }
1442 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1443}
1444
1445static INSN *
1446insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1447{
1448 VALUE *operands = 0;
1449 va_list argv;
1450 if (argc > 0) {
1451 int i;
1452 va_start(argv, argc);
1453 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1454 for (i = 0; i < argc; i++) {
1455 VALUE v = va_arg(argv, VALUE);
1456 operands[i] = v;
1457 }
1458 va_end(argv);
1459 }
1460
1461 iobj->insn_id = insn_id;
1462 iobj->operand_size = argc;
1463 iobj->operands = operands;
1464 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1465
1466 return iobj;
1467}
1468
1469static const struct rb_callinfo *
1470new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1471{
1472 VM_ASSERT(argc >= 0);
1473
1474 if (kw_arg) {
1475 flag |= VM_CALL_KWARG;
1476 argc += kw_arg->keyword_len;
1477 }
1478
1479 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1480 && !has_blockiseq) {
1481 flag |= VM_CALL_ARGS_SIMPLE;
1482 }
1483
1484 ISEQ_BODY(iseq)->ci_size++;
1485 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1486 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1487 return ci;
1488}
1489
1490static INSN *
1491new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1492{
1493 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1494 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1495 operands[0] = ci;
1496 operands[1] = (VALUE)blockiseq;
1497 if (blockiseq) {
1498 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1499 }
1500
1501 INSN *insn;
1502
1503 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1504 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1505 }
1506 else {
1507 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1508 }
1509
1510 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1511 RB_GC_GUARD(ci);
1512 return insn;
1513}
1514
1515static rb_iseq_t *
1516new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1517 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1518{
1519 rb_iseq_t *ret_iseq;
1520 VALUE ast_value = rb_ruby_ast_new(node);
1521
1522 debugs("[new_child_iseq]> ---------------------------------------\n");
1523 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1524 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1525 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1526 line_no, parent,
1527 isolated_depth ? isolated_depth + 1 : 0,
1528 type, ISEQ_COMPILE_DATA(iseq)->option,
1529 ISEQ_BODY(iseq)->variable.script_lines);
1530 debugs("[new_child_iseq]< ---------------------------------------\n");
1531 return ret_iseq;
1532}
1533
1534static rb_iseq_t *
1535new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1536 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1537{
1538 rb_iseq_t *ret_iseq;
1539
1540 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1541 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1542 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1543 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1544 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1545 return ret_iseq;
1546}
1547
1548static void
1549set_catch_except_p(rb_iseq_t *iseq)
1550{
1551 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1552 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1553 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1554 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1555 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1556 }
1557 }
1558}
1559
1560/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1561 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1562 if catch table exists. But we want to optimize while loop, which always has catch
1563 table entries for break/next/redo.
1564
1565 So this function sets true for limited ISeqs with break/next/redo catch table entries
1566 whose child ISeq would really raise an exception. */
1567static void
1568update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1569{
1570 unsigned int pos;
1571 size_t i;
1572 int insn;
1573 const struct iseq_catch_table *ct = body->catch_table;
1574
1575 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1576 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1577 pos = 0;
1578 while (pos < body->iseq_size) {
1579 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1580 if (insn == BIN(throw)) {
1581 set_catch_except_p(iseq);
1582 break;
1583 }
1584 pos += insn_len(insn);
1585 }
1586
1587 if (ct == NULL)
1588 return;
1589
1590 for (i = 0; i < ct->size; i++) {
1591 const struct iseq_catch_table_entry *entry =
1592 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1593 if (entry->type != CATCH_TYPE_BREAK
1594 && entry->type != CATCH_TYPE_NEXT
1595 && entry->type != CATCH_TYPE_REDO) {
1596 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1597 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1598 break;
1599 }
1600 }
1601}
1602
1603static void
1604iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1605{
1606 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1607 if (NIL_P(catch_table_ary)) return;
1608 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1609 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1610 for (i = 0; i < tlen; i++) {
1611 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1612 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1613 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1614 LINK_ELEMENT *e;
1615
1616 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1617
1618 if (ct != CATCH_TYPE_BREAK
1619 && ct != CATCH_TYPE_NEXT
1620 && ct != CATCH_TYPE_REDO) {
1621
1622 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1623 if (e == cont) {
1624 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1625 ELEM_INSERT_NEXT(end, &nop->link);
1626 break;
1627 }
1628 }
1629 }
1630 }
1631
1632 RB_GC_GUARD(catch_table_ary);
1633}
1634
1635static int
1636iseq_setup_insn(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 2] (iseq_array_to_linkedlist)\n"); */
1642
1643 if (compile_debug > 5)
1644 dump_disasm_list(FIRST_ELEMENT(anchor));
1645
1646 debugs("[compile step 3.1 (iseq_optimize)]\n");
1647 iseq_optimize(iseq, anchor);
1648
1649 if (compile_debug > 5)
1650 dump_disasm_list(FIRST_ELEMENT(anchor));
1651
1652 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1653 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1654 iseq_insns_unification(iseq, anchor);
1655 if (compile_debug > 5)
1656 dump_disasm_list(FIRST_ELEMENT(anchor));
1657 }
1658
1659 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1660 iseq_insert_nop_between_end_and_cont(iseq);
1661 if (compile_debug > 5)
1662 dump_disasm_list(FIRST_ELEMENT(anchor));
1663
1664 return COMPILE_OK;
1665}
1666
1667static int
1668iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1669{
1670 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1671 return COMPILE_NG;
1672
1673 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1674 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1675 if (compile_debug > 5)
1676 dump_disasm_list(FIRST_ELEMENT(anchor));
1677
1678 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1679 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1680
1681 debugs("[compile step 4.3 (set_optargs_table)] \n");
1682 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1683
1684 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1685 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1686
1687 debugs("[compile step 6 (update_catch_except_flags)] \n");
1688 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1689 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1690
1691 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1692 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1693 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1694 xfree(ISEQ_BODY(iseq)->catch_table);
1695 ISEQ_BODY(iseq)->catch_table = NULL;
1696 }
1697
1698#if VM_INSN_INFO_TABLE_IMPL == 2
1699 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1700 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1701 rb_iseq_insns_info_encode_positions(iseq);
1702 }
1703#endif
1704
1705 if (compile_debug > 1) {
1706 VALUE str = rb_iseq_disasm(iseq);
1707 printf("%s\n", StringValueCStr(str));
1708 }
1709 verify_call_cache(iseq);
1710 debugs("[compile step: finish]\n");
1711
1712 return COMPILE_OK;
1713}
1714
1715static int
1716iseq_set_exception_local_table(rb_iseq_t *iseq)
1717{
1718 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1719 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1720 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1721 return COMPILE_OK;
1722}
1723
1724static int
1725get_lvar_level(const rb_iseq_t *iseq)
1726{
1727 int lev = 0;
1728 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1729 lev++;
1730 iseq = ISEQ_BODY(iseq)->parent_iseq;
1731 }
1732 return lev;
1733}
1734
1735static int
1736get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1737{
1738 unsigned int i;
1739
1740 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1741 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1742 return (int)i;
1743 }
1744 }
1745 return -1;
1746}
1747
1748static int
1749get_local_var_idx(const rb_iseq_t *iseq, ID id)
1750{
1751 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1752
1753 if (idx < 0) {
1754 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1755 "get_local_var_idx: %d", idx);
1756 }
1757
1758 return idx;
1759}
1760
1761static int
1762get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1763{
1764 int lv = 0, idx = -1;
1765 const rb_iseq_t *const topmost_iseq = iseq;
1766
1767 while (iseq) {
1768 idx = get_dyna_var_idx_at_raw(iseq, id);
1769 if (idx >= 0) {
1770 break;
1771 }
1772 iseq = ISEQ_BODY(iseq)->parent_iseq;
1773 lv++;
1774 }
1775
1776 if (idx < 0) {
1777 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1778 "get_dyna_var_idx: -1");
1779 }
1780
1781 *level = lv;
1782 *ls = ISEQ_BODY(iseq)->local_table_size;
1783 return idx;
1784}
1785
1786static int
1787iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1788{
1789 const struct rb_iseq_constant_body *body;
1790 while (level > 0) {
1791 iseq = ISEQ_BODY(iseq)->parent_iseq;
1792 level--;
1793 }
1794 body = ISEQ_BODY(iseq);
1795 if (body->local_iseq == iseq && /* local variables */
1796 body->param.flags.has_block &&
1797 body->local_table_size - body->param.block_start == idx) {
1798 return TRUE;
1799 }
1800 else {
1801 return FALSE;
1802 }
1803}
1804
1805static int
1806iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1807{
1808 int level, ls;
1809 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1810 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1811 *pidx = ls - idx;
1812 *plevel = level;
1813 return TRUE;
1814 }
1815 else {
1816 return FALSE;
1817 }
1818}
1819
1820static void
1821access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1822{
1823 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1824
1825 if (isolated_depth && level >= isolated_depth) {
1826 if (id == rb_intern("yield")) {
1827 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1828 }
1829 else {
1830 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1831 }
1832 }
1833
1834 for (int i=0; i<level; i++) {
1835 VALUE val;
1836 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1837
1838 if (!ovs) {
1839 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1840 }
1841
1842 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1843 if (write && !val) {
1844 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1845 }
1846 }
1847 else {
1848 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1849 }
1850
1851 iseq = ISEQ_BODY(iseq)->parent_iseq;
1852 }
1853}
1854
1855static ID
1856iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1857{
1858 for (int i=0; i<level; i++) {
1859 iseq = ISEQ_BODY(iseq)->parent_iseq;
1860 }
1861
1862 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1863 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1864 return id;
1865}
1866
1867static void
1868update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1869{
1870 for (int i=0; i<level; i++) {
1871 iseq = ISEQ_BODY(iseq)->parent_iseq;
1872 }
1873
1874 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1875 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1876 switch (states[table_idx]) {
1877 case lvar_uninitialized:
1878 states[table_idx] = lvar_initialized;
1879 break;
1880 case lvar_initialized:
1881 states[table_idx] = lvar_reassigned;
1882 break;
1883 case lvar_reassigned:
1884 /* nothing */
1885 break;
1886 default:
1887 rb_bug("unreachable");
1888 }
1889}
1890
1891static int
1892iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1893{
1894 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1895 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1896 }
1897
1898 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1899 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1900 for (int i=0; i<opt_num; i++) {
1901 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1902 }
1903
1904 return COMPILE_OK;
1905}
1906
1907static void
1908iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1909{
1910 if (iseq_local_block_param_p(iseq, idx, level)) {
1911 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1912 }
1913 else {
1914 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1915 }
1916 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1917}
1918
1919static void
1920iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1921{
1922 if (iseq_local_block_param_p(iseq, idx, level)) {
1923 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1924 }
1925 else {
1926 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1927 }
1928 update_lvar_state(iseq, level, idx);
1929 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1930}
1931
1932
1933
1934static void
1935iseq_calc_param_size(rb_iseq_t *iseq)
1936{
1937 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1938 if (body->param.flags.has_opt ||
1939 body->param.flags.has_post ||
1940 body->param.flags.has_rest ||
1941 body->param.flags.has_block ||
1942 body->param.flags.has_kw ||
1943 body->param.flags.has_kwrest) {
1944
1945 if (body->param.flags.has_block) {
1946 body->param.size = body->param.block_start + 1;
1947 }
1948 else if (body->param.flags.has_kwrest) {
1949 body->param.size = body->param.keyword->rest_start + 1;
1950 }
1951 else if (body->param.flags.has_kw) {
1952 body->param.size = body->param.keyword->bits_start + 1;
1953 }
1954 else if (body->param.flags.has_post) {
1955 body->param.size = body->param.post_start + body->param.post_num;
1956 }
1957 else if (body->param.flags.has_rest) {
1958 body->param.size = body->param.rest_start + 1;
1959 }
1960 else if (body->param.flags.has_opt) {
1961 body->param.size = body->param.lead_num + body->param.opt_num;
1962 }
1963 else {
1965 }
1966 }
1967 else {
1968 body->param.size = body->param.lead_num;
1969 }
1970}
1971
1972static int
1973iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1974 const struct rb_args_info *args, int arg_size)
1975{
1976 const rb_node_kw_arg_t *node = args->kw_args;
1977 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1978 struct rb_iseq_param_keyword *keyword;
1979 const VALUE default_values = rb_ary_hidden_new(1);
1980 const VALUE complex_mark = rb_str_tmp_new(0);
1981 int kw = 0, rkw = 0, di = 0, i;
1982
1983 body->param.flags.has_kw = TRUE;
1984 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1985
1986 while (node) {
1987 kw++;
1988 node = node->nd_next;
1989 }
1990 arg_size += kw;
1991 keyword->bits_start = arg_size++;
1992
1993 node = args->kw_args;
1994 while (node) {
1995 const NODE *val_node = get_nd_value(node->nd_body);
1996 VALUE dv;
1997
1998 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1999 ++rkw;
2000 }
2001 else {
2002 switch (nd_type(val_node)) {
2003 case NODE_SYM:
2004 dv = rb_node_sym_string_val(val_node);
2005 break;
2006 case NODE_REGX:
2007 dv = rb_node_regx_string_val(val_node);
2008 break;
2009 case NODE_LINE:
2010 dv = rb_node_line_lineno_val(val_node);
2011 break;
2012 case NODE_INTEGER:
2013 dv = rb_node_integer_literal_val(val_node);
2014 break;
2015 case NODE_FLOAT:
2016 dv = rb_node_float_literal_val(val_node);
2017 break;
2018 case NODE_RATIONAL:
2019 dv = rb_node_rational_literal_val(val_node);
2020 break;
2021 case NODE_IMAGINARY:
2022 dv = rb_node_imaginary_literal_val(val_node);
2023 break;
2024 case NODE_ENCODING:
2025 dv = rb_node_encoding_val(val_node);
2026 break;
2027 case NODE_NIL:
2028 dv = Qnil;
2029 break;
2030 case NODE_TRUE:
2031 dv = Qtrue;
2032 break;
2033 case NODE_FALSE:
2034 dv = Qfalse;
2035 break;
2036 default:
2037 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2038 dv = complex_mark;
2039 }
2040
2041 keyword->num = ++di;
2042 rb_ary_push(default_values, dv);
2043 }
2044
2045 node = node->nd_next;
2046 }
2047
2048 keyword->num = kw;
2049
2050 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2051 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2052 keyword->rest_start = arg_size++;
2053 body->param.flags.has_kwrest = TRUE;
2054
2055 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2056 }
2057 keyword->required_num = rkw;
2058 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2059
2060 if (RARRAY_LEN(default_values)) {
2061 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2062
2063 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2064 VALUE dv = RARRAY_AREF(default_values, i);
2065 if (dv == complex_mark) dv = Qundef;
2066 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2067 }
2068
2069 keyword->default_values = dvs;
2070 }
2071 return arg_size;
2072}
2073
2074static void
2075iseq_set_use_block(rb_iseq_t *iseq)
2076{
2077 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2078 if (!body->param.flags.use_block) {
2079 body->param.flags.use_block = 1;
2080
2081 rb_vm_t *vm = GET_VM();
2082
2083 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2084 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2085 set_insert(vm->unused_block_warning_table, key);
2086 }
2087 }
2088}
2089
2090static int
2091iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2092{
2093 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2094
2095 if (node_args) {
2096 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2097 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2098 ID rest_id = 0;
2099 int last_comma = 0;
2100 ID block_id = 0;
2101 int arg_size;
2102
2103 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2104
2105 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2106 body->param.lead_num = arg_size = (int)args->pre_args_num;
2107 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2108 debugs(" - argc: %d\n", body->param.lead_num);
2109
2110 rest_id = args->rest_arg;
2111 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2112 last_comma = 1;
2113 rest_id = 0;
2114 }
2115 block_id = args->block_arg;
2116
2117 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2118
2119 if (optimized_forward) {
2120 rest_id = 0;
2121 block_id = 0;
2122 }
2123
2124 if (args->opt_args) {
2125 const rb_node_opt_arg_t *node = args->opt_args;
2126 LABEL *label;
2127 VALUE labels = rb_ary_hidden_new(1);
2128 VALUE *opt_table;
2129 int i = 0, j;
2130
2131 while (node) {
2132 label = NEW_LABEL(nd_line(RNODE(node)));
2133 rb_ary_push(labels, (VALUE)label | 1);
2134 ADD_LABEL(optargs, label);
2135 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2136 node = node->nd_next;
2137 i += 1;
2138 }
2139
2140 /* last label */
2141 label = NEW_LABEL(nd_line(node_args));
2142 rb_ary_push(labels, (VALUE)label | 1);
2143 ADD_LABEL(optargs, label);
2144
2145 opt_table = ALLOC_N(VALUE, i+1);
2146
2147 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2148 for (j = 0; j < i+1; j++) {
2149 opt_table[j] &= ~1;
2150 }
2151 rb_ary_clear(labels);
2152
2153 body->param.flags.has_opt = TRUE;
2154 body->param.opt_num = i;
2155 body->param.opt_table = opt_table;
2156 arg_size += i;
2157 }
2158
2159 if (rest_id) {
2160 body->param.rest_start = arg_size++;
2161 body->param.flags.has_rest = TRUE;
2162 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2163 RUBY_ASSERT(body->param.rest_start != -1);
2164 }
2165
2166 if (args->first_post_arg) {
2167 body->param.post_start = arg_size;
2168 body->param.post_num = args->post_args_num;
2169 body->param.flags.has_post = TRUE;
2170 arg_size += args->post_args_num;
2171
2172 if (body->param.flags.has_rest) { /* TODO: why that? */
2173 body->param.post_start = body->param.rest_start + 1;
2174 }
2175 }
2176
2177 if (args->kw_args) {
2178 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2179 }
2180 else if (args->kw_rest_arg && !optimized_forward) {
2181 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2182 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2183 keyword->rest_start = arg_size++;
2184 body->param.keyword = keyword;
2185 body->param.flags.has_kwrest = TRUE;
2186
2187 static ID anon_kwrest = 0;
2188 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2189 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2190 }
2191 else if (args->no_kwarg) {
2192 body->param.flags.accepts_no_kwarg = TRUE;
2193 }
2194
2195 if (block_id) {
2196 body->param.block_start = arg_size++;
2197 body->param.flags.has_block = TRUE;
2198 iseq_set_use_block(iseq);
2199 }
2200
2201 // Only optimize specifically methods like this: `foo(...)`
2202 if (optimized_forward) {
2203 body->param.flags.use_block = 1;
2204 body->param.flags.forwardable = TRUE;
2205 arg_size = 1;
2206 }
2207
2208 iseq_calc_param_size(iseq);
2209 body->param.size = arg_size;
2210
2211 if (args->pre_init) { /* m_init */
2212 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2213 }
2214 if (args->post_init) { /* p_init */
2215 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2216 }
2217
2218 if (body->type == ISEQ_TYPE_BLOCK) {
2219 if (body->param.flags.has_opt == FALSE &&
2220 body->param.flags.has_post == FALSE &&
2221 body->param.flags.has_rest == FALSE &&
2222 body->param.flags.has_kw == FALSE &&
2223 body->param.flags.has_kwrest == FALSE) {
2224
2225 if (body->param.lead_num == 1 && last_comma == 0) {
2226 /* {|a|} */
2227 body->param.flags.ambiguous_param0 = TRUE;
2228 }
2229 }
2230 }
2231 }
2232
2233 return COMPILE_OK;
2234}
2235
2236static int
2237iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2238{
2239 unsigned int size = tbl ? tbl->size : 0;
2240 unsigned int offset = 0;
2241
2242 if (node_args) {
2243 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2244
2245 // If we have a function that only has `...` as the parameter,
2246 // then its local table should only be `...`
2247 // FIXME: I think this should be fixed in the AST rather than special case here.
2248 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2249 CHECK(size >= 3);
2250 size -= 3;
2251 offset += 3;
2252 }
2253 }
2254
2255 if (size > 0) {
2256 ID *ids = ALLOC_N(ID, size);
2257 MEMCPY(ids, tbl->ids + offset, ID, size);
2258 ISEQ_BODY(iseq)->local_table = ids;
2259
2260 enum lvar_state *states = ALLOC_N(enum lvar_state, size);
2261 // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
2262 for (unsigned int i=0; i<size; i++) {
2263 states[i] = lvar_uninitialized;
2264 // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
2265 }
2266 ISEQ_BODY(iseq)->lvar_states = states;
2267 }
2268 ISEQ_BODY(iseq)->local_table_size = size;
2269
2270 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2271 return COMPILE_OK;
2272}
2273
2274int
2275rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2276{
2277 int tval, tlit;
2278
2279 if (val == lit) {
2280 return 0;
2281 }
2282 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2283 return val != lit;
2284 }
2285 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2286 return -1;
2287 }
2288 else if (tlit != tval) {
2289 return -1;
2290 }
2291 else if (tlit == T_SYMBOL) {
2292 return val != lit;
2293 }
2294 else if (tlit == T_STRING) {
2295 return rb_str_hash_cmp(lit, val);
2296 }
2297 else if (tlit == T_BIGNUM) {
2298 long x = FIX2LONG(rb_big_cmp(lit, val));
2299
2300 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2301 * There is no need to call rb_fix2int here. */
2302 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2303 return (int)x;
2304 }
2305 else if (tlit == T_FLOAT) {
2306 return rb_float_cmp(lit, val);
2307 }
2308 else if (tlit == T_RATIONAL) {
2309 const struct RRational *rat1 = RRATIONAL(val);
2310 const struct RRational *rat2 = RRATIONAL(lit);
2311 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2312 }
2313 else if (tlit == T_COMPLEX) {
2314 const struct RComplex *comp1 = RCOMPLEX(val);
2315 const struct RComplex *comp2 = RCOMPLEX(lit);
2316 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2317 }
2318 else if (tlit == T_REGEXP) {
2319 return rb_reg_equal(val, lit) ? 0 : -1;
2320 }
2321 else {
2323 }
2324}
2325
2326st_index_t
2327rb_iseq_cdhash_hash(VALUE a)
2328{
2329 switch (OBJ_BUILTIN_TYPE(a)) {
2330 case -1:
2331 case T_SYMBOL:
2332 return (st_index_t)a;
2333 case T_STRING:
2334 return rb_str_hash(a);
2335 case T_BIGNUM:
2336 return FIX2LONG(rb_big_hash(a));
2337 case T_FLOAT:
2338 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2339 case T_RATIONAL:
2340 return rb_rational_hash(a);
2341 case T_COMPLEX:
2342 return rb_complex_hash(a);
2343 case T_REGEXP:
2344 return NUM2LONG(rb_reg_hash(a));
2345 default:
2347 }
2348}
2349
2350static const struct st_hash_type cdhash_type = {
2351 rb_iseq_cdhash_cmp,
2352 rb_iseq_cdhash_hash,
2353};
2354
2356 VALUE hash;
2357 int pos;
2358 int len;
2359};
2360
2361static int
2362cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2363{
2364 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2365 LABEL *lobj = (LABEL *)(val & ~1);
2366 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2367 return ST_CONTINUE;
2368}
2369
2370
2371static inline VALUE
2372get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2373{
2374 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2375}
2376
2377static inline VALUE
2378get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2379{
2380 VALUE val;
2381 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2382 if (tbl) {
2383 if (rb_id_table_lookup(tbl,id,&val)) {
2384 return val;
2385 }
2386 }
2387 else {
2388 tbl = rb_id_table_create(1);
2389 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2390 }
2391 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2392 rb_id_table_insert(tbl,id,val);
2393 return val;
2394}
2395
2396#define BADINSN_DUMP(anchor, list, dest) \
2397 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2398
2399#define BADINSN_ERROR \
2400 (xfree(generated_iseq), \
2401 xfree(insns_info), \
2402 BADINSN_DUMP(anchor, list, NULL), \
2403 COMPILE_ERROR)
2404
2405static int
2406fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2407{
2408 int stack_max = 0, sp = 0, line = 0;
2409 LINK_ELEMENT *list;
2410
2411 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2412 if (IS_LABEL(list)) {
2413 LABEL *lobj = (LABEL *)list;
2414 lobj->set = TRUE;
2415 }
2416 }
2417
2418 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2419 switch (list->type) {
2420 case ISEQ_ELEMENT_INSN:
2421 {
2422 int j, len, insn;
2423 const char *types;
2424 VALUE *operands;
2425 INSN *iobj = (INSN *)list;
2426
2427 /* update sp */
2428 sp = calc_sp_depth(sp, iobj);
2429 if (sp < 0) {
2430 BADINSN_DUMP(anchor, list, NULL);
2431 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2432 "argument stack underflow (%d)", sp);
2433 return -1;
2434 }
2435 if (sp > stack_max) {
2436 stack_max = sp;
2437 }
2438
2439 line = iobj->insn_info.line_no;
2440 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2441 operands = iobj->operands;
2442 insn = iobj->insn_id;
2443 types = insn_op_types(insn);
2444 len = insn_len(insn);
2445
2446 /* operand check */
2447 if (iobj->operand_size != len - 1) {
2448 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2449 BADINSN_DUMP(anchor, list, NULL);
2450 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2451 "operand size miss! (%d for %d)",
2452 iobj->operand_size, len - 1);
2453 return -1;
2454 }
2455
2456 for (j = 0; types[j]; j++) {
2457 if (types[j] == TS_OFFSET) {
2458 /* label(destination position) */
2459 LABEL *lobj = (LABEL *)operands[j];
2460 if (!lobj->set) {
2461 BADINSN_DUMP(anchor, list, NULL);
2462 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2463 "unknown label: "LABEL_FORMAT, lobj->label_no);
2464 return -1;
2465 }
2466 if (lobj->sp == -1) {
2467 lobj->sp = sp;
2468 }
2469 else if (lobj->sp != sp) {
2470 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2471 RSTRING_PTR(rb_iseq_path(iseq)), line,
2472 lobj->label_no, lobj->sp, sp);
2473 }
2474 }
2475 }
2476 break;
2477 }
2478 case ISEQ_ELEMENT_LABEL:
2479 {
2480 LABEL *lobj = (LABEL *)list;
2481 if (lobj->sp == -1) {
2482 lobj->sp = sp;
2483 }
2484 else {
2485 if (lobj->sp != sp) {
2486 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2487 RSTRING_PTR(rb_iseq_path(iseq)), line,
2488 lobj->label_no, lobj->sp, sp);
2489 }
2490 sp = lobj->sp;
2491 }
2492 break;
2493 }
2494 case ISEQ_ELEMENT_TRACE:
2495 {
2496 /* ignore */
2497 break;
2498 }
2499 case ISEQ_ELEMENT_ADJUST:
2500 {
2501 ADJUST *adjust = (ADJUST *)list;
2502 int orig_sp = sp;
2503
2504 sp = adjust->label ? adjust->label->sp : 0;
2505 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2506 BADINSN_DUMP(anchor, list, NULL);
2507 COMPILE_ERROR(iseq, adjust->line_no,
2508 "iseq_set_sequence: adjust bug %d < %d",
2509 orig_sp, sp);
2510 return -1;
2511 }
2512 break;
2513 }
2514 default:
2515 BADINSN_DUMP(anchor, list, NULL);
2516 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2517 return -1;
2518 }
2519 }
2520 return stack_max;
2521}
2522
2523static int
2524add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2525 int insns_info_index, int code_index, const INSN *iobj)
2526{
2527 if (insns_info_index == 0 ||
2528 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2529#ifdef USE_ISEQ_NODE_ID
2530 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2531#endif
2532 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2533 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2534#ifdef USE_ISEQ_NODE_ID
2535 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2536#endif
2537 insns_info[insns_info_index].events = iobj->insn_info.events;
2538 positions[insns_info_index] = code_index;
2539 return TRUE;
2540 }
2541 return FALSE;
2542}
2543
2544static int
2545add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2546 int insns_info_index, int code_index, const ADJUST *adjust)
2547{
2548 insns_info[insns_info_index].line_no = adjust->line_no;
2549 insns_info[insns_info_index].node_id = -1;
2550 insns_info[insns_info_index].events = 0;
2551 positions[insns_info_index] = code_index;
2552 return TRUE;
2553}
2554
2555static ID *
2556array_to_idlist(VALUE arr)
2557{
2559 long size = RARRAY_LEN(arr);
2560 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2561 for (long i = 0; i < size; i++) {
2562 VALUE sym = RARRAY_AREF(arr, i);
2563 ids[i] = SYM2ID(sym);
2564 }
2565 ids[size] = 0;
2566 return ids;
2567}
2568
2569static VALUE
2570idlist_to_array(const ID *ids)
2571{
2572 VALUE arr = rb_ary_new();
2573 while (*ids) {
2574 rb_ary_push(arr, ID2SYM(*ids++));
2575 }
2576 return arr;
2577}
2578
2582static int
2583iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2584{
2585 struct iseq_insn_info_entry *insns_info;
2586 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2587 unsigned int *positions;
2588 LINK_ELEMENT *list;
2589 VALUE *generated_iseq;
2590 rb_event_flag_t events = 0;
2591 long data = 0;
2592
2593 int insn_num, code_index, insns_info_index, sp = 0;
2594 int stack_max = fix_sp_depth(iseq, anchor);
2595
2596 if (stack_max < 0) return COMPILE_NG;
2597
2598 /* fix label position */
2599 insn_num = code_index = 0;
2600 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2601 switch (list->type) {
2602 case ISEQ_ELEMENT_INSN:
2603 {
2604 INSN *iobj = (INSN *)list;
2605 /* update sp */
2606 sp = calc_sp_depth(sp, iobj);
2607 insn_num++;
2608 events = iobj->insn_info.events |= events;
2609 if (ISEQ_COVERAGE(iseq)) {
2610 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2611 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2612 int line = iobj->insn_info.line_no - 1;
2613 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2614 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2615 }
2616 }
2617 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2618 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2619 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2620 }
2621 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2622 }
2623 }
2624 code_index += insn_data_length(iobj);
2625 events = 0;
2626 data = 0;
2627 break;
2628 }
2629 case ISEQ_ELEMENT_LABEL:
2630 {
2631 LABEL *lobj = (LABEL *)list;
2632 lobj->position = code_index;
2633 if (lobj->sp != sp) {
2634 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2635 RSTRING_PTR(rb_iseq_path(iseq)),
2636 lobj->label_no, lobj->sp, sp);
2637 }
2638 sp = lobj->sp;
2639 break;
2640 }
2641 case ISEQ_ELEMENT_TRACE:
2642 {
2643 TRACE *trace = (TRACE *)list;
2644 events |= trace->event;
2645 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2646 break;
2647 }
2648 case ISEQ_ELEMENT_ADJUST:
2649 {
2650 ADJUST *adjust = (ADJUST *)list;
2651 if (adjust->line_no != -1) {
2652 int orig_sp = sp;
2653 sp = adjust->label ? adjust->label->sp : 0;
2654 if (orig_sp - sp > 0) {
2655 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2656 code_index++; /* insn */
2657 insn_num++;
2658 }
2659 }
2660 break;
2661 }
2662 default: break;
2663 }
2664 }
2665
2666 /* make instruction sequence */
2667 generated_iseq = ALLOC_N(VALUE, code_index);
2668 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2669 positions = ALLOC_N(unsigned int, insn_num);
2670 if (ISEQ_IS_SIZE(body)) {
2671 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2672 }
2673 else {
2674 body->is_entries = NULL;
2675 }
2676
2677 if (body->ci_size) {
2678 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2679 }
2680 else {
2681 body->call_data = NULL;
2682 }
2683 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2684
2685 // Calculate the bitmask buffer size.
2686 // Round the generated_iseq size up to the nearest multiple
2687 // of the number of bits in an unsigned long.
2688
2689 // Allocate enough room for the bitmask list
2690 iseq_bits_t * mark_offset_bits;
2691 int code_size = code_index;
2692
2693 bool needs_bitmap = false;
2694
2695 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2696 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2697 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2698 }
2699 else {
2700 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2701 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2702 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2703 }
2704
2705 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2706 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2707
2708 list = FIRST_ELEMENT(anchor);
2709 insns_info_index = code_index = sp = 0;
2710
2711 while (list) {
2712 switch (list->type) {
2713 case ISEQ_ELEMENT_INSN:
2714 {
2715 int j, len, insn;
2716 const char *types;
2717 VALUE *operands;
2718 INSN *iobj = (INSN *)list;
2719
2720 /* update sp */
2721 sp = calc_sp_depth(sp, iobj);
2722 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2723 operands = iobj->operands;
2724 insn = iobj->insn_id;
2725 generated_iseq[code_index] = insn;
2726 types = insn_op_types(insn);
2727 len = insn_len(insn);
2728
2729 for (j = 0; types[j]; j++) {
2730 char type = types[j];
2731
2732 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2733 switch (type) {
2734 case TS_OFFSET:
2735 {
2736 /* label(destination position) */
2737 LABEL *lobj = (LABEL *)operands[j];
2738 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2739 break;
2740 }
2741 case TS_CDHASH:
2742 {
2743 VALUE map = operands[j];
2744 struct cdhash_set_label_struct data;
2745 data.hash = map;
2746 data.pos = code_index;
2747 data.len = len;
2748 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2749
2750 rb_hash_rehash(map);
2751 freeze_hide_obj(map);
2752 generated_iseq[code_index + 1 + j] = map;
2753 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2754 RB_OBJ_WRITTEN(iseq, Qundef, map);
2755 needs_bitmap = true;
2756 break;
2757 }
2758 case TS_LINDEX:
2759 case TS_NUM: /* ulong */
2760 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2761 break;
2762 case TS_ISEQ: /* iseq */
2763 case TS_VALUE: /* VALUE */
2764 {
2765 VALUE v = operands[j];
2766 generated_iseq[code_index + 1 + j] = v;
2767 /* to mark ruby object */
2768 if (!SPECIAL_CONST_P(v)) {
2769 RB_OBJ_WRITTEN(iseq, Qundef, v);
2770 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2771 needs_bitmap = true;
2772 }
2773 break;
2774 }
2775 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2776 case TS_IC: /* inline cache: constants */
2777 {
2778 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2779 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2780 if (UNLIKELY(ic_index >= body->ic_size)) {
2781 BADINSN_DUMP(anchor, &iobj->link, 0);
2782 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2783 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2784 ic_index, ISEQ_IS_SIZE(body));
2785 }
2786
2787 ic->segments = array_to_idlist(operands[j]);
2788
2789 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2790 }
2791 break;
2792 case TS_IVC: /* inline ivar cache */
2793 {
2794 unsigned int ic_index = FIX2UINT(operands[j]);
2795
2796 IVC cache = ((IVC)&body->is_entries[ic_index]);
2797
2798 if (insn == BIN(setinstancevariable)) {
2799 cache->iv_set_name = SYM2ID(operands[j - 1]);
2800 }
2801 else {
2802 cache->iv_set_name = 0;
2803 }
2804
2805 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2806 }
2807 case TS_ISE: /* inline storage entry: `once` insn */
2808 case TS_ICVARC: /* inline cvar cache */
2809 {
2810 unsigned int ic_index = FIX2UINT(operands[j]);
2811 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2812 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2813 BADINSN_DUMP(anchor, &iobj->link, 0);
2814 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2815 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2816 ic_index, ISEQ_IS_SIZE(body));
2817 }
2818 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2819
2820 break;
2821 }
2822 case TS_CALLDATA:
2823 {
2824 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2825 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2826 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2827 cd->ci = source_ci;
2828 cd->cc = vm_cc_empty();
2829 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2830 break;
2831 }
2832 case TS_ID: /* ID */
2833 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2834 break;
2835 case TS_FUNCPTR:
2836 generated_iseq[code_index + 1 + j] = operands[j];
2837 break;
2838 case TS_BUILTIN:
2839 generated_iseq[code_index + 1 + j] = operands[j];
2840 break;
2841 default:
2842 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2843 "unknown operand type: %c", type);
2844 return COMPILE_NG;
2845 }
2846 }
2847 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2848 code_index += len;
2849 break;
2850 }
2851 case ISEQ_ELEMENT_LABEL:
2852 {
2853 LABEL *lobj = (LABEL *)list;
2854 if (lobj->sp != sp) {
2855 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2856 RSTRING_PTR(rb_iseq_path(iseq)),
2857 lobj->label_no, lobj->sp, sp);
2858 }
2859 sp = lobj->sp;
2860 break;
2861 }
2862 case ISEQ_ELEMENT_ADJUST:
2863 {
2864 ADJUST *adjust = (ADJUST *)list;
2865 int orig_sp = sp;
2866
2867 if (adjust->label) {
2868 sp = adjust->label->sp;
2869 }
2870 else {
2871 sp = 0;
2872 }
2873
2874 if (adjust->line_no != -1) {
2875 const int diff = orig_sp - sp;
2876 if (diff > 0) {
2877 if (insns_info_index == 0) {
2878 COMPILE_ERROR(iseq, adjust->line_no,
2879 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2880 }
2881 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2882 }
2883 if (diff > 1) {
2884 generated_iseq[code_index++] = BIN(adjuststack);
2885 generated_iseq[code_index++] = orig_sp - sp;
2886 }
2887 else if (diff == 1) {
2888 generated_iseq[code_index++] = BIN(pop);
2889 }
2890 else if (diff < 0) {
2891 int label_no = adjust->label ? adjust->label->label_no : -1;
2892 xfree(generated_iseq);
2893 xfree(insns_info);
2894 xfree(positions);
2895 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2896 xfree(mark_offset_bits);
2897 }
2898 debug_list(anchor, list);
2899 COMPILE_ERROR(iseq, adjust->line_no,
2900 "iseq_set_sequence: adjust bug to %d %d < %d",
2901 label_no, orig_sp, sp);
2902 return COMPILE_NG;
2903 }
2904 }
2905 break;
2906 }
2907 default:
2908 /* ignore */
2909 break;
2910 }
2911 list = list->next;
2912 }
2913
2914 body->iseq_encoded = (void *)generated_iseq;
2915 body->iseq_size = code_index;
2916 body->stack_max = stack_max;
2917
2918 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2919 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2920 }
2921 else {
2922 if (needs_bitmap) {
2923 body->mark_bits.list = mark_offset_bits;
2924 }
2925 else {
2926 body->mark_bits.list = NULL;
2927 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2928 ruby_xfree(mark_offset_bits);
2929 }
2930 }
2931
2932 /* get rid of memory leak when REALLOC failed */
2933 body->insns_info.body = insns_info;
2934 body->insns_info.positions = positions;
2935
2936 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2937 body->insns_info.body = insns_info;
2938 REALLOC_N(positions, unsigned int, insns_info_index);
2939 body->insns_info.positions = positions;
2940 body->insns_info.size = insns_info_index;
2941
2942 return COMPILE_OK;
2943}
2944
2945static int
2946label_get_position(LABEL *lobj)
2947{
2948 return lobj->position;
2949}
2950
2951static int
2952label_get_sp(LABEL *lobj)
2953{
2954 return lobj->sp;
2955}
2956
2957static int
2958iseq_set_exception_table(rb_iseq_t *iseq)
2959{
2960 const VALUE *tptr, *ptr;
2961 unsigned int tlen, i;
2962 struct iseq_catch_table_entry *entry;
2963
2964 ISEQ_BODY(iseq)->catch_table = NULL;
2965
2966 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2967 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2968 tlen = (int)RARRAY_LEN(catch_table_ary);
2969 tptr = RARRAY_CONST_PTR(catch_table_ary);
2970
2971 if (tlen > 0) {
2972 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2973 table->size = tlen;
2974
2975 for (i = 0; i < table->size; i++) {
2976 int pos;
2977 ptr = RARRAY_CONST_PTR(tptr[i]);
2978 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2979 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2980 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2981 RUBY_ASSERT(pos >= 0);
2982 entry->start = (unsigned int)pos;
2983 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2984 RUBY_ASSERT(pos >= 0);
2985 entry->end = (unsigned int)pos;
2986 entry->iseq = (rb_iseq_t *)ptr[3];
2987 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2988
2989 /* stack depth */
2990 if (ptr[4]) {
2991 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2992 entry->cont = label_get_position(lobj);
2993 entry->sp = label_get_sp(lobj);
2994
2995 /* TODO: Dirty Hack! Fix me */
2996 if (entry->type == CATCH_TYPE_RESCUE ||
2997 entry->type == CATCH_TYPE_BREAK ||
2998 entry->type == CATCH_TYPE_NEXT) {
2999 RUBY_ASSERT(entry->sp > 0);
3000 entry->sp--;
3001 }
3002 }
3003 else {
3004 entry->cont = 0;
3005 }
3006 }
3007 ISEQ_BODY(iseq)->catch_table = table;
3008 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3009 }
3010
3011 RB_GC_GUARD(catch_table_ary);
3012
3013 return COMPILE_OK;
3014}
3015
3016/*
3017 * set optional argument table
3018 * def foo(a, b=expr1, c=expr2)
3019 * =>
3020 * b:
3021 * expr1
3022 * c:
3023 * expr2
3024 */
3025static int
3026iseq_set_optargs_table(rb_iseq_t *iseq)
3027{
3028 int i;
3029 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3030
3031 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3032 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3033 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3034 }
3035 }
3036 return COMPILE_OK;
3037}
3038
3039static LINK_ELEMENT *
3040get_destination_insn(INSN *iobj)
3041{
3042 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3043 LINK_ELEMENT *list;
3044 rb_event_flag_t events = 0;
3045
3046 list = lobj->link.next;
3047 while (list) {
3048 switch (list->type) {
3049 case ISEQ_ELEMENT_INSN:
3050 case ISEQ_ELEMENT_ADJUST:
3051 goto found;
3052 case ISEQ_ELEMENT_LABEL:
3053 /* ignore */
3054 break;
3055 case ISEQ_ELEMENT_TRACE:
3056 {
3057 TRACE *trace = (TRACE *)list;
3058 events |= trace->event;
3059 }
3060 break;
3061 default: break;
3062 }
3063 list = list->next;
3064 }
3065 found:
3066 if (list && IS_INSN(list)) {
3067 INSN *iobj = (INSN *)list;
3068 iobj->insn_info.events |= events;
3069 }
3070 return list;
3071}
3072
3073static LINK_ELEMENT *
3074get_next_insn(INSN *iobj)
3075{
3076 LINK_ELEMENT *list = iobj->link.next;
3077
3078 while (list) {
3079 if (IS_INSN(list) || IS_ADJUST(list)) {
3080 return list;
3081 }
3082 list = list->next;
3083 }
3084 return 0;
3085}
3086
3087static LINK_ELEMENT *
3088get_prev_insn(INSN *iobj)
3089{
3090 LINK_ELEMENT *list = iobj->link.prev;
3091
3092 while (list) {
3093 if (IS_INSN(list) || IS_ADJUST(list)) {
3094 return list;
3095 }
3096 list = list->prev;
3097 }
3098 return 0;
3099}
3100
3101static void
3102unref_destination(INSN *iobj, int pos)
3103{
3104 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3105 --lobj->refcnt;
3106 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3107}
3108
3109static bool
3110replace_destination(INSN *dobj, INSN *nobj)
3111{
3112 VALUE n = OPERAND_AT(nobj, 0);
3113 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3114 LABEL *nl = (LABEL *)n;
3115 if (dl == nl) return false;
3116 --dl->refcnt;
3117 ++nl->refcnt;
3118 OPERAND_AT(dobj, 0) = n;
3119 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3120 return true;
3121}
3122
3123static LABEL*
3124find_destination(INSN *i)
3125{
3126 int pos, len = insn_len(i->insn_id);
3127 for (pos = 0; pos < len; ++pos) {
3128 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3129 return (LABEL *)OPERAND_AT(i, pos);
3130 }
3131 }
3132 return 0;
3133}
3134
3135static int
3136remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3137{
3138 LINK_ELEMENT *first = i, *end;
3139 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3140
3141 if (!i) return 0;
3142 unref_counts = ALLOCA_N(int, nlabels);
3143 MEMZERO(unref_counts, int, nlabels);
3144 end = i;
3145 do {
3146 LABEL *lab;
3147 if (IS_INSN(i)) {
3148 if (IS_INSN_ID(i, leave)) {
3149 end = i;
3150 break;
3151 }
3152 else if ((lab = find_destination((INSN *)i)) != 0) {
3153 unref_counts[lab->label_no]++;
3154 }
3155 }
3156 else if (IS_LABEL(i)) {
3157 lab = (LABEL *)i;
3158 if (lab->unremovable) return 0;
3159 if (lab->refcnt > unref_counts[lab->label_no]) {
3160 if (i == first) return 0;
3161 break;
3162 }
3163 continue;
3164 }
3165 else if (IS_TRACE(i)) {
3166 /* do nothing */
3167 }
3168 else if (IS_ADJUST(i)) {
3169 return 0;
3170 }
3171 end = i;
3172 } while ((i = i->next) != 0);
3173 i = first;
3174 do {
3175 if (IS_INSN(i)) {
3176 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3177 VALUE insn = INSN_OF(i);
3178 int pos, len = insn_len(insn);
3179 for (pos = 0; pos < len; ++pos) {
3180 switch (insn_op_types(insn)[pos]) {
3181 case TS_OFFSET:
3182 unref_destination((INSN *)i, pos);
3183 break;
3184 case TS_CALLDATA:
3185 --(body->ci_size);
3186 break;
3187 }
3188 }
3189 }
3190 ELEM_REMOVE(i);
3191 } while ((i != end) && (i = i->next) != 0);
3192 return 1;
3193}
3194
3195static int
3196iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3197{
3198 switch (OPERAND_AT(iobj, 0)) {
3199 case INT2FIX(0): /* empty array */
3200 ELEM_REMOVE(&iobj->link);
3201 return TRUE;
3202 case INT2FIX(1): /* single element array */
3203 ELEM_REMOVE(&iobj->link);
3204 return FALSE;
3205 default:
3206 iobj->insn_id = BIN(adjuststack);
3207 return TRUE;
3208 }
3209}
3210
3211static int
3212is_frozen_putstring(INSN *insn, VALUE *op)
3213{
3214 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3215 *op = OPERAND_AT(insn, 0);
3216 return 1;
3217 }
3218 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3219 *op = OPERAND_AT(insn, 0);
3220 return RB_TYPE_P(*op, T_STRING);
3221 }
3222 return 0;
3223}
3224
3225static int
3226optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3227{
3228 /*
3229 * putobject obj
3230 * dup
3231 * checktype T_XXX
3232 * branchif l1
3233 * l2:
3234 * ...
3235 * l1:
3236 *
3237 * => obj is a T_XXX
3238 *
3239 * putobject obj (T_XXX)
3240 * jump L1
3241 * L1:
3242 *
3243 * => obj is not a T_XXX
3244 *
3245 * putobject obj (T_XXX)
3246 * jump L2
3247 * L2:
3248 */
3249 int line, node_id;
3250 INSN *niobj, *ciobj, *dup = 0;
3251 LABEL *dest = 0;
3252 VALUE type;
3253
3254 switch (INSN_OF(iobj)) {
3255 case BIN(putstring):
3256 case BIN(putchilledstring):
3258 break;
3259 case BIN(putnil):
3260 type = INT2FIX(T_NIL);
3261 break;
3262 case BIN(putobject):
3263 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3264 break;
3265 default: return FALSE;
3266 }
3267
3268 ciobj = (INSN *)get_next_insn(iobj);
3269 if (IS_INSN_ID(ciobj, jump)) {
3270 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3271 }
3272 if (IS_INSN_ID(ciobj, dup)) {
3273 ciobj = (INSN *)get_next_insn(dup = ciobj);
3274 }
3275 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3276 niobj = (INSN *)get_next_insn(ciobj);
3277 if (!niobj) {
3278 /* TODO: putobject true/false */
3279 return FALSE;
3280 }
3281 switch (INSN_OF(niobj)) {
3282 case BIN(branchif):
3283 if (OPERAND_AT(ciobj, 0) == type) {
3284 dest = (LABEL *)OPERAND_AT(niobj, 0);
3285 }
3286 break;
3287 case BIN(branchunless):
3288 if (OPERAND_AT(ciobj, 0) != type) {
3289 dest = (LABEL *)OPERAND_AT(niobj, 0);
3290 }
3291 break;
3292 default:
3293 return FALSE;
3294 }
3295 line = ciobj->insn_info.line_no;
3296 node_id = ciobj->insn_info.node_id;
3297 if (!dest) {
3298 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3299 dest = (LABEL *)niobj->link.next; /* reuse label */
3300 }
3301 else {
3302 dest = NEW_LABEL(line);
3303 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3304 }
3305 }
3306 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3307 LABEL_REF(dest);
3308 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3309 return TRUE;
3310}
3311
3312static const struct rb_callinfo *
3313ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3314{
3315 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3316 vm_ci_flag(ci) | add,
3317 vm_ci_argc(ci),
3318 vm_ci_kwarg(ci));
3319 RB_OBJ_WRITTEN(iseq, ci, nci);
3320 return nci;
3321}
3322
3323static const struct rb_callinfo *
3324ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3325{
3326 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3327 vm_ci_flag(ci),
3328 argc,
3329 vm_ci_kwarg(ci));
3330 RB_OBJ_WRITTEN(iseq, ci, nci);
3331 return nci;
3332}
3333
3334#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3335
3336static int
3337iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3338{
3339 INSN *const iobj = (INSN *)list;
3340
3341 again:
3342 optimize_checktype(iseq, iobj);
3343
3344 if (IS_INSN_ID(iobj, jump)) {
3345 INSN *niobj, *diobj, *piobj;
3346 diobj = (INSN *)get_destination_insn(iobj);
3347 niobj = (INSN *)get_next_insn(iobj);
3348
3349 if (diobj == niobj) {
3350 /*
3351 * jump LABEL
3352 * LABEL:
3353 * =>
3354 * LABEL:
3355 */
3356 unref_destination(iobj, 0);
3357 ELEM_REMOVE(&iobj->link);
3358 return COMPILE_OK;
3359 }
3360 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3361 IS_INSN_ID(diobj, jump) &&
3362 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3363 diobj->insn_info.events == 0) {
3364 /*
3365 * useless jump elimination:
3366 * jump LABEL1
3367 * ...
3368 * LABEL1:
3369 * jump LABEL2
3370 *
3371 * => in this case, first jump instruction should jump to
3372 * LABEL2 directly
3373 */
3374 if (replace_destination(iobj, diobj)) {
3375 remove_unreachable_chunk(iseq, iobj->link.next);
3376 goto again;
3377 }
3378 }
3379 else if (IS_INSN_ID(diobj, leave)) {
3380 /*
3381 * jump LABEL
3382 * ...
3383 * LABEL:
3384 * leave
3385 * =>
3386 * leave
3387 * ...
3388 * LABEL:
3389 * leave
3390 */
3391 /* replace */
3392 unref_destination(iobj, 0);
3393 iobj->insn_id = BIN(leave);
3394 iobj->operand_size = 0;
3395 iobj->insn_info = diobj->insn_info;
3396 goto again;
3397 }
3398 else if (IS_INSN(iobj->link.prev) &&
3399 (piobj = (INSN *)iobj->link.prev) &&
3400 (IS_INSN_ID(piobj, branchif) ||
3401 IS_INSN_ID(piobj, branchunless))) {
3402 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3403 if (niobj == pdiobj) {
3404 int refcnt = IS_LABEL(piobj->link.next) ?
3405 ((LABEL *)piobj->link.next)->refcnt : 0;
3406 /*
3407 * useless jump elimination (if/unless destination):
3408 * if L1
3409 * jump L2
3410 * L1:
3411 * ...
3412 * L2:
3413 *
3414 * ==>
3415 * unless L2
3416 * L1:
3417 * ...
3418 * L2:
3419 */
3420 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3421 ? BIN(branchunless) : BIN(branchif);
3422 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3423 ELEM_REMOVE(&iobj->link);
3424 }
3425 else {
3426 /* TODO: replace other branch destinations too */
3427 }
3428 return COMPILE_OK;
3429 }
3430 else if (diobj == pdiobj) {
3431 /*
3432 * useless jump elimination (if/unless before jump):
3433 * L1:
3434 * ...
3435 * if L1
3436 * jump L1
3437 *
3438 * ==>
3439 * L1:
3440 * ...
3441 * pop
3442 * jump L1
3443 */
3444 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3445 ELEM_REPLACE(&piobj->link, &popiobj->link);
3446 }
3447 }
3448 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3449 goto again;
3450 }
3451 }
3452
3453 /*
3454 * putstring "beg"
3455 * putstring "end"
3456 * newrange excl
3457 *
3458 * ==>
3459 *
3460 * putobject "beg".."end"
3461 */
3462 if (IS_INSN_ID(iobj, newrange)) {
3463 INSN *const range = iobj;
3464 INSN *beg, *end;
3465 VALUE str_beg, str_end;
3466
3467 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3468 is_frozen_putstring(end, &str_end) &&
3469 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3470 is_frozen_putstring(beg, &str_beg)) {
3471 int excl = FIX2INT(OPERAND_AT(range, 0));
3472 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3473
3474 ELEM_REMOVE(&beg->link);
3475 ELEM_REMOVE(&end->link);
3476 range->insn_id = BIN(putobject);
3477 OPERAND_AT(range, 0) = lit_range;
3478 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3479 }
3480 }
3481
3482 if (IS_INSN_ID(iobj, leave)) {
3483 remove_unreachable_chunk(iseq, iobj->link.next);
3484 }
3485
3486 /*
3487 * ...
3488 * duparray [...]
3489 * concatarray | concattoarray
3490 * =>
3491 * ...
3492 * putobject [...]
3493 * concatarray | concattoarray
3494 */
3495 if (IS_INSN_ID(iobj, duparray)) {
3496 LINK_ELEMENT *next = iobj->link.next;
3497 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3498 iobj->insn_id = BIN(putobject);
3499 }
3500 }
3501
3502 /*
3503 * duparray [...]
3504 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3505 * =>
3506 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3507 */
3508 if (IS_INSN_ID(iobj, duparray)) {
3509 LINK_ELEMENT *next = iobj->link.next;
3510 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3511 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3512 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3513
3514 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3515 VALUE ary = iobj->operands[0];
3517
3518 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3519 ELEM_REMOVE(next);
3520 }
3521 }
3522 }
3523
3524 /*
3525 * duphash {...}
3526 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3527 * =>
3528 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3529 */
3530 if (IS_INSN_ID(iobj, duphash)) {
3531 LINK_ELEMENT *next = iobj->link.next;
3532 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3533 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3534 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3535
3536 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3537 VALUE hash = iobj->operands[0];
3538 rb_obj_reveal(hash, rb_cHash);
3539
3540 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3541 ELEM_REMOVE(next);
3542 }
3543 }
3544 }
3545
3546 /*
3547 * newarray 0
3548 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3549 * =>
3550 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3551 */
3552 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3553 LINK_ELEMENT *next = iobj->link.next;
3554 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3555 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3556 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3557
3558 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3559 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3560 ELEM_REMOVE(next);
3561 }
3562 }
3563 }
3564
3565 /*
3566 * newhash 0
3567 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3568 * =>
3569 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3570 */
3571 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3572 LINK_ELEMENT *next = iobj->link.next;
3573 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3574 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3575 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3576
3577 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3578 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3579 ELEM_REMOVE(next);
3580 }
3581 }
3582 }
3583
3584 if (IS_INSN_ID(iobj, branchif) ||
3585 IS_INSN_ID(iobj, branchnil) ||
3586 IS_INSN_ID(iobj, branchunless)) {
3587 /*
3588 * if L1
3589 * ...
3590 * L1:
3591 * jump L2
3592 * =>
3593 * if L2
3594 */
3595 INSN *nobj = (INSN *)get_destination_insn(iobj);
3596
3597 /* This is super nasty hack!!!
3598 *
3599 * This jump-jump optimization may ignore event flags of the jump
3600 * instruction being skipped. Actually, Line 2 TracePoint event
3601 * is never fired in the following code:
3602 *
3603 * 1: raise if 1 == 2
3604 * 2: while true
3605 * 3: break
3606 * 4: end
3607 *
3608 * This is critical for coverage measurement. [Bug #15980]
3609 *
3610 * This is a stopgap measure: stop the jump-jump optimization if
3611 * coverage measurement is enabled and if the skipped instruction
3612 * has any event flag.
3613 *
3614 * Note that, still, TracePoint Line event does not occur on Line 2.
3615 * This should be fixed in future.
3616 */
3617 int stop_optimization =
3618 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3619 nobj->link.type == ISEQ_ELEMENT_INSN &&
3620 nobj->insn_info.events;
3621 if (!stop_optimization) {
3622 INSN *pobj = (INSN *)iobj->link.prev;
3623 int prev_dup = 0;
3624 if (pobj) {
3625 if (!IS_INSN(&pobj->link))
3626 pobj = 0;
3627 else if (IS_INSN_ID(pobj, dup))
3628 prev_dup = 1;
3629 }
3630
3631 for (;;) {
3632 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3633 if (!replace_destination(iobj, nobj)) break;
3634 }
3635 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3636 !!(nobj = (INSN *)nobj->link.next) &&
3637 /* basic blocks, with no labels in the middle */
3638 nobj->insn_id == iobj->insn_id) {
3639 /*
3640 * dup
3641 * if L1
3642 * ...
3643 * L1:
3644 * dup
3645 * if L2
3646 * =>
3647 * dup
3648 * if L2
3649 * ...
3650 * L1:
3651 * dup
3652 * if L2
3653 */
3654 if (!replace_destination(iobj, nobj)) break;
3655 }
3656 else if (pobj) {
3657 /*
3658 * putnil
3659 * if L1
3660 * =>
3661 * # nothing
3662 *
3663 * putobject true
3664 * if L1
3665 * =>
3666 * jump L1
3667 *
3668 * putstring ".."
3669 * if L1
3670 * =>
3671 * jump L1
3672 *
3673 * putstring ".."
3674 * dup
3675 * if L1
3676 * =>
3677 * putstring ".."
3678 * jump L1
3679 *
3680 */
3681 int cond;
3682 if (prev_dup && IS_INSN(pobj->link.prev)) {
3683 pobj = (INSN *)pobj->link.prev;
3684 }
3685 if (IS_INSN_ID(pobj, putobject)) {
3686 cond = (IS_INSN_ID(iobj, branchif) ?
3687 OPERAND_AT(pobj, 0) != Qfalse :
3688 IS_INSN_ID(iobj, branchunless) ?
3689 OPERAND_AT(pobj, 0) == Qfalse :
3690 FALSE);
3691 }
3692 else if (IS_INSN_ID(pobj, putstring) ||
3693 IS_INSN_ID(pobj, duparray) ||
3694 IS_INSN_ID(pobj, newarray)) {
3695 cond = IS_INSN_ID(iobj, branchif);
3696 }
3697 else if (IS_INSN_ID(pobj, putnil)) {
3698 cond = !IS_INSN_ID(iobj, branchif);
3699 }
3700 else break;
3701 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3702 ELEM_REMOVE(iobj->link.prev);
3703 }
3704 else if (!iseq_pop_newarray(iseq, pobj)) {
3705 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3706 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3707 }
3708 if (cond) {
3709 if (prev_dup) {
3710 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3711 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3712 }
3713 iobj->insn_id = BIN(jump);
3714 goto again;
3715 }
3716 else {
3717 unref_destination(iobj, 0);
3718 ELEM_REMOVE(&iobj->link);
3719 }
3720 break;
3721 }
3722 else break;
3723 nobj = (INSN *)get_destination_insn(nobj);
3724 }
3725 }
3726 }
3727
3728 if (IS_INSN_ID(iobj, pop)) {
3729 /*
3730 * putself / putnil / putobject obj / putstring "..."
3731 * pop
3732 * =>
3733 * # do nothing
3734 */
3735 LINK_ELEMENT *prev = iobj->link.prev;
3736 if (IS_INSN(prev)) {
3737 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3738 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3739 previ == BIN(putself) || previ == BIN(putstring) ||
3740 previ == BIN(putchilledstring) ||
3741 previ == BIN(dup) ||
3742 previ == BIN(getlocal) ||
3743 previ == BIN(getblockparam) ||
3744 previ == BIN(getblockparamproxy) ||
3745 previ == BIN(getinstancevariable) ||
3746 previ == BIN(duparray)) {
3747 /* just push operand or static value and pop soon, no
3748 * side effects */
3749 ELEM_REMOVE(prev);
3750 ELEM_REMOVE(&iobj->link);
3751 }
3752 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3753 ELEM_REMOVE(&iobj->link);
3754 }
3755 else if (previ == BIN(concatarray)) {
3756 INSN *piobj = (INSN *)prev;
3757 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3758 INSN_OF(piobj) = BIN(pop);
3759 }
3760 else if (previ == BIN(concatstrings)) {
3761 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3762 ELEM_REMOVE(prev);
3763 }
3764 else {
3765 ELEM_REMOVE(&iobj->link);
3766 INSN_OF(prev) = BIN(adjuststack);
3767 }
3768 }
3769 }
3770 }
3771
3772 if (IS_INSN_ID(iobj, newarray) ||
3773 IS_INSN_ID(iobj, duparray) ||
3774 IS_INSN_ID(iobj, concatarray) ||
3775 IS_INSN_ID(iobj, splatarray) ||
3776 0) {
3777 /*
3778 * newarray N
3779 * splatarray
3780 * =>
3781 * newarray N
3782 * newarray always puts an array
3783 */
3784 LINK_ELEMENT *next = iobj->link.next;
3785 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3786 /* remove splatarray following always-array insn */
3787 ELEM_REMOVE(next);
3788 }
3789 }
3790
3791 if (IS_INSN_ID(iobj, newarray)) {
3792 LINK_ELEMENT *next = iobj->link.next;
3793 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3794 OPERAND_AT(next, 1) == INT2FIX(0)) {
3795 VALUE op1, op2;
3796 op1 = OPERAND_AT(iobj, 0);
3797 op2 = OPERAND_AT(next, 0);
3798 ELEM_REMOVE(next);
3799
3800 if (op1 == op2) {
3801 /*
3802 * newarray 2
3803 * expandarray 2, 0
3804 * =>
3805 * swap
3806 */
3807 if (op1 == INT2FIX(2)) {
3808 INSN_OF(iobj) = BIN(swap);
3809 iobj->operand_size = 0;
3810 }
3811 /*
3812 * newarray X
3813 * expandarray X, 0
3814 * =>
3815 * opt_reverse X
3816 */
3817 else {
3818 INSN_OF(iobj) = BIN(opt_reverse);
3819 }
3820 }
3821 else {
3822 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3823 INSN_OF(iobj) = BIN(opt_reverse);
3824 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3825
3826 if (op1 > op2) {
3827 /* X > Y
3828 * newarray X
3829 * expandarray Y, 0
3830 * =>
3831 * pop * (Y-X)
3832 * opt_reverse Y
3833 */
3834 for (; diff > 0; diff--) {
3835 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3836 }
3837 }
3838 else { /* (op1 < op2) */
3839 /* X < Y
3840 * newarray X
3841 * expandarray Y, 0
3842 * =>
3843 * putnil * (Y-X)
3844 * opt_reverse Y
3845 */
3846 for (; diff < 0; diff++) {
3847 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3848 }
3849 }
3850 }
3851 }
3852 }
3853
3854 if (IS_INSN_ID(iobj, duparray)) {
3855 LINK_ELEMENT *next = iobj->link.next;
3856 /*
3857 * duparray obj
3858 * expandarray X, 0
3859 * =>
3860 * putobject obj
3861 * expandarray X, 0
3862 */
3863 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3864 INSN_OF(iobj) = BIN(putobject);
3865 }
3866 }
3867
3868 if (IS_INSN_ID(iobj, anytostring)) {
3869 LINK_ELEMENT *next = iobj->link.next;
3870 /*
3871 * anytostring
3872 * concatstrings 1
3873 * =>
3874 * anytostring
3875 */
3876 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3877 OPERAND_AT(next, 0) == INT2FIX(1)) {
3878 ELEM_REMOVE(next);
3879 }
3880 }
3881
3882 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3883 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3884 /*
3885 * putstring ""
3886 * concatstrings N
3887 * =>
3888 * concatstrings N-1
3889 */
3890 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3891 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3892 INSN *next = (INSN *)iobj->link.next;
3893 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3894 ELEM_REMOVE(&next->link);
3895 }
3896 ELEM_REMOVE(&iobj->link);
3897 }
3898 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3899 INSN *next = (INSN *)iobj->link.next;
3900 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3901 VALUE src = OPERAND_AT(iobj, 0);
3902 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3903 VALUE path = rb_iseq_path(iseq);
3904 int line = iobj->insn_info.line_no;
3905 VALUE errinfo = rb_errinfo();
3906 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3907 if (NIL_P(re)) {
3908 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3909 rb_set_errinfo(errinfo);
3910 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3911 }
3912 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3913 ELEM_REMOVE(iobj->link.next);
3914 }
3915 }
3916 }
3917
3918 if (IS_INSN_ID(iobj, concatstrings)) {
3919 /*
3920 * concatstrings N
3921 * concatstrings M
3922 * =>
3923 * concatstrings N+M-1
3924 */
3925 LINK_ELEMENT *next = iobj->link.next;
3926 INSN *jump = 0;
3927 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3928 next = get_destination_insn(jump = (INSN *)next);
3929 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3930 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3931 OPERAND_AT(iobj, 0) = INT2FIX(n);
3932 if (jump) {
3933 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3934 if (!--label->refcnt) {
3935 ELEM_REMOVE(&label->link);
3936 }
3937 else {
3938 label = NEW_LABEL(0);
3939 OPERAND_AT(jump, 0) = (VALUE)label;
3940 }
3941 label->refcnt++;
3942 ELEM_INSERT_NEXT(next, &label->link);
3943 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3944 }
3945 else {
3946 ELEM_REMOVE(next);
3947 }
3948 }
3949 }
3950
3951 if (do_tailcallopt &&
3952 (IS_INSN_ID(iobj, send) ||
3953 IS_INSN_ID(iobj, invokesuper))) {
3954 /*
3955 * send ...
3956 * leave
3957 * =>
3958 * send ..., ... | VM_CALL_TAILCALL, ...
3959 * leave # unreachable
3960 */
3961 INSN *piobj = NULL;
3962 if (iobj->link.next) {
3963 LINK_ELEMENT *next = iobj->link.next;
3964 do {
3965 if (!IS_INSN(next)) {
3966 next = next->next;
3967 continue;
3968 }
3969 switch (INSN_OF(next)) {
3970 case BIN(nop):
3971 next = next->next;
3972 break;
3973 case BIN(jump):
3974 /* if cond
3975 * return tailcall
3976 * end
3977 */
3978 next = get_destination_insn((INSN *)next);
3979 break;
3980 case BIN(leave):
3981 piobj = iobj;
3982 /* fall through */
3983 default:
3984 next = NULL;
3985 break;
3986 }
3987 } while (next);
3988 }
3989
3990 if (piobj) {
3991 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3992 if (IS_INSN_ID(piobj, send) ||
3993 IS_INSN_ID(piobj, invokesuper)) {
3994 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3995 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3996 OPERAND_AT(piobj, 0) = (VALUE)ci;
3997 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3998 }
3999 }
4000 else {
4001 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4002 OPERAND_AT(piobj, 0) = (VALUE)ci;
4003 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4004 }
4005 }
4006 }
4007
4008 if (IS_INSN_ID(iobj, dup)) {
4009 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4010 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4011
4012 /*
4013 * dup
4014 * setlocal x, y
4015 * setlocal x, y
4016 * =>
4017 * dup
4018 * setlocal x, y
4019 */
4020 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4021 set2 = set1->next;
4022 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4023 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4024 ELEM_REMOVE(set1);
4025 ELEM_REMOVE(&iobj->link);
4026 }
4027 }
4028
4029 /*
4030 * dup
4031 * setlocal x, y
4032 * dup
4033 * setlocal x, y
4034 * =>
4035 * dup
4036 * setlocal x, y
4037 */
4038 else if (IS_NEXT_INSN_ID(set1, dup) &&
4039 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4040 set2 = set1->next->next;
4041 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4042 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4043 ELEM_REMOVE(set1->next);
4044 ELEM_REMOVE(set2);
4045 }
4046 }
4047 }
4048 }
4049
4050 /*
4051 * getlocal x, y
4052 * dup
4053 * setlocal x, y
4054 * =>
4055 * dup
4056 */
4057 if (IS_INSN_ID(iobj, getlocal)) {
4058 LINK_ELEMENT *niobj = &iobj->link;
4059 if (IS_NEXT_INSN_ID(niobj, dup)) {
4060 niobj = niobj->next;
4061 }
4062 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4063 LINK_ELEMENT *set1 = niobj->next;
4064 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4065 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4066 ELEM_REMOVE(set1);
4067 ELEM_REMOVE(niobj);
4068 }
4069 }
4070 }
4071
4072 /*
4073 * opt_invokebuiltin_delegate
4074 * trace
4075 * leave
4076 * =>
4077 * opt_invokebuiltin_delegate_leave
4078 * trace
4079 * leave
4080 */
4081 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4082 if (IS_TRACE(iobj->link.next)) {
4083 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4084 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4085 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4086 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4087 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4088 }
4089 }
4090 }
4091 }
4092
4093 /*
4094 * getblockparam
4095 * branchif / branchunless
4096 * =>
4097 * getblockparamproxy
4098 * branchif / branchunless
4099 */
4100 if (IS_INSN_ID(iobj, getblockparam)) {
4101 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4102 iobj->insn_id = BIN(getblockparamproxy);
4103 }
4104 }
4105
4106 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4107 LINK_ELEMENT *niobj = &iobj->link;
4108 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4109 niobj = niobj->next;
4110 LINK_ELEMENT *siobj;
4111 unsigned int set_flags = 0, unset_flags = 0;
4112
4113 /*
4114 * Eliminate hash allocation for f(*a, kw: 1)
4115 *
4116 * splatarray false
4117 * duphash
4118 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4119 * =>
4120 * splatarray false
4121 * putobject
4122 * send ARGS_SPLAT|KW_SPLAT
4123 */
4124 if (IS_NEXT_INSN_ID(niobj, send)) {
4125 siobj = niobj->next;
4126 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4127 unset_flags = VM_CALL_ARGS_BLOCKARG;
4128 }
4129 /*
4130 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4131 *
4132 * splatarray false
4133 * duphash
4134 * getlocal / getinstancevariable / getblockparamproxy
4135 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4136 * =>
4137 * splatarray false
4138 * putobject
4139 * getlocal / getinstancevariable / getblockparamproxy
4140 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4141 */
4142 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4143 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4144 siobj = niobj->next->next;
4145 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4146 }
4147
4148 if (set_flags) {
4149 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4150 unsigned int flags = vm_ci_flag(ci);
4151 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4152 ((INSN*)niobj)->insn_id = BIN(putobject);
4153 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4154
4155 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4156 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4157 RB_OBJ_WRITTEN(iseq, ci, nci);
4158 OPERAND_AT(siobj, 0) = (VALUE)nci;
4159 }
4160 }
4161 }
4162 }
4163
4164 return COMPILE_OK;
4165}
4166
4167static int
4168insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4169{
4170 if (insn_id == BIN(opt_neq)) {
4171 VALUE original_ci = iobj->operands[0];
4172 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4173 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4174 }
4175 else {
4176 iobj->insn_id = insn_id;
4177 iobj->operand_size = insn_len(insn_id) - 1;
4178 }
4179 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4180
4181 return COMPILE_OK;
4182}
4183
4184static int
4185iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4186{
4187 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4188 IS_INSN(iobj->link.next)) {
4189 /*
4190 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4191 */
4192 INSN *niobj = (INSN *)iobj->link.next;
4193 if (IS_INSN_ID(niobj, send)) {
4194 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4195 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4196 VALUE method = INT2FIX(0);
4197 switch (vm_ci_mid(ci)) {
4198 case idMax:
4199 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4200 break;
4201 case idMin:
4202 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4203 break;
4204 case idHash:
4205 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4206 break;
4207 }
4208
4209 if (method != INT2FIX(0)) {
4210 VALUE num = iobj->operands[0];
4211 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4212 ELEM_REMOVE(&niobj->link);
4213 return COMPILE_OK;
4214 }
4215 }
4216 }
4217 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4218 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4219 IS_NEXT_INSN_ID(&niobj->link, send)) {
4220 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4221 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4222 VALUE num = iobj->operands[0];
4223 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4224 ELEM_REMOVE(&iobj->link);
4225 ELEM_REMOVE(niobj->link.next);
4226 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4227 return COMPILE_OK;
4228 }
4229 }
4230 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4231 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4232 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4233 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4234 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4235 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4236 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4237 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4238 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4239 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4240 VALUE num = iobj->operands[0];
4241 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4242 // Remove the "send" insn.
4243 ELEM_REMOVE((niobj->link.next)->next);
4244 // Remove the modified insn from its original "newarray" position...
4245 ELEM_REMOVE(&iobj->link);
4246 // and insert it after the buffer insn.
4247 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4248 return COMPILE_OK;
4249 }
4250 }
4251
4252 // Break the "else if" chain since some prior checks abort after sub-ifs.
4253 // We already found "newarray". To match `[...].include?(arg)` we look for
4254 // the instruction(s) representing the argument followed by a "send".
4255 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4256 IS_INSN_ID(niobj, putobject) ||
4257 IS_INSN_ID(niobj, putself) ||
4258 IS_INSN_ID(niobj, getlocal) ||
4259 IS_INSN_ID(niobj, getinstancevariable)) &&
4260 IS_NEXT_INSN_ID(&niobj->link, send)) {
4261
4262 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4263 const struct rb_callinfo *ci;
4264 // Allow any number (0 or more) of simple method calls on the argument
4265 // (as in `[...].include?(arg.method1.method2)`.
4266 do {
4267 sendobj = sendobj->next;
4268 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4269 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4270
4271 // If this send is for .include? with one arg we can do our opt.
4272 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4273 VALUE num = iobj->operands[0];
4274 INSN *sendins = (INSN *)sendobj;
4275 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4276 // Remove the original "newarray" insn.
4277 ELEM_REMOVE(&iobj->link);
4278 return COMPILE_OK;
4279 }
4280 }
4281 }
4282
4283 /*
4284 * duparray [...]
4285 * some insn for the arg...
4286 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4287 * =>
4288 * arg insn...
4289 * opt_duparray_send [...], :include?, 1
4290 */
4291 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4292 INSN *niobj = (INSN *)iobj->link.next;
4293 if ((IS_INSN_ID(niobj, getlocal) ||
4294 IS_INSN_ID(niobj, getinstancevariable) ||
4295 IS_INSN_ID(niobj, putself)) &&
4296 IS_NEXT_INSN_ID(&niobj->link, send)) {
4297
4298 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4299 const struct rb_callinfo *ci;
4300 // Allow any number (0 or more) of simple method calls on the argument
4301 // (as in `[...].include?(arg.method1.method2)`.
4302 do {
4303 sendobj = sendobj->next;
4304 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4305 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4306
4307 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4308 // Move the array arg from duparray to opt_duparray_send.
4309 VALUE ary = iobj->operands[0];
4311
4312 INSN *sendins = (INSN *)sendobj;
4313 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4314
4315 // Remove the duparray insn.
4316 ELEM_REMOVE(&iobj->link);
4317 return COMPILE_OK;
4318 }
4319 }
4320 }
4321
4322
4323 if (IS_INSN_ID(iobj, send)) {
4324 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4325 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4326
4327#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4328 if (vm_ci_simple(ci)) {
4329 switch (vm_ci_argc(ci)) {
4330 case 0:
4331 switch (vm_ci_mid(ci)) {
4332 case idLength: SP_INSN(length); return COMPILE_OK;
4333 case idSize: SP_INSN(size); return COMPILE_OK;
4334 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4335 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4336 case idSucc: SP_INSN(succ); return COMPILE_OK;
4337 case idNot: SP_INSN(not); return COMPILE_OK;
4338 }
4339 break;
4340 case 1:
4341 switch (vm_ci_mid(ci)) {
4342 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4343 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4344 case idMULT: SP_INSN(mult); return COMPILE_OK;
4345 case idDIV: SP_INSN(div); return COMPILE_OK;
4346 case idMOD: SP_INSN(mod); return COMPILE_OK;
4347 case idEq: SP_INSN(eq); return COMPILE_OK;
4348 case idNeq: SP_INSN(neq); return COMPILE_OK;
4349 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4350 case idLT: SP_INSN(lt); return COMPILE_OK;
4351 case idLE: SP_INSN(le); return COMPILE_OK;
4352 case idGT: SP_INSN(gt); return COMPILE_OK;
4353 case idGE: SP_INSN(ge); return COMPILE_OK;
4354 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4355 case idAREF: SP_INSN(aref); return COMPILE_OK;
4356 case idAnd: SP_INSN(and); return COMPILE_OK;
4357 case idOr: SP_INSN(or); return COMPILE_OK;
4358 }
4359 break;
4360 case 2:
4361 switch (vm_ci_mid(ci)) {
4362 case idASET: SP_INSN(aset); return COMPILE_OK;
4363 }
4364 break;
4365 }
4366 }
4367
4368 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4369 iobj->insn_id = BIN(opt_send_without_block);
4370 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4371 }
4372 }
4373#undef SP_INSN
4374
4375 return COMPILE_OK;
4376}
4377
4378static inline int
4379tailcallable_p(rb_iseq_t *iseq)
4380{
4381 switch (ISEQ_BODY(iseq)->type) {
4382 case ISEQ_TYPE_TOP:
4383 case ISEQ_TYPE_EVAL:
4384 case ISEQ_TYPE_MAIN:
4385 /* not tail callable because cfp will be over popped */
4386 case ISEQ_TYPE_RESCUE:
4387 case ISEQ_TYPE_ENSURE:
4388 /* rescue block can't tail call because of errinfo */
4389 return FALSE;
4390 default:
4391 return TRUE;
4392 }
4393}
4394
4395static int
4396iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4397{
4398 LINK_ELEMENT *list;
4399 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4400 const int do_tailcallopt = tailcallable_p(iseq) &&
4401 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4402 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4403 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4404 int rescue_level = 0;
4405 int tailcallopt = do_tailcallopt;
4406
4407 list = FIRST_ELEMENT(anchor);
4408
4409 int do_block_optimization = 0;
4410 LABEL * block_loop_label = NULL;
4411
4412 // If we're optimizing a block
4413 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4414 do_block_optimization = 1;
4415
4416 // If the block starts with a nop and a label,
4417 // record the label so we can detect if it's a jump target
4418 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4419 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4420 block_loop_label = (LABEL *)le->next;
4421 }
4422 }
4423
4424 while (list) {
4425 if (IS_INSN(list)) {
4426 if (do_peepholeopt) {
4427 iseq_peephole_optimize(iseq, list, tailcallopt);
4428 }
4429 if (do_si) {
4430 iseq_specialized_instruction(iseq, (INSN *)list);
4431 }
4432 if (do_ou) {
4433 insn_operands_unification((INSN *)list);
4434 }
4435
4436 if (do_block_optimization) {
4437 INSN * item = (INSN *)list;
4438 // Give up if there is a throw
4439 if (IS_INSN_ID(item, throw)) {
4440 do_block_optimization = 0;
4441 }
4442 else {
4443 // If the instruction has a jump target, check if the
4444 // jump target is the block loop label
4445 const char *types = insn_op_types(item->insn_id);
4446 for (int j = 0; types[j]; j++) {
4447 if (types[j] == TS_OFFSET) {
4448 // If the jump target is equal to the block loop
4449 // label, then we can't do the optimization because
4450 // the leading `nop` instruction fires the block
4451 // entry tracepoint
4452 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4453 if (target == block_loop_label) {
4454 do_block_optimization = 0;
4455 }
4456 }
4457 }
4458 }
4459 }
4460 }
4461 if (IS_LABEL(list)) {
4462 switch (((LABEL *)list)->rescued) {
4463 case LABEL_RESCUE_BEG:
4464 rescue_level++;
4465 tailcallopt = FALSE;
4466 break;
4467 case LABEL_RESCUE_END:
4468 if (!--rescue_level) tailcallopt = do_tailcallopt;
4469 break;
4470 }
4471 }
4472 list = list->next;
4473 }
4474
4475 if (do_block_optimization) {
4476 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4477 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4478 ELEM_REMOVE(le);
4479 }
4480 }
4481 return COMPILE_OK;
4482}
4483
4484#if OPT_INSTRUCTIONS_UNIFICATION
4485static INSN *
4486new_unified_insn(rb_iseq_t *iseq,
4487 int insn_id, int size, LINK_ELEMENT *seq_list)
4488{
4489 INSN *iobj = 0;
4490 LINK_ELEMENT *list = seq_list;
4491 int i, argc = 0;
4492 VALUE *operands = 0, *ptr = 0;
4493
4494
4495 /* count argc */
4496 for (i = 0; i < size; i++) {
4497 iobj = (INSN *)list;
4498 argc += iobj->operand_size;
4499 list = list->next;
4500 }
4501
4502 if (argc > 0) {
4503 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4504 }
4505
4506 /* copy operands */
4507 list = seq_list;
4508 for (i = 0; i < size; i++) {
4509 iobj = (INSN *)list;
4510 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4511 ptr += iobj->operand_size;
4512 list = list->next;
4513 }
4514
4515 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4516}
4517#endif
4518
4519/*
4520 * This scheme can get more performance if do this optimize with
4521 * label address resolving.
4522 * It's future work (if compile time was bottle neck).
4523 */
4524static int
4525iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4526{
4527#if OPT_INSTRUCTIONS_UNIFICATION
4528 LINK_ELEMENT *list;
4529 INSN *iobj, *niobj;
4530 int id, k;
4531 intptr_t j;
4532
4533 list = FIRST_ELEMENT(anchor);
4534 while (list) {
4535 if (IS_INSN(list)) {
4536 iobj = (INSN *)list;
4537 id = iobj->insn_id;
4538 if (unified_insns_data[id] != 0) {
4539 const int *const *entry = unified_insns_data[id];
4540 for (j = 1; j < (intptr_t)entry[0]; j++) {
4541 const int *unified = entry[j];
4542 LINK_ELEMENT *li = list->next;
4543 for (k = 2; k < unified[1]; k++) {
4544 if (!IS_INSN(li) ||
4545 ((INSN *)li)->insn_id != unified[k]) {
4546 goto miss;
4547 }
4548 li = li->next;
4549 }
4550 /* matched */
4551 niobj =
4552 new_unified_insn(iseq, unified[0], unified[1] - 1,
4553 list);
4554
4555 /* insert to list */
4556 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4557 niobj->link.next = li;
4558 if (li) {
4559 li->prev = (LINK_ELEMENT *)niobj;
4560 }
4561
4562 list->prev->next = (LINK_ELEMENT *)niobj;
4563 list = (LINK_ELEMENT *)niobj;
4564 break;
4565 miss:;
4566 }
4567 }
4568 }
4569 list = list->next;
4570 }
4571#endif
4572 return COMPILE_OK;
4573}
4574
4575static int
4576all_string_result_p(const NODE *node)
4577{
4578 if (!node) return FALSE;
4579 switch (nd_type(node)) {
4580 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4581 return TRUE;
4582 case NODE_IF: case NODE_UNLESS:
4583 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4584 if (all_string_result_p(RNODE_IF(node)->nd_body))
4585 return all_string_result_p(RNODE_IF(node)->nd_else);
4586 return FALSE;
4587 case NODE_AND: case NODE_OR:
4588 if (!RNODE_AND(node)->nd_2nd)
4589 return all_string_result_p(RNODE_AND(node)->nd_1st);
4590 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4591 return FALSE;
4592 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4593 default:
4594 return FALSE;
4595 }
4596}
4597
4599 rb_iseq_t *const iseq;
4600 LINK_ANCHOR *const ret;
4601 VALUE lit;
4602 const NODE *lit_node;
4603 int cnt;
4604 int dregx;
4605};
4606
4607static int
4608append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4609{
4610 VALUE s = rb_str_new_mutable_parser_string(str);
4611 if (args->dregx) {
4612 VALUE error = rb_reg_check_preprocess(s);
4613 if (!NIL_P(error)) {
4614 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4615 return COMPILE_NG;
4616 }
4617 }
4618 if (NIL_P(args->lit)) {
4619 args->lit = s;
4620 args->lit_node = node;
4621 }
4622 else {
4623 rb_str_buf_append(args->lit, s);
4624 }
4625 return COMPILE_OK;
4626}
4627
4628static void
4629flush_dstr_fragment(struct dstr_ctxt *args)
4630{
4631 if (!NIL_P(args->lit)) {
4632 rb_iseq_t *iseq = args->iseq;
4633 VALUE lit = args->lit;
4634 args->lit = Qnil;
4635 lit = rb_fstring(lit);
4636 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4637 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4638 args->cnt++;
4639 }
4640}
4641
4642static int
4643compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4644{
4645 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4646 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4647
4648 if (str) {
4649 CHECK(append_dstr_fragment(args, node, str));
4650 }
4651
4652 while (list) {
4653 const NODE *const head = list->nd_head;
4654 if (nd_type_p(head, NODE_STR)) {
4655 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4656 }
4657 else if (nd_type_p(head, NODE_DSTR)) {
4658 CHECK(compile_dstr_fragments_0(args, head));
4659 }
4660 else {
4661 flush_dstr_fragment(args);
4662 rb_iseq_t *iseq = args->iseq;
4663 CHECK(COMPILE(args->ret, "each string", head));
4664 args->cnt++;
4665 }
4666 list = (struct RNode_LIST *)list->nd_next;
4667 }
4668 return COMPILE_OK;
4669}
4670
4671static int
4672compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4673{
4674 struct dstr_ctxt args = {
4675 .iseq = iseq, .ret = ret,
4676 .lit = Qnil, .lit_node = NULL,
4677 .cnt = 0, .dregx = dregx,
4678 };
4679 CHECK(compile_dstr_fragments_0(&args, node));
4680 flush_dstr_fragment(&args);
4681
4682 *cntp = args.cnt;
4683
4684 return COMPILE_OK;
4685}
4686
4687static int
4688compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4689{
4690 while (node && nd_type_p(node, NODE_BLOCK)) {
4691 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4692 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4693 node = RNODE_BLOCK(node)->nd_next;
4694 }
4695 if (node) {
4696 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4697 }
4698 return COMPILE_OK;
4699}
4700
4701static int
4702compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4703{
4704 int cnt;
4705 if (!RNODE_DSTR(node)->nd_next) {
4706 VALUE lit = rb_node_dstr_string_val(node);
4707 ADD_INSN1(ret, node, putstring, lit);
4708 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4709 }
4710 else {
4711 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4712 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4713 }
4714 return COMPILE_OK;
4715}
4716
4717static int
4718compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4719{
4720 int cnt;
4721 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4722
4723 if (!RNODE_DREGX(node)->nd_next) {
4724 if (!popped) {
4725 VALUE src = rb_node_dregx_string_val(node);
4726 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4727 ADD_INSN1(ret, node, putobject, match);
4728 RB_OBJ_WRITTEN(iseq, Qundef, match);
4729 }
4730 return COMPILE_OK;
4731 }
4732
4733 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4734 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4735
4736 if (popped) {
4737 ADD_INSN(ret, node, pop);
4738 }
4739
4740 return COMPILE_OK;
4741}
4742
4743static int
4744compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4745 LABEL *then_label, LABEL *else_label)
4746{
4747 const int line = nd_line(node);
4748 LABEL *lend = NEW_LABEL(line);
4749 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4750 + VM_SVAR_FLIPFLOP_START;
4751 VALUE key = INT2FIX(cnt);
4752
4753 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4754 ADD_INSNL(ret, node, branchif, lend);
4755
4756 /* *flip == 0 */
4757 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4758 ADD_INSNL(ret, node, branchunless, else_label);
4759 ADD_INSN1(ret, node, putobject, Qtrue);
4760 ADD_INSN1(ret, node, setspecial, key);
4761 if (!again) {
4762 ADD_INSNL(ret, node, jump, then_label);
4763 }
4764
4765 /* *flip == 1 */
4766 ADD_LABEL(ret, lend);
4767 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4768 ADD_INSNL(ret, node, branchunless, then_label);
4769 ADD_INSN1(ret, node, putobject, Qfalse);
4770 ADD_INSN1(ret, node, setspecial, key);
4771 ADD_INSNL(ret, node, jump, then_label);
4772
4773 return COMPILE_OK;
4774}
4775
4776static int
4777compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4778 LABEL *then_label, LABEL *else_label);
4779
4780#define COMPILE_SINGLE 2
4781static int
4782compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4783 LABEL *then_label, LABEL *else_label)
4784{
4785 DECL_ANCHOR(seq);
4786 INIT_ANCHOR(seq);
4787 LABEL *label = NEW_LABEL(nd_line(cond));
4788 if (!then_label) then_label = label;
4789 else if (!else_label) else_label = label;
4790
4791 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4792
4793 if (LIST_INSN_SIZE_ONE(seq)) {
4794 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4795 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4796 return COMPILE_OK;
4797 }
4798 if (!label->refcnt) {
4799 return COMPILE_SINGLE;
4800 }
4801 ADD_LABEL(seq, label);
4802 ADD_SEQ(ret, seq);
4803 return COMPILE_OK;
4804}
4805
4806static int
4807compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4808 LABEL *then_label, LABEL *else_label)
4809{
4810 int ok;
4811 DECL_ANCHOR(ignore);
4812
4813 again:
4814 switch (nd_type(cond)) {
4815 case NODE_AND:
4816 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4817 cond = RNODE_AND(cond)->nd_2nd;
4818 if (ok == COMPILE_SINGLE) {
4819 INIT_ANCHOR(ignore);
4820 ret = ignore;
4821 then_label = NEW_LABEL(nd_line(cond));
4822 }
4823 goto again;
4824 case NODE_OR:
4825 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4826 cond = RNODE_OR(cond)->nd_2nd;
4827 if (ok == COMPILE_SINGLE) {
4828 INIT_ANCHOR(ignore);
4829 ret = ignore;
4830 else_label = NEW_LABEL(nd_line(cond));
4831 }
4832 goto again;
4833 case NODE_SYM:
4834 case NODE_LINE:
4835 case NODE_FILE:
4836 case NODE_ENCODING:
4837 case NODE_INTEGER: /* NODE_INTEGER is always true */
4838 case NODE_FLOAT: /* NODE_FLOAT is always true */
4839 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4840 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4841 case NODE_TRUE:
4842 case NODE_STR:
4843 case NODE_REGX:
4844 case NODE_ZLIST:
4845 case NODE_LAMBDA:
4846 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4847 ADD_INSNL(ret, cond, jump, then_label);
4848 return COMPILE_OK;
4849 case NODE_FALSE:
4850 case NODE_NIL:
4851 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4852 ADD_INSNL(ret, cond, jump, else_label);
4853 return COMPILE_OK;
4854 case NODE_LIST:
4855 case NODE_ARGSCAT:
4856 case NODE_DREGX:
4857 case NODE_DSTR:
4858 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4859 ADD_INSNL(ret, cond, jump, then_label);
4860 return COMPILE_OK;
4861 case NODE_FLIP2:
4862 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4863 return COMPILE_OK;
4864 case NODE_FLIP3:
4865 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4866 return COMPILE_OK;
4867 case NODE_DEFINED:
4868 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4869 break;
4870 default:
4871 {
4872 DECL_ANCHOR(cond_seq);
4873 INIT_ANCHOR(cond_seq);
4874
4875 CHECK(COMPILE(cond_seq, "branch condition", cond));
4876
4877 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4878 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4879 if (insn->insn_id == BIN(putobject)) {
4880 if (RTEST(insn->operands[0])) {
4881 ADD_INSNL(ret, cond, jump, then_label);
4882 // maybe unreachable
4883 return COMPILE_OK;
4884 }
4885 else {
4886 ADD_INSNL(ret, cond, jump, else_label);
4887 return COMPILE_OK;
4888 }
4889 }
4890 }
4891 ADD_SEQ(ret, cond_seq);
4892 }
4893 break;
4894 }
4895
4896 ADD_INSNL(ret, cond, branchunless, else_label);
4897 ADD_INSNL(ret, cond, jump, then_label);
4898 return COMPILE_OK;
4899}
4900
4901#define HASH_BRACE 1
4902
4903static int
4904keyword_node_p(const NODE *const node)
4905{
4906 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4907}
4908
4909static VALUE
4910get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4911{
4912 switch (nd_type(node)) {
4913 case NODE_SYM:
4914 return rb_node_sym_string_val(node);
4915 default:
4916 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4917 }
4918}
4919
4920static VALUE
4921node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4922{
4923 NODE *node = node_hash->nd_head;
4924 VALUE hash = rb_hash_new();
4925 VALUE ary = rb_ary_new();
4926
4927 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4928 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4929 VALUE idx = rb_hash_aref(hash, key);
4930 if (!NIL_P(idx)) {
4931 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4932 (*count_ptr)--;
4933 }
4934 rb_hash_aset(hash, key, INT2FIX(i));
4935 rb_ary_store(ary, i, Qtrue);
4936 (*count_ptr)++;
4937 }
4938
4939 return ary;
4940}
4941
4942static int
4943compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4944 const NODE *const root_node,
4945 struct rb_callinfo_kwarg **const kw_arg_ptr,
4946 unsigned int *flag)
4947{
4948 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4949 RUBY_ASSERT(kw_arg_ptr != NULL);
4950 RUBY_ASSERT(flag != NULL);
4951
4952 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4953 const NODE *node = RNODE_HASH(root_node)->nd_head;
4954 int seen_nodes = 0;
4955
4956 while (node) {
4957 const NODE *key_node = RNODE_LIST(node)->nd_head;
4958 seen_nodes++;
4959
4960 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4961 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4962 /* can be keywords */
4963 }
4964 else {
4965 if (flag) {
4966 *flag |= VM_CALL_KW_SPLAT;
4967 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4968 /* A new hash will be created for the keyword arguments
4969 * in this case, so mark the method as passing mutable
4970 * keyword splat.
4971 */
4972 *flag |= VM_CALL_KW_SPLAT_MUT;
4973 }
4974 }
4975 return FALSE;
4976 }
4977 node = RNODE_LIST(node)->nd_next; /* skip value node */
4978 node = RNODE_LIST(node)->nd_next;
4979 }
4980
4981 /* may be keywords */
4982 node = RNODE_HASH(root_node)->nd_head;
4983 {
4984 int len = 0;
4985 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4986 struct rb_callinfo_kwarg *kw_arg =
4987 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4988 VALUE *keywords = kw_arg->keywords;
4989 int i = 0;
4990 int j = 0;
4991 kw_arg->references = 0;
4992 kw_arg->keyword_len = len;
4993
4994 *kw_arg_ptr = kw_arg;
4995
4996 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4997 const NODE *key_node = RNODE_LIST(node)->nd_head;
4998 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4999 int popped = TRUE;
5000 if (rb_ary_entry(key_index, i)) {
5001 keywords[j] = get_symbol_value(iseq, key_node);
5002 j++;
5003 popped = FALSE;
5004 }
5005 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5006 }
5007 RUBY_ASSERT(j == len);
5008 return TRUE;
5009 }
5010 }
5011 return FALSE;
5012}
5013
5014static int
5015compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5016{
5017 int len = 0;
5018
5019 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5020 if (CPDEBUG > 0) {
5021 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5022 }
5023
5024 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5025 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5026 }
5027 else {
5028 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5029 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5030 }
5031 }
5032
5033 return len;
5034}
5035
5036static inline bool
5037frozen_string_literal_p(const rb_iseq_t *iseq)
5038{
5039 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5040}
5041
5042static inline bool
5043static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5044{
5045 switch (nd_type(node)) {
5046 case NODE_SYM:
5047 case NODE_REGX:
5048 case NODE_LINE:
5049 case NODE_ENCODING:
5050 case NODE_INTEGER:
5051 case NODE_FLOAT:
5052 case NODE_RATIONAL:
5053 case NODE_IMAGINARY:
5054 case NODE_NIL:
5055 case NODE_TRUE:
5056 case NODE_FALSE:
5057 return TRUE;
5058 case NODE_STR:
5059 case NODE_FILE:
5060 return hash_key || frozen_string_literal_p(iseq);
5061 default:
5062 return FALSE;
5063 }
5064}
5065
5066static inline VALUE
5067static_literal_value(const NODE *node, rb_iseq_t *iseq)
5068{
5069 switch (nd_type(node)) {
5070 case NODE_INTEGER:
5071 return rb_node_integer_literal_val(node);
5072 case NODE_FLOAT:
5073 return rb_node_float_literal_val(node);
5074 case NODE_RATIONAL:
5075 return rb_node_rational_literal_val(node);
5076 case NODE_IMAGINARY:
5077 return rb_node_imaginary_literal_val(node);
5078 case NODE_NIL:
5079 return Qnil;
5080 case NODE_TRUE:
5081 return Qtrue;
5082 case NODE_FALSE:
5083 return Qfalse;
5084 case NODE_SYM:
5085 return rb_node_sym_string_val(node);
5086 case NODE_REGX:
5087 return rb_node_regx_string_val(node);
5088 case NODE_LINE:
5089 return rb_node_line_lineno_val(node);
5090 case NODE_ENCODING:
5091 return rb_node_encoding_val(node);
5092 case NODE_FILE:
5093 case NODE_STR:
5094 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5095 VALUE lit = get_string_value(node);
5096 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5097 }
5098 else {
5099 return get_string_value(node);
5100 }
5101 default:
5102 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5103 }
5104}
5105
5106static int
5107compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5108{
5109 const NODE *line_node = node;
5110
5111 if (nd_type_p(node, NODE_ZLIST)) {
5112 if (!popped) {
5113 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5114 }
5115 return 0;
5116 }
5117
5118 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5119
5120 if (popped) {
5121 for (; node; node = RNODE_LIST(node)->nd_next) {
5122 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5123 }
5124 return 1;
5125 }
5126
5127 /* Compilation of an array literal.
5128 * The following code is essentially the same as:
5129 *
5130 * for (int count = 0; node; count++; node->nd_next) {
5131 * compile(node->nd_head);
5132 * }
5133 * ADD_INSN(newarray, count);
5134 *
5135 * However, there are three points.
5136 *
5137 * - The code above causes stack overflow for a big string literal.
5138 * The following limits the stack length up to max_stack_len.
5139 *
5140 * [x1,x2,...,x10000] =>
5141 * push x1 ; push x2 ; ...; push x256; newarray 256;
5142 * push x257; push x258; ...; push x512; pushtoarray 256;
5143 * push x513; push x514; ...; push x768; pushtoarray 256;
5144 * ...
5145 *
5146 * - Long subarray can be optimized by pre-allocating a hidden array.
5147 *
5148 * [1,2,3,...,100] =>
5149 * duparray [1,2,3,...,100]
5150 *
5151 * [x, 1,2,3,...,100, z] =>
5152 * push x; newarray 1;
5153 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5154 * push z; pushtoarray 1;
5155 *
5156 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5157 * to only push it onto the array if it is not empty
5158 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5159 *
5160 * [1,2,3,**kw] =>
5161 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5162 */
5163
5164 const int max_stack_len = 0x100;
5165 const int min_tmp_ary_len = 0x40;
5166 int stack_len = 0;
5167
5168 /* Either create a new array, or push to the existing array */
5169#define FLUSH_CHUNK \
5170 if (stack_len) { \
5171 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5172 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5173 first_chunk = FALSE; \
5174 stack_len = 0; \
5175 }
5176
5177 while (node) {
5178 int count = 1;
5179
5180 /* pre-allocation check (this branch can be omittable) */
5181 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5182 /* count the elements that are optimizable */
5183 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5184 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5185 count++;
5186
5187 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5188 /* The literal contains only optimizable elements, or the subarray is long enough */
5189 VALUE ary = rb_ary_hidden_new(count);
5190
5191 /* Create a hidden array */
5192 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5193 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5194 OBJ_FREEZE(ary);
5195
5196 /* Emit optimized code */
5197 FLUSH_CHUNK;
5198 if (first_chunk) {
5199 ADD_INSN1(ret, line_node, duparray, ary);
5200 first_chunk = FALSE;
5201 }
5202 else {
5203 ADD_INSN1(ret, line_node, putobject, ary);
5204 ADD_INSN(ret, line_node, concattoarray);
5205 }
5206 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5207 }
5208 }
5209
5210 /* Base case: Compile "count" elements */
5211 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5212 if (CPDEBUG > 0) {
5213 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5214 }
5215
5216 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5217 /* Create array or push existing non-keyword elements onto array */
5218 if (stack_len == 0 && first_chunk) {
5219 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5220 }
5221 else {
5222 FLUSH_CHUNK;
5223 }
5224 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5225 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5226 return 1;
5227 }
5228 else {
5229 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5230 stack_len++;
5231 }
5232
5233 /* If there are many pushed elements, flush them to avoid stack overflow */
5234 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5235 }
5236 }
5237
5238 FLUSH_CHUNK;
5239#undef FLUSH_CHUNK
5240 return 1;
5241}
5242
5243static inline int
5244static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5245{
5246 return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, true) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq, false);
5247}
5248
5249static int
5250compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5251{
5252 const NODE *line_node = node;
5253
5254 node = RNODE_HASH(node)->nd_head;
5255
5256 if (!node || nd_type_p(node, NODE_ZLIST)) {
5257 if (!popped) {
5258 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5259 }
5260 return 0;
5261 }
5262
5263 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5264
5265 if (popped) {
5266 for (; node; node = RNODE_LIST(node)->nd_next) {
5267 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5268 }
5269 return 1;
5270 }
5271
5272 /* Compilation of a hash literal (or keyword arguments).
5273 * This is very similar to compile_array, but there are some differences:
5274 *
5275 * - It contains key-value pairs. So we need to take every two elements.
5276 * We can assume that the length is always even.
5277 *
5278 * - Merging is done by a method call (id_core_hash_merge_ptr).
5279 * Sometimes we need to insert the receiver, so "anchor" is needed.
5280 * In addition, a method call is much slower than concatarray.
5281 * So it pays only when the subsequence is really long.
5282 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5283 *
5284 * - We need to handle keyword splat: **kw.
5285 * For **kw, the key part (node->nd_head) is NULL, and the value part
5286 * (node->nd_next->nd_head) is "kw".
5287 * The code is a bit difficult to avoid hash allocation for **{}.
5288 */
5289
5290 const int max_stack_len = 0x100;
5291 const int min_tmp_hash_len = 0x800;
5292 int stack_len = 0;
5293 int first_chunk = 1;
5294 DECL_ANCHOR(anchor);
5295 INIT_ANCHOR(anchor);
5296
5297 /* Convert pushed elements to a hash, and merge if needed */
5298#define FLUSH_CHUNK() \
5299 if (stack_len) { \
5300 if (first_chunk) { \
5301 APPEND_LIST(ret, anchor); \
5302 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5303 } \
5304 else { \
5305 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5306 ADD_INSN(ret, line_node, swap); \
5307 APPEND_LIST(ret, anchor); \
5308 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5309 } \
5310 INIT_ANCHOR(anchor); \
5311 first_chunk = stack_len = 0; \
5312 }
5313
5314 while (node) {
5315 int count = 1;
5316
5317 /* pre-allocation check (this branch can be omittable) */
5318 if (static_literal_node_pair_p(node, iseq)) {
5319 /* count the elements that are optimizable */
5320 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5321 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5322 count++;
5323
5324 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5325 /* The literal contains only optimizable elements, or the subsequence is long enough */
5326 VALUE ary = rb_ary_hidden_new(count);
5327
5328 /* Create a hidden hash */
5329 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5330 VALUE elem[2];
5331 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5332 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5333 rb_ary_cat(ary, elem, 2);
5334 }
5335 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5336 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5337 hash = rb_obj_hide(hash);
5338 OBJ_FREEZE(hash);
5339
5340 /* Emit optimized code */
5341 FLUSH_CHUNK();
5342 if (first_chunk) {
5343 ADD_INSN1(ret, line_node, duphash, hash);
5344 first_chunk = 0;
5345 }
5346 else {
5347 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5348 ADD_INSN(ret, line_node, swap);
5349
5350 ADD_INSN1(ret, line_node, putobject, hash);
5351
5352 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5353 }
5354 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5355 }
5356 }
5357
5358 /* Base case: Compile "count" elements */
5359 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5360
5361 if (CPDEBUG > 0) {
5362 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5363 }
5364
5365 if (RNODE_LIST(node)->nd_head) {
5366 /* Normal key-value pair */
5367 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5368 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5369 stack_len += 2;
5370
5371 /* If there are many pushed elements, flush them to avoid stack overflow */
5372 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5373 }
5374 else {
5375 /* kwsplat case: foo(..., **kw, ...) */
5376 FLUSH_CHUNK();
5377
5378 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5379 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5380 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5381 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5382 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5383
5384 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5385 if (empty_kw) {
5386 if (only_kw && method_call_keywords) {
5387 /* **{} appears at the only keyword argument in method call,
5388 * so it won't be modified.
5389 * kw is a special NODE_LIT that contains a special empty hash,
5390 * so this emits: putobject {}.
5391 * This is only done for method calls and not for literal hashes,
5392 * because literal hashes should always result in a new hash.
5393 */
5394 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5395 }
5396 else if (first_kw) {
5397 /* **{} appears as the first keyword argument, so it may be modified.
5398 * We need to create a fresh hash object.
5399 */
5400 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5401 }
5402 /* Any empty keyword splats that are not the first can be ignored.
5403 * since merging an empty hash into the existing hash is the same
5404 * as not merging it. */
5405 }
5406 else {
5407 if (only_kw && method_call_keywords) {
5408 /* **kw is only keyword argument in method call.
5409 * Use directly. This will be not be flagged as mutable.
5410 * This is only done for method calls and not for literal hashes,
5411 * because literal hashes should always result in a new hash.
5412 */
5413 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5414 }
5415 else {
5416 /* There is more than one keyword argument, or this is not a method
5417 * call. In that case, we need to add an empty hash (if first keyword),
5418 * or merge the hash to the accumulated hash (if not the first keyword).
5419 */
5420 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5421 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5422 else ADD_INSN(ret, line_node, swap);
5423
5424 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5425
5426 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5427 }
5428 }
5429
5430 first_chunk = 0;
5431 }
5432 }
5433 }
5434
5435 FLUSH_CHUNK();
5436#undef FLUSH_CHUNK
5437 return 1;
5438}
5439
5440VALUE
5441rb_node_case_when_optimizable_literal(const NODE *const node)
5442{
5443 switch (nd_type(node)) {
5444 case NODE_INTEGER:
5445 return rb_node_integer_literal_val(node);
5446 case NODE_FLOAT: {
5447 VALUE v = rb_node_float_literal_val(node);
5448 double ival;
5449
5450 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5451 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5452 }
5453 return v;
5454 }
5455 case NODE_RATIONAL:
5456 case NODE_IMAGINARY:
5457 return Qundef;
5458 case NODE_NIL:
5459 return Qnil;
5460 case NODE_TRUE:
5461 return Qtrue;
5462 case NODE_FALSE:
5463 return Qfalse;
5464 case NODE_SYM:
5465 return rb_node_sym_string_val(node);
5466 case NODE_LINE:
5467 return rb_node_line_lineno_val(node);
5468 case NODE_STR:
5469 return rb_node_str_string_val(node);
5470 case NODE_FILE:
5471 return rb_node_file_path_val(node);
5472 }
5473 return Qundef;
5474}
5475
5476static int
5477when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5478 LABEL *l1, int only_special_literals, VALUE literals)
5479{
5480 while (vals) {
5481 const NODE *val = RNODE_LIST(vals)->nd_head;
5482 VALUE lit = rb_node_case_when_optimizable_literal(val);
5483
5484 if (UNDEF_P(lit)) {
5485 only_special_literals = 0;
5486 }
5487 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5488 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5489 }
5490
5491 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5492 debugp_param("nd_lit", get_string_value(val));
5493 lit = get_string_value(val);
5494 ADD_INSN1(cond_seq, val, putobject, lit);
5495 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5496 }
5497 else {
5498 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5499 }
5500
5501 // Emit pattern === target
5502 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5503 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5504 ADD_INSNL(cond_seq, val, branchif, l1);
5505 vals = RNODE_LIST(vals)->nd_next;
5506 }
5507 return only_special_literals;
5508}
5509
5510static int
5511when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5512 LABEL *l1, int only_special_literals, VALUE literals)
5513{
5514 const NODE *line_node = vals;
5515
5516 switch (nd_type(vals)) {
5517 case NODE_LIST:
5518 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5519 return COMPILE_NG;
5520 break;
5521 case NODE_SPLAT:
5522 ADD_INSN (cond_seq, line_node, dup);
5523 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5524 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5525 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5526 ADD_INSNL(cond_seq, line_node, branchif, l1);
5527 break;
5528 case NODE_ARGSCAT:
5529 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5530 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5531 break;
5532 case NODE_ARGSPUSH:
5533 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5534 ADD_INSN (cond_seq, line_node, dup);
5535 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5536 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5537 ADD_INSNL(cond_seq, line_node, branchif, l1);
5538 break;
5539 default:
5540 ADD_INSN (cond_seq, line_node, dup);
5541 CHECK(COMPILE(cond_seq, "when val", vals));
5542 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5543 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5544 ADD_INSNL(cond_seq, line_node, branchif, l1);
5545 break;
5546 }
5547 return COMPILE_OK;
5548}
5549
5550/* Multiple Assignment Handling
5551 *
5552 * In order to handle evaluation of multiple assignment such that the left hand side
5553 * is evaluated before the right hand side, we need to process the left hand side
5554 * and see if there are any attributes that need to be assigned, or constants set
5555 * on explicit objects. If so, we add instructions to evaluate the receiver of
5556 * any assigned attributes or constants before we process the right hand side.
5557 *
5558 * For a multiple assignment such as:
5559 *
5560 * l1.m1, l2[0] = r3, r4
5561 *
5562 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5563 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5564 * On the VM stack, this looks like:
5565 *
5566 * self # putself
5567 * l1 # send
5568 * l1, self # putself
5569 * l1, l2 # send
5570 * l1, l2, 0 # putobject 0
5571 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5572 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5573 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5574 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5575 * l1, l2, 0, [r3, r4], r4, m1= # send
5576 * l1, l2, 0, [r3, r4], r4 # pop
5577 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5578 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5579 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5580 * l1, l2, 0, [r3, r4], r4, []= # send
5581 * l1, l2, 0, [r3, r4], r4 # pop
5582 * l1, l2, 0, [r3, r4] # pop
5583 * [r3, r4], l2, 0, [r3, r4] # setn 3
5584 * [r3, r4], l2, 0 # pop
5585 * [r3, r4], l2 # pop
5586 * [r3, r4] # pop
5587 *
5588 * This is made more complex when you have to handle splats, post args,
5589 * and arbitrary levels of nesting. You need to keep track of the total
5590 * number of attributes to set, and for each attribute, how many entries
5591 * are on the stack before the final attribute, in order to correctly
5592 * calculate the topn value to use to get the receiver of the attribute
5593 * setter method.
5594 *
5595 * A brief description of the VM stack for simple multiple assignment
5596 * with no splat (rhs_array will not be present if the return value of
5597 * the multiple assignment is not needed):
5598 *
5599 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5600 *
5601 * For multiple assignment with splats, while processing the part before
5602 * the splat (splat+post here is an array of the splat and the post arguments):
5603 *
5604 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5605 *
5606 * When processing the splat and post arguments:
5607 *
5608 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5609 *
5610 * When processing nested multiple assignment, existing values on the stack
5611 * are kept. So for:
5612 *
5613 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5614 *
5615 * The stack layout would be the following before processing the nested
5616 * multiple assignment:
5617 *
5618 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5619 *
5620 * In order to handle this correctly, we need to keep track of the nesting
5621 * level for each attribute assignment, as well as the attribute number
5622 * (left hand side attributes are processed left to right) and number of
5623 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5624 * this information.
5625 *
5626 * We also need to track information for the entire multiple assignment, such
5627 * as the total number of arguments, and the current nesting level, to
5628 * handle both nested multiple assignment as well as cases where the
5629 * rhs is not needed. We also need to keep track of all attribute
5630 * assignments in this, which we do using a linked listed. struct masgn_state
5631 * tracks this information.
5632 */
5633
5635 INSN *before_insn;
5636 struct masgn_lhs_node *next;
5637 const NODE *line_node;
5638 int argn;
5639 int num_args;
5640 int lhs_pos;
5641};
5642
5644 struct masgn_lhs_node *first_memo;
5645 struct masgn_lhs_node *last_memo;
5646 int lhs_level;
5647 int num_args;
5648 bool nested;
5649};
5650
5651static int
5652add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5653{
5654 if (!state) {
5655 rb_bug("no masgn_state");
5656 }
5657
5658 struct masgn_lhs_node *memo;
5659 memo = malloc(sizeof(struct masgn_lhs_node));
5660 if (!memo) {
5661 return COMPILE_NG;
5662 }
5663
5664 memo->before_insn = before_insn;
5665 memo->line_node = line_node;
5666 memo->argn = state->num_args + 1;
5667 memo->num_args = argc;
5668 state->num_args += argc;
5669 memo->lhs_pos = lhs_pos;
5670 memo->next = NULL;
5671 if (!state->first_memo) {
5672 state->first_memo = memo;
5673 }
5674 else {
5675 state->last_memo->next = memo;
5676 }
5677 state->last_memo = memo;
5678
5679 return COMPILE_OK;
5680}
5681
5682static 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);
5683
5684static int
5685compile_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)
5686{
5687 switch (nd_type(node)) {
5688 case NODE_ATTRASGN: {
5689 INSN *iobj;
5690 const NODE *line_node = node;
5691
5692 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5693
5694 bool safenav_call = false;
5695 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5696 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5697 ASSUME(iobj);
5698 ELEM_REMOVE(insn_element);
5699 if (!IS_INSN_ID(iobj, send)) {
5700 safenav_call = true;
5701 iobj = (INSN *)get_prev_insn(iobj);
5702 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5703 }
5704 (pre->last = iobj->link.prev)->next = 0;
5705
5706 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5707 int argc = vm_ci_argc(ci) + 1;
5708 ci = ci_argc_set(iseq, ci, argc);
5709 OPERAND_AT(iobj, 0) = (VALUE)ci;
5710 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5711
5712 if (argc == 1) {
5713 ADD_INSN(lhs, line_node, swap);
5714 }
5715 else {
5716 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5717 }
5718
5719 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5720 return COMPILE_NG;
5721 }
5722
5723 iobj->link.prev = lhs->last;
5724 lhs->last->next = &iobj->link;
5725 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5726 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5727 int argc = vm_ci_argc(ci);
5728 bool dupsplat = false;
5729 ci = ci_argc_set(iseq, ci, argc - 1);
5730 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5731 /* Given h[*a], _ = ary
5732 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5733 * `a` must be dupped, because it will be appended with ary[0]
5734 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5735 */
5736 dupsplat = true;
5737 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5738 }
5739 OPERAND_AT(iobj, 0) = (VALUE)ci;
5740 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5741
5742 /* Given: h[*a], h[*b, 1] = ary
5743 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5744 * so this uses splatarray true on a to dup it before using pushtoarray
5745 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5746 * so you can use pushtoarray directly
5747 */
5748 int line_no = nd_line(line_node);
5749 int node_id = nd_node_id(line_node);
5750
5751 if (dupsplat) {
5752 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5753 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5754 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5755 }
5756 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5757 }
5758 if (!safenav_call) {
5759 ADD_INSN(lhs, line_node, pop);
5760 if (argc != 1) {
5761 ADD_INSN(lhs, line_node, pop);
5762 }
5763 }
5764 for (int i=0; i < argc; i++) {
5765 ADD_INSN(post, line_node, pop);
5766 }
5767 break;
5768 }
5769 case NODE_MASGN: {
5770 DECL_ANCHOR(nest_rhs);
5771 INIT_ANCHOR(nest_rhs);
5772 DECL_ANCHOR(nest_lhs);
5773 INIT_ANCHOR(nest_lhs);
5774
5775 int prev_level = state->lhs_level;
5776 bool prev_nested = state->nested;
5777 state->nested = 1;
5778 state->lhs_level = lhs_pos - 1;
5779 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5780 state->lhs_level = prev_level;
5781 state->nested = prev_nested;
5782
5783 ADD_SEQ(lhs, nest_rhs);
5784 ADD_SEQ(lhs, nest_lhs);
5785 break;
5786 }
5787 case NODE_CDECL:
5788 if (!RNODE_CDECL(node)->nd_vid) {
5789 /* Special handling only needed for expr::C, not for C */
5790 INSN *iobj;
5791
5792 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5793
5794 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5795 iobj = (INSN *)insn_element; /* setconstant insn */
5796 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5797 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5798 ELEM_REMOVE(insn_element);
5799 pre->last = iobj->link.prev;
5800 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5801
5802 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5803 return COMPILE_NG;
5804 }
5805
5806 ADD_INSN(post, node, pop);
5807 break;
5808 }
5809 /* Fallthrough */
5810 default: {
5811 DECL_ANCHOR(anchor);
5812 INIT_ANCHOR(anchor);
5813 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5814 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5815 ADD_SEQ(lhs, anchor);
5816 }
5817 }
5818
5819 return COMPILE_OK;
5820}
5821
5822static int
5823compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5824{
5825 if (lhsn) {
5826 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5827 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5828 }
5829 return COMPILE_OK;
5830}
5831
5832static int
5833compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5834 const NODE *rhsn, const NODE *orig_lhsn)
5835{
5836 VALUE mem[64];
5837 const int memsize = numberof(mem);
5838 int memindex = 0;
5839 int llen = 0, rlen = 0;
5840 int i;
5841 const NODE *lhsn = orig_lhsn;
5842
5843#define MEMORY(v) { \
5844 int i; \
5845 if (memindex == memsize) return 0; \
5846 for (i=0; i<memindex; i++) { \
5847 if (mem[i] == (v)) return 0; \
5848 } \
5849 mem[memindex++] = (v); \
5850}
5851
5852 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5853 return 0;
5854 }
5855
5856 while (lhsn) {
5857 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5858 switch (nd_type(ln)) {
5859 case NODE_LASGN:
5860 case NODE_DASGN:
5861 case NODE_IASGN:
5862 case NODE_CVASGN:
5863 MEMORY(get_nd_vid(ln));
5864 break;
5865 default:
5866 return 0;
5867 }
5868 lhsn = RNODE_LIST(lhsn)->nd_next;
5869 llen++;
5870 }
5871
5872 while (rhsn) {
5873 if (llen <= rlen) {
5874 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5875 }
5876 else {
5877 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5878 }
5879 rhsn = RNODE_LIST(rhsn)->nd_next;
5880 rlen++;
5881 }
5882
5883 if (llen > rlen) {
5884 for (i=0; i<llen-rlen; i++) {
5885 ADD_INSN(ret, orig_lhsn, putnil);
5886 }
5887 }
5888
5889 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5890 return 1;
5891}
5892
5893static int
5894compile_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)
5895{
5896 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5897 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5898 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5899 const NODE *lhsn_count = lhsn;
5900 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5901
5902 int llen = 0;
5903 int lpos = 0;
5904
5905 while (lhsn_count) {
5906 llen++;
5907 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5908 }
5909 while (lhsn) {
5910 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5911 lpos++;
5912 lhsn = RNODE_LIST(lhsn)->nd_next;
5913 }
5914
5915 if (lhs_splat) {
5916 if (nd_type_p(splatn, NODE_POSTARG)) {
5917 /*a, b, *r, p1, p2 */
5918 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5919 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5920 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5921 int ppos = 0;
5922 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5923
5924 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5925
5926 if (NODE_NAMED_REST_P(restn)) {
5927 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5928 }
5929 while (postn) {
5930 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5931 ppos++;
5932 postn = RNODE_LIST(postn)->nd_next;
5933 }
5934 }
5935 else {
5936 /* a, b, *r */
5937 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5938 }
5939 }
5940
5941 if (!state->nested) {
5942 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5943 }
5944
5945 if (!popped) {
5946 ADD_INSN(rhs, node, dup);
5947 }
5948 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5949 return COMPILE_OK;
5950}
5951
5952static int
5953compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5954{
5955 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5956 struct masgn_state state;
5957 state.lhs_level = popped ? 0 : 1;
5958 state.nested = 0;
5959 state.num_args = 0;
5960 state.first_memo = NULL;
5961 state.last_memo = NULL;
5962
5963 DECL_ANCHOR(pre);
5964 INIT_ANCHOR(pre);
5965 DECL_ANCHOR(rhs);
5966 INIT_ANCHOR(rhs);
5967 DECL_ANCHOR(lhs);
5968 INIT_ANCHOR(lhs);
5969 DECL_ANCHOR(post);
5970 INIT_ANCHOR(post);
5971 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5972
5973 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5974 while (memo) {
5975 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5976 for (int i = 0; i < memo->num_args; i++) {
5977 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5978 }
5979 tmp_memo = memo->next;
5980 free(memo);
5981 memo = tmp_memo;
5982 }
5983 CHECK(ok);
5984
5985 ADD_SEQ(ret, pre);
5986 ADD_SEQ(ret, rhs);
5987 ADD_SEQ(ret, lhs);
5988 if (!popped && state.num_args >= 1) {
5989 /* make sure rhs array is returned before popping */
5990 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5991 }
5992 ADD_SEQ(ret, post);
5993 }
5994 return COMPILE_OK;
5995}
5996
5997static VALUE
5998collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5999{
6000 VALUE arr = rb_ary_new();
6001 for (;;) {
6002 switch (nd_type(node)) {
6003 case NODE_CONST:
6004 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6005 return arr;
6006 case NODE_COLON3:
6007 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6008 rb_ary_unshift(arr, ID2SYM(idNULL));
6009 return arr;
6010 case NODE_COLON2:
6011 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6012 node = RNODE_COLON2(node)->nd_head;
6013 break;
6014 default:
6015 return Qfalse;
6016 }
6017 }
6018}
6019
6020static int
6021compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6022 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6023{
6024 switch (nd_type(node)) {
6025 case NODE_CONST:
6026 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6027 ADD_INSN1(body, node, putobject, Qtrue);
6028 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6029 break;
6030 case NODE_COLON3:
6031 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6032 ADD_INSN(body, node, pop);
6033 ADD_INSN1(body, node, putobject, rb_cObject);
6034 ADD_INSN1(body, node, putobject, Qtrue);
6035 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6036 break;
6037 case NODE_COLON2:
6038 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6039 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6040 ADD_INSN1(body, node, putobject, Qfalse);
6041 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6042 break;
6043 default:
6044 CHECK(COMPILE(pref, "const colon2 prefix", node));
6045 break;
6046 }
6047 return COMPILE_OK;
6048}
6049
6050static int
6051compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6052{
6053 if (nd_type_p(cpath, NODE_COLON3)) {
6054 /* toplevel class ::Foo */
6055 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6056 return VM_DEFINECLASS_FLAG_SCOPED;
6057 }
6058 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6059 /* Bar::Foo */
6060 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6061 return VM_DEFINECLASS_FLAG_SCOPED;
6062 }
6063 else {
6064 /* class at cbase Foo */
6065 ADD_INSN1(ret, cpath, putspecialobject,
6066 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6067 return 0;
6068 }
6069}
6070
6071static inline int
6072private_recv_p(const NODE *node)
6073{
6074 NODE *recv = get_nd_recv(node);
6075 if (recv && nd_type_p(recv, NODE_SELF)) {
6076 return RNODE_SELF(recv)->nd_state != 0;
6077 }
6078 return 0;
6079}
6080
6081static void
6082defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6083 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6084
6085static int
6086compile_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);
6087
6088static void
6089defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6090 const NODE *const node, LABEL **lfinish, VALUE needstr,
6091 bool keep_result)
6092{
6093 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6094 enum node_type type;
6095 const int line = nd_line(node);
6096 const NODE *line_node = node;
6097
6098 switch (type = nd_type(node)) {
6099
6100 /* easy literals */
6101 case NODE_NIL:
6102 expr_type = DEFINED_NIL;
6103 break;
6104 case NODE_SELF:
6105 expr_type = DEFINED_SELF;
6106 break;
6107 case NODE_TRUE:
6108 expr_type = DEFINED_TRUE;
6109 break;
6110 case NODE_FALSE:
6111 expr_type = DEFINED_FALSE;
6112 break;
6113
6114 case NODE_HASH:
6115 case NODE_LIST:{
6116 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6117
6118 if (vals) {
6119 do {
6120 if (RNODE_LIST(vals)->nd_head) {
6121 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6122
6123 if (!lfinish[1]) {
6124 lfinish[1] = NEW_LABEL(line);
6125 }
6126 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6127 }
6128 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6129 }
6130 }
6131 /* fall through */
6132 case NODE_STR:
6133 case NODE_SYM:
6134 case NODE_REGX:
6135 case NODE_LINE:
6136 case NODE_FILE:
6137 case NODE_ENCODING:
6138 case NODE_INTEGER:
6139 case NODE_FLOAT:
6140 case NODE_RATIONAL:
6141 case NODE_IMAGINARY:
6142 case NODE_ZLIST:
6143 case NODE_AND:
6144 case NODE_OR:
6145 default:
6146 expr_type = DEFINED_EXPR;
6147 break;
6148
6149 case NODE_SPLAT:
6150 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6151 if (!lfinish[1]) {
6152 lfinish[1] = NEW_LABEL(line);
6153 }
6154 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6155 expr_type = DEFINED_EXPR;
6156 break;
6157
6158 /* variables */
6159 case NODE_LVAR:
6160 case NODE_DVAR:
6161 expr_type = DEFINED_LVAR;
6162 break;
6163
6164#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6165 case NODE_IVAR:
6166 ADD_INSN3(ret, line_node, definedivar,
6167 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6168 return;
6169
6170 case NODE_GVAR:
6171 ADD_INSN(ret, line_node, putnil);
6172 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6173 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6174 return;
6175
6176 case NODE_CVAR:
6177 ADD_INSN(ret, line_node, putnil);
6178 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6179 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6180 return;
6181
6182 case NODE_CONST:
6183 ADD_INSN(ret, line_node, putnil);
6184 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6185 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6186 return;
6187 case NODE_COLON2:
6188 if (!lfinish[1]) {
6189 lfinish[1] = NEW_LABEL(line);
6190 }
6191 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6192 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6193 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6194
6195 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6196 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6197 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6198 }
6199 else {
6200 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6201 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6202 }
6203 return;
6204 case NODE_COLON3:
6205 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6206 ADD_INSN3(ret, line_node, defined,
6207 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6208 return;
6209
6210 /* method dispatch */
6211 case NODE_CALL:
6212 case NODE_OPCALL:
6213 case NODE_VCALL:
6214 case NODE_FCALL:
6215 case NODE_ATTRASGN:{
6216 const int explicit_receiver =
6217 (type == NODE_CALL || type == NODE_OPCALL ||
6218 (type == NODE_ATTRASGN && !private_recv_p(node)));
6219
6220 if (get_nd_args(node) || explicit_receiver) {
6221 if (!lfinish[1]) {
6222 lfinish[1] = NEW_LABEL(line);
6223 }
6224 if (!lfinish[2]) {
6225 lfinish[2] = NEW_LABEL(line);
6226 }
6227 }
6228 if (get_nd_args(node)) {
6229 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6230 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6231 }
6232 if (explicit_receiver) {
6233 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6234 switch (nd_type(get_nd_recv(node))) {
6235 case NODE_CALL:
6236 case NODE_OPCALL:
6237 case NODE_VCALL:
6238 case NODE_FCALL:
6239 case NODE_ATTRASGN:
6240 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6241 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6242 break;
6243 default:
6244 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6245 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6246 break;
6247 }
6248 if (keep_result) {
6249 ADD_INSN(ret, line_node, dup);
6250 }
6251 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6252 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6253 }
6254 else {
6255 ADD_INSN(ret, line_node, putself);
6256 if (keep_result) {
6257 ADD_INSN(ret, line_node, dup);
6258 }
6259 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6260 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6261 }
6262 return;
6263 }
6264
6265 case NODE_YIELD:
6266 ADD_INSN(ret, line_node, putnil);
6267 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6268 PUSH_VAL(DEFINED_YIELD));
6269 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6270 return;
6271
6272 case NODE_BACK_REF:
6273 case NODE_NTH_REF:
6274 ADD_INSN(ret, line_node, putnil);
6275 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6276 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6277 PUSH_VAL(DEFINED_GVAR));
6278 return;
6279
6280 case NODE_SUPER:
6281 case NODE_ZSUPER:
6282 ADD_INSN(ret, line_node, putnil);
6283 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6284 PUSH_VAL(DEFINED_ZSUPER));
6285 return;
6286
6287#undef PUSH_VAL
6288 case NODE_OP_ASGN1:
6289 case NODE_OP_ASGN2:
6290 case NODE_OP_ASGN_OR:
6291 case NODE_OP_ASGN_AND:
6292 case NODE_MASGN:
6293 case NODE_LASGN:
6294 case NODE_DASGN:
6295 case NODE_GASGN:
6296 case NODE_IASGN:
6297 case NODE_CDECL:
6298 case NODE_CVASGN:
6299 case NODE_OP_CDECL:
6300 expr_type = DEFINED_ASGN;
6301 break;
6302 }
6303
6304 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6305
6306 if (needstr != Qfalse) {
6307 VALUE str = rb_iseq_defined_string(expr_type);
6308 ADD_INSN1(ret, line_node, putobject, str);
6309 }
6310 else {
6311 ADD_INSN1(ret, line_node, putobject, Qtrue);
6312 }
6313}
6314
6315static void
6316build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6317{
6318 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6319 iseq_set_exception_local_table(iseq);
6320}
6321
6322static void
6323defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6324 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6325{
6326 LINK_ELEMENT *lcur = ret->last;
6327 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6328 if (lfinish[1]) {
6329 int line = nd_line(node);
6330 LABEL *lstart = NEW_LABEL(line);
6331 LABEL *lend = NEW_LABEL(line);
6332 const rb_iseq_t *rescue;
6334 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6335 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6336 rb_str_concat(rb_str_new2("defined guard in "),
6337 ISEQ_BODY(iseq)->location.label),
6338 ISEQ_TYPE_RESCUE, 0);
6339 lstart->rescued = LABEL_RESCUE_BEG;
6340 lend->rescued = LABEL_RESCUE_END;
6341 APPEND_LABEL(ret, lcur, lstart);
6342 ADD_LABEL(ret, lend);
6343 if (!ignore) {
6344 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6345 }
6346 }
6347}
6348
6349static int
6350compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6351{
6352 const int line = nd_line(node);
6353 const NODE *line_node = node;
6354 if (!RNODE_DEFINED(node)->nd_head) {
6355 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6356 ADD_INSN1(ret, line_node, putobject, str);
6357 }
6358 else {
6359 LABEL *lfinish[3];
6360 LINK_ELEMENT *last = ret->last;
6361 lfinish[0] = NEW_LABEL(line);
6362 lfinish[1] = 0;
6363 lfinish[2] = 0;
6364 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6365 if (lfinish[1]) {
6366 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6367 ADD_INSN(ret, line_node, swap);
6368 if (lfinish[2]) {
6369 ADD_LABEL(ret, lfinish[2]);
6370 }
6371 ADD_INSN(ret, line_node, pop);
6372 ADD_LABEL(ret, lfinish[1]);
6373 }
6374 ADD_LABEL(ret, lfinish[0]);
6375 }
6376 return COMPILE_OK;
6377}
6378
6379static VALUE
6380make_name_for_block(const rb_iseq_t *orig_iseq)
6381{
6382 int level = 1;
6383 const rb_iseq_t *iseq = orig_iseq;
6384
6385 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6386 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6387 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6388 level++;
6389 }
6390 iseq = ISEQ_BODY(iseq)->parent_iseq;
6391 }
6392 }
6393
6394 if (level == 1) {
6395 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6396 }
6397 else {
6398 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6399 }
6400}
6401
6402static void
6403push_ensure_entry(rb_iseq_t *iseq,
6405 struct ensure_range *er, const void *const node)
6406{
6407 enl->ensure_node = node;
6408 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6409 enl->erange = er;
6410 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6411}
6412
6413static void
6414add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6415 LABEL *lstart, LABEL *lend)
6416{
6417 struct ensure_range *ne =
6418 compile_data_alloc(iseq, sizeof(struct ensure_range));
6419
6420 while (erange->next != 0) {
6421 erange = erange->next;
6422 }
6423 ne->next = 0;
6424 ne->begin = lend;
6425 ne->end = erange->end;
6426 erange->end = lstart;
6427
6428 erange->next = ne;
6429}
6430
6431static bool
6432can_add_ensure_iseq(const rb_iseq_t *iseq)
6433{
6435 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6436 while (e) {
6437 if (e->ensure_node) return false;
6438 e = e->prev;
6439 }
6440 }
6441 return true;
6442}
6443
6444static void
6445add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6446{
6447 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6448
6450 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6451 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6452 DECL_ANCHOR(ensure);
6453
6454 INIT_ANCHOR(ensure);
6455 while (enlp) {
6456 if (enlp->erange != NULL) {
6457 DECL_ANCHOR(ensure_part);
6458 LABEL *lstart = NEW_LABEL(0);
6459 LABEL *lend = NEW_LABEL(0);
6460 INIT_ANCHOR(ensure_part);
6461
6462 add_ensure_range(iseq, enlp->erange, lstart, lend);
6463
6464 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6465 ADD_LABEL(ensure_part, lstart);
6466 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6467 ADD_LABEL(ensure_part, lend);
6468 ADD_SEQ(ensure, ensure_part);
6469 }
6470 else {
6471 if (!is_return) {
6472 break;
6473 }
6474 }
6475 enlp = enlp->prev;
6476 }
6477 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6478 ADD_SEQ(ret, ensure);
6479}
6480
6481#if RUBY_DEBUG
6482static int
6483check_keyword(const NODE *node)
6484{
6485 /* This check is essentially a code clone of compile_keyword_arg. */
6486
6487 if (nd_type_p(node, NODE_LIST)) {
6488 while (RNODE_LIST(node)->nd_next) {
6489 node = RNODE_LIST(node)->nd_next;
6490 }
6491 node = RNODE_LIST(node)->nd_head;
6492 }
6493
6494 return keyword_node_p(node);
6495}
6496#endif
6497
6498static bool
6499keyword_node_single_splat_p(NODE *kwnode)
6500{
6501 RUBY_ASSERT(keyword_node_p(kwnode));
6502
6503 NODE *node = RNODE_HASH(kwnode)->nd_head;
6504 return RNODE_LIST(node)->nd_head == NULL &&
6505 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6506}
6507
6508static void
6509compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6510 NODE *kwnode, unsigned int *flag_ptr)
6511{
6512 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6513 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6514 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6515 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6516 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6517}
6518
6519#define SPLATARRAY_FALSE 0
6520#define SPLATARRAY_TRUE 1
6521#define DUP_SINGLE_KW_SPLAT 2
6522
6523static int
6524setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6525 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6526{
6527 if (!argn) return 0;
6528
6529 NODE *kwnode = NULL;
6530
6531 switch (nd_type(argn)) {
6532 case NODE_LIST: {
6533 // f(x, y, z)
6534 int len = compile_args(iseq, args, argn, &kwnode);
6535 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6536
6537 if (kwnode) {
6538 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6539 len -= 1;
6540 }
6541 else {
6542 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6543 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6544 }
6545 else {
6546 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6547 }
6548 }
6549 }
6550
6551 return len;
6552 }
6553 case NODE_SPLAT: {
6554 // f(*a)
6555 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6556 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6557 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6558 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6559 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6560 return 1;
6561 }
6562 case NODE_ARGSCAT: {
6563 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6564 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6565 bool args_pushed = false;
6566
6567 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6568 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6569 if (kwnode) rest_len--;
6570 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6571 args_pushed = true;
6572 }
6573 else {
6574 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6575 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6576 }
6577
6578 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6579 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6580 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6581 argc += 1;
6582 }
6583 else if (!args_pushed) {
6584 ADD_INSN(args, argn, concattoarray);
6585 }
6586
6587 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6588 if (kwnode) {
6589 // kwsplat
6590 *flag_ptr |= VM_CALL_KW_SPLAT;
6591 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6592 argc += 1;
6593 }
6594
6595 return argc;
6596 }
6597 case NODE_ARGSPUSH: {
6598 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6599 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6600
6601 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6602 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6603 if (kwnode) rest_len--;
6604 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6605 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6606 }
6607 else {
6608 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6609 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6610 }
6611 else {
6612 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6613 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6614 }
6615 }
6616
6617 if (kwnode) {
6618 // f(*a, k:1)
6619 *flag_ptr |= VM_CALL_KW_SPLAT;
6620 if (!keyword_node_single_splat_p(kwnode)) {
6621 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6622 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6623 }
6624 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6625 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6626 }
6627 else {
6628 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6629 }
6630 argc += 1;
6631 }
6632
6633 return argc;
6634 }
6635 default: {
6636 UNKNOWN_NODE("setup_arg", argn, Qnil);
6637 }
6638 }
6639}
6640
6641static void
6642setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6643{
6644 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6645 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6646 }
6647}
6648
6649static bool
6650setup_args_dup_rest_p(const NODE *argn)
6651{
6652 switch(nd_type(argn)) {
6653 case NODE_LVAR:
6654 case NODE_DVAR:
6655 case NODE_GVAR:
6656 case NODE_IVAR:
6657 case NODE_CVAR:
6658 case NODE_CONST:
6659 case NODE_COLON3:
6660 case NODE_INTEGER:
6661 case NODE_FLOAT:
6662 case NODE_RATIONAL:
6663 case NODE_IMAGINARY:
6664 case NODE_STR:
6665 case NODE_SYM:
6666 case NODE_REGX:
6667 case NODE_SELF:
6668 case NODE_NIL:
6669 case NODE_TRUE:
6670 case NODE_FALSE:
6671 case NODE_LAMBDA:
6672 case NODE_NTH_REF:
6673 case NODE_BACK_REF:
6674 return false;
6675 case NODE_COLON2:
6676 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6677 case NODE_LIST:
6678 while (argn) {
6679 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6680 return true;
6681 }
6682 argn = RNODE_LIST(argn)->nd_next;
6683 }
6684 return false;
6685 default:
6686 return true;
6687 }
6688}
6689
6690static VALUE
6691setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6692 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6693{
6694 VALUE ret;
6695 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6696
6697 if (argn) {
6698 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6699 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6700
6701 if (check_arg) {
6702 switch(nd_type(check_arg)) {
6703 case(NODE_SPLAT):
6704 // avoid caller side array allocation for f(*arg)
6705 dup_rest = SPLATARRAY_FALSE;
6706 break;
6707 case(NODE_ARGSCAT):
6708 // avoid caller side array allocation for f(1, *arg)
6709 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6710 break;
6711 case(NODE_ARGSPUSH):
6712 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6713 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6714 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6715 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6716 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6717 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6718
6719 if (dup_rest == SPLATARRAY_FALSE) {
6720 // require allocation for keyword key/value/splat that may modify splatted argument
6721 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6722 while (node) {
6723 NODE *key_node = RNODE_LIST(node)->nd_head;
6724 if (key_node && setup_args_dup_rest_p(key_node)) {
6725 dup_rest = SPLATARRAY_TRUE;
6726 break;
6727 }
6728
6729 node = RNODE_LIST(node)->nd_next;
6730 NODE *value_node = RNODE_LIST(node)->nd_head;
6731 if (setup_args_dup_rest_p(value_node)) {
6732 dup_rest = SPLATARRAY_TRUE;
6733 break;
6734 }
6735
6736 node = RNODE_LIST(node)->nd_next;
6737 }
6738 }
6739 break;
6740 default:
6741 break;
6742 }
6743 }
6744
6745 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6746 // for block pass that may modify splatted argument, dup rest and kwrest if given
6747 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6748 }
6749 }
6750 initial_dup_rest = dup_rest;
6751
6752 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6753 DECL_ANCHOR(arg_block);
6754 INIT_ANCHOR(arg_block);
6755
6756 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6757 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6758
6759 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6760 const NODE * arg_node =
6761 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6762
6763 int argc = 0;
6764
6765 // Only compile leading args:
6766 // foo(x, y, ...)
6767 // ^^^^
6768 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6769 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6770 }
6771
6772 *flag |= VM_CALL_FORWARDING;
6773
6774 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6775 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6776 return INT2FIX(argc);
6777 }
6778 else {
6779 *flag |= VM_CALL_ARGS_BLOCKARG;
6780
6781 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6782 }
6783
6784 if (LIST_INSN_SIZE_ONE(arg_block)) {
6785 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6786 if (IS_INSN(elem)) {
6787 INSN *iobj = (INSN *)elem;
6788 if (iobj->insn_id == BIN(getblockparam)) {
6789 iobj->insn_id = BIN(getblockparamproxy);
6790 }
6791 }
6792 }
6793 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6794 ADD_SEQ(args, arg_block);
6795 }
6796 else {
6797 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6798 }
6799 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6800 return ret;
6801}
6802
6803static void
6804build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6805{
6806 const NODE *body = ptr;
6807 int line = nd_line(body);
6808 VALUE argc = INT2FIX(0);
6809 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6810
6811 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6812 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6813 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6814 iseq_set_local_table(iseq, 0, 0);
6815}
6816
6817static void
6818compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6819{
6820 const NODE *vars;
6821 LINK_ELEMENT *last;
6822 int line = nd_line(node);
6823 const NODE *line_node = node;
6824 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6825
6826#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6827 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6828#else
6829 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6830#endif
6831 ADD_INSN(ret, line_node, dup);
6832 ADD_INSNL(ret, line_node, branchunless, fail_label);
6833
6834 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6835 INSN *cap;
6836 if (RNODE_BLOCK(vars)->nd_next) {
6837 ADD_INSN(ret, line_node, dup);
6838 }
6839 last = ret->last;
6840 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6841 last = last->next; /* putobject :var */
6842 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6843 NULL, INT2FIX(0), NULL);
6844 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6845#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6846 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6847 /* only one name */
6848 DECL_ANCHOR(nom);
6849
6850 INIT_ANCHOR(nom);
6851 ADD_INSNL(nom, line_node, jump, end_label);
6852 ADD_LABEL(nom, fail_label);
6853# if 0 /* $~ must be MatchData or nil */
6854 ADD_INSN(nom, line_node, pop);
6855 ADD_INSN(nom, line_node, putnil);
6856# endif
6857 ADD_LABEL(nom, end_label);
6858 (nom->last->next = cap->link.next)->prev = nom->last;
6859 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6860 return;
6861 }
6862#endif
6863 }
6864 ADD_INSNL(ret, line_node, jump, end_label);
6865 ADD_LABEL(ret, fail_label);
6866 ADD_INSN(ret, line_node, pop);
6867 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6868 last = ret->last;
6869 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6870 last = last->next; /* putobject :var */
6871 ((INSN*)last)->insn_id = BIN(putnil);
6872 ((INSN*)last)->operand_size = 0;
6873 }
6874 ADD_LABEL(ret, end_label);
6875}
6876
6877static int
6878optimizable_range_item_p(const NODE *n)
6879{
6880 if (!n) return FALSE;
6881 switch (nd_type(n)) {
6882 case NODE_LINE:
6883 return TRUE;
6884 case NODE_INTEGER:
6885 return TRUE;
6886 case NODE_NIL:
6887 return TRUE;
6888 default:
6889 return FALSE;
6890 }
6891}
6892
6893static VALUE
6894optimized_range_item(const NODE *n)
6895{
6896 switch (nd_type(n)) {
6897 case NODE_LINE:
6898 return rb_node_line_lineno_val(n);
6899 case NODE_INTEGER:
6900 return rb_node_integer_literal_val(n);
6901 case NODE_FLOAT:
6902 return rb_node_float_literal_val(n);
6903 case NODE_RATIONAL:
6904 return rb_node_rational_literal_val(n);
6905 case NODE_IMAGINARY:
6906 return rb_node_imaginary_literal_val(n);
6907 case NODE_NIL:
6908 return Qnil;
6909 default:
6910 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6911 }
6912}
6913
6914static int
6915compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6916{
6917 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6918 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6919
6920 const int line = nd_line(node);
6921 const NODE *line_node = node;
6922 DECL_ANCHOR(cond_seq);
6923 LABEL *then_label, *else_label, *end_label;
6924 VALUE branches = Qfalse;
6925
6926 INIT_ANCHOR(cond_seq);
6927 then_label = NEW_LABEL(line);
6928 else_label = NEW_LABEL(line);
6929 end_label = 0;
6930
6931 NODE *cond = RNODE_IF(node)->nd_cond;
6932 if (nd_type(cond) == NODE_BLOCK) {
6933 cond = RNODE_BLOCK(cond)->nd_head;
6934 }
6935
6936 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6937 ADD_SEQ(ret, cond_seq);
6938
6939 if (then_label->refcnt && else_label->refcnt) {
6940 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6941 }
6942
6943 if (then_label->refcnt) {
6944 ADD_LABEL(ret, then_label);
6945
6946 DECL_ANCHOR(then_seq);
6947 INIT_ANCHOR(then_seq);
6948 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6949
6950 if (else_label->refcnt) {
6951 const NODE *const coverage_node = node_body ? node_body : node;
6952 add_trace_branch_coverage(
6953 iseq,
6954 ret,
6955 nd_code_loc(coverage_node),
6956 nd_node_id(coverage_node),
6957 0,
6958 type == NODE_IF ? "then" : "else",
6959 branches);
6960 end_label = NEW_LABEL(line);
6961 ADD_INSNL(then_seq, line_node, jump, end_label);
6962 if (!popped) {
6963 ADD_INSN(then_seq, line_node, pop);
6964 }
6965 }
6966 ADD_SEQ(ret, then_seq);
6967 }
6968
6969 if (else_label->refcnt) {
6970 ADD_LABEL(ret, else_label);
6971
6972 DECL_ANCHOR(else_seq);
6973 INIT_ANCHOR(else_seq);
6974 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6975
6976 if (then_label->refcnt) {
6977 const NODE *const coverage_node = node_else ? node_else : node;
6978 add_trace_branch_coverage(
6979 iseq,
6980 ret,
6981 nd_code_loc(coverage_node),
6982 nd_node_id(coverage_node),
6983 1,
6984 type == NODE_IF ? "else" : "then",
6985 branches);
6986 }
6987 ADD_SEQ(ret, else_seq);
6988 }
6989
6990 if (end_label) {
6991 ADD_LABEL(ret, end_label);
6992 }
6993
6994 return COMPILE_OK;
6995}
6996
6997static int
6998compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6999{
7000 const NODE *vals;
7001 const NODE *node = orig_node;
7002 LABEL *endlabel, *elselabel;
7003 DECL_ANCHOR(head);
7004 DECL_ANCHOR(body_seq);
7005 DECL_ANCHOR(cond_seq);
7006 int only_special_literals = 1;
7007 VALUE literals = rb_hash_new();
7008 int line;
7009 enum node_type type;
7010 const NODE *line_node;
7011 VALUE branches = Qfalse;
7012 int branch_id = 0;
7013
7014 INIT_ANCHOR(head);
7015 INIT_ANCHOR(body_seq);
7016 INIT_ANCHOR(cond_seq);
7017
7018 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7019
7020 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7021
7022 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7023
7024 node = RNODE_CASE(node)->nd_body;
7025 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7026 type = nd_type(node);
7027 line = nd_line(node);
7028 line_node = node;
7029
7030 endlabel = NEW_LABEL(line);
7031 elselabel = NEW_LABEL(line);
7032
7033 ADD_SEQ(ret, head); /* case VAL */
7034
7035 while (type == NODE_WHEN) {
7036 LABEL *l1;
7037
7038 l1 = NEW_LABEL(line);
7039 ADD_LABEL(body_seq, l1);
7040 ADD_INSN(body_seq, line_node, pop);
7041
7042 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7043 add_trace_branch_coverage(
7044 iseq,
7045 body_seq,
7046 nd_code_loc(coverage_node),
7047 nd_node_id(coverage_node),
7048 branch_id++,
7049 "when",
7050 branches);
7051
7052 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7053 ADD_INSNL(body_seq, line_node, jump, endlabel);
7054
7055 vals = RNODE_WHEN(node)->nd_head;
7056 if (vals) {
7057 switch (nd_type(vals)) {
7058 case NODE_LIST:
7059 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7060 if (only_special_literals < 0) return COMPILE_NG;
7061 break;
7062 case NODE_SPLAT:
7063 case NODE_ARGSCAT:
7064 case NODE_ARGSPUSH:
7065 only_special_literals = 0;
7066 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7067 break;
7068 default:
7069 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7070 }
7071 }
7072 else {
7073 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7074 }
7075
7076 node = RNODE_WHEN(node)->nd_next;
7077 if (!node) {
7078 break;
7079 }
7080 type = nd_type(node);
7081 line = nd_line(node);
7082 line_node = node;
7083 }
7084 /* else */
7085 if (node) {
7086 ADD_LABEL(cond_seq, elselabel);
7087 ADD_INSN(cond_seq, line_node, pop);
7088 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7089 CHECK(COMPILE_(cond_seq, "else", node, popped));
7090 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7091 }
7092 else {
7093 debugs("== else (implicit)\n");
7094 ADD_LABEL(cond_seq, elselabel);
7095 ADD_INSN(cond_seq, orig_node, pop);
7096 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7097 if (!popped) {
7098 ADD_INSN(cond_seq, orig_node, putnil);
7099 }
7100 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7101 }
7102
7103 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7104 ADD_INSN(ret, orig_node, dup);
7105 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7106 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7107 LABEL_REF(elselabel);
7108 }
7109
7110 ADD_SEQ(ret, cond_seq);
7111 ADD_SEQ(ret, body_seq);
7112 ADD_LABEL(ret, endlabel);
7113 return COMPILE_OK;
7114}
7115
7116static int
7117compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7118{
7119 const NODE *vals;
7120 const NODE *val;
7121 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7122 LABEL *endlabel;
7123 DECL_ANCHOR(body_seq);
7124 VALUE branches = Qfalse;
7125 int branch_id = 0;
7126
7127 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7128
7129 INIT_ANCHOR(body_seq);
7130 endlabel = NEW_LABEL(nd_line(node));
7131
7132 while (node && nd_type_p(node, NODE_WHEN)) {
7133 const int line = nd_line(node);
7134 LABEL *l1 = NEW_LABEL(line);
7135 ADD_LABEL(body_seq, l1);
7136
7137 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7138 add_trace_branch_coverage(
7139 iseq,
7140 body_seq,
7141 nd_code_loc(coverage_node),
7142 nd_node_id(coverage_node),
7143 branch_id++,
7144 "when",
7145 branches);
7146
7147 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7148 ADD_INSNL(body_seq, node, jump, endlabel);
7149
7150 vals = RNODE_WHEN(node)->nd_head;
7151 if (!vals) {
7152 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7153 }
7154 switch (nd_type(vals)) {
7155 case NODE_LIST:
7156 while (vals) {
7157 LABEL *lnext;
7158 val = RNODE_LIST(vals)->nd_head;
7159 lnext = NEW_LABEL(nd_line(val));
7160 debug_compile("== when2\n", (void)0);
7161 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7162 ADD_LABEL(ret, lnext);
7163 vals = RNODE_LIST(vals)->nd_next;
7164 }
7165 break;
7166 case NODE_SPLAT:
7167 case NODE_ARGSCAT:
7168 case NODE_ARGSPUSH:
7169 ADD_INSN(ret, vals, putnil);
7170 CHECK(COMPILE(ret, "when2/cond splat", vals));
7171 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7172 ADD_INSNL(ret, vals, branchif, l1);
7173 break;
7174 default:
7175 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7176 }
7177 node = RNODE_WHEN(node)->nd_next;
7178 }
7179 /* else */
7180 const NODE *const coverage_node = node ? node : orig_node;
7181 add_trace_branch_coverage(
7182 iseq,
7183 ret,
7184 nd_code_loc(coverage_node),
7185 nd_node_id(coverage_node),
7186 branch_id,
7187 "else",
7188 branches);
7189 CHECK(COMPILE_(ret, "else", node, popped));
7190 ADD_INSNL(ret, orig_node, jump, endlabel);
7191
7192 ADD_SEQ(ret, body_seq);
7193 ADD_LABEL(ret, endlabel);
7194 return COMPILE_OK;
7195}
7196
7197static 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);
7198
7199static 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);
7200static 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);
7201static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7202static 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);
7203static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7204
7205#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7206#define CASE3_BI_OFFSET_ERROR_STRING 1
7207#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7208#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7209#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7210
7211static int
7212iseq_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)
7213{
7214 const int line = nd_line(node);
7215 const NODE *line_node = node;
7216
7217 switch (nd_type(node)) {
7218 case NODE_ARYPTN: {
7219 /*
7220 * if pattern.use_rest_num?
7221 * rest_num = 0
7222 * end
7223 * if pattern.has_constant_node?
7224 * unless pattern.constant === obj
7225 * goto match_failed
7226 * end
7227 * end
7228 * unless obj.respond_to?(:deconstruct)
7229 * goto match_failed
7230 * end
7231 * d = obj.deconstruct
7232 * unless Array === d
7233 * goto type_error
7234 * end
7235 * min_argc = pattern.pre_args_num + pattern.post_args_num
7236 * if pattern.has_rest_arg?
7237 * unless d.length >= min_argc
7238 * goto match_failed
7239 * end
7240 * else
7241 * unless d.length == min_argc
7242 * goto match_failed
7243 * end
7244 * end
7245 * pattern.pre_args_num.each do |i|
7246 * unless pattern.pre_args[i].match?(d[i])
7247 * goto match_failed
7248 * end
7249 * end
7250 * if pattern.use_rest_num?
7251 * rest_num = d.length - min_argc
7252 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7253 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7254 * goto match_failed
7255 * end
7256 * end
7257 * end
7258 * pattern.post_args_num.each do |i|
7259 * j = pattern.pre_args_num + i
7260 * j += rest_num
7261 * unless pattern.post_args[i].match?(d[j])
7262 * goto match_failed
7263 * end
7264 * end
7265 * goto matched
7266 * type_error:
7267 * FrozenCore.raise TypeError
7268 * match_failed:
7269 * goto unmatched
7270 */
7271 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7272 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7273 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7274
7275 const int min_argc = pre_args_num + post_args_num;
7276 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7277 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7278
7279 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7280 int i;
7281 match_failed = NEW_LABEL(line);
7282 type_error = NEW_LABEL(line);
7283 deconstruct = NEW_LABEL(line);
7284 deconstructed = NEW_LABEL(line);
7285
7286 if (use_rest_num) {
7287 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7288 ADD_INSN(ret, line_node, swap);
7289 if (base_index) {
7290 base_index++;
7291 }
7292 }
7293
7294 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7295
7296 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7297
7298 ADD_INSN(ret, line_node, dup);
7299 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7300 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7301 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7302 if (in_single_pattern) {
7303 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7304 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7305 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7306 INT2FIX(min_argc), base_index + 1 /* (1) */));
7307 }
7308 ADD_INSNL(ret, line_node, branchunless, match_failed);
7309
7310 for (i = 0; i < pre_args_num; i++) {
7311 ADD_INSN(ret, line_node, dup);
7312 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7313 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7314 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));
7315 args = RNODE_LIST(args)->nd_next;
7316 }
7317
7318 if (RNODE_ARYPTN(node)->rest_arg) {
7319 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7320 ADD_INSN(ret, line_node, dup);
7321 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7322 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7323 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7324 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7325 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7326 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7327 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7328
7329 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));
7330 }
7331 else {
7332 if (post_args_num > 0) {
7333 ADD_INSN(ret, line_node, dup);
7334 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7335 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7336 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7337 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7338 ADD_INSN(ret, line_node, pop);
7339 }
7340 }
7341 }
7342
7343 args = RNODE_ARYPTN(node)->post_args;
7344 for (i = 0; i < post_args_num; i++) {
7345 ADD_INSN(ret, line_node, dup);
7346
7347 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7348 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7349 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7350
7351 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7352 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));
7353 args = RNODE_LIST(args)->nd_next;
7354 }
7355
7356 ADD_INSN(ret, line_node, pop);
7357 if (use_rest_num) {
7358 ADD_INSN(ret, line_node, pop);
7359 }
7360 ADD_INSNL(ret, line_node, jump, matched);
7361 ADD_INSN(ret, line_node, putnil);
7362 if (use_rest_num) {
7363 ADD_INSN(ret, line_node, putnil);
7364 }
7365
7366 ADD_LABEL(ret, type_error);
7367 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7368 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7369 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7370 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7371 ADD_INSN(ret, line_node, pop);
7372
7373 ADD_LABEL(ret, match_failed);
7374 ADD_INSN(ret, line_node, pop);
7375 if (use_rest_num) {
7376 ADD_INSN(ret, line_node, pop);
7377 }
7378 ADD_INSNL(ret, line_node, jump, unmatched);
7379
7380 break;
7381 }
7382 case NODE_FNDPTN: {
7383 /*
7384 * if pattern.has_constant_node?
7385 * unless pattern.constant === obj
7386 * goto match_failed
7387 * end
7388 * end
7389 * unless obj.respond_to?(:deconstruct)
7390 * goto match_failed
7391 * end
7392 * d = obj.deconstruct
7393 * unless Array === d
7394 * goto type_error
7395 * end
7396 * unless d.length >= pattern.args_num
7397 * goto match_failed
7398 * end
7399 *
7400 * begin
7401 * len = d.length
7402 * limit = d.length - pattern.args_num
7403 * i = 0
7404 * while i <= limit
7405 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7406 * if pattern.has_pre_rest_arg_id
7407 * unless pattern.pre_rest_arg.match?(d[0, i])
7408 * goto find_failed
7409 * end
7410 * end
7411 * if pattern.has_post_rest_arg_id
7412 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7413 * goto find_failed
7414 * end
7415 * end
7416 * goto find_succeeded
7417 * end
7418 * i+=1
7419 * end
7420 * find_failed:
7421 * goto match_failed
7422 * find_succeeded:
7423 * end
7424 *
7425 * goto matched
7426 * type_error:
7427 * FrozenCore.raise TypeError
7428 * match_failed:
7429 * goto unmatched
7430 */
7431 const NODE *args = RNODE_FNDPTN(node)->args;
7432 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7433
7434 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7435 match_failed = NEW_LABEL(line);
7436 type_error = NEW_LABEL(line);
7437 deconstruct = NEW_LABEL(line);
7438 deconstructed = NEW_LABEL(line);
7439
7440 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7441
7442 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7443
7444 ADD_INSN(ret, line_node, dup);
7445 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7446 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7447 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7448 if (in_single_pattern) {
7449 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) */));
7450 }
7451 ADD_INSNL(ret, line_node, branchunless, match_failed);
7452
7453 {
7454 LABEL *while_begin = NEW_LABEL(nd_line(node));
7455 LABEL *next_loop = NEW_LABEL(nd_line(node));
7456 LABEL *find_succeeded = NEW_LABEL(line);
7457 LABEL *find_failed = NEW_LABEL(nd_line(node));
7458 int j;
7459
7460 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7461 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7462
7463 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7464 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7465 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7466
7467 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7468
7469 ADD_LABEL(ret, while_begin);
7470
7471 ADD_INSN(ret, line_node, dup);
7472 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7473 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7474 ADD_INSNL(ret, line_node, branchunless, find_failed);
7475
7476 for (j = 0; j < args_num; j++) {
7477 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7478 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7479 if (j != 0) {
7480 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7481 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7482 }
7483 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7484
7485 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));
7486 args = RNODE_LIST(args)->nd_next;
7487 }
7488
7489 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7490 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7491 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7492 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7493 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7494 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));
7495 }
7496 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7497 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7498 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7499 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7500 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7501 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7502 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7503 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));
7504 }
7505 ADD_INSNL(ret, line_node, jump, find_succeeded);
7506
7507 ADD_LABEL(ret, next_loop);
7508 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7509 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7510 ADD_INSNL(ret, line_node, jump, while_begin);
7511
7512 ADD_LABEL(ret, find_failed);
7513 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7514 if (in_single_pattern) {
7515 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7516 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7517 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7518 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7519 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7520
7521 ADD_INSN1(ret, line_node, putobject, Qfalse);
7522 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7523
7524 ADD_INSN(ret, line_node, pop);
7525 ADD_INSN(ret, line_node, pop);
7526 }
7527 ADD_INSNL(ret, line_node, jump, match_failed);
7528 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7529
7530 ADD_LABEL(ret, find_succeeded);
7531 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7532 }
7533
7534 ADD_INSN(ret, line_node, pop);
7535 ADD_INSNL(ret, line_node, jump, matched);
7536 ADD_INSN(ret, line_node, putnil);
7537
7538 ADD_LABEL(ret, type_error);
7539 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7540 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7541 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7542 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7543 ADD_INSN(ret, line_node, pop);
7544
7545 ADD_LABEL(ret, match_failed);
7546 ADD_INSN(ret, line_node, pop);
7547 ADD_INSNL(ret, line_node, jump, unmatched);
7548
7549 break;
7550 }
7551 case NODE_HSHPTN: {
7552 /*
7553 * keys = nil
7554 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7555 * keys = pattern.kw_args_node.keys
7556 * end
7557 * if pattern.has_constant_node?
7558 * unless pattern.constant === obj
7559 * goto match_failed
7560 * end
7561 * end
7562 * unless obj.respond_to?(:deconstruct_keys)
7563 * goto match_failed
7564 * end
7565 * d = obj.deconstruct_keys(keys)
7566 * unless Hash === d
7567 * goto type_error
7568 * end
7569 * if pattern.has_kw_rest_arg_node?
7570 * d = d.dup
7571 * end
7572 * if pattern.has_kw_args_node?
7573 * pattern.kw_args_node.each |k,|
7574 * unless d.key?(k)
7575 * goto match_failed
7576 * end
7577 * end
7578 * pattern.kw_args_node.each |k, pat|
7579 * if pattern.has_kw_rest_arg_node?
7580 * unless pat.match?(d.delete(k))
7581 * goto match_failed
7582 * end
7583 * else
7584 * unless pat.match?(d[k])
7585 * goto match_failed
7586 * end
7587 * end
7588 * end
7589 * else
7590 * unless d.empty?
7591 * goto match_failed
7592 * end
7593 * end
7594 * if pattern.has_kw_rest_arg_node?
7595 * if pattern.no_rest_keyword?
7596 * unless d.empty?
7597 * goto match_failed
7598 * end
7599 * else
7600 * unless pattern.kw_rest_arg_node.match?(d)
7601 * goto match_failed
7602 * end
7603 * end
7604 * end
7605 * goto matched
7606 * type_error:
7607 * FrozenCore.raise TypeError
7608 * match_failed:
7609 * goto unmatched
7610 */
7611 LABEL *match_failed, *type_error;
7612 VALUE keys = Qnil;
7613
7614 match_failed = NEW_LABEL(line);
7615 type_error = NEW_LABEL(line);
7616
7617 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7618 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7619 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7620 while (kw_args) {
7621 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7622 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7623 }
7624 }
7625
7626 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7627
7628 ADD_INSN(ret, line_node, dup);
7629 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7630 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7631 if (in_single_pattern) {
7632 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7633 }
7634 ADD_INSNL(ret, line_node, branchunless, match_failed);
7635
7636 if (NIL_P(keys)) {
7637 ADD_INSN(ret, line_node, putnil);
7638 }
7639 else {
7640 ADD_INSN1(ret, line_node, duparray, keys);
7641 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7642 }
7643 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7644
7645 ADD_INSN(ret, line_node, dup);
7646 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7647 ADD_INSNL(ret, line_node, branchunless, type_error);
7648
7649 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7650 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7651 }
7652
7653 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7654 int i;
7655 int keys_num;
7656 const NODE *args;
7657 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7658 if (args) {
7659 DECL_ANCHOR(match_values);
7660 INIT_ANCHOR(match_values);
7661 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7662 for (i = 0; i < keys_num; i++) {
7663 NODE *key_node = RNODE_LIST(args)->nd_head;
7664 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7665 VALUE key = get_symbol_value(iseq, key_node);
7666
7667 ADD_INSN(ret, line_node, dup);
7668 ADD_INSN1(ret, line_node, putobject, key);
7669 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7670 if (in_single_pattern) {
7671 LABEL *match_succeeded;
7672 match_succeeded = NEW_LABEL(line);
7673
7674 ADD_INSN(ret, line_node, dup);
7675 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7676
7677 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7678 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7679 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7680 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7681 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7682 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7683 ADD_INSN1(ret, line_node, putobject, key); // (7)
7684 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7685
7686 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7687
7688 ADD_LABEL(ret, match_succeeded);
7689 }
7690 ADD_INSNL(ret, line_node, branchunless, match_failed);
7691
7692 ADD_INSN(match_values, line_node, dup);
7693 ADD_INSN1(match_values, line_node, putobject, key);
7694 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7695 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7696 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7697 }
7698 ADD_SEQ(ret, match_values);
7699 }
7700 }
7701 else {
7702 ADD_INSN(ret, line_node, dup);
7703 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7704 if (in_single_pattern) {
7705 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7706 }
7707 ADD_INSNL(ret, line_node, branchunless, match_failed);
7708 }
7709
7710 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7711 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7712 ADD_INSN(ret, line_node, dup);
7713 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7714 if (in_single_pattern) {
7715 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7716 }
7717 ADD_INSNL(ret, line_node, branchunless, match_failed);
7718 }
7719 else {
7720 ADD_INSN(ret, line_node, dup); // (11)
7721 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));
7722 }
7723 }
7724
7725 ADD_INSN(ret, line_node, pop);
7726 ADD_INSNL(ret, line_node, jump, matched);
7727 ADD_INSN(ret, line_node, putnil);
7728
7729 ADD_LABEL(ret, type_error);
7730 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7731 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7732 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7733 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7734 ADD_INSN(ret, line_node, pop);
7735
7736 ADD_LABEL(ret, match_failed);
7737 ADD_INSN(ret, line_node, pop);
7738 ADD_INSNL(ret, line_node, jump, unmatched);
7739 break;
7740 }
7741 case NODE_SYM:
7742 case NODE_REGX:
7743 case NODE_LINE:
7744 case NODE_INTEGER:
7745 case NODE_FLOAT:
7746 case NODE_RATIONAL:
7747 case NODE_IMAGINARY:
7748 case NODE_FILE:
7749 case NODE_ENCODING:
7750 case NODE_STR:
7751 case NODE_XSTR:
7752 case NODE_DSTR:
7753 case NODE_DSYM:
7754 case NODE_DREGX:
7755 case NODE_LIST:
7756 case NODE_ZLIST:
7757 case NODE_LAMBDA:
7758 case NODE_DOT2:
7759 case NODE_DOT3:
7760 case NODE_CONST:
7761 case NODE_LVAR:
7762 case NODE_DVAR:
7763 case NODE_IVAR:
7764 case NODE_CVAR:
7765 case NODE_GVAR:
7766 case NODE_TRUE:
7767 case NODE_FALSE:
7768 case NODE_SELF:
7769 case NODE_NIL:
7770 case NODE_COLON2:
7771 case NODE_COLON3:
7772 case NODE_BEGIN:
7773 case NODE_BLOCK:
7774 case NODE_ONCE:
7775 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7776 if (in_single_pattern) {
7777 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7778 }
7779 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7780 if (in_single_pattern) {
7781 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7782 }
7783 ADD_INSNL(ret, line_node, branchif, matched);
7784 ADD_INSNL(ret, line_node, jump, unmatched);
7785 break;
7786 case NODE_LASGN: {
7787 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7788 ID id = RNODE_LASGN(node)->nd_vid;
7789 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7790
7791 if (in_alt_pattern) {
7792 const char *name = rb_id2name(id);
7793 if (name && strlen(name) > 0 && name[0] != '_') {
7794 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7795 rb_id2str(id));
7796 return COMPILE_NG;
7797 }
7798 }
7799
7800 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7801 ADD_INSNL(ret, line_node, jump, matched);
7802 break;
7803 }
7804 case NODE_DASGN: {
7805 int idx, lv, ls;
7806 ID id = RNODE_DASGN(node)->nd_vid;
7807
7808 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7809
7810 if (in_alt_pattern) {
7811 const char *name = rb_id2name(id);
7812 if (name && strlen(name) > 0 && name[0] != '_') {
7813 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7814 rb_id2str(id));
7815 return COMPILE_NG;
7816 }
7817 }
7818
7819 if (idx < 0) {
7820 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7821 rb_id2str(id));
7822 return COMPILE_NG;
7823 }
7824 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7825 ADD_INSNL(ret, line_node, jump, matched);
7826 break;
7827 }
7828 case NODE_IF:
7829 case NODE_UNLESS: {
7830 LABEL *match_failed;
7831 match_failed = unmatched;
7832 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7833 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7834 if (in_single_pattern) {
7835 LABEL *match_succeeded;
7836 match_succeeded = NEW_LABEL(line);
7837
7838 ADD_INSN(ret, line_node, dup);
7839 if (nd_type_p(node, NODE_IF)) {
7840 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7841 }
7842 else {
7843 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7844 }
7845
7846 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7847 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7848 ADD_INSN1(ret, line_node, putobject, Qfalse);
7849 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7850
7851 ADD_INSN(ret, line_node, pop);
7852 ADD_INSN(ret, line_node, pop);
7853
7854 ADD_LABEL(ret, match_succeeded);
7855 }
7856 if (nd_type_p(node, NODE_IF)) {
7857 ADD_INSNL(ret, line_node, branchunless, match_failed);
7858 }
7859 else {
7860 ADD_INSNL(ret, line_node, branchif, match_failed);
7861 }
7862 ADD_INSNL(ret, line_node, jump, matched);
7863 break;
7864 }
7865 case NODE_HASH: {
7866 NODE *n;
7867 LABEL *match_failed;
7868 match_failed = NEW_LABEL(line);
7869
7870 n = RNODE_HASH(node)->nd_head;
7871 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7872 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7873 return COMPILE_NG;
7874 }
7875
7876 ADD_INSN(ret, line_node, dup); // (1)
7877 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));
7878 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));
7879 ADD_INSN(ret, line_node, putnil);
7880
7881 ADD_LABEL(ret, match_failed);
7882 ADD_INSN(ret, line_node, pop);
7883 ADD_INSNL(ret, line_node, jump, unmatched);
7884 break;
7885 }
7886 case NODE_OR: {
7887 LABEL *match_succeeded, *fin;
7888 match_succeeded = NEW_LABEL(line);
7889 fin = NEW_LABEL(line);
7890
7891 ADD_INSN(ret, line_node, dup); // (1)
7892 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));
7893 ADD_LABEL(ret, match_succeeded);
7894 ADD_INSN(ret, line_node, pop);
7895 ADD_INSNL(ret, line_node, jump, matched);
7896 ADD_INSN(ret, line_node, putnil);
7897 ADD_LABEL(ret, fin);
7898 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7899 break;
7900 }
7901 default:
7902 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7903 }
7904 return COMPILE_OK;
7905}
7906
7907static int
7908iseq_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)
7909{
7910 LABEL *fin = NEW_LABEL(nd_line(node));
7911 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7912 ADD_LABEL(ret, fin);
7913 return COMPILE_OK;
7914}
7915
7916static int
7917iseq_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)
7918{
7919 const NODE *line_node = node;
7920
7921 if (RNODE_ARYPTN(node)->nd_pconst) {
7922 ADD_INSN(ret, line_node, dup); // (1)
7923 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7924 if (in_single_pattern) {
7925 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7926 }
7927 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7928 if (in_single_pattern) {
7929 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7930 }
7931 ADD_INSNL(ret, line_node, branchunless, match_failed);
7932 }
7933 return COMPILE_OK;
7934}
7935
7936
7937static int
7938iseq_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)
7939{
7940 const NODE *line_node = node;
7941
7942 // NOTE: this optimization allows us to re-use the #deconstruct value
7943 // (or its absence).
7944 if (use_deconstructed_cache) {
7945 // If value is nil then we haven't tried to deconstruct
7946 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7947 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7948
7949 // If false then the value is not deconstructable
7950 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7951 ADD_INSNL(ret, line_node, branchunless, match_failed);
7952
7953 // Drop value, add deconstructed to the stack and jump
7954 ADD_INSN(ret, line_node, pop); // (1)
7955 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7956 ADD_INSNL(ret, line_node, jump, deconstructed);
7957 }
7958 else {
7959 ADD_INSNL(ret, line_node, jump, deconstruct);
7960 }
7961
7962 ADD_LABEL(ret, deconstruct);
7963 ADD_INSN(ret, line_node, dup);
7964 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7965 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7966
7967 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7968 if (use_deconstructed_cache) {
7969 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7970 }
7971
7972 if (in_single_pattern) {
7973 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7974 }
7975
7976 ADD_INSNL(ret, line_node, branchunless, match_failed);
7977
7978 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7979
7980 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7981 if (use_deconstructed_cache) {
7982 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7983 }
7984
7985 ADD_INSN(ret, line_node, dup);
7986 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7987 ADD_INSNL(ret, line_node, branchunless, type_error);
7988
7989 ADD_LABEL(ret, deconstructed);
7990
7991 return COMPILE_OK;
7992}
7993
7994static int
7995iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7996{
7997 /*
7998 * if match_succeeded?
7999 * goto match_succeeded
8000 * end
8001 * error_string = FrozenCore.sprintf(errmsg, matchee)
8002 * key_error_p = false
8003 * match_succeeded:
8004 */
8005 const int line = nd_line(node);
8006 const NODE *line_node = node;
8007 LABEL *match_succeeded = NEW_LABEL(line);
8008
8009 ADD_INSN(ret, line_node, dup);
8010 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8011
8012 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8013 ADD_INSN1(ret, line_node, putobject, errmsg);
8014 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8015 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8016 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8017
8018 ADD_INSN1(ret, line_node, putobject, Qfalse);
8019 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8020
8021 ADD_INSN(ret, line_node, pop);
8022 ADD_INSN(ret, line_node, pop);
8023 ADD_LABEL(ret, match_succeeded);
8024
8025 return COMPILE_OK;
8026}
8027
8028static int
8029iseq_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)
8030{
8031 /*
8032 * if match_succeeded?
8033 * goto match_succeeded
8034 * end
8035 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8036 * key_error_p = false
8037 * match_succeeded:
8038 */
8039 const int line = nd_line(node);
8040 const NODE *line_node = node;
8041 LABEL *match_succeeded = NEW_LABEL(line);
8042
8043 ADD_INSN(ret, line_node, dup);
8044 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8045
8046 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8047 ADD_INSN1(ret, line_node, putobject, errmsg);
8048 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8049 ADD_INSN(ret, line_node, dup);
8050 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8051 ADD_INSN1(ret, line_node, putobject, pattern_length);
8052 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8053 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8054
8055 ADD_INSN1(ret, line_node, putobject, Qfalse);
8056 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8057
8058 ADD_INSN(ret, line_node, pop);
8059 ADD_INSN(ret, line_node, pop);
8060 ADD_LABEL(ret, match_succeeded);
8061
8062 return COMPILE_OK;
8063}
8064
8065static int
8066iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8067{
8068 /*
8069 * if match_succeeded?
8070 * goto match_succeeded
8071 * end
8072 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8073 * key_error_p = false
8074 * match_succeeded:
8075 */
8076 const int line = nd_line(node);
8077 const NODE *line_node = node;
8078 LABEL *match_succeeded = NEW_LABEL(line);
8079
8080 ADD_INSN(ret, line_node, dup);
8081 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8082
8083 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8084 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8085 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8086 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8087 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8088 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8089
8090 ADD_INSN1(ret, line_node, putobject, Qfalse);
8091 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8092
8093 ADD_INSN(ret, line_node, pop);
8094 ADD_INSN(ret, line_node, pop);
8095
8096 ADD_LABEL(ret, match_succeeded);
8097 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8098 ADD_INSN(ret, line_node, pop);
8099 ADD_INSN(ret, line_node, pop);
8100
8101 return COMPILE_OK;
8102}
8103
8104static int
8105compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8106{
8107 const NODE *pattern;
8108 const NODE *node = orig_node;
8109 LABEL *endlabel, *elselabel;
8110 DECL_ANCHOR(head);
8111 DECL_ANCHOR(body_seq);
8112 DECL_ANCHOR(cond_seq);
8113 int line;
8114 enum node_type type;
8115 const NODE *line_node;
8116 VALUE branches = 0;
8117 int branch_id = 0;
8118 bool single_pattern;
8119
8120 INIT_ANCHOR(head);
8121 INIT_ANCHOR(body_seq);
8122 INIT_ANCHOR(cond_seq);
8123
8124 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8125
8126 node = RNODE_CASE3(node)->nd_body;
8127 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8128 type = nd_type(node);
8129 line = nd_line(node);
8130 line_node = node;
8131 single_pattern = !RNODE_IN(node)->nd_next;
8132
8133 endlabel = NEW_LABEL(line);
8134 elselabel = NEW_LABEL(line);
8135
8136 if (single_pattern) {
8137 /* allocate stack for ... */
8138 ADD_INSN(head, line_node, putnil); /* key_error_key */
8139 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8140 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8141 ADD_INSN(head, line_node, putnil); /* error_string */
8142 }
8143 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8144
8145 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8146
8147 ADD_SEQ(ret, head); /* case VAL */
8148
8149 while (type == NODE_IN) {
8150 LABEL *l1;
8151
8152 if (branch_id) {
8153 ADD_INSN(body_seq, line_node, putnil);
8154 }
8155 l1 = NEW_LABEL(line);
8156 ADD_LABEL(body_seq, l1);
8157 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8158
8159 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8160 add_trace_branch_coverage(
8161 iseq,
8162 body_seq,
8163 nd_code_loc(coverage_node),
8164 nd_node_id(coverage_node),
8165 branch_id++,
8166 "in",
8167 branches);
8168
8169 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8170 ADD_INSNL(body_seq, line_node, jump, endlabel);
8171
8172 pattern = RNODE_IN(node)->nd_head;
8173 if (pattern) {
8174 int pat_line = nd_line(pattern);
8175 LABEL *next_pat = NEW_LABEL(pat_line);
8176 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8177 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8178 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8179 ADD_LABEL(cond_seq, next_pat);
8180 LABEL_UNREMOVABLE(next_pat);
8181 }
8182 else {
8183 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8184 return COMPILE_NG;
8185 }
8186
8187 node = RNODE_IN(node)->nd_next;
8188 if (!node) {
8189 break;
8190 }
8191 type = nd_type(node);
8192 line = nd_line(node);
8193 line_node = node;
8194 }
8195 /* else */
8196 if (node) {
8197 ADD_LABEL(cond_seq, elselabel);
8198 ADD_INSN(cond_seq, line_node, pop);
8199 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8200 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8201 CHECK(COMPILE_(cond_seq, "else", node, popped));
8202 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8203 ADD_INSN(cond_seq, line_node, putnil);
8204 if (popped) {
8205 ADD_INSN(cond_seq, line_node, putnil);
8206 }
8207 }
8208 else {
8209 debugs("== else (implicit)\n");
8210 ADD_LABEL(cond_seq, elselabel);
8211 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8212 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8213
8214 if (single_pattern) {
8215 /*
8216 * if key_error_p
8217 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8218 * else
8219 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8220 * end
8221 */
8222 LABEL *key_error, *fin;
8223 struct rb_callinfo_kwarg *kw_arg;
8224
8225 key_error = NEW_LABEL(line);
8226 fin = NEW_LABEL(line);
8227
8228 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8229 kw_arg->references = 0;
8230 kw_arg->keyword_len = 2;
8231 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8232 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8233
8234 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8235 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8236 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8237 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8238 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8239 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8240 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8241 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8242 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8243 ADD_INSNL(cond_seq, orig_node, jump, fin);
8244
8245 ADD_LABEL(cond_seq, key_error);
8246 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8247 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8248 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8249 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8250 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8251 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8252 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8253 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8254 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8255 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8256
8257 ADD_LABEL(cond_seq, fin);
8258 }
8259 else {
8260 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8261 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8262 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8263 }
8264 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8265 if (!popped) {
8266 ADD_INSN(cond_seq, orig_node, putnil);
8267 }
8268 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8269 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8270 if (popped) {
8271 ADD_INSN(cond_seq, line_node, putnil);
8272 }
8273 }
8274
8275 ADD_SEQ(ret, cond_seq);
8276 ADD_SEQ(ret, body_seq);
8277 ADD_LABEL(ret, endlabel);
8278 return COMPILE_OK;
8279}
8280
8281#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8282#undef CASE3_BI_OFFSET_ERROR_STRING
8283#undef CASE3_BI_OFFSET_KEY_ERROR_P
8284#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8285#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8286
8287static int
8288compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8289{
8290 const int line = (int)nd_line(node);
8291 const NODE *line_node = node;
8292
8293 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8294 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8295 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8296 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8297 VALUE branches = Qfalse;
8298
8300
8301 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8302 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8303 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8304 LABEL *end_label = NEW_LABEL(line);
8305 LABEL *adjust_label = NEW_LABEL(line);
8306
8307 LABEL *next_catch_label = NEW_LABEL(line);
8308 LABEL *tmp_label = NULL;
8309
8310 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8311 push_ensure_entry(iseq, &enl, NULL, NULL);
8312
8313 if (RNODE_WHILE(node)->nd_state == 1) {
8314 ADD_INSNL(ret, line_node, jump, next_label);
8315 }
8316 else {
8317 tmp_label = NEW_LABEL(line);
8318 ADD_INSNL(ret, line_node, jump, tmp_label);
8319 }
8320 ADD_LABEL(ret, adjust_label);
8321 ADD_INSN(ret, line_node, putnil);
8322 ADD_LABEL(ret, next_catch_label);
8323 ADD_INSN(ret, line_node, pop);
8324 ADD_INSNL(ret, line_node, jump, next_label);
8325 if (tmp_label) ADD_LABEL(ret, tmp_label);
8326
8327 ADD_LABEL(ret, redo_label);
8328 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8329
8330 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8331 add_trace_branch_coverage(
8332 iseq,
8333 ret,
8334 nd_code_loc(coverage_node),
8335 nd_node_id(coverage_node),
8336 0,
8337 "body",
8338 branches);
8339
8340 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8341 ADD_LABEL(ret, next_label); /* next */
8342
8343 if (type == NODE_WHILE) {
8344 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8345 redo_label, end_label));
8346 }
8347 else {
8348 /* until */
8349 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8350 end_label, redo_label));
8351 }
8352
8353 ADD_LABEL(ret, end_label);
8354 ADD_ADJUST_RESTORE(ret, adjust_label);
8355
8356 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8357 /* ADD_INSN(ret, line_node, putundef); */
8358 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8359 return COMPILE_NG;
8360 }
8361 else {
8362 ADD_INSN(ret, line_node, putnil);
8363 }
8364
8365 ADD_LABEL(ret, break_label); /* break */
8366
8367 if (popped) {
8368 ADD_INSN(ret, line_node, pop);
8369 }
8370
8371 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8372 break_label);
8373 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8374 next_catch_label);
8375 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8376 ISEQ_COMPILE_DATA(iseq)->redo_label);
8377
8378 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8379 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8380 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8381 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8382 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8383 return COMPILE_OK;
8384}
8385
8386static int
8387compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8388{
8389 const int line = nd_line(node);
8390 const NODE *line_node = node;
8391 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8392 LABEL *retry_label = NEW_LABEL(line);
8393 LABEL *retry_end_l = NEW_LABEL(line);
8394 const rb_iseq_t *child_iseq;
8395
8396 ADD_LABEL(ret, retry_label);
8397 if (nd_type_p(node, NODE_FOR)) {
8398 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8399
8400 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8401 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8402 ISEQ_TYPE_BLOCK, line);
8403 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8404 }
8405 else {
8406 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8407 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8408 ISEQ_TYPE_BLOCK, line);
8409 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8410 }
8411
8412 {
8413 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8414 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8415 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8416 //
8417 // Normally, "send" instruction is at the last.
8418 // However, qcall under branch coverage measurement adds some instructions after the "send".
8419 //
8420 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8421 INSN *iobj;
8422 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8423 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8424 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8425 iobj = (INSN*) get_prev_insn(iobj);
8426 }
8427 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8428
8429 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8430 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8431 if (&iobj->link == LAST_ELEMENT(ret)) {
8432 ret->last = (LINK_ELEMENT*) retry_end_l;
8433 }
8434 }
8435
8436 if (popped) {
8437 ADD_INSN(ret, line_node, pop);
8438 }
8439
8440 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8441
8442 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8443 return COMPILE_OK;
8444}
8445
8446static int
8447compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8448{
8449 /* massign to var in "for"
8450 * (args.length == 1 && Array.try_convert(args[0])) || args
8451 */
8452 const NODE *line_node = node;
8453 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8454 LABEL *not_single = NEW_LABEL(nd_line(var));
8455 LABEL *not_ary = NEW_LABEL(nd_line(var));
8456 CHECK(COMPILE(ret, "for var", var));
8457 ADD_INSN(ret, line_node, dup);
8458 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8459 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8460 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8461 ADD_INSNL(ret, line_node, branchunless, not_single);
8462 ADD_INSN(ret, line_node, dup);
8463 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8464 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8465 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8466 ADD_INSN(ret, line_node, swap);
8467 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8468 ADD_INSN(ret, line_node, dup);
8469 ADD_INSNL(ret, line_node, branchunless, not_ary);
8470 ADD_INSN(ret, line_node, swap);
8471 ADD_LABEL(ret, not_ary);
8472 ADD_INSN(ret, line_node, pop);
8473 ADD_LABEL(ret, not_single);
8474 return COMPILE_OK;
8475}
8476
8477static int
8478compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8479{
8480 const NODE *line_node = node;
8481 unsigned long throw_flag = 0;
8482
8483 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8484 /* while/until */
8485 LABEL *splabel = NEW_LABEL(0);
8486 ADD_LABEL(ret, splabel);
8487 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8488 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8489 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8490 add_ensure_iseq(ret, iseq, 0);
8491 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8492 ADD_ADJUST_RESTORE(ret, splabel);
8493
8494 if (!popped) {
8495 ADD_INSN(ret, line_node, putnil);
8496 }
8497 }
8498 else {
8499 const rb_iseq_t *ip = iseq;
8500
8501 while (ip) {
8502 if (!ISEQ_COMPILE_DATA(ip)) {
8503 ip = 0;
8504 break;
8505 }
8506
8507 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8508 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8509 }
8510 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8511 throw_flag = 0;
8512 }
8513 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8514 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8515 return COMPILE_NG;
8516 }
8517 else {
8518 ip = ISEQ_BODY(ip)->parent_iseq;
8519 continue;
8520 }
8521
8522 /* escape from block */
8523 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8524 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8525 if (popped) {
8526 ADD_INSN(ret, line_node, pop);
8527 }
8528 return COMPILE_OK;
8529 }
8530 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8531 return COMPILE_NG;
8532 }
8533 return COMPILE_OK;
8534}
8535
8536static int
8537compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8538{
8539 const NODE *line_node = node;
8540 unsigned long throw_flag = 0;
8541
8542 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8543 LABEL *splabel = NEW_LABEL(0);
8544 debugs("next in while loop\n");
8545 ADD_LABEL(ret, splabel);
8546 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8547 add_ensure_iseq(ret, iseq, 0);
8548 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8549 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8550 ADD_ADJUST_RESTORE(ret, splabel);
8551 if (!popped) {
8552 ADD_INSN(ret, line_node, putnil);
8553 }
8554 }
8555 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8556 LABEL *splabel = NEW_LABEL(0);
8557 debugs("next in block\n");
8558 ADD_LABEL(ret, splabel);
8559 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8560 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8561 add_ensure_iseq(ret, iseq, 0);
8562 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8563 ADD_ADJUST_RESTORE(ret, splabel);
8564
8565 if (!popped) {
8566 ADD_INSN(ret, line_node, putnil);
8567 }
8568 }
8569 else {
8570 const rb_iseq_t *ip = iseq;
8571
8572 while (ip) {
8573 if (!ISEQ_COMPILE_DATA(ip)) {
8574 ip = 0;
8575 break;
8576 }
8577
8578 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8579 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8580 /* while loop */
8581 break;
8582 }
8583 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8584 break;
8585 }
8586 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8587 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8588 return COMPILE_NG;
8589 }
8590
8591 ip = ISEQ_BODY(ip)->parent_iseq;
8592 }
8593 if (ip != 0) {
8594 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8595 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8596
8597 if (popped) {
8598 ADD_INSN(ret, line_node, pop);
8599 }
8600 }
8601 else {
8602 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8603 return COMPILE_NG;
8604 }
8605 }
8606 return COMPILE_OK;
8607}
8608
8609static int
8610compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8611{
8612 const NODE *line_node = node;
8613
8614 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8615 LABEL *splabel = NEW_LABEL(0);
8616 debugs("redo in while");
8617 ADD_LABEL(ret, splabel);
8618 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8619 add_ensure_iseq(ret, iseq, 0);
8620 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8621 ADD_ADJUST_RESTORE(ret, splabel);
8622 if (!popped) {
8623 ADD_INSN(ret, line_node, putnil);
8624 }
8625 }
8626 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8627 LABEL *splabel = NEW_LABEL(0);
8628
8629 debugs("redo in block");
8630 ADD_LABEL(ret, splabel);
8631 add_ensure_iseq(ret, iseq, 0);
8632 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8633 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8634 ADD_ADJUST_RESTORE(ret, splabel);
8635
8636 if (!popped) {
8637 ADD_INSN(ret, line_node, putnil);
8638 }
8639 }
8640 else {
8641 const rb_iseq_t *ip = iseq;
8642
8643 while (ip) {
8644 if (!ISEQ_COMPILE_DATA(ip)) {
8645 ip = 0;
8646 break;
8647 }
8648
8649 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8650 break;
8651 }
8652 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8653 break;
8654 }
8655 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8656 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8657 return COMPILE_NG;
8658 }
8659
8660 ip = ISEQ_BODY(ip)->parent_iseq;
8661 }
8662 if (ip != 0) {
8663 ADD_INSN(ret, line_node, putnil);
8664 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8665
8666 if (popped) {
8667 ADD_INSN(ret, line_node, pop);
8668 }
8669 }
8670 else {
8671 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8672 return COMPILE_NG;
8673 }
8674 }
8675 return COMPILE_OK;
8676}
8677
8678static int
8679compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8680{
8681 const NODE *line_node = node;
8682
8683 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8684 ADD_INSN(ret, line_node, putnil);
8685 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8686
8687 if (popped) {
8688 ADD_INSN(ret, line_node, pop);
8689 }
8690 }
8691 else {
8692 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8693 return COMPILE_NG;
8694 }
8695 return COMPILE_OK;
8696}
8697
8698static int
8699compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8700{
8701 const int line = nd_line(node);
8702 const NODE *line_node = node;
8703 LABEL *lstart = NEW_LABEL(line);
8704 LABEL *lend = NEW_LABEL(line);
8705 LABEL *lcont = NEW_LABEL(line);
8706 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8707 rb_str_concat(rb_str_new2("rescue in "),
8708 ISEQ_BODY(iseq)->location.label),
8709 ISEQ_TYPE_RESCUE, line);
8710
8711 lstart->rescued = LABEL_RESCUE_BEG;
8712 lend->rescued = LABEL_RESCUE_END;
8713 ADD_LABEL(ret, lstart);
8714
8715 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8716 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8717 {
8718 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8719 }
8720 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8721
8722 ADD_LABEL(ret, lend);
8723 if (RNODE_RESCUE(node)->nd_else) {
8724 ADD_INSN(ret, line_node, pop);
8725 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8726 }
8727 ADD_INSN(ret, line_node, nop);
8728 ADD_LABEL(ret, lcont);
8729
8730 if (popped) {
8731 ADD_INSN(ret, line_node, pop);
8732 }
8733
8734 /* register catch entry */
8735 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8736 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8737 return COMPILE_OK;
8738}
8739
8740static int
8741compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8742{
8743 const int line = nd_line(node);
8744 const NODE *line_node = node;
8745 const NODE *resq = node;
8746 const NODE *narg;
8747 LABEL *label_miss, *label_hit;
8748
8749 while (resq) {
8750 label_miss = NEW_LABEL(line);
8751 label_hit = NEW_LABEL(line);
8752
8753 narg = RNODE_RESBODY(resq)->nd_args;
8754 if (narg) {
8755 switch (nd_type(narg)) {
8756 case NODE_LIST:
8757 while (narg) {
8758 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8759 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8760 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8761 ADD_INSNL(ret, line_node, branchif, label_hit);
8762 narg = RNODE_LIST(narg)->nd_next;
8763 }
8764 break;
8765 case NODE_SPLAT:
8766 case NODE_ARGSCAT:
8767 case NODE_ARGSPUSH:
8768 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8769 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8770 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8771 ADD_INSNL(ret, line_node, branchif, label_hit);
8772 break;
8773 default:
8774 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8775 }
8776 }
8777 else {
8778 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8779 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8780 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8781 ADD_INSNL(ret, line_node, branchif, label_hit);
8782 }
8783 ADD_INSNL(ret, line_node, jump, label_miss);
8784 ADD_LABEL(ret, label_hit);
8785 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8786
8787 if (RNODE_RESBODY(resq)->nd_exc_var) {
8788 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8789 }
8790
8791 if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL && !RNODE_RESBODY(resq)->nd_exc_var) {
8792 // empty body
8793 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8794 }
8795 else {
8796 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8797 }
8798
8799 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8800 ADD_INSN(ret, line_node, nop);
8801 }
8802 ADD_INSN(ret, line_node, leave);
8803 ADD_LABEL(ret, label_miss);
8804 resq = RNODE_RESBODY(resq)->nd_next;
8805 }
8806 return COMPILE_OK;
8807}
8808
8809static int
8810compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8811{
8812 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8813 const NODE *line_node = node;
8814 DECL_ANCHOR(ensr);
8815 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8816 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8817 ISEQ_TYPE_ENSURE, line);
8818 LABEL *lstart = NEW_LABEL(line);
8819 LABEL *lend = NEW_LABEL(line);
8820 LABEL *lcont = NEW_LABEL(line);
8821 LINK_ELEMENT *last;
8822 int last_leave = 0;
8823 struct ensure_range er;
8825 struct ensure_range *erange;
8826
8827 INIT_ANCHOR(ensr);
8828 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8829 last = ensr->last;
8830 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8831
8832 er.begin = lstart;
8833 er.end = lend;
8834 er.next = 0;
8835 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8836
8837 ADD_LABEL(ret, lstart);
8838 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8839 ADD_LABEL(ret, lend);
8840 ADD_SEQ(ret, ensr);
8841 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8842 ADD_LABEL(ret, lcont);
8843 if (last_leave) ADD_INSN(ret, line_node, pop);
8844
8845 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8846 if (lstart->link.next != &lend->link) {
8847 while (erange) {
8848 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8849 ensure, lcont);
8850 erange = erange->next;
8851 }
8852 }
8853
8854 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8855 return COMPILE_OK;
8856}
8857
8858static int
8859compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8860{
8861 const NODE *line_node = node;
8862
8863 if (iseq) {
8864 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8865 const rb_iseq_t *is = iseq;
8866 enum rb_iseq_type t = type;
8867 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8868 LABEL *splabel = 0;
8869
8870 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8871 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8872 t = ISEQ_BODY(is)->type;
8873 }
8874 switch (t) {
8875 case ISEQ_TYPE_TOP:
8876 case ISEQ_TYPE_MAIN:
8877 if (retval) {
8878 rb_warn("argument of top-level return is ignored");
8879 }
8880 if (is == iseq) {
8881 /* plain top-level, leave directly */
8882 type = ISEQ_TYPE_METHOD;
8883 }
8884 break;
8885 default:
8886 break;
8887 }
8888
8889 if (type == ISEQ_TYPE_METHOD) {
8890 splabel = NEW_LABEL(0);
8891 ADD_LABEL(ret, splabel);
8892 ADD_ADJUST(ret, line_node, 0);
8893 }
8894
8895 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8896
8897 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8898 add_ensure_iseq(ret, iseq, 1);
8899 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8900 ADD_INSN(ret, line_node, leave);
8901 ADD_ADJUST_RESTORE(ret, splabel);
8902
8903 if (!popped) {
8904 ADD_INSN(ret, line_node, putnil);
8905 }
8906 }
8907 else {
8908 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8909 if (popped) {
8910 ADD_INSN(ret, line_node, pop);
8911 }
8912 }
8913 }
8914 return COMPILE_OK;
8915}
8916
8917static bool
8918drop_unreachable_return(LINK_ANCHOR *ret)
8919{
8920 LINK_ELEMENT *i = ret->last, *last;
8921 if (!i) return false;
8922 if (IS_TRACE(i)) i = i->prev;
8923 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8924 last = i = i->prev;
8925 if (IS_ADJUST(i)) i = i->prev;
8926 if (!IS_INSN(i)) return false;
8927 switch (INSN_OF(i)) {
8928 case BIN(leave):
8929 case BIN(jump):
8930 break;
8931 default:
8932 return false;
8933 }
8934 (ret->last = last->prev)->next = NULL;
8935 return true;
8936}
8937
8938static int
8939compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8940{
8941 CHECK(COMPILE_(ret, "nd_body", node, popped));
8942
8943 if (!popped && !all_string_result_p(node)) {
8944 const NODE *line_node = node;
8945 const unsigned int flag = VM_CALL_FCALL;
8946
8947 // Note, this dup could be removed if we are willing to change anytostring. It pops
8948 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8949 ADD_INSN(ret, line_node, dup);
8950 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8951 ADD_INSN(ret, line_node, anytostring);
8952 }
8953 return COMPILE_OK;
8954}
8955
8956static void
8957compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8958{
8959 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8960
8961 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8962 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8963}
8964
8965static LABEL *
8966qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8967{
8968 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8969 VALUE br = 0;
8970
8971 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8972 *branches = br;
8973 ADD_INSN(recv, line_node, dup);
8974 ADD_INSNL(recv, line_node, branchnil, else_label);
8975 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8976 return else_label;
8977}
8978
8979static void
8980qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8981{
8982 LABEL *end_label;
8983 if (!else_label) return;
8984 end_label = NEW_LABEL(nd_line(line_node));
8985 ADD_INSNL(ret, line_node, jump, end_label);
8986 ADD_LABEL(ret, else_label);
8987 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8988 ADD_LABEL(ret, end_label);
8989}
8990
8991static int
8992compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8993{
8994 /* optimization shortcut
8995 * "literal".freeze -> opt_str_freeze("literal")
8996 */
8997 if (get_nd_recv(node) &&
8998 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8999 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9000 get_nd_args(node) == NULL &&
9001 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9002 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9003 VALUE str = get_string_value(get_nd_recv(node));
9004 if (get_node_call_nd_mid(node) == idUMinus) {
9005 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9006 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9007 }
9008 else {
9009 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9010 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9011 }
9012 RB_OBJ_WRITTEN(iseq, Qundef, str);
9013 if (popped) {
9014 ADD_INSN(ret, line_node, pop);
9015 }
9016 return TRUE;
9017 }
9018 return FALSE;
9019}
9020
9021static int
9022iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9023{
9024 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9025}
9026
9027static const struct rb_builtin_function *
9028iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9029{
9030 int i;
9031 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9032 for (i=0; table[i].index != -1; i++) {
9033 if (strcmp(table[i].name, name) == 0) {
9034 return &table[i];
9035 }
9036 }
9037 return NULL;
9038}
9039
9040static const char *
9041iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9042{
9043 const char *name = rb_id2name(mid);
9044 static const char prefix[] = "__builtin_";
9045 const size_t prefix_len = sizeof(prefix) - 1;
9046
9047 switch (type) {
9048 case NODE_CALL:
9049 if (recv) {
9050 switch (nd_type(recv)) {
9051 case NODE_VCALL:
9052 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9053 return name;
9054 }
9055 break;
9056 case NODE_CONST:
9057 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9058 return name;
9059 }
9060 break;
9061 default: break;
9062 }
9063 }
9064 break;
9065 case NODE_VCALL:
9066 case NODE_FCALL:
9067 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9068 return &name[prefix_len];
9069 }
9070 break;
9071 default: break;
9072 }
9073 return NULL;
9074}
9075
9076static int
9077delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9078{
9079
9080 if (argc == 0) {
9081 *pstart_index = 0;
9082 return TRUE;
9083 }
9084 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9085 unsigned int start=0;
9086
9087 // local_table: [p1, p2, p3, l1, l2, l3]
9088 // arguments: [p3, l1, l2] -> 2
9089 for (start = 0;
9090 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9091 start++) {
9092 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9093
9094 for (unsigned int i=start; i-start<argc; i++) {
9095 if (IS_INSN(elem) &&
9096 INSN_OF(elem) == BIN(getlocal)) {
9097 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9098 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9099
9100 if (local_level == 0) {
9101 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9102 if (0) { // for debug
9103 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9104 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9105 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9106 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9107 }
9108 if (i == index) {
9109 elem = elem->next;
9110 continue; /* for */
9111 }
9112 else {
9113 goto next;
9114 }
9115 }
9116 else {
9117 goto fail; // level != 0 is unsupported
9118 }
9119 }
9120 else {
9121 goto fail; // insn is not a getlocal
9122 }
9123 }
9124 goto success;
9125 next:;
9126 }
9127 fail:
9128 return FALSE;
9129 success:
9130 *pstart_index = start;
9131 return TRUE;
9132 }
9133 else {
9134 return FALSE;
9135 }
9136}
9137
9138// Compile Primitive.attr! :leaf, ...
9139static int
9140compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9141{
9142 VALUE symbol;
9143 VALUE string;
9144 if (!node) goto no_arg;
9145 while (node) {
9146 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9147 const NODE *next = RNODE_LIST(node)->nd_next;
9148
9149 node = RNODE_LIST(node)->nd_head;
9150 if (!node) goto no_arg;
9151 switch (nd_type(node)) {
9152 case NODE_SYM:
9153 symbol = rb_node_sym_string_val(node);
9154 break;
9155 default:
9156 goto bad_arg;
9157 }
9158
9159 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9160
9161 string = rb_sym2str(symbol);
9162 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9163 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9164 }
9165 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9166 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9167 }
9168 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9169 iseq_set_use_block(iseq);
9170 }
9171 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9172 // Let the iseq act like a C method in backtraces
9173 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9174 }
9175 else {
9176 goto unknown_arg;
9177 }
9178 node = next;
9179 }
9180 return COMPILE_OK;
9181 no_arg:
9182 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9183 return COMPILE_NG;
9184 non_symbol_arg:
9185 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9186 return COMPILE_NG;
9187 unknown_arg:
9188 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9189 return COMPILE_NG;
9190 bad_arg:
9191 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9192}
9193
9194static int
9195compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9196{
9197 VALUE name;
9198
9199 if (!node) goto no_arg;
9200 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9201 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9202 node = RNODE_LIST(node)->nd_head;
9203 if (!node) goto no_arg;
9204 switch (nd_type(node)) {
9205 case NODE_SYM:
9206 name = rb_node_sym_string_val(node);
9207 break;
9208 default:
9209 goto bad_arg;
9210 }
9211 if (!SYMBOL_P(name)) goto non_symbol_arg;
9212 if (!popped) {
9213 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9214 }
9215 return COMPILE_OK;
9216 no_arg:
9217 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9218 return COMPILE_NG;
9219 too_many_arg:
9220 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9221 return COMPILE_NG;
9222 non_symbol_arg:
9223 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9224 rb_builtin_class_name(name));
9225 return COMPILE_NG;
9226 bad_arg:
9227 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9228}
9229
9230static NODE *
9231mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9232{
9233 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9234 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9235 return RNODE_IF(node)->nd_body;
9236 }
9237 else {
9238 rb_bug("mandatory_node: can't find mandatory node");
9239 }
9240}
9241
9242static int
9243compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9244{
9245 // arguments
9246 struct rb_args_info args = {
9247 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9248 };
9249 rb_node_args_t args_node;
9250 rb_node_init(RNODE(&args_node), NODE_ARGS);
9251 args_node.nd_ainfo = args;
9252
9253 // local table without non-mandatory parameters
9254 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9255 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9256
9257 VALUE idtmp = 0;
9258 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9259 tbl->size = table_size;
9260
9261 int i;
9262
9263 // lead parameters
9264 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9265 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9266 }
9267 // local variables
9268 for (; i<table_size; i++) {
9269 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9270 }
9271
9272 rb_node_scope_t scope_node;
9273 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9274 scope_node.nd_tbl = tbl;
9275 scope_node.nd_body = mandatory_node(iseq, node);
9276 scope_node.nd_parent = NULL;
9277 scope_node.nd_args = &args_node;
9278
9279 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9280
9281 const rb_iseq_t *mandatory_only_iseq =
9282 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9283 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9284 nd_line(line_node), NULL, 0,
9285 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9286 ISEQ_BODY(iseq)->variable.script_lines);
9287 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9288
9289 ALLOCV_END(idtmp);
9290 return COMPILE_OK;
9291}
9292
9293static int
9294compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9295 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9296{
9297 NODE *args_node = get_nd_args(node);
9298
9299 if (parent_block != NULL) {
9300 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9301 return COMPILE_NG;
9302 }
9303 else {
9304# define BUILTIN_INLINE_PREFIX "_bi"
9305 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9306 bool cconst = false;
9307 retry:;
9308 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9309
9310 if (bf == NULL) {
9311 if (strcmp("cstmt!", builtin_func) == 0 ||
9312 strcmp("cexpr!", builtin_func) == 0) {
9313 // ok
9314 }
9315 else if (strcmp("cconst!", builtin_func) == 0) {
9316 cconst = true;
9317 }
9318 else if (strcmp("cinit!", builtin_func) == 0) {
9319 // ignore
9320 return COMPILE_OK;
9321 }
9322 else if (strcmp("attr!", builtin_func) == 0) {
9323 return compile_builtin_attr(iseq, args_node);
9324 }
9325 else if (strcmp("arg!", builtin_func) == 0) {
9326 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9327 }
9328 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9329 if (popped) {
9330 rb_bug("mandatory_only? should be in if condition");
9331 }
9332 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9333 rb_bug("mandatory_only? should be put on top");
9334 }
9335
9336 ADD_INSN1(ret, line_node, putobject, Qfalse);
9337 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9338 }
9339 else if (1) {
9340 rb_bug("can't find builtin function:%s", builtin_func);
9341 }
9342 else {
9343 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9344 return COMPILE_NG;
9345 }
9346
9347 int inline_index = nd_line(node);
9348 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9349 builtin_func = inline_func;
9350 args_node = NULL;
9351 goto retry;
9352 }
9353
9354 if (cconst) {
9355 typedef VALUE(*builtin_func0)(void *, VALUE);
9356 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9357 ADD_INSN1(ret, line_node, putobject, const_val);
9358 return COMPILE_OK;
9359 }
9360
9361 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9362
9363 unsigned int flag = 0;
9364 struct rb_callinfo_kwarg *keywords = NULL;
9365 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9366
9367 if (FIX2INT(argc) != bf->argc) {
9368 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9369 builtin_func, bf->argc, FIX2INT(argc));
9370 return COMPILE_NG;
9371 }
9372
9373 unsigned int start_index;
9374 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9375 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9376 }
9377 else {
9378 ADD_SEQ(ret, args);
9379 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9380 }
9381
9382 if (popped) ADD_INSN(ret, line_node, pop);
9383 return COMPILE_OK;
9384 }
9385}
9386
9387static int
9388compile_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)
9389{
9390 /* call: obj.method(...)
9391 * fcall: func(...)
9392 * vcall: func
9393 */
9394 DECL_ANCHOR(recv);
9395 DECL_ANCHOR(args);
9396 ID mid = get_node_call_nd_mid(node);
9397 VALUE argc;
9398 unsigned int flag = 0;
9399 struct rb_callinfo_kwarg *keywords = NULL;
9400 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9401 LABEL *else_label = NULL;
9402 VALUE branches = Qfalse;
9403
9404 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9405
9406 INIT_ANCHOR(recv);
9407 INIT_ANCHOR(args);
9408
9409#if OPT_SUPPORT_JOKE
9410 if (nd_type_p(node, NODE_VCALL)) {
9411 ID id_bitblt;
9412 ID id_answer;
9413
9414 CONST_ID(id_bitblt, "bitblt");
9415 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9416
9417 if (mid == id_bitblt) {
9418 ADD_INSN(ret, line_node, bitblt);
9419 return COMPILE_OK;
9420 }
9421 else if (mid == id_answer) {
9422 ADD_INSN(ret, line_node, answer);
9423 return COMPILE_OK;
9424 }
9425 }
9426 /* only joke */
9427 {
9428 ID goto_id;
9429 ID label_id;
9430
9431 CONST_ID(goto_id, "__goto__");
9432 CONST_ID(label_id, "__label__");
9433
9434 if (nd_type_p(node, NODE_FCALL) &&
9435 (mid == goto_id || mid == label_id)) {
9436 LABEL *label;
9437 st_data_t data;
9438 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9439 VALUE label_name;
9440
9441 if (!labels_table) {
9442 labels_table = st_init_numtable();
9443 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9444 }
9445 {
9446 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9447 return COMPILE_NG;
9448 }
9449
9450 if (mid == goto_id) {
9451 ADD_INSNL(ret, line_node, jump, label);
9452 }
9453 else {
9454 ADD_LABEL(ret, label);
9455 }
9456 return COMPILE_OK;
9457 }
9458 }
9459#endif
9460
9461 const char *builtin_func;
9462 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9463 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9464 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9465 }
9466
9467 /* receiver */
9468 if (!assume_receiver) {
9469 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9470 int idx, level;
9471
9472 if (mid == idCall &&
9473 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9474 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9475 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9476 }
9477 else if (private_recv_p(node)) {
9478 ADD_INSN(recv, node, putself);
9479 flag |= VM_CALL_FCALL;
9480 }
9481 else {
9482 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9483 }
9484
9485 if (type == NODE_QCALL) {
9486 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9487 }
9488 }
9489 else if (type == NODE_FCALL || type == NODE_VCALL) {
9490 ADD_CALL_RECEIVER(recv, line_node);
9491 }
9492 }
9493
9494 /* args */
9495 if (type != NODE_VCALL) {
9496 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9497 CHECK(!NIL_P(argc));
9498 }
9499 else {
9500 argc = INT2FIX(0);
9501 }
9502
9503 ADD_SEQ(ret, recv);
9504
9505 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9506 mid == rb_intern("new") &&
9507 parent_block == NULL &&
9508 !(flag & VM_CALL_ARGS_BLOCKARG);
9509
9510 if (inline_new) {
9511 ADD_INSN(ret, node, putnil);
9512 ADD_INSN(ret, node, swap);
9513 }
9514
9515 ADD_SEQ(ret, args);
9516
9517 debugp_param("call args argc", argc);
9518 debugp_param("call method", ID2SYM(mid));
9519
9520 switch ((int)type) {
9521 case NODE_VCALL:
9522 flag |= VM_CALL_VCALL;
9523 /* VCALL is funcall, so fall through */
9524 case NODE_FCALL:
9525 flag |= VM_CALL_FCALL;
9526 }
9527
9528 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9529 ADD_INSN(ret, line_node, splatkw);
9530 }
9531
9532 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9533 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9534
9535 if (inline_new) {
9536 // Jump unless the receiver uses the "basic" implementation of "new"
9537 VALUE ci;
9538 if (flag & VM_CALL_FORWARDING) {
9539 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9540 }
9541 else {
9542 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9543 }
9544 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9545 LABEL_REF(not_basic_new);
9546
9547 // optimized path
9548 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9549 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9550
9551 ADD_LABEL(ret, not_basic_new);
9552 // Fall back to normal send
9553 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9554 ADD_INSN(ret, line_node, swap);
9555
9556 ADD_LABEL(ret, not_basic_new_finish);
9557 ADD_INSN(ret, line_node, pop);
9558 }
9559 else {
9560 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9561 }
9562
9563 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9564 if (popped) {
9565 ADD_INSN(ret, line_node, pop);
9566 }
9567 return COMPILE_OK;
9568}
9569
9570static int
9571compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9572{
9573 const int line = nd_line(node);
9574 VALUE argc;
9575 unsigned int flag = 0;
9576 int asgnflag = 0;
9577 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9578
9579 /*
9580 * a[x] (op)= y
9581 *
9582 * nil # nil
9583 * eval a # nil a
9584 * eval x # nil a x
9585 * dupn 2 # nil a x a x
9586 * send :[] # nil a x a[x]
9587 * eval y # nil a x a[x] y
9588 * send op # nil a x ret
9589 * setn 3 # ret a x ret
9590 * send []= # ret ?
9591 * pop # ret
9592 */
9593
9594 /*
9595 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9596 * NODE_OP_ASGN nd_recv
9597 * nd_args->nd_head
9598 * nd_args->nd_body
9599 * nd_mid
9600 */
9601
9602 if (!popped) {
9603 ADD_INSN(ret, node, putnil);
9604 }
9605 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9606 CHECK(asgnflag != -1);
9607 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9608 case NODE_ZLIST:
9609 argc = INT2FIX(0);
9610 break;
9611 default:
9612 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9613 CHECK(!NIL_P(argc));
9614 }
9615 int dup_argn = FIX2INT(argc) + 1;
9616 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9617 flag |= asgnflag;
9618 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9619
9620 if (id == idOROP || id == idANDOP) {
9621 /* a[x] ||= y or a[x] &&= y
9622
9623 unless/if a[x]
9624 a[x]= y
9625 else
9626 nil
9627 end
9628 */
9629 LABEL *label = NEW_LABEL(line);
9630 LABEL *lfin = NEW_LABEL(line);
9631
9632 ADD_INSN(ret, node, dup);
9633 if (id == idOROP) {
9634 ADD_INSNL(ret, node, branchif, label);
9635 }
9636 else { /* idANDOP */
9637 ADD_INSNL(ret, node, branchunless, label);
9638 }
9639 ADD_INSN(ret, node, pop);
9640
9641 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9642 if (!popped) {
9643 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9644 }
9645 if (flag & VM_CALL_ARGS_SPLAT) {
9646 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9647 ADD_INSN(ret, node, swap);
9648 ADD_INSN1(ret, node, splatarray, Qtrue);
9649 ADD_INSN(ret, node, swap);
9650 flag |= VM_CALL_ARGS_SPLAT_MUT;
9651 }
9652 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9653 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9654 }
9655 else {
9656 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9657 }
9658 ADD_INSN(ret, node, pop);
9659 ADD_INSNL(ret, node, jump, lfin);
9660 ADD_LABEL(ret, label);
9661 if (!popped) {
9662 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9663 }
9664 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9665 ADD_LABEL(ret, lfin);
9666 }
9667 else {
9668 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9669 ADD_SEND(ret, node, id, INT2FIX(1));
9670 if (!popped) {
9671 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9672 }
9673 if (flag & VM_CALL_ARGS_SPLAT) {
9674 if (flag & VM_CALL_KW_SPLAT) {
9675 ADD_INSN1(ret, node, topn, INT2FIX(2));
9676 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9677 ADD_INSN1(ret, node, splatarray, Qtrue);
9678 flag |= VM_CALL_ARGS_SPLAT_MUT;
9679 }
9680 ADD_INSN(ret, node, swap);
9681 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9682 ADD_INSN1(ret, node, setn, INT2FIX(2));
9683 ADD_INSN(ret, node, pop);
9684 }
9685 else {
9686 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9687 ADD_INSN(ret, node, swap);
9688 ADD_INSN1(ret, node, splatarray, Qtrue);
9689 ADD_INSN(ret, node, swap);
9690 flag |= VM_CALL_ARGS_SPLAT_MUT;
9691 }
9692 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9693 }
9694 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9695 }
9696 else {
9697 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9698 }
9699 ADD_INSN(ret, node, pop);
9700 }
9701 return COMPILE_OK;
9702}
9703
9704static int
9705compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9706{
9707 const int line = nd_line(node);
9708 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9709 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9710 int asgnflag;
9711 LABEL *lfin = NEW_LABEL(line);
9712 LABEL *lcfin = NEW_LABEL(line);
9713 LABEL *lskip = 0;
9714 /*
9715 class C; attr_accessor :c; end
9716 r = C.new
9717 r.a &&= v # asgn2
9718
9719 eval r # r
9720 dup # r r
9721 eval r.a # r o
9722
9723 # or
9724 dup # r o o
9725 if lcfin # r o
9726 pop # r
9727 eval v # r v
9728 swap # v r
9729 topn 1 # v r v
9730 send a= # v ?
9731 jump lfin # v ?
9732
9733 lcfin: # r o
9734 swap # o r
9735
9736 lfin: # o ?
9737 pop # o
9738
9739 # or (popped)
9740 if lcfin # r
9741 eval v # r v
9742 send a= # ?
9743 jump lfin # ?
9744
9745 lcfin: # r
9746
9747 lfin: # ?
9748 pop #
9749
9750 # and
9751 dup # r o o
9752 unless lcfin
9753 pop # r
9754 eval v # r v
9755 swap # v r
9756 topn 1 # v r v
9757 send a= # v ?
9758 jump lfin # v ?
9759
9760 # others
9761 eval v # r o v
9762 send ?? # r w
9763 send a= # w
9764
9765 */
9766
9767 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9768 CHECK(asgnflag != -1);
9769 if (RNODE_OP_ASGN2(node)->nd_aid) {
9770 lskip = NEW_LABEL(line);
9771 ADD_INSN(ret, node, dup);
9772 ADD_INSNL(ret, node, branchnil, lskip);
9773 }
9774 ADD_INSN(ret, node, dup);
9775 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9776
9777 if (atype == idOROP || atype == idANDOP) {
9778 if (!popped) {
9779 ADD_INSN(ret, node, dup);
9780 }
9781 if (atype == idOROP) {
9782 ADD_INSNL(ret, node, branchif, lcfin);
9783 }
9784 else { /* idANDOP */
9785 ADD_INSNL(ret, node, branchunless, lcfin);
9786 }
9787 if (!popped) {
9788 ADD_INSN(ret, node, pop);
9789 }
9790 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9791 if (!popped) {
9792 ADD_INSN(ret, node, swap);
9793 ADD_INSN1(ret, node, topn, INT2FIX(1));
9794 }
9795 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9796 ADD_INSNL(ret, node, jump, lfin);
9797
9798 ADD_LABEL(ret, lcfin);
9799 if (!popped) {
9800 ADD_INSN(ret, node, swap);
9801 }
9802
9803 ADD_LABEL(ret, lfin);
9804 }
9805 else {
9806 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9807 ADD_SEND(ret, node, atype, INT2FIX(1));
9808 if (!popped) {
9809 ADD_INSN(ret, node, swap);
9810 ADD_INSN1(ret, node, topn, INT2FIX(1));
9811 }
9812 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9813 }
9814 if (lskip && popped) {
9815 ADD_LABEL(ret, lskip);
9816 }
9817 ADD_INSN(ret, node, pop);
9818 if (lskip && !popped) {
9819 ADD_LABEL(ret, lskip);
9820 }
9821 return COMPILE_OK;
9822}
9823
9824static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9825
9826static int
9827compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9828{
9829 const int line = nd_line(node);
9830 LABEL *lfin = 0;
9831 LABEL *lassign = 0;
9832 ID mid;
9833
9834 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9835 case NODE_COLON3:
9836 ADD_INSN1(ret, node, putobject, rb_cObject);
9837 break;
9838 case NODE_COLON2:
9839 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9840 break;
9841 default:
9842 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9843 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9844 return COMPILE_NG;
9845 }
9846 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9847 /* cref */
9848 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9849 lassign = NEW_LABEL(line);
9850 ADD_INSN(ret, node, dup); /* cref cref */
9851 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9852 ID2SYM(mid), Qtrue); /* cref bool */
9853 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9854 }
9855 ADD_INSN(ret, node, dup); /* cref cref */
9856 ADD_INSN1(ret, node, putobject, Qtrue);
9857 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9858
9859 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9860 lfin = NEW_LABEL(line);
9861 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9862 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9863 ADD_INSNL(ret, node, branchif, lfin);
9864 else /* idANDOP */
9865 ADD_INSNL(ret, node, branchunless, lfin);
9866 /* cref [obj] */
9867 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9868 if (lassign) ADD_LABEL(ret, lassign);
9869 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9870 /* cref value */
9871 if (popped)
9872 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9873 else {
9874 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9875 ADD_INSN(ret, node, swap); /* cref value value cref */
9876 }
9877 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9878 ADD_LABEL(ret, lfin); /* cref [value] */
9879 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9880 ADD_INSN(ret, node, pop); /* [value] */
9881 }
9882 else {
9883 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9884 /* cref obj value */
9885 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9886 /* cref value */
9887 ADD_INSN(ret, node, swap); /* value cref */
9888 if (!popped) {
9889 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9890 ADD_INSN(ret, node, swap); /* value value cref */
9891 }
9892 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9893 }
9894 return COMPILE_OK;
9895}
9896
9897static int
9898compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9899{
9900 const int line = nd_line(node);
9901 LABEL *lfin = NEW_LABEL(line);
9902 LABEL *lassign;
9903
9904 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9905 LABEL *lfinish[2];
9906 lfinish[0] = lfin;
9907 lfinish[1] = 0;
9908 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9909 lassign = lfinish[1];
9910 if (!lassign) {
9911 lassign = NEW_LABEL(line);
9912 }
9913 ADD_INSNL(ret, node, branchunless, lassign);
9914 }
9915 else {
9916 lassign = NEW_LABEL(line);
9917 }
9918
9919 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9920
9921 if (!popped) {
9922 ADD_INSN(ret, node, dup);
9923 }
9924
9925 if (type == NODE_OP_ASGN_AND) {
9926 ADD_INSNL(ret, node, branchunless, lfin);
9927 }
9928 else {
9929 ADD_INSNL(ret, node, branchif, lfin);
9930 }
9931
9932 if (!popped) {
9933 ADD_INSN(ret, node, pop);
9934 }
9935
9936 ADD_LABEL(ret, lassign);
9937 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9938 ADD_LABEL(ret, lfin);
9939 return COMPILE_OK;
9940}
9941
9942static int
9943compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9944{
9945 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9946 DECL_ANCHOR(args);
9947 int argc;
9948 unsigned int flag = 0;
9949 struct rb_callinfo_kwarg *keywords = NULL;
9950 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9951 int use_block = 1;
9952
9953 INIT_ANCHOR(args);
9954 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9955
9956 if (type == NODE_SUPER) {
9957 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9958 CHECK(!NIL_P(vargc));
9959 argc = FIX2INT(vargc);
9960 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9961 ADD_INSN(args, node, splatkw);
9962 }
9963
9964 if (flag & VM_CALL_ARGS_BLOCKARG) {
9965 use_block = 0;
9966 }
9967 }
9968 else {
9969 /* NODE_ZSUPER */
9970 int i;
9971 const rb_iseq_t *liseq = body->local_iseq;
9972 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9973 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9974 int lvar_level = get_lvar_level(iseq);
9975
9976 argc = local_body->param.lead_num;
9977
9978 /* normal arguments */
9979 for (i = 0; i < local_body->param.lead_num; i++) {
9980 int idx = local_body->local_table_size - i;
9981 ADD_GETLOCAL(args, node, idx, lvar_level);
9982 }
9983
9984 /* forward ... */
9985 if (local_body->param.flags.forwardable) {
9986 flag |= VM_CALL_FORWARDING;
9987 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9988 ADD_GETLOCAL(args, node, idx, lvar_level);
9989 }
9990
9991 if (local_body->param.flags.has_opt) {
9992 /* optional arguments */
9993 int j;
9994 for (j = 0; j < local_body->param.opt_num; j++) {
9995 int idx = local_body->local_table_size - (i + j);
9996 ADD_GETLOCAL(args, node, idx, lvar_level);
9997 }
9998 i += j;
9999 argc = i;
10000 }
10001 if (local_body->param.flags.has_rest) {
10002 /* rest argument */
10003 int idx = local_body->local_table_size - local_body->param.rest_start;
10004 ADD_GETLOCAL(args, node, idx, lvar_level);
10005 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10006
10007 argc = local_body->param.rest_start + 1;
10008 flag |= VM_CALL_ARGS_SPLAT;
10009 }
10010 if (local_body->param.flags.has_post) {
10011 /* post arguments */
10012 int post_len = local_body->param.post_num;
10013 int post_start = local_body->param.post_start;
10014
10015 if (local_body->param.flags.has_rest) {
10016 int j;
10017 for (j=0; j<post_len; j++) {
10018 int idx = local_body->local_table_size - (post_start + j);
10019 ADD_GETLOCAL(args, node, idx, lvar_level);
10020 }
10021 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10022 flag |= VM_CALL_ARGS_SPLAT_MUT;
10023 /* argc is settled at above */
10024 }
10025 else {
10026 int j;
10027 for (j=0; j<post_len; j++) {
10028 int idx = local_body->local_table_size - (post_start + j);
10029 ADD_GETLOCAL(args, node, idx, lvar_level);
10030 }
10031 argc = post_len + post_start;
10032 }
10033 }
10034
10035 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10036 int local_size = local_body->local_table_size;
10037 argc++;
10038
10039 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10040
10041 if (local_body->param.flags.has_kwrest) {
10042 int idx = local_body->local_table_size - local_kwd->rest_start;
10043 ADD_GETLOCAL(args, node, idx, lvar_level);
10044 RUBY_ASSERT(local_kwd->num > 0);
10045 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10046 }
10047 else {
10048 ADD_INSN1(args, node, newhash, INT2FIX(0));
10049 }
10050 for (i = 0; i < local_kwd->num; ++i) {
10051 ID id = local_kwd->table[i];
10052 int idx = local_size - get_local_var_idx(liseq, id);
10053 ADD_INSN1(args, node, putobject, ID2SYM(id));
10054 ADD_GETLOCAL(args, node, idx, lvar_level);
10055 }
10056 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10057 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10058 }
10059 else if (local_body->param.flags.has_kwrest) {
10060 int idx = local_body->local_table_size - local_kwd->rest_start;
10061 ADD_GETLOCAL(args, node, idx, lvar_level);
10062 argc++;
10063 flag |= VM_CALL_KW_SPLAT;
10064 }
10065 }
10066
10067 if (use_block && parent_block == NULL) {
10068 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10069 }
10070
10071 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10072 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10073 ADD_INSN(ret, node, putself);
10074 ADD_SEQ(ret, args);
10075
10076 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10077
10078 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10079 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10080 }
10081 else {
10082 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10083 }
10084
10085 if (popped) {
10086 ADD_INSN(ret, node, pop);
10087 }
10088 return COMPILE_OK;
10089}
10090
10091static int
10092compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10093{
10094 DECL_ANCHOR(args);
10095 VALUE argc;
10096 unsigned int flag = 0;
10097 struct rb_callinfo_kwarg *keywords = NULL;
10098
10099 INIT_ANCHOR(args);
10100
10101 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10102 case ISEQ_TYPE_TOP:
10103 case ISEQ_TYPE_MAIN:
10104 case ISEQ_TYPE_CLASS:
10105 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10106 return COMPILE_NG;
10107 default: /* valid */;
10108 }
10109
10110 if (RNODE_YIELD(node)->nd_head) {
10111 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10112 CHECK(!NIL_P(argc));
10113 }
10114 else {
10115 argc = INT2FIX(0);
10116 }
10117
10118 ADD_SEQ(ret, args);
10119 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10120 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10121
10122 if (popped) {
10123 ADD_INSN(ret, node, pop);
10124 }
10125
10126 int level = 0;
10127 const rb_iseq_t *tmp_iseq = iseq;
10128 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10129 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10130 }
10131 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10132
10133 return COMPILE_OK;
10134}
10135
10136static int
10137compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10138{
10139 DECL_ANCHOR(recv);
10140 DECL_ANCHOR(val);
10141
10142 INIT_ANCHOR(recv);
10143 INIT_ANCHOR(val);
10144 switch ((int)type) {
10145 case NODE_MATCH:
10146 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10147 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10148 INT2FIX(0));
10149 break;
10150 case NODE_MATCH2:
10151 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10152 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10153 break;
10154 case NODE_MATCH3:
10155 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10156 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10157 break;
10158 }
10159
10160 ADD_SEQ(ret, recv);
10161 ADD_SEQ(ret, val);
10162 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10163
10164 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10165 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10166 }
10167
10168 if (popped) {
10169 ADD_INSN(ret, node, pop);
10170 }
10171 return COMPILE_OK;
10172}
10173
10174static int
10175compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10176{
10177 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10178 /* constant */
10179 VALUE segments;
10180 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10181 (segments = collect_const_segments(iseq, node))) {
10182 ISEQ_BODY(iseq)->ic_size++;
10183 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10184 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10185 }
10186 else {
10187 /* constant */
10188 DECL_ANCHOR(pref);
10189 DECL_ANCHOR(body);
10190
10191 INIT_ANCHOR(pref);
10192 INIT_ANCHOR(body);
10193 CHECK(compile_const_prefix(iseq, node, pref, body));
10194 if (LIST_INSN_SIZE_ZERO(pref)) {
10195 ADD_INSN(ret, node, putnil);
10196 ADD_SEQ(ret, body);
10197 }
10198 else {
10199 ADD_SEQ(ret, pref);
10200 ADD_SEQ(ret, body);
10201 }
10202 }
10203 }
10204 else {
10205 /* function call */
10206 ADD_CALL_RECEIVER(ret, node);
10207 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10208 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10209 }
10210 if (popped) {
10211 ADD_INSN(ret, node, pop);
10212 }
10213 return COMPILE_OK;
10214}
10215
10216static int
10217compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10218{
10219 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10220
10221 /* add cache insn */
10222 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10223 ISEQ_BODY(iseq)->ic_size++;
10224 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10225 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10226 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10227 }
10228 else {
10229 ADD_INSN1(ret, node, putobject, rb_cObject);
10230 ADD_INSN1(ret, node, putobject, Qtrue);
10231 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10232 }
10233
10234 if (popped) {
10235 ADD_INSN(ret, node, pop);
10236 }
10237 return COMPILE_OK;
10238}
10239
10240static int
10241compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10242{
10243 VALUE flag = INT2FIX(excl);
10244 const NODE *b = RNODE_DOT2(node)->nd_beg;
10245 const NODE *e = RNODE_DOT2(node)->nd_end;
10246
10247 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10248 if (!popped) {
10249 VALUE bv = optimized_range_item(b);
10250 VALUE ev = optimized_range_item(e);
10251 VALUE val = rb_range_new(bv, ev, excl);
10252 ADD_INSN1(ret, node, putobject, val);
10253 RB_OBJ_WRITTEN(iseq, Qundef, val);
10254 }
10255 }
10256 else {
10257 CHECK(COMPILE_(ret, "min", b, popped));
10258 CHECK(COMPILE_(ret, "max", e, popped));
10259 if (!popped) {
10260 ADD_INSN1(ret, node, newrange, flag);
10261 }
10262 }
10263 return COMPILE_OK;
10264}
10265
10266static int
10267compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10268{
10269 if (!popped) {
10270 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10271 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10272 }
10273 else {
10274 const rb_iseq_t *ip = iseq;
10275 int level = 0;
10276 while (ip) {
10277 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10278 break;
10279 }
10280 ip = ISEQ_BODY(ip)->parent_iseq;
10281 level++;
10282 }
10283 if (ip) {
10284 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10285 }
10286 else {
10287 ADD_INSN(ret, node, putnil);
10288 }
10289 }
10290 }
10291 return COMPILE_OK;
10292}
10293
10294static int
10295compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10296{
10297 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10298 LABEL *end_label = NEW_LABEL(nd_line(node));
10299 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10300
10301 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10302 /* required argument. do nothing */
10303 COMPILE_ERROR(ERROR_ARGS "unreachable");
10304 return COMPILE_NG;
10305 }
10306 else if (nd_type_p(default_value, NODE_SYM) ||
10307 nd_type_p(default_value, NODE_REGX) ||
10308 nd_type_p(default_value, NODE_LINE) ||
10309 nd_type_p(default_value, NODE_INTEGER) ||
10310 nd_type_p(default_value, NODE_FLOAT) ||
10311 nd_type_p(default_value, NODE_RATIONAL) ||
10312 nd_type_p(default_value, NODE_IMAGINARY) ||
10313 nd_type_p(default_value, NODE_NIL) ||
10314 nd_type_p(default_value, NODE_TRUE) ||
10315 nd_type_p(default_value, NODE_FALSE)) {
10316 COMPILE_ERROR(ERROR_ARGS "unreachable");
10317 return COMPILE_NG;
10318 }
10319 else {
10320 /* if keywordcheck(_kw_bits, nth_keyword)
10321 * kw = default_value
10322 * end
10323 */
10324 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10325 int keyword_idx = body->param.keyword->num;
10326
10327 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10328 ADD_INSNL(ret, node, branchif, end_label);
10329 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10330 ADD_LABEL(ret, end_label);
10331 }
10332 return COMPILE_OK;
10333}
10334
10335static int
10336compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10337{
10338 DECL_ANCHOR(recv);
10339 DECL_ANCHOR(args);
10340 unsigned int flag = 0;
10341 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10342 VALUE argc;
10343 LABEL *else_label = NULL;
10344 VALUE branches = Qfalse;
10345
10346 INIT_ANCHOR(recv);
10347 INIT_ANCHOR(args);
10348 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10349 CHECK(!NIL_P(argc));
10350
10351 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10352 CHECK(asgnflag != -1);
10353 flag |= (unsigned int)asgnflag;
10354
10355 debugp_param("argc", argc);
10356 debugp_param("nd_mid", ID2SYM(mid));
10357
10358 if (!rb_is_attrset_id(mid)) {
10359 /* safe nav attr */
10360 mid = rb_id_attrset(mid);
10361 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10362 }
10363 if (!popped) {
10364 ADD_INSN(ret, node, putnil);
10365 ADD_SEQ(ret, recv);
10366 ADD_SEQ(ret, args);
10367
10368 if (flag & VM_CALL_ARGS_SPLAT) {
10369 ADD_INSN(ret, node, dup);
10370 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10371 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10372 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10373 ADD_INSN (ret, node, pop);
10374 }
10375 else {
10376 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10377 }
10378 }
10379 else {
10380 ADD_SEQ(ret, recv);
10381 ADD_SEQ(ret, args);
10382 }
10383 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10384 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10385 ADD_INSN(ret, node, pop);
10386 return COMPILE_OK;
10387}
10388
10389static int
10390compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10391{
10392 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10393 ADD_SEQ(ret, sub);
10394
10395 if (copy) {
10396 /*
10397 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10398 * NEW_LIST(value, loc), loc);
10399 */
10400 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10401 }
10402 else {
10403 /*
10404 * NEW_CALL(fcore, rb_intern("make_shareable"),
10405 * NEW_LIST(value, loc), loc);
10406 */
10407 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10408 }
10409
10410 return COMPILE_OK;
10411}
10412
10413static VALUE
10414node_const_decl_val(const NODE *node)
10415{
10416 VALUE path;
10417 switch (nd_type(node)) {
10418 case NODE_CDECL:
10419 if (RNODE_CDECL(node)->nd_vid) {
10420 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10421 goto end;
10422 }
10423 else {
10424 node = RNODE_CDECL(node)->nd_else;
10425 }
10426 break;
10427 case NODE_COLON2:
10428 break;
10429 case NODE_COLON3:
10430 // ::Const
10431 path = rb_str_new_cstr("::");
10432 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10433 goto end;
10434 default:
10435 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10437 }
10438
10439 path = rb_ary_new();
10440 if (node) {
10441 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10442 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10443 }
10444 if (node && nd_type_p(node, NODE_CONST)) {
10445 // Const::Name
10446 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10447 }
10448 else if (node && nd_type_p(node, NODE_COLON3)) {
10449 // ::Const::Name
10450 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10451 rb_ary_push(path, rb_str_new(0, 0));
10452 }
10453 else {
10454 // expression::Name
10455 rb_ary_push(path, rb_str_new_cstr("..."));
10456 }
10457 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10458 }
10459 end:
10460 path = rb_fstring(path);
10461 return path;
10462}
10463
10464static VALUE
10465const_decl_path(NODE *dest)
10466{
10467 VALUE path = Qnil;
10468 if (!nd_type_p(dest, NODE_CALL)) {
10469 path = node_const_decl_val(dest);
10470 }
10471 return path;
10472}
10473
10474static int
10475compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10476{
10477 /*
10478 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10479 */
10480 VALUE path = const_decl_path(dest);
10481 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10482 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10483 ADD_INSN1(ret, value, putobject, path);
10484 RB_OBJ_WRITTEN(iseq, Qundef, path);
10485 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10486
10487 return COMPILE_OK;
10488}
10489
10490#ifndef SHAREABLE_BARE_EXPRESSION
10491#define SHAREABLE_BARE_EXPRESSION 1
10492#endif
10493
10494static int
10495compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, NODE *dest, const NODE *node, size_t level, VALUE *value_p, int *shareable_literal_p)
10496{
10497# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10498 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10499 VALUE lit = Qnil;
10500 DECL_ANCHOR(anchor);
10501
10502 enum node_type type = node ? nd_type(node) : NODE_NIL;
10503 switch (type) {
10504 case NODE_TRUE:
10505 *value_p = Qtrue;
10506 goto compile;
10507 case NODE_FALSE:
10508 *value_p = Qfalse;
10509 goto compile;
10510 case NODE_NIL:
10511 *value_p = Qnil;
10512 goto compile;
10513 case NODE_SYM:
10514 *value_p = rb_node_sym_string_val(node);
10515 goto compile;
10516 case NODE_REGX:
10517 *value_p = rb_node_regx_string_val(node);
10518 goto compile;
10519 case NODE_LINE:
10520 *value_p = rb_node_line_lineno_val(node);
10521 goto compile;
10522 case NODE_INTEGER:
10523 *value_p = rb_node_integer_literal_val(node);
10524 goto compile;
10525 case NODE_FLOAT:
10526 *value_p = rb_node_float_literal_val(node);
10527 goto compile;
10528 case NODE_RATIONAL:
10529 *value_p = rb_node_rational_literal_val(node);
10530 goto compile;
10531 case NODE_IMAGINARY:
10532 *value_p = rb_node_imaginary_literal_val(node);
10533 goto compile;
10534 case NODE_ENCODING:
10535 *value_p = rb_node_encoding_val(node);
10536
10537 compile:
10538 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10539 *shareable_literal_p = 1;
10540 return COMPILE_OK;
10541
10542 case NODE_DSTR:
10543 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10544 if (shareable == rb_parser_shareable_literal) {
10545 /*
10546 * NEW_CALL(node, idUMinus, 0, loc);
10547 *
10548 * -"#{var}"
10549 */
10550 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10551 }
10552 *value_p = Qundef;
10553 *shareable_literal_p = 1;
10554 return COMPILE_OK;
10555
10556 case NODE_STR:{
10557 VALUE lit = rb_node_str_string_val(node);
10558 ADD_INSN1(ret, node, putobject, lit);
10559 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10560 *value_p = lit;
10561 *shareable_literal_p = 1;
10562
10563 return COMPILE_OK;
10564 }
10565
10566 case NODE_FILE:{
10567 VALUE lit = rb_node_file_path_val(node);
10568 ADD_INSN1(ret, node, putobject, lit);
10569 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10570 *value_p = lit;
10571 *shareable_literal_p = 1;
10572
10573 return COMPILE_OK;
10574 }
10575
10576 case NODE_ZLIST:{
10577 VALUE lit = rb_ary_new();
10578 OBJ_FREEZE(lit);
10579 ADD_INSN1(ret, node, putobject, lit);
10580 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10581 *value_p = lit;
10582 *shareable_literal_p = 1;
10583
10584 return COMPILE_OK;
10585 }
10586
10587 case NODE_LIST:{
10588 INIT_ANCHOR(anchor);
10589 lit = rb_ary_new();
10590 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10591 VALUE val;
10592 int shareable_literal_p2;
10593 NODE *elt = RNODE_LIST(n)->nd_head;
10594 if (elt) {
10595 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10596 if (shareable_literal_p2) {
10597 /* noop */
10598 }
10599 else if (RTEST(lit)) {
10600 rb_ary_clear(lit);
10601 lit = Qfalse;
10602 }
10603 }
10604 if (RTEST(lit)) {
10605 if (!UNDEF_P(val)) {
10606 rb_ary_push(lit, val);
10607 }
10608 else {
10609 rb_ary_clear(lit);
10610 lit = Qnil; /* make shareable at runtime */
10611 }
10612 }
10613 }
10614 break;
10615 }
10616 case NODE_HASH:{
10617 if (!RNODE_HASH(node)->nd_brace) {
10618 *value_p = Qundef;
10619 *shareable_literal_p = 0;
10620 return COMPILE_OK;
10621 }
10622 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10623 if (!RNODE_LIST(n)->nd_head) {
10624 // If the hash node have a keyword splat, fall back to the default case.
10625 goto compile_shareable;
10626 }
10627 }
10628
10629 INIT_ANCHOR(anchor);
10630 lit = rb_hash_new();
10631 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10632 VALUE key_val = 0;
10633 VALUE value_val = 0;
10634 int shareable_literal_p2;
10635 NODE *key = RNODE_LIST(n)->nd_head;
10636 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10637 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10638 if (shareable_literal_p2) {
10639 /* noop */
10640 }
10641 else if (RTEST(lit)) {
10642 rb_hash_clear(lit);
10643 lit = Qfalse;
10644 }
10645 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10646 if (shareable_literal_p2) {
10647 /* noop */
10648 }
10649 else if (RTEST(lit)) {
10650 rb_hash_clear(lit);
10651 lit = Qfalse;
10652 }
10653 if (RTEST(lit)) {
10654 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10655 rb_hash_aset(lit, key_val, value_val);
10656 }
10657 else {
10658 rb_hash_clear(lit);
10659 lit = Qnil; /* make shareable at runtime */
10660 }
10661 }
10662 }
10663 break;
10664 }
10665
10666 default:
10667
10668 compile_shareable:
10669 if (shareable == rb_parser_shareable_literal &&
10670 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10671 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10672 *value_p = Qundef;
10673 *shareable_literal_p = 1;
10674 return COMPILE_OK;
10675 }
10676 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10677 *value_p = Qundef;
10678 *shareable_literal_p = 0;
10679 return COMPILE_OK;
10680 }
10681
10682 /* Array or Hash that does not have keyword splat */
10683 if (!lit) {
10684 if (nd_type(node) == NODE_LIST) {
10685 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10686 }
10687 else if (nd_type(node) == NODE_HASH) {
10688 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10689 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10690 }
10691 *value_p = Qundef;
10692 *shareable_literal_p = 0;
10693 ADD_SEQ(ret, anchor);
10694 return COMPILE_OK;
10695 }
10696 if (NIL_P(lit)) {
10697 // if shareable_literal, all elements should have been ensured
10698 // as shareable
10699 if (nd_type(node) == NODE_LIST) {
10700 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10701 }
10702 else if (nd_type(node) == NODE_HASH) {
10703 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10704 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10705 }
10706 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10707 *value_p = Qundef;
10708 *shareable_literal_p = 1;
10709 }
10710 else {
10712 ADD_INSN1(ret, node, putobject, val);
10713 RB_OBJ_WRITTEN(iseq, Qundef, val);
10714 *value_p = val;
10715 *shareable_literal_p = 1;
10716 }
10717
10718 return COMPILE_OK;
10719}
10720
10721static int
10722compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10723{
10724 int literal_p = 0;
10725 VALUE val;
10726 DECL_ANCHOR(anchor);
10727 INIT_ANCHOR(anchor);
10728
10729 switch (shareable) {
10730 case rb_parser_shareable_none:
10731 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10732 return COMPILE_OK;
10733
10734 case rb_parser_shareable_literal:
10735 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10736 ADD_SEQ(ret, anchor);
10737 return COMPILE_OK;
10738
10739 case rb_parser_shareable_copy:
10740 case rb_parser_shareable_everything:
10741 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10742 if (!literal_p) {
10743 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10744 }
10745 else {
10746 ADD_SEQ(ret, anchor);
10747 }
10748 return COMPILE_OK;
10749 default:
10750 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10751 }
10752}
10753
10754static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10762static int
10763iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10764{
10765 if (node == 0) {
10766 if (!popped) {
10767 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10768 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10769 debugs("node: NODE_NIL(implicit)\n");
10770 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10771 }
10772 return COMPILE_OK;
10773 }
10774 return iseq_compile_each0(iseq, ret, node, popped);
10775}
10776
10777static int
10778iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10779{
10780 const int line = (int)nd_line(node);
10781 const enum node_type type = nd_type(node);
10782 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10783
10784 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10785 /* ignore */
10786 }
10787 else {
10788 if (nd_fl_newline(node)) {
10789 int event = RUBY_EVENT_LINE;
10790 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10791 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10792 event |= RUBY_EVENT_COVERAGE_LINE;
10793 }
10794 ADD_TRACE(ret, event);
10795 }
10796 }
10797
10798 debug_node_start(node);
10799#undef BEFORE_RETURN
10800#define BEFORE_RETURN debug_node_end()
10801
10802 switch (type) {
10803 case NODE_BLOCK:
10804 CHECK(compile_block(iseq, ret, node, popped));
10805 break;
10806 case NODE_IF:
10807 case NODE_UNLESS:
10808 CHECK(compile_if(iseq, ret, node, popped, type));
10809 break;
10810 case NODE_CASE:
10811 CHECK(compile_case(iseq, ret, node, popped));
10812 break;
10813 case NODE_CASE2:
10814 CHECK(compile_case2(iseq, ret, node, popped));
10815 break;
10816 case NODE_CASE3:
10817 CHECK(compile_case3(iseq, ret, node, popped));
10818 break;
10819 case NODE_WHILE:
10820 case NODE_UNTIL:
10821 CHECK(compile_loop(iseq, ret, node, popped, type));
10822 break;
10823 case NODE_FOR:
10824 case NODE_ITER:
10825 CHECK(compile_iter(iseq, ret, node, popped));
10826 break;
10827 case NODE_FOR_MASGN:
10828 CHECK(compile_for_masgn(iseq, ret, node, popped));
10829 break;
10830 case NODE_BREAK:
10831 CHECK(compile_break(iseq, ret, node, popped));
10832 break;
10833 case NODE_NEXT:
10834 CHECK(compile_next(iseq, ret, node, popped));
10835 break;
10836 case NODE_REDO:
10837 CHECK(compile_redo(iseq, ret, node, popped));
10838 break;
10839 case NODE_RETRY:
10840 CHECK(compile_retry(iseq, ret, node, popped));
10841 break;
10842 case NODE_BEGIN:{
10843 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10844 break;
10845 }
10846 case NODE_RESCUE:
10847 CHECK(compile_rescue(iseq, ret, node, popped));
10848 break;
10849 case NODE_RESBODY:
10850 CHECK(compile_resbody(iseq, ret, node, popped));
10851 break;
10852 case NODE_ENSURE:
10853 CHECK(compile_ensure(iseq, ret, node, popped));
10854 break;
10855
10856 case NODE_AND:
10857 case NODE_OR:{
10858 LABEL *end_label = NEW_LABEL(line);
10859 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10860 if (!popped) {
10861 ADD_INSN(ret, node, dup);
10862 }
10863 if (type == NODE_AND) {
10864 ADD_INSNL(ret, node, branchunless, end_label);
10865 }
10866 else {
10867 ADD_INSNL(ret, node, branchif, end_label);
10868 }
10869 if (!popped) {
10870 ADD_INSN(ret, node, pop);
10871 }
10872 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10873 ADD_LABEL(ret, end_label);
10874 break;
10875 }
10876
10877 case NODE_MASGN:{
10878 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10879 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10880 compile_massign(iseq, ret, node, popped);
10881 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10882 break;
10883 }
10884
10885 case NODE_LASGN:{
10886 ID id = RNODE_LASGN(node)->nd_vid;
10887 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10888
10889 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10890 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10891
10892 if (!popped) {
10893 ADD_INSN(ret, node, dup);
10894 }
10895 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10896 break;
10897 }
10898 case NODE_DASGN: {
10899 int idx, lv, ls;
10900 ID id = RNODE_DASGN(node)->nd_vid;
10901 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10902 debugi("dassn id", rb_id2str(id) ? id : '*');
10903
10904 if (!popped) {
10905 ADD_INSN(ret, node, dup);
10906 }
10907
10908 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10909
10910 if (idx < 0) {
10911 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10912 rb_id2str(id));
10913 goto ng;
10914 }
10915 ADD_SETLOCAL(ret, node, ls - idx, lv);
10916 break;
10917 }
10918 case NODE_GASGN:{
10919 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10920
10921 if (!popped) {
10922 ADD_INSN(ret, node, dup);
10923 }
10924 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10925 break;
10926 }
10927 case NODE_IASGN:{
10928 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10929 if (!popped) {
10930 ADD_INSN(ret, node, dup);
10931 }
10932 ADD_INSN2(ret, node, setinstancevariable,
10933 ID2SYM(RNODE_IASGN(node)->nd_vid),
10934 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10935 break;
10936 }
10937 case NODE_CDECL:{
10938 if (RNODE_CDECL(node)->nd_vid) {
10939 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10940
10941 if (!popped) {
10942 ADD_INSN(ret, node, dup);
10943 }
10944
10945 ADD_INSN1(ret, node, putspecialobject,
10946 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10947 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10948 }
10949 else {
10950 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10951 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10952 ADD_INSN(ret, node, swap);
10953
10954 if (!popped) {
10955 ADD_INSN1(ret, node, topn, INT2FIX(1));
10956 ADD_INSN(ret, node, swap);
10957 }
10958
10959 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10960 }
10961 break;
10962 }
10963 case NODE_CVASGN:{
10964 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10965 if (!popped) {
10966 ADD_INSN(ret, node, dup);
10967 }
10968 ADD_INSN2(ret, node, setclassvariable,
10969 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10970 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10971 break;
10972 }
10973 case NODE_OP_ASGN1:
10974 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10975 break;
10976 case NODE_OP_ASGN2:
10977 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10978 break;
10979 case NODE_OP_CDECL:
10980 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10981 break;
10982 case NODE_OP_ASGN_AND:
10983 case NODE_OP_ASGN_OR:
10984 CHECK(compile_op_log(iseq, ret, node, popped, type));
10985 break;
10986 case NODE_CALL: /* obj.foo */
10987 case NODE_OPCALL: /* foo[] */
10988 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10989 break;
10990 }
10991 case NODE_QCALL: /* obj&.foo */
10992 case NODE_FCALL: /* foo() */
10993 case NODE_VCALL: /* foo (variable or call) */
10994 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10995 goto ng;
10996 }
10997 break;
10998 case NODE_SUPER:
10999 case NODE_ZSUPER:
11000 CHECK(compile_super(iseq, ret, node, popped, type));
11001 break;
11002 case NODE_LIST:{
11003 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11004 break;
11005 }
11006 case NODE_ZLIST:{
11007 if (!popped) {
11008 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11009 }
11010 break;
11011 }
11012 case NODE_HASH:
11013 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11014 break;
11015 case NODE_RETURN:
11016 CHECK(compile_return(iseq, ret, node, popped));
11017 break;
11018 case NODE_YIELD:
11019 CHECK(compile_yield(iseq, ret, node, popped));
11020 break;
11021 case NODE_LVAR:{
11022 if (!popped) {
11023 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11024 }
11025 break;
11026 }
11027 case NODE_DVAR:{
11028 int lv, idx, ls;
11029 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11030 if (!popped) {
11031 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11032 if (idx < 0) {
11033 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11034 rb_id2str(RNODE_DVAR(node)->nd_vid));
11035 goto ng;
11036 }
11037 ADD_GETLOCAL(ret, node, ls - idx, lv);
11038 }
11039 break;
11040 }
11041 case NODE_GVAR:{
11042 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11043 if (popped) {
11044 ADD_INSN(ret, node, pop);
11045 }
11046 break;
11047 }
11048 case NODE_IVAR:{
11049 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11050 if (!popped) {
11051 ADD_INSN2(ret, node, getinstancevariable,
11052 ID2SYM(RNODE_IVAR(node)->nd_vid),
11053 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11054 }
11055 break;
11056 }
11057 case NODE_CONST:{
11058 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11059
11060 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11061 body->ic_size++;
11062 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11063 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11064 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11065 }
11066 else {
11067 ADD_INSN(ret, node, putnil);
11068 ADD_INSN1(ret, node, putobject, Qtrue);
11069 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11070 }
11071
11072 if (popped) {
11073 ADD_INSN(ret, node, pop);
11074 }
11075 break;
11076 }
11077 case NODE_CVAR:{
11078 if (!popped) {
11079 ADD_INSN2(ret, node, getclassvariable,
11080 ID2SYM(RNODE_CVAR(node)->nd_vid),
11081 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11082 }
11083 break;
11084 }
11085 case NODE_NTH_REF:{
11086 if (!popped) {
11087 if (!RNODE_NTH_REF(node)->nd_nth) {
11088 ADD_INSN(ret, node, putnil);
11089 break;
11090 }
11091 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11092 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11093 }
11094 break;
11095 }
11096 case NODE_BACK_REF:{
11097 if (!popped) {
11098 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11099 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11100 }
11101 break;
11102 }
11103 case NODE_MATCH:
11104 case NODE_MATCH2:
11105 case NODE_MATCH3:
11106 CHECK(compile_match(iseq, ret, node, popped, type));
11107 break;
11108 case NODE_SYM:{
11109 if (!popped) {
11110 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11111 }
11112 break;
11113 }
11114 case NODE_LINE:{
11115 if (!popped) {
11116 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11117 }
11118 break;
11119 }
11120 case NODE_ENCODING:{
11121 if (!popped) {
11122 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11123 }
11124 break;
11125 }
11126 case NODE_INTEGER:{
11127 VALUE lit = rb_node_integer_literal_val(node);
11128 debugp_param("integer", lit);
11129 if (!popped) {
11130 ADD_INSN1(ret, node, putobject, lit);
11131 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11132 }
11133 break;
11134 }
11135 case NODE_FLOAT:{
11136 VALUE lit = rb_node_float_literal_val(node);
11137 debugp_param("float", lit);
11138 if (!popped) {
11139 ADD_INSN1(ret, node, putobject, lit);
11140 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11141 }
11142 break;
11143 }
11144 case NODE_RATIONAL:{
11145 VALUE lit = rb_node_rational_literal_val(node);
11146 debugp_param("rational", lit);
11147 if (!popped) {
11148 ADD_INSN1(ret, node, putobject, lit);
11149 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11150 }
11151 break;
11152 }
11153 case NODE_IMAGINARY:{
11154 VALUE lit = rb_node_imaginary_literal_val(node);
11155 debugp_param("imaginary", lit);
11156 if (!popped) {
11157 ADD_INSN1(ret, node, putobject, lit);
11158 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11159 }
11160 break;
11161 }
11162 case NODE_FILE:
11163 case NODE_STR:{
11164 debugp_param("nd_lit", get_string_value(node));
11165 if (!popped) {
11166 VALUE lit = get_string_value(node);
11167 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11168 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11169 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11170 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11171 }
11172 switch (option->frozen_string_literal) {
11173 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11174 ADD_INSN1(ret, node, putchilledstring, lit);
11175 break;
11176 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11177 ADD_INSN1(ret, node, putstring, lit);
11178 break;
11179 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11180 ADD_INSN1(ret, node, putobject, lit);
11181 break;
11182 default:
11183 rb_bug("invalid frozen_string_literal");
11184 }
11185 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11186 }
11187 break;
11188 }
11189 case NODE_DSTR:{
11190 compile_dstr(iseq, ret, node);
11191
11192 if (popped) {
11193 ADD_INSN(ret, node, pop);
11194 }
11195 break;
11196 }
11197 case NODE_XSTR:{
11198 ADD_CALL_RECEIVER(ret, node);
11199 VALUE str = rb_node_str_string_val(node);
11200 ADD_INSN1(ret, node, putobject, str);
11201 RB_OBJ_WRITTEN(iseq, Qundef, str);
11202 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11203
11204 if (popped) {
11205 ADD_INSN(ret, node, pop);
11206 }
11207 break;
11208 }
11209 case NODE_DXSTR:{
11210 ADD_CALL_RECEIVER(ret, node);
11211 compile_dstr(iseq, ret, node);
11212 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11213
11214 if (popped) {
11215 ADD_INSN(ret, node, pop);
11216 }
11217 break;
11218 }
11219 case NODE_EVSTR:
11220 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11221 break;
11222 case NODE_REGX:{
11223 if (!popped) {
11224 VALUE lit = rb_node_regx_string_val(node);
11225 ADD_INSN1(ret, node, putobject, lit);
11226 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11227 }
11228 break;
11229 }
11230 case NODE_DREGX:
11231 compile_dregx(iseq, ret, node, popped);
11232 break;
11233 case NODE_ONCE:{
11234 int ic_index = body->ise_size++;
11235 const rb_iseq_t *block_iseq;
11236 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11237
11238 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11239 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11240
11241 if (popped) {
11242 ADD_INSN(ret, node, pop);
11243 }
11244 break;
11245 }
11246 case NODE_ARGSCAT:{
11247 if (popped) {
11248 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11249 ADD_INSN1(ret, node, splatarray, Qfalse);
11250 ADD_INSN(ret, node, pop);
11251 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11252 ADD_INSN1(ret, node, splatarray, Qfalse);
11253 ADD_INSN(ret, node, pop);
11254 }
11255 else {
11256 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11257 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11258 if (nd_type_p(body_node, NODE_LIST)) {
11259 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11260 }
11261 else {
11262 CHECK(COMPILE(ret, "argscat body", body_node));
11263 ADD_INSN(ret, node, concattoarray);
11264 }
11265 }
11266 break;
11267 }
11268 case NODE_ARGSPUSH:{
11269 if (popped) {
11270 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11271 ADD_INSN1(ret, node, splatarray, Qfalse);
11272 ADD_INSN(ret, node, pop);
11273 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11274 }
11275 else {
11276 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11277 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11278 if (keyword_node_p(body_node)) {
11279 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11280 ADD_INSN(ret, node, pushtoarraykwsplat);
11281 }
11282 else if (static_literal_node_p(body_node, iseq, false)) {
11283 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11284 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11285 }
11286 else {
11287 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11288 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11289 }
11290 }
11291 break;
11292 }
11293 case NODE_SPLAT:{
11294 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11295 ADD_INSN1(ret, node, splatarray, Qtrue);
11296
11297 if (popped) {
11298 ADD_INSN(ret, node, pop);
11299 }
11300 break;
11301 }
11302 case NODE_DEFN:{
11303 ID mid = RNODE_DEFN(node)->nd_mid;
11304 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11305 rb_id2str(mid),
11306 ISEQ_TYPE_METHOD, line);
11307
11308 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11309 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11310 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11311
11312 if (!popped) {
11313 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11314 }
11315
11316 break;
11317 }
11318 case NODE_DEFS:{
11319 ID mid = RNODE_DEFS(node)->nd_mid;
11320 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11321 rb_id2str(mid),
11322 ISEQ_TYPE_METHOD, line);
11323
11324 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11325 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11326 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11327 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11328
11329 if (!popped) {
11330 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11331 }
11332 break;
11333 }
11334 case NODE_ALIAS:{
11335 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11336 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11337 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11338 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11339 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11340
11341 if (popped) {
11342 ADD_INSN(ret, node, pop);
11343 }
11344 break;
11345 }
11346 case NODE_VALIAS:{
11347 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11348 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11349 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11350 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11351
11352 if (popped) {
11353 ADD_INSN(ret, node, pop);
11354 }
11355 break;
11356 }
11357 case NODE_UNDEF:{
11358 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11359
11360 for (long i = 0; i < ary->len; i++) {
11361 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11362 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11363 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11364 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11365
11366 if (i < ary->len - 1) {
11367 ADD_INSN(ret, node, pop);
11368 }
11369 }
11370
11371 if (popped) {
11372 ADD_INSN(ret, node, pop);
11373 }
11374 break;
11375 }
11376 case NODE_CLASS:{
11377 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11378 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11379 ISEQ_TYPE_CLASS, line);
11380 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11381 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11382 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11383
11384 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11385 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11386 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11387
11388 if (popped) {
11389 ADD_INSN(ret, node, pop);
11390 }
11391 break;
11392 }
11393 case NODE_MODULE:{
11394 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11395 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11396 ISEQ_TYPE_CLASS, line);
11397 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11398 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11399
11400 ADD_INSN (ret, node, putnil); /* dummy */
11401 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11402 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11403
11404 if (popped) {
11405 ADD_INSN(ret, node, pop);
11406 }
11407 break;
11408 }
11409 case NODE_SCLASS:{
11410 ID singletonclass;
11411 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11412 ISEQ_TYPE_CLASS, line);
11413
11414 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11415 ADD_INSN (ret, node, putnil);
11416 CONST_ID(singletonclass, "singletonclass");
11417 ADD_INSN3(ret, node, defineclass,
11418 ID2SYM(singletonclass), singleton_class,
11419 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11420 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11421
11422 if (popped) {
11423 ADD_INSN(ret, node, pop);
11424 }
11425 break;
11426 }
11427 case NODE_COLON2:
11428 CHECK(compile_colon2(iseq, ret, node, popped));
11429 break;
11430 case NODE_COLON3:
11431 CHECK(compile_colon3(iseq, ret, node, popped));
11432 break;
11433 case NODE_DOT2:
11434 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11435 break;
11436 case NODE_DOT3:
11437 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11438 break;
11439 case NODE_FLIP2:
11440 case NODE_FLIP3:{
11441 LABEL *lend = NEW_LABEL(line);
11442 LABEL *ltrue = NEW_LABEL(line);
11443 LABEL *lfalse = NEW_LABEL(line);
11444 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11445 ltrue, lfalse));
11446 ADD_LABEL(ret, ltrue);
11447 ADD_INSN1(ret, node, putobject, Qtrue);
11448 ADD_INSNL(ret, node, jump, lend);
11449 ADD_LABEL(ret, lfalse);
11450 ADD_INSN1(ret, node, putobject, Qfalse);
11451 ADD_LABEL(ret, lend);
11452 break;
11453 }
11454 case NODE_SELF:{
11455 if (!popped) {
11456 ADD_INSN(ret, node, putself);
11457 }
11458 break;
11459 }
11460 case NODE_NIL:{
11461 if (!popped) {
11462 ADD_INSN(ret, node, putnil);
11463 }
11464 break;
11465 }
11466 case NODE_TRUE:{
11467 if (!popped) {
11468 ADD_INSN1(ret, node, putobject, Qtrue);
11469 }
11470 break;
11471 }
11472 case NODE_FALSE:{
11473 if (!popped) {
11474 ADD_INSN1(ret, node, putobject, Qfalse);
11475 }
11476 break;
11477 }
11478 case NODE_ERRINFO:
11479 CHECK(compile_errinfo(iseq, ret, node, popped));
11480 break;
11481 case NODE_DEFINED:
11482 if (!popped) {
11483 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11484 }
11485 break;
11486 case NODE_POSTEXE:{
11487 /* compiled to:
11488 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11489 */
11490 int is_index = body->ise_size++;
11492 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11493 const rb_iseq_t *once_iseq =
11494 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11495
11496 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11497 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11498
11499 if (popped) {
11500 ADD_INSN(ret, node, pop);
11501 }
11502 break;
11503 }
11504 case NODE_KW_ARG:
11505 CHECK(compile_kw_arg(iseq, ret, node, popped));
11506 break;
11507 case NODE_DSYM:{
11508 compile_dstr(iseq, ret, node);
11509 if (!popped) {
11510 ADD_INSN(ret, node, intern);
11511 }
11512 else {
11513 ADD_INSN(ret, node, pop);
11514 }
11515 break;
11516 }
11517 case NODE_ATTRASGN:
11518 CHECK(compile_attrasgn(iseq, ret, node, popped));
11519 break;
11520 case NODE_LAMBDA:{
11521 /* compile same as lambda{...} */
11522 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11523 VALUE argc = INT2FIX(0);
11524
11525 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11526 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11527 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11528
11529 if (popped) {
11530 ADD_INSN(ret, node, pop);
11531 }
11532 break;
11533 }
11534 default:
11535 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11536 ng:
11537 debug_node_end();
11538 return COMPILE_NG;
11539 }
11540
11541 debug_node_end();
11542 return COMPILE_OK;
11543}
11544
11545/***************************/
11546/* instruction information */
11547/***************************/
11548
11549static int
11550insn_data_length(INSN *iobj)
11551{
11552 return insn_len(iobj->insn_id);
11553}
11554
11555static int
11556calc_sp_depth(int depth, INSN *insn)
11557{
11558 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11559}
11560
11561static VALUE
11562opobj_inspect(VALUE obj)
11563{
11564 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11565 switch (BUILTIN_TYPE(obj)) {
11566 case T_STRING:
11567 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11568 break;
11569 case T_ARRAY:
11570 obj = rb_ary_dup(obj);
11571 break;
11572 default:
11573 break;
11574 }
11575 }
11576 return rb_inspect(obj);
11577}
11578
11579
11580
11581static VALUE
11582insn_data_to_s_detail(INSN *iobj)
11583{
11584 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11585
11586 if (iobj->operands) {
11587 const char *types = insn_op_types(iobj->insn_id);
11588 int j;
11589
11590 for (j = 0; types[j]; j++) {
11591 char type = types[j];
11592
11593 switch (type) {
11594 case TS_OFFSET: /* label(destination position) */
11595 {
11596 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11597 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11598 break;
11599 }
11600 break;
11601 case TS_ISEQ: /* iseq */
11602 {
11603 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11604 VALUE val = Qnil;
11605 if (0 && iseq) { /* TODO: invalidate now */
11606 val = (VALUE)iseq;
11607 }
11608 rb_str_concat(str, opobj_inspect(val));
11609 }
11610 break;
11611 case TS_LINDEX:
11612 case TS_NUM: /* ulong */
11613 case TS_VALUE: /* VALUE */
11614 {
11615 VALUE v = OPERAND_AT(iobj, j);
11616 if (!CLASS_OF(v))
11617 rb_str_cat2(str, "<hidden>");
11618 else {
11619 rb_str_concat(str, opobj_inspect(v));
11620 }
11621 break;
11622 }
11623 case TS_ID: /* ID */
11624 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11625 break;
11626 case TS_IC: /* inline cache */
11627 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11628 break;
11629 case TS_IVC: /* inline ivar cache */
11630 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11631 break;
11632 case TS_ICVARC: /* inline cvar cache */
11633 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11634 break;
11635 case TS_ISE: /* inline storage entry */
11636 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11637 break;
11638 case TS_CALLDATA: /* we store these as call infos at compile time */
11639 {
11640 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11641 rb_str_cat2(str, "<calldata:");
11642 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11643 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11644 break;
11645 }
11646 case TS_CDHASH: /* case/when condition cache */
11647 rb_str_cat2(str, "<ch>");
11648 break;
11649 case TS_FUNCPTR:
11650 {
11651 void *func = (void *)OPERAND_AT(iobj, j);
11652#ifdef HAVE_DLADDR
11653 Dl_info info;
11654 if (dladdr(func, &info) && info.dli_sname) {
11655 rb_str_cat2(str, info.dli_sname);
11656 break;
11657 }
11658#endif
11659 rb_str_catf(str, "<%p>", func);
11660 }
11661 break;
11662 case TS_BUILTIN:
11663 rb_str_cat2(str, "<TS_BUILTIN>");
11664 break;
11665 default:{
11666 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11667 }
11668 }
11669 if (types[j + 1]) {
11670 rb_str_cat2(str, ", ");
11671 }
11672 }
11673 }
11674 return str;
11675}
11676
11677static void
11678dump_disasm_list(const LINK_ELEMENT *link)
11679{
11680 dump_disasm_list_with_cursor(link, NULL, NULL);
11681}
11682
11683static void
11684dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11685{
11686 int pos = 0;
11687 INSN *iobj;
11688 LABEL *lobj;
11689 VALUE str;
11690
11691 printf("-- raw disasm--------\n");
11692
11693 while (link) {
11694 if (curr) printf(curr == link ? "*" : " ");
11695 switch (link->type) {
11696 case ISEQ_ELEMENT_INSN:
11697 {
11698 iobj = (INSN *)link;
11699 str = insn_data_to_s_detail(iobj);
11700 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11701 pos += insn_data_length(iobj);
11702 break;
11703 }
11704 case ISEQ_ELEMENT_LABEL:
11705 {
11706 lobj = (LABEL *)link;
11707 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11708 dest == lobj ? " <---" : "");
11709 break;
11710 }
11711 case ISEQ_ELEMENT_TRACE:
11712 {
11713 TRACE *trace = (TRACE *)link;
11714 printf(" trace: %0x\n", trace->event);
11715 break;
11716 }
11717 case ISEQ_ELEMENT_ADJUST:
11718 {
11719 ADJUST *adjust = (ADJUST *)link;
11720 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11721 break;
11722 }
11723 default:
11724 /* ignore */
11725 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11726 }
11727 link = link->next;
11728 }
11729 printf("---------------------\n");
11730 fflush(stdout);
11731}
11732
11733int
11734rb_insn_len(VALUE insn)
11735{
11736 return insn_len(insn);
11737}
11738
11739const char *
11740rb_insns_name(int i)
11741{
11742 return insn_name(i);
11743}
11744
11745VALUE
11746rb_insns_name_array(void)
11747{
11748 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11749 int i;
11750 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11751 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11752 }
11753 return rb_ary_freeze(ary);
11754}
11755
11756static LABEL *
11757register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11758{
11759 LABEL *label = 0;
11760 st_data_t tmp;
11761 obj = rb_to_symbol_type(obj);
11762
11763 if (st_lookup(labels_table, obj, &tmp) == 0) {
11764 label = NEW_LABEL(0);
11765 st_insert(labels_table, obj, (st_data_t)label);
11766 }
11767 else {
11768 label = (LABEL *)tmp;
11769 }
11770 LABEL_REF(label);
11771 return label;
11772}
11773
11774static VALUE
11775get_exception_sym2type(VALUE sym)
11776{
11777 static VALUE symRescue, symEnsure, symRetry;
11778 static VALUE symBreak, symRedo, symNext;
11779
11780 if (symRescue == 0) {
11781 symRescue = ID2SYM(rb_intern_const("rescue"));
11782 symEnsure = ID2SYM(rb_intern_const("ensure"));
11783 symRetry = ID2SYM(rb_intern_const("retry"));
11784 symBreak = ID2SYM(rb_intern_const("break"));
11785 symRedo = ID2SYM(rb_intern_const("redo"));
11786 symNext = ID2SYM(rb_intern_const("next"));
11787 }
11788
11789 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11790 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11791 if (sym == symRetry) return CATCH_TYPE_RETRY;
11792 if (sym == symBreak) return CATCH_TYPE_BREAK;
11793 if (sym == symRedo) return CATCH_TYPE_REDO;
11794 if (sym == symNext) return CATCH_TYPE_NEXT;
11795 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11796 return 0;
11797}
11798
11799static int
11800iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11801 VALUE exception)
11802{
11803 int i;
11804
11805 for (i=0; i<RARRAY_LEN(exception); i++) {
11806 const rb_iseq_t *eiseq;
11807 VALUE v, type;
11808 LABEL *lstart, *lend, *lcont;
11809 unsigned int sp;
11810
11811 v = rb_to_array_type(RARRAY_AREF(exception, i));
11812 if (RARRAY_LEN(v) != 6) {
11813 rb_raise(rb_eSyntaxError, "wrong exception entry");
11814 }
11815 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11816 if (NIL_P(RARRAY_AREF(v, 1))) {
11817 eiseq = NULL;
11818 }
11819 else {
11820 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11821 }
11822
11823 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11824 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11825 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11826 sp = NUM2UINT(RARRAY_AREF(v, 5));
11827
11828 /* TODO: Dirty Hack! Fix me */
11829 if (type == CATCH_TYPE_RESCUE ||
11830 type == CATCH_TYPE_BREAK ||
11831 type == CATCH_TYPE_NEXT) {
11832 ++sp;
11833 }
11834
11835 lcont->sp = sp;
11836
11837 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11838
11839 RB_GC_GUARD(v);
11840 }
11841 return COMPILE_OK;
11842}
11843
11844static struct st_table *
11845insn_make_insn_table(void)
11846{
11847 struct st_table *table;
11848 int i;
11849 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11850
11851 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11852 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11853 }
11854
11855 return table;
11856}
11857
11858static const rb_iseq_t *
11859iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11860{
11861 VALUE iseqw;
11862 const rb_iseq_t *loaded_iseq;
11863
11864 if (RB_TYPE_P(op, T_ARRAY)) {
11865 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11866 }
11867 else if (CLASS_OF(op) == rb_cISeq) {
11868 iseqw = op;
11869 }
11870 else {
11871 rb_raise(rb_eSyntaxError, "ISEQ is required");
11872 }
11873
11874 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11875 return loaded_iseq;
11876}
11877
11878static VALUE
11879iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11880{
11881 ID mid = 0;
11882 int orig_argc = 0;
11883 unsigned int flag = 0;
11884 struct rb_callinfo_kwarg *kw_arg = 0;
11885
11886 if (!NIL_P(op)) {
11887 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11888 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11889 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11890 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11891
11892 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11893 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11894 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11895
11896 if (!NIL_P(vkw_arg)) {
11897 int i;
11898 int len = RARRAY_LENINT(vkw_arg);
11899 size_t n = rb_callinfo_kwarg_bytes(len);
11900
11901 kw_arg = xmalloc(n);
11902 kw_arg->references = 0;
11903 kw_arg->keyword_len = len;
11904 for (i = 0; i < len; i++) {
11905 VALUE kw = RARRAY_AREF(vkw_arg, i);
11906 SYM2ID(kw); /* make immortal */
11907 kw_arg->keywords[i] = kw;
11908 }
11909 }
11910 }
11911
11912 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11913 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11914 return (VALUE)ci;
11915}
11916
11917static rb_event_flag_t
11918event_name_to_flag(VALUE sym)
11919{
11920#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11921 CHECK_EVENT(RUBY_EVENT_LINE);
11922 CHECK_EVENT(RUBY_EVENT_CLASS);
11923 CHECK_EVENT(RUBY_EVENT_END);
11924 CHECK_EVENT(RUBY_EVENT_CALL);
11925 CHECK_EVENT(RUBY_EVENT_RETURN);
11926 CHECK_EVENT(RUBY_EVENT_B_CALL);
11927 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11928 CHECK_EVENT(RUBY_EVENT_RESCUE);
11929#undef CHECK_EVENT
11930 return RUBY_EVENT_NONE;
11931}
11932
11933static int
11934iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11935 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11936{
11937 /* TODO: body should be frozen */
11938 long i, len = RARRAY_LEN(body);
11939 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11940 int j;
11941 int line_no = 0, node_id = -1, insn_idx = 0;
11942 int ret = COMPILE_OK;
11943
11944 /*
11945 * index -> LABEL *label
11946 */
11947 static struct st_table *insn_table;
11948
11949 if (insn_table == 0) {
11950 insn_table = insn_make_insn_table();
11951 }
11952
11953 for (i=0; i<len; i++) {
11954 VALUE obj = RARRAY_AREF(body, i);
11955
11956 if (SYMBOL_P(obj)) {
11957 rb_event_flag_t event;
11958 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11959 ADD_TRACE(anchor, event);
11960 }
11961 else {
11962 LABEL *label = register_label(iseq, labels_table, obj);
11963 ADD_LABEL(anchor, label);
11964 }
11965 }
11966 else if (FIXNUM_P(obj)) {
11967 line_no = NUM2INT(obj);
11968 }
11969 else if (RB_TYPE_P(obj, T_ARRAY)) {
11970 VALUE *argv = 0;
11971 int argc = RARRAY_LENINT(obj) - 1;
11972 st_data_t insn_id;
11973 VALUE insn;
11974
11975 if (node_ids) {
11976 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11977 }
11978
11979 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11980 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11981 /* TODO: exception */
11982 COMPILE_ERROR(iseq, line_no,
11983 "unknown instruction: %+"PRIsVALUE, insn);
11984 ret = COMPILE_NG;
11985 break;
11986 }
11987
11988 if (argc != insn_len((VALUE)insn_id)-1) {
11989 COMPILE_ERROR(iseq, line_no,
11990 "operand size mismatch");
11991 ret = COMPILE_NG;
11992 break;
11993 }
11994
11995 if (argc > 0) {
11996 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11997
11998 // add element before operand setup to make GC root
11999 ADD_ELEM(anchor,
12000 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12001 (enum ruby_vminsn_type)insn_id, argc, argv));
12002
12003 for (j=0; j<argc; j++) {
12004 VALUE op = rb_ary_entry(obj, j+1);
12005 switch (insn_op_type((VALUE)insn_id, j)) {
12006 case TS_OFFSET: {
12007 LABEL *label = register_label(iseq, labels_table, op);
12008 argv[j] = (VALUE)label;
12009 break;
12010 }
12011 case TS_LINDEX:
12012 case TS_NUM:
12013 (void)NUM2INT(op);
12014 argv[j] = op;
12015 break;
12016 case TS_VALUE:
12017 argv[j] = op;
12018 RB_OBJ_WRITTEN(iseq, Qundef, op);
12019 break;
12020 case TS_ISEQ:
12021 {
12022 if (op != Qnil) {
12023 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12024 argv[j] = v;
12025 RB_OBJ_WRITTEN(iseq, Qundef, v);
12026 }
12027 else {
12028 argv[j] = 0;
12029 }
12030 }
12031 break;
12032 case TS_ISE:
12033 argv[j] = op;
12034 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12035 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12036 }
12037 break;
12038 case TS_IC:
12039 {
12040 VALUE segments = rb_ary_new();
12041 op = rb_to_array_type(op);
12042
12043 for (int i = 0; i < RARRAY_LEN(op); i++) {
12044 VALUE sym = RARRAY_AREF(op, i);
12045 sym = rb_to_symbol_type(sym);
12046 rb_ary_push(segments, sym);
12047 }
12048
12049 RB_GC_GUARD(op);
12050 argv[j] = segments;
12051 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12052 ISEQ_BODY(iseq)->ic_size++;
12053 }
12054 break;
12055 case TS_IVC: /* inline ivar cache */
12056 argv[j] = op;
12057 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12058 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12059 }
12060 break;
12061 case TS_ICVARC: /* inline cvar cache */
12062 argv[j] = op;
12063 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12064 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12065 }
12066 break;
12067 case TS_CALLDATA:
12068 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12069 break;
12070 case TS_ID:
12071 argv[j] = rb_to_symbol_type(op);
12072 break;
12073 case TS_CDHASH:
12074 {
12075 int i;
12076 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12077
12078 RHASH_TBL_RAW(map)->type = &cdhash_type;
12079 op = rb_to_array_type(op);
12080 for (i=0; i<RARRAY_LEN(op); i+=2) {
12081 VALUE key = RARRAY_AREF(op, i);
12082 VALUE sym = RARRAY_AREF(op, i+1);
12083 LABEL *label =
12084 register_label(iseq, labels_table, sym);
12085 rb_hash_aset(map, key, (VALUE)label | 1);
12086 }
12087 RB_GC_GUARD(op);
12088 argv[j] = map;
12089 RB_OBJ_WRITTEN(iseq, Qundef, map);
12090 }
12091 break;
12092 case TS_FUNCPTR:
12093 {
12094#if SIZEOF_VALUE <= SIZEOF_LONG
12095 long funcptr = NUM2LONG(op);
12096#else
12097 LONG_LONG funcptr = NUM2LL(op);
12098#endif
12099 argv[j] = (VALUE)funcptr;
12100 }
12101 break;
12102 default:
12103 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12104 }
12105 }
12106 }
12107 else {
12108 ADD_ELEM(anchor,
12109 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12110 (enum ruby_vminsn_type)insn_id, argc, NULL));
12111 }
12112 }
12113 else {
12114 rb_raise(rb_eTypeError, "unexpected object for instruction");
12115 }
12116 }
12117 RTYPEDDATA_DATA(labels_wrapper) = 0;
12118 RB_GC_GUARD(labels_wrapper);
12119 validate_labels(iseq, labels_table);
12120 if (!ret) return ret;
12121 return iseq_setup(iseq, anchor);
12122}
12123
12124#define CHECK_ARRAY(v) rb_to_array_type(v)
12125#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12126
12127static int
12128int_param(int *dst, VALUE param, VALUE sym)
12129{
12130 VALUE val = rb_hash_aref(param, sym);
12131 if (FIXNUM_P(val)) {
12132 *dst = FIX2INT(val);
12133 return TRUE;
12134 }
12135 else if (!NIL_P(val)) {
12136 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12137 sym, val);
12138 }
12139 return FALSE;
12140}
12141
12142static const struct rb_iseq_param_keyword *
12143iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12144{
12145 int i, j;
12146 int len = RARRAY_LENINT(keywords);
12147 int default_len;
12148 VALUE key, sym, default_val;
12149 VALUE *dvs;
12150 ID *ids;
12151 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12152
12153 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12154
12155 keyword->num = len;
12156#define SYM(s) ID2SYM(rb_intern_const(#s))
12157 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12158 i = keyword->bits_start - keyword->num;
12159 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12160#undef SYM
12161
12162 /* required args */
12163 for (i = 0; i < len; i++) {
12164 VALUE val = RARRAY_AREF(keywords, i);
12165
12166 if (!SYMBOL_P(val)) {
12167 goto default_values;
12168 }
12169 ids[i] = SYM2ID(val);
12170 keyword->required_num++;
12171 }
12172
12173 default_values: /* note: we intentionally preserve `i' from previous loop */
12174 default_len = len - i;
12175 if (default_len == 0) {
12176 keyword->table = ids;
12177 return keyword;
12178 }
12179 else if (default_len < 0) {
12181 }
12182
12183 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12184
12185 for (j = 0; i < len; i++, j++) {
12186 key = RARRAY_AREF(keywords, i);
12187 CHECK_ARRAY(key);
12188
12189 switch (RARRAY_LEN(key)) {
12190 case 1:
12191 sym = RARRAY_AREF(key, 0);
12192 default_val = Qundef;
12193 break;
12194 case 2:
12195 sym = RARRAY_AREF(key, 0);
12196 default_val = RARRAY_AREF(key, 1);
12197 break;
12198 default:
12199 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12200 }
12201 ids[i] = SYM2ID(sym);
12202 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12203 }
12204
12205 keyword->table = ids;
12206 keyword->default_values = dvs;
12207
12208 return keyword;
12209}
12210
12211static void
12212iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12213{
12214 rb_gc_mark_and_move(obj);
12215}
12216
12217void
12218rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12219{
12220 INSN *iobj = 0;
12221 size_t size = sizeof(INSN);
12222 unsigned int pos = 0;
12223
12224 while (storage) {
12225#ifdef STRICT_ALIGNMENT
12226 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12227#else
12228 const size_t padding = 0; /* expected to be optimized by compiler */
12229#endif /* STRICT_ALIGNMENT */
12230 size_t offset = pos + size + padding;
12231 if (offset > storage->size || offset > storage->pos) {
12232 pos = 0;
12233 storage = storage->next;
12234 }
12235 else {
12236#ifdef STRICT_ALIGNMENT
12237 pos += (int)padding;
12238#endif /* STRICT_ALIGNMENT */
12239
12240 iobj = (INSN *)&storage->buff[pos];
12241
12242 if (iobj->operands) {
12243 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12244 }
12245 pos += (int)size;
12246 }
12247 }
12248}
12249
12250static const rb_data_type_t labels_wrapper_type = {
12251 .wrap_struct_name = "compiler/labels_wrapper",
12252 .function = {
12253 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12254 .dfree = (RUBY_DATA_FUNC)st_free_table,
12255 },
12256 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12257};
12258
12259void
12260rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12261 VALUE exception, VALUE body)
12262{
12263#define SYM(s) ID2SYM(rb_intern_const(#s))
12264 int i, len;
12265 unsigned int arg_size, local_size, stack_max;
12266 ID *tbl;
12267 struct st_table *labels_table = st_init_numtable();
12268 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12269 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12270 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12271 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12272 DECL_ANCHOR(anchor);
12273 INIT_ANCHOR(anchor);
12274
12275 len = RARRAY_LENINT(locals);
12276 ISEQ_BODY(iseq)->local_table_size = len;
12277 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12278
12279 for (i = 0; i < len; i++) {
12280 VALUE lv = RARRAY_AREF(locals, i);
12281
12282 if (sym_arg_rest == lv) {
12283 tbl[i] = 0;
12284 }
12285 else {
12286 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12287 }
12288 }
12289
12290#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12291 if (INT_PARAM(lead_num)) {
12292 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12293 }
12294 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12295 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12296 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12297 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12298#undef INT_PARAM
12299 {
12300#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12301 int x;
12302 INT_PARAM(arg_size);
12303 INT_PARAM(local_size);
12304 INT_PARAM(stack_max);
12305#undef INT_PARAM
12306 }
12307
12308 VALUE node_ids = Qfalse;
12309#ifdef USE_ISEQ_NODE_ID
12310 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12311 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12312 rb_raise(rb_eTypeError, "node_ids is not an array");
12313 }
12314#endif
12315
12316 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12317 len = RARRAY_LENINT(arg_opt_labels);
12318 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12319
12320 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12321 VALUE *opt_table = ALLOC_N(VALUE, len);
12322
12323 for (i = 0; i < len; i++) {
12324 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12325 LABEL *label = register_label(iseq, labels_table, ent);
12326 opt_table[i] = (VALUE)label;
12327 }
12328
12329 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12330 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12331 }
12332 }
12333 else if (!NIL_P(arg_opt_labels)) {
12334 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12335 arg_opt_labels);
12336 }
12337
12338 if (RB_TYPE_P(keywords, T_ARRAY)) {
12339 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12340 }
12341 else if (!NIL_P(keywords)) {
12342 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12343 keywords);
12344 }
12345
12346 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12347 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12348 }
12349
12350 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12351 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12352 }
12353
12354 if (int_param(&i, params, SYM(kwrest))) {
12355 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12356 if (keyword == NULL) {
12357 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12358 }
12359 keyword->rest_start = i;
12360 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12361 }
12362#undef SYM
12363 iseq_calc_param_size(iseq);
12364
12365 /* exception */
12366 iseq_build_from_ary_exception(iseq, labels_table, exception);
12367
12368 /* body */
12369 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12370
12371 ISEQ_BODY(iseq)->param.size = arg_size;
12372 ISEQ_BODY(iseq)->local_table_size = local_size;
12373 ISEQ_BODY(iseq)->stack_max = stack_max;
12374}
12375
12376/* for parser */
12377
12378int
12379rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12380{
12381 if (iseq) {
12382 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12383 while (body->type == ISEQ_TYPE_BLOCK ||
12384 body->type == ISEQ_TYPE_RESCUE ||
12385 body->type == ISEQ_TYPE_ENSURE ||
12386 body->type == ISEQ_TYPE_EVAL ||
12387 body->type == ISEQ_TYPE_MAIN
12388 ) {
12389 unsigned int i;
12390
12391 for (i = 0; i < body->local_table_size; i++) {
12392 if (body->local_table[i] == id) {
12393 return 1;
12394 }
12395 }
12396 iseq = body->parent_iseq;
12397 body = ISEQ_BODY(iseq);
12398 }
12399 }
12400 return 0;
12401}
12402
12403int
12404rb_local_defined(ID id, const rb_iseq_t *iseq)
12405{
12406 if (iseq) {
12407 unsigned int i;
12408 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12409
12410 for (i=0; i<body->local_table_size; i++) {
12411 if (body->local_table[i] == id) {
12412 return 1;
12413 }
12414 }
12415 }
12416 return 0;
12417}
12418
12419/* ISeq binary format */
12420
12421#ifndef IBF_ISEQ_DEBUG
12422#define IBF_ISEQ_DEBUG 0
12423#endif
12424
12425#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12426#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12427#endif
12428
12429typedef uint32_t ibf_offset_t;
12430#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12431
12432#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12433#ifdef RUBY_DEVEL
12434#define IBF_DEVEL_VERSION 5
12435#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12436#else
12437#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12438#endif
12439
12440static const char IBF_ENDIAN_MARK =
12441#ifdef WORDS_BIGENDIAN
12442 'b'
12443#else
12444 'l'
12445#endif
12446 ;
12447
12449 char magic[4]; /* YARB */
12450 uint32_t major_version;
12451 uint32_t minor_version;
12452 uint32_t size;
12453 uint32_t extra_size;
12454
12455 uint32_t iseq_list_size;
12456 uint32_t global_object_list_size;
12457 ibf_offset_t iseq_list_offset;
12458 ibf_offset_t global_object_list_offset;
12459 uint8_t endian;
12460 uint8_t wordsize; /* assume no 2048-bit CPU */
12461};
12462
12464 VALUE str;
12465 st_table *obj_table; /* obj -> obj number */
12466};
12467
12468struct ibf_dump {
12469 st_table *iseq_table; /* iseq -> iseq number */
12470 struct ibf_dump_buffer global_buffer;
12471 struct ibf_dump_buffer *current_buffer;
12472};
12473
12475 const char *buff;
12476 ibf_offset_t size;
12477
12478 VALUE obj_list; /* [obj0, ...] */
12479 unsigned int obj_list_size;
12480 ibf_offset_t obj_list_offset;
12481};
12482
12483struct ibf_load {
12484 const struct ibf_header *header;
12485 VALUE iseq_list; /* [iseq0, ...] */
12486 struct ibf_load_buffer global_buffer;
12487 VALUE loader_obj;
12488 rb_iseq_t *iseq;
12489 VALUE str;
12490 struct ibf_load_buffer *current_buffer;
12491};
12492
12494 long size;
12495 VALUE buffer[1];
12496};
12497
12498static void
12499pinned_list_mark(void *ptr)
12500{
12501 long i;
12502 struct pinned_list *list = (struct pinned_list *)ptr;
12503 for (i = 0; i < list->size; i++) {
12504 if (list->buffer[i]) {
12505 rb_gc_mark(list->buffer[i]);
12506 }
12507 }
12508}
12509
12510static const rb_data_type_t pinned_list_type = {
12511 "pinned_list",
12512 {
12513 pinned_list_mark,
12515 NULL, // No external memory to report,
12516 },
12517 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12518};
12519
12520static VALUE
12521pinned_list_fetch(VALUE list, long offset)
12522{
12523 struct pinned_list * ptr;
12524
12525 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12526
12527 if (offset >= ptr->size) {
12528 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12529 }
12530
12531 return ptr->buffer[offset];
12532}
12533
12534static void
12535pinned_list_store(VALUE list, long offset, VALUE object)
12536{
12537 struct pinned_list * ptr;
12538
12539 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12540
12541 if (offset >= ptr->size) {
12542 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12543 }
12544
12545 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12546}
12547
12548static VALUE
12549pinned_list_new(long size)
12550{
12551 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12552 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12553 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12554 ptr->size = size;
12555 return obj_list;
12556}
12557
12558static ibf_offset_t
12559ibf_dump_pos(struct ibf_dump *dump)
12560{
12561 long pos = RSTRING_LEN(dump->current_buffer->str);
12562#if SIZEOF_LONG > SIZEOF_INT
12563 if (pos >= UINT_MAX) {
12564 rb_raise(rb_eRuntimeError, "dump size exceeds");
12565 }
12566#endif
12567 return (unsigned int)pos;
12568}
12569
12570static void
12571ibf_dump_align(struct ibf_dump *dump, size_t align)
12572{
12573 ibf_offset_t pos = ibf_dump_pos(dump);
12574 if (pos % align) {
12575 static const char padding[sizeof(VALUE)];
12576 size_t size = align - ((size_t)pos % align);
12577#if SIZEOF_LONG > SIZEOF_INT
12578 if (pos + size >= UINT_MAX) {
12579 rb_raise(rb_eRuntimeError, "dump size exceeds");
12580 }
12581#endif
12582 for (; size > sizeof(padding); size -= sizeof(padding)) {
12583 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12584 }
12585 rb_str_cat(dump->current_buffer->str, padding, size);
12586 }
12587}
12588
12589static ibf_offset_t
12590ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12591{
12592 ibf_offset_t pos = ibf_dump_pos(dump);
12593#if SIZEOF_LONG > SIZEOF_INT
12594 /* ensure the resulting dump does not exceed UINT_MAX */
12595 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12596 rb_raise(rb_eRuntimeError, "dump size exceeds");
12597 }
12598#endif
12599 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12600 return pos;
12601}
12602
12603static ibf_offset_t
12604ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12605{
12606 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12607}
12608
12609static void
12610ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12611{
12612 VALUE str = dump->current_buffer->str;
12613 char *ptr = RSTRING_PTR(str);
12614 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12615 rb_bug("ibf_dump_overwrite: overflow");
12616 memcpy(ptr + offset, buff, size);
12617}
12618
12619static const void *
12620ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12621{
12622 ibf_offset_t beg = *offset;
12623 *offset += size;
12624 return load->current_buffer->buff + beg;
12625}
12626
12627static void *
12628ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12629{
12630 void *buff = ruby_xmalloc2(x, y);
12631 size_t size = x * y;
12632 memcpy(buff, load->current_buffer->buff + offset, size);
12633 return buff;
12634}
12635
12636#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12637
12638#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12639#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12640#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12641#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12642#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12643
12644static int
12645ibf_table_lookup(struct st_table *table, st_data_t key)
12646{
12647 st_data_t val;
12648
12649 if (st_lookup(table, key, &val)) {
12650 return (int)val;
12651 }
12652 else {
12653 return -1;
12654 }
12655}
12656
12657static int
12658ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12659{
12660 int index = ibf_table_lookup(table, key);
12661
12662 if (index < 0) { /* not found */
12663 index = (int)table->num_entries;
12664 st_insert(table, key, (st_data_t)index);
12665 }
12666
12667 return index;
12668}
12669
12670/* dump/load generic */
12671
12672static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12673
12674static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12675static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12676
12677static st_table *
12678ibf_dump_object_table_new(void)
12679{
12680 st_table *obj_table = st_init_numtable(); /* need free */
12681 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12682
12683 return obj_table;
12684}
12685
12686static VALUE
12687ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12688{
12689 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12690}
12691
12692static VALUE
12693ibf_dump_id(struct ibf_dump *dump, ID id)
12694{
12695 if (id == 0 || rb_id2name(id) == NULL) {
12696 return 0;
12697 }
12698 return ibf_dump_object(dump, rb_id2sym(id));
12699}
12700
12701static ID
12702ibf_load_id(const struct ibf_load *load, const ID id_index)
12703{
12704 if (id_index == 0) {
12705 return 0;
12706 }
12707 VALUE sym = ibf_load_object(load, id_index);
12708 if (rb_integer_type_p(sym)) {
12709 /* Load hidden local variables as indexes */
12710 return NUM2ULONG(sym);
12711 }
12712 return rb_sym2id(sym);
12713}
12714
12715/* dump/load: code */
12716
12717static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12718
12719static int
12720ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12721{
12722 if (iseq == NULL) {
12723 return -1;
12724 }
12725 else {
12726 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12727 }
12728}
12729
12730static unsigned char
12731ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12732{
12733 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12734 return (unsigned char)load->current_buffer->buff[(*offset)++];
12735}
12736
12737/*
12738 * Small uint serialization
12739 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12740 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12741 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12742 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12743 * ...
12744 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12745 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12746 */
12747static void
12748ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12749{
12750 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12751 ibf_dump_write(dump, &x, sizeof(VALUE));
12752 return;
12753 }
12754
12755 enum { max_byte_length = sizeof(VALUE) + 1 };
12756
12757 unsigned char bytes[max_byte_length];
12758 ibf_offset_t n;
12759
12760 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12761 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12762 }
12763
12764 x <<= 1;
12765 x |= 1;
12766 x <<= n;
12767 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12768 n++;
12769
12770 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12771}
12772
12773static VALUE
12774ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12775{
12776 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12777 union { char s[sizeof(VALUE)]; VALUE v; } x;
12778
12779 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12780 *offset += sizeof(VALUE);
12781
12782 return x.v;
12783 }
12784
12785 enum { max_byte_length = sizeof(VALUE) + 1 };
12786
12787 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12788 const unsigned char c = buffer[*offset];
12789
12790 ibf_offset_t n =
12791 c & 1 ? 1 :
12792 c == 0 ? 9 : ntz_int32(c) + 1;
12793 VALUE x = (VALUE)c >> n;
12794
12795 if (*offset + n > load->current_buffer->size) {
12796 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12797 }
12798
12799 ibf_offset_t i;
12800 for (i = 1; i < n; i++) {
12801 x <<= 8;
12802 x |= (VALUE)buffer[*offset + i];
12803 }
12804
12805 *offset += n;
12806 return x;
12807}
12808
12809static void
12810ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12811{
12812 // short: index
12813 // short: name.length
12814 // bytes: name
12815 // // omit argc (only verify with name)
12816 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12817
12818 size_t len = strlen(bf->name);
12819 ibf_dump_write_small_value(dump, (VALUE)len);
12820 ibf_dump_write(dump, bf->name, len);
12821}
12822
12823static const struct rb_builtin_function *
12824ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12825{
12826 int i = (int)ibf_load_small_value(load, offset);
12827 int len = (int)ibf_load_small_value(load, offset);
12828 const char *name = (char *)ibf_load_ptr(load, offset, len);
12829
12830 if (0) {
12831 fprintf(stderr, "%.*s!!\n", len, name);
12832 }
12833
12834 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12835 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12836 if (strncmp(table[i].name, name, len) != 0) {
12837 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12838 }
12839 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12840
12841 return &table[i];
12842}
12843
12844static ibf_offset_t
12845ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12846{
12847 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12848 const int iseq_size = body->iseq_size;
12849 int code_index;
12850 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12851
12852 ibf_offset_t offset = ibf_dump_pos(dump);
12853
12854 for (code_index=0; code_index<iseq_size;) {
12855 const VALUE insn = orig_code[code_index++];
12856 const char *types = insn_op_types(insn);
12857 int op_index;
12858
12859 /* opcode */
12860 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12861 ibf_dump_write_small_value(dump, insn);
12862
12863 /* operands */
12864 for (op_index=0; types[op_index]; op_index++, code_index++) {
12865 VALUE op = orig_code[code_index];
12866 VALUE wv;
12867
12868 switch (types[op_index]) {
12869 case TS_CDHASH:
12870 case TS_VALUE:
12871 wv = ibf_dump_object(dump, op);
12872 break;
12873 case TS_ISEQ:
12874 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12875 break;
12876 case TS_IC:
12877 {
12878 IC ic = (IC)op;
12879 VALUE arr = idlist_to_array(ic->segments);
12880 wv = ibf_dump_object(dump, arr);
12881 }
12882 break;
12883 case TS_ISE:
12884 case TS_IVC:
12885 case TS_ICVARC:
12886 {
12888 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12889 }
12890 break;
12891 case TS_CALLDATA:
12892 {
12893 goto skip_wv;
12894 }
12895 case TS_ID:
12896 wv = ibf_dump_id(dump, (ID)op);
12897 break;
12898 case TS_FUNCPTR:
12899 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12900 goto skip_wv;
12901 case TS_BUILTIN:
12902 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12903 goto skip_wv;
12904 default:
12905 wv = op;
12906 break;
12907 }
12908 ibf_dump_write_small_value(dump, wv);
12909 skip_wv:;
12910 }
12911 RUBY_ASSERT(insn_len(insn) == op_index+1);
12912 }
12913
12914 return offset;
12915}
12916
12917static VALUE *
12918ibf_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)
12919{
12920 VALUE iseqv = (VALUE)iseq;
12921 unsigned int code_index;
12922 ibf_offset_t reading_pos = bytecode_offset;
12923 VALUE *code = ALLOC_N(VALUE, iseq_size);
12924
12925 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12926 struct rb_call_data *cd_entries = load_body->call_data;
12927 int ic_index = 0;
12928
12929 iseq_bits_t * mark_offset_bits;
12930
12931 iseq_bits_t tmp[1] = {0};
12932
12933 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12934 mark_offset_bits = tmp;
12935 }
12936 else {
12937 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12938 }
12939 bool needs_bitmap = false;
12940
12941 for (code_index=0; code_index<iseq_size;) {
12942 /* opcode */
12943 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12944 const char *types = insn_op_types(insn);
12945 int op_index;
12946
12947 code_index++;
12948
12949 /* operands */
12950 for (op_index=0; types[op_index]; op_index++, code_index++) {
12951 const char operand_type = types[op_index];
12952 switch (operand_type) {
12953 case TS_VALUE:
12954 {
12955 VALUE op = ibf_load_small_value(load, &reading_pos);
12956 VALUE v = ibf_load_object(load, op);
12957 code[code_index] = v;
12958 if (!SPECIAL_CONST_P(v)) {
12959 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12960 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12961 needs_bitmap = true;
12962 }
12963 break;
12964 }
12965 case TS_CDHASH:
12966 {
12967 VALUE op = ibf_load_small_value(load, &reading_pos);
12968 VALUE v = ibf_load_object(load, op);
12969 v = rb_hash_dup(v); // hash dumped as frozen
12970 RHASH_TBL_RAW(v)->type = &cdhash_type;
12971 rb_hash_rehash(v); // hash function changed
12972 freeze_hide_obj(v);
12973
12974 // Overwrite the existing hash in the object list. This
12975 // is to keep the object alive during load time.
12976 // [Bug #17984] [ruby-core:104259]
12977 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12978
12979 code[code_index] = v;
12980 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12981 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12982 needs_bitmap = true;
12983 break;
12984 }
12985 case TS_ISEQ:
12986 {
12987 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12988 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12989 code[code_index] = v;
12990 if (!SPECIAL_CONST_P(v)) {
12991 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12992 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12993 needs_bitmap = true;
12994 }
12995 break;
12996 }
12997 case TS_IC:
12998 {
12999 VALUE op = ibf_load_small_value(load, &reading_pos);
13000 VALUE arr = ibf_load_object(load, op);
13001
13002 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13003 ic->segments = array_to_idlist(arr);
13004
13005 code[code_index] = (VALUE)ic;
13006 }
13007 break;
13008 case TS_ISE:
13009 case TS_ICVARC:
13010 case TS_IVC:
13011 {
13012 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13013
13014 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13015 code[code_index] = (VALUE)ic;
13016
13017 if (operand_type == TS_IVC) {
13018 IVC cache = (IVC)ic;
13019
13020 if (insn == BIN(setinstancevariable)) {
13021 ID iv_name = (ID)code[code_index - 1];
13022 cache->iv_set_name = iv_name;
13023 }
13024 else {
13025 cache->iv_set_name = 0;
13026 }
13027
13028 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13029 }
13030
13031 }
13032 break;
13033 case TS_CALLDATA:
13034 {
13035 code[code_index] = (VALUE)cd_entries++;
13036 }
13037 break;
13038 case TS_ID:
13039 {
13040 VALUE op = ibf_load_small_value(load, &reading_pos);
13041 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13042 }
13043 break;
13044 case TS_FUNCPTR:
13045 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13046 break;
13047 case TS_BUILTIN:
13048 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13049 break;
13050 default:
13051 code[code_index] = ibf_load_small_value(load, &reading_pos);
13052 continue;
13053 }
13054 }
13055 if (insn_len(insn) != op_index+1) {
13056 rb_raise(rb_eRuntimeError, "operand size mismatch");
13057 }
13058 }
13059
13060 load_body->iseq_encoded = code;
13061 load_body->iseq_size = code_index;
13062
13063 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13064 load_body->mark_bits.single = mark_offset_bits[0];
13065 }
13066 else {
13067 if (needs_bitmap) {
13068 load_body->mark_bits.list = mark_offset_bits;
13069 }
13070 else {
13071 load_body->mark_bits.list = 0;
13072 ruby_xfree(mark_offset_bits);
13073 }
13074 }
13075
13076 RUBY_ASSERT(code_index == iseq_size);
13077 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13078 return code;
13079}
13080
13081static ibf_offset_t
13082ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13083{
13084 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13085
13086 if (opt_num > 0) {
13087 IBF_W_ALIGN(VALUE);
13088 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13089 }
13090 else {
13091 return ibf_dump_pos(dump);
13092 }
13093}
13094
13095static VALUE *
13096ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13097{
13098 if (opt_num > 0) {
13099 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13100 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13101 return table;
13102 }
13103 else {
13104 return NULL;
13105 }
13106}
13107
13108static ibf_offset_t
13109ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13110{
13111 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13112
13113 if (kw) {
13114 struct rb_iseq_param_keyword dump_kw = *kw;
13115 int dv_num = kw->num - kw->required_num;
13116 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13117 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13118 int i;
13119
13120 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13121 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13122
13123 dump_kw.table = IBF_W(ids, ID, kw->num);
13124 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13125 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13126 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13127 }
13128 else {
13129 return 0;
13130 }
13131}
13132
13133static const struct rb_iseq_param_keyword *
13134ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13135{
13136 if (param_keyword_offset) {
13137 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13138 int dv_num = kw->num - kw->required_num;
13139 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13140
13141 int i;
13142 for (i=0; i<dv_num; i++) {
13143 dvs[i] = ibf_load_object(load, dvs[i]);
13144 }
13145
13146 // Will be set once the local table is loaded.
13147 kw->table = NULL;
13148
13149 kw->default_values = dvs;
13150 return kw;
13151 }
13152 else {
13153 return NULL;
13154 }
13155}
13156
13157static ibf_offset_t
13158ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13159{
13160 ibf_offset_t offset = ibf_dump_pos(dump);
13161 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13162
13163 unsigned int i;
13164 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13165 ibf_dump_write_small_value(dump, entries[i].line_no);
13166#ifdef USE_ISEQ_NODE_ID
13167 ibf_dump_write_small_value(dump, entries[i].node_id);
13168#endif
13169 ibf_dump_write_small_value(dump, entries[i].events);
13170 }
13171
13172 return offset;
13173}
13174
13175static struct iseq_insn_info_entry *
13176ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13177{
13178 ibf_offset_t reading_pos = body_offset;
13179 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13180
13181 unsigned int i;
13182 for (i = 0; i < size; i++) {
13183 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13184#ifdef USE_ISEQ_NODE_ID
13185 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13186#endif
13187 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13188 }
13189
13190 return entries;
13191}
13192
13193static ibf_offset_t
13194ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13195{
13196 ibf_offset_t offset = ibf_dump_pos(dump);
13197
13198 unsigned int last = 0;
13199 unsigned int i;
13200 for (i = 0; i < size; i++) {
13201 ibf_dump_write_small_value(dump, positions[i] - last);
13202 last = positions[i];
13203 }
13204
13205 return offset;
13206}
13207
13208static unsigned int *
13209ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13210{
13211 ibf_offset_t reading_pos = positions_offset;
13212 unsigned int *positions = ALLOC_N(unsigned int, size);
13213
13214 unsigned int last = 0;
13215 unsigned int i;
13216 for (i = 0; i < size; i++) {
13217 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13218 last = positions[i];
13219 }
13220
13221 return positions;
13222}
13223
13224static ibf_offset_t
13225ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13226{
13227 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13228 const int size = body->local_table_size;
13229 ID *table = ALLOCA_N(ID, size);
13230 int i;
13231
13232 for (i=0; i<size; i++) {
13233 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13234 if (v == 0) {
13235 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13236 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13237 }
13238 table[i] = v;
13239 }
13240
13241 IBF_W_ALIGN(ID);
13242 return ibf_dump_write(dump, table, sizeof(ID) * size);
13243}
13244
13245static const ID *
13246ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13247{
13248 if (size > 0) {
13249 ID *table = IBF_R(local_table_offset, ID, size);
13250 int i;
13251
13252 for (i=0; i<size; i++) {
13253 table[i] = ibf_load_id(load, table[i]);
13254 }
13255
13256 if (size == 1 && table[0] == idERROR_INFO) {
13257 xfree(table);
13258 return rb_iseq_shared_exc_local_tbl;
13259 }
13260 else {
13261 return table;
13262 }
13263 }
13264 else {
13265 return NULL;
13266 }
13267}
13268
13269static ibf_offset_t
13270ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13271{
13272 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13273 const int size = body->local_table_size;
13274 IBF_W_ALIGN(enum lvar_state);
13275 return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
13276}
13277
13278static enum lvar_state *
13279ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13280{
13281 if (local_table == rb_iseq_shared_exc_local_tbl ||
13282 size <= 0) {
13283 return NULL;
13284 }
13285 else {
13286 enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
13287 return states;
13288 }
13289}
13290
13291static ibf_offset_t
13292ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13293{
13294 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13295
13296 if (table) {
13297 int *iseq_indices = ALLOCA_N(int, table->size);
13298 unsigned int i;
13299
13300 for (i=0; i<table->size; i++) {
13301 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13302 }
13303
13304 const ibf_offset_t offset = ibf_dump_pos(dump);
13305
13306 for (i=0; i<table->size; i++) {
13307 ibf_dump_write_small_value(dump, iseq_indices[i]);
13308 ibf_dump_write_small_value(dump, table->entries[i].type);
13309 ibf_dump_write_small_value(dump, table->entries[i].start);
13310 ibf_dump_write_small_value(dump, table->entries[i].end);
13311 ibf_dump_write_small_value(dump, table->entries[i].cont);
13312 ibf_dump_write_small_value(dump, table->entries[i].sp);
13313 }
13314 return offset;
13315 }
13316 else {
13317 return ibf_dump_pos(dump);
13318 }
13319}
13320
13321static void
13322ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13323{
13324 if (size) {
13325 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13326 table->size = size;
13327 ISEQ_BODY(parent_iseq)->catch_table = table;
13328
13329 ibf_offset_t reading_pos = catch_table_offset;
13330
13331 unsigned int i;
13332 for (i=0; i<table->size; i++) {
13333 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13334 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13335 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13336 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13337 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13338 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13339
13340 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13341 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13342 }
13343 }
13344 else {
13345 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13346 }
13347}
13348
13349static ibf_offset_t
13350ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13351{
13352 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13353 const unsigned int ci_size = body->ci_size;
13354 const struct rb_call_data *cds = body->call_data;
13355
13356 ibf_offset_t offset = ibf_dump_pos(dump);
13357
13358 unsigned int i;
13359
13360 for (i = 0; i < ci_size; i++) {
13361 const struct rb_callinfo *ci = cds[i].ci;
13362 if (ci != NULL) {
13363 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13364 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13365 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13366
13367 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13368 if (kwarg) {
13369 int len = kwarg->keyword_len;
13370 ibf_dump_write_small_value(dump, len);
13371 for (int j=0; j<len; j++) {
13372 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13373 ibf_dump_write_small_value(dump, keyword);
13374 }
13375 }
13376 else {
13377 ibf_dump_write_small_value(dump, 0);
13378 }
13379 }
13380 else {
13381 // TODO: truncate NULL ci from call_data.
13382 ibf_dump_write_small_value(dump, (VALUE)-1);
13383 }
13384 }
13385
13386 return offset;
13387}
13388
13390 ID id;
13391 VALUE name;
13392 VALUE val;
13393};
13394
13396 size_t num;
13397 struct outer_variable_pair pairs[1];
13398};
13399
13400static enum rb_id_table_iterator_result
13401store_outer_variable(ID id, VALUE val, void *dump)
13402{
13403 struct outer_variable_list *ovlist = dump;
13404 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13405 pair->id = id;
13406 pair->name = rb_id2str(id);
13407 pair->val = val;
13408 return ID_TABLE_CONTINUE;
13409}
13410
13411static int
13412outer_variable_cmp(const void *a, const void *b, void *arg)
13413{
13414 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13415 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13416
13417 if (!ap->name) {
13418 return -1;
13419 }
13420 else if (!bp->name) {
13421 return 1;
13422 }
13423
13424 return rb_str_cmp(ap->name, bp->name);
13425}
13426
13427static ibf_offset_t
13428ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13429{
13430 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13431
13432 ibf_offset_t offset = ibf_dump_pos(dump);
13433
13434 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13435 ibf_dump_write_small_value(dump, (VALUE)size);
13436 if (size > 0) {
13437 VALUE buff;
13438 size_t buffsize =
13439 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13440 offsetof(struct outer_variable_list, pairs),
13441 rb_eArgError);
13442 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13443 ovlist->num = 0;
13444 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13445 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13446 for (size_t i = 0; i < size; ++i) {
13447 ID id = ovlist->pairs[i].id;
13448 ID val = ovlist->pairs[i].val;
13449 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13450 ibf_dump_write_small_value(dump, val);
13451 }
13452 }
13453
13454 return offset;
13455}
13456
13457/* note that we dump out rb_call_info but load back rb_call_data */
13458static void
13459ibf_load_ci_entries(const struct ibf_load *load,
13460 ibf_offset_t ci_entries_offset,
13461 unsigned int ci_size,
13462 struct rb_call_data **cd_ptr)
13463{
13464 if (!ci_size) {
13465 *cd_ptr = NULL;
13466 return;
13467 }
13468
13469 ibf_offset_t reading_pos = ci_entries_offset;
13470
13471 unsigned int i;
13472
13473 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13474 *cd_ptr = cds;
13475
13476 for (i = 0; i < ci_size; i++) {
13477 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13478 if (mid_index != (VALUE)-1) {
13479 ID mid = ibf_load_id(load, mid_index);
13480 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13481 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13482
13483 struct rb_callinfo_kwarg *kwarg = NULL;
13484 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13485 if (kwlen > 0) {
13486 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13487 kwarg->references = 0;
13488 kwarg->keyword_len = kwlen;
13489 for (int j=0; j<kwlen; j++) {
13490 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13491 kwarg->keywords[j] = ibf_load_object(load, keyword);
13492 }
13493 }
13494
13495 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13496 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13497 cds[i].cc = vm_cc_empty();
13498 }
13499 else {
13500 // NULL ci
13501 cds[i].ci = NULL;
13502 cds[i].cc = NULL;
13503 }
13504 }
13505}
13506
13507static struct rb_id_table *
13508ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13509{
13510 ibf_offset_t reading_pos = outer_variables_offset;
13511
13512 struct rb_id_table *tbl = NULL;
13513
13514 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13515
13516 if (table_size > 0) {
13517 tbl = rb_id_table_create(table_size);
13518 }
13519
13520 for (size_t i = 0; i < table_size; i++) {
13521 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13522 VALUE value = ibf_load_small_value(load, &reading_pos);
13523 if (!key) key = rb_make_temporary_id(i);
13524 rb_id_table_insert(tbl, key, value);
13525 }
13526
13527 return tbl;
13528}
13529
13530static ibf_offset_t
13531ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13532{
13533 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13534
13535 unsigned int *positions;
13536
13537 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13538
13539 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13540 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13541 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13542
13543#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13544 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13545
13546 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13547 struct ibf_dump_buffer buffer;
13548 buffer.str = rb_str_new(0, 0);
13549 buffer.obj_table = ibf_dump_object_table_new();
13550 dump->current_buffer = &buffer;
13551#endif
13552
13553 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13554 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13555 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13556 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13557 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13558
13559 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13560 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13561 ruby_xfree(positions);
13562
13563 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13564 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13565 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13566 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13567 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13568 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13569 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13570 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13571 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13572
13573#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13574 ibf_offset_t local_obj_list_offset;
13575 unsigned int local_obj_list_size;
13576
13577 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13578#endif
13579
13580 ibf_offset_t body_offset = ibf_dump_pos(dump);
13581
13582 /* dump the constant body */
13583 unsigned int param_flags =
13584 (body->param.flags.has_lead << 0) |
13585 (body->param.flags.has_opt << 1) |
13586 (body->param.flags.has_rest << 2) |
13587 (body->param.flags.has_post << 3) |
13588 (body->param.flags.has_kw << 4) |
13589 (body->param.flags.has_kwrest << 5) |
13590 (body->param.flags.has_block << 6) |
13591 (body->param.flags.ambiguous_param0 << 7) |
13592 (body->param.flags.accepts_no_kwarg << 8) |
13593 (body->param.flags.ruby2_keywords << 9) |
13594 (body->param.flags.anon_rest << 10) |
13595 (body->param.flags.anon_kwrest << 11) |
13596 (body->param.flags.use_block << 12) |
13597 (body->param.flags.forwardable << 13) ;
13598
13599#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13600# define IBF_BODY_OFFSET(x) (x)
13601#else
13602# define IBF_BODY_OFFSET(x) (body_offset - (x))
13603#endif
13604
13605 ibf_dump_write_small_value(dump, body->type);
13606 ibf_dump_write_small_value(dump, body->iseq_size);
13607 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13608 ibf_dump_write_small_value(dump, bytecode_size);
13609 ibf_dump_write_small_value(dump, param_flags);
13610 ibf_dump_write_small_value(dump, body->param.size);
13611 ibf_dump_write_small_value(dump, body->param.lead_num);
13612 ibf_dump_write_small_value(dump, body->param.opt_num);
13613 ibf_dump_write_small_value(dump, body->param.rest_start);
13614 ibf_dump_write_small_value(dump, body->param.post_start);
13615 ibf_dump_write_small_value(dump, body->param.post_num);
13616 ibf_dump_write_small_value(dump, body->param.block_start);
13617 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13618 ibf_dump_write_small_value(dump, param_keyword_offset);
13619 ibf_dump_write_small_value(dump, location_pathobj_index);
13620 ibf_dump_write_small_value(dump, location_base_label_index);
13621 ibf_dump_write_small_value(dump, location_label_index);
13622 ibf_dump_write_small_value(dump, body->location.first_lineno);
13623 ibf_dump_write_small_value(dump, body->location.node_id);
13624 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13625 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13626 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13627 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13628 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13629 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13630 ibf_dump_write_small_value(dump, body->insns_info.size);
13631 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13632 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13633 ibf_dump_write_small_value(dump, catch_table_size);
13634 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13635 ibf_dump_write_small_value(dump, parent_iseq_index);
13636 ibf_dump_write_small_value(dump, local_iseq_index);
13637 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13638 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13639 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13640 ibf_dump_write_small_value(dump, body->variable.flip_count);
13641 ibf_dump_write_small_value(dump, body->local_table_size);
13642 ibf_dump_write_small_value(dump, body->ivc_size);
13643 ibf_dump_write_small_value(dump, body->icvarc_size);
13644 ibf_dump_write_small_value(dump, body->ise_size);
13645 ibf_dump_write_small_value(dump, body->ic_size);
13646 ibf_dump_write_small_value(dump, body->ci_size);
13647 ibf_dump_write_small_value(dump, body->stack_max);
13648 ibf_dump_write_small_value(dump, body->builtin_attrs);
13649 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13650
13651#undef IBF_BODY_OFFSET
13652
13653#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13654 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13655
13656 dump->current_buffer = saved_buffer;
13657 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13658
13659 ibf_offset_t offset = ibf_dump_pos(dump);
13660 ibf_dump_write_small_value(dump, iseq_start);
13661 ibf_dump_write_small_value(dump, iseq_length_bytes);
13662 ibf_dump_write_small_value(dump, body_offset);
13663
13664 ibf_dump_write_small_value(dump, local_obj_list_offset);
13665 ibf_dump_write_small_value(dump, local_obj_list_size);
13666
13667 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13668
13669 return offset;
13670#else
13671 return body_offset;
13672#endif
13673}
13674
13675static VALUE
13676ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13677{
13678 VALUE str = ibf_load_object(load, str_index);
13679 if (str != Qnil) {
13680 str = rb_fstring(str);
13681 }
13682 return str;
13683}
13684
13685static void
13686ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13687{
13688 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13689
13690 ibf_offset_t reading_pos = offset;
13691
13692#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13693 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13694 load->current_buffer = &load->global_buffer;
13695
13696 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13697 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13698 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13699
13700 struct ibf_load_buffer buffer;
13701 buffer.buff = load->global_buffer.buff + iseq_start;
13702 buffer.size = iseq_length_bytes;
13703 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13704 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13705 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13706
13707 load->current_buffer = &buffer;
13708 reading_pos = body_offset;
13709#endif
13710
13711#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13712# define IBF_BODY_OFFSET(x) (x)
13713#else
13714# define IBF_BODY_OFFSET(x) (offset - (x))
13715#endif
13716
13717 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13718 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13719 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13720 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13721 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13722 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13723 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13724 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13725 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13726 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13727 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13728 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13729 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13730 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13731 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13732 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13733 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13734 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13735 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13736 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13737 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13738 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13739 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13740 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13741 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13742 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13743 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13744 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13745 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13746 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13747 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13748 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13749 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13750 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13751 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13752 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13753 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13754
13755 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13756 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13757 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13758 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13759
13760 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13761 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13762 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13763 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13764
13765 // setup fname and dummy frame
13766 VALUE path = ibf_load_object(load, location_pathobj_index);
13767 {
13768 VALUE realpath = Qnil;
13769
13770 if (RB_TYPE_P(path, T_STRING)) {
13771 realpath = path = rb_fstring(path);
13772 }
13773 else if (RB_TYPE_P(path, T_ARRAY)) {
13774 VALUE pathobj = path;
13775 if (RARRAY_LEN(pathobj) != 2) {
13776 rb_raise(rb_eRuntimeError, "path object size mismatch");
13777 }
13778 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13779 realpath = RARRAY_AREF(pathobj, 1);
13780 if (!NIL_P(realpath)) {
13781 if (!RB_TYPE_P(realpath, T_STRING)) {
13782 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13783 "(%x), path=%+"PRIsVALUE,
13784 realpath, TYPE(realpath), path);
13785 }
13786 realpath = rb_fstring(realpath);
13787 }
13788 }
13789 else {
13790 rb_raise(rb_eRuntimeError, "unexpected path object");
13791 }
13792 rb_iseq_pathobj_set(iseq, path, realpath);
13793 }
13794
13795 // push dummy frame
13796 rb_execution_context_t *ec = GET_EC();
13797 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13798
13799#undef IBF_BODY_OFFSET
13800
13801 load_body->type = type;
13802 load_body->stack_max = stack_max;
13803 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13804 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13805 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13806 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13807 load_body->param.flags.has_kw = FALSE;
13808 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13809 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13810 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13811 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13812 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13813 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13814 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13815 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13816 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13817 load_body->param.size = param_size;
13818 load_body->param.lead_num = param_lead_num;
13819 load_body->param.opt_num = param_opt_num;
13820 load_body->param.rest_start = param_rest_start;
13821 load_body->param.post_start = param_post_start;
13822 load_body->param.post_num = param_post_num;
13823 load_body->param.block_start = param_block_start;
13824 load_body->local_table_size = local_table_size;
13825 load_body->ci_size = ci_size;
13826 load_body->insns_info.size = insns_info_size;
13827
13828 ISEQ_COVERAGE_SET(iseq, Qnil);
13829 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13830 load_body->variable.flip_count = variable_flip_count;
13831 load_body->variable.script_lines = Qnil;
13832
13833 load_body->location.first_lineno = location_first_lineno;
13834 load_body->location.node_id = location_node_id;
13835 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13836 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13837 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13838 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13839 load_body->builtin_attrs = builtin_attrs;
13840 load_body->prism = prism;
13841
13842 load_body->ivc_size = ivc_size;
13843 load_body->icvarc_size = icvarc_size;
13844 load_body->ise_size = ise_size;
13845 load_body->ic_size = ic_size;
13846
13847 if (ISEQ_IS_SIZE(load_body)) {
13848 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13849 }
13850 else {
13851 load_body->is_entries = NULL;
13852 }
13853 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13854 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13855 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13856 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13857 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13858 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13859 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13860 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13861 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13862 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13863
13864 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13865 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13866 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13867
13868 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13869 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13870 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13871
13872 // This must be done after the local table is loaded.
13873 if (load_body->param.keyword != NULL) {
13874 RUBY_ASSERT(load_body->local_table);
13875 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13876 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13877 }
13878
13879 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13880#if VM_INSN_INFO_TABLE_IMPL == 2
13881 rb_iseq_insns_info_encode_positions(iseq);
13882#endif
13883
13884 rb_iseq_translate_threaded_code(iseq);
13885
13886#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13887 load->current_buffer = &load->global_buffer;
13888#endif
13889
13890 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13891 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13892
13893#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13894 load->current_buffer = saved_buffer;
13895#endif
13896 verify_call_cache(iseq);
13897
13898 RB_GC_GUARD(dummy_frame);
13899 rb_vm_pop_frame_no_int(ec);
13900}
13901
13903{
13904 struct ibf_dump *dump;
13905 VALUE offset_list;
13906};
13907
13908static int
13909ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13910{
13911 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13912 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13913
13914 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13915 rb_ary_push(args->offset_list, UINT2NUM(offset));
13916
13917 return ST_CONTINUE;
13918}
13919
13920static void
13921ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13922{
13923 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13924
13925 struct ibf_dump_iseq_list_arg args;
13926 args.dump = dump;
13927 args.offset_list = offset_list;
13928
13929 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13930
13931 st_index_t i;
13932 st_index_t size = dump->iseq_table->num_entries;
13933 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13934
13935 for (i = 0; i < size; i++) {
13936 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13937 }
13938
13939 ibf_dump_align(dump, sizeof(ibf_offset_t));
13940 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13941 header->iseq_list_size = (unsigned int)size;
13942}
13943
13944#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13945
13946/*
13947 * Binary format
13948 * - ibf_object_header
13949 * - ibf_object_xxx (xxx is type)
13950 */
13951
13953 unsigned int type: 5;
13954 unsigned int special_const: 1;
13955 unsigned int frozen: 1;
13956 unsigned int internal: 1;
13957};
13958
13959enum ibf_object_class_index {
13960 IBF_OBJECT_CLASS_OBJECT,
13961 IBF_OBJECT_CLASS_ARRAY,
13962 IBF_OBJECT_CLASS_STANDARD_ERROR,
13963 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13964 IBF_OBJECT_CLASS_TYPE_ERROR,
13965 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13966};
13967
13969 long srcstr;
13970 char option;
13971};
13972
13974 long len;
13975 long keyval[FLEX_ARY_LEN];
13976};
13977
13979 long class_index;
13980 long len;
13981 long beg;
13982 long end;
13983 int excl;
13984};
13985
13987 ssize_t slen;
13988 BDIGIT digits[FLEX_ARY_LEN];
13989};
13990
13991enum ibf_object_data_type {
13992 IBF_OBJECT_DATA_ENCODING,
13993};
13994
13996 long a, b;
13997};
13998
14000 long str;
14001};
14002
14003#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14004 ((((offset) - 1) / (align) + 1) * (align))
14005/* No cast, since it's UB to create an unaligned pointer.
14006 * Leave as void* for use with memcpy in those cases.
14007 * We align the offset, but the buffer pointer is only VALUE aligned,
14008 * so the returned pointer may be unaligned for `type` .*/
14009#define IBF_OBJBODY(type, offset) \
14010 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14011
14012static const void *
14013ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14014{
14015 if (offset >= load->current_buffer->size) {
14016 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14017 }
14018 return load->current_buffer->buff + offset;
14019}
14020
14021NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14022
14023static void
14024ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14025{
14026 char buff[0x100];
14027 rb_raw_obj_info(buff, sizeof(buff), obj);
14028 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14029}
14030
14031NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14032
14033static VALUE
14034ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14035{
14036 rb_raise(rb_eArgError, "unsupported");
14038}
14039
14040static void
14041ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14042{
14043 enum ibf_object_class_index cindex;
14044 if (obj == rb_cObject) {
14045 cindex = IBF_OBJECT_CLASS_OBJECT;
14046 }
14047 else if (obj == rb_cArray) {
14048 cindex = IBF_OBJECT_CLASS_ARRAY;
14049 }
14050 else if (obj == rb_eStandardError) {
14051 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14052 }
14053 else if (obj == rb_eNoMatchingPatternError) {
14054 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14055 }
14056 else if (obj == rb_eTypeError) {
14057 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14058 }
14059 else if (obj == rb_eNoMatchingPatternKeyError) {
14060 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14061 }
14062 else {
14063 rb_obj_info_dump(obj);
14064 rb_p(obj);
14065 rb_bug("unsupported class");
14066 }
14067 ibf_dump_write_small_value(dump, (VALUE)cindex);
14068}
14069
14070static VALUE
14071ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14072{
14073 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14074
14075 switch (cindex) {
14076 case IBF_OBJECT_CLASS_OBJECT:
14077 return rb_cObject;
14078 case IBF_OBJECT_CLASS_ARRAY:
14079 return rb_cArray;
14080 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14081 return rb_eStandardError;
14082 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14084 case IBF_OBJECT_CLASS_TYPE_ERROR:
14085 return rb_eTypeError;
14086 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14088 }
14089
14090 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14091}
14092
14093
14094static void
14095ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14096{
14097 double dbl = RFLOAT_VALUE(obj);
14098 (void)IBF_W(&dbl, double, 1);
14099}
14100
14101static VALUE
14102ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14103{
14104 double d;
14105 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14106 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14107 return DBL2NUM(d);
14108}
14109
14110static void
14111ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14112{
14113 long encindex = (long)rb_enc_get_index(obj);
14114 long len = RSTRING_LEN(obj);
14115 const char *ptr = RSTRING_PTR(obj);
14116
14117 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14118 rb_encoding *enc = rb_enc_from_index((int)encindex);
14119 const char *enc_name = rb_enc_name(enc);
14120 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14121 }
14122
14123 ibf_dump_write_small_value(dump, encindex);
14124 ibf_dump_write_small_value(dump, len);
14125 IBF_WP(ptr, char, len);
14126}
14127
14128static VALUE
14129ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14130{
14131 ibf_offset_t reading_pos = offset;
14132
14133 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14134 const long len = (long)ibf_load_small_value(load, &reading_pos);
14135 const char *ptr = load->current_buffer->buff + reading_pos;
14136
14137 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14138 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14139 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14140 }
14141
14142 VALUE str;
14143 if (header->frozen && !header->internal) {
14144 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14145 }
14146 else {
14147 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14148
14149 if (header->internal) rb_obj_hide(str);
14150 if (header->frozen) str = rb_fstring(str);
14151 }
14152 return str;
14153}
14154
14155static void
14156ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14157{
14158 VALUE srcstr = RREGEXP_SRC(obj);
14159 struct ibf_object_regexp regexp;
14160 regexp.option = (char)rb_reg_options(obj);
14161 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14162
14163 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14164 ibf_dump_write_small_value(dump, regexp.srcstr);
14165}
14166
14167static VALUE
14168ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14169{
14170 struct ibf_object_regexp regexp;
14171 regexp.option = ibf_load_byte(load, &offset);
14172 regexp.srcstr = ibf_load_small_value(load, &offset);
14173
14174 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14175 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14176
14177 if (header->internal) rb_obj_hide(reg);
14178 if (header->frozen) rb_obj_freeze(reg);
14179
14180 return reg;
14181}
14182
14183static void
14184ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14185{
14186 long i, len = RARRAY_LEN(obj);
14187 ibf_dump_write_small_value(dump, len);
14188 for (i=0; i<len; i++) {
14189 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14190 ibf_dump_write_small_value(dump, index);
14191 }
14192}
14193
14194static VALUE
14195ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14196{
14197 ibf_offset_t reading_pos = offset;
14198
14199 const long len = (long)ibf_load_small_value(load, &reading_pos);
14200
14201 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14202 int i;
14203
14204 for (i=0; i<len; i++) {
14205 const VALUE index = ibf_load_small_value(load, &reading_pos);
14206 rb_ary_push(ary, ibf_load_object(load, index));
14207 }
14208
14209 if (header->frozen) rb_ary_freeze(ary);
14210
14211 return ary;
14212}
14213
14214static int
14215ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14216{
14217 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14218
14219 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14220 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14221
14222 ibf_dump_write_small_value(dump, key_index);
14223 ibf_dump_write_small_value(dump, val_index);
14224 return ST_CONTINUE;
14225}
14226
14227static void
14228ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14229{
14230 long len = RHASH_SIZE(obj);
14231 ibf_dump_write_small_value(dump, (VALUE)len);
14232
14233 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14234}
14235
14236static VALUE
14237ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14238{
14239 long len = (long)ibf_load_small_value(load, &offset);
14240 VALUE obj = rb_hash_new_with_size(len);
14241 int i;
14242
14243 for (i = 0; i < len; i++) {
14244 VALUE key_index = ibf_load_small_value(load, &offset);
14245 VALUE val_index = ibf_load_small_value(load, &offset);
14246
14247 VALUE key = ibf_load_object(load, key_index);
14248 VALUE val = ibf_load_object(load, val_index);
14249 rb_hash_aset(obj, key, val);
14250 }
14251 rb_hash_rehash(obj);
14252
14253 if (header->internal) rb_obj_hide(obj);
14254 if (header->frozen) rb_obj_freeze(obj);
14255
14256 return obj;
14257}
14258
14259static void
14260ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14261{
14262 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14263 struct ibf_object_struct_range range;
14264 VALUE beg, end;
14265 IBF_ZERO(range);
14266 range.len = 3;
14267 range.class_index = 0;
14268
14269 rb_range_values(obj, &beg, &end, &range.excl);
14270 range.beg = (long)ibf_dump_object(dump, beg);
14271 range.end = (long)ibf_dump_object(dump, end);
14272
14273 IBF_W_ALIGN(struct ibf_object_struct_range);
14274 IBF_WV(range);
14275 }
14276 else {
14277 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14278 rb_class_name(CLASS_OF(obj)));
14279 }
14280}
14281
14282static VALUE
14283ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14284{
14285 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14286 VALUE beg = ibf_load_object(load, range->beg);
14287 VALUE end = ibf_load_object(load, range->end);
14288 VALUE obj = rb_range_new(beg, end, range->excl);
14289 if (header->internal) rb_obj_hide(obj);
14290 if (header->frozen) rb_obj_freeze(obj);
14291 return obj;
14292}
14293
14294static void
14295ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14296{
14297 ssize_t len = BIGNUM_LEN(obj);
14298 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14299 BDIGIT *d = BIGNUM_DIGITS(obj);
14300
14301 (void)IBF_W(&slen, ssize_t, 1);
14302 IBF_WP(d, BDIGIT, len);
14303}
14304
14305static VALUE
14306ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14307{
14308 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14309 int sign = bignum->slen > 0;
14310 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14311 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14314 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14315 big_unpack_flags |
14316 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14317 if (header->internal) rb_obj_hide(obj);
14318 if (header->frozen) rb_obj_freeze(obj);
14319 return obj;
14320}
14321
14322static void
14323ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14324{
14325 if (rb_data_is_encoding(obj)) {
14326 rb_encoding *enc = rb_to_encoding(obj);
14327 const char *name = rb_enc_name(enc);
14328 long len = strlen(name) + 1;
14329 long data[2];
14330 data[0] = IBF_OBJECT_DATA_ENCODING;
14331 data[1] = len;
14332 (void)IBF_W(data, long, 2);
14333 IBF_WP(name, char, len);
14334 }
14335 else {
14336 ibf_dump_object_unsupported(dump, obj);
14337 }
14338}
14339
14340static VALUE
14341ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14342{
14343 const long *body = IBF_OBJBODY(long, offset);
14344 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14345 /* const long len = body[1]; */
14346 const char *data = (const char *)&body[2];
14347
14348 switch (type) {
14349 case IBF_OBJECT_DATA_ENCODING:
14350 {
14351 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14352 return encobj;
14353 }
14354 }
14355
14356 return ibf_load_object_unsupported(load, header, offset);
14357}
14358
14359static void
14360ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14361{
14362 long data[2];
14363 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14364 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14365
14366 (void)IBF_W(data, long, 2);
14367}
14368
14369static VALUE
14370ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14371{
14372 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14373 VALUE a = ibf_load_object(load, nums->a);
14374 VALUE b = ibf_load_object(load, nums->b);
14375 VALUE obj = header->type == T_COMPLEX ?
14376 rb_complex_new(a, b) : rb_rational_new(a, b);
14377
14378 if (header->internal) rb_obj_hide(obj);
14379 if (header->frozen) rb_obj_freeze(obj);
14380 return obj;
14381}
14382
14383static void
14384ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14385{
14386 ibf_dump_object_string(dump, rb_sym2str(obj));
14387}
14388
14389static VALUE
14390ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14391{
14392 ibf_offset_t reading_pos = offset;
14393
14394 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14395 const long len = (long)ibf_load_small_value(load, &reading_pos);
14396 const char *ptr = load->current_buffer->buff + reading_pos;
14397
14398 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14399 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14400 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14401 }
14402
14403 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14404 return ID2SYM(id);
14405}
14406
14407typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14408static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14409 ibf_dump_object_unsupported, /* T_NONE */
14410 ibf_dump_object_unsupported, /* T_OBJECT */
14411 ibf_dump_object_class, /* T_CLASS */
14412 ibf_dump_object_unsupported, /* T_MODULE */
14413 ibf_dump_object_float, /* T_FLOAT */
14414 ibf_dump_object_string, /* T_STRING */
14415 ibf_dump_object_regexp, /* T_REGEXP */
14416 ibf_dump_object_array, /* T_ARRAY */
14417 ibf_dump_object_hash, /* T_HASH */
14418 ibf_dump_object_struct, /* T_STRUCT */
14419 ibf_dump_object_bignum, /* T_BIGNUM */
14420 ibf_dump_object_unsupported, /* T_FILE */
14421 ibf_dump_object_data, /* T_DATA */
14422 ibf_dump_object_unsupported, /* T_MATCH */
14423 ibf_dump_object_complex_rational, /* T_COMPLEX */
14424 ibf_dump_object_complex_rational, /* T_RATIONAL */
14425 ibf_dump_object_unsupported, /* 0x10 */
14426 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14427 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14428 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14429 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14430 ibf_dump_object_unsupported, /* T_FIXNUM */
14431 ibf_dump_object_unsupported, /* T_UNDEF */
14432 ibf_dump_object_unsupported, /* 0x17 */
14433 ibf_dump_object_unsupported, /* 0x18 */
14434 ibf_dump_object_unsupported, /* 0x19 */
14435 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14436 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14437 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14438 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14439 ibf_dump_object_unsupported, /* 0x1e */
14440 ibf_dump_object_unsupported, /* 0x1f */
14441};
14442
14443static void
14444ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14445{
14446 unsigned char byte =
14447 (header.type << 0) |
14448 (header.special_const << 5) |
14449 (header.frozen << 6) |
14450 (header.internal << 7);
14451
14452 IBF_WV(byte);
14453}
14454
14455static struct ibf_object_header
14456ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14457{
14458 unsigned char byte = ibf_load_byte(load, offset);
14459
14460 struct ibf_object_header header;
14461 header.type = (byte >> 0) & 0x1f;
14462 header.special_const = (byte >> 5) & 0x01;
14463 header.frozen = (byte >> 6) & 0x01;
14464 header.internal = (byte >> 7) & 0x01;
14465
14466 return header;
14467}
14468
14469static ibf_offset_t
14470ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14471{
14472 struct ibf_object_header obj_header;
14473 ibf_offset_t current_offset;
14474 IBF_ZERO(obj_header);
14475 obj_header.type = TYPE(obj);
14476
14477 IBF_W_ALIGN(ibf_offset_t);
14478 current_offset = ibf_dump_pos(dump);
14479
14480 if (SPECIAL_CONST_P(obj) &&
14481 ! (SYMBOL_P(obj) ||
14482 RB_FLOAT_TYPE_P(obj))) {
14483 obj_header.special_const = TRUE;
14484 obj_header.frozen = TRUE;
14485 obj_header.internal = TRUE;
14486 ibf_dump_object_object_header(dump, obj_header);
14487 ibf_dump_write_small_value(dump, obj);
14488 }
14489 else {
14490 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14491 obj_header.special_const = FALSE;
14492 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14493 ibf_dump_object_object_header(dump, obj_header);
14494 (*dump_object_functions[obj_header.type])(dump, obj);
14495 }
14496
14497 return current_offset;
14498}
14499
14500typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14501static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14502 ibf_load_object_unsupported, /* T_NONE */
14503 ibf_load_object_unsupported, /* T_OBJECT */
14504 ibf_load_object_class, /* T_CLASS */
14505 ibf_load_object_unsupported, /* T_MODULE */
14506 ibf_load_object_float, /* T_FLOAT */
14507 ibf_load_object_string, /* T_STRING */
14508 ibf_load_object_regexp, /* T_REGEXP */
14509 ibf_load_object_array, /* T_ARRAY */
14510 ibf_load_object_hash, /* T_HASH */
14511 ibf_load_object_struct, /* T_STRUCT */
14512 ibf_load_object_bignum, /* T_BIGNUM */
14513 ibf_load_object_unsupported, /* T_FILE */
14514 ibf_load_object_data, /* T_DATA */
14515 ibf_load_object_unsupported, /* T_MATCH */
14516 ibf_load_object_complex_rational, /* T_COMPLEX */
14517 ibf_load_object_complex_rational, /* T_RATIONAL */
14518 ibf_load_object_unsupported, /* 0x10 */
14519 ibf_load_object_unsupported, /* T_NIL */
14520 ibf_load_object_unsupported, /* T_TRUE */
14521 ibf_load_object_unsupported, /* T_FALSE */
14522 ibf_load_object_symbol,
14523 ibf_load_object_unsupported, /* T_FIXNUM */
14524 ibf_load_object_unsupported, /* T_UNDEF */
14525 ibf_load_object_unsupported, /* 0x17 */
14526 ibf_load_object_unsupported, /* 0x18 */
14527 ibf_load_object_unsupported, /* 0x19 */
14528 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14529 ibf_load_object_unsupported, /* T_NODE 0x1b */
14530 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14531 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14532 ibf_load_object_unsupported, /* 0x1e */
14533 ibf_load_object_unsupported, /* 0x1f */
14534};
14535
14536static VALUE
14537ibf_load_object(const struct ibf_load *load, VALUE object_index)
14538{
14539 if (object_index == 0) {
14540 return Qnil;
14541 }
14542 else {
14543 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14544 if (!obj) {
14545 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14546 ibf_offset_t offset = offsets[object_index];
14547 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14548
14549#if IBF_ISEQ_DEBUG
14550 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14551 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14552 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14553 header.type, header.special_const, header.frozen, header.internal);
14554#endif
14555 if (offset >= load->current_buffer->size) {
14556 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14557 }
14558
14559 if (header.special_const) {
14560 ibf_offset_t reading_pos = offset;
14561
14562 obj = ibf_load_small_value(load, &reading_pos);
14563 }
14564 else {
14565 obj = (*load_object_functions[header.type])(load, &header, offset);
14566 }
14567
14568 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14569 }
14570#if IBF_ISEQ_DEBUG
14571 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14572 object_index, obj);
14573#endif
14574 return obj;
14575 }
14576}
14577
14579{
14580 struct ibf_dump *dump;
14581 VALUE offset_list;
14582};
14583
14584static int
14585ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14586{
14587 VALUE obj = (VALUE)key;
14588 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14589
14590 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14591 rb_ary_push(args->offset_list, UINT2NUM(offset));
14592
14593 return ST_CONTINUE;
14594}
14595
14596static void
14597ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14598{
14599 st_table *obj_table = dump->current_buffer->obj_table;
14600 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14601
14602 struct ibf_dump_object_list_arg args;
14603 args.dump = dump;
14604 args.offset_list = offset_list;
14605
14606 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14607
14608 IBF_W_ALIGN(ibf_offset_t);
14609 *obj_list_offset = ibf_dump_pos(dump);
14610
14611 st_index_t size = obj_table->num_entries;
14612 st_index_t i;
14613
14614 for (i=0; i<size; i++) {
14615 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14616 IBF_WV(offset);
14617 }
14618
14619 *obj_list_size = (unsigned int)size;
14620}
14621
14622static void
14623ibf_dump_mark(void *ptr)
14624{
14625 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14626 rb_gc_mark(dump->global_buffer.str);
14627
14628 rb_mark_set(dump->global_buffer.obj_table);
14629 rb_mark_set(dump->iseq_table);
14630}
14631
14632static void
14633ibf_dump_free(void *ptr)
14634{
14635 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14636 if (dump->global_buffer.obj_table) {
14637 st_free_table(dump->global_buffer.obj_table);
14638 dump->global_buffer.obj_table = 0;
14639 }
14640 if (dump->iseq_table) {
14641 st_free_table(dump->iseq_table);
14642 dump->iseq_table = 0;
14643 }
14644}
14645
14646static size_t
14647ibf_dump_memsize(const void *ptr)
14648{
14649 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14650 size_t size = 0;
14651 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14652 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14653 return size;
14654}
14655
14656static const rb_data_type_t ibf_dump_type = {
14657 "ibf_dump",
14658 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14659 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14660};
14661
14662static void
14663ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14664{
14665 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14666 dump->iseq_table = NULL;
14667
14668 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14669 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14670 dump->iseq_table = st_init_numtable(); /* need free */
14671
14672 dump->current_buffer = &dump->global_buffer;
14673}
14674
14675VALUE
14676rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14677{
14678 struct ibf_dump *dump;
14679 struct ibf_header header = {{0}};
14680 VALUE dump_obj;
14681 VALUE str;
14682
14683 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14684 ISEQ_BODY(iseq)->local_iseq != iseq) {
14685 rb_raise(rb_eRuntimeError, "should be top of iseq");
14686 }
14687 if (RTEST(ISEQ_COVERAGE(iseq))) {
14688 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14689 }
14690
14691 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14692 ibf_dump_setup(dump, dump_obj);
14693
14694 ibf_dump_write(dump, &header, sizeof(header));
14695 ibf_dump_iseq(dump, iseq);
14696
14697 header.magic[0] = 'Y'; /* YARB */
14698 header.magic[1] = 'A';
14699 header.magic[2] = 'R';
14700 header.magic[3] = 'B';
14701 header.major_version = IBF_MAJOR_VERSION;
14702 header.minor_version = IBF_MINOR_VERSION;
14703 header.endian = IBF_ENDIAN_MARK;
14704 header.wordsize = (uint8_t)SIZEOF_VALUE;
14705 ibf_dump_iseq_list(dump, &header);
14706 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14707 header.size = ibf_dump_pos(dump);
14708
14709 if (RTEST(opt)) {
14710 VALUE opt_str = opt;
14711 const char *ptr = StringValuePtr(opt_str);
14712 header.extra_size = RSTRING_LENINT(opt_str);
14713 ibf_dump_write(dump, ptr, header.extra_size);
14714 }
14715 else {
14716 header.extra_size = 0;
14717 }
14718
14719 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14720
14721 str = dump->global_buffer.str;
14722 RB_GC_GUARD(dump_obj);
14723 return str;
14724}
14725
14726static const ibf_offset_t *
14727ibf_iseq_list(const struct ibf_load *load)
14728{
14729 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14730}
14731
14732void
14733rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14734{
14735 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14736 rb_iseq_t *prev_src_iseq = load->iseq;
14737 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14738 load->iseq = iseq;
14739#if IBF_ISEQ_DEBUG
14740 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14741 iseq->aux.loader.index, offset,
14742 load->header->size);
14743#endif
14744 ibf_load_iseq_each(load, iseq, offset);
14745 ISEQ_COMPILE_DATA_CLEAR(iseq);
14746 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14747 rb_iseq_init_trace(iseq);
14748 load->iseq = prev_src_iseq;
14749}
14750
14751#if USE_LAZY_LOAD
14752const rb_iseq_t *
14753rb_iseq_complete(const rb_iseq_t *iseq)
14754{
14755 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14756 return iseq;
14757}
14758#endif
14759
14760static rb_iseq_t *
14761ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14762{
14763 int iseq_index = (int)(VALUE)index_iseq;
14764
14765#if IBF_ISEQ_DEBUG
14766 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14767 (void *)index_iseq, (void *)load->iseq_list);
14768#endif
14769 if (iseq_index == -1) {
14770 return NULL;
14771 }
14772 else {
14773 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14774
14775#if IBF_ISEQ_DEBUG
14776 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14777#endif
14778 if (iseqv) {
14779 return (rb_iseq_t *)iseqv;
14780 }
14781 else {
14782 rb_iseq_t *iseq = iseq_imemo_alloc();
14783#if IBF_ISEQ_DEBUG
14784 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14785#endif
14786 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14787 iseq->aux.loader.obj = load->loader_obj;
14788 iseq->aux.loader.index = iseq_index;
14789#if IBF_ISEQ_DEBUG
14790 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14791 (void *)iseq, (void *)load->loader_obj, iseq_index);
14792#endif
14793 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14794
14795 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14796#if IBF_ISEQ_DEBUG
14797 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14798#endif
14799 rb_ibf_load_iseq_complete(iseq);
14800 }
14801
14802#if IBF_ISEQ_DEBUG
14803 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14804 (void *)iseq, (void *)load->iseq);
14805#endif
14806 return iseq;
14807 }
14808 }
14809}
14810
14811static void
14812ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14813{
14814 struct ibf_header *header = (struct ibf_header *)bytes;
14815 load->loader_obj = loader_obj;
14816 load->global_buffer.buff = bytes;
14817 load->header = header;
14818 load->global_buffer.size = header->size;
14819 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14820 load->global_buffer.obj_list_size = header->global_object_list_size;
14821 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14822 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14823 load->iseq = NULL;
14824
14825 load->current_buffer = &load->global_buffer;
14826
14827 if (size < header->size) {
14828 rb_raise(rb_eRuntimeError, "broken binary format");
14829 }
14830 if (strncmp(header->magic, "YARB", 4) != 0) {
14831 rb_raise(rb_eRuntimeError, "unknown binary format");
14832 }
14833 if (header->major_version != IBF_MAJOR_VERSION ||
14834 header->minor_version != IBF_MINOR_VERSION) {
14835 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14836 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14837 }
14838 if (header->endian != IBF_ENDIAN_MARK) {
14839 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14840 }
14841 if (header->wordsize != SIZEOF_VALUE) {
14842 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14843 }
14844 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14845 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14846 header->iseq_list_offset);
14847 }
14848 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14849 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14850 load->global_buffer.obj_list_offset);
14851 }
14852}
14853
14854static void
14855ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14856{
14857 StringValue(str);
14858
14859 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14860 rb_raise(rb_eRuntimeError, "broken binary format");
14861 }
14862
14863 if (USE_LAZY_LOAD) {
14864 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14865 }
14866
14867 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14868 RB_OBJ_WRITE(loader_obj, &load->str, str);
14869}
14870
14871static void
14872ibf_loader_mark(void *ptr)
14873{
14874 struct ibf_load *load = (struct ibf_load *)ptr;
14875 rb_gc_mark(load->str);
14876 rb_gc_mark(load->iseq_list);
14877 rb_gc_mark(load->global_buffer.obj_list);
14878}
14879
14880static void
14881ibf_loader_free(void *ptr)
14882{
14883 struct ibf_load *load = (struct ibf_load *)ptr;
14884 ruby_xfree(load);
14885}
14886
14887static size_t
14888ibf_loader_memsize(const void *ptr)
14889{
14890 return sizeof(struct ibf_load);
14891}
14892
14893static const rb_data_type_t ibf_load_type = {
14894 "ibf_loader",
14895 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14896 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14897};
14898
14899const rb_iseq_t *
14900rb_iseq_ibf_load(VALUE str)
14901{
14902 struct ibf_load *load;
14903 rb_iseq_t *iseq;
14904 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14905
14906 ibf_load_setup(load, loader_obj, str);
14907 iseq = ibf_load_iseq(load, 0);
14908
14909 RB_GC_GUARD(loader_obj);
14910 return iseq;
14911}
14912
14913const rb_iseq_t *
14914rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14915{
14916 struct ibf_load *load;
14917 rb_iseq_t *iseq;
14918 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14919
14920 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14921 iseq = ibf_load_iseq(load, 0);
14922
14923 RB_GC_GUARD(loader_obj);
14924 return iseq;
14925}
14926
14927VALUE
14928rb_iseq_ibf_load_extra_data(VALUE str)
14929{
14930 struct ibf_load *load;
14931 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14932 VALUE extra_str;
14933
14934 ibf_load_setup(load, loader_obj, str);
14935 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14936 RB_GC_GUARD(loader_obj);
14937 return extra_str;
14938}
14939
14940#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#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:134
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#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 NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:696
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_cHash
Hash class.
Definition hash.c:109
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:687
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:910
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1329
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#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:1079
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1839
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:69
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4220
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3772
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1721
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4135
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4121
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3540
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3738
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4189
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:4009
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3253
#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:1513
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:498
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:974
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:993
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:943
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1428
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:521
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:456
#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:503
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9068
#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:30
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:286
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:257
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:209
struct rb_iseq_constant_body::@157 param
parameter information
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145