Ruby 4.0.7p0 (2026-09-15 revision 229531a6cfbf07e3caef30dbac24a2a3f3fed482)
compile.c
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/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;
63} LINK_ELEMENT;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
68} LINK_ANCHOR;
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
140
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
613static VALUE
614setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
615{
616 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
617 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
618 VALUE branch = rb_ary_hidden_new(6);
619
620 rb_hash_aset(structure, key, branch);
621 rb_ary_push(branch, ID2SYM(rb_intern(type)));
622 rb_ary_push(branch, INT2FIX(first_lineno));
623 rb_ary_push(branch, INT2FIX(first_column));
624 rb_ary_push(branch, INT2FIX(last_lineno));
625 rb_ary_push(branch, INT2FIX(last_column));
626 return branch;
627}
628
629static VALUE
630decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
631{
632 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
633
634 /*
635 * if !structure[node]
636 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
637 * else
638 * branches = structure[node][5]
639 * end
640 */
641
642 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
643 VALUE branch_base = rb_hash_aref(structure, key);
644 VALUE branches;
645
646 if (NIL_P(branch_base)) {
647 branch_base = setup_branch(loc, type, structure, key);
648 branches = rb_hash_new();
649 rb_obj_hide(branches);
650 rb_ary_push(branch_base, branches);
651 }
652 else {
653 branches = RARRAY_AREF(branch_base, 5);
654 }
655
656 return branches;
657}
658
659static NODE
660generate_dummy_line_node(int lineno, int node_id)
661{
662 NODE dummy = { 0 };
663 nd_set_line(&dummy, lineno);
664 nd_set_node_id(&dummy, node_id);
665 return dummy;
666}
667
668static void
669add_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)
670{
671 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
672
673 /*
674 * if !branches[branch_id]
675 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
676 * else
677 * counter_idx= branches[branch_id][5]
678 * end
679 */
680
681 VALUE key = INT2FIX(branch_id);
682 VALUE branch = rb_hash_aref(branches, key);
683 long counter_idx;
684
685 if (NIL_P(branch)) {
686 branch = setup_branch(loc, type, branches, key);
687 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
688 counter_idx = RARRAY_LEN(counters);
689 rb_ary_push(branch, LONG2FIX(counter_idx));
690 rb_ary_push(counters, INT2FIX(0));
691 }
692 else {
693 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
694 }
695
696 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
697 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724static NODE *
725get_nd_recv(const NODE *node)
726{
727 switch (nd_type(node)) {
728 case NODE_CALL:
729 return RNODE_CALL(node)->nd_recv;
730 case NODE_OPCALL:
731 return RNODE_OPCALL(node)->nd_recv;
732 case NODE_FCALL:
733 return 0;
734 case NODE_QCALL:
735 return RNODE_QCALL(node)->nd_recv;
736 case NODE_VCALL:
737 return 0;
738 case NODE_ATTRASGN:
739 return RNODE_ATTRASGN(node)->nd_recv;
740 case NODE_OP_ASGN1:
741 return RNODE_OP_ASGN1(node)->nd_recv;
742 case NODE_OP_ASGN2:
743 return RNODE_OP_ASGN2(node)->nd_recv;
744 default:
745 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
746 }
747}
748
749static ID
750get_node_call_nd_mid(const NODE *node)
751{
752 switch (nd_type(node)) {
753 case NODE_CALL:
754 return RNODE_CALL(node)->nd_mid;
755 case NODE_OPCALL:
756 return RNODE_OPCALL(node)->nd_mid;
757 case NODE_FCALL:
758 return RNODE_FCALL(node)->nd_mid;
759 case NODE_QCALL:
760 return RNODE_QCALL(node)->nd_mid;
761 case NODE_VCALL:
762 return RNODE_VCALL(node)->nd_mid;
763 case NODE_ATTRASGN:
764 return RNODE_ATTRASGN(node)->nd_mid;
765 default:
766 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
767 }
768}
769
770static NODE *
771get_nd_args(const NODE *node)
772{
773 switch (nd_type(node)) {
774 case NODE_CALL:
775 return RNODE_CALL(node)->nd_args;
776 case NODE_OPCALL:
777 return RNODE_OPCALL(node)->nd_args;
778 case NODE_FCALL:
779 return RNODE_FCALL(node)->nd_args;
780 case NODE_QCALL:
781 return RNODE_QCALL(node)->nd_args;
782 case NODE_VCALL:
783 return 0;
784 case NODE_ATTRASGN:
785 return RNODE_ATTRASGN(node)->nd_args;
786 default:
787 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
788 }
789}
790
791static ID
792get_node_colon_nd_mid(const NODE *node)
793{
794 switch (nd_type(node)) {
795 case NODE_COLON2:
796 return RNODE_COLON2(node)->nd_mid;
797 case NODE_COLON3:
798 return RNODE_COLON3(node)->nd_mid;
799 default:
800 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
801 }
802}
803
804static ID
805get_nd_vid(const NODE *node)
806{
807 switch (nd_type(node)) {
808 case NODE_LASGN:
809 return RNODE_LASGN(node)->nd_vid;
810 case NODE_DASGN:
811 return RNODE_DASGN(node)->nd_vid;
812 case NODE_IASGN:
813 return RNODE_IASGN(node)->nd_vid;
814 case NODE_CVASGN:
815 return RNODE_CVASGN(node)->nd_vid;
816 default:
817 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
818 }
819}
820
821static NODE *
822get_nd_value(const NODE *node)
823{
824 switch (nd_type(node)) {
825 case NODE_LASGN:
826 return RNODE_LASGN(node)->nd_value;
827 case NODE_DASGN:
828 return RNODE_DASGN(node)->nd_value;
829 default:
830 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
831 }
832}
833
834static VALUE
835get_string_value(const NODE *node)
836{
837 switch (nd_type(node)) {
838 case NODE_STR:
839 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
840 case NODE_FILE:
841 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
842 default:
843 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
844 }
845}
846
847VALUE
848rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
849{
850 DECL_ANCHOR(ret);
851 INIT_ANCHOR(ret);
852
853 (*ifunc->func)(iseq, ret, ifunc->data);
854
855 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
856
857 CHECK(iseq_setup_insn(iseq, ret));
858 return iseq_setup(iseq, ret);
859}
860
861static bool drop_unreachable_return(LINK_ANCHOR *ret);
862
863VALUE
864rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
865{
866 DECL_ANCHOR(ret);
867 INIT_ANCHOR(ret);
868
869 if (node == 0) {
870 NO_CHECK(COMPILE(ret, "nil", node));
871 iseq_set_local_table(iseq, 0, 0);
872 }
873 /* assume node is T_NODE */
874 else if (nd_type_p(node, NODE_SCOPE)) {
875 /* iseq type of top, method, class, block */
876 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
877 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_parameters_lvar_state(iseq);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(&OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1402 RBASIC_CLASS(*obj) == 0 || // hidden
1403 RB_OBJ_SHAREABLE_P(*obj));
1404}
1405
1406static INSN *
1407new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1408{
1409 INSN *iobj = compile_data_alloc_insn(iseq);
1410
1411 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1412
1413 iobj->link.type = ISEQ_ELEMENT_INSN;
1414 iobj->link.next = 0;
1415 iobj->insn_id = insn_id;
1416 iobj->insn_info.line_no = line_no;
1417 iobj->insn_info.node_id = node_id;
1418 iobj->insn_info.events = 0;
1419 iobj->operands = argv;
1420 iobj->operand_size = argc;
1421 iobj->sc_state = 0;
1422
1423 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1424
1425 return iobj;
1426}
1427
1428static INSN *
1429new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1430{
1431 VALUE *operands = 0;
1432 va_list argv;
1433 if (argc > 0) {
1434 int i;
1435 va_start(argv, argc);
1436 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1437 for (i = 0; i < argc; i++) {
1438 VALUE v = va_arg(argv, VALUE);
1439 operands[i] = v;
1440 }
1441 va_end(argv);
1442 }
1443 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1444}
1445
1446static INSN *
1447insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1448{
1449 VALUE *operands = 0;
1450 va_list argv;
1451 if (argc > 0) {
1452 int i;
1453 va_start(argv, argc);
1454 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1455 for (i = 0; i < argc; i++) {
1456 VALUE v = va_arg(argv, VALUE);
1457 operands[i] = v;
1458 }
1459 va_end(argv);
1460 }
1461
1462 iobj->insn_id = insn_id;
1463 iobj->operand_size = argc;
1464 iobj->operands = operands;
1465 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1466
1467 return iobj;
1468}
1469
1470static const struct rb_callinfo *
1471new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1472{
1473 VM_ASSERT(argc >= 0);
1474
1475 if (kw_arg) {
1476 flag |= VM_CALL_KWARG;
1477 argc += kw_arg->keyword_len;
1478 }
1479
1480 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1481 && !has_blockiseq) {
1482 flag |= VM_CALL_ARGS_SIMPLE;
1483 }
1484
1485 ISEQ_BODY(iseq)->ci_size++;
1486 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1487 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1488 return ci;
1489}
1490
1491static INSN *
1492new_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)
1493{
1494 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1495 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1496 operands[0] = ci;
1497 operands[1] = (VALUE)blockiseq;
1498 if (blockiseq) {
1499 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1500 }
1501
1502 INSN *insn;
1503
1504 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1506 }
1507 else {
1508 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1509 }
1510
1511 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1512 RB_GC_GUARD(ci);
1513 return insn;
1514}
1515
1516static rb_iseq_t *
1517new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1518 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1519{
1520 rb_iseq_t *ret_iseq;
1521 VALUE ast_value = rb_ruby_ast_new(node);
1522
1523 debugs("[new_child_iseq]> ---------------------------------------\n");
1524 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1525 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1526 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1527 line_no, parent,
1528 isolated_depth ? isolated_depth + 1 : 0,
1529 type, ISEQ_COMPILE_DATA(iseq)->option,
1530 ISEQ_BODY(iseq)->variable.script_lines);
1531 debugs("[new_child_iseq]< ---------------------------------------\n");
1532 return ret_iseq;
1533}
1534
1535static rb_iseq_t *
1536new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1537 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1538{
1539 rb_iseq_t *ret_iseq;
1540
1541 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1542 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1543 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1544 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1545 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1546 return ret_iseq;
1547}
1548
1549static void
1550set_catch_except_p(rb_iseq_t *iseq)
1551{
1552 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1553 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1554 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1555 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1556 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1557 }
1558 }
1559}
1560
1561/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1562 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1563 if catch table exists. But we want to optimize while loop, which always has catch
1564 table entries for break/next/redo.
1565
1566 So this function sets true for limited ISeqs with break/next/redo catch table entries
1567 whose child ISeq would really raise an exception. */
1568static void
1569update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1570{
1571 unsigned int pos;
1572 size_t i;
1573 int insn;
1574 const struct iseq_catch_table *ct = body->catch_table;
1575
1576 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1577 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1578 pos = 0;
1579 while (pos < body->iseq_size) {
1580 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1581 if (insn == BIN(throw)) {
1582 set_catch_except_p(iseq);
1583 break;
1584 }
1585 pos += insn_len(insn);
1586 }
1587
1588 if (ct == NULL)
1589 return;
1590
1591 for (i = 0; i < ct->size; i++) {
1592 const struct iseq_catch_table_entry *entry =
1593 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1594 if (entry->type != CATCH_TYPE_BREAK
1595 && entry->type != CATCH_TYPE_NEXT
1596 && entry->type != CATCH_TYPE_REDO) {
1597 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1598 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1599 break;
1600 }
1601 }
1602}
1603
1604static void
1605iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1606{
1607 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1608 if (NIL_P(catch_table_ary)) return;
1609 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1610 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1611 for (i = 0; i < tlen; i++) {
1612 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1613 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1614 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1615 LINK_ELEMENT *e;
1616
1617 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1618
1619 if (ct != CATCH_TYPE_BREAK
1620 && ct != CATCH_TYPE_NEXT
1621 && ct != CATCH_TYPE_REDO) {
1622
1623 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1624 if (e == cont) {
1625 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1626 ELEM_INSERT_NEXT(end, &nop->link);
1627 break;
1628 }
1629 }
1630 }
1631 }
1632
1633 RB_GC_GUARD(catch_table_ary);
1634}
1635
1636static int
1637iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1638{
1639 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1640 return COMPILE_NG;
1641
1642 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1643
1644 if (compile_debug > 5)
1645 dump_disasm_list(FIRST_ELEMENT(anchor));
1646
1647 debugs("[compile step 3.1 (iseq_optimize)]\n");
1648 iseq_optimize(iseq, anchor);
1649
1650 if (compile_debug > 5)
1651 dump_disasm_list(FIRST_ELEMENT(anchor));
1652
1653 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1654 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1655 iseq_insns_unification(iseq, anchor);
1656 if (compile_debug > 5)
1657 dump_disasm_list(FIRST_ELEMENT(anchor));
1658 }
1659
1660 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1661 iseq_insert_nop_between_end_and_cont(iseq);
1662 if (compile_debug > 5)
1663 dump_disasm_list(FIRST_ELEMENT(anchor));
1664
1665 return COMPILE_OK;
1666}
1667
1668static int
1669iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1670{
1671 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1672 return COMPILE_NG;
1673
1674 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1675 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1676 if (compile_debug > 5)
1677 dump_disasm_list(FIRST_ELEMENT(anchor));
1678
1679 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1680 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1681
1682 debugs("[compile step 4.3 (set_optargs_table)] \n");
1683 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1684
1685 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1686 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1687
1688 debugs("[compile step 6 (update_catch_except_flags)] \n");
1689 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1690 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1691
1692 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1693 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1694 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1695 xfree(ISEQ_BODY(iseq)->catch_table);
1696 ISEQ_BODY(iseq)->catch_table = NULL;
1697 }
1698
1699#if VM_INSN_INFO_TABLE_IMPL == 2
1700 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1701 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1702 rb_iseq_insns_info_encode_positions(iseq);
1703 }
1704#endif
1705
1706 if (compile_debug > 1) {
1707 VALUE str = rb_iseq_disasm(iseq);
1708 printf("%s\n", StringValueCStr(str));
1709 }
1710 verify_call_cache(iseq);
1711 debugs("[compile step: finish]\n");
1712
1713 return COMPILE_OK;
1714}
1715
1716static int
1717iseq_set_exception_local_table(rb_iseq_t *iseq)
1718{
1719 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1720 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1721 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1722 return COMPILE_OK;
1723}
1724
1725static int
1726get_lvar_level(const rb_iseq_t *iseq)
1727{
1728 int lev = 0;
1729 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1730 lev++;
1731 iseq = ISEQ_BODY(iseq)->parent_iseq;
1732 }
1733 return lev;
1734}
1735
1736static int
1737get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1738{
1739 unsigned int i;
1740
1741 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1742 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1743 return (int)i;
1744 }
1745 }
1746 return -1;
1747}
1748
1749static int
1750get_local_var_idx(const rb_iseq_t *iseq, ID id)
1751{
1752 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1753
1754 if (idx < 0) {
1755 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1756 "get_local_var_idx: %d", idx);
1757 }
1758
1759 return idx;
1760}
1761
1762static int
1763get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1764{
1765 int lv = 0, idx = -1;
1766 const rb_iseq_t *const topmost_iseq = iseq;
1767
1768 while (iseq) {
1769 idx = get_dyna_var_idx_at_raw(iseq, id);
1770 if (idx >= 0) {
1771 break;
1772 }
1773 iseq = ISEQ_BODY(iseq)->parent_iseq;
1774 lv++;
1775 }
1776
1777 if (idx < 0) {
1778 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1779 "get_dyna_var_idx: -1");
1780 }
1781
1782 *level = lv;
1783 *ls = ISEQ_BODY(iseq)->local_table_size;
1784 return idx;
1785}
1786
1787static int
1788iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1789{
1790 const struct rb_iseq_constant_body *body;
1791 while (level > 0) {
1792 iseq = ISEQ_BODY(iseq)->parent_iseq;
1793 level--;
1794 }
1795 body = ISEQ_BODY(iseq);
1796 if (body->local_iseq == iseq && /* local variables */
1797 body->param.flags.has_block &&
1798 body->local_table_size - body->param.block_start == idx) {
1799 return TRUE;
1800 }
1801 else {
1802 return FALSE;
1803 }
1804}
1805
1806static int
1807iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1808{
1809 int level, ls;
1810 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1811 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1812 *pidx = ls - idx;
1813 *plevel = level;
1814 return TRUE;
1815 }
1816 else {
1817 return FALSE;
1818 }
1819}
1820
1821static void
1822access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1823{
1824 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1825
1826 if (isolated_depth && level >= isolated_depth) {
1827 if (id == rb_intern("yield")) {
1828 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1829 }
1830 else {
1831 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1832 }
1833 }
1834
1835 for (int i=0; i<level; i++) {
1836 VALUE val;
1837 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1838
1839 if (!ovs) {
1840 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1841 }
1842
1843 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1844 if (write && !val) {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1846 }
1847 }
1848 else {
1849 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1850 }
1851
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1853 }
1854}
1855
1856static ID
1857iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1858{
1859 for (int i=0; i<level; i++) {
1860 iseq = ISEQ_BODY(iseq)->parent_iseq;
1861 }
1862
1863 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1864 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1865 return id;
1866}
1867
1868static void
1869update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1870{
1871 for (int i=0; i<level; i++) {
1872 iseq = ISEQ_BODY(iseq)->parent_iseq;
1873 }
1874
1875 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1876 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1877 switch (states[table_idx]) {
1878 case lvar_uninitialized:
1879 states[table_idx] = lvar_initialized;
1880 break;
1881 case lvar_initialized:
1882 states[table_idx] = lvar_reassigned;
1883 break;
1884 case lvar_reassigned:
1885 /* nothing */
1886 break;
1887 default:
1888 rb_bug("unreachable");
1889 }
1890}
1891
1892static int
1893iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1894{
1895 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1896 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1897 }
1898
1899 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1900 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1901 for (int i=0; i<opt_num; i++) {
1902 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1903 }
1904
1905 return COMPILE_OK;
1906}
1907
1908static void
1909iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1910{
1911 if (iseq_local_block_param_p(iseq, idx, level)) {
1912 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1913 }
1914 else {
1915 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1916 }
1917 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1918}
1919
1920static void
1921iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1922{
1923 if (iseq_local_block_param_p(iseq, idx, level)) {
1924 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1925 }
1926 else {
1927 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1928 }
1929 update_lvar_state(iseq, level, idx);
1930 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1931}
1932
1933
1934
1935static void
1936iseq_calc_param_size(rb_iseq_t *iseq)
1937{
1938 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1939 if (body->param.flags.has_opt ||
1940 body->param.flags.has_post ||
1941 body->param.flags.has_rest ||
1942 body->param.flags.has_block ||
1943 body->param.flags.has_kw ||
1944 body->param.flags.has_kwrest) {
1945
1946 if (body->param.flags.has_block) {
1947 body->param.size = body->param.block_start + 1;
1948 }
1949 else if (body->param.flags.has_kwrest) {
1950 body->param.size = body->param.keyword->rest_start + 1;
1951 }
1952 else if (body->param.flags.has_kw) {
1953 body->param.size = body->param.keyword->bits_start + 1;
1954 }
1955 else if (body->param.flags.has_post) {
1956 body->param.size = body->param.post_start + body->param.post_num;
1957 }
1958 else if (body->param.flags.has_rest) {
1959 body->param.size = body->param.rest_start + 1;
1960 }
1961 else if (body->param.flags.has_opt) {
1962 body->param.size = body->param.lead_num + body->param.opt_num;
1963 }
1964 else {
1966 }
1967 }
1968 else {
1969 body->param.size = body->param.lead_num;
1970 }
1971}
1972
1973static int
1974iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1975 const struct rb_args_info *args, int arg_size)
1976{
1977 const rb_node_kw_arg_t *node = args->kw_args;
1978 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1979 struct rb_iseq_param_keyword *keyword;
1980 const VALUE default_values = rb_ary_hidden_new(1);
1981 const VALUE complex_mark = rb_str_tmp_new(0);
1982 int kw = 0, rkw = 0, di = 0, i;
1983
1984 body->param.flags.has_kw = TRUE;
1985 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1986
1987 while (node) {
1988 kw++;
1989 node = node->nd_next;
1990 }
1991 if (kw > VM_CALL_KW_LEN_MAX) {
1992 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args)) "too many keyword parameters (%d, maximum is %d)",
1993 kw, (int)VM_CALL_KW_LEN_MAX);
1994 }
1995 arg_size += kw;
1996 keyword->bits_start = arg_size++;
1997
1998 node = args->kw_args;
1999 while (node) {
2000 const NODE *val_node = get_nd_value(node->nd_body);
2001 VALUE dv;
2002
2003 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2004 ++rkw;
2005 }
2006 else {
2007 switch (nd_type(val_node)) {
2008 case NODE_SYM:
2009 dv = rb_node_sym_string_val(val_node);
2010 break;
2011 case NODE_REGX:
2012 dv = rb_node_regx_string_val(val_node);
2013 break;
2014 case NODE_LINE:
2015 dv = rb_node_line_lineno_val(val_node);
2016 break;
2017 case NODE_INTEGER:
2018 dv = rb_node_integer_literal_val(val_node);
2019 break;
2020 case NODE_FLOAT:
2021 dv = rb_node_float_literal_val(val_node);
2022 break;
2023 case NODE_RATIONAL:
2024 dv = rb_node_rational_literal_val(val_node);
2025 break;
2026 case NODE_IMAGINARY:
2027 dv = rb_node_imaginary_literal_val(val_node);
2028 break;
2029 case NODE_ENCODING:
2030 dv = rb_node_encoding_val(val_node);
2031 break;
2032 case NODE_NIL:
2033 dv = Qnil;
2034 break;
2035 case NODE_TRUE:
2036 dv = Qtrue;
2037 break;
2038 case NODE_FALSE:
2039 dv = Qfalse;
2040 break;
2041 default:
2042 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2043 dv = complex_mark;
2044 }
2045
2046 keyword->num = ++di;
2047 rb_ary_push(default_values, dv);
2048 }
2049
2050 node = node->nd_next;
2051 }
2052
2053 keyword->num = kw;
2054
2055 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2056 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2057 keyword->rest_start = arg_size++;
2058 body->param.flags.has_kwrest = TRUE;
2059
2060 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2061 }
2062 keyword->required_num = rkw;
2063 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2064
2065 if (RARRAY_LEN(default_values)) {
2066 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2067
2068 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2069 VALUE dv = RARRAY_AREF(default_values, i);
2070 if (dv == complex_mark) dv = Qundef;
2072 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2073 }
2074
2075 keyword->default_values = dvs;
2076 }
2077 return arg_size;
2078}
2079
2080static void
2081iseq_set_use_block(rb_iseq_t *iseq)
2082{
2083 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2084 if (!body->param.flags.use_block) {
2085 body->param.flags.use_block = 1;
2086
2087 rb_vm_t *vm = GET_VM();
2088
2089 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2090 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2091 set_insert(vm->unused_block_warning_table, key);
2092 }
2093 }
2094}
2095
2096static int
2097iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2098{
2099 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2100
2101 if (node_args) {
2102 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2103 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2104 ID rest_id = 0;
2105 int last_comma = 0;
2106 ID block_id = 0;
2107 int arg_size;
2108
2109 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2110
2111 body->param.lead_num = arg_size = (int)args->pre_args_num;
2112 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2113 debugs(" - argc: %d\n", body->param.lead_num);
2114
2115 rest_id = args->rest_arg;
2116 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2117 last_comma = 1;
2118 rest_id = 0;
2119 }
2120 block_id = args->block_arg;
2121
2122 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2123
2124 if (optimized_forward) {
2125 rest_id = 0;
2126 block_id = 0;
2127 }
2128
2129 if (args->opt_args) {
2130 const rb_node_opt_arg_t *node = args->opt_args;
2131 LABEL *label;
2132 VALUE labels = rb_ary_hidden_new(1);
2133 VALUE *opt_table;
2134 int i = 0, j;
2135
2136 while (node) {
2137 label = NEW_LABEL(nd_line(RNODE(node)));
2138 rb_ary_push(labels, (VALUE)label | 1);
2139 ADD_LABEL(optargs, label);
2140 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2141 node = node->nd_next;
2142 i += 1;
2143 }
2144
2145 /* last label */
2146 label = NEW_LABEL(nd_line(node_args));
2147 rb_ary_push(labels, (VALUE)label | 1);
2148 ADD_LABEL(optargs, label);
2149
2150 opt_table = ALLOC_N(VALUE, i+1);
2151
2152 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2153 for (j = 0; j < i+1; j++) {
2154 opt_table[j] &= ~1;
2155 }
2156 rb_ary_clear(labels);
2157
2158 body->param.flags.has_opt = TRUE;
2159 body->param.opt_num = i;
2160 body->param.opt_table = opt_table;
2161 arg_size += i;
2162 }
2163
2164 if (rest_id) {
2165 body->param.rest_start = arg_size++;
2166 body->param.flags.has_rest = TRUE;
2167 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2168 RUBY_ASSERT(body->param.rest_start != -1);
2169 }
2170
2171 if (args->first_post_arg) {
2172 body->param.post_start = arg_size;
2173 body->param.post_num = args->post_args_num;
2174 body->param.flags.has_post = TRUE;
2175 arg_size += args->post_args_num;
2176
2177 if (body->param.flags.has_rest) { /* TODO: why that? */
2178 body->param.post_start = body->param.rest_start + 1;
2179 }
2180 }
2181
2182 if (args->kw_args) {
2183 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2184 }
2185 else if (args->kw_rest_arg && !optimized_forward) {
2186 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2187 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2188 keyword->rest_start = arg_size++;
2189 body->param.keyword = keyword;
2190 body->param.flags.has_kwrest = TRUE;
2191
2192 static ID anon_kwrest = 0;
2193 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2194 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2195 }
2196 else if (args->no_kwarg) {
2197 body->param.flags.accepts_no_kwarg = TRUE;
2198 }
2199
2200 if (block_id) {
2201 body->param.block_start = arg_size++;
2202 body->param.flags.has_block = TRUE;
2203 iseq_set_use_block(iseq);
2204 }
2205
2206 // Only optimize specifically methods like this: `foo(...)`
2207 if (optimized_forward) {
2208 body->param.flags.use_block = 1;
2209 body->param.flags.forwardable = TRUE;
2210 arg_size = 1;
2211 }
2212
2213 iseq_calc_param_size(iseq);
2214 body->param.size = arg_size;
2215
2216 if (args->pre_init) { /* m_init */
2217 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2218 }
2219 if (args->post_init) { /* p_init */
2220 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2221 }
2222
2223 if (body->type == ISEQ_TYPE_BLOCK) {
2224 if (body->param.flags.has_opt == FALSE &&
2225 body->param.flags.has_post == FALSE &&
2226 body->param.flags.has_rest == FALSE &&
2227 body->param.flags.has_kw == FALSE &&
2228 body->param.flags.has_kwrest == FALSE) {
2229
2230 if (body->param.lead_num == 1 && last_comma == 0) {
2231 /* {|a|} */
2232 body->param.flags.ambiguous_param0 = TRUE;
2233 }
2234 }
2235 }
2236 }
2237
2238 return COMPILE_OK;
2239}
2240
2241static int
2242iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2243{
2244 unsigned int size = tbl ? tbl->size : 0;
2245 unsigned int offset = 0;
2246
2247 if (node_args) {
2248 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2249
2250 // If we have a function that only has `...` as the parameter,
2251 // then its local table should only be `...`
2252 // FIXME: I think this should be fixed in the AST rather than special case here.
2253 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2254 CHECK(size >= 3);
2255 size -= 3;
2256 offset += 3;
2257 }
2258 }
2259
2260 if (size > 0) {
2261 ID *ids = ALLOC_N(ID, size);
2262 MEMCPY(ids, tbl->ids + offset, ID, size);
2263 ISEQ_BODY(iseq)->local_table = ids;
2264
2265 enum lvar_state *states = ALLOC_N(enum lvar_state, size);
2266 // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
2267 for (unsigned int i=0; i<size; i++) {
2268 states[i] = lvar_uninitialized;
2269 // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
2270 }
2271 ISEQ_BODY(iseq)->lvar_states = states;
2272 }
2273 ISEQ_BODY(iseq)->local_table_size = size;
2274
2275 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2276 return COMPILE_OK;
2277}
2278
2279int
2280rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2281{
2282 int tval, tlit;
2283
2284 if (val == lit) {
2285 return 0;
2286 }
2287 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2288 return val != lit;
2289 }
2290 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2291 return -1;
2292 }
2293 else if (tlit != tval) {
2294 return -1;
2295 }
2296 else if (tlit == T_SYMBOL) {
2297 return val != lit;
2298 }
2299 else if (tlit == T_STRING) {
2300 return rb_str_hash_cmp(lit, val);
2301 }
2302 else if (tlit == T_BIGNUM) {
2303 long x = FIX2LONG(rb_big_cmp(lit, val));
2304
2305 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2306 * There is no need to call rb_fix2int here. */
2307 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2308 return (int)x;
2309 }
2310 else if (tlit == T_FLOAT) {
2311 return rb_float_cmp(lit, val);
2312 }
2313 else if (tlit == T_RATIONAL) {
2314 const struct RRational *rat1 = RRATIONAL(val);
2315 const struct RRational *rat2 = RRATIONAL(lit);
2316 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2317 }
2318 else if (tlit == T_COMPLEX) {
2319 const struct RComplex *comp1 = RCOMPLEX(val);
2320 const struct RComplex *comp2 = RCOMPLEX(lit);
2321 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2322 }
2323 else if (tlit == T_REGEXP) {
2324 return rb_reg_equal(val, lit) ? 0 : -1;
2325 }
2326 else {
2328 }
2329}
2330
2331st_index_t
2332rb_iseq_cdhash_hash(VALUE a)
2333{
2334 switch (OBJ_BUILTIN_TYPE(a)) {
2335 case -1:
2336 case T_SYMBOL:
2337 return (st_index_t)a;
2338 case T_STRING:
2339 return rb_str_hash(a);
2340 case T_BIGNUM:
2341 return FIX2LONG(rb_big_hash(a));
2342 case T_FLOAT:
2343 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2344 case T_RATIONAL:
2345 return rb_rational_hash(a);
2346 case T_COMPLEX:
2347 return rb_complex_hash(a);
2348 case T_REGEXP:
2349 return NUM2LONG(rb_reg_hash(a));
2350 default:
2352 }
2353}
2354
2355static const struct st_hash_type cdhash_type = {
2356 rb_iseq_cdhash_cmp,
2357 rb_iseq_cdhash_hash,
2358};
2359
2361 VALUE hash;
2362 int pos;
2363 int len;
2364};
2365
2366static int
2367cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2368{
2369 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2370 LABEL *lobj = (LABEL *)(val & ~1);
2371 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2372 return ST_CONTINUE;
2373}
2374
2375
2376static inline VALUE
2377get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2378{
2379 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2380}
2381
2382static inline VALUE
2383get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2384{
2385 VALUE val;
2386 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2387 if (tbl) {
2388 if (rb_id_table_lookup(tbl,id,&val)) {
2389 return val;
2390 }
2391 }
2392 else {
2393 tbl = rb_id_table_create(1);
2394 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2395 }
2396 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2397 rb_id_table_insert(tbl,id,val);
2398 return val;
2399}
2400
2401#define BADINSN_DUMP(anchor, list, dest) \
2402 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2403
2404#define BADINSN_ERROR \
2405 (xfree(generated_iseq), \
2406 xfree(insns_info), \
2407 BADINSN_DUMP(anchor, list, NULL), \
2408 COMPILE_ERROR)
2409
2410static int
2411fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2412{
2413 int stack_max = 0, sp = 0, line = 0;
2414 LINK_ELEMENT *list;
2415
2416 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2417 if (IS_LABEL(list)) {
2418 LABEL *lobj = (LABEL *)list;
2419 lobj->set = TRUE;
2420 }
2421 }
2422
2423 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2424 switch (list->type) {
2425 case ISEQ_ELEMENT_INSN:
2426 {
2427 int j, len, insn;
2428 const char *types;
2429 VALUE *operands;
2430 INSN *iobj = (INSN *)list;
2431
2432 /* update sp */
2433 sp = calc_sp_depth(sp, iobj);
2434 if (sp < 0) {
2435 BADINSN_DUMP(anchor, list, NULL);
2436 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2437 "argument stack underflow (%d)", sp);
2438 return -1;
2439 }
2440 if (sp > stack_max) {
2441 stack_max = sp;
2442 }
2443
2444 line = iobj->insn_info.line_no;
2445 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2446 operands = iobj->operands;
2447 insn = iobj->insn_id;
2448 types = insn_op_types(insn);
2449 len = insn_len(insn);
2450
2451 /* operand check */
2452 if (iobj->operand_size != len - 1) {
2453 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2454 BADINSN_DUMP(anchor, list, NULL);
2455 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2456 "operand size miss! (%d for %d)",
2457 iobj->operand_size, len - 1);
2458 return -1;
2459 }
2460
2461 for (j = 0; types[j]; j++) {
2462 if (types[j] == TS_OFFSET) {
2463 /* label(destination position) */
2464 LABEL *lobj = (LABEL *)operands[j];
2465 if (!lobj->set) {
2466 BADINSN_DUMP(anchor, list, NULL);
2467 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2468 "unknown label: "LABEL_FORMAT, lobj->label_no);
2469 return -1;
2470 }
2471 if (lobj->sp == -1) {
2472 lobj->sp = sp;
2473 }
2474 else if (lobj->sp != sp) {
2475 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2476 RSTRING_PTR(rb_iseq_path(iseq)), line,
2477 lobj->label_no, lobj->sp, sp);
2478 }
2479 }
2480 }
2481 break;
2482 }
2483 case ISEQ_ELEMENT_LABEL:
2484 {
2485 LABEL *lobj = (LABEL *)list;
2486 if (lobj->sp == -1) {
2487 lobj->sp = sp;
2488 }
2489 else {
2490 if (lobj->sp != sp) {
2491 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2492 RSTRING_PTR(rb_iseq_path(iseq)), line,
2493 lobj->label_no, lobj->sp, sp);
2494 }
2495 sp = lobj->sp;
2496 }
2497 break;
2498 }
2499 case ISEQ_ELEMENT_TRACE:
2500 {
2501 /* ignore */
2502 break;
2503 }
2504 case ISEQ_ELEMENT_ADJUST:
2505 {
2506 ADJUST *adjust = (ADJUST *)list;
2507 int orig_sp = sp;
2508
2509 sp = adjust->label ? adjust->label->sp : 0;
2510 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2511 BADINSN_DUMP(anchor, list, NULL);
2512 COMPILE_ERROR(iseq, adjust->line_no,
2513 "iseq_set_sequence: adjust bug %d < %d",
2514 orig_sp, sp);
2515 return -1;
2516 }
2517 break;
2518 }
2519 default:
2520 BADINSN_DUMP(anchor, list, NULL);
2521 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2522 return -1;
2523 }
2524 }
2525 return stack_max;
2526}
2527
2528static int
2529add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2530 int insns_info_index, int code_index, const INSN *iobj)
2531{
2532 if (insns_info_index == 0 ||
2533 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2534#ifdef USE_ISEQ_NODE_ID
2535 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2536#endif
2537 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2538 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2539#ifdef USE_ISEQ_NODE_ID
2540 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2541#endif
2542 insns_info[insns_info_index].events = iobj->insn_info.events;
2543 positions[insns_info_index] = code_index;
2544 return TRUE;
2545 }
2546 return FALSE;
2547}
2548
2549static int
2550add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2551 int insns_info_index, int code_index, const ADJUST *adjust)
2552{
2553 insns_info[insns_info_index].line_no = adjust->line_no;
2554 insns_info[insns_info_index].node_id = -1;
2555 insns_info[insns_info_index].events = 0;
2556 positions[insns_info_index] = code_index;
2557 return TRUE;
2558}
2559
2560static ID *
2561array_to_idlist(VALUE arr)
2562{
2563 RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2564 long size = RARRAY_LEN(arr);
2565 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2566 for (long i = 0; i < size; i++) {
2567 VALUE sym = RARRAY_AREF(arr, i);
2568 ids[i] = SYM2ID(sym);
2569 }
2570 ids[size] = 0;
2571 return ids;
2572}
2573
2574static VALUE
2575idlist_to_array(const ID *ids)
2576{
2577 VALUE arr = rb_ary_new();
2578 while (*ids) {
2579 rb_ary_push(arr, ID2SYM(*ids++));
2580 }
2581 return arr;
2582}
2583
2587static int
2588iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2589{
2590 struct iseq_insn_info_entry *insns_info;
2591 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2592 unsigned int *positions;
2593 LINK_ELEMENT *list;
2594 VALUE *generated_iseq;
2595 rb_event_flag_t events = 0;
2596 long data = 0;
2597
2598 int insn_num, code_index, insns_info_index, sp = 0;
2599 int stack_max = fix_sp_depth(iseq, anchor);
2600
2601 if (stack_max < 0) return COMPILE_NG;
2602
2603 /* fix label position */
2604 insn_num = code_index = 0;
2605 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2606 switch (list->type) {
2607 case ISEQ_ELEMENT_INSN:
2608 {
2609 INSN *iobj = (INSN *)list;
2610 /* update sp */
2611 sp = calc_sp_depth(sp, iobj);
2612 insn_num++;
2613 events = iobj->insn_info.events |= events;
2614 if (ISEQ_COVERAGE(iseq)) {
2615 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2616 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2617 int line = iobj->insn_info.line_no - 1;
2618 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2619 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2620 }
2621 }
2622 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2623 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2624 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2625 }
2626 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2627 }
2628 }
2629 code_index += insn_data_length(iobj);
2630 events = 0;
2631 data = 0;
2632 break;
2633 }
2634 case ISEQ_ELEMENT_LABEL:
2635 {
2636 LABEL *lobj = (LABEL *)list;
2637 lobj->position = code_index;
2638 if (lobj->sp != sp) {
2639 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2640 RSTRING_PTR(rb_iseq_path(iseq)),
2641 lobj->label_no, lobj->sp, sp);
2642 }
2643 sp = lobj->sp;
2644 break;
2645 }
2646 case ISEQ_ELEMENT_TRACE:
2647 {
2648 TRACE *trace = (TRACE *)list;
2649 events |= trace->event;
2650 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2651 break;
2652 }
2653 case ISEQ_ELEMENT_ADJUST:
2654 {
2655 ADJUST *adjust = (ADJUST *)list;
2656 if (adjust->line_no != -1) {
2657 int orig_sp = sp;
2658 sp = adjust->label ? adjust->label->sp : 0;
2659 if (orig_sp - sp > 0) {
2660 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2661 code_index++; /* insn */
2662 insn_num++;
2663 }
2664 }
2665 break;
2666 }
2667 default: break;
2668 }
2669 }
2670
2671 /* make instruction sequence */
2672 generated_iseq = ALLOC_N(VALUE, code_index);
2673 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2674 positions = ALLOC_N(unsigned int, insn_num);
2675 if (ISEQ_IS_SIZE(body)) {
2676 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2677 }
2678 else {
2679 body->is_entries = NULL;
2680 }
2681
2682 if (body->ci_size) {
2683 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2684 }
2685 else {
2686 body->call_data = NULL;
2687 }
2688 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2689
2690 // Calculate the bitmask buffer size.
2691 // Round the generated_iseq size up to the nearest multiple
2692 // of the number of bits in an unsigned long.
2693
2694 // Allocate enough room for the bitmask list
2695 iseq_bits_t * mark_offset_bits;
2696 int code_size = code_index;
2697
2698 bool needs_bitmap = false;
2699
2700 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2701 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2702 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2703 }
2704 else {
2705 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2706 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2707 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2708 }
2709
2710 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2711 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2712
2713 list = FIRST_ELEMENT(anchor);
2714 insns_info_index = code_index = sp = 0;
2715
2716 while (list) {
2717 switch (list->type) {
2718 case ISEQ_ELEMENT_INSN:
2719 {
2720 int j, len, insn;
2721 const char *types;
2722 VALUE *operands;
2723 INSN *iobj = (INSN *)list;
2724
2725 /* update sp */
2726 sp = calc_sp_depth(sp, iobj);
2727 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2728 operands = iobj->operands;
2729 insn = iobj->insn_id;
2730 generated_iseq[code_index] = insn;
2731 types = insn_op_types(insn);
2732 len = insn_len(insn);
2733
2734 for (j = 0; types[j]; j++) {
2735 char type = types[j];
2736
2737 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2738 switch (type) {
2739 case TS_OFFSET:
2740 {
2741 /* label(destination position) */
2742 LABEL *lobj = (LABEL *)operands[j];
2743 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2744 break;
2745 }
2746 case TS_CDHASH:
2747 {
2748 VALUE map = operands[j];
2749 struct cdhash_set_label_struct data;
2750 data.hash = map;
2751 data.pos = code_index;
2752 data.len = len;
2753 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2754
2755 rb_hash_rehash(map);
2756 freeze_hide_obj(map);
2758 generated_iseq[code_index + 1 + j] = map;
2759 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2760 RB_OBJ_WRITTEN(iseq, Qundef, map);
2761 needs_bitmap = true;
2762 break;
2763 }
2764 case TS_LINDEX:
2765 case TS_NUM: /* ulong */
2766 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2767 break;
2768 case TS_ISEQ: /* iseq */
2769 case TS_VALUE: /* VALUE */
2770 {
2771 VALUE v = operands[j];
2772 generated_iseq[code_index + 1 + j] = v;
2773 /* to mark ruby object */
2774 if (!SPECIAL_CONST_P(v)) {
2775 RB_OBJ_WRITTEN(iseq, Qundef, v);
2776 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2777 needs_bitmap = true;
2778 }
2779 break;
2780 }
2781 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2782 case TS_IC: /* inline cache: constants */
2783 {
2784 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2785 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2786 if (UNLIKELY(ic_index >= body->ic_size)) {
2787 BADINSN_DUMP(anchor, &iobj->link, 0);
2788 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2789 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2790 ic_index, ISEQ_IS_SIZE(body));
2791 }
2792
2793 ic->segments = array_to_idlist(operands[j]);
2794
2795 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2796 }
2797 break;
2798 case TS_IVC: /* inline ivar cache */
2799 {
2800 unsigned int ic_index = FIX2UINT(operands[j]);
2801
2802 IVC cache = ((IVC)&body->is_entries[ic_index]);
2803
2804 if (insn == BIN(setinstancevariable)) {
2805 cache->iv_set_name = SYM2ID(operands[j - 1]);
2806 }
2807 else {
2808 cache->iv_set_name = 0;
2809 }
2810
2811 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2812 }
2813 case TS_ISE: /* inline storage entry: `once` insn */
2814 case TS_ICVARC: /* inline cvar cache */
2815 {
2816 unsigned int ic_index = FIX2UINT(operands[j]);
2817 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2818 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2819 BADINSN_DUMP(anchor, &iobj->link, 0);
2820 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2821 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2822 ic_index, ISEQ_IS_SIZE(body));
2823 }
2824 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2825
2826 break;
2827 }
2828 case TS_CALLDATA:
2829 {
2830 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2831 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2832 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2833 cd->ci = source_ci;
2834 cd->cc = vm_cc_empty();
2835 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2836 break;
2837 }
2838 case TS_ID: /* ID */
2839 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2840 break;
2841 case TS_FUNCPTR:
2842 generated_iseq[code_index + 1 + j] = operands[j];
2843 break;
2844 case TS_BUILTIN:
2845 generated_iseq[code_index + 1 + j] = operands[j];
2846 break;
2847 default:
2848 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2849 "unknown operand type: %c", type);
2850 return COMPILE_NG;
2851 }
2852 }
2853 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2854 code_index += len;
2855 break;
2856 }
2857 case ISEQ_ELEMENT_LABEL:
2858 {
2859 LABEL *lobj = (LABEL *)list;
2860 if (lobj->sp != sp) {
2861 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2862 RSTRING_PTR(rb_iseq_path(iseq)),
2863 lobj->label_no, lobj->sp, sp);
2864 }
2865 sp = lobj->sp;
2866 break;
2867 }
2868 case ISEQ_ELEMENT_ADJUST:
2869 {
2870 ADJUST *adjust = (ADJUST *)list;
2871 int orig_sp = sp;
2872
2873 if (adjust->label) {
2874 sp = adjust->label->sp;
2875 }
2876 else {
2877 sp = 0;
2878 }
2879
2880 if (adjust->line_no != -1) {
2881 const int diff = orig_sp - sp;
2882 if (diff > 0) {
2883 if (insns_info_index == 0) {
2884 COMPILE_ERROR(iseq, adjust->line_no,
2885 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2886 }
2887 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2888 }
2889 if (diff > 1) {
2890 generated_iseq[code_index++] = BIN(adjuststack);
2891 generated_iseq[code_index++] = orig_sp - sp;
2892 }
2893 else if (diff == 1) {
2894 generated_iseq[code_index++] = BIN(pop);
2895 }
2896 else if (diff < 0) {
2897 int label_no = adjust->label ? adjust->label->label_no : -1;
2898 xfree(generated_iseq);
2899 xfree(insns_info);
2900 xfree(positions);
2901 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2902 xfree(mark_offset_bits);
2903 }
2904 debug_list(anchor, list);
2905 COMPILE_ERROR(iseq, adjust->line_no,
2906 "iseq_set_sequence: adjust bug to %d %d < %d",
2907 label_no, orig_sp, sp);
2908 return COMPILE_NG;
2909 }
2910 }
2911 break;
2912 }
2913 default:
2914 /* ignore */
2915 break;
2916 }
2917 list = list->next;
2918 }
2919
2920 body->iseq_encoded = (void *)generated_iseq;
2921 body->iseq_size = code_index;
2922 body->stack_max = stack_max;
2923
2924 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2925 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2926 }
2927 else {
2928 if (needs_bitmap) {
2929 body->mark_bits.list = mark_offset_bits;
2930 }
2931 else {
2932 body->mark_bits.list = NULL;
2933 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2934 ruby_xfree(mark_offset_bits);
2935 }
2936 }
2937
2938 /* get rid of memory leak when REALLOC failed */
2939 body->insns_info.body = insns_info;
2940 body->insns_info.positions = positions;
2941
2942 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2943 body->insns_info.body = insns_info;
2944 REALLOC_N(positions, unsigned int, insns_info_index);
2945 body->insns_info.positions = positions;
2946 body->insns_info.size = insns_info_index;
2947
2948 return COMPILE_OK;
2949}
2950
2951static int
2952label_get_position(LABEL *lobj)
2953{
2954 return lobj->position;
2955}
2956
2957static int
2958label_get_sp(LABEL *lobj)
2959{
2960 return lobj->sp;
2961}
2962
2963static int
2964iseq_set_exception_table(rb_iseq_t *iseq)
2965{
2966 const VALUE *tptr, *ptr;
2967 unsigned int tlen, i;
2968 struct iseq_catch_table_entry *entry;
2969
2970 ISEQ_BODY(iseq)->catch_table = NULL;
2971
2972 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2973 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2974 tlen = (int)RARRAY_LEN(catch_table_ary);
2975 tptr = RARRAY_CONST_PTR(catch_table_ary);
2976
2977 if (tlen > 0) {
2978 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2979 table->size = tlen;
2980
2981 for (i = 0; i < table->size; i++) {
2982 int pos;
2983 ptr = RARRAY_CONST_PTR(tptr[i]);
2984 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2985 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2986 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2987 RUBY_ASSERT(pos >= 0);
2988 entry->start = (unsigned int)pos;
2989 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2990 RUBY_ASSERT(pos >= 0);
2991 entry->end = (unsigned int)pos;
2992 entry->iseq = (rb_iseq_t *)ptr[3];
2993 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2994
2995 /* stack depth */
2996 if (ptr[4]) {
2997 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2998 entry->cont = label_get_position(lobj);
2999 entry->sp = label_get_sp(lobj);
3000
3001 /* TODO: Dirty Hack! Fix me */
3002 if (entry->type == CATCH_TYPE_RESCUE ||
3003 entry->type == CATCH_TYPE_BREAK ||
3004 entry->type == CATCH_TYPE_NEXT) {
3005 RUBY_ASSERT(entry->sp > 0);
3006 entry->sp--;
3007 }
3008 }
3009 else {
3010 entry->cont = 0;
3011 }
3012 }
3013 ISEQ_BODY(iseq)->catch_table = table;
3014 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3015 }
3016
3017 RB_GC_GUARD(catch_table_ary);
3018
3019 return COMPILE_OK;
3020}
3021
3022/*
3023 * set optional argument table
3024 * def foo(a, b=expr1, c=expr2)
3025 * =>
3026 * b:
3027 * expr1
3028 * c:
3029 * expr2
3030 */
3031static int
3032iseq_set_optargs_table(rb_iseq_t *iseq)
3033{
3034 int i;
3035 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3036
3037 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3038 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3039 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3040 }
3041 }
3042 return COMPILE_OK;
3043}
3044
3045static LINK_ELEMENT *
3046get_destination_insn(INSN *iobj)
3047{
3048 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3049 LINK_ELEMENT *list;
3050 rb_event_flag_t events = 0;
3051
3052 list = lobj->link.next;
3053 while (list) {
3054 switch (list->type) {
3055 case ISEQ_ELEMENT_INSN:
3056 case ISEQ_ELEMENT_ADJUST:
3057 goto found;
3058 case ISEQ_ELEMENT_LABEL:
3059 /* ignore */
3060 break;
3061 case ISEQ_ELEMENT_TRACE:
3062 {
3063 TRACE *trace = (TRACE *)list;
3064 events |= trace->event;
3065 }
3066 break;
3067 default: break;
3068 }
3069 list = list->next;
3070 }
3071 found:
3072 if (list && IS_INSN(list)) {
3073 INSN *iobj = (INSN *)list;
3074 iobj->insn_info.events |= events;
3075 }
3076 return list;
3077}
3078
3079static LINK_ELEMENT *
3080get_next_insn(INSN *iobj)
3081{
3082 LINK_ELEMENT *list = iobj->link.next;
3083
3084 while (list) {
3085 if (IS_INSN(list) || IS_ADJUST(list)) {
3086 return list;
3087 }
3088 list = list->next;
3089 }
3090 return 0;
3091}
3092
3093static LINK_ELEMENT *
3094get_prev_insn(INSN *iobj)
3095{
3096 LINK_ELEMENT *list = iobj->link.prev;
3097
3098 while (list) {
3099 if (IS_INSN(list) || IS_ADJUST(list)) {
3100 return list;
3101 }
3102 list = list->prev;
3103 }
3104 return 0;
3105}
3106
3107static void
3108unref_destination(INSN *iobj, int pos)
3109{
3110 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3111 --lobj->refcnt;
3112 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3113}
3114
3115static bool
3116replace_destination(INSN *dobj, INSN *nobj)
3117{
3118 VALUE n = OPERAND_AT(nobj, 0);
3119 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3120 LABEL *nl = (LABEL *)n;
3121 if (dl == nl) return false;
3122 --dl->refcnt;
3123 ++nl->refcnt;
3124 OPERAND_AT(dobj, 0) = n;
3125 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3126 return true;
3127}
3128
3129static LABEL*
3130find_destination(INSN *i)
3131{
3132 int pos, len = insn_len(i->insn_id);
3133 for (pos = 0; pos < len; ++pos) {
3134 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3135 return (LABEL *)OPERAND_AT(i, pos);
3136 }
3137 }
3138 return 0;
3139}
3140
3141static int
3142remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3143{
3144 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3145 LABEL *pending = 0;
3146 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3147
3148 if (!i) return 0;
3149 unref_counts = ALLOCA_N(int, nlabels);
3150 MEMZERO(unref_counts, int, nlabels);
3151
3152 end = i;
3153 scan = i;
3154 do {
3155 LABEL *lab;
3156 if (IS_INSN(scan)) {
3157 if (IS_INSN_ID(scan, leave)) {
3158 if (pending) break;
3159 end = scan;
3160 break;
3161 }
3162 else if ((lab = find_destination((INSN *)scan)) != 0) {
3163 unref_counts[lab->label_no]++;
3164 if (lab == pending && lab->refcnt <= unref_counts[lab->label_no]) {
3165 pending = 0;
3166 }
3167 }
3168 }
3169 else if (IS_LABEL(scan)) {
3170 lab = (LABEL *)scan;
3171 if (lab->unremovable) {
3172 if (pending) break;
3173 return 0;
3174 }
3175 if (lab->refcnt > unref_counts[lab->label_no]) {
3176 if (pending) break;
3177 pending = lab;
3178 pending_end = (scan == first) ? 0 : end;
3179 }
3180 continue;
3181 }
3182 else if (IS_ADJUST(scan)) {
3183 if (pending) break;
3184 return 0;
3185 }
3186 if (!pending) end = scan;
3187 } while ((scan = scan->next) != 0);
3188
3189 if (pending) {
3190 if (!pending_end) return 0;
3191 end = pending_end;
3192 }
3193 i = first;
3194 do {
3195 if (IS_INSN(i)) {
3196 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3197 VALUE insn = INSN_OF(i);
3198 int pos, len = insn_len(insn);
3199 for (pos = 0; pos < len; ++pos) {
3200 switch (insn_op_types(insn)[pos]) {
3201 case TS_OFFSET:
3202 unref_destination((INSN *)i, pos);
3203 break;
3204 case TS_CALLDATA:
3205 --(body->ci_size);
3206 break;
3207 }
3208 }
3209 }
3210 ELEM_REMOVE(i);
3211 } while ((i != end) && (i = i->next) != 0);
3212 return 1;
3213}
3214
3215static int
3216iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3217{
3218 switch (OPERAND_AT(iobj, 0)) {
3219 case INT2FIX(0): /* empty array */
3220 ELEM_REMOVE(&iobj->link);
3221 return TRUE;
3222 case INT2FIX(1): /* single element array */
3223 ELEM_REMOVE(&iobj->link);
3224 return FALSE;
3225 default:
3226 iobj->insn_id = BIN(adjuststack);
3227 return TRUE;
3228 }
3229}
3230
3231static int
3232is_frozen_putstring(INSN *insn, VALUE *op)
3233{
3234 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3235 *op = OPERAND_AT(insn, 0);
3236 return 1;
3237 }
3238 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3239 *op = OPERAND_AT(insn, 0);
3240 return RB_TYPE_P(*op, T_STRING);
3241 }
3242 return 0;
3243}
3244
3245static int
3246insn_has_label_before(LINK_ELEMENT *elem)
3247{
3248 LINK_ELEMENT *prev = elem->prev;
3249 while (prev) {
3250 if (prev->type == ISEQ_ELEMENT_LABEL) {
3251 LABEL *label = (LABEL *)prev;
3252 if (label->refcnt > 0) {
3253 return 1;
3254 }
3255 }
3256 else if (prev->type == ISEQ_ELEMENT_INSN) {
3257 break;
3258 }
3259 prev = prev->prev;
3260 }
3261 return 0;
3262}
3263
3264static int
3265optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3266{
3267 /*
3268 * putobject obj
3269 * dup
3270 * checktype T_XXX
3271 * branchif l1
3272 * l2:
3273 * ...
3274 * l1:
3275 *
3276 * => obj is a T_XXX
3277 *
3278 * putobject obj (T_XXX)
3279 * jump L1
3280 * L1:
3281 *
3282 * => obj is not a T_XXX
3283 *
3284 * putobject obj (T_XXX)
3285 * jump L2
3286 * L2:
3287 */
3288 int line, node_id;
3289 INSN *niobj, *ciobj, *dup = 0;
3290 LABEL *dest = 0;
3291 VALUE type;
3292
3293 switch (INSN_OF(iobj)) {
3294 case BIN(putstring):
3295 case BIN(putchilledstring):
3297 break;
3298 case BIN(putnil):
3299 type = INT2FIX(T_NIL);
3300 break;
3301 case BIN(putobject):
3302 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3303 break;
3304 default: return FALSE;
3305 }
3306
3307 ciobj = (INSN *)get_next_insn(iobj);
3308 if (IS_INSN_ID(ciobj, jump)) {
3309 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3310 }
3311 if (IS_INSN_ID(ciobj, dup)) {
3312 ciobj = (INSN *)get_next_insn(dup = ciobj);
3313 }
3314 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3315 niobj = (INSN *)get_next_insn(ciobj);
3316 if (!niobj) {
3317 /* TODO: putobject true/false */
3318 return FALSE;
3319 }
3320 switch (INSN_OF(niobj)) {
3321 case BIN(branchif):
3322 if (OPERAND_AT(ciobj, 0) == type) {
3323 dest = (LABEL *)OPERAND_AT(niobj, 0);
3324 }
3325 break;
3326 case BIN(branchunless):
3327 if (OPERAND_AT(ciobj, 0) != type) {
3328 dest = (LABEL *)OPERAND_AT(niobj, 0);
3329 }
3330 break;
3331 default:
3332 return FALSE;
3333 }
3334 line = ciobj->insn_info.line_no;
3335 node_id = ciobj->insn_info.node_id;
3336 if (!dest) {
3337 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3338 dest = (LABEL *)niobj->link.next; /* reuse label */
3339 }
3340 else {
3341 dest = NEW_LABEL(line);
3342 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3343 }
3344 }
3345 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3346 LABEL_REF(dest);
3347 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3348 return TRUE;
3349}
3350
3351static const struct rb_callinfo *
3352ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3353{
3354 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3355 vm_ci_flag(ci) | add,
3356 vm_ci_argc(ci),
3357 vm_ci_kwarg(ci));
3358 RB_OBJ_WRITTEN(iseq, ci, nci);
3359 return nci;
3360}
3361
3362static const struct rb_callinfo *
3363ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3364{
3365 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3366 vm_ci_flag(ci),
3367 argc,
3368 vm_ci_kwarg(ci));
3369 RB_OBJ_WRITTEN(iseq, ci, nci);
3370 return nci;
3371}
3372
3373#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3374
3375static VALUE
3376iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3377{
3378 VALUE errinfo = rb_errinfo();
3379 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3380 if (NIL_P(re)) {
3381 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3382 rb_set_errinfo(errinfo);
3383 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3384 }
3385 else {
3386 RB_OBJ_SET_SHAREABLE(re);
3387 }
3388 return re;
3389}
3390
3391static int
3392iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3393{
3394 INSN *const iobj = (INSN *)list;
3395
3396 again:
3397 optimize_checktype(iseq, iobj);
3398
3399 if (IS_INSN_ID(iobj, jump)) {
3400 INSN *niobj, *diobj, *piobj;
3401 diobj = (INSN *)get_destination_insn(iobj);
3402 niobj = (INSN *)get_next_insn(iobj);
3403
3404 if (diobj == niobj) {
3405 /*
3406 * jump LABEL
3407 * LABEL:
3408 * =>
3409 * LABEL:
3410 */
3411 unref_destination(iobj, 0);
3412 ELEM_REMOVE(&iobj->link);
3413 return COMPILE_OK;
3414 }
3415 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3416 IS_INSN_ID(diobj, jump) &&
3417 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3418 diobj->insn_info.events == 0) {
3419 /*
3420 * useless jump elimination:
3421 * jump LABEL1
3422 * ...
3423 * LABEL1:
3424 * jump LABEL2
3425 *
3426 * => in this case, first jump instruction should jump to
3427 * LABEL2 directly
3428 */
3429 if (replace_destination(iobj, diobj)) {
3430 remove_unreachable_chunk(iseq, iobj->link.next);
3431 goto again;
3432 }
3433 }
3434 else if (IS_INSN_ID(diobj, leave)) {
3435 /*
3436 * jump LABEL
3437 * ...
3438 * LABEL:
3439 * leave
3440 * =>
3441 * leave
3442 * ...
3443 * LABEL:
3444 * leave
3445 */
3446 /* replace */
3447 unref_destination(iobj, 0);
3448 iobj->insn_id = BIN(leave);
3449 iobj->operand_size = 0;
3450 iobj->insn_info = diobj->insn_info;
3451 goto again;
3452 }
3453 else if (IS_INSN(iobj->link.prev) &&
3454 (piobj = (INSN *)iobj->link.prev) &&
3455 (IS_INSN_ID(piobj, branchif) ||
3456 IS_INSN_ID(piobj, branchunless))) {
3457 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3458 if (niobj == pdiobj) {
3459 int refcnt = IS_LABEL(piobj->link.next) ?
3460 ((LABEL *)piobj->link.next)->refcnt : 0;
3461 /*
3462 * useless jump elimination (if/unless destination):
3463 * if L1
3464 * jump L2
3465 * L1:
3466 * ...
3467 * L2:
3468 *
3469 * ==>
3470 * unless L2
3471 * L1:
3472 * ...
3473 * L2:
3474 */
3475 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3476 ? BIN(branchunless) : BIN(branchif);
3477 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3478 ELEM_REMOVE(&iobj->link);
3479 }
3480 else {
3481 /* TODO: replace other branch destinations too */
3482 }
3483 return COMPILE_OK;
3484 }
3485 else if (diobj == pdiobj) {
3486 /*
3487 * useless jump elimination (if/unless before jump):
3488 * L1:
3489 * ...
3490 * if L1
3491 * jump L1
3492 *
3493 * ==>
3494 * L1:
3495 * ...
3496 * pop
3497 * jump L1
3498 */
3499 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3500 ELEM_REPLACE(&piobj->link, &popiobj->link);
3501 }
3502 }
3503 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3504 goto again;
3505 }
3506 }
3507
3508 /*
3509 * putstring "beg"
3510 * putstring "end"
3511 * newrange excl
3512 *
3513 * ==>
3514 *
3515 * putobject "beg".."end"
3516 */
3517 if (IS_INSN_ID(iobj, newrange)) {
3518 INSN *const range = iobj;
3519 INSN *beg, *end;
3520 VALUE str_beg, str_end;
3521
3522 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3523 is_frozen_putstring(end, &str_end) &&
3524 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3525 is_frozen_putstring(beg, &str_beg) &&
3526 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3527 int excl = FIX2INT(OPERAND_AT(range, 0));
3528 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3529
3530 ELEM_REMOVE(&beg->link);
3531 ELEM_REMOVE(&end->link);
3532 range->insn_id = BIN(putobject);
3533 OPERAND_AT(range, 0) = lit_range;
3534 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3535 }
3536 }
3537
3538 if (IS_INSN_ID(iobj, leave)) {
3539 remove_unreachable_chunk(iseq, iobj->link.next);
3540 }
3541
3542 /*
3543 * ...
3544 * duparray [...]
3545 * concatarray | concattoarray
3546 * =>
3547 * ...
3548 * putobject [...]
3549 * concatarray | concattoarray
3550 */
3551 if (IS_INSN_ID(iobj, duparray)) {
3552 LINK_ELEMENT *next = iobj->link.next;
3553 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3554 iobj->insn_id = BIN(putobject);
3555 }
3556 }
3557
3558 /*
3559 * duparray [...]
3560 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3561 * =>
3562 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3563 */
3564 if (IS_INSN_ID(iobj, duparray)) {
3565 LINK_ELEMENT *next = iobj->link.next;
3566 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3567 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3568 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3569
3570 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3571 VALUE ary = iobj->operands[0];
3573
3574 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3575 ELEM_REMOVE(next);
3576 }
3577 }
3578 }
3579
3580 /*
3581 * duphash {...}
3582 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3583 * =>
3584 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3585 */
3586 if (IS_INSN_ID(iobj, duphash)) {
3587 LINK_ELEMENT *next = iobj->link.next;
3588 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3589 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3590 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3591
3592 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3593 VALUE hash = iobj->operands[0];
3594 rb_obj_reveal(hash, rb_cHash);
3595 RB_OBJ_SET_SHAREABLE(hash);
3596
3597 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3598 ELEM_REMOVE(next);
3599 }
3600 }
3601 }
3602
3603 /*
3604 * newarray 0
3605 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3606 * =>
3607 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3608 */
3609 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3610 LINK_ELEMENT *next = iobj->link.next;
3611 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3612 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3613 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3614
3615 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3616 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3617 ELEM_REMOVE(next);
3618 }
3619 }
3620 }
3621
3622 /*
3623 * newhash 0
3624 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3625 * =>
3626 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3627 */
3628 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3629 LINK_ELEMENT *next = iobj->link.next;
3630 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3631 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3632 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3633
3634 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3635 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3636 ELEM_REMOVE(next);
3637 }
3638 }
3639 }
3640
3641 if (IS_INSN_ID(iobj, branchif) ||
3642 IS_INSN_ID(iobj, branchnil) ||
3643 IS_INSN_ID(iobj, branchunless)) {
3644 /*
3645 * if L1
3646 * ...
3647 * L1:
3648 * jump L2
3649 * =>
3650 * if L2
3651 */
3652 INSN *nobj = (INSN *)get_destination_insn(iobj);
3653
3654 /* This jump-jump optimization may ignore line events on the jump
3655 * instruction being skipped. For example, the Line 2 TracePoint
3656 * event would otherwise never fire in the following code:
3657 *
3658 * 1: raise if 1 == 2
3659 * 2: while true
3660 * 3: break
3661 * 4: end
3662 *
3663 * Do not skip a jump that carries a line event. This applies even
3664 * when coverage is disabled because TracePoint consumes the same
3665 * event. [Bug #15980]
3666 */
3667 int stop_optimization =
3668 nobj->link.type == ISEQ_ELEMENT_INSN &&
3669 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3670 if (!stop_optimization) {
3671 INSN *pobj = (INSN *)iobj->link.prev;
3672 int prev_dup = 0;
3673 if (pobj) {
3674 if (!IS_INSN(&pobj->link))
3675 pobj = 0;
3676 else if (IS_INSN_ID(pobj, dup))
3677 prev_dup = 1;
3678 }
3679
3680 for (;;) {
3681 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3682 if (!replace_destination(iobj, nobj)) break;
3683 }
3684 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3685 !!(nobj = (INSN *)nobj->link.next) &&
3686 IS_INSN(&nobj->link) &&
3687 /* basic blocks, with no labels in the middle */
3688 nobj->insn_id == iobj->insn_id) {
3689 /*
3690 * dup
3691 * if L1
3692 * ...
3693 * L1:
3694 * dup
3695 * if L2
3696 * =>
3697 * dup
3698 * if L2
3699 * ...
3700 * L1:
3701 * dup
3702 * if L2
3703 */
3704 if (!replace_destination(iobj, nobj)) break;
3705 }
3706 else if (pobj) {
3707 /*
3708 * putnil
3709 * if L1
3710 * =>
3711 * # nothing
3712 *
3713 * putobject true
3714 * if L1
3715 * =>
3716 * jump L1
3717 *
3718 * putstring ".."
3719 * if L1
3720 * =>
3721 * jump L1
3722 *
3723 * putstring ".."
3724 * dup
3725 * if L1
3726 * =>
3727 * putstring ".."
3728 * jump L1
3729 *
3730 */
3731 int cond;
3732 if (prev_dup && IS_INSN(pobj->link.prev)) {
3733 pobj = (INSN *)pobj->link.prev;
3734 }
3735 if (IS_INSN_ID(pobj, putobject)) {
3736 cond = (IS_INSN_ID(iobj, branchif) ?
3737 OPERAND_AT(pobj, 0) != Qfalse :
3738 IS_INSN_ID(iobj, branchunless) ?
3739 OPERAND_AT(pobj, 0) == Qfalse :
3740 FALSE);
3741 }
3742 else if (IS_INSN_ID(pobj, putstring) ||
3743 IS_INSN_ID(pobj, duparray) ||
3744 IS_INSN_ID(pobj, newarray)) {
3745 cond = IS_INSN_ID(iobj, branchif);
3746 }
3747 else if (IS_INSN_ID(pobj, putnil)) {
3748 cond = !IS_INSN_ID(iobj, branchif);
3749 }
3750 else break;
3751 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3752 ELEM_REMOVE(iobj->link.prev);
3753 }
3754 else if (!iseq_pop_newarray(iseq, pobj)) {
3755 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3756 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3757 }
3758 if (cond) {
3759 if (prev_dup) {
3760 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3761 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3762 }
3763 iobj->insn_id = BIN(jump);
3764 goto again;
3765 }
3766 else {
3767 unref_destination(iobj, 0);
3768 ELEM_REMOVE(&iobj->link);
3769 }
3770 break;
3771 }
3772 else break;
3773 {
3774 LINK_ELEMENT *dest = get_destination_insn(nobj);
3775 if (!dest || !IS_INSN(dest)) break;
3776 nobj = (INSN *)dest;
3777 }
3778 }
3779 }
3780 }
3781
3782 if (IS_INSN_ID(iobj, pop)) {
3783 /*
3784 * putself / putnil / putobject obj / putstring "..."
3785 * pop
3786 * =>
3787 * # do nothing
3788 */
3789 LINK_ELEMENT *prev = iobj->link.prev;
3790 if (IS_INSN(prev)) {
3791 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3792 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3793 previ == BIN(putself) || previ == BIN(putstring) ||
3794 previ == BIN(putchilledstring) ||
3795 previ == BIN(dup) ||
3796 previ == BIN(getlocal) ||
3797 previ == BIN(getblockparam) ||
3798 previ == BIN(getblockparamproxy) ||
3799 previ == BIN(getinstancevariable) ||
3800 previ == BIN(duparray)) {
3801 /* just push operand or static value and pop soon, no
3802 * side effects */
3803 ELEM_REMOVE(prev);
3804 ELEM_REMOVE(&iobj->link);
3805 }
3806 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3807 ELEM_REMOVE(&iobj->link);
3808 }
3809 else if (previ == BIN(concatarray)) {
3810 INSN *piobj = (INSN *)prev;
3811 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3812 INSN_OF(piobj) = BIN(pop);
3813 }
3814 else if (previ == BIN(concatstrings)) {
3815 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3816 ELEM_REMOVE(prev);
3817 }
3818 else {
3819 ELEM_REMOVE(&iobj->link);
3820 INSN_OF(prev) = BIN(adjuststack);
3821 }
3822 }
3823 }
3824 }
3825
3826 if (IS_INSN_ID(iobj, newarray) ||
3827 IS_INSN_ID(iobj, duparray) ||
3828 IS_INSN_ID(iobj, concatarray) ||
3829 IS_INSN_ID(iobj, splatarray) ||
3830 0) {
3831 /*
3832 * newarray N
3833 * splatarray
3834 * =>
3835 * newarray N
3836 * newarray always puts an array
3837 */
3838 LINK_ELEMENT *next = iobj->link.next;
3839 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3840 /* remove splatarray following always-array insn */
3841 ELEM_REMOVE(next);
3842 }
3843 }
3844
3845 if (IS_INSN_ID(iobj, newarray)) {
3846 LINK_ELEMENT *next = iobj->link.next;
3847 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3848 OPERAND_AT(next, 1) == INT2FIX(0)) {
3849 VALUE op1, op2;
3850 op1 = OPERAND_AT(iobj, 0);
3851 op2 = OPERAND_AT(next, 0);
3852 ELEM_REMOVE(next);
3853
3854 if (op1 == op2) {
3855 /*
3856 * newarray 2
3857 * expandarray 2, 0
3858 * =>
3859 * swap
3860 */
3861 if (op1 == INT2FIX(2)) {
3862 INSN_OF(iobj) = BIN(swap);
3863 iobj->operand_size = 0;
3864 }
3865 /*
3866 * newarray X
3867 * expandarray X, 0
3868 * =>
3869 * opt_reverse X
3870 */
3871 else {
3872 INSN_OF(iobj) = BIN(opt_reverse);
3873 }
3874 }
3875 else {
3876 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3877 INSN_OF(iobj) = BIN(opt_reverse);
3878 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3879
3880 if (op1 > op2) {
3881 /* X > Y
3882 * newarray X
3883 * expandarray Y, 0
3884 * =>
3885 * pop * (Y-X)
3886 * opt_reverse Y
3887 */
3888 for (; diff > 0; diff--) {
3889 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3890 }
3891 }
3892 else { /* (op1 < op2) */
3893 /* X < Y
3894 * newarray X
3895 * expandarray Y, 0
3896 * =>
3897 * putnil * (Y-X)
3898 * opt_reverse Y
3899 */
3900 for (; diff < 0; diff++) {
3901 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3902 }
3903 }
3904 }
3905 }
3906 }
3907
3908 if (IS_INSN_ID(iobj, duparray)) {
3909 LINK_ELEMENT *next = iobj->link.next;
3910 /*
3911 * duparray obj
3912 * expandarray X, 0
3913 * =>
3914 * putobject obj
3915 * expandarray X, 0
3916 */
3917 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3918 INSN_OF(iobj) = BIN(putobject);
3919 }
3920 }
3921
3922 if (IS_INSN_ID(iobj, anytostring)) {
3923 LINK_ELEMENT *next = iobj->link.next;
3924 /*
3925 * anytostring
3926 * concatstrings 1
3927 * =>
3928 * anytostring
3929 */
3930 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3931 OPERAND_AT(next, 0) == INT2FIX(1)) {
3932 ELEM_REMOVE(next);
3933 }
3934 }
3935
3936 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3937 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3938 /*
3939 * putstring ""
3940 * concatstrings N
3941 * =>
3942 * concatstrings N-1
3943 */
3944 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3945 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3946 INSN *next = (INSN *)iobj->link.next;
3947 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3948 ELEM_REMOVE(&next->link);
3949 }
3950 ELEM_REMOVE(&iobj->link);
3951 }
3952 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3953 INSN *next = (INSN *)iobj->link.next;
3954 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3955 VALUE src = OPERAND_AT(iobj, 0);
3956 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3957 VALUE path = rb_iseq_path(iseq);
3958 int line = iobj->insn_info.line_no;
3959 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
3960 /* The folded operand is a Regexp, so the instruction must be
3961 * putobject: dupstring/dupchilledstring would resurrect the
3962 * Regexp as a String at run time (e.g. for a /o regexp whose
3963 * interpolation folds to a constant, such as /#{"a"}/o). */
3964 iobj->insn_id = BIN(putobject);
3965 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3966 ELEM_REMOVE(iobj->link.next);
3967 }
3968 }
3969 }
3970
3971 if (IS_INSN_ID(iobj, concatstrings)) {
3972 /*
3973 * concatstrings N
3974 * concatstrings M
3975 * =>
3976 * concatstrings N+M-1
3977 */
3978 LINK_ELEMENT *next = iobj->link.next;
3979 INSN *jump = 0;
3980 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3981 next = get_destination_insn(jump = (INSN *)next);
3982 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3983 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3984 OPERAND_AT(iobj, 0) = INT2FIX(n);
3985 if (jump) {
3986 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3987 if (!--label->refcnt) {
3988 ELEM_REMOVE(&label->link);
3989 }
3990 else {
3991 label = NEW_LABEL(0);
3992 OPERAND_AT(jump, 0) = (VALUE)label;
3993 }
3994 label->refcnt++;
3995 ELEM_INSERT_NEXT(next, &label->link);
3996 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3997 }
3998 else {
3999 ELEM_REMOVE(next);
4000 }
4001 }
4002 }
4003
4004 if (do_tailcallopt &&
4005 (IS_INSN_ID(iobj, send) ||
4006 IS_INSN_ID(iobj, invokesuper))) {
4007 /*
4008 * send ...
4009 * leave
4010 * =>
4011 * send ..., ... | VM_CALL_TAILCALL, ...
4012 * leave # unreachable
4013 */
4014 INSN *piobj = NULL;
4015 if (iobj->link.next) {
4016 LINK_ELEMENT *next = iobj->link.next;
4017 do {
4018 if (!IS_INSN(next)) {
4019 next = next->next;
4020 continue;
4021 }
4022 switch (INSN_OF(next)) {
4023 case BIN(nop):
4024 next = next->next;
4025 break;
4026 case BIN(jump):
4027 /* if cond
4028 * return tailcall
4029 * end
4030 */
4031 next = get_destination_insn((INSN *)next);
4032 break;
4033 case BIN(leave):
4034 piobj = iobj;
4035 /* fall through */
4036 default:
4037 next = NULL;
4038 break;
4039 }
4040 } while (next);
4041 }
4042
4043 if (piobj) {
4044 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4045 if (IS_INSN_ID(piobj, send) ||
4046 IS_INSN_ID(piobj, invokesuper)) {
4047 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4048 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4049 OPERAND_AT(piobj, 0) = (VALUE)ci;
4050 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4051 }
4052 }
4053 else {
4054 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4055 OPERAND_AT(piobj, 0) = (VALUE)ci;
4056 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4057 }
4058 }
4059 }
4060
4061 if (IS_INSN_ID(iobj, dup)) {
4062 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4063 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4064
4065 /*
4066 * dup
4067 * setlocal x, y
4068 * setlocal x, y
4069 * =>
4070 * dup
4071 * setlocal x, y
4072 */
4073 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4074 set2 = set1->next;
4075 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4076 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4077 ELEM_REMOVE(set1);
4078 ELEM_REMOVE(&iobj->link);
4079 }
4080 }
4081
4082 /*
4083 * dup
4084 * setlocal x, y
4085 * dup
4086 * setlocal x, y
4087 * =>
4088 * dup
4089 * setlocal x, y
4090 */
4091 else if (IS_NEXT_INSN_ID(set1, dup) &&
4092 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4093 set2 = set1->next->next;
4094 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4095 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4096 ELEM_REMOVE(set1->next);
4097 ELEM_REMOVE(set2);
4098 }
4099 }
4100 }
4101 }
4102
4103 /*
4104 * getlocal x, y
4105 * dup
4106 * setlocal x, y
4107 * =>
4108 * dup
4109 */
4110 if (IS_INSN_ID(iobj, getlocal)) {
4111 LINK_ELEMENT *niobj = &iobj->link;
4112 if (IS_NEXT_INSN_ID(niobj, dup)) {
4113 niobj = niobj->next;
4114 }
4115 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4116 LINK_ELEMENT *set1 = niobj->next;
4117 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4118 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4119 ELEM_REMOVE(set1);
4120 ELEM_REMOVE(niobj);
4121 }
4122 }
4123 }
4124
4125 /*
4126 * opt_invokebuiltin_delegate
4127 * trace
4128 * leave
4129 * =>
4130 * opt_invokebuiltin_delegate_leave
4131 * trace
4132 * leave
4133 */
4134 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4135 if (IS_TRACE(iobj->link.next)) {
4136 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4137 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4138 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4139 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4140 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4141 }
4142 }
4143 }
4144 }
4145
4146 /*
4147 * getblockparam
4148 * branchif / branchunless
4149 * =>
4150 * getblockparamproxy
4151 * branchif / branchunless
4152 */
4153 if (IS_INSN_ID(iobj, getblockparam)) {
4154 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4155 iobj->insn_id = BIN(getblockparamproxy);
4156 }
4157 }
4158
4159 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4160 LINK_ELEMENT *niobj = &iobj->link;
4161 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4162 niobj = niobj->next;
4163 LINK_ELEMENT *siobj;
4164 unsigned int set_flags = 0, unset_flags = 0;
4165
4166 /*
4167 * Eliminate hash allocation for f(*a, kw: 1)
4168 *
4169 * splatarray false
4170 * duphash
4171 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4172 * =>
4173 * splatarray false
4174 * putobject
4175 * send ARGS_SPLAT|KW_SPLAT
4176 */
4177 if (IS_NEXT_INSN_ID(niobj, send)) {
4178 siobj = niobj->next;
4179 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4180 unset_flags = VM_CALL_ARGS_BLOCKARG;
4181 }
4182 /*
4183 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4184 *
4185 * splatarray false
4186 * duphash
4187 * getlocal / getinstancevariable / getblockparamproxy
4188 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4189 * =>
4190 * splatarray false
4191 * putobject
4192 * getlocal / getinstancevariable / getblockparamproxy
4193 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4194 */
4195 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4196 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4197 siobj = niobj->next->next;
4198 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4199 }
4200
4201 if (set_flags) {
4202 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4203 unsigned int flags = vm_ci_flag(ci);
4204 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4205 ((INSN*)niobj)->insn_id = BIN(putobject);
4206 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4207
4208 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4209 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4210 RB_OBJ_WRITTEN(iseq, ci, nci);
4211 OPERAND_AT(siobj, 0) = (VALUE)nci;
4212 }
4213 }
4214 }
4215 }
4216
4217 return COMPILE_OK;
4218}
4219
4220static int
4221insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4222{
4223 if (insn_id == BIN(opt_neq)) {
4224 VALUE original_ci = iobj->operands[0];
4225 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4226 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4227 }
4228 else {
4229 iobj->insn_id = insn_id;
4230 iobj->operand_size = insn_len(insn_id) - 1;
4231 }
4232 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4233
4234 return COMPILE_OK;
4235}
4236
4237static int
4238iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4239{
4240 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4241 IS_INSN(iobj->link.next)) {
4242 /*
4243 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4244 */
4245 INSN *niobj = (INSN *)iobj->link.next;
4246 if (IS_INSN_ID(niobj, send)) {
4247 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4248 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4249 VALUE method = INT2FIX(0);
4250 switch (vm_ci_mid(ci)) {
4251 case idMax:
4252 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4253 break;
4254 case idMin:
4255 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4256 break;
4257 case idHash:
4258 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4259 break;
4260 }
4261
4262 if (method != INT2FIX(0)) {
4263 VALUE num = iobj->operands[0];
4264 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4265 ELEM_REMOVE(&niobj->link);
4266 return COMPILE_OK;
4267 }
4268 }
4269 }
4270 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4271 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4272 IS_NEXT_INSN_ID(&niobj->link, send)) {
4273 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4274 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4275 VALUE num = iobj->operands[0];
4276 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4277 ELEM_REMOVE(&iobj->link);
4278 ELEM_REMOVE(niobj->link.next);
4279 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4280 return COMPILE_OK;
4281 }
4282 }
4283 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4284 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4285 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4286 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4287 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4288 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4289 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4290 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4291 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4292 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4293 VALUE num = iobj->operands[0];
4294 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4295 // Remove the "send" insn.
4296 ELEM_REMOVE((niobj->link.next)->next);
4297 // Remove the modified insn from its original "newarray" position...
4298 ELEM_REMOVE(&iobj->link);
4299 // and insert it after the buffer insn.
4300 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4301 return COMPILE_OK;
4302 }
4303 }
4304
4305 // Break the "else if" chain since some prior checks abort after sub-ifs.
4306 // We already found "newarray". To match `[...].include?(arg)` we look for
4307 // the instruction(s) representing the argument followed by a "send".
4308 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4309 IS_INSN_ID(niobj, putobject) ||
4310 IS_INSN_ID(niobj, putself) ||
4311 IS_INSN_ID(niobj, getlocal) ||
4312 IS_INSN_ID(niobj, getinstancevariable)) &&
4313 IS_NEXT_INSN_ID(&niobj->link, send)) {
4314
4315 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4316 const struct rb_callinfo *ci;
4317 // Allow any number (0 or more) of simple method calls on the argument
4318 // (as in `[...].include?(arg.method1.method2)`.
4319 do {
4320 sendobj = sendobj->next;
4321 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4322 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4323
4324 // If this send is for .include? with one arg we can do our opt.
4325 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4326 VALUE num = iobj->operands[0];
4327 INSN *sendins = (INSN *)sendobj;
4328 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4329 // Remove the original "newarray" insn.
4330 ELEM_REMOVE(&iobj->link);
4331 return COMPILE_OK;
4332 }
4333 }
4334 }
4335
4336 /*
4337 * duparray [...]
4338 * some insn for the arg...
4339 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4340 * =>
4341 * arg insn...
4342 * opt_duparray_send [...], :include?, 1
4343 */
4344 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4345 INSN *niobj = (INSN *)iobj->link.next;
4346 if ((IS_INSN_ID(niobj, getlocal) ||
4347 IS_INSN_ID(niobj, getinstancevariable) ||
4348 IS_INSN_ID(niobj, putself)) &&
4349 IS_NEXT_INSN_ID(&niobj->link, send)) {
4350
4351 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4352 const struct rb_callinfo *ci;
4353 // Allow any number (0 or more) of simple method calls on the argument
4354 // (as in `[...].include?(arg.method1.method2)`.
4355 do {
4356 sendobj = sendobj->next;
4357 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4358 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4359
4360 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4361 // Move the array arg from duparray to opt_duparray_send.
4362 VALUE ary = iobj->operands[0];
4364
4365 INSN *sendins = (INSN *)sendobj;
4366 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4367
4368 // Remove the duparray insn.
4369 ELEM_REMOVE(&iobj->link);
4370 return COMPILE_OK;
4371 }
4372 }
4373 }
4374
4375
4376 if (IS_INSN_ID(iobj, send)) {
4377 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4378 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4379
4380#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4381 if (vm_ci_simple(ci)) {
4382 switch (vm_ci_argc(ci)) {
4383 case 0:
4384 switch (vm_ci_mid(ci)) {
4385 case idLength: SP_INSN(length); return COMPILE_OK;
4386 case idSize: SP_INSN(size); return COMPILE_OK;
4387 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4388 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4389 case idSucc: SP_INSN(succ); return COMPILE_OK;
4390 case idNot: SP_INSN(not); return COMPILE_OK;
4391 }
4392 break;
4393 case 1:
4394 switch (vm_ci_mid(ci)) {
4395 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4396 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4397 case idMULT: SP_INSN(mult); return COMPILE_OK;
4398 case idDIV: SP_INSN(div); return COMPILE_OK;
4399 case idMOD: SP_INSN(mod); return COMPILE_OK;
4400 case idEq: SP_INSN(eq); return COMPILE_OK;
4401 case idNeq: SP_INSN(neq); return COMPILE_OK;
4402 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4403 case idLT: SP_INSN(lt); return COMPILE_OK;
4404 case idLE: SP_INSN(le); return COMPILE_OK;
4405 case idGT: SP_INSN(gt); return COMPILE_OK;
4406 case idGE: SP_INSN(ge); return COMPILE_OK;
4407 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4408 case idAREF: SP_INSN(aref); return COMPILE_OK;
4409 case idAnd: SP_INSN(and); return COMPILE_OK;
4410 case idOr: SP_INSN(or); return COMPILE_OK;
4411 }
4412 break;
4413 case 2:
4414 switch (vm_ci_mid(ci)) {
4415 case idASET: SP_INSN(aset); return COMPILE_OK;
4416 }
4417 break;
4418 }
4419 }
4420
4421 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4422 iobj->insn_id = BIN(opt_send_without_block);
4423 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4424 }
4425 }
4426#undef SP_INSN
4427
4428 return COMPILE_OK;
4429}
4430
4431static inline int
4432tailcallable_p(rb_iseq_t *iseq)
4433{
4434 switch (ISEQ_BODY(iseq)->type) {
4435 case ISEQ_TYPE_TOP:
4436 case ISEQ_TYPE_EVAL:
4437 case ISEQ_TYPE_MAIN:
4438 /* not tail callable because cfp will be over popped */
4439 case ISEQ_TYPE_RESCUE:
4440 case ISEQ_TYPE_ENSURE:
4441 /* rescue block can't tail call because of errinfo */
4442 return FALSE;
4443 default:
4444 return TRUE;
4445 }
4446}
4447
4448static int
4449iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4450{
4451 LINK_ELEMENT *list;
4452 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4453 const int do_tailcallopt = tailcallable_p(iseq) &&
4454 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4455 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4456 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4457 int rescue_level = 0;
4458 int tailcallopt = do_tailcallopt;
4459
4460 list = FIRST_ELEMENT(anchor);
4461
4462 int do_block_optimization = 0;
4463 LABEL * block_loop_label = NULL;
4464
4465 // If we're optimizing a block
4466 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4467 do_block_optimization = 1;
4468
4469 // If the block starts with a nop and a label,
4470 // record the label so we can detect if it's a jump target
4471 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4472 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4473 block_loop_label = (LABEL *)le->next;
4474 }
4475 }
4476
4477 while (list) {
4478 if (IS_INSN(list)) {
4479 if (do_peepholeopt) {
4480 iseq_peephole_optimize(iseq, list, tailcallopt);
4481 }
4482 if (do_si) {
4483 iseq_specialized_instruction(iseq, (INSN *)list);
4484 }
4485 if (do_ou) {
4486 insn_operands_unification((INSN *)list);
4487 }
4488
4489 if (do_block_optimization) {
4490 INSN * item = (INSN *)list;
4491 // Give up if there is a throw
4492 if (IS_INSN_ID(item, throw)) {
4493 do_block_optimization = 0;
4494 }
4495 else {
4496 // If the instruction has a jump target, check if the
4497 // jump target is the block loop label
4498 const char *types = insn_op_types(item->insn_id);
4499 for (int j = 0; types[j]; j++) {
4500 if (types[j] == TS_OFFSET) {
4501 // If the jump target is equal to the block loop
4502 // label, then we can't do the optimization because
4503 // the leading `nop` instruction fires the block
4504 // entry tracepoint
4505 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4506 if (target == block_loop_label) {
4507 do_block_optimization = 0;
4508 }
4509 }
4510 }
4511 }
4512 }
4513 }
4514 if (IS_LABEL(list)) {
4515 switch (((LABEL *)list)->rescued) {
4516 case LABEL_RESCUE_BEG:
4517 rescue_level++;
4518 tailcallopt = FALSE;
4519 break;
4520 case LABEL_RESCUE_END:
4521 if (!--rescue_level) tailcallopt = do_tailcallopt;
4522 break;
4523 }
4524 }
4525 list = list->next;
4526 }
4527
4528 if (do_block_optimization) {
4529 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4530 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4531 ELEM_REMOVE(le);
4532 }
4533 }
4534 return COMPILE_OK;
4535}
4536
4537#if OPT_INSTRUCTIONS_UNIFICATION
4538static INSN *
4539new_unified_insn(rb_iseq_t *iseq,
4540 int insn_id, int size, LINK_ELEMENT *seq_list)
4541{
4542 INSN *iobj = 0;
4543 LINK_ELEMENT *list = seq_list;
4544 int i, argc = 0;
4545 VALUE *operands = 0, *ptr = 0;
4546
4547
4548 /* count argc */
4549 for (i = 0; i < size; i++) {
4550 iobj = (INSN *)list;
4551 argc += iobj->operand_size;
4552 list = list->next;
4553 }
4554
4555 if (argc > 0) {
4556 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4557 }
4558
4559 /* copy operands */
4560 list = seq_list;
4561 for (i = 0; i < size; i++) {
4562 iobj = (INSN *)list;
4563 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4564 ptr += iobj->operand_size;
4565 list = list->next;
4566 }
4567
4568 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4569}
4570#endif
4571
4572/*
4573 * This scheme can get more performance if do this optimize with
4574 * label address resolving.
4575 * It's future work (if compile time was bottle neck).
4576 */
4577static int
4578iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4579{
4580#if OPT_INSTRUCTIONS_UNIFICATION
4581 LINK_ELEMENT *list;
4582 INSN *iobj, *niobj;
4583 int id, k;
4584 intptr_t j;
4585
4586 list = FIRST_ELEMENT(anchor);
4587 while (list) {
4588 if (IS_INSN(list)) {
4589 iobj = (INSN *)list;
4590 id = iobj->insn_id;
4591 if (unified_insns_data[id] != 0) {
4592 const int *const *entry = unified_insns_data[id];
4593 for (j = 1; j < (intptr_t)entry[0]; j++) {
4594 const int *unified = entry[j];
4595 LINK_ELEMENT *li = list->next;
4596 for (k = 2; k < unified[1]; k++) {
4597 if (!IS_INSN(li) ||
4598 ((INSN *)li)->insn_id != unified[k]) {
4599 goto miss;
4600 }
4601 li = li->next;
4602 }
4603 /* matched */
4604 niobj =
4605 new_unified_insn(iseq, unified[0], unified[1] - 1,
4606 list);
4607
4608 /* insert to list */
4609 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4610 niobj->link.next = li;
4611 if (li) {
4612 li->prev = (LINK_ELEMENT *)niobj;
4613 }
4614
4615 list->prev->next = (LINK_ELEMENT *)niobj;
4616 list = (LINK_ELEMENT *)niobj;
4617 break;
4618 miss:;
4619 }
4620 }
4621 }
4622 list = list->next;
4623 }
4624#endif
4625 return COMPILE_OK;
4626}
4627
4628static int
4629all_string_result_p(const NODE *node)
4630{
4631 if (!node) return FALSE;
4632 switch (nd_type(node)) {
4633 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4634 return TRUE;
4635 case NODE_IF: case NODE_UNLESS:
4636 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4637 if (all_string_result_p(RNODE_IF(node)->nd_body))
4638 return all_string_result_p(RNODE_IF(node)->nd_else);
4639 return FALSE;
4640 case NODE_AND: case NODE_OR:
4641 if (!RNODE_AND(node)->nd_2nd)
4642 return all_string_result_p(RNODE_AND(node)->nd_1st);
4643 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4644 return FALSE;
4645 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4646 default:
4647 return FALSE;
4648 }
4649}
4650
4652 rb_iseq_t *const iseq;
4653 LINK_ANCHOR *const ret;
4654 VALUE lit;
4655 const NODE *lit_node;
4656 int cnt;
4657 int dregx;
4658};
4659
4660static int
4661append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4662{
4663 VALUE s = rb_str_new_mutable_parser_string(str);
4664 if (args->dregx) {
4665 VALUE error = rb_reg_check_preprocess(s);
4666 if (!NIL_P(error)) {
4667 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4668 return COMPILE_NG;
4669 }
4670 }
4671 if (NIL_P(args->lit)) {
4672 args->lit = s;
4673 args->lit_node = node;
4674 }
4675 else {
4676 rb_str_buf_append(args->lit, s);
4677 }
4678 return COMPILE_OK;
4679}
4680
4681static void
4682flush_dstr_fragment(struct dstr_ctxt *args)
4683{
4684 if (!NIL_P(args->lit)) {
4685 rb_iseq_t *iseq = args->iseq;
4686 VALUE lit = args->lit;
4687 args->lit = Qnil;
4688 lit = rb_fstring(lit);
4689 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4690 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4691 args->cnt++;
4692 }
4693}
4694
4695static int
4696compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4697{
4698 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4699 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4700
4701 if (str) {
4702 CHECK(append_dstr_fragment(args, node, str));
4703 }
4704
4705 while (list) {
4706 const NODE *const head = list->nd_head;
4707 if (nd_type_p(head, NODE_STR)) {
4708 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4709 }
4710 else if (nd_type_p(head, NODE_DSTR)) {
4711 CHECK(compile_dstr_fragments_0(args, head));
4712 }
4713 else {
4714 flush_dstr_fragment(args);
4715 rb_iseq_t *iseq = args->iseq;
4716 CHECK(COMPILE(args->ret, "each string", head));
4717 args->cnt++;
4718 }
4719 list = (struct RNode_LIST *)list->nd_next;
4720 }
4721 return COMPILE_OK;
4722}
4723
4724static int
4725compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4726{
4727 struct dstr_ctxt args = {
4728 .iseq = iseq, .ret = ret,
4729 .lit = Qnil, .lit_node = NULL,
4730 .cnt = 0, .dregx = dregx,
4731 };
4732 CHECK(compile_dstr_fragments_0(&args, node));
4733 flush_dstr_fragment(&args);
4734
4735 *cntp = args.cnt;
4736
4737 return COMPILE_OK;
4738}
4739
4740static int
4741compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4742{
4743 while (node && nd_type_p(node, NODE_BLOCK)) {
4744 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4745 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4746 node = RNODE_BLOCK(node)->nd_next;
4747 }
4748 if (node) {
4749 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4750 }
4751 return COMPILE_OK;
4752}
4753
4754static int
4755compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4756{
4757 int cnt;
4758 if (!RNODE_DSTR(node)->nd_next) {
4759 VALUE lit = rb_node_dstr_string_val(node);
4760 ADD_INSN1(ret, node, putstring, lit);
4761 RB_OBJ_SET_SHAREABLE(lit);
4762 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4763 }
4764 else {
4765 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4766 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4767 }
4768 return COMPILE_OK;
4769}
4770
4771static int
4772compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4773{
4774 int cnt;
4775 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4776
4777 if (!RNODE_DREGX(node)->nd_next) {
4778 if (!popped) {
4779 VALUE src = rb_node_dregx_string_val(node);
4780 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4781 ADD_INSN1(ret, node, putobject, match);
4782 RB_OBJ_WRITTEN(iseq, Qundef, match);
4783 }
4784 return COMPILE_OK;
4785 }
4786
4787 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4788 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4789
4790 if (popped) {
4791 ADD_INSN(ret, node, pop);
4792 }
4793
4794 return COMPILE_OK;
4795}
4796
4797static int
4798compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4799 LABEL *then_label, LABEL *else_label)
4800{
4801 const int line = nd_line(node);
4802 LABEL *lend = NEW_LABEL(line);
4803 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4804 + VM_SVAR_FLIPFLOP_START;
4805 VALUE key = INT2FIX(cnt);
4806
4807 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4808 ADD_INSNL(ret, node, branchif, lend);
4809
4810 /* *flip == 0 */
4811 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4812 ADD_INSNL(ret, node, branchunless, else_label);
4813 ADD_INSN1(ret, node, putobject, Qtrue);
4814 ADD_INSN1(ret, node, setspecial, key);
4815 if (!again) {
4816 ADD_INSNL(ret, node, jump, then_label);
4817 }
4818
4819 /* *flip == 1 */
4820 ADD_LABEL(ret, lend);
4821 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4822 ADD_INSNL(ret, node, branchunless, then_label);
4823 ADD_INSN1(ret, node, putobject, Qfalse);
4824 ADD_INSN1(ret, node, setspecial, key);
4825 ADD_INSNL(ret, node, jump, then_label);
4826
4827 return COMPILE_OK;
4828}
4829
4830static int
4831compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4832 LABEL *then_label, LABEL *else_label);
4833
4834#define COMPILE_SINGLE 2
4835static int
4836compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4837 LABEL *then_label, LABEL *else_label)
4838{
4839 DECL_ANCHOR(seq);
4840 INIT_ANCHOR(seq);
4841 LABEL *label = NEW_LABEL(nd_line(cond));
4842 if (!then_label) then_label = label;
4843 else if (!else_label) else_label = label;
4844
4845 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4846
4847 if (LIST_INSN_SIZE_ONE(seq)) {
4848 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4849 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4850 return COMPILE_OK;
4851 }
4852 if (!label->refcnt) {
4853 return COMPILE_SINGLE;
4854 }
4855 ADD_LABEL(seq, label);
4856 ADD_SEQ(ret, seq);
4857 return COMPILE_OK;
4858}
4859
4860static int
4861compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4862 LABEL *then_label, LABEL *else_label)
4863{
4864 int ok;
4865 DECL_ANCHOR(ignore);
4866
4867 again:
4868 switch (nd_type(cond)) {
4869 case NODE_AND:
4870 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4871 cond = RNODE_AND(cond)->nd_2nd;
4872 if (ok == COMPILE_SINGLE) {
4873 ADD_INSNL(ret, cond, jump, else_label);
4874 INIT_ANCHOR(ignore);
4875 ret = ignore;
4876 then_label = NEW_LABEL(nd_line(cond));
4877 }
4878 goto again;
4879 case NODE_OR:
4880 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4881 cond = RNODE_OR(cond)->nd_2nd;
4882 if (ok == COMPILE_SINGLE) {
4883 ADD_INSNL(ret, cond, jump, then_label);
4884 INIT_ANCHOR(ignore);
4885 ret = ignore;
4886 else_label = NEW_LABEL(nd_line(cond));
4887 }
4888 goto again;
4889 case NODE_SYM:
4890 case NODE_LINE:
4891 case NODE_FILE:
4892 case NODE_ENCODING:
4893 case NODE_INTEGER: /* NODE_INTEGER is always true */
4894 case NODE_FLOAT: /* NODE_FLOAT is always true */
4895 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4896 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4897 case NODE_TRUE:
4898 case NODE_STR:
4899 case NODE_REGX:
4900 case NODE_ZLIST:
4901 case NODE_LAMBDA:
4902 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4903 ADD_INSNL(ret, cond, jump, then_label);
4904 return COMPILE_OK;
4905 case NODE_FALSE:
4906 case NODE_NIL:
4907 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4908 ADD_INSNL(ret, cond, jump, else_label);
4909 return COMPILE_OK;
4910 case NODE_LIST:
4911 case NODE_ARGSCAT:
4912 case NODE_DREGX:
4913 case NODE_DSTR:
4914 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4915 ADD_INSNL(ret, cond, jump, then_label);
4916 return COMPILE_OK;
4917 case NODE_FLIP2:
4918 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4919 return COMPILE_OK;
4920 case NODE_FLIP3:
4921 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4922 return COMPILE_OK;
4923 case NODE_DEFINED:
4924 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4925 break;
4926 default:
4927 {
4928 DECL_ANCHOR(cond_seq);
4929 INIT_ANCHOR(cond_seq);
4930
4931 CHECK(COMPILE(cond_seq, "branch condition", cond));
4932
4933 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4934 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4935 if (insn->insn_id == BIN(putobject)) {
4936 if (RTEST(insn->operands[0])) {
4937 ADD_INSNL(ret, cond, jump, then_label);
4938 // maybe unreachable
4939 return COMPILE_OK;
4940 }
4941 else {
4942 ADD_INSNL(ret, cond, jump, else_label);
4943 return COMPILE_OK;
4944 }
4945 }
4946 }
4947 ADD_SEQ(ret, cond_seq);
4948 }
4949 break;
4950 }
4951
4952 ADD_INSNL(ret, cond, branchunless, else_label);
4953 ADD_INSNL(ret, cond, jump, then_label);
4954 return COMPILE_OK;
4955}
4956
4957#define HASH_BRACE 1
4958
4959static int
4960keyword_node_p(const NODE *const node)
4961{
4962 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4963}
4964
4965static VALUE
4966get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4967{
4968 switch (nd_type(node)) {
4969 case NODE_SYM:
4970 return rb_node_sym_string_val(node);
4971 default:
4972 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4973 }
4974}
4975
4976static VALUE
4977node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4978{
4979 NODE *node = node_hash->nd_head;
4980 VALUE hash = rb_hash_new();
4981 VALUE ary = rb_ary_new();
4982
4983 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4984 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4985 VALUE idx = rb_hash_aref(hash, key);
4986 if (!NIL_P(idx)) {
4987 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4988 (*count_ptr)--;
4989 }
4990 rb_hash_aset(hash, key, INT2FIX(i));
4991 rb_ary_store(ary, i, Qtrue);
4992 (*count_ptr)++;
4993 }
4994
4995 return ary;
4996}
4997
4998static int
4999compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5000 const NODE *const root_node,
5001 struct rb_callinfo_kwarg **const kw_arg_ptr,
5002 unsigned int *flag)
5003{
5004 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5005 RUBY_ASSERT(kw_arg_ptr != NULL);
5006 RUBY_ASSERT(flag != NULL);
5007
5008 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5009 const NODE *node = RNODE_HASH(root_node)->nd_head;
5010 int seen_nodes = 0;
5011
5012 while (node) {
5013 const NODE *key_node = RNODE_LIST(node)->nd_head;
5014 seen_nodes++;
5015
5016 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5017 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5018 /* can be keywords */
5019 }
5020 else {
5021 if (flag) {
5022 *flag |= VM_CALL_KW_SPLAT;
5023 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5024 /* A new hash will be created for the keyword arguments
5025 * in this case, so mark the method as passing mutable
5026 * keyword splat.
5027 */
5028 *flag |= VM_CALL_KW_SPLAT_MUT;
5029 }
5030 }
5031 return FALSE;
5032 }
5033 node = RNODE_LIST(node)->nd_next; /* skip value node */
5034 node = RNODE_LIST(node)->nd_next;
5035 }
5036
5037 /* may be keywords */
5038 node = RNODE_HASH(root_node)->nd_head;
5039 {
5040 int len = 0;
5041 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5042
5043 if (len > VM_CALL_KW_LEN_MAX) {
5044 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5045 len, (int)VM_CALL_KW_LEN_MAX);
5046 }
5047
5048 struct rb_callinfo_kwarg *kw_arg =
5049 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5050 VALUE *keywords = kw_arg->keywords;
5051 int i = 0;
5052 int j = 0;
5053 kw_arg->references = 0;
5054 kw_arg->keyword_len = len;
5055
5056 *kw_arg_ptr = kw_arg;
5057
5058 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5059 const NODE *key_node = RNODE_LIST(node)->nd_head;
5060 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5061 int popped = TRUE;
5062 if (rb_ary_entry(key_index, i)) {
5063 keywords[j] = get_symbol_value(iseq, key_node);
5064 j++;
5065 popped = FALSE;
5066 }
5067 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5068 }
5069 RUBY_ASSERT(j == len);
5070 return TRUE;
5071 }
5072 }
5073 return FALSE;
5074}
5075
5076static int
5077compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5078{
5079 int len = 0;
5080
5081 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5082 if (CPDEBUG > 0) {
5083 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5084 }
5085
5086 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5087 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5088 }
5089 else {
5090 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5091 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5092 }
5093 }
5094
5095 return len;
5096}
5097
5098static inline bool
5099frozen_string_literal_p(const rb_iseq_t *iseq)
5100{
5101 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5102}
5103
5104static inline bool
5105static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5106{
5107 switch (nd_type(node)) {
5108 case NODE_SYM:
5109 case NODE_REGX:
5110 case NODE_LINE:
5111 case NODE_ENCODING:
5112 case NODE_INTEGER:
5113 case NODE_FLOAT:
5114 case NODE_RATIONAL:
5115 case NODE_IMAGINARY:
5116 case NODE_NIL:
5117 case NODE_TRUE:
5118 case NODE_FALSE:
5119 return TRUE;
5120 case NODE_STR:
5121 case NODE_FILE:
5122 return hash_key || frozen_string_literal_p(iseq);
5123 default:
5124 return FALSE;
5125 }
5126}
5127
5128static inline VALUE
5129static_literal_value(const NODE *node, rb_iseq_t *iseq)
5130{
5131 switch (nd_type(node)) {
5132 case NODE_INTEGER:
5133 {
5134 VALUE lit = rb_node_integer_literal_val(node);
5135 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5136 return lit;
5137 }
5138 case NODE_FLOAT:
5139 {
5140 VALUE lit = rb_node_float_literal_val(node);
5141 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5142 return lit;
5143 }
5144 case NODE_RATIONAL:
5145 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5146 case NODE_IMAGINARY:
5147 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5148 case NODE_NIL:
5149 return Qnil;
5150 case NODE_TRUE:
5151 return Qtrue;
5152 case NODE_FALSE:
5153 return Qfalse;
5154 case NODE_SYM:
5155 return rb_node_sym_string_val(node);
5156 case NODE_REGX:
5157 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5158 case NODE_LINE:
5159 return rb_node_line_lineno_val(node);
5160 case NODE_ENCODING:
5161 return rb_node_encoding_val(node);
5162 case NODE_FILE:
5163 case NODE_STR:
5164 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5165 VALUE lit = get_string_value(node);
5166 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5167 RB_OBJ_SET_SHAREABLE(str);
5168 return str;
5169 }
5170 else {
5171 return get_string_value(node);
5172 }
5173 default:
5174 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5175 }
5176}
5177
5178static int
5179compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5180{
5181 const NODE *line_node = node;
5182
5183 if (nd_type_p(node, NODE_ZLIST)) {
5184 if (!popped) {
5185 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5186 }
5187 return 0;
5188 }
5189
5190 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5191
5192 if (popped) {
5193 for (; node; node = RNODE_LIST(node)->nd_next) {
5194 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5195 }
5196 return 1;
5197 }
5198
5199 /* Compilation of an array literal.
5200 * The following code is essentially the same as:
5201 *
5202 * for (int count = 0; node; count++; node->nd_next) {
5203 * compile(node->nd_head);
5204 * }
5205 * ADD_INSN(newarray, count);
5206 *
5207 * However, there are three points.
5208 *
5209 * - The code above causes stack overflow for a big string literal.
5210 * The following limits the stack length up to max_stack_len.
5211 *
5212 * [x1,x2,...,x10000] =>
5213 * push x1 ; push x2 ; ...; push x256; newarray 256;
5214 * push x257; push x258; ...; push x512; pushtoarray 256;
5215 * push x513; push x514; ...; push x768; pushtoarray 256;
5216 * ...
5217 *
5218 * - Long subarray can be optimized by pre-allocating a hidden array.
5219 *
5220 * [1,2,3,...,100] =>
5221 * duparray [1,2,3,...,100]
5222 *
5223 * [x, 1,2,3,...,100, z] =>
5224 * push x; newarray 1;
5225 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5226 * push z; pushtoarray 1;
5227 *
5228 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5229 * to only push it onto the array if it is not empty
5230 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5231 *
5232 * [1,2,3,**kw] =>
5233 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5234 */
5235
5236 const int max_stack_len = 0x100;
5237 const int min_tmp_ary_len = 0x40;
5238 int stack_len = 0;
5239
5240 /* Either create a new array, or push to the existing array */
5241#define FLUSH_CHUNK \
5242 if (stack_len) { \
5243 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5244 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5245 first_chunk = FALSE; \
5246 stack_len = 0; \
5247 }
5248
5249 while (node) {
5250 int count = 1;
5251
5252 /* pre-allocation check (this branch can be omittable) */
5253 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5254 /* count the elements that are optimizable */
5255 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5256 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5257 count++;
5258
5259 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5260 /* The literal contains only optimizable elements, or the subarray is long enough */
5261 VALUE ary = rb_ary_hidden_new(count);
5262
5263 /* Create a hidden array */
5264 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5265 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5266 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5267
5268 /* Emit optimized code */
5269 FLUSH_CHUNK;
5270 if (first_chunk) {
5271 ADD_INSN1(ret, line_node, duparray, ary);
5272 first_chunk = FALSE;
5273 }
5274 else {
5275 ADD_INSN1(ret, line_node, putobject, ary);
5276 ADD_INSN(ret, line_node, concattoarray);
5277 }
5278 RB_OBJ_SET_SHAREABLE(ary);
5279 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5280 }
5281 }
5282
5283 /* Base case: Compile "count" elements */
5284 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5285 if (CPDEBUG > 0) {
5286 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5287 }
5288
5289 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5290 /* Create array or push existing non-keyword elements onto array */
5291 if (stack_len == 0 && first_chunk) {
5292 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5293 }
5294 else {
5295 FLUSH_CHUNK;
5296 }
5297 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5298 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5299 return 1;
5300 }
5301 else {
5302 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5303 stack_len++;
5304 }
5305
5306 /* If there are many pushed elements, flush them to avoid stack overflow */
5307 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5308 }
5309 }
5310
5311 FLUSH_CHUNK;
5312#undef FLUSH_CHUNK
5313 return 1;
5314}
5315
5316static inline int
5317static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5318{
5319 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);
5320}
5321
5322static int
5323compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5324{
5325 const NODE *line_node = node;
5326
5327 node = RNODE_HASH(node)->nd_head;
5328
5329 if (!node || nd_type_p(node, NODE_ZLIST)) {
5330 if (!popped) {
5331 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5332 }
5333 return 0;
5334 }
5335
5336 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5337
5338 if (popped) {
5339 for (; node; node = RNODE_LIST(node)->nd_next) {
5340 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5341 }
5342 return 1;
5343 }
5344
5345 /* Compilation of a hash literal (or keyword arguments).
5346 * This is very similar to compile_array, but there are some differences:
5347 *
5348 * - It contains key-value pairs. So we need to take every two elements.
5349 * We can assume that the length is always even.
5350 *
5351 * - Merging is done by a method call (id_core_hash_merge_ptr).
5352 * Sometimes we need to insert the receiver, so "anchor" is needed.
5353 * In addition, a method call is much slower than concatarray.
5354 * So it pays only when the subsequence is really long.
5355 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5356 *
5357 * - We need to handle keyword splat: **kw.
5358 * For **kw, the key part (node->nd_head) is NULL, and the value part
5359 * (node->nd_next->nd_head) is "kw".
5360 * The code is a bit difficult to avoid hash allocation for **{}.
5361 */
5362
5363 const int max_stack_len = 0x100;
5364 const int min_tmp_hash_len = 0x800;
5365 int stack_len = 0;
5366 int first_chunk = 1;
5367 DECL_ANCHOR(anchor);
5368 INIT_ANCHOR(anchor);
5369
5370 /* Convert pushed elements to a hash, and merge if needed */
5371#define FLUSH_CHUNK() \
5372 if (stack_len) { \
5373 if (first_chunk) { \
5374 APPEND_LIST(ret, anchor); \
5375 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5376 } \
5377 else { \
5378 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5379 ADD_INSN(ret, line_node, swap); \
5380 APPEND_LIST(ret, anchor); \
5381 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5382 } \
5383 INIT_ANCHOR(anchor); \
5384 first_chunk = stack_len = 0; \
5385 }
5386
5387 while (node) {
5388 int count = 1;
5389
5390 /* pre-allocation check (this branch can be omittable) */
5391 if (static_literal_node_pair_p(node, iseq)) {
5392 /* count the elements that are optimizable */
5393 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5394 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5395 count++;
5396
5397 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5398 /* The literal contains only optimizable elements, or the subsequence is long enough */
5399 VALUE ary = rb_ary_hidden_new(count);
5400
5401 /* Create a hidden hash */
5402 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5403 VALUE elem[2];
5404 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5405 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5406 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5407 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5408 rb_ary_cat(ary, elem, 2);
5409 }
5410 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5411 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5412 RB_GC_GUARD(ary);
5413 hash = RB_OBJ_SET_FROZEN_SHAREABLE(rb_obj_hide(hash));
5414
5415 /* Emit optimized code */
5416 FLUSH_CHUNK();
5417 if (first_chunk) {
5418 ADD_INSN1(ret, line_node, duphash, hash);
5419 first_chunk = 0;
5420 }
5421 else {
5422 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5423 ADD_INSN(ret, line_node, swap);
5424
5425 ADD_INSN1(ret, line_node, putobject, hash);
5426
5427 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5428 }
5429 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5430 }
5431 }
5432
5433 /* Base case: Compile "count" elements */
5434 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5435
5436 if (CPDEBUG > 0) {
5437 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5438 }
5439
5440 if (RNODE_LIST(node)->nd_head) {
5441 /* Normal key-value pair */
5442 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5443 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5444 stack_len += 2;
5445
5446 /* If there are many pushed elements, flush them to avoid stack overflow */
5447 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5448 }
5449 else {
5450 /* kwsplat case: foo(..., **kw, ...) */
5451 FLUSH_CHUNK();
5452
5453 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5454 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5455 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5456 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5457 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5458
5459 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5460 if (empty_kw) {
5461 if (only_kw && method_call_keywords) {
5462 /* **{} appears at the only keyword argument in method call,
5463 * so it won't be modified.
5464 * kw is a special NODE_LIT that contains a special empty hash,
5465 * so this emits: putobject {}.
5466 * This is only done for method calls and not for literal hashes,
5467 * because literal hashes should always result in a new hash.
5468 */
5469 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5470 }
5471 else if (first_kw) {
5472 /* **{} appears as the first keyword argument, so it may be modified.
5473 * We need to create a fresh hash object.
5474 */
5475 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5476 }
5477 /* Any empty keyword splats that are not the first can be ignored.
5478 * since merging an empty hash into the existing hash is the same
5479 * as not merging it. */
5480 }
5481 else {
5482 if (only_kw && method_call_keywords) {
5483 /* **kw is only keyword argument in method call.
5484 * Use directly. This will be not be flagged as mutable.
5485 * This is only done for method calls and not for literal hashes,
5486 * because literal hashes should always result in a new hash.
5487 */
5488 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5489 }
5490 else {
5491 /* There is more than one keyword argument, or this is not a method
5492 * call. In that case, we need to add an empty hash (if first keyword),
5493 * or merge the hash to the accumulated hash (if not the first keyword).
5494 */
5495 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5496 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5497 else ADD_INSN(ret, line_node, swap);
5498
5499 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5500
5501 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5502 }
5503 }
5504
5505 first_chunk = 0;
5506 }
5507 }
5508 }
5509
5510 FLUSH_CHUNK();
5511#undef FLUSH_CHUNK
5512 return 1;
5513}
5514
5515VALUE
5516rb_node_case_when_optimizable_literal(const NODE *const node)
5517{
5518 switch (nd_type(node)) {
5519 case NODE_INTEGER:
5520 return rb_node_integer_literal_val(node);
5521 case NODE_FLOAT: {
5522 VALUE v = rb_node_float_literal_val(node);
5523 double ival;
5524
5525 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5526 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5527 }
5528 return v;
5529 }
5530 case NODE_RATIONAL:
5531 case NODE_IMAGINARY:
5532 return Qundef;
5533 case NODE_NIL:
5534 return Qnil;
5535 case NODE_TRUE:
5536 return Qtrue;
5537 case NODE_FALSE:
5538 return Qfalse;
5539 case NODE_SYM:
5540 return rb_node_sym_string_val(node);
5541 case NODE_LINE:
5542 return rb_node_line_lineno_val(node);
5543 case NODE_STR:
5544 return rb_node_str_string_val(node);
5545 case NODE_FILE:
5546 return rb_node_file_path_val(node);
5547 }
5548 return Qundef;
5549}
5550
5551static int
5552when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5553 LABEL *l1, int only_special_literals, VALUE literals)
5554{
5555 while (vals) {
5556 const NODE *val = RNODE_LIST(vals)->nd_head;
5557 VALUE lit = rb_node_case_when_optimizable_literal(val);
5558
5559 if (UNDEF_P(lit)) {
5560 only_special_literals = 0;
5561 }
5562 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5563 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5564 }
5565
5566 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5567 debugp_param("nd_lit", get_string_value(val));
5568 lit = get_string_value(val);
5569 ADD_INSN1(cond_seq, val, putobject, lit);
5570 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5571 }
5572 else {
5573 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5574 }
5575
5576 // Emit pattern === target
5577 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5578 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5579 ADD_INSNL(cond_seq, val, branchif, l1);
5580 vals = RNODE_LIST(vals)->nd_next;
5581 }
5582 return only_special_literals;
5583}
5584
5585static int
5586when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5587 LABEL *l1, int only_special_literals, VALUE literals)
5588{
5589 const NODE *line_node = vals;
5590
5591 switch (nd_type(vals)) {
5592 case NODE_LIST:
5593 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5594 return COMPILE_NG;
5595 break;
5596 case NODE_SPLAT:
5597 ADD_INSN (cond_seq, line_node, dup);
5598 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5599 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5600 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5601 ADD_INSNL(cond_seq, line_node, branchif, l1);
5602 break;
5603 case NODE_ARGSCAT:
5604 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5605 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5606 break;
5607 case NODE_ARGSPUSH:
5608 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5609 ADD_INSN (cond_seq, line_node, dup);
5610 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5611 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5612 ADD_INSNL(cond_seq, line_node, branchif, l1);
5613 break;
5614 default:
5615 ADD_INSN (cond_seq, line_node, dup);
5616 CHECK(COMPILE(cond_seq, "when val", vals));
5617 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5618 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5619 ADD_INSNL(cond_seq, line_node, branchif, l1);
5620 break;
5621 }
5622 return COMPILE_OK;
5623}
5624
5625/* Multiple Assignment Handling
5626 *
5627 * In order to handle evaluation of multiple assignment such that the left hand side
5628 * is evaluated before the right hand side, we need to process the left hand side
5629 * and see if there are any attributes that need to be assigned, or constants set
5630 * on explicit objects. If so, we add instructions to evaluate the receiver of
5631 * any assigned attributes or constants before we process the right hand side.
5632 *
5633 * For a multiple assignment such as:
5634 *
5635 * l1.m1, l2[0] = r3, r4
5636 *
5637 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5638 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5639 * On the VM stack, this looks like:
5640 *
5641 * self # putself
5642 * l1 # send
5643 * l1, self # putself
5644 * l1, l2 # send
5645 * l1, l2, 0 # putobject 0
5646 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5647 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5648 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5649 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5650 * l1, l2, 0, [r3, r4], r4, m1= # send
5651 * l1, l2, 0, [r3, r4], r4 # pop
5652 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5653 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5654 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5655 * l1, l2, 0, [r3, r4], r4, []= # send
5656 * l1, l2, 0, [r3, r4], r4 # pop
5657 * l1, l2, 0, [r3, r4] # pop
5658 * [r3, r4], l2, 0, [r3, r4] # setn 3
5659 * [r3, r4], l2, 0 # pop
5660 * [r3, r4], l2 # pop
5661 * [r3, r4] # pop
5662 *
5663 * This is made more complex when you have to handle splats, post args,
5664 * and arbitrary levels of nesting. You need to keep track of the total
5665 * number of attributes to set, and for each attribute, how many entries
5666 * are on the stack before the final attribute, in order to correctly
5667 * calculate the topn value to use to get the receiver of the attribute
5668 * setter method.
5669 *
5670 * A brief description of the VM stack for simple multiple assignment
5671 * with no splat (rhs_array will not be present if the return value of
5672 * the multiple assignment is not needed):
5673 *
5674 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5675 *
5676 * For multiple assignment with splats, while processing the part before
5677 * the splat (splat+post here is an array of the splat and the post arguments):
5678 *
5679 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5680 *
5681 * When processing the splat and post arguments:
5682 *
5683 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5684 *
5685 * When processing nested multiple assignment, existing values on the stack
5686 * are kept. So for:
5687 *
5688 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5689 *
5690 * The stack layout would be the following before processing the nested
5691 * multiple assignment:
5692 *
5693 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5694 *
5695 * In order to handle this correctly, we need to keep track of the nesting
5696 * level for each attribute assignment, as well as the attribute number
5697 * (left hand side attributes are processed left to right) and number of
5698 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5699 * this information.
5700 *
5701 * We also need to track information for the entire multiple assignment, such
5702 * as the total number of arguments, and the current nesting level, to
5703 * handle both nested multiple assignment as well as cases where the
5704 * rhs is not needed. We also need to keep track of all attribute
5705 * assignments in this, which we do using a linked listed. struct masgn_state
5706 * tracks this information.
5707 */
5708
5710 INSN *before_insn;
5711 struct masgn_lhs_node *next;
5712 const NODE *line_node;
5713 int argn;
5714 int num_args;
5715 int lhs_pos;
5716};
5717
5719 struct masgn_lhs_node *first_memo;
5720 struct masgn_lhs_node *last_memo;
5721 int lhs_level;
5722 int num_args;
5723 bool nested;
5724};
5725
5726static int
5727add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5728{
5729 if (!state) {
5730 rb_bug("no masgn_state");
5731 }
5732
5733 struct masgn_lhs_node *memo;
5734 memo = malloc(sizeof(struct masgn_lhs_node));
5735 if (!memo) {
5736 return COMPILE_NG;
5737 }
5738
5739 memo->before_insn = before_insn;
5740 memo->line_node = line_node;
5741 memo->argn = state->num_args + 1;
5742 memo->num_args = argc;
5743 state->num_args += argc;
5744 memo->lhs_pos = lhs_pos;
5745 memo->next = NULL;
5746 if (!state->first_memo) {
5747 state->first_memo = memo;
5748 }
5749 else {
5750 state->last_memo->next = memo;
5751 }
5752 state->last_memo = memo;
5753
5754 return COMPILE_OK;
5755}
5756
5757static 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);
5758
5759static int
5760compile_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)
5761{
5762 switch (nd_type(node)) {
5763 case NODE_ATTRASGN: {
5764 INSN *iobj;
5765 const NODE *line_node = node;
5766
5767 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5768
5769 bool safenav_call = false;
5770 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5771 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5772 ASSUME(iobj);
5773 ELEM_REMOVE(insn_element);
5774 if (!IS_INSN_ID(iobj, send)) {
5775 safenav_call = true;
5776 iobj = (INSN *)get_prev_insn(iobj);
5777 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5778 }
5779 (pre->last = iobj->link.prev)->next = 0;
5780
5781 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5782 int argc = vm_ci_argc(ci) + 1;
5783 ci = ci_argc_set(iseq, ci, argc);
5784 OPERAND_AT(iobj, 0) = (VALUE)ci;
5785 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5786
5787 if (argc == 1) {
5788 ADD_INSN(lhs, line_node, swap);
5789 }
5790 else {
5791 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5792 }
5793
5794 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5795 return COMPILE_NG;
5796 }
5797
5798 iobj->link.prev = lhs->last;
5799 lhs->last->next = &iobj->link;
5800 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5801 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5802 int argc = vm_ci_argc(ci);
5803 bool dupsplat = false;
5804 ci = ci_argc_set(iseq, ci, argc - 1);
5805 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5806 /* Given h[*a], _ = ary
5807 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5808 * `a` must be dupped, because it will be appended with ary[0]
5809 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5810 */
5811 dupsplat = true;
5812 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5813 }
5814 OPERAND_AT(iobj, 0) = (VALUE)ci;
5815 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5816
5817 /* Given: h[*a], h[*b, 1] = ary
5818 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5819 * so this uses splatarray true on a to dup it before using pushtoarray
5820 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5821 * so you can use pushtoarray directly
5822 */
5823 int line_no = nd_line(line_node);
5824 int node_id = nd_node_id(line_node);
5825
5826 if (dupsplat) {
5827 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5828 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5829 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5830 }
5831 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5832 }
5833 if (!safenav_call) {
5834 ADD_INSN(lhs, line_node, pop);
5835 if (argc != 1) {
5836 ADD_INSN(lhs, line_node, pop);
5837 }
5838 }
5839 for (int i=0; i < argc; i++) {
5840 ADD_INSN(post, line_node, pop);
5841 }
5842 break;
5843 }
5844 case NODE_MASGN: {
5845 DECL_ANCHOR(nest_rhs);
5846 INIT_ANCHOR(nest_rhs);
5847 DECL_ANCHOR(nest_lhs);
5848 INIT_ANCHOR(nest_lhs);
5849
5850 int prev_level = state->lhs_level;
5851 bool prev_nested = state->nested;
5852 state->nested = 1;
5853 state->lhs_level = lhs_pos - 1;
5854 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5855 state->lhs_level = prev_level;
5856 state->nested = prev_nested;
5857
5858 ADD_SEQ(lhs, nest_rhs);
5859 ADD_SEQ(lhs, nest_lhs);
5860 break;
5861 }
5862 case NODE_CDECL:
5863 if (!RNODE_CDECL(node)->nd_vid) {
5864 /* Special handling only needed for expr::C, not for C */
5865 INSN *iobj;
5866
5867 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5868
5869 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5870 iobj = (INSN *)insn_element; /* setconstant insn */
5871 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5872 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5873 ELEM_REMOVE(insn_element);
5874 pre->last = iobj->link.prev;
5875 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5876
5877 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5878 return COMPILE_NG;
5879 }
5880
5881 ADD_INSN(post, node, pop);
5882 break;
5883 }
5884 /* Fallthrough */
5885 default: {
5886 DECL_ANCHOR(anchor);
5887 INIT_ANCHOR(anchor);
5888 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5889 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5890 ADD_SEQ(lhs, anchor);
5891 }
5892 }
5893
5894 return COMPILE_OK;
5895}
5896
5897static int
5898compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5899{
5900 if (lhsn) {
5901 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5902 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5903 }
5904 return COMPILE_OK;
5905}
5906
5907static int
5908compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5909 const NODE *rhsn, const NODE *orig_lhsn)
5910{
5911 VALUE mem[64];
5912 const int memsize = numberof(mem);
5913 int memindex = 0;
5914 int llen = 0, rlen = 0;
5915 int i;
5916 const NODE *lhsn = orig_lhsn;
5917
5918#define MEMORY(v) { \
5919 int i; \
5920 if (memindex == memsize) return 0; \
5921 for (i=0; i<memindex; i++) { \
5922 if (mem[i] == (v)) return 0; \
5923 } \
5924 mem[memindex++] = (v); \
5925}
5926
5927 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5928 return 0;
5929 }
5930
5931 while (lhsn) {
5932 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5933 switch (nd_type(ln)) {
5934 case NODE_LASGN:
5935 case NODE_DASGN:
5936 case NODE_IASGN:
5937 case NODE_CVASGN:
5938 MEMORY(get_nd_vid(ln));
5939 break;
5940 default:
5941 return 0;
5942 }
5943 lhsn = RNODE_LIST(lhsn)->nd_next;
5944 llen++;
5945 }
5946
5947 while (rhsn) {
5948 if (llen <= rlen) {
5949 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5950 }
5951 else {
5952 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5953 }
5954 rhsn = RNODE_LIST(rhsn)->nd_next;
5955 rlen++;
5956 }
5957
5958 if (llen > rlen) {
5959 for (i=0; i<llen-rlen; i++) {
5960 ADD_INSN(ret, orig_lhsn, putnil);
5961 }
5962 }
5963
5964 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5965 return 1;
5966}
5967
5968static int
5969compile_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)
5970{
5971 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5972 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5973 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5974 const NODE *lhsn_count = lhsn;
5975 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5976
5977 int llen = 0;
5978 int lpos = 0;
5979
5980 while (lhsn_count) {
5981 llen++;
5982 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5983 }
5984 while (lhsn) {
5985 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5986 lpos++;
5987 lhsn = RNODE_LIST(lhsn)->nd_next;
5988 }
5989
5990 if (lhs_splat) {
5991 if (nd_type_p(splatn, NODE_POSTARG)) {
5992 /*a, b, *r, p1, p2 */
5993 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5994 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5995 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5996 int ppos = 0;
5997 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5998
5999 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6000
6001 if (NODE_NAMED_REST_P(restn)) {
6002 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6003 }
6004 while (postn) {
6005 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6006 ppos++;
6007 postn = RNODE_LIST(postn)->nd_next;
6008 }
6009 }
6010 else {
6011 /* a, b, *r */
6012 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6013 }
6014 }
6015
6016 if (!state->nested) {
6017 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6018 }
6019
6020 if (!popped) {
6021 ADD_INSN(rhs, node, dup);
6022 }
6023 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6024 return COMPILE_OK;
6025}
6026
6027static int
6028compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6029{
6030 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6031 struct masgn_state state;
6032 state.lhs_level = popped ? 0 : 1;
6033 state.nested = 0;
6034 state.num_args = 0;
6035 state.first_memo = NULL;
6036 state.last_memo = NULL;
6037
6038 DECL_ANCHOR(pre);
6039 INIT_ANCHOR(pre);
6040 DECL_ANCHOR(rhs);
6041 INIT_ANCHOR(rhs);
6042 DECL_ANCHOR(lhs);
6043 INIT_ANCHOR(lhs);
6044 DECL_ANCHOR(post);
6045 INIT_ANCHOR(post);
6046 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6047
6048 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6049 while (memo) {
6050 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6051 for (int i = 0; i < memo->num_args; i++) {
6052 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6053 }
6054 tmp_memo = memo->next;
6055 free(memo);
6056 memo = tmp_memo;
6057 }
6058 CHECK(ok);
6059
6060 ADD_SEQ(ret, pre);
6061 ADD_SEQ(ret, rhs);
6062 ADD_SEQ(ret, lhs);
6063 if (!popped && state.num_args >= 1) {
6064 /* make sure rhs array is returned before popping */
6065 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6066 }
6067 ADD_SEQ(ret, post);
6068 }
6069 return COMPILE_OK;
6070}
6071
6072static VALUE
6073collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6074{
6075 VALUE arr = rb_ary_new();
6076 for (;;) {
6077 switch (nd_type(node)) {
6078 case NODE_CONST:
6079 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6080 RB_OBJ_SET_SHAREABLE(arr);
6081 return arr;
6082 case NODE_COLON3:
6083 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6084 rb_ary_unshift(arr, ID2SYM(idNULL));
6085 RB_OBJ_SET_SHAREABLE(arr);
6086 return arr;
6087 case NODE_COLON2:
6088 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6089 node = RNODE_COLON2(node)->nd_head;
6090 break;
6091 default:
6092 return Qfalse;
6093 }
6094 }
6095}
6096
6097static int
6098compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6099 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6100{
6101 switch (nd_type(node)) {
6102 case NODE_CONST:
6103 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6104 ADD_INSN1(body, node, putobject, Qtrue);
6105 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6106 break;
6107 case NODE_COLON3:
6108 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6109 ADD_INSN(body, node, pop);
6110 ADD_INSN1(body, node, putobject, rb_cObject);
6111 ADD_INSN1(body, node, putobject, Qtrue);
6112 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6113 break;
6114 case NODE_COLON2:
6115 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6116 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6117 ADD_INSN1(body, node, putobject, Qfalse);
6118 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6119 break;
6120 default:
6121 CHECK(COMPILE(pref, "const colon2 prefix", node));
6122 break;
6123 }
6124 return COMPILE_OK;
6125}
6126
6127static int
6128compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6129{
6130 if (nd_type_p(cpath, NODE_COLON3)) {
6131 /* toplevel class ::Foo */
6132 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6133 return VM_DEFINECLASS_FLAG_SCOPED;
6134 }
6135 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6136 /* Bar::Foo */
6137 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6138 return VM_DEFINECLASS_FLAG_SCOPED;
6139 }
6140 else {
6141 /* class at cbase Foo */
6142 ADD_INSN1(ret, cpath, putspecialobject,
6143 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6144 return 0;
6145 }
6146}
6147
6148static inline int
6149private_recv_p(const NODE *node)
6150{
6151 NODE *recv = get_nd_recv(node);
6152 if (recv && nd_type_p(recv, NODE_SELF)) {
6153 return RNODE_SELF(recv)->nd_state != 0;
6154 }
6155 return 0;
6156}
6157
6158static void
6159defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6160 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6161
6162static int
6163compile_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);
6164
6165static void
6166defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6167 const NODE *const node, LABEL **lfinish, VALUE needstr,
6168 bool keep_result)
6169{
6170 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6171 enum node_type type;
6172 const int line = nd_line(node);
6173 const NODE *line_node = node;
6174
6175 switch (type = nd_type(node)) {
6176
6177 /* easy literals */
6178 case NODE_NIL:
6179 expr_type = DEFINED_NIL;
6180 break;
6181 case NODE_SELF:
6182 expr_type = DEFINED_SELF;
6183 break;
6184 case NODE_TRUE:
6185 expr_type = DEFINED_TRUE;
6186 break;
6187 case NODE_FALSE:
6188 expr_type = DEFINED_FALSE;
6189 break;
6190
6191 case NODE_HASH:
6192 case NODE_LIST:{
6193 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6194
6195 if (vals) {
6196 do {
6197 if (RNODE_LIST(vals)->nd_head) {
6198 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6199
6200 if (!lfinish[1]) {
6201 lfinish[1] = NEW_LABEL(line);
6202 }
6203 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6204 }
6205 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6206 }
6207 }
6208 /* fall through */
6209 case NODE_STR:
6210 case NODE_SYM:
6211 case NODE_REGX:
6212 case NODE_LINE:
6213 case NODE_FILE:
6214 case NODE_ENCODING:
6215 case NODE_INTEGER:
6216 case NODE_FLOAT:
6217 case NODE_RATIONAL:
6218 case NODE_IMAGINARY:
6219 case NODE_ZLIST:
6220 case NODE_AND:
6221 case NODE_OR:
6222 default:
6223 expr_type = DEFINED_EXPR;
6224 break;
6225
6226 case NODE_SPLAT:
6227 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6228 if (!lfinish[1]) {
6229 lfinish[1] = NEW_LABEL(line);
6230 }
6231 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6232 expr_type = DEFINED_EXPR;
6233 break;
6234
6235 /* variables */
6236 case NODE_LVAR:
6237 case NODE_DVAR:
6238 expr_type = DEFINED_LVAR;
6239 break;
6240
6241#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6242 case NODE_IVAR:
6243 ADD_INSN3(ret, line_node, definedivar,
6244 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6245 return;
6246
6247 case NODE_GVAR:
6248 ADD_INSN(ret, line_node, putnil);
6249 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6250 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6251 return;
6252
6253 case NODE_CVAR:
6254 ADD_INSN(ret, line_node, putnil);
6255 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6256 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6257 return;
6258
6259 case NODE_CONST:
6260 ADD_INSN(ret, line_node, putnil);
6261 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6262 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6263 return;
6264 case NODE_COLON2:
6265 if (!lfinish[1]) {
6266 lfinish[1] = NEW_LABEL(line);
6267 }
6268 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6269 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6270 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6271
6272 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6273 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6274 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6275 }
6276 else {
6277 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6278 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6279 }
6280 return;
6281 case NODE_COLON3:
6282 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6283 ADD_INSN3(ret, line_node, defined,
6284 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6285 return;
6286
6287 /* method dispatch */
6288 case NODE_CALL:
6289 case NODE_OPCALL:
6290 case NODE_VCALL:
6291 case NODE_FCALL:
6292 case NODE_ATTRASGN:{
6293 const int explicit_receiver =
6294 (type == NODE_CALL || type == NODE_OPCALL ||
6295 (type == NODE_ATTRASGN && !private_recv_p(node)));
6296
6297 if (get_nd_args(node) || explicit_receiver) {
6298 if (!lfinish[1]) {
6299 lfinish[1] = NEW_LABEL(line);
6300 }
6301 if (!lfinish[2]) {
6302 lfinish[2] = NEW_LABEL(line);
6303 }
6304 }
6305 if (get_nd_args(node)) {
6306 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6307 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6308 }
6309 if (explicit_receiver) {
6310 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6311 switch (nd_type(get_nd_recv(node))) {
6312 case NODE_CALL:
6313 case NODE_OPCALL:
6314 case NODE_VCALL:
6315 case NODE_FCALL:
6316 case NODE_ATTRASGN:
6317 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6318 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6319 break;
6320 default:
6321 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6322 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6323 break;
6324 }
6325 if (keep_result) {
6326 ADD_INSN(ret, line_node, dup);
6327 }
6328 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6329 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6330 }
6331 else {
6332 ADD_INSN(ret, line_node, putself);
6333 if (keep_result) {
6334 ADD_INSN(ret, line_node, dup);
6335 }
6336 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6337 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6338 }
6339 return;
6340 }
6341
6342 case NODE_YIELD:
6343 ADD_INSN(ret, line_node, putnil);
6344 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6345 PUSH_VAL(DEFINED_YIELD));
6346 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6347 return;
6348
6349 case NODE_BACK_REF:
6350 case NODE_NTH_REF:
6351 ADD_INSN(ret, line_node, putnil);
6352 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6353 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6354 PUSH_VAL(DEFINED_GVAR));
6355 return;
6356
6357 case NODE_SUPER:
6358 case NODE_ZSUPER:
6359 ADD_INSN(ret, line_node, putnil);
6360 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6361 PUSH_VAL(DEFINED_ZSUPER));
6362 return;
6363
6364#undef PUSH_VAL
6365 case NODE_OP_ASGN1:
6366 case NODE_OP_ASGN2:
6367 case NODE_OP_ASGN_OR:
6368 case NODE_OP_ASGN_AND:
6369 case NODE_MASGN:
6370 case NODE_LASGN:
6371 case NODE_DASGN:
6372 case NODE_GASGN:
6373 case NODE_IASGN:
6374 case NODE_CDECL:
6375 case NODE_CVASGN:
6376 case NODE_OP_CDECL:
6377 expr_type = DEFINED_ASGN;
6378 break;
6379 }
6380
6381 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6382
6383 if (needstr != Qfalse) {
6384 VALUE str = rb_iseq_defined_string(expr_type);
6385 ADD_INSN1(ret, line_node, putobject, str);
6386 }
6387 else {
6388 ADD_INSN1(ret, line_node, putobject, Qtrue);
6389 }
6390}
6391
6392static void
6393build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6394{
6395 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6396 iseq_set_exception_local_table(iseq);
6397}
6398
6399static void
6400defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6401 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6402{
6403 LINK_ELEMENT *lcur = ret->last;
6404 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6405 if (lfinish[1]) {
6406 int line = nd_line(node);
6407 LABEL *lstart = NEW_LABEL(line);
6408 LABEL *lend = NEW_LABEL(line);
6409 const rb_iseq_t *rescue;
6411 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6412 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6413 rb_str_concat(rb_str_new2("defined guard in "),
6414 ISEQ_BODY(iseq)->location.label),
6415 ISEQ_TYPE_RESCUE, 0);
6416 lstart->rescued = LABEL_RESCUE_BEG;
6417 lend->rescued = LABEL_RESCUE_END;
6418 APPEND_LABEL(ret, lcur, lstart);
6419 ADD_LABEL(ret, lend);
6420 if (!ignore) {
6421 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6422 }
6423 }
6424}
6425
6426static int
6427compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6428{
6429 const int line = nd_line(node);
6430 const NODE *line_node = node;
6431 if (!RNODE_DEFINED(node)->nd_head) {
6432 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6433 ADD_INSN1(ret, line_node, putobject, str);
6434 }
6435 else {
6436 LABEL *lfinish[3];
6437 LINK_ELEMENT *last = ret->last;
6438 lfinish[0] = NEW_LABEL(line);
6439 lfinish[1] = 0;
6440 lfinish[2] = 0;
6441 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6442 if (lfinish[1]) {
6443 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6444 ADD_INSN(ret, line_node, swap);
6445 if (lfinish[2]) {
6446 ADD_LABEL(ret, lfinish[2]);
6447 }
6448 ADD_INSN(ret, line_node, pop);
6449 ADD_LABEL(ret, lfinish[1]);
6450 }
6451 ADD_LABEL(ret, lfinish[0]);
6452 }
6453 return COMPILE_OK;
6454}
6455
6456static VALUE
6457make_name_for_block(const rb_iseq_t *orig_iseq)
6458{
6459 int level = 1;
6460 const rb_iseq_t *iseq = orig_iseq;
6461
6462 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6463 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6464 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6465 level++;
6466 }
6467 iseq = ISEQ_BODY(iseq)->parent_iseq;
6468 }
6469 }
6470
6471 if (level == 1) {
6472 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6473 }
6474 else {
6475 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6476 }
6477}
6478
6479static void
6480push_ensure_entry(rb_iseq_t *iseq,
6482 struct ensure_range *er, const void *const node)
6483{
6484 enl->ensure_node = node;
6485 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6486 enl->erange = er;
6487 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6488}
6489
6490static void
6491add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6492 LABEL *lstart, LABEL *lend)
6493{
6494 struct ensure_range *ne =
6495 compile_data_alloc(iseq, sizeof(struct ensure_range));
6496
6497 while (erange->next != 0) {
6498 erange = erange->next;
6499 }
6500 ne->next = 0;
6501 ne->begin = lend;
6502 ne->end = erange->end;
6503 erange->end = lstart;
6504
6505 erange->next = ne;
6506}
6507
6508static bool
6509can_add_ensure_iseq(const rb_iseq_t *iseq)
6510{
6512 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6513 while (e) {
6514 if (e->ensure_node) return false;
6515 e = e->prev;
6516 }
6517 }
6518 return true;
6519}
6520
6521static void
6522add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6523{
6524 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6525
6527 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6528 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6529 DECL_ANCHOR(ensure);
6530
6531 INIT_ANCHOR(ensure);
6532 while (enlp) {
6533 if (enlp->erange != NULL) {
6534 DECL_ANCHOR(ensure_part);
6535 LABEL *lstart = NEW_LABEL(0);
6536 LABEL *lend = NEW_LABEL(0);
6537 INIT_ANCHOR(ensure_part);
6538
6539 add_ensure_range(iseq, enlp->erange, lstart, lend);
6540
6541 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6542 ADD_LABEL(ensure_part, lstart);
6543 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6544 ADD_LABEL(ensure_part, lend);
6545 ADD_SEQ(ensure, ensure_part);
6546 }
6547 else {
6548 if (!is_return) {
6549 break;
6550 }
6551 }
6552 enlp = enlp->prev;
6553 }
6554 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6555 ADD_SEQ(ret, ensure);
6556}
6557
6558#if RUBY_DEBUG
6559static int
6560check_keyword(const NODE *node)
6561{
6562 /* This check is essentially a code clone of compile_keyword_arg. */
6563
6564 if (nd_type_p(node, NODE_LIST)) {
6565 while (RNODE_LIST(node)->nd_next) {
6566 node = RNODE_LIST(node)->nd_next;
6567 }
6568 node = RNODE_LIST(node)->nd_head;
6569 }
6570
6571 return keyword_node_p(node);
6572}
6573#endif
6574
6575static bool
6576keyword_node_single_splat_p(NODE *kwnode)
6577{
6578 RUBY_ASSERT(keyword_node_p(kwnode));
6579
6580 NODE *node = RNODE_HASH(kwnode)->nd_head;
6581 return RNODE_LIST(node)->nd_head == NULL &&
6582 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6583}
6584
6585static void
6586compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6587 NODE *kwnode, unsigned int *flag_ptr)
6588{
6589 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6590 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6591 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6592 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6593 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6594}
6595
6596#define SPLATARRAY_FALSE 0
6597#define SPLATARRAY_TRUE 1
6598#define DUP_SINGLE_KW_SPLAT 2
6599
6600static int
6601setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6602 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6603{
6604 if (!argn) return 0;
6605
6606 NODE *kwnode = NULL;
6607
6608 switch (nd_type(argn)) {
6609 case NODE_LIST: {
6610 // f(x, y, z)
6611 int len = compile_args(iseq, args, argn, &kwnode);
6612 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6613
6614 if (kwnode) {
6615 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6616 len -= 1;
6617 }
6618 else {
6619 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6620 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6621 }
6622 else {
6623 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6624 }
6625 }
6626 }
6627
6628 return len;
6629 }
6630 case NODE_SPLAT: {
6631 // f(*a)
6632 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6633 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6634 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6635 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6636 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6637 return 1;
6638 }
6639 case NODE_ARGSCAT: {
6640 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6641 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6642 bool args_pushed = false;
6643
6644 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6645 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6646 if (kwnode) rest_len--;
6647 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6648 args_pushed = true;
6649 }
6650 else {
6651 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6652 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6653 }
6654
6655 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6656 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6657 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6658 argc += 1;
6659 }
6660 else if (!args_pushed) {
6661 ADD_INSN(args, argn, concattoarray);
6662 }
6663
6664 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6665 if (kwnode) {
6666 // kwsplat
6667 *flag_ptr |= VM_CALL_KW_SPLAT;
6668 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6669 argc += 1;
6670 }
6671
6672 return argc;
6673 }
6674 case NODE_ARGSPUSH: {
6675 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6676 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6677
6678 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6679 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6680 if (kwnode) rest_len--;
6681 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6682 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6683 }
6684 else {
6685 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6686 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6687 }
6688 else {
6689 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6690 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6691 }
6692 }
6693
6694 if (kwnode) {
6695 // f(*a, k:1)
6696 *flag_ptr |= VM_CALL_KW_SPLAT;
6697 if (!keyword_node_single_splat_p(kwnode)) {
6698 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6699 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6700 }
6701 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6702 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6703 }
6704 else {
6705 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6706 }
6707 argc += 1;
6708 }
6709
6710 return argc;
6711 }
6712 default: {
6713 UNKNOWN_NODE("setup_arg", argn, Qnil);
6714 }
6715 }
6716}
6717
6718static void
6719setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6720{
6721 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6722 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6723 }
6724}
6725
6726static bool
6727setup_args_dup_rest_p(const NODE *argn)
6728{
6729 switch(nd_type(argn)) {
6730 case NODE_LVAR:
6731 case NODE_DVAR:
6732 case NODE_GVAR:
6733 case NODE_IVAR:
6734 case NODE_CVAR:
6735 case NODE_CONST:
6736 case NODE_COLON3:
6737 case NODE_INTEGER:
6738 case NODE_FLOAT:
6739 case NODE_RATIONAL:
6740 case NODE_IMAGINARY:
6741 case NODE_STR:
6742 case NODE_SYM:
6743 case NODE_REGX:
6744 case NODE_SELF:
6745 case NODE_NIL:
6746 case NODE_TRUE:
6747 case NODE_FALSE:
6748 case NODE_LAMBDA:
6749 case NODE_NTH_REF:
6750 case NODE_BACK_REF:
6751 return false;
6752 case NODE_COLON2:
6753 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6754 case NODE_LIST:
6755 while (argn) {
6756 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6757 return true;
6758 }
6759 argn = RNODE_LIST(argn)->nd_next;
6760 }
6761 return false;
6762 default:
6763 return true;
6764 }
6765}
6766
6767static VALUE
6768setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6769 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6770{
6771 VALUE ret;
6772 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6773
6774 if (argn) {
6775 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6776 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6777
6778 if (check_arg) {
6779 switch(nd_type(check_arg)) {
6780 case(NODE_SPLAT):
6781 // avoid caller side array allocation for f(*arg)
6782 dup_rest = SPLATARRAY_FALSE;
6783 break;
6784 case(NODE_ARGSCAT):
6785 // avoid caller side array allocation for f(1, *arg)
6786 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6787 break;
6788 case(NODE_ARGSPUSH):
6789 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6790 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6791 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6792 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6793 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6794 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6795
6796 if (dup_rest == SPLATARRAY_FALSE) {
6797 // require allocation for keyword key/value/splat that may modify splatted argument
6798 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6799 while (node) {
6800 NODE *key_node = RNODE_LIST(node)->nd_head;
6801 if (key_node && setup_args_dup_rest_p(key_node)) {
6802 dup_rest = SPLATARRAY_TRUE;
6803 break;
6804 }
6805
6806 node = RNODE_LIST(node)->nd_next;
6807 NODE *value_node = RNODE_LIST(node)->nd_head;
6808 if (setup_args_dup_rest_p(value_node)) {
6809 dup_rest = SPLATARRAY_TRUE;
6810 break;
6811 }
6812
6813 node = RNODE_LIST(node)->nd_next;
6814 }
6815 }
6816 break;
6817 default:
6818 break;
6819 }
6820 }
6821
6822 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6823 // for block pass that may modify splatted argument, dup rest and kwrest if given
6824 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6825 }
6826 }
6827 initial_dup_rest = dup_rest;
6828
6829 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6830 DECL_ANCHOR(arg_block);
6831 INIT_ANCHOR(arg_block);
6832
6833 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6834 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6835
6836 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6837 const NODE * arg_node =
6838 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6839
6840 int argc = 0;
6841
6842 // Only compile leading args:
6843 // foo(x, y, ...)
6844 // ^^^^
6845 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6846 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6847 }
6848
6849 *flag |= VM_CALL_FORWARDING;
6850
6851 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6852 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6853 return INT2FIX(argc);
6854 }
6855 else {
6856 *flag |= VM_CALL_ARGS_BLOCKARG;
6857
6858 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6859 }
6860
6861 if (LIST_INSN_SIZE_ONE(arg_block)) {
6862 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6863 if (IS_INSN(elem)) {
6864 INSN *iobj = (INSN *)elem;
6865 if (iobj->insn_id == BIN(getblockparam)) {
6866 iobj->insn_id = BIN(getblockparamproxy);
6867 }
6868 }
6869 }
6870 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6871 ADD_SEQ(args, arg_block);
6872 }
6873 else {
6874 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6875 }
6876 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6877 return ret;
6878}
6879
6880static void
6881build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6882{
6883 const NODE *body = ptr;
6884 int line = nd_line(body);
6885 VALUE argc = INT2FIX(0);
6886 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6887
6888 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6889 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6890 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6891 iseq_set_local_table(iseq, 0, 0);
6892}
6893
6894static void
6895compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6896{
6897 const NODE *vars;
6898 LINK_ELEMENT *last;
6899 int line = nd_line(node);
6900 const NODE *line_node = node;
6901 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6902
6903#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6904 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6905#else
6906 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6907#endif
6908 ADD_INSN(ret, line_node, dup);
6909 ADD_INSNL(ret, line_node, branchunless, fail_label);
6910
6911 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6912 INSN *cap;
6913 if (RNODE_BLOCK(vars)->nd_next) {
6914 ADD_INSN(ret, line_node, dup);
6915 }
6916 last = ret->last;
6917 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6918 last = last->next; /* putobject :var */
6919 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6920 NULL, INT2FIX(0), NULL);
6921 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6922#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6923 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6924 /* only one name */
6925 DECL_ANCHOR(nom);
6926
6927 INIT_ANCHOR(nom);
6928 ADD_INSNL(nom, line_node, jump, end_label);
6929 ADD_LABEL(nom, fail_label);
6930# if 0 /* $~ must be MatchData or nil */
6931 ADD_INSN(nom, line_node, pop);
6932 ADD_INSN(nom, line_node, putnil);
6933# endif
6934 ADD_LABEL(nom, end_label);
6935 (nom->last->next = cap->link.next)->prev = nom->last;
6936 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6937 return;
6938 }
6939#endif
6940 }
6941 ADD_INSNL(ret, line_node, jump, end_label);
6942 ADD_LABEL(ret, fail_label);
6943 ADD_INSN(ret, line_node, pop);
6944 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6945 last = ret->last;
6946 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6947 last = last->next; /* putobject :var */
6948 ((INSN*)last)->insn_id = BIN(putnil);
6949 ((INSN*)last)->operand_size = 0;
6950 }
6951 ADD_LABEL(ret, end_label);
6952}
6953
6954static int
6955optimizable_range_item_p(const NODE *n)
6956{
6957 if (!n) return FALSE;
6958 switch (nd_type(n)) {
6959 case NODE_LINE:
6960 return TRUE;
6961 case NODE_INTEGER:
6962 return TRUE;
6963 case NODE_NIL:
6964 return TRUE;
6965 default:
6966 return FALSE;
6967 }
6968}
6969
6970static VALUE
6971optimized_range_item(const NODE *n)
6972{
6973 switch (nd_type(n)) {
6974 case NODE_LINE:
6975 return rb_node_line_lineno_val(n);
6976 case NODE_INTEGER:
6977 return rb_node_integer_literal_val(n);
6978 case NODE_FLOAT:
6979 return rb_node_float_literal_val(n);
6980 case NODE_RATIONAL:
6981 return rb_node_rational_literal_val(n);
6982 case NODE_IMAGINARY:
6983 return rb_node_imaginary_literal_val(n);
6984 case NODE_NIL:
6985 return Qnil;
6986 default:
6987 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6988 }
6989}
6990
6991static int
6992compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6993{
6994 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6995 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6996
6997 const int line = nd_line(node);
6998 const NODE *line_node = node;
6999 DECL_ANCHOR(cond_seq);
7000 LABEL *then_label, *else_label, *end_label;
7001 VALUE branches = Qfalse;
7002
7003 INIT_ANCHOR(cond_seq);
7004 then_label = NEW_LABEL(line);
7005 else_label = NEW_LABEL(line);
7006 end_label = 0;
7007
7008 NODE *cond = RNODE_IF(node)->nd_cond;
7009 if (nd_type(cond) == NODE_BLOCK) {
7010 cond = RNODE_BLOCK(cond)->nd_head;
7011 }
7012
7013 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7014 ADD_SEQ(ret, cond_seq);
7015
7016 if (then_label->refcnt && else_label->refcnt) {
7017 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7018 }
7019
7020 if (then_label->refcnt) {
7021 ADD_LABEL(ret, then_label);
7022
7023 DECL_ANCHOR(then_seq);
7024 INIT_ANCHOR(then_seq);
7025 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7026
7027 if (else_label->refcnt) {
7028 const NODE *const coverage_node = node_body ? node_body : node;
7029 add_trace_branch_coverage(
7030 iseq,
7031 ret,
7032 nd_code_loc(coverage_node),
7033 nd_node_id(coverage_node),
7034 0,
7035 type == NODE_IF ? "then" : "else",
7036 branches);
7037 end_label = NEW_LABEL(line);
7038 ADD_INSNL(then_seq, line_node, jump, end_label);
7039 if (!popped) {
7040 ADD_INSN(then_seq, line_node, pop);
7041 }
7042 }
7043 ADD_SEQ(ret, then_seq);
7044 }
7045
7046 if (else_label->refcnt) {
7047 ADD_LABEL(ret, else_label);
7048
7049 DECL_ANCHOR(else_seq);
7050 INIT_ANCHOR(else_seq);
7051 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7052
7053 if (then_label->refcnt) {
7054 const NODE *const coverage_node = node_else ? node_else : node;
7055 add_trace_branch_coverage(
7056 iseq,
7057 ret,
7058 nd_code_loc(coverage_node),
7059 nd_node_id(coverage_node),
7060 1,
7061 type == NODE_IF ? "else" : "then",
7062 branches);
7063 }
7064 ADD_SEQ(ret, else_seq);
7065 }
7066
7067 if (end_label) {
7068 ADD_LABEL(ret, end_label);
7069 }
7070
7071 return COMPILE_OK;
7072}
7073
7074static int
7075compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7076{
7077 const NODE *vals;
7078 const NODE *node = orig_node;
7079 LABEL *endlabel, *elselabel;
7080 DECL_ANCHOR(head);
7081 DECL_ANCHOR(body_seq);
7082 DECL_ANCHOR(cond_seq);
7083 int only_special_literals = 1;
7084 VALUE literals = rb_hash_new();
7085 int line;
7086 enum node_type type;
7087 const NODE *line_node;
7088 VALUE branches = Qfalse;
7089 int branch_id = 0;
7090
7091 INIT_ANCHOR(head);
7092 INIT_ANCHOR(body_seq);
7093 INIT_ANCHOR(cond_seq);
7094
7095 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7096
7097 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7098
7099 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7100
7101 node = RNODE_CASE(node)->nd_body;
7102 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7103 type = nd_type(node);
7104 line = nd_line(node);
7105 line_node = node;
7106
7107 endlabel = NEW_LABEL(line);
7108 elselabel = NEW_LABEL(line);
7109
7110 ADD_SEQ(ret, head); /* case VAL */
7111
7112 while (type == NODE_WHEN) {
7113 LABEL *l1;
7114
7115 l1 = NEW_LABEL(line);
7116 ADD_LABEL(body_seq, l1);
7117 ADD_INSN(body_seq, line_node, pop);
7118
7119 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7120 add_trace_branch_coverage(
7121 iseq,
7122 body_seq,
7123 nd_code_loc(coverage_node),
7124 nd_node_id(coverage_node),
7125 branch_id++,
7126 "when",
7127 branches);
7128
7129 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7130 ADD_INSNL(body_seq, line_node, jump, endlabel);
7131
7132 vals = RNODE_WHEN(node)->nd_head;
7133 if (vals) {
7134 switch (nd_type(vals)) {
7135 case NODE_LIST:
7136 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7137 if (only_special_literals < 0) return COMPILE_NG;
7138 break;
7139 case NODE_SPLAT:
7140 case NODE_ARGSCAT:
7141 case NODE_ARGSPUSH:
7142 only_special_literals = 0;
7143 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7144 break;
7145 default:
7146 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7147 }
7148 }
7149 else {
7150 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7151 }
7152
7153 node = RNODE_WHEN(node)->nd_next;
7154 if (!node) {
7155 break;
7156 }
7157 type = nd_type(node);
7158 line = nd_line(node);
7159 line_node = node;
7160 }
7161 /* else */
7162 if (node) {
7163 ADD_LABEL(cond_seq, elselabel);
7164 ADD_INSN(cond_seq, line_node, pop);
7165 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7166 CHECK(COMPILE_(cond_seq, "else", node, popped));
7167 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7168 }
7169 else {
7170 debugs("== else (implicit)\n");
7171 ADD_LABEL(cond_seq, elselabel);
7172 ADD_INSN(cond_seq, orig_node, pop);
7173 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7174 if (!popped) {
7175 ADD_INSN(cond_seq, orig_node, putnil);
7176 }
7177 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7178 }
7179
7180 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7181 ADD_INSN(ret, orig_node, dup);
7182 rb_obj_hide(literals);
7183 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7184 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7185 LABEL_REF(elselabel);
7186 }
7187
7188 ADD_SEQ(ret, cond_seq);
7189 ADD_SEQ(ret, body_seq);
7190 ADD_LABEL(ret, endlabel);
7191 return COMPILE_OK;
7192}
7193
7194static int
7195compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7196{
7197 const NODE *vals;
7198 const NODE *val;
7199 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7200 LABEL *endlabel;
7201 DECL_ANCHOR(body_seq);
7202 VALUE branches = Qfalse;
7203 int branch_id = 0;
7204
7205 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7206
7207 INIT_ANCHOR(body_seq);
7208 endlabel = NEW_LABEL(nd_line(node));
7209
7210 while (node && nd_type_p(node, NODE_WHEN)) {
7211 const int line = nd_line(node);
7212 LABEL *l1 = NEW_LABEL(line);
7213 ADD_LABEL(body_seq, l1);
7214
7215 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7216 add_trace_branch_coverage(
7217 iseq,
7218 body_seq,
7219 nd_code_loc(coverage_node),
7220 nd_node_id(coverage_node),
7221 branch_id++,
7222 "when",
7223 branches);
7224
7225 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7226 ADD_INSNL(body_seq, node, jump, endlabel);
7227
7228 vals = RNODE_WHEN(node)->nd_head;
7229 if (!vals) {
7230 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7231 }
7232 switch (nd_type(vals)) {
7233 case NODE_LIST:
7234 while (vals) {
7235 LABEL *lnext;
7236 val = RNODE_LIST(vals)->nd_head;
7237 lnext = NEW_LABEL(nd_line(val));
7238 debug_compile("== when2\n", (void)0);
7239 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7240 ADD_LABEL(ret, lnext);
7241 vals = RNODE_LIST(vals)->nd_next;
7242 }
7243 break;
7244 case NODE_SPLAT:
7245 case NODE_ARGSCAT:
7246 case NODE_ARGSPUSH:
7247 ADD_INSN(ret, vals, putnil);
7248 CHECK(COMPILE(ret, "when2/cond splat", vals));
7249 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7250 ADD_INSNL(ret, vals, branchif, l1);
7251 break;
7252 default:
7253 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7254 }
7255 node = RNODE_WHEN(node)->nd_next;
7256 }
7257 /* else */
7258 const NODE *const coverage_node = node ? node : orig_node;
7259 add_trace_branch_coverage(
7260 iseq,
7261 ret,
7262 nd_code_loc(coverage_node),
7263 nd_node_id(coverage_node),
7264 branch_id,
7265 "else",
7266 branches);
7267 CHECK(COMPILE_(ret, "else", node, popped));
7268 ADD_INSNL(ret, orig_node, jump, endlabel);
7269
7270 ADD_SEQ(ret, body_seq);
7271 ADD_LABEL(ret, endlabel);
7272 return COMPILE_OK;
7273}
7274
7275static 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);
7276
7277static 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);
7278static 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);
7279static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7280static 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);
7281static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7282
7283#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7284#define CASE3_BI_OFFSET_ERROR_STRING 1
7285#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7286#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7287#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7288
7289static int
7290iseq_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)
7291{
7292 const int line = nd_line(node);
7293 const NODE *line_node = node;
7294
7295 switch (nd_type(node)) {
7296 case NODE_ARYPTN: {
7297 /*
7298 * if pattern.use_rest_num?
7299 * rest_num = 0
7300 * end
7301 * if pattern.has_constant_node?
7302 * unless pattern.constant === obj
7303 * goto match_failed
7304 * end
7305 * end
7306 * unless obj.respond_to?(:deconstruct)
7307 * goto match_failed
7308 * end
7309 * d = obj.deconstruct
7310 * unless Array === d
7311 * goto type_error
7312 * end
7313 * min_argc = pattern.pre_args_num + pattern.post_args_num
7314 * if pattern.has_rest_arg?
7315 * unless d.length >= min_argc
7316 * goto match_failed
7317 * end
7318 * else
7319 * unless d.length == min_argc
7320 * goto match_failed
7321 * end
7322 * end
7323 * pattern.pre_args_num.each do |i|
7324 * unless pattern.pre_args[i].match?(d[i])
7325 * goto match_failed
7326 * end
7327 * end
7328 * if pattern.use_rest_num?
7329 * rest_num = d.length - min_argc
7330 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7331 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7332 * goto match_failed
7333 * end
7334 * end
7335 * end
7336 * pattern.post_args_num.each do |i|
7337 * j = pattern.pre_args_num + i
7338 * j += rest_num
7339 * unless pattern.post_args[i].match?(d[j])
7340 * goto match_failed
7341 * end
7342 * end
7343 * goto matched
7344 * type_error:
7345 * FrozenCore.raise TypeError
7346 * match_failed:
7347 * goto unmatched
7348 */
7349 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7350 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7351 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7352
7353 const int min_argc = pre_args_num + post_args_num;
7354 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7355 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7356
7357 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7358 int i;
7359 match_failed = NEW_LABEL(line);
7360 type_error = NEW_LABEL(line);
7361 deconstruct = NEW_LABEL(line);
7362 deconstructed = NEW_LABEL(line);
7363
7364 if (use_rest_num) {
7365 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7366 ADD_INSN(ret, line_node, swap);
7367 if (base_index) {
7368 base_index++;
7369 }
7370 }
7371
7372 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7373
7374 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7375
7376 ADD_INSN(ret, line_node, dup);
7377 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7378 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7379 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7380 if (in_single_pattern) {
7381 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7382 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7383 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7384 INT2FIX(min_argc), base_index + 1 /* (1) */));
7385 }
7386 ADD_INSNL(ret, line_node, branchunless, match_failed);
7387
7388 for (i = 0; i < pre_args_num; i++) {
7389 ADD_INSN(ret, line_node, dup);
7390 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7391 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7392 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));
7393 args = RNODE_LIST(args)->nd_next;
7394 }
7395
7396 if (RNODE_ARYPTN(node)->rest_arg) {
7397 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7398 ADD_INSN(ret, line_node, dup);
7399 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7400 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7401 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7402 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7403 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7404 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7405 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7406
7407 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));
7408 }
7409 else {
7410 if (post_args_num > 0) {
7411 ADD_INSN(ret, line_node, dup);
7412 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7413 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7414 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7415 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7416 ADD_INSN(ret, line_node, pop);
7417 }
7418 }
7419 }
7420
7421 args = RNODE_ARYPTN(node)->post_args;
7422 for (i = 0; i < post_args_num; i++) {
7423 ADD_INSN(ret, line_node, dup);
7424
7425 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7426 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7427 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7428
7429 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7430 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));
7431 args = RNODE_LIST(args)->nd_next;
7432 }
7433
7434 ADD_INSN(ret, line_node, pop);
7435 if (use_rest_num) {
7436 ADD_INSN(ret, line_node, pop);
7437 }
7438 ADD_INSNL(ret, line_node, jump, matched);
7439 ADD_INSN(ret, line_node, putnil);
7440 if (use_rest_num) {
7441 ADD_INSN(ret, line_node, putnil);
7442 }
7443
7444 ADD_LABEL(ret, type_error);
7445 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7446 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7447 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7448 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7449 ADD_INSN(ret, line_node, pop);
7450
7451 ADD_LABEL(ret, match_failed);
7452 ADD_INSN(ret, line_node, pop);
7453 if (use_rest_num) {
7454 ADD_INSN(ret, line_node, pop);
7455 }
7456 ADD_INSNL(ret, line_node, jump, unmatched);
7457
7458 break;
7459 }
7460 case NODE_FNDPTN: {
7461 /*
7462 * if pattern.has_constant_node?
7463 * unless pattern.constant === obj
7464 * goto match_failed
7465 * end
7466 * end
7467 * unless obj.respond_to?(:deconstruct)
7468 * goto match_failed
7469 * end
7470 * d = obj.deconstruct
7471 * unless Array === d
7472 * goto type_error
7473 * end
7474 * unless d.length >= pattern.args_num
7475 * goto match_failed
7476 * end
7477 *
7478 * begin
7479 * len = d.length
7480 * limit = d.length - pattern.args_num
7481 * i = 0
7482 * while i <= limit
7483 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7484 * if pattern.has_pre_rest_arg_id
7485 * unless pattern.pre_rest_arg.match?(d[0, i])
7486 * goto find_failed
7487 * end
7488 * end
7489 * if pattern.has_post_rest_arg_id
7490 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7491 * goto find_failed
7492 * end
7493 * end
7494 * goto find_succeeded
7495 * end
7496 * i+=1
7497 * end
7498 * find_failed:
7499 * goto match_failed
7500 * find_succeeded:
7501 * end
7502 *
7503 * goto matched
7504 * type_error:
7505 * FrozenCore.raise TypeError
7506 * match_failed:
7507 * goto unmatched
7508 */
7509 const NODE *args = RNODE_FNDPTN(node)->args;
7510 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7511
7512 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7513 match_failed = NEW_LABEL(line);
7514 type_error = NEW_LABEL(line);
7515 deconstruct = NEW_LABEL(line);
7516 deconstructed = NEW_LABEL(line);
7517
7518 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7519
7520 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7521
7522 ADD_INSN(ret, line_node, dup);
7523 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7524 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7525 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7526 if (in_single_pattern) {
7527 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) */));
7528 }
7529 ADD_INSNL(ret, line_node, branchunless, match_failed);
7530
7531 {
7532 LABEL *while_begin = NEW_LABEL(nd_line(node));
7533 LABEL *next_loop = NEW_LABEL(nd_line(node));
7534 LABEL *find_succeeded = NEW_LABEL(line);
7535 LABEL *find_failed = NEW_LABEL(nd_line(node));
7536 int j;
7537
7538 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7539 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7540
7541 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7542 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7543 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7544
7545 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7546
7547 ADD_LABEL(ret, while_begin);
7548
7549 ADD_INSN(ret, line_node, dup);
7550 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7551 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7552 ADD_INSNL(ret, line_node, branchunless, find_failed);
7553
7554 for (j = 0; j < args_num; j++) {
7555 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7556 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7557 if (j != 0) {
7558 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7559 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7560 }
7561 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7562
7563 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));
7564 args = RNODE_LIST(args)->nd_next;
7565 }
7566
7567 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7568 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7569 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7570 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7571 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7572 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));
7573 }
7574 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7575 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7576 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7577 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7578 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7579 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7580 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7581 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));
7582 }
7583 ADD_INSNL(ret, line_node, jump, find_succeeded);
7584
7585 ADD_LABEL(ret, next_loop);
7586 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7587 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7588 ADD_INSNL(ret, line_node, jump, while_begin);
7589
7590 ADD_LABEL(ret, find_failed);
7591 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7592 if (in_single_pattern) {
7593 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7594 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7595 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7596 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7597 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7598
7599 ADD_INSN1(ret, line_node, putobject, Qfalse);
7600 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7601
7602 ADD_INSN(ret, line_node, pop);
7603 ADD_INSN(ret, line_node, pop);
7604 }
7605 ADD_INSNL(ret, line_node, jump, match_failed);
7606 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7607
7608 ADD_LABEL(ret, find_succeeded);
7609 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7610 }
7611
7612 ADD_INSN(ret, line_node, pop);
7613 ADD_INSNL(ret, line_node, jump, matched);
7614 ADD_INSN(ret, line_node, putnil);
7615
7616 ADD_LABEL(ret, type_error);
7617 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7618 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7619 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7620 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7621 ADD_INSN(ret, line_node, pop);
7622
7623 ADD_LABEL(ret, match_failed);
7624 ADD_INSN(ret, line_node, pop);
7625 ADD_INSNL(ret, line_node, jump, unmatched);
7626
7627 break;
7628 }
7629 case NODE_HSHPTN: {
7630 /*
7631 * keys = nil
7632 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7633 * keys = pattern.kw_args_node.keys
7634 * end
7635 * if pattern.has_constant_node?
7636 * unless pattern.constant === obj
7637 * goto match_failed
7638 * end
7639 * end
7640 * unless obj.respond_to?(:deconstruct_keys)
7641 * goto match_failed
7642 * end
7643 * d = obj.deconstruct_keys(keys)
7644 * unless Hash === d
7645 * goto type_error
7646 * end
7647 * if pattern.has_kw_rest_arg_node?
7648 * d = d.dup
7649 * end
7650 * if pattern.has_kw_args_node?
7651 * pattern.kw_args_node.each |k,|
7652 * unless d.key?(k)
7653 * goto match_failed
7654 * end
7655 * end
7656 * pattern.kw_args_node.each |k, pat|
7657 * if pattern.has_kw_rest_arg_node?
7658 * unless pat.match?(d.delete(k))
7659 * goto match_failed
7660 * end
7661 * else
7662 * unless pat.match?(d[k])
7663 * goto match_failed
7664 * end
7665 * end
7666 * end
7667 * else
7668 * unless d.empty?
7669 * goto match_failed
7670 * end
7671 * end
7672 * if pattern.has_kw_rest_arg_node?
7673 * if pattern.no_rest_keyword?
7674 * unless d.empty?
7675 * goto match_failed
7676 * end
7677 * else
7678 * unless pattern.kw_rest_arg_node.match?(d)
7679 * goto match_failed
7680 * end
7681 * end
7682 * end
7683 * goto matched
7684 * type_error:
7685 * FrozenCore.raise TypeError
7686 * match_failed:
7687 * goto unmatched
7688 */
7689 LABEL *match_failed, *type_error;
7690 VALUE keys = Qnil;
7691
7692 match_failed = NEW_LABEL(line);
7693 type_error = NEW_LABEL(line);
7694
7695 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7696 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7697 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7698 while (kw_args) {
7699 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7700 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7701 }
7702 }
7703
7704 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7705
7706 ADD_INSN(ret, line_node, dup);
7707 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7708 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7709 if (in_single_pattern) {
7710 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7711 }
7712 ADD_INSNL(ret, line_node, branchunless, match_failed);
7713
7714 if (NIL_P(keys)) {
7715 ADD_INSN(ret, line_node, putnil);
7716 }
7717 else {
7718 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7719 ADD_INSN1(ret, line_node, duparray, keys);
7720 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7721 }
7722 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7723
7724 ADD_INSN(ret, line_node, dup);
7725 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7726 ADD_INSNL(ret, line_node, branchunless, type_error);
7727
7728 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7729 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7730 }
7731
7732 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7733 int i;
7734 int keys_num;
7735 const NODE *args;
7736 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7737 if (args) {
7738 DECL_ANCHOR(match_values);
7739 INIT_ANCHOR(match_values);
7740 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7741 for (i = 0; i < keys_num; i++) {
7742 NODE *key_node = RNODE_LIST(args)->nd_head;
7743 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7744 VALUE key = get_symbol_value(iseq, key_node);
7745
7746 ADD_INSN(ret, line_node, dup);
7747 ADD_INSN1(ret, line_node, putobject, key);
7748 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7749 if (in_single_pattern) {
7750 LABEL *match_succeeded;
7751 match_succeeded = NEW_LABEL(line);
7752
7753 ADD_INSN(ret, line_node, dup);
7754 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7755
7756 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7757 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7758 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7759 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7760 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7761 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7762 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7763 ADD_INSN1(ret, line_node, putobject, key); // (7)
7764 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7765
7766 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7767
7768 ADD_LABEL(ret, match_succeeded);
7769 }
7770 ADD_INSNL(ret, line_node, branchunless, match_failed);
7771
7772 ADD_INSN(match_values, line_node, dup);
7773 ADD_INSN1(match_values, line_node, putobject, key);
7774 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7775 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7776 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7777 }
7778 ADD_SEQ(ret, match_values);
7779 }
7780 }
7781 else {
7782 ADD_INSN(ret, line_node, dup);
7783 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7784 if (in_single_pattern) {
7785 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7786 }
7787 ADD_INSNL(ret, line_node, branchunless, match_failed);
7788 }
7789
7790 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7791 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7792 ADD_INSN(ret, line_node, dup);
7793 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7794 if (in_single_pattern) {
7795 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7796 }
7797 ADD_INSNL(ret, line_node, branchunless, match_failed);
7798 }
7799 else {
7800 ADD_INSN(ret, line_node, dup); // (11)
7801 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));
7802 }
7803 }
7804
7805 ADD_INSN(ret, line_node, pop);
7806 ADD_INSNL(ret, line_node, jump, matched);
7807 ADD_INSN(ret, line_node, putnil);
7808
7809 ADD_LABEL(ret, type_error);
7810 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7811 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7812 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7813 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7814 ADD_INSN(ret, line_node, pop);
7815
7816 ADD_LABEL(ret, match_failed);
7817 ADD_INSN(ret, line_node, pop);
7818 ADD_INSNL(ret, line_node, jump, unmatched);
7819 break;
7820 }
7821 case NODE_SYM:
7822 case NODE_REGX:
7823 case NODE_LINE:
7824 case NODE_INTEGER:
7825 case NODE_FLOAT:
7826 case NODE_RATIONAL:
7827 case NODE_IMAGINARY:
7828 case NODE_FILE:
7829 case NODE_ENCODING:
7830 case NODE_STR:
7831 case NODE_XSTR:
7832 case NODE_DSTR:
7833 case NODE_DSYM:
7834 case NODE_DREGX:
7835 case NODE_LIST:
7836 case NODE_ZLIST:
7837 case NODE_LAMBDA:
7838 case NODE_DOT2:
7839 case NODE_DOT3:
7840 case NODE_CONST:
7841 case NODE_LVAR:
7842 case NODE_DVAR:
7843 case NODE_IVAR:
7844 case NODE_CVAR:
7845 case NODE_GVAR:
7846 case NODE_TRUE:
7847 case NODE_FALSE:
7848 case NODE_SELF:
7849 case NODE_NIL:
7850 case NODE_COLON2:
7851 case NODE_COLON3:
7852 case NODE_BEGIN:
7853 case NODE_BLOCK:
7854 case NODE_ONCE:
7855 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7856 if (in_single_pattern) {
7857 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7858 }
7859 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7860 if (in_single_pattern) {
7861 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7862 }
7863 ADD_INSNL(ret, line_node, branchif, matched);
7864 ADD_INSNL(ret, line_node, jump, unmatched);
7865 break;
7866 case NODE_LASGN: {
7867 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7868 ID id = RNODE_LASGN(node)->nd_vid;
7869 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7870
7871 if (in_alt_pattern) {
7872 const char *name = rb_id2name(id);
7873 if (name && strlen(name) > 0 && name[0] != '_') {
7874 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7875 rb_id2str(id));
7876 return COMPILE_NG;
7877 }
7878 }
7879
7880 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7881 ADD_INSNL(ret, line_node, jump, matched);
7882 break;
7883 }
7884 case NODE_DASGN: {
7885 int idx, lv, ls;
7886 ID id = RNODE_DASGN(node)->nd_vid;
7887
7888 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7889
7890 if (in_alt_pattern) {
7891 const char *name = rb_id2name(id);
7892 if (name && strlen(name) > 0 && name[0] != '_') {
7893 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7894 rb_id2str(id));
7895 return COMPILE_NG;
7896 }
7897 }
7898
7899 if (idx < 0) {
7900 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7901 rb_id2str(id));
7902 return COMPILE_NG;
7903 }
7904 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7905 ADD_INSNL(ret, line_node, jump, matched);
7906 break;
7907 }
7908 case NODE_IF:
7909 case NODE_UNLESS: {
7910 LABEL *match_failed;
7911 match_failed = unmatched;
7912 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7913 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7914 if (in_single_pattern) {
7915 LABEL *match_succeeded;
7916 match_succeeded = NEW_LABEL(line);
7917
7918 ADD_INSN(ret, line_node, dup);
7919 if (nd_type_p(node, NODE_IF)) {
7920 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7921 }
7922 else {
7923 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7924 }
7925
7926 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7927 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7928 ADD_INSN1(ret, line_node, putobject, Qfalse);
7929 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7930
7931 ADD_INSN(ret, line_node, pop);
7932 ADD_INSN(ret, line_node, pop);
7933
7934 ADD_LABEL(ret, match_succeeded);
7935 }
7936 if (nd_type_p(node, NODE_IF)) {
7937 ADD_INSNL(ret, line_node, branchunless, match_failed);
7938 }
7939 else {
7940 ADD_INSNL(ret, line_node, branchif, match_failed);
7941 }
7942 ADD_INSNL(ret, line_node, jump, matched);
7943 break;
7944 }
7945 case NODE_HASH: {
7946 NODE *n;
7947 LABEL *match_failed;
7948 match_failed = NEW_LABEL(line);
7949
7950 n = RNODE_HASH(node)->nd_head;
7951 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7952 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7953 return COMPILE_NG;
7954 }
7955
7956 ADD_INSN(ret, line_node, dup); // (1)
7957 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));
7958 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));
7959 ADD_INSN(ret, line_node, putnil);
7960
7961 ADD_LABEL(ret, match_failed);
7962 ADD_INSN(ret, line_node, pop);
7963 ADD_INSNL(ret, line_node, jump, unmatched);
7964 break;
7965 }
7966 case NODE_OR: {
7967 LABEL *match_succeeded, *fin;
7968 match_succeeded = NEW_LABEL(line);
7969 fin = NEW_LABEL(line);
7970
7971 ADD_INSN(ret, line_node, dup); // (1)
7972 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));
7973 ADD_LABEL(ret, match_succeeded);
7974 ADD_INSN(ret, line_node, pop);
7975 ADD_INSNL(ret, line_node, jump, matched);
7976 ADD_INSN(ret, line_node, putnil);
7977 ADD_LABEL(ret, fin);
7978 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7979 break;
7980 }
7981 default:
7982 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7983 }
7984 return COMPILE_OK;
7985}
7986
7987static int
7988iseq_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)
7989{
7990 LABEL *fin = NEW_LABEL(nd_line(node));
7991 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7992 ADD_LABEL(ret, fin);
7993 return COMPILE_OK;
7994}
7995
7996static int
7997iseq_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)
7998{
7999 const NODE *line_node = node;
8000
8001 if (RNODE_ARYPTN(node)->nd_pconst) {
8002 ADD_INSN(ret, line_node, dup); // (1)
8003 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8004 if (in_single_pattern) {
8005 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8006 }
8007 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8008 if (in_single_pattern) {
8009 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8010 }
8011 ADD_INSNL(ret, line_node, branchunless, match_failed);
8012 }
8013 return COMPILE_OK;
8014}
8015
8016
8017static int
8018iseq_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)
8019{
8020 const NODE *line_node = node;
8021
8022 // NOTE: this optimization allows us to re-use the #deconstruct value
8023 // (or its absence).
8024 if (use_deconstructed_cache) {
8025 // If value is nil then we haven't tried to deconstruct
8026 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8027 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8028
8029 // If false then the value is not deconstructable
8030 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8031 ADD_INSNL(ret, line_node, branchunless, match_failed);
8032
8033 // Drop value, add deconstructed to the stack and jump
8034 ADD_INSN(ret, line_node, pop); // (1)
8035 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8036 ADD_INSNL(ret, line_node, jump, deconstructed);
8037 }
8038 else {
8039 ADD_INSNL(ret, line_node, jump, deconstruct);
8040 }
8041
8042 ADD_LABEL(ret, deconstruct);
8043 ADD_INSN(ret, line_node, dup);
8044 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8045 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8046
8047 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8048 if (use_deconstructed_cache) {
8049 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8050 }
8051
8052 if (in_single_pattern) {
8053 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8054 }
8055
8056 ADD_INSNL(ret, line_node, branchunless, match_failed);
8057
8058 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8059
8060 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8061 if (use_deconstructed_cache) {
8062 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8063 }
8064
8065 ADD_INSN(ret, line_node, dup);
8066 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8067 ADD_INSNL(ret, line_node, branchunless, type_error);
8068
8069 ADD_LABEL(ret, deconstructed);
8070
8071 return COMPILE_OK;
8072}
8073
8074static int
8075iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8076{
8077 /*
8078 * if match_succeeded?
8079 * goto match_succeeded
8080 * end
8081 * error_string = FrozenCore.sprintf(errmsg, matchee)
8082 * key_error_p = false
8083 * match_succeeded:
8084 */
8085 const int line = nd_line(node);
8086 const NODE *line_node = node;
8087 LABEL *match_succeeded = NEW_LABEL(line);
8088
8089 ADD_INSN(ret, line_node, dup);
8090 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8091
8092 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8093 ADD_INSN1(ret, line_node, putobject, errmsg);
8094 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8095 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8096 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8097
8098 ADD_INSN1(ret, line_node, putobject, Qfalse);
8099 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8100
8101 ADD_INSN(ret, line_node, pop);
8102 ADD_INSN(ret, line_node, pop);
8103 ADD_LABEL(ret, match_succeeded);
8104
8105 return COMPILE_OK;
8106}
8107
8108static int
8109iseq_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)
8110{
8111 /*
8112 * if match_succeeded?
8113 * goto match_succeeded
8114 * end
8115 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8116 * key_error_p = false
8117 * match_succeeded:
8118 */
8119 const int line = nd_line(node);
8120 const NODE *line_node = node;
8121 LABEL *match_succeeded = NEW_LABEL(line);
8122
8123 ADD_INSN(ret, line_node, dup);
8124 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8125
8126 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8127 ADD_INSN1(ret, line_node, putobject, errmsg);
8128 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8129 ADD_INSN(ret, line_node, dup);
8130 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8131 ADD_INSN1(ret, line_node, putobject, pattern_length);
8132 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8133 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8134
8135 ADD_INSN1(ret, line_node, putobject, Qfalse);
8136 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8137
8138 ADD_INSN(ret, line_node, pop);
8139 ADD_INSN(ret, line_node, pop);
8140 ADD_LABEL(ret, match_succeeded);
8141
8142 return COMPILE_OK;
8143}
8144
8145static int
8146iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8147{
8148 /*
8149 * if match_succeeded?
8150 * goto match_succeeded
8151 * end
8152 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8153 * key_error_p = false
8154 * match_succeeded:
8155 */
8156 const int line = nd_line(node);
8157 const NODE *line_node = node;
8158 LABEL *match_succeeded = NEW_LABEL(line);
8159
8160 ADD_INSN(ret, line_node, dup);
8161 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8162
8163 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8164 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8165 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8166 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8167 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8168 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8169
8170 ADD_INSN1(ret, line_node, putobject, Qfalse);
8171 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8172
8173 ADD_INSN(ret, line_node, pop);
8174 ADD_INSN(ret, line_node, pop);
8175
8176 ADD_LABEL(ret, match_succeeded);
8177 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8178 ADD_INSN(ret, line_node, pop);
8179 ADD_INSN(ret, line_node, pop);
8180
8181 return COMPILE_OK;
8182}
8183
8184static int
8185compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8186{
8187 const NODE *pattern;
8188 const NODE *node = orig_node;
8189 LABEL *endlabel, *elselabel;
8190 DECL_ANCHOR(head);
8191 DECL_ANCHOR(body_seq);
8192 DECL_ANCHOR(cond_seq);
8193 int line;
8194 enum node_type type;
8195 const NODE *line_node;
8196 VALUE branches = 0;
8197 int branch_id = 0;
8198 bool single_pattern;
8199
8200 INIT_ANCHOR(head);
8201 INIT_ANCHOR(body_seq);
8202 INIT_ANCHOR(cond_seq);
8203
8204 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8205
8206 node = RNODE_CASE3(node)->nd_body;
8207 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8208 type = nd_type(node);
8209 line = nd_line(node);
8210 line_node = node;
8211 single_pattern = !RNODE_IN(node)->nd_next;
8212
8213 endlabel = NEW_LABEL(line);
8214 elselabel = NEW_LABEL(line);
8215
8216 if (single_pattern) {
8217 /* allocate stack for ... */
8218 ADD_INSN(head, line_node, putnil); /* key_error_key */
8219 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8220 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8221 ADD_INSN(head, line_node, putnil); /* error_string */
8222 }
8223 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8224
8225 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8226
8227 ADD_SEQ(ret, head); /* case VAL */
8228
8229 while (type == NODE_IN) {
8230 LABEL *l1;
8231
8232 if (branch_id) {
8233 ADD_INSN(body_seq, line_node, putnil);
8234 }
8235 l1 = NEW_LABEL(line);
8236 ADD_LABEL(body_seq, l1);
8237 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8238
8239 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8240 add_trace_branch_coverage(
8241 iseq,
8242 body_seq,
8243 nd_code_loc(coverage_node),
8244 nd_node_id(coverage_node),
8245 branch_id++,
8246 "in",
8247 branches);
8248
8249 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8250 ADD_INSNL(body_seq, line_node, jump, endlabel);
8251
8252 pattern = RNODE_IN(node)->nd_head;
8253 if (pattern) {
8254 int pat_line = nd_line(pattern);
8255 LABEL *next_pat = NEW_LABEL(pat_line);
8256 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8257 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8258 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8259 ADD_LABEL(cond_seq, next_pat);
8260 LABEL_UNREMOVABLE(next_pat);
8261 }
8262 else {
8263 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8264 return COMPILE_NG;
8265 }
8266
8267 node = RNODE_IN(node)->nd_next;
8268 if (!node) {
8269 break;
8270 }
8271 type = nd_type(node);
8272 line = nd_line(node);
8273 line_node = node;
8274 }
8275 /* else */
8276 if (node) {
8277 ADD_LABEL(cond_seq, elselabel);
8278 ADD_INSN(cond_seq, line_node, pop);
8279 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8280 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8281 CHECK(COMPILE_(cond_seq, "else", node, popped));
8282 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8283 ADD_INSN(cond_seq, line_node, putnil);
8284 if (popped) {
8285 ADD_INSN(cond_seq, line_node, putnil);
8286 }
8287 }
8288 else {
8289 debugs("== else (implicit)\n");
8290 ADD_LABEL(cond_seq, elselabel);
8291 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8292 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8293
8294 if (single_pattern) {
8295 /*
8296 * if key_error_p
8297 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8298 * else
8299 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8300 * end
8301 */
8302 LABEL *key_error, *fin;
8303 struct rb_callinfo_kwarg *kw_arg;
8304
8305 key_error = NEW_LABEL(line);
8306 fin = NEW_LABEL(line);
8307
8308 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8309 kw_arg->references = 0;
8310 kw_arg->keyword_len = 2;
8311 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8312 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8313
8314 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8315 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8316 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8317 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8318 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8319 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8320 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8321 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8322 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8323 ADD_INSNL(cond_seq, orig_node, jump, fin);
8324
8325 ADD_LABEL(cond_seq, key_error);
8326 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8327 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8328 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8329 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8330 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8331 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8332 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8333 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8334 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8335 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8336
8337 ADD_LABEL(cond_seq, fin);
8338 }
8339 else {
8340 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8341 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8342 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8343 }
8344 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8345 if (!popped) {
8346 ADD_INSN(cond_seq, orig_node, putnil);
8347 }
8348 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8349 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8350 if (popped) {
8351 ADD_INSN(cond_seq, line_node, putnil);
8352 }
8353 }
8354
8355 ADD_SEQ(ret, cond_seq);
8356 ADD_SEQ(ret, body_seq);
8357 ADD_LABEL(ret, endlabel);
8358 return COMPILE_OK;
8359}
8360
8361#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8362#undef CASE3_BI_OFFSET_ERROR_STRING
8363#undef CASE3_BI_OFFSET_KEY_ERROR_P
8364#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8365#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8366
8367static int
8368compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8369{
8370 const int line = (int)nd_line(node);
8371 const NODE *line_node = node;
8372
8373 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8374 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8375 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8376 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8377 VALUE branches = Qfalse;
8378
8380
8381 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8382 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8383 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8384 LABEL *end_label = NEW_LABEL(line);
8385 LABEL *adjust_label = NEW_LABEL(line);
8386
8387 LABEL *next_catch_label = NEW_LABEL(line);
8388 LABEL *tmp_label = NULL;
8389
8390 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8391 push_ensure_entry(iseq, &enl, NULL, NULL);
8392
8393 if (RNODE_WHILE(node)->nd_state == 1) {
8394 ADD_INSNL(ret, line_node, jump, next_label);
8395 }
8396 else {
8397 tmp_label = NEW_LABEL(line);
8398 ADD_INSNL(ret, line_node, jump, tmp_label);
8399 }
8400 ADD_LABEL(ret, adjust_label);
8401 ADD_INSN(ret, line_node, putnil);
8402 ADD_LABEL(ret, next_catch_label);
8403 ADD_INSN(ret, line_node, pop);
8404 ADD_INSNL(ret, line_node, jump, next_label);
8405 if (tmp_label) ADD_LABEL(ret, tmp_label);
8406
8407 ADD_LABEL(ret, redo_label);
8408 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8409
8410 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8411 add_trace_branch_coverage(
8412 iseq,
8413 ret,
8414 nd_code_loc(coverage_node),
8415 nd_node_id(coverage_node),
8416 0,
8417 "body",
8418 branches);
8419
8420 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8421 ADD_LABEL(ret, next_label); /* next */
8422
8423 if (type == NODE_WHILE) {
8424 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8425 redo_label, end_label));
8426 }
8427 else {
8428 /* until */
8429 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8430 end_label, redo_label));
8431 }
8432
8433 ADD_LABEL(ret, end_label);
8434 ADD_ADJUST_RESTORE(ret, adjust_label);
8435
8436 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8437 /* ADD_INSN(ret, line_node, putundef); */
8438 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8439 return COMPILE_NG;
8440 }
8441 else {
8442 ADD_INSN(ret, line_node, putnil);
8443 }
8444
8445 ADD_LABEL(ret, break_label); /* break */
8446
8447 if (popped) {
8448 ADD_INSN(ret, line_node, pop);
8449 }
8450
8451 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8452 break_label);
8453 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8454 next_catch_label);
8455 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8456 ISEQ_COMPILE_DATA(iseq)->redo_label);
8457
8458 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8459 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8460 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8461 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8462 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8463 return COMPILE_OK;
8464}
8465
8466static int
8467compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8468{
8469 const int line = nd_line(node);
8470 const NODE *line_node = node;
8471 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8472 LABEL *retry_label = NEW_LABEL(line);
8473 LABEL *retry_end_l = NEW_LABEL(line);
8474 const rb_iseq_t *child_iseq;
8475
8476 ADD_LABEL(ret, retry_label);
8477 if (nd_type_p(node, NODE_FOR)) {
8478 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8479
8480 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8481 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8482 ISEQ_TYPE_BLOCK, line);
8483 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8484 }
8485 else {
8486 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8487 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8488 ISEQ_TYPE_BLOCK, line);
8489 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8490 }
8491
8492 {
8493 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8494 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8495 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8496 //
8497 // Normally, "send" instruction is at the last.
8498 // However, qcall under branch coverage measurement adds some instructions after the "send".
8499 //
8500 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8501 INSN *iobj;
8502 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8503 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8504 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8505 iobj = (INSN*) get_prev_insn(iobj);
8506 }
8507 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8508
8509 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8510 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8511 if (&iobj->link == LAST_ELEMENT(ret)) {
8512 ret->last = (LINK_ELEMENT*) retry_end_l;
8513 }
8514 }
8515
8516 if (popped) {
8517 ADD_INSN(ret, line_node, pop);
8518 }
8519
8520 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8521
8522 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8523 return COMPILE_OK;
8524}
8525
8526static int
8527compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8528{
8529 /* massign to var in "for"
8530 * (args.length == 1 && Array.try_convert(args[0])) || args
8531 */
8532 const NODE *line_node = node;
8533 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8534 LABEL *not_single = NEW_LABEL(nd_line(var));
8535 LABEL *not_ary = NEW_LABEL(nd_line(var));
8536 CHECK(COMPILE(ret, "for var", var));
8537 ADD_INSN(ret, line_node, dup);
8538 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8539 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8540 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8541 ADD_INSNL(ret, line_node, branchunless, not_single);
8542 ADD_INSN(ret, line_node, dup);
8543 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8544 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8545 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8546 ADD_INSN(ret, line_node, swap);
8547 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8548 ADD_INSN(ret, line_node, dup);
8549 ADD_INSNL(ret, line_node, branchunless, not_ary);
8550 ADD_INSN(ret, line_node, swap);
8551 ADD_LABEL(ret, not_ary);
8552 ADD_INSN(ret, line_node, pop);
8553 ADD_LABEL(ret, not_single);
8554 return COMPILE_OK;
8555}
8556
8557static int
8558compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8559{
8560 const NODE *line_node = node;
8561 unsigned long throw_flag = 0;
8562
8563 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8564 /* while/until */
8565 LABEL *splabel = NEW_LABEL(0);
8566 ADD_LABEL(ret, splabel);
8567 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8568 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8569 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8570 add_ensure_iseq(ret, iseq, 0);
8571 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8572 ADD_ADJUST_RESTORE(ret, splabel);
8573
8574 if (!popped) {
8575 ADD_INSN(ret, line_node, putnil);
8576 }
8577 }
8578 else {
8579 const rb_iseq_t *ip = iseq;
8580
8581 while (ip) {
8582 if (!ISEQ_COMPILE_DATA(ip)) {
8583 ip = 0;
8584 break;
8585 }
8586
8587 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8588 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8589 }
8590 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8591 throw_flag = 0;
8592 }
8593 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8594 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8595 return COMPILE_NG;
8596 }
8597 else {
8598 ip = ISEQ_BODY(ip)->parent_iseq;
8599 continue;
8600 }
8601
8602 /* escape from block */
8603 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8604 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8605 if (popped) {
8606 ADD_INSN(ret, line_node, pop);
8607 }
8608 return COMPILE_OK;
8609 }
8610 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8611 return COMPILE_NG;
8612 }
8613 return COMPILE_OK;
8614}
8615
8616static int
8617compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8618{
8619 const NODE *line_node = node;
8620 unsigned long throw_flag = 0;
8621
8622 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8623 LABEL *splabel = NEW_LABEL(0);
8624 debugs("next in while loop\n");
8625 ADD_LABEL(ret, splabel);
8626 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8627 add_ensure_iseq(ret, iseq, 0);
8628 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8629 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8630 ADD_ADJUST_RESTORE(ret, splabel);
8631 if (!popped) {
8632 ADD_INSN(ret, line_node, putnil);
8633 }
8634 }
8635 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8636 LABEL *splabel = NEW_LABEL(0);
8637 debugs("next in block\n");
8638 ADD_LABEL(ret, splabel);
8639 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8640 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8641 add_ensure_iseq(ret, iseq, 0);
8642 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8643 ADD_ADJUST_RESTORE(ret, splabel);
8644
8645 if (!popped) {
8646 ADD_INSN(ret, line_node, putnil);
8647 }
8648 }
8649 else {
8650 const rb_iseq_t *ip = iseq;
8651
8652 while (ip) {
8653 if (!ISEQ_COMPILE_DATA(ip)) {
8654 ip = 0;
8655 break;
8656 }
8657
8658 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8659 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8660 /* while loop */
8661 break;
8662 }
8663 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8664 break;
8665 }
8666 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8667 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8668 return COMPILE_NG;
8669 }
8670
8671 ip = ISEQ_BODY(ip)->parent_iseq;
8672 }
8673 if (ip != 0) {
8674 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8675 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8676
8677 if (popped) {
8678 ADD_INSN(ret, line_node, pop);
8679 }
8680 }
8681 else {
8682 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8683 return COMPILE_NG;
8684 }
8685 }
8686 return COMPILE_OK;
8687}
8688
8689static int
8690compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8691{
8692 const NODE *line_node = node;
8693
8694 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8695 LABEL *splabel = NEW_LABEL(0);
8696 debugs("redo in while");
8697 ADD_LABEL(ret, splabel);
8698 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8699 add_ensure_iseq(ret, iseq, 0);
8700 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8701 ADD_ADJUST_RESTORE(ret, splabel);
8702 if (!popped) {
8703 ADD_INSN(ret, line_node, putnil);
8704 }
8705 }
8706 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8707 LABEL *splabel = NEW_LABEL(0);
8708
8709 debugs("redo in block");
8710 ADD_LABEL(ret, splabel);
8711 add_ensure_iseq(ret, iseq, 0);
8712 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8713 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8714 ADD_ADJUST_RESTORE(ret, splabel);
8715
8716 if (!popped) {
8717 ADD_INSN(ret, line_node, putnil);
8718 }
8719 }
8720 else {
8721 const rb_iseq_t *ip = iseq;
8722
8723 while (ip) {
8724 if (!ISEQ_COMPILE_DATA(ip)) {
8725 ip = 0;
8726 break;
8727 }
8728
8729 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8730 break;
8731 }
8732 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8733 break;
8734 }
8735 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8736 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8737 return COMPILE_NG;
8738 }
8739
8740 ip = ISEQ_BODY(ip)->parent_iseq;
8741 }
8742 if (ip != 0) {
8743 ADD_INSN(ret, line_node, putnil);
8744 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8745
8746 if (popped) {
8747 ADD_INSN(ret, line_node, pop);
8748 }
8749 }
8750 else {
8751 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8752 return COMPILE_NG;
8753 }
8754 }
8755 return COMPILE_OK;
8756}
8757
8758static int
8759compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8760{
8761 const NODE *line_node = node;
8762
8763 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8764 ADD_INSN(ret, line_node, putnil);
8765 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8766
8767 if (popped) {
8768 ADD_INSN(ret, line_node, pop);
8769 }
8770 }
8771 else {
8772 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8773 return COMPILE_NG;
8774 }
8775 return COMPILE_OK;
8776}
8777
8778static int
8779compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8780{
8781 const int line = nd_line(node);
8782 const NODE *line_node = node;
8783 LABEL *lstart = NEW_LABEL(line);
8784 LABEL *lend = NEW_LABEL(line);
8785 LABEL *lcont = NEW_LABEL(line);
8786 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8787 rb_str_concat(rb_str_new2("rescue in "),
8788 ISEQ_BODY(iseq)->location.label),
8789 ISEQ_TYPE_RESCUE, line);
8790
8791 lstart->rescued = LABEL_RESCUE_BEG;
8792 lend->rescued = LABEL_RESCUE_END;
8793 ADD_LABEL(ret, lstart);
8794
8795 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8796 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8797 {
8798 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8799 }
8800 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8801
8802 ADD_LABEL(ret, lend);
8803 if (RNODE_RESCUE(node)->nd_else) {
8804 ADD_INSN(ret, line_node, pop);
8805 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8806 }
8807 ADD_INSN(ret, line_node, nop);
8808 ADD_LABEL(ret, lcont);
8809
8810 if (popped) {
8811 ADD_INSN(ret, line_node, pop);
8812 }
8813
8814 /* register catch entry */
8815 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8816 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8817 return COMPILE_OK;
8818}
8819
8820static int
8821compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8822{
8823 const int line = nd_line(node);
8824 const NODE *line_node = node;
8825 const NODE *resq = node;
8826 const NODE *narg;
8827 LABEL *label_miss, *label_hit;
8828
8829 while (resq) {
8830 label_miss = NEW_LABEL(line);
8831 label_hit = NEW_LABEL(line);
8832
8833 narg = RNODE_RESBODY(resq)->nd_args;
8834 if (narg) {
8835 switch (nd_type(narg)) {
8836 case NODE_LIST:
8837 while (narg) {
8838 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8839 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8840 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8841 ADD_INSNL(ret, line_node, branchif, label_hit);
8842 narg = RNODE_LIST(narg)->nd_next;
8843 }
8844 break;
8845 case NODE_SPLAT:
8846 case NODE_ARGSCAT:
8847 case NODE_ARGSPUSH:
8848 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8849 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8850 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8851 ADD_INSNL(ret, line_node, branchif, label_hit);
8852 break;
8853 default:
8854 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8855 }
8856 }
8857 else {
8858 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8859 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8860 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8861 ADD_INSNL(ret, line_node, branchif, label_hit);
8862 }
8863 ADD_INSNL(ret, line_node, jump, label_miss);
8864 ADD_LABEL(ret, label_hit);
8865 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8866
8867 if (RNODE_RESBODY(resq)->nd_exc_var) {
8868 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8869 }
8870
8871 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) {
8872 // empty body
8873 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8874 }
8875 else {
8876 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8877 }
8878
8879 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8880 ADD_INSN(ret, line_node, nop);
8881 }
8882 ADD_INSN(ret, line_node, leave);
8883 ADD_LABEL(ret, label_miss);
8884 resq = RNODE_RESBODY(resq)->nd_next;
8885 }
8886 return COMPILE_OK;
8887}
8888
8889static int
8890compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8891{
8892 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8893 const NODE *line_node = node;
8894 DECL_ANCHOR(ensr);
8895 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8896 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8897 ISEQ_TYPE_ENSURE, line);
8898 LABEL *lstart = NEW_LABEL(line);
8899 LABEL *lend = NEW_LABEL(line);
8900 LABEL *lcont = NEW_LABEL(line);
8901 LINK_ELEMENT *last;
8902 int last_leave = 0;
8903 struct ensure_range er;
8905 struct ensure_range *erange;
8906
8907 INIT_ANCHOR(ensr);
8908 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8909 last = ensr->last;
8910 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8911
8912 er.begin = lstart;
8913 er.end = lend;
8914 er.next = 0;
8915 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8916
8917 ADD_LABEL(ret, lstart);
8918 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8919 ADD_LABEL(ret, lend);
8920 ADD_SEQ(ret, ensr);
8921 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8922 ADD_LABEL(ret, lcont);
8923 if (last_leave) ADD_INSN(ret, line_node, pop);
8924
8925 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8926 if (lstart->link.next != &lend->link) {
8927 while (erange) {
8928 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8929 ensure, lcont);
8930 erange = erange->next;
8931 }
8932 }
8933
8934 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8935 return COMPILE_OK;
8936}
8937
8938static int
8939compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8940{
8941 const NODE *line_node = node;
8942
8943 if (iseq) {
8944 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8945 const rb_iseq_t *is = iseq;
8946 enum rb_iseq_type t = type;
8947 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8948 LABEL *splabel = 0;
8949
8950 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8951 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8952 t = ISEQ_BODY(is)->type;
8953 }
8954 switch (t) {
8955 case ISEQ_TYPE_TOP:
8956 case ISEQ_TYPE_MAIN:
8957 if (retval) {
8958 rb_warn("argument of top-level return is ignored");
8959 }
8960 if (is == iseq) {
8961 /* plain top-level, leave directly */
8962 type = ISEQ_TYPE_METHOD;
8963 }
8964 break;
8965 default:
8966 break;
8967 }
8968
8969 if (type == ISEQ_TYPE_METHOD) {
8970 splabel = NEW_LABEL(0);
8971 ADD_LABEL(ret, splabel);
8972 ADD_ADJUST(ret, line_node, 0);
8973 }
8974
8975 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8976
8977 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8978 add_ensure_iseq(ret, iseq, 1);
8979 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8980 ADD_INSN(ret, line_node, leave);
8981 ADD_ADJUST_RESTORE(ret, splabel);
8982
8983 if (!popped) {
8984 ADD_INSN(ret, line_node, putnil);
8985 }
8986 }
8987 else {
8988 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8989 if (popped) {
8990 ADD_INSN(ret, line_node, pop);
8991 }
8992 }
8993 }
8994 return COMPILE_OK;
8995}
8996
8997static bool
8998drop_unreachable_return(LINK_ANCHOR *ret)
8999{
9000 LINK_ELEMENT *i = ret->last, *last;
9001 if (!i) return false;
9002 if (IS_TRACE(i)) i = i->prev;
9003 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9004 last = i = i->prev;
9005 if (IS_ADJUST(i)) i = i->prev;
9006 if (!IS_INSN(i)) return false;
9007 switch (INSN_OF(i)) {
9008 case BIN(leave):
9009 case BIN(jump):
9010 break;
9011 default:
9012 return false;
9013 }
9014 (ret->last = last->prev)->next = NULL;
9015 return true;
9016}
9017
9018static int
9019compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9020{
9021 CHECK(COMPILE_(ret, "nd_body", node, popped));
9022
9023 if (!popped && !all_string_result_p(node)) {
9024 const NODE *line_node = node;
9025 const unsigned int flag = VM_CALL_FCALL;
9026
9027 // Note, this dup could be removed if we are willing to change anytostring. It pops
9028 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9029 ADD_INSN(ret, line_node, dup);
9030 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9031 ADD_INSN(ret, line_node, anytostring);
9032 }
9033 return COMPILE_OK;
9034}
9035
9036static void
9037compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9038{
9039 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9040
9041 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9042 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9043}
9044
9045static LABEL *
9046qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9047{
9048 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9049 VALUE br = 0;
9050
9051 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
9052 *branches = br;
9053 ADD_INSN(recv, line_node, dup);
9054 ADD_INSNL(recv, line_node, branchnil, else_label);
9055 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9056 return else_label;
9057}
9058
9059static void
9060qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9061{
9062 LABEL *end_label;
9063 if (!else_label) return;
9064 end_label = NEW_LABEL(nd_line(line_node));
9065 ADD_INSNL(ret, line_node, jump, end_label);
9066 ADD_LABEL(ret, else_label);
9067 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9068 ADD_LABEL(ret, end_label);
9069}
9070
9071static int
9072compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9073{
9074 /* optimization shortcut
9075 * "literal".freeze -> opt_str_freeze("literal")
9076 */
9077 if (get_nd_recv(node) &&
9078 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9079 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9080 get_nd_args(node) == NULL &&
9081 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9082 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9083 VALUE str = get_string_value(get_nd_recv(node));
9084 if (get_node_call_nd_mid(node) == idUMinus) {
9085 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9086 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9087 }
9088 else {
9089 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9090 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9091 }
9092 RB_OBJ_WRITTEN(iseq, Qundef, str);
9093 if (popped) {
9094 ADD_INSN(ret, line_node, pop);
9095 }
9096 return TRUE;
9097 }
9098 return FALSE;
9099}
9100
9101static int
9102iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9103{
9104 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9105}
9106
9107static const struct rb_builtin_function *
9108iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9109{
9110 int i;
9111 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9112 for (i=0; table[i].index != -1; i++) {
9113 if (strcmp(table[i].name, name) == 0) {
9114 return &table[i];
9115 }
9116 }
9117 return NULL;
9118}
9119
9120static const char *
9121iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9122{
9123 const char *name = rb_id2name(mid);
9124 static const char prefix[] = "__builtin_";
9125 const size_t prefix_len = sizeof(prefix) - 1;
9126
9127 switch (type) {
9128 case NODE_CALL:
9129 if (recv) {
9130 switch (nd_type(recv)) {
9131 case NODE_VCALL:
9132 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9133 return name;
9134 }
9135 break;
9136 case NODE_CONST:
9137 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9138 return name;
9139 }
9140 break;
9141 default: break;
9142 }
9143 }
9144 break;
9145 case NODE_VCALL:
9146 case NODE_FCALL:
9147 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9148 return &name[prefix_len];
9149 }
9150 break;
9151 default: break;
9152 }
9153 return NULL;
9154}
9155
9156static int
9157delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9158{
9159
9160 if (argc == 0) {
9161 *pstart_index = 0;
9162 return TRUE;
9163 }
9164 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9165 unsigned int start=0;
9166
9167 // local_table: [p1, p2, p3, l1, l2, l3]
9168 // arguments: [p3, l1, l2] -> 2
9169 for (start = 0;
9170 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9171 start++) {
9172 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9173
9174 for (unsigned int i=start; i-start<argc; i++) {
9175 if (IS_INSN(elem) &&
9176 INSN_OF(elem) == BIN(getlocal)) {
9177 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9178 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9179
9180 if (local_level == 0) {
9181 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9182 if (0) { // for debug
9183 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9184 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9185 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9186 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9187 }
9188 if (i == index) {
9189 elem = elem->next;
9190 continue; /* for */
9191 }
9192 else {
9193 goto next;
9194 }
9195 }
9196 else {
9197 goto fail; // level != 0 is unsupported
9198 }
9199 }
9200 else {
9201 goto fail; // insn is not a getlocal
9202 }
9203 }
9204 goto success;
9205 next:;
9206 }
9207 fail:
9208 return FALSE;
9209 success:
9210 *pstart_index = start;
9211 return TRUE;
9212 }
9213 else {
9214 return FALSE;
9215 }
9216}
9217
9218// Compile Primitive.attr! :leaf, ...
9219static int
9220compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9221{
9222 VALUE symbol;
9223 VALUE string;
9224 if (!node) goto no_arg;
9225 while (node) {
9226 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9227 const NODE *next = RNODE_LIST(node)->nd_next;
9228
9229 node = RNODE_LIST(node)->nd_head;
9230 if (!node) goto no_arg;
9231 switch (nd_type(node)) {
9232 case NODE_SYM:
9233 symbol = rb_node_sym_string_val(node);
9234 break;
9235 default:
9236 goto bad_arg;
9237 }
9238
9239 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9240
9241 string = rb_sym2str(symbol);
9242 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9243 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9244 }
9245 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9246 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9247 }
9248 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9249 iseq_set_use_block(iseq);
9250 }
9251 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9252 // Let the iseq act like a C method in backtraces
9253 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9254 }
9255 else {
9256 goto unknown_arg;
9257 }
9258 node = next;
9259 }
9260 return COMPILE_OK;
9261 no_arg:
9262 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9263 return COMPILE_NG;
9264 non_symbol_arg:
9265 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9266 return COMPILE_NG;
9267 unknown_arg:
9268 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9269 return COMPILE_NG;
9270 bad_arg:
9271 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9272}
9273
9274static int
9275compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9276{
9277 VALUE name;
9278
9279 if (!node) goto no_arg;
9280 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9281 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9282 node = RNODE_LIST(node)->nd_head;
9283 if (!node) goto no_arg;
9284 switch (nd_type(node)) {
9285 case NODE_SYM:
9286 name = rb_node_sym_string_val(node);
9287 break;
9288 default:
9289 goto bad_arg;
9290 }
9291 if (!SYMBOL_P(name)) goto non_symbol_arg;
9292 if (!popped) {
9293 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9294 }
9295 return COMPILE_OK;
9296 no_arg:
9297 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9298 return COMPILE_NG;
9299 too_many_arg:
9300 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9301 return COMPILE_NG;
9302 non_symbol_arg:
9303 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9304 rb_builtin_class_name(name));
9305 return COMPILE_NG;
9306 bad_arg:
9307 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9308}
9309
9310static NODE *
9311mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9312{
9313 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9314 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9315 return RNODE_IF(node)->nd_body;
9316 }
9317 else {
9318 rb_bug("mandatory_node: can't find mandatory node");
9319 }
9320}
9321
9322static int
9323compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9324{
9325 // arguments
9326 struct rb_args_info args = {
9327 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9328 };
9329 rb_node_args_t args_node;
9330 rb_node_init(RNODE(&args_node), NODE_ARGS);
9331 args_node.nd_ainfo = args;
9332
9333 // local table without non-mandatory parameters
9334 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9335 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9336
9337 VALUE idtmp = 0;
9338 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9339 tbl->size = table_size;
9340
9341 int i;
9342
9343 // lead parameters
9344 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9345 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9346 }
9347 // local variables
9348 for (; i<table_size; i++) {
9349 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9350 }
9351
9352 rb_node_scope_t scope_node;
9353 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9354 scope_node.nd_tbl = tbl;
9355 scope_node.nd_body = mandatory_node(iseq, node);
9356 scope_node.nd_parent = NULL;
9357 scope_node.nd_args = &args_node;
9358
9359 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9360
9361 const rb_iseq_t *mandatory_only_iseq =
9362 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9363 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9364 nd_line(line_node), NULL, 0,
9365 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9366 ISEQ_BODY(iseq)->variable.script_lines);
9367 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9368
9369 ALLOCV_END(idtmp);
9370 return COMPILE_OK;
9371}
9372
9373static int
9374compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9375 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9376{
9377 NODE *args_node = get_nd_args(node);
9378
9379 if (parent_block != NULL) {
9380 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9381 return COMPILE_NG;
9382 }
9383 else {
9384# define BUILTIN_INLINE_PREFIX "_bi"
9385 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9386 bool cconst = false;
9387 retry:;
9388 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9389
9390 if (bf == NULL) {
9391 if (strcmp("cstmt!", builtin_func) == 0 ||
9392 strcmp("cexpr!", builtin_func) == 0) {
9393 // ok
9394 }
9395 else if (strcmp("cconst!", builtin_func) == 0) {
9396 cconst = true;
9397 }
9398 else if (strcmp("cinit!", builtin_func) == 0) {
9399 // ignore
9400 return COMPILE_OK;
9401 }
9402 else if (strcmp("attr!", builtin_func) == 0) {
9403 return compile_builtin_attr(iseq, args_node);
9404 }
9405 else if (strcmp("arg!", builtin_func) == 0) {
9406 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9407 }
9408 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9409 if (popped) {
9410 rb_bug("mandatory_only? should be in if condition");
9411 }
9412 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9413 rb_bug("mandatory_only? should be put on top");
9414 }
9415
9416 ADD_INSN1(ret, line_node, putobject, Qfalse);
9417 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9418 }
9419 else if (1) {
9420 rb_bug("can't find builtin function:%s", builtin_func);
9421 }
9422 else {
9423 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9424 return COMPILE_NG;
9425 }
9426
9427 int inline_index = nd_line(node);
9428 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9429 builtin_func = inline_func;
9430 args_node = NULL;
9431 goto retry;
9432 }
9433
9434 if (cconst) {
9435 typedef VALUE(*builtin_func0)(void *, VALUE);
9436 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9437 ADD_INSN1(ret, line_node, putobject, const_val);
9438 return COMPILE_OK;
9439 }
9440
9441 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9442
9443 unsigned int flag = 0;
9444 struct rb_callinfo_kwarg *keywords = NULL;
9445 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9446
9447 if (FIX2INT(argc) != bf->argc) {
9448 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9449 builtin_func, bf->argc, FIX2INT(argc));
9450 return COMPILE_NG;
9451 }
9452
9453 unsigned int start_index;
9454 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9455 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9456 }
9457 else {
9458 ADD_SEQ(ret, args);
9459 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9460 }
9461
9462 if (popped) ADD_INSN(ret, line_node, pop);
9463 return COMPILE_OK;
9464 }
9465}
9466
9467static int
9468compile_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)
9469{
9470 /* call: obj.method(...)
9471 * fcall: func(...)
9472 * vcall: func
9473 */
9474 DECL_ANCHOR(recv);
9475 DECL_ANCHOR(args);
9476 ID mid = get_node_call_nd_mid(node);
9477 VALUE argc;
9478 unsigned int flag = 0;
9479 struct rb_callinfo_kwarg *keywords = NULL;
9480 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9481 LABEL *else_label = NULL;
9482 VALUE branches = Qfalse;
9483
9484 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9485
9486 INIT_ANCHOR(recv);
9487 INIT_ANCHOR(args);
9488
9489#if OPT_SUPPORT_JOKE
9490 if (nd_type_p(node, NODE_VCALL)) {
9491 ID id_bitblt;
9492 ID id_answer;
9493
9494 CONST_ID(id_bitblt, "bitblt");
9495 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9496
9497 if (mid == id_bitblt) {
9498 ADD_INSN(ret, line_node, bitblt);
9499 return COMPILE_OK;
9500 }
9501 else if (mid == id_answer) {
9502 ADD_INSN(ret, line_node, answer);
9503 return COMPILE_OK;
9504 }
9505 }
9506 /* only joke */
9507 {
9508 ID goto_id;
9509 ID label_id;
9510
9511 CONST_ID(goto_id, "__goto__");
9512 CONST_ID(label_id, "__label__");
9513
9514 if (nd_type_p(node, NODE_FCALL) &&
9515 (mid == goto_id || mid == label_id)) {
9516 LABEL *label;
9517 st_data_t data;
9518 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9519 VALUE label_name;
9520
9521 if (!labels_table) {
9522 labels_table = st_init_numtable();
9523 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9524 }
9525 {
9526 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9527 return COMPILE_NG;
9528 }
9529
9530 if (mid == goto_id) {
9531 ADD_INSNL(ret, line_node, jump, label);
9532 }
9533 else {
9534 ADD_LABEL(ret, label);
9535 }
9536 return COMPILE_OK;
9537 }
9538 }
9539#endif
9540
9541 const char *builtin_func;
9542 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9543 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9544 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9545 }
9546
9547 /* receiver */
9548 if (!assume_receiver) {
9549 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9550 int idx, level;
9551
9552 if (mid == idCall &&
9553 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9554 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9555 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9556 }
9557 else if (private_recv_p(node)) {
9558 ADD_INSN(recv, node, putself);
9559 flag |= VM_CALL_FCALL;
9560 }
9561 else {
9562 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9563 }
9564
9565 if (type == NODE_QCALL) {
9566 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9567 }
9568 }
9569 else if (type == NODE_FCALL || type == NODE_VCALL) {
9570 ADD_CALL_RECEIVER(recv, line_node);
9571 }
9572 }
9573
9574 /* args */
9575 if (type != NODE_VCALL) {
9576 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9577 CHECK(!NIL_P(argc));
9578 }
9579 else {
9580 argc = INT2FIX(0);
9581 }
9582
9583 ADD_SEQ(ret, recv);
9584
9585 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9586 mid == rb_intern("new") &&
9587 parent_block == NULL &&
9588 !(flag & VM_CALL_ARGS_BLOCKARG);
9589
9590 if (inline_new) {
9591 ADD_INSN(ret, node, putnil);
9592 ADD_INSN(ret, node, swap);
9593 }
9594
9595 ADD_SEQ(ret, args);
9596
9597 debugp_param("call args argc", argc);
9598 debugp_param("call method", ID2SYM(mid));
9599
9600 switch ((int)type) {
9601 case NODE_VCALL:
9602 flag |= VM_CALL_VCALL;
9603 /* VCALL is funcall, so fall through */
9604 case NODE_FCALL:
9605 flag |= VM_CALL_FCALL;
9606 }
9607
9608 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9609 ADD_INSN(ret, line_node, splatkw);
9610 }
9611
9612 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9613 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9614
9615 if (inline_new) {
9616 // Jump unless the receiver uses the "basic" implementation of "new"
9617 VALUE ci;
9618 if (flag & VM_CALL_FORWARDING) {
9619 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9620 }
9621 else {
9622 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9623 }
9624 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9625 LABEL_REF(not_basic_new);
9626
9627 // optimized path
9628 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9629 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9630
9631 ADD_LABEL(ret, not_basic_new);
9632 // Fall back to normal send
9633 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9634 ADD_INSN(ret, line_node, swap);
9635
9636 ADD_LABEL(ret, not_basic_new_finish);
9637 ADD_INSN(ret, line_node, pop);
9638 }
9639 else {
9640 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9641 }
9642
9643 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9644 if (popped) {
9645 ADD_INSN(ret, line_node, pop);
9646 }
9647 return COMPILE_OK;
9648}
9649
9650static int
9651compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9652{
9653 const int line = nd_line(node);
9654 VALUE argc;
9655 unsigned int flag = 0;
9656 int asgnflag = 0;
9657 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9658
9659 /*
9660 * a[x] (op)= y
9661 *
9662 * nil # nil
9663 * eval a # nil a
9664 * eval x # nil a x
9665 * dupn 2 # nil a x a x
9666 * send :[] # nil a x a[x]
9667 * eval y # nil a x a[x] y
9668 * send op # nil a x ret
9669 * setn 3 # ret a x ret
9670 * send []= # ret ?
9671 * pop # ret
9672 */
9673
9674 /*
9675 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9676 * NODE_OP_ASGN nd_recv
9677 * nd_args->nd_head
9678 * nd_args->nd_body
9679 * nd_mid
9680 */
9681
9682 if (!popped) {
9683 ADD_INSN(ret, node, putnil);
9684 }
9685 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9686 CHECK(asgnflag != -1);
9687 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9688 case NODE_ZLIST:
9689 argc = INT2FIX(0);
9690 break;
9691 default:
9692 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9693 CHECK(!NIL_P(argc));
9694 }
9695 int dup_argn = FIX2INT(argc) + 1;
9696 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9697 flag |= asgnflag;
9698 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9699
9700 if (id == idOROP || id == idANDOP) {
9701 /* a[x] ||= y or a[x] &&= y
9702
9703 unless/if a[x]
9704 a[x]= y
9705 else
9706 nil
9707 end
9708 */
9709 LABEL *label = NEW_LABEL(line);
9710 LABEL *lfin = NEW_LABEL(line);
9711
9712 ADD_INSN(ret, node, dup);
9713 if (id == idOROP) {
9714 ADD_INSNL(ret, node, branchif, label);
9715 }
9716 else { /* idANDOP */
9717 ADD_INSNL(ret, node, branchunless, label);
9718 }
9719 ADD_INSN(ret, node, pop);
9720
9721 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9722 if (!popped) {
9723 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9724 }
9725 if (flag & VM_CALL_ARGS_SPLAT) {
9726 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9727 ADD_INSN(ret, node, swap);
9728 ADD_INSN1(ret, node, splatarray, Qtrue);
9729 ADD_INSN(ret, node, swap);
9730 flag |= VM_CALL_ARGS_SPLAT_MUT;
9731 }
9732 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9733 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9734 }
9735 else {
9736 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9737 }
9738 ADD_INSN(ret, node, pop);
9739 ADD_INSNL(ret, node, jump, lfin);
9740 ADD_LABEL(ret, label);
9741 if (!popped) {
9742 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9743 }
9744 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9745 ADD_LABEL(ret, lfin);
9746 }
9747 else {
9748 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9749 ADD_SEND(ret, node, id, INT2FIX(1));
9750 if (!popped) {
9751 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9752 }
9753 if (flag & VM_CALL_ARGS_SPLAT) {
9754 if (flag & VM_CALL_KW_SPLAT) {
9755 ADD_INSN1(ret, node, topn, INT2FIX(2));
9756 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9757 ADD_INSN1(ret, node, splatarray, Qtrue);
9758 flag |= VM_CALL_ARGS_SPLAT_MUT;
9759 }
9760 ADD_INSN(ret, node, swap);
9761 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9762 ADD_INSN1(ret, node, setn, INT2FIX(2));
9763 ADD_INSN(ret, node, pop);
9764 }
9765 else {
9766 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9767 ADD_INSN(ret, node, swap);
9768 ADD_INSN1(ret, node, splatarray, Qtrue);
9769 ADD_INSN(ret, node, swap);
9770 flag |= VM_CALL_ARGS_SPLAT_MUT;
9771 }
9772 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9773 }
9774 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9775 }
9776 else {
9777 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9778 }
9779 ADD_INSN(ret, node, pop);
9780 }
9781 return COMPILE_OK;
9782}
9783
9784static int
9785compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9786{
9787 const int line = nd_line(node);
9788 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9789 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9790 int asgnflag;
9791 LABEL *lfin = NEW_LABEL(line);
9792 LABEL *lcfin = NEW_LABEL(line);
9793 LABEL *lskip = 0;
9794 /*
9795 class C; attr_accessor :c; end
9796 r = C.new
9797 r.a &&= v # asgn2
9798
9799 eval r # r
9800 dup # r r
9801 eval r.a # r o
9802
9803 # or
9804 dup # r o o
9805 if lcfin # r o
9806 pop # r
9807 eval v # r v
9808 swap # v r
9809 topn 1 # v r v
9810 send a= # v ?
9811 jump lfin # v ?
9812
9813 lcfin: # r o
9814 swap # o r
9815
9816 lfin: # o ?
9817 pop # o
9818
9819 # or (popped)
9820 if lcfin # r
9821 eval v # r v
9822 send a= # ?
9823 jump lfin # ?
9824
9825 lcfin: # r
9826
9827 lfin: # ?
9828 pop #
9829
9830 # and
9831 dup # r o o
9832 unless lcfin
9833 pop # r
9834 eval v # r v
9835 swap # v r
9836 topn 1 # v r v
9837 send a= # v ?
9838 jump lfin # v ?
9839
9840 # others
9841 eval v # r o v
9842 send ?? # r w
9843 send a= # w
9844
9845 */
9846
9847 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9848 CHECK(asgnflag != -1);
9849 if (RNODE_OP_ASGN2(node)->nd_aid) {
9850 lskip = NEW_LABEL(line);
9851 ADD_INSN(ret, node, dup);
9852 ADD_INSNL(ret, node, branchnil, lskip);
9853 }
9854 ADD_INSN(ret, node, dup);
9855 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9856
9857 if (atype == idOROP || atype == idANDOP) {
9858 if (!popped) {
9859 ADD_INSN(ret, node, dup);
9860 }
9861 if (atype == idOROP) {
9862 ADD_INSNL(ret, node, branchif, lcfin);
9863 }
9864 else { /* idANDOP */
9865 ADD_INSNL(ret, node, branchunless, lcfin);
9866 }
9867 if (!popped) {
9868 ADD_INSN(ret, node, pop);
9869 }
9870 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9871 if (!popped) {
9872 ADD_INSN(ret, node, swap);
9873 ADD_INSN1(ret, node, topn, INT2FIX(1));
9874 }
9875 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9876 ADD_INSNL(ret, node, jump, lfin);
9877
9878 ADD_LABEL(ret, lcfin);
9879 if (!popped) {
9880 ADD_INSN(ret, node, swap);
9881 }
9882
9883 ADD_LABEL(ret, lfin);
9884 }
9885 else {
9886 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9887 ADD_SEND(ret, node, atype, INT2FIX(1));
9888 if (!popped) {
9889 ADD_INSN(ret, node, swap);
9890 ADD_INSN1(ret, node, topn, INT2FIX(1));
9891 }
9892 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9893 }
9894 if (lskip && popped) {
9895 ADD_LABEL(ret, lskip);
9896 }
9897 ADD_INSN(ret, node, pop);
9898 if (lskip && !popped) {
9899 ADD_LABEL(ret, lskip);
9900 }
9901 return COMPILE_OK;
9902}
9903
9904static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9905
9906static int
9907compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9908{
9909 const int line = nd_line(node);
9910 LABEL *lfin = 0;
9911 LABEL *lassign = 0;
9912 ID mid;
9913
9914 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9915 case NODE_COLON3:
9916 ADD_INSN1(ret, node, putobject, rb_cObject);
9917 break;
9918 case NODE_COLON2:
9919 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9920 break;
9921 default:
9922 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9923 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9924 return COMPILE_NG;
9925 }
9926 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9927 /* cref */
9928 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9929 lassign = NEW_LABEL(line);
9930 ADD_INSN(ret, node, dup); /* cref cref */
9931 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9932 ID2SYM(mid), Qtrue); /* cref bool */
9933 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9934 }
9935 ADD_INSN(ret, node, dup); /* cref cref */
9936 ADD_INSN1(ret, node, putobject, Qtrue);
9937 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9938
9939 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9940 lfin = NEW_LABEL(line);
9941 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9942 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9943 ADD_INSNL(ret, node, branchif, lfin);
9944 else /* idANDOP */
9945 ADD_INSNL(ret, node, branchunless, lfin);
9946 /* cref [obj] */
9947 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9948 if (lassign) ADD_LABEL(ret, lassign);
9949 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9950 /* cref value */
9951 if (popped)
9952 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9953 else {
9954 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9955 ADD_INSN(ret, node, swap); /* cref value value cref */
9956 }
9957 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9958 ADD_LABEL(ret, lfin); /* cref [value] */
9959 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9960 ADD_INSN(ret, node, pop); /* [value] */
9961 }
9962 else {
9963 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9964 /* cref obj value */
9965 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9966 /* cref value */
9967 ADD_INSN(ret, node, swap); /* value cref */
9968 if (!popped) {
9969 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9970 ADD_INSN(ret, node, swap); /* value value cref */
9971 }
9972 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9973 }
9974 return COMPILE_OK;
9975}
9976
9977static int
9978compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9979{
9980 const int line = nd_line(node);
9981 LABEL *lfin = NEW_LABEL(line);
9982 LABEL *lassign;
9983
9984 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9985 LABEL *lfinish[2];
9986 lfinish[0] = lfin;
9987 lfinish[1] = 0;
9988 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9989 lassign = lfinish[1];
9990 if (!lassign) {
9991 lassign = NEW_LABEL(line);
9992 }
9993 ADD_INSNL(ret, node, branchunless, lassign);
9994 }
9995 else {
9996 lassign = NEW_LABEL(line);
9997 }
9998
9999 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10000
10001 if (!popped) {
10002 ADD_INSN(ret, node, dup);
10003 }
10004
10005 if (type == NODE_OP_ASGN_AND) {
10006 ADD_INSNL(ret, node, branchunless, lfin);
10007 }
10008 else {
10009 ADD_INSNL(ret, node, branchif, lfin);
10010 }
10011
10012 if (!popped) {
10013 ADD_INSN(ret, node, pop);
10014 }
10015
10016 ADD_LABEL(ret, lassign);
10017 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10018 ADD_LABEL(ret, lfin);
10019 return COMPILE_OK;
10020}
10021
10022static int
10023compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10024{
10025 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10026 DECL_ANCHOR(args);
10027 int argc;
10028 unsigned int flag = 0;
10029 struct rb_callinfo_kwarg *keywords = NULL;
10030 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10031 int use_block = 1;
10032
10033 INIT_ANCHOR(args);
10034 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10035
10036 if (type == NODE_SUPER) {
10037 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10038 CHECK(!NIL_P(vargc));
10039 argc = FIX2INT(vargc);
10040 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10041 ADD_INSN(args, node, splatkw);
10042 }
10043
10044 if (flag & VM_CALL_ARGS_BLOCKARG) {
10045 use_block = 0;
10046 }
10047 }
10048 else {
10049 /* NODE_ZSUPER */
10050 int i;
10051 const rb_iseq_t *liseq = body->local_iseq;
10052 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10053 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10054 int lvar_level = get_lvar_level(iseq);
10055
10056 argc = local_body->param.lead_num;
10057
10058 /* normal arguments */
10059 for (i = 0; i < local_body->param.lead_num; i++) {
10060 int idx = local_body->local_table_size - i;
10061 ADD_GETLOCAL(args, node, idx, lvar_level);
10062 }
10063
10064 /* forward ... */
10065 if (local_body->param.flags.forwardable) {
10066 flag |= VM_CALL_FORWARDING;
10067 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10068 ADD_GETLOCAL(args, node, idx, lvar_level);
10069 }
10070
10071 if (local_body->param.flags.has_opt) {
10072 /* optional arguments */
10073 int j;
10074 for (j = 0; j < local_body->param.opt_num; j++) {
10075 int idx = local_body->local_table_size - (i + j);
10076 ADD_GETLOCAL(args, node, idx, lvar_level);
10077 }
10078 i += j;
10079 argc = i;
10080 }
10081 if (local_body->param.flags.has_rest) {
10082 /* rest argument */
10083 int idx = local_body->local_table_size - local_body->param.rest_start;
10084 ADD_GETLOCAL(args, node, idx, lvar_level);
10085 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10086
10087 argc = local_body->param.rest_start + 1;
10088 flag |= VM_CALL_ARGS_SPLAT;
10089 }
10090 if (local_body->param.flags.has_post) {
10091 /* post arguments */
10092 int post_len = local_body->param.post_num;
10093 int post_start = local_body->param.post_start;
10094
10095 if (local_body->param.flags.has_rest) {
10096 int j;
10097 for (j=0; j<post_len; j++) {
10098 int idx = local_body->local_table_size - (post_start + j);
10099 ADD_GETLOCAL(args, node, idx, lvar_level);
10100 }
10101 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10102 flag |= VM_CALL_ARGS_SPLAT_MUT;
10103 /* argc is settled at above */
10104 }
10105 else {
10106 int j;
10107 for (j=0; j<post_len; j++) {
10108 int idx = local_body->local_table_size - (post_start + j);
10109 ADD_GETLOCAL(args, node, idx, lvar_level);
10110 }
10111 argc = post_len + post_start;
10112 }
10113 }
10114
10115 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10116 int local_size = local_body->local_table_size;
10117 argc++;
10118
10119 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10120
10121 if (local_body->param.flags.has_kwrest) {
10122 int idx = local_body->local_table_size - local_kwd->rest_start;
10123 ADD_GETLOCAL(args, node, idx, lvar_level);
10124 RUBY_ASSERT(local_kwd->num > 0);
10125 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10126 }
10127 else {
10128 ADD_INSN1(args, node, newhash, INT2FIX(0));
10129 }
10130 for (i = 0; i < local_kwd->num; ++i) {
10131 ID id = local_kwd->table[i];
10132 int idx = local_size - get_local_var_idx(liseq, id);
10133 ADD_INSN1(args, node, putobject, ID2SYM(id));
10134 ADD_GETLOCAL(args, node, idx, lvar_level);
10135 }
10136 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10137 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10138 }
10139 else if (local_body->param.flags.has_kwrest) {
10140 int idx = local_body->local_table_size - local_kwd->rest_start;
10141 ADD_GETLOCAL(args, node, idx, lvar_level);
10142 argc++;
10143 flag |= VM_CALL_KW_SPLAT;
10144 }
10145 }
10146
10147 if (use_block && parent_block == NULL) {
10148 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10149 }
10150
10151 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10152 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10153 ADD_INSN(ret, node, putself);
10154 ADD_SEQ(ret, args);
10155
10156 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10157
10158 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10159 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10160 }
10161 else {
10162 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10163 }
10164
10165 if (popped) {
10166 ADD_INSN(ret, node, pop);
10167 }
10168 return COMPILE_OK;
10169}
10170
10171static int
10172compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10173{
10174 DECL_ANCHOR(args);
10175 VALUE argc;
10176 unsigned int flag = 0;
10177 struct rb_callinfo_kwarg *keywords = NULL;
10178
10179 INIT_ANCHOR(args);
10180
10181 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10182 case ISEQ_TYPE_TOP:
10183 case ISEQ_TYPE_MAIN:
10184 case ISEQ_TYPE_CLASS:
10185 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10186 return COMPILE_NG;
10187 default: /* valid */;
10188 }
10189
10190 if (RNODE_YIELD(node)->nd_head) {
10191 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10192 CHECK(!NIL_P(argc));
10193 }
10194 else {
10195 argc = INT2FIX(0);
10196 }
10197
10198 ADD_SEQ(ret, args);
10199 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10200 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10201
10202 if (popped) {
10203 ADD_INSN(ret, node, pop);
10204 }
10205
10206 int level = 0;
10207 const rb_iseq_t *tmp_iseq = iseq;
10208 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10209 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10210 }
10211 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10212
10213 return COMPILE_OK;
10214}
10215
10216static int
10217compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10218{
10219 DECL_ANCHOR(recv);
10220 DECL_ANCHOR(val);
10221
10222 INIT_ANCHOR(recv);
10223 INIT_ANCHOR(val);
10224 switch ((int)type) {
10225 case NODE_MATCH:
10226 {
10227 VALUE re = rb_node_regx_string_val(node);
10228 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10229 ADD_INSN1(recv, node, putobject, re);
10230 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10231 INT2FIX(0));
10232 }
10233 break;
10234 case NODE_MATCH2:
10235 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10236 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10237 break;
10238 case NODE_MATCH3:
10239 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10240 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10241 break;
10242 }
10243
10244 ADD_SEQ(ret, recv);
10245 ADD_SEQ(ret, val);
10246 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10247
10248 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10249 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10250 }
10251
10252 if (popped) {
10253 ADD_INSN(ret, node, pop);
10254 }
10255 return COMPILE_OK;
10256}
10257
10258static int
10259compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10260{
10261 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10262 /* constant */
10263 VALUE segments;
10264 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10265 (segments = collect_const_segments(iseq, node))) {
10266 ISEQ_BODY(iseq)->ic_size++;
10267 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10268 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10269 }
10270 else {
10271 /* constant */
10272 DECL_ANCHOR(pref);
10273 DECL_ANCHOR(body);
10274
10275 INIT_ANCHOR(pref);
10276 INIT_ANCHOR(body);
10277 CHECK(compile_const_prefix(iseq, node, pref, body));
10278 if (LIST_INSN_SIZE_ZERO(pref)) {
10279 ADD_INSN(ret, node, putnil);
10280 ADD_SEQ(ret, body);
10281 }
10282 else {
10283 ADD_SEQ(ret, pref);
10284 ADD_SEQ(ret, body);
10285 }
10286 }
10287 }
10288 else {
10289 /* function call */
10290 ADD_CALL_RECEIVER(ret, node);
10291 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10292 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10293 }
10294 if (popped) {
10295 ADD_INSN(ret, node, pop);
10296 }
10297 return COMPILE_OK;
10298}
10299
10300static int
10301compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10302{
10303 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10304
10305 /* add cache insn */
10306 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10307 ISEQ_BODY(iseq)->ic_size++;
10308 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10309 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10310 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10311 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10312 }
10313 else {
10314 ADD_INSN1(ret, node, putobject, rb_cObject);
10315 ADD_INSN1(ret, node, putobject, Qtrue);
10316 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10317 }
10318
10319 if (popped) {
10320 ADD_INSN(ret, node, pop);
10321 }
10322 return COMPILE_OK;
10323}
10324
10325static int
10326compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10327{
10328 VALUE flag = INT2FIX(excl);
10329 const NODE *b = RNODE_DOT2(node)->nd_beg;
10330 const NODE *e = RNODE_DOT2(node)->nd_end;
10331
10332 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10333 if (!popped) {
10334 VALUE bv = optimized_range_item(b);
10335 VALUE ev = optimized_range_item(e);
10336 VALUE val = rb_range_new(bv, ev, excl);
10338 ADD_INSN1(ret, node, putobject, val);
10339 RB_OBJ_WRITTEN(iseq, Qundef, val);
10340 }
10341 }
10342 else {
10343 CHECK(COMPILE_(ret, "min", b, popped));
10344 CHECK(COMPILE_(ret, "max", e, popped));
10345 if (!popped) {
10346 ADD_INSN1(ret, node, newrange, flag);
10347 }
10348 }
10349 return COMPILE_OK;
10350}
10351
10352static int
10353compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10354{
10355 if (!popped) {
10356 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10357 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10358 }
10359 else {
10360 const rb_iseq_t *ip = iseq;
10361 int level = 0;
10362 while (ip) {
10363 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10364 break;
10365 }
10366 ip = ISEQ_BODY(ip)->parent_iseq;
10367 level++;
10368 }
10369 if (ip) {
10370 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10371 }
10372 else {
10373 ADD_INSN(ret, node, putnil);
10374 }
10375 }
10376 }
10377 return COMPILE_OK;
10378}
10379
10380static int
10381compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10382{
10383 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10384 LABEL *end_label = NEW_LABEL(nd_line(node));
10385 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10386
10387 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10388 /* required argument. do nothing */
10389 COMPILE_ERROR(ERROR_ARGS "unreachable");
10390 return COMPILE_NG;
10391 }
10392 else if (nd_type_p(default_value, NODE_SYM) ||
10393 nd_type_p(default_value, NODE_REGX) ||
10394 nd_type_p(default_value, NODE_LINE) ||
10395 nd_type_p(default_value, NODE_INTEGER) ||
10396 nd_type_p(default_value, NODE_FLOAT) ||
10397 nd_type_p(default_value, NODE_RATIONAL) ||
10398 nd_type_p(default_value, NODE_IMAGINARY) ||
10399 nd_type_p(default_value, NODE_NIL) ||
10400 nd_type_p(default_value, NODE_TRUE) ||
10401 nd_type_p(default_value, NODE_FALSE)) {
10402 COMPILE_ERROR(ERROR_ARGS "unreachable");
10403 return COMPILE_NG;
10404 }
10405 else {
10406 /* if keywordcheck(_kw_bits, nth_keyword)
10407 * kw = default_value
10408 * end
10409 */
10410 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10411 int keyword_idx = body->param.keyword->num;
10412
10413 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10414 ADD_INSNL(ret, node, branchif, end_label);
10415 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10416 ADD_LABEL(ret, end_label);
10417 }
10418 return COMPILE_OK;
10419}
10420
10421static int
10422compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10423{
10424 DECL_ANCHOR(recv);
10425 DECL_ANCHOR(args);
10426 unsigned int flag = 0;
10427 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10428 VALUE argc;
10429 LABEL *else_label = NULL;
10430 VALUE branches = Qfalse;
10431
10432 INIT_ANCHOR(recv);
10433 INIT_ANCHOR(args);
10434 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10435 CHECK(!NIL_P(argc));
10436
10437 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10438 CHECK(asgnflag != -1);
10439 flag |= (unsigned int)asgnflag;
10440
10441 debugp_param("argc", argc);
10442 debugp_param("nd_mid", ID2SYM(mid));
10443
10444 if (!rb_is_attrset_id(mid)) {
10445 /* safe nav attr */
10446 mid = rb_id_attrset(mid);
10447 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10448 }
10449 if (!popped) {
10450 ADD_INSN(ret, node, putnil);
10451 ADD_SEQ(ret, recv);
10452 ADD_SEQ(ret, args);
10453
10454 if (flag & VM_CALL_ARGS_SPLAT) {
10455 ADD_INSN(ret, node, dup);
10456 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10457 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10458 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10459 ADD_INSN (ret, node, pop);
10460 }
10461 else {
10462 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10463 }
10464 }
10465 else {
10466 ADD_SEQ(ret, recv);
10467 ADD_SEQ(ret, args);
10468 }
10469 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10470 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10471 ADD_INSN(ret, node, pop);
10472 return COMPILE_OK;
10473}
10474
10475static int
10476compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10477{
10478 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10479 ADD_SEQ(ret, sub);
10480
10481 if (copy) {
10482 /*
10483 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10484 * NEW_LIST(value, loc), loc);
10485 */
10486 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10487 }
10488 else {
10489 /*
10490 * NEW_CALL(fcore, rb_intern("make_shareable"),
10491 * NEW_LIST(value, loc), loc);
10492 */
10493 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10494 }
10495
10496 return COMPILE_OK;
10497}
10498
10499static VALUE
10500node_const_decl_val(const NODE *node)
10501{
10502 VALUE path;
10503 switch (nd_type(node)) {
10504 case NODE_CDECL:
10505 if (RNODE_CDECL(node)->nd_vid) {
10506 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10507 goto end;
10508 }
10509 else {
10510 node = RNODE_CDECL(node)->nd_else;
10511 }
10512 break;
10513 case NODE_COLON2:
10514 break;
10515 case NODE_COLON3:
10516 // ::Const
10517 path = rb_str_new_cstr("::");
10518 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10519 goto end;
10520 default:
10521 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10523 }
10524
10525 path = rb_ary_new();
10526 if (node) {
10527 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10528 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10529 }
10530 if (node && nd_type_p(node, NODE_CONST)) {
10531 // Const::Name
10532 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10533 }
10534 else if (node && nd_type_p(node, NODE_COLON3)) {
10535 // ::Const::Name
10536 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10537 rb_ary_push(path, rb_str_new(0, 0));
10538 }
10539 else {
10540 // expression::Name
10541 rb_ary_push(path, rb_str_new_cstr("..."));
10542 }
10543 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10544 }
10545 end:
10546 path = rb_fstring(path);
10547 return path;
10548}
10549
10550static VALUE
10551const_decl_path(NODE *dest)
10552{
10553 VALUE path = Qnil;
10554 if (!nd_type_p(dest, NODE_CALL)) {
10555 path = node_const_decl_val(dest);
10556 }
10557 return path;
10558}
10559
10560static int
10561compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10562{
10563 /*
10564 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10565 */
10566 VALUE path = const_decl_path(dest);
10567 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10568 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10569 ADD_INSN1(ret, value, putobject, path);
10570 RB_OBJ_WRITTEN(iseq, Qundef, path);
10571 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10572
10573 return COMPILE_OK;
10574}
10575
10576#ifndef SHAREABLE_BARE_EXPRESSION
10577#define SHAREABLE_BARE_EXPRESSION 1
10578#endif
10579
10580static int
10581compile_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)
10582{
10583# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10584 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10585 VALUE lit = Qnil;
10586 DECL_ANCHOR(anchor);
10587
10588 enum node_type type = node ? nd_type(node) : NODE_NIL;
10589 switch (type) {
10590 case NODE_TRUE:
10591 *value_p = Qtrue;
10592 goto compile;
10593 case NODE_FALSE:
10594 *value_p = Qfalse;
10595 goto compile;
10596 case NODE_NIL:
10597 *value_p = Qnil;
10598 goto compile;
10599 case NODE_SYM:
10600 *value_p = rb_node_sym_string_val(node);
10601 goto compile;
10602 case NODE_REGX:
10603 *value_p = rb_node_regx_string_val(node);
10604 goto compile;
10605 case NODE_LINE:
10606 *value_p = rb_node_line_lineno_val(node);
10607 goto compile;
10608 case NODE_INTEGER:
10609 *value_p = rb_node_integer_literal_val(node);
10610 goto compile;
10611 case NODE_FLOAT:
10612 *value_p = rb_node_float_literal_val(node);
10613 goto compile;
10614 case NODE_RATIONAL:
10615 *value_p = rb_node_rational_literal_val(node);
10616 goto compile;
10617 case NODE_IMAGINARY:
10618 *value_p = rb_node_imaginary_literal_val(node);
10619 goto compile;
10620 case NODE_ENCODING:
10621 *value_p = rb_node_encoding_val(node);
10622
10623 compile:
10624 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10625 *shareable_literal_p = 1;
10626 return COMPILE_OK;
10627
10628 case NODE_DSTR:
10629 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10630 if (shareable == rb_parser_shareable_literal) {
10631 /*
10632 * NEW_CALL(node, idUMinus, 0, loc);
10633 *
10634 * -"#{var}"
10635 */
10636 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10637 }
10638 *value_p = Qundef;
10639 *shareable_literal_p = 1;
10640 return COMPILE_OK;
10641
10642 case NODE_STR:{
10643 VALUE lit = rb_node_str_string_val(node);
10644 ADD_INSN1(ret, node, putobject, lit);
10645 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10646 *value_p = lit;
10647 *shareable_literal_p = 1;
10648
10649 return COMPILE_OK;
10650 }
10651
10652 case NODE_FILE:{
10653 VALUE lit = rb_node_file_path_val(node);
10654 ADD_INSN1(ret, node, putobject, lit);
10655 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10656 *value_p = lit;
10657 *shareable_literal_p = 1;
10658
10659 return COMPILE_OK;
10660 }
10661
10662 case NODE_ZLIST:{
10663 VALUE lit = rb_ary_new();
10664 OBJ_FREEZE(lit);
10665 ADD_INSN1(ret, node, putobject, lit);
10666 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10667 *value_p = lit;
10668 *shareable_literal_p = 1;
10669
10670 return COMPILE_OK;
10671 }
10672
10673 case NODE_LIST:{
10674 INIT_ANCHOR(anchor);
10675 lit = rb_ary_new();
10676 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10677 VALUE val;
10678 int shareable_literal_p2;
10679 NODE *elt = RNODE_LIST(n)->nd_head;
10680 if (elt) {
10681 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10682 if (shareable_literal_p2) {
10683 /* noop */
10684 }
10685 else if (RTEST(lit)) {
10686 rb_ary_clear(lit);
10687 lit = Qfalse;
10688 }
10689 }
10690 if (RTEST(lit)) {
10691 if (!UNDEF_P(val)) {
10692 rb_ary_push(lit, val);
10693 }
10694 else {
10695 rb_ary_clear(lit);
10696 lit = Qnil; /* make shareable at runtime */
10697 }
10698 }
10699 }
10700 break;
10701 }
10702 case NODE_HASH:{
10703 if (!RNODE_HASH(node)->nd_brace) {
10704 *value_p = Qundef;
10705 *shareable_literal_p = 0;
10706 return COMPILE_OK;
10707 }
10708 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10709 if (!RNODE_LIST(n)->nd_head) {
10710 // If the hash node have a keyword splat, fall back to the default case.
10711 goto compile_shareable;
10712 }
10713 }
10714
10715 INIT_ANCHOR(anchor);
10716 lit = rb_hash_new();
10717 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10718 VALUE key_val = 0;
10719 VALUE value_val = 0;
10720 int shareable_literal_p2;
10721 NODE *key = RNODE_LIST(n)->nd_head;
10722 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10723 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10724 if (shareable_literal_p2) {
10725 /* noop */
10726 }
10727 else if (RTEST(lit)) {
10728 rb_hash_clear(lit);
10729 lit = Qfalse;
10730 }
10731 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10732 if (shareable_literal_p2) {
10733 /* noop */
10734 }
10735 else if (RTEST(lit)) {
10736 rb_hash_clear(lit);
10737 lit = Qfalse;
10738 }
10739 if (RTEST(lit)) {
10740 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10741 rb_hash_aset(lit, key_val, value_val);
10742 }
10743 else {
10744 rb_hash_clear(lit);
10745 lit = Qnil; /* make shareable at runtime */
10746 }
10747 }
10748 }
10749 break;
10750 }
10751
10752 default:
10753
10754 compile_shareable:
10755 if (shareable == rb_parser_shareable_literal &&
10756 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10757 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10758 *value_p = Qundef;
10759 *shareable_literal_p = 1;
10760 return COMPILE_OK;
10761 }
10762 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10763 *value_p = Qundef;
10764 *shareable_literal_p = 0;
10765 return COMPILE_OK;
10766 }
10767
10768 /* Array or Hash that does not have keyword splat */
10769 if (!lit) {
10770 if (nd_type(node) == NODE_LIST) {
10771 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10772 }
10773 else if (nd_type(node) == NODE_HASH) {
10774 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10775 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10776 }
10777 *value_p = Qundef;
10778 *shareable_literal_p = 0;
10779 ADD_SEQ(ret, anchor);
10780 return COMPILE_OK;
10781 }
10782 if (NIL_P(lit)) {
10783 // if shareable_literal, all elements should have been ensured
10784 // as shareable
10785 if (nd_type(node) == NODE_LIST) {
10786 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10787 }
10788 else if (nd_type(node) == NODE_HASH) {
10789 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10790 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10791 }
10792 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10793 *value_p = Qundef;
10794 *shareable_literal_p = 1;
10795 }
10796 else {
10798 ADD_INSN1(ret, node, putobject, val);
10799 RB_OBJ_WRITTEN(iseq, Qundef, val);
10800 *value_p = val;
10801 *shareable_literal_p = 1;
10802 }
10803
10804 return COMPILE_OK;
10805}
10806
10807static int
10808compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10809{
10810 int literal_p = 0;
10811 VALUE val;
10812 DECL_ANCHOR(anchor);
10813 INIT_ANCHOR(anchor);
10814
10815 switch (shareable) {
10816 case rb_parser_shareable_none:
10817 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10818 return COMPILE_OK;
10819
10820 case rb_parser_shareable_literal:
10821 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10822 ADD_SEQ(ret, anchor);
10823 return COMPILE_OK;
10824
10825 case rb_parser_shareable_copy:
10826 case rb_parser_shareable_everything:
10827 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10828 if (!literal_p) {
10829 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10830 }
10831 else {
10832 ADD_SEQ(ret, anchor);
10833 }
10834 return COMPILE_OK;
10835 default:
10836 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10837 }
10838}
10839
10840static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10848static int
10849iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10850{
10851 if (node == 0) {
10852 if (!popped) {
10853 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10854 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10855 debugs("node: NODE_NIL(implicit)\n");
10856 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10857 }
10858 return COMPILE_OK;
10859 }
10860 return iseq_compile_each0(iseq, ret, node, popped);
10861}
10862
10863static int
10864iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10865{
10866 const int line = (int)nd_line(node);
10867 const enum node_type type = nd_type(node);
10868 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10869
10870 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10871 /* ignore */
10872 }
10873 else {
10874 if (nd_fl_newline(node)) {
10875 int event = RUBY_EVENT_LINE;
10876 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10877 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10878 event |= RUBY_EVENT_COVERAGE_LINE;
10879 }
10880 ADD_TRACE(ret, event);
10881 }
10882 }
10883
10884 debug_node_start(node);
10885#undef BEFORE_RETURN
10886#define BEFORE_RETURN debug_node_end()
10887
10888 switch (type) {
10889 case NODE_BLOCK:
10890 CHECK(compile_block(iseq, ret, node, popped));
10891 break;
10892 case NODE_IF:
10893 case NODE_UNLESS:
10894 CHECK(compile_if(iseq, ret, node, popped, type));
10895 break;
10896 case NODE_CASE:
10897 CHECK(compile_case(iseq, ret, node, popped));
10898 break;
10899 case NODE_CASE2:
10900 CHECK(compile_case2(iseq, ret, node, popped));
10901 break;
10902 case NODE_CASE3:
10903 CHECK(compile_case3(iseq, ret, node, popped));
10904 break;
10905 case NODE_WHILE:
10906 case NODE_UNTIL:
10907 CHECK(compile_loop(iseq, ret, node, popped, type));
10908 break;
10909 case NODE_FOR:
10910 case NODE_ITER:
10911 CHECK(compile_iter(iseq, ret, node, popped));
10912 break;
10913 case NODE_FOR_MASGN:
10914 CHECK(compile_for_masgn(iseq, ret, node, popped));
10915 break;
10916 case NODE_BREAK:
10917 CHECK(compile_break(iseq, ret, node, popped));
10918 break;
10919 case NODE_NEXT:
10920 CHECK(compile_next(iseq, ret, node, popped));
10921 break;
10922 case NODE_REDO:
10923 CHECK(compile_redo(iseq, ret, node, popped));
10924 break;
10925 case NODE_RETRY:
10926 CHECK(compile_retry(iseq, ret, node, popped));
10927 break;
10928 case NODE_BEGIN:{
10929 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10930 break;
10931 }
10932 case NODE_RESCUE:
10933 CHECK(compile_rescue(iseq, ret, node, popped));
10934 break;
10935 case NODE_RESBODY:
10936 CHECK(compile_resbody(iseq, ret, node, popped));
10937 break;
10938 case NODE_ENSURE:
10939 CHECK(compile_ensure(iseq, ret, node, popped));
10940 break;
10941
10942 case NODE_AND:
10943 case NODE_OR:{
10944 LABEL *end_label = NEW_LABEL(line);
10945 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10946 if (!popped) {
10947 ADD_INSN(ret, node, dup);
10948 }
10949 if (type == NODE_AND) {
10950 ADD_INSNL(ret, node, branchunless, end_label);
10951 }
10952 else {
10953 ADD_INSNL(ret, node, branchif, end_label);
10954 }
10955 if (!popped) {
10956 ADD_INSN(ret, node, pop);
10957 }
10958 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10959 ADD_LABEL(ret, end_label);
10960 break;
10961 }
10962
10963 case NODE_MASGN:{
10964 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10965 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10966 compile_massign(iseq, ret, node, popped);
10967 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10968 break;
10969 }
10970
10971 case NODE_LASGN:{
10972 ID id = RNODE_LASGN(node)->nd_vid;
10973 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10974
10975 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10976 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10977
10978 if (!popped) {
10979 ADD_INSN(ret, node, dup);
10980 }
10981 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10982 break;
10983 }
10984 case NODE_DASGN: {
10985 int idx, lv, ls;
10986 ID id = RNODE_DASGN(node)->nd_vid;
10987 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10988 debugi("dassn id", rb_id2str(id) ? id : '*');
10989
10990 if (!popped) {
10991 ADD_INSN(ret, node, dup);
10992 }
10993
10994 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10995
10996 if (idx < 0) {
10997 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10998 rb_id2str(id));
10999 goto ng;
11000 }
11001 ADD_SETLOCAL(ret, node, ls - idx, lv);
11002 break;
11003 }
11004 case NODE_GASGN:{
11005 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11006
11007 if (!popped) {
11008 ADD_INSN(ret, node, dup);
11009 }
11010 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11011 break;
11012 }
11013 case NODE_IASGN:{
11014 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11015 if (!popped) {
11016 ADD_INSN(ret, node, dup);
11017 }
11018 ADD_INSN2(ret, node, setinstancevariable,
11019 ID2SYM(RNODE_IASGN(node)->nd_vid),
11020 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11021 break;
11022 }
11023 case NODE_CDECL:{
11024 if (RNODE_CDECL(node)->nd_vid) {
11025 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11026
11027 if (!popped) {
11028 ADD_INSN(ret, node, dup);
11029 }
11030
11031 ADD_INSN1(ret, node, putspecialobject,
11032 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11033 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11034 }
11035 else {
11036 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11037 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11038 ADD_INSN(ret, node, swap);
11039
11040 if (!popped) {
11041 ADD_INSN1(ret, node, topn, INT2FIX(1));
11042 ADD_INSN(ret, node, swap);
11043 }
11044
11045 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11046 }
11047 break;
11048 }
11049 case NODE_CVASGN:{
11050 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11051 if (!popped) {
11052 ADD_INSN(ret, node, dup);
11053 }
11054 ADD_INSN2(ret, node, setclassvariable,
11055 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11056 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11057 break;
11058 }
11059 case NODE_OP_ASGN1:
11060 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11061 break;
11062 case NODE_OP_ASGN2:
11063 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11064 break;
11065 case NODE_OP_CDECL:
11066 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11067 break;
11068 case NODE_OP_ASGN_AND:
11069 case NODE_OP_ASGN_OR:
11070 CHECK(compile_op_log(iseq, ret, node, popped, type));
11071 break;
11072 case NODE_CALL: /* obj.foo */
11073 case NODE_OPCALL: /* foo[] */
11074 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11075 break;
11076 }
11077 case NODE_QCALL: /* obj&.foo */
11078 case NODE_FCALL: /* foo() */
11079 case NODE_VCALL: /* foo (variable or call) */
11080 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11081 goto ng;
11082 }
11083 break;
11084 case NODE_SUPER:
11085 case NODE_ZSUPER:
11086 CHECK(compile_super(iseq, ret, node, popped, type));
11087 break;
11088 case NODE_LIST:{
11089 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11090 break;
11091 }
11092 case NODE_ZLIST:{
11093 if (!popped) {
11094 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11095 }
11096 break;
11097 }
11098 case NODE_HASH:
11099 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11100 break;
11101 case NODE_RETURN:
11102 CHECK(compile_return(iseq, ret, node, popped));
11103 break;
11104 case NODE_YIELD:
11105 CHECK(compile_yield(iseq, ret, node, popped));
11106 break;
11107 case NODE_LVAR:{
11108 if (!popped) {
11109 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11110 }
11111 break;
11112 }
11113 case NODE_DVAR:{
11114 int lv, idx, ls;
11115 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11116 if (!popped) {
11117 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11118 if (idx < 0) {
11119 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11120 rb_id2str(RNODE_DVAR(node)->nd_vid));
11121 goto ng;
11122 }
11123 ADD_GETLOCAL(ret, node, ls - idx, lv);
11124 }
11125 break;
11126 }
11127 case NODE_GVAR:{
11128 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11129 if (popped) {
11130 ADD_INSN(ret, node, pop);
11131 }
11132 break;
11133 }
11134 case NODE_IVAR:{
11135 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11136 if (!popped) {
11137 ADD_INSN2(ret, node, getinstancevariable,
11138 ID2SYM(RNODE_IVAR(node)->nd_vid),
11139 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11140 }
11141 break;
11142 }
11143 case NODE_CONST:{
11144 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11145
11146 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11147 body->ic_size++;
11148 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11149 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11150 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11151 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11152 }
11153 else {
11154 ADD_INSN(ret, node, putnil);
11155 ADD_INSN1(ret, node, putobject, Qtrue);
11156 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11157 }
11158
11159 if (popped) {
11160 ADD_INSN(ret, node, pop);
11161 }
11162 break;
11163 }
11164 case NODE_CVAR:{
11165 if (!popped) {
11166 ADD_INSN2(ret, node, getclassvariable,
11167 ID2SYM(RNODE_CVAR(node)->nd_vid),
11168 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11169 }
11170 break;
11171 }
11172 case NODE_NTH_REF:{
11173 if (!popped) {
11174 if (!RNODE_NTH_REF(node)->nd_nth) {
11175 ADD_INSN(ret, node, putnil);
11176 break;
11177 }
11178 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11179 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11180 }
11181 break;
11182 }
11183 case NODE_BACK_REF:{
11184 if (!popped) {
11185 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11186 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11187 }
11188 break;
11189 }
11190 case NODE_MATCH:
11191 case NODE_MATCH2:
11192 case NODE_MATCH3:
11193 CHECK(compile_match(iseq, ret, node, popped, type));
11194 break;
11195 case NODE_SYM:{
11196 if (!popped) {
11197 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11198 }
11199 break;
11200 }
11201 case NODE_LINE:{
11202 if (!popped) {
11203 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11204 }
11205 break;
11206 }
11207 case NODE_ENCODING:{
11208 if (!popped) {
11209 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11210 }
11211 break;
11212 }
11213 case NODE_INTEGER:{
11214 VALUE lit = rb_node_integer_literal_val(node);
11215 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11216 debugp_param("integer", lit);
11217 if (!popped) {
11218 ADD_INSN1(ret, node, putobject, lit);
11219 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11220 }
11221 break;
11222 }
11223 case NODE_FLOAT:{
11224 VALUE lit = rb_node_float_literal_val(node);
11225 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11226 debugp_param("float", lit);
11227 if (!popped) {
11228 ADD_INSN1(ret, node, putobject, lit);
11229 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11230 }
11231 break;
11232 }
11233 case NODE_RATIONAL:{
11234 VALUE lit = rb_node_rational_literal_val(node);
11236 debugp_param("rational", lit);
11237 if (!popped) {
11238 ADD_INSN1(ret, node, putobject, lit);
11239 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11240 }
11241 break;
11242 }
11243 case NODE_IMAGINARY:{
11244 VALUE lit = rb_node_imaginary_literal_val(node);
11246 debugp_param("imaginary", lit);
11247 if (!popped) {
11248 ADD_INSN1(ret, node, putobject, lit);
11249 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11250 }
11251 break;
11252 }
11253 case NODE_FILE:
11254 case NODE_STR:{
11255 debugp_param("nd_lit", get_string_value(node));
11256 if (!popped) {
11257 VALUE lit = get_string_value(node);
11258 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11259 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11260 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11261 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11262 RB_OBJ_SET_SHAREABLE(lit);
11263 }
11264 switch (option->frozen_string_literal) {
11265 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11266 ADD_INSN1(ret, node, putchilledstring, lit);
11267 break;
11268 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11269 ADD_INSN1(ret, node, putstring, lit);
11270 break;
11271 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11272 ADD_INSN1(ret, node, putobject, lit);
11273 break;
11274 default:
11275 rb_bug("invalid frozen_string_literal");
11276 }
11277 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11278 }
11279 break;
11280 }
11281 case NODE_DSTR:{
11282 compile_dstr(iseq, ret, node);
11283
11284 if (popped) {
11285 ADD_INSN(ret, node, pop);
11286 }
11287 break;
11288 }
11289 case NODE_XSTR:{
11290 ADD_CALL_RECEIVER(ret, node);
11291 VALUE str = rb_node_str_string_val(node);
11292 ADD_INSN1(ret, node, putobject, str);
11293 RB_OBJ_WRITTEN(iseq, Qundef, str);
11294 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11295
11296 if (popped) {
11297 ADD_INSN(ret, node, pop);
11298 }
11299 break;
11300 }
11301 case NODE_DXSTR:{
11302 ADD_CALL_RECEIVER(ret, node);
11303 compile_dstr(iseq, ret, node);
11304 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11305
11306 if (popped) {
11307 ADD_INSN(ret, node, pop);
11308 }
11309 break;
11310 }
11311 case NODE_EVSTR:
11312 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11313 break;
11314 case NODE_REGX:{
11315 if (!popped) {
11316 VALUE lit = rb_node_regx_string_val(node);
11317 RB_OBJ_SET_SHAREABLE(lit);
11318 ADD_INSN1(ret, node, putobject, lit);
11319 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11320 }
11321 break;
11322 }
11323 case NODE_DREGX:
11324 compile_dregx(iseq, ret, node, popped);
11325 break;
11326 case NODE_ONCE:{
11327 int ic_index = body->ise_size++;
11328 const rb_iseq_t *block_iseq;
11329 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11330
11331 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11332 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11333
11334 if (popped) {
11335 ADD_INSN(ret, node, pop);
11336 }
11337 break;
11338 }
11339 case NODE_ARGSCAT:{
11340 if (popped) {
11341 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11342 ADD_INSN1(ret, node, splatarray, Qfalse);
11343 ADD_INSN(ret, node, pop);
11344 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11345 ADD_INSN1(ret, node, splatarray, Qfalse);
11346 ADD_INSN(ret, node, pop);
11347 }
11348 else {
11349 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11350 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11351 if (nd_type_p(body_node, NODE_LIST)) {
11352 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11353 }
11354 else {
11355 CHECK(COMPILE(ret, "argscat body", body_node));
11356 ADD_INSN(ret, node, concattoarray);
11357 }
11358 }
11359 break;
11360 }
11361 case NODE_ARGSPUSH:{
11362 if (popped) {
11363 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11364 ADD_INSN1(ret, node, splatarray, Qfalse);
11365 ADD_INSN(ret, node, pop);
11366 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11367 }
11368 else {
11369 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11370 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11371 if (keyword_node_p(body_node)) {
11372 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11373 ADD_INSN(ret, node, pushtoarraykwsplat);
11374 }
11375 else if (static_literal_node_p(body_node, iseq, false)) {
11376 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11377 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11378 }
11379 else {
11380 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11381 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11382 }
11383 }
11384 break;
11385 }
11386 case NODE_SPLAT:{
11387 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11388 ADD_INSN1(ret, node, splatarray, Qtrue);
11389
11390 if (popped) {
11391 ADD_INSN(ret, node, pop);
11392 }
11393 break;
11394 }
11395 case NODE_DEFN:{
11396 ID mid = RNODE_DEFN(node)->nd_mid;
11397 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11398 rb_id2str(mid),
11399 ISEQ_TYPE_METHOD, line);
11400
11401 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11402 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11403 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11404
11405 if (!popped) {
11406 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11407 }
11408
11409 break;
11410 }
11411 case NODE_DEFS:{
11412 ID mid = RNODE_DEFS(node)->nd_mid;
11413 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11414 rb_id2str(mid),
11415 ISEQ_TYPE_METHOD, line);
11416
11417 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11418 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11419 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11420 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11421
11422 if (!popped) {
11423 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11424 }
11425 break;
11426 }
11427 case NODE_ALIAS:{
11428 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11429 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11430 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11431 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11432 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11433
11434 if (popped) {
11435 ADD_INSN(ret, node, pop);
11436 }
11437 break;
11438 }
11439 case NODE_VALIAS:{
11440 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11441 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11442 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11443 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11444
11445 if (popped) {
11446 ADD_INSN(ret, node, pop);
11447 }
11448 break;
11449 }
11450 case NODE_UNDEF:{
11451 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11452
11453 for (long i = 0; i < ary->len; i++) {
11454 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11455 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11456 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11457 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11458
11459 if (i < ary->len - 1) {
11460 ADD_INSN(ret, node, pop);
11461 }
11462 }
11463
11464 if (popped) {
11465 ADD_INSN(ret, node, pop);
11466 }
11467 break;
11468 }
11469 case NODE_CLASS:{
11470 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11471 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11472 ISEQ_TYPE_CLASS, line);
11473 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11474 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11475 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11476
11477 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11478 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11479 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11480
11481 if (popped) {
11482 ADD_INSN(ret, node, pop);
11483 }
11484 break;
11485 }
11486 case NODE_MODULE:{
11487 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11488 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11489 ISEQ_TYPE_CLASS, line);
11490 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11491 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11492
11493 ADD_INSN (ret, node, putnil); /* dummy */
11494 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11495 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11496
11497 if (popped) {
11498 ADD_INSN(ret, node, pop);
11499 }
11500 break;
11501 }
11502 case NODE_SCLASS:{
11503 ID singletonclass;
11504 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11505 ISEQ_TYPE_CLASS, line);
11506
11507 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11508 ADD_INSN (ret, node, putnil);
11509 CONST_ID(singletonclass, "singletonclass");
11510 ADD_INSN3(ret, node, defineclass,
11511 ID2SYM(singletonclass), singleton_class,
11512 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11513 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11514
11515 if (popped) {
11516 ADD_INSN(ret, node, pop);
11517 }
11518 break;
11519 }
11520 case NODE_COLON2:
11521 CHECK(compile_colon2(iseq, ret, node, popped));
11522 break;
11523 case NODE_COLON3:
11524 CHECK(compile_colon3(iseq, ret, node, popped));
11525 break;
11526 case NODE_DOT2:
11527 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11528 break;
11529 case NODE_DOT3:
11530 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11531 break;
11532 case NODE_FLIP2:
11533 case NODE_FLIP3:{
11534 LABEL *lend = NEW_LABEL(line);
11535 LABEL *ltrue = NEW_LABEL(line);
11536 LABEL *lfalse = NEW_LABEL(line);
11537 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11538 ltrue, lfalse));
11539 ADD_LABEL(ret, ltrue);
11540 ADD_INSN1(ret, node, putobject, Qtrue);
11541 ADD_INSNL(ret, node, jump, lend);
11542 ADD_LABEL(ret, lfalse);
11543 ADD_INSN1(ret, node, putobject, Qfalse);
11544 ADD_LABEL(ret, lend);
11545 break;
11546 }
11547 case NODE_SELF:{
11548 if (!popped) {
11549 ADD_INSN(ret, node, putself);
11550 }
11551 break;
11552 }
11553 case NODE_NIL:{
11554 if (!popped) {
11555 ADD_INSN(ret, node, putnil);
11556 }
11557 break;
11558 }
11559 case NODE_TRUE:{
11560 if (!popped) {
11561 ADD_INSN1(ret, node, putobject, Qtrue);
11562 }
11563 break;
11564 }
11565 case NODE_FALSE:{
11566 if (!popped) {
11567 ADD_INSN1(ret, node, putobject, Qfalse);
11568 }
11569 break;
11570 }
11571 case NODE_ERRINFO:
11572 CHECK(compile_errinfo(iseq, ret, node, popped));
11573 break;
11574 case NODE_DEFINED:
11575 if (!popped) {
11576 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11577 }
11578 break;
11579 case NODE_POSTEXE:{
11580 /* compiled to:
11581 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11582 */
11583 int is_index = body->ise_size++;
11585 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11586 const rb_iseq_t *once_iseq =
11587 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11588
11589 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11590 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11591
11592 if (popped) {
11593 ADD_INSN(ret, node, pop);
11594 }
11595 break;
11596 }
11597 case NODE_KW_ARG:
11598 CHECK(compile_kw_arg(iseq, ret, node, popped));
11599 break;
11600 case NODE_DSYM:{
11601 compile_dstr(iseq, ret, node);
11602 if (!popped) {
11603 ADD_INSN(ret, node, intern);
11604 }
11605 else {
11606 ADD_INSN(ret, node, pop);
11607 }
11608 break;
11609 }
11610 case NODE_ATTRASGN:
11611 CHECK(compile_attrasgn(iseq, ret, node, popped));
11612 break;
11613 case NODE_LAMBDA:{
11614 /* compile same as lambda{...} */
11615 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11616 VALUE argc = INT2FIX(0);
11617
11618 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11619 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11620 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11621
11622 if (popped) {
11623 ADD_INSN(ret, node, pop);
11624 }
11625 break;
11626 }
11627 default:
11628 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11629 ng:
11630 debug_node_end();
11631 return COMPILE_NG;
11632 }
11633
11634 debug_node_end();
11635 return COMPILE_OK;
11636}
11637
11638/***************************/
11639/* instruction information */
11640/***************************/
11641
11642static int
11643insn_data_length(INSN *iobj)
11644{
11645 return insn_len(iobj->insn_id);
11646}
11647
11648static int
11649calc_sp_depth(int depth, INSN *insn)
11650{
11651 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11652}
11653
11654static VALUE
11655opobj_inspect(VALUE obj)
11656{
11657 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11658 switch (BUILTIN_TYPE(obj)) {
11659 case T_STRING:
11660 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11661 break;
11662 case T_ARRAY:
11663 obj = rb_ary_dup(obj);
11664 break;
11665 default:
11666 break;
11667 }
11668 }
11669 return rb_inspect(obj);
11670}
11671
11672
11673
11674static VALUE
11675insn_data_to_s_detail(INSN *iobj)
11676{
11677 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11678
11679 if (iobj->operands) {
11680 const char *types = insn_op_types(iobj->insn_id);
11681 int j;
11682
11683 for (j = 0; types[j]; j++) {
11684 char type = types[j];
11685
11686 switch (type) {
11687 case TS_OFFSET: /* label(destination position) */
11688 {
11689 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11690 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11691 break;
11692 }
11693 break;
11694 case TS_ISEQ: /* iseq */
11695 {
11696 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11697 VALUE val = Qnil;
11698 if (0 && iseq) { /* TODO: invalidate now */
11699 val = (VALUE)iseq;
11700 }
11701 rb_str_concat(str, opobj_inspect(val));
11702 }
11703 break;
11704 case TS_LINDEX:
11705 case TS_NUM: /* ulong */
11706 case TS_VALUE: /* VALUE */
11707 {
11708 VALUE v = OPERAND_AT(iobj, j);
11709 if (!CLASS_OF(v))
11710 rb_str_cat2(str, "<hidden>");
11711 else {
11712 rb_str_concat(str, opobj_inspect(v));
11713 }
11714 break;
11715 }
11716 case TS_ID: /* ID */
11717 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11718 break;
11719 case TS_IC: /* inline cache */
11720 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11721 break;
11722 case TS_IVC: /* inline ivar cache */
11723 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11724 break;
11725 case TS_ICVARC: /* inline cvar cache */
11726 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11727 break;
11728 case TS_ISE: /* inline storage entry */
11729 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11730 break;
11731 case TS_CALLDATA: /* we store these as call infos at compile time */
11732 {
11733 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11734 rb_str_cat2(str, "<calldata:");
11735 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11736 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11737 break;
11738 }
11739 case TS_CDHASH: /* case/when condition cache */
11740 rb_str_cat2(str, "<ch>");
11741 break;
11742 case TS_FUNCPTR:
11743 {
11744 void *func = (void *)OPERAND_AT(iobj, j);
11745#ifdef HAVE_DLADDR
11746 Dl_info info;
11747 if (dladdr(func, &info) && info.dli_sname) {
11748 rb_str_cat2(str, info.dli_sname);
11749 break;
11750 }
11751#endif
11752 rb_str_catf(str, "<%p>", func);
11753 }
11754 break;
11755 case TS_BUILTIN:
11756 rb_str_cat2(str, "<TS_BUILTIN>");
11757 break;
11758 default:{
11759 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11760 }
11761 }
11762 if (types[j + 1]) {
11763 rb_str_cat2(str, ", ");
11764 }
11765 }
11766 }
11767 return str;
11768}
11769
11770static void
11771dump_disasm_list(const LINK_ELEMENT *link)
11772{
11773 dump_disasm_list_with_cursor(link, NULL, NULL);
11774}
11775
11776static void
11777dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11778{
11779 int pos = 0;
11780 INSN *iobj;
11781 LABEL *lobj;
11782 VALUE str;
11783
11784 printf("-- raw disasm--------\n");
11785
11786 while (link) {
11787 if (curr) printf(curr == link ? "*" : " ");
11788 switch (link->type) {
11789 case ISEQ_ELEMENT_INSN:
11790 {
11791 iobj = (INSN *)link;
11792 str = insn_data_to_s_detail(iobj);
11793 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11794 pos += insn_data_length(iobj);
11795 break;
11796 }
11797 case ISEQ_ELEMENT_LABEL:
11798 {
11799 lobj = (LABEL *)link;
11800 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11801 dest == lobj ? " <---" : "");
11802 break;
11803 }
11804 case ISEQ_ELEMENT_TRACE:
11805 {
11806 TRACE *trace = (TRACE *)link;
11807 printf(" trace: %0x\n", trace->event);
11808 break;
11809 }
11810 case ISEQ_ELEMENT_ADJUST:
11811 {
11812 ADJUST *adjust = (ADJUST *)link;
11813 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11814 break;
11815 }
11816 default:
11817 /* ignore */
11818 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11819 }
11820 link = link->next;
11821 }
11822 printf("---------------------\n");
11823 fflush(stdout);
11824}
11825
11826int
11827rb_insn_len(VALUE insn)
11828{
11829 return insn_len(insn);
11830}
11831
11832const char *
11833rb_insns_name(int i)
11834{
11835 return insn_name(i);
11836}
11837
11838VALUE
11839rb_insns_name_array(void)
11840{
11841 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11842 int i;
11843 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11844 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11845 }
11846 return rb_ary_freeze(ary);
11847}
11848
11849static LABEL *
11850register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11851{
11852 LABEL *label = 0;
11853 st_data_t tmp;
11854 obj = rb_to_symbol_type(obj);
11855
11856 if (st_lookup(labels_table, obj, &tmp) == 0) {
11857 label = NEW_LABEL(0);
11858 st_insert(labels_table, obj, (st_data_t)label);
11859 }
11860 else {
11861 label = (LABEL *)tmp;
11862 }
11863 LABEL_REF(label);
11864 return label;
11865}
11866
11867static VALUE
11868get_exception_sym2type(VALUE sym)
11869{
11870 static VALUE symRescue, symEnsure, symRetry;
11871 static VALUE symBreak, symRedo, symNext;
11872
11873 if (symRescue == 0) {
11874 symRescue = ID2SYM(rb_intern_const("rescue"));
11875 symEnsure = ID2SYM(rb_intern_const("ensure"));
11876 symRetry = ID2SYM(rb_intern_const("retry"));
11877 symBreak = ID2SYM(rb_intern_const("break"));
11878 symRedo = ID2SYM(rb_intern_const("redo"));
11879 symNext = ID2SYM(rb_intern_const("next"));
11880 }
11881
11882 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11883 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11884 if (sym == symRetry) return CATCH_TYPE_RETRY;
11885 if (sym == symBreak) return CATCH_TYPE_BREAK;
11886 if (sym == symRedo) return CATCH_TYPE_REDO;
11887 if (sym == symNext) return CATCH_TYPE_NEXT;
11888 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11889 return 0;
11890}
11891
11892static int
11893iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11894 VALUE exception)
11895{
11896 int i;
11897
11898 for (i=0; i<RARRAY_LEN(exception); i++) {
11899 const rb_iseq_t *eiseq;
11900 VALUE v, type;
11901 LABEL *lstart, *lend, *lcont;
11902 unsigned int sp;
11903
11904 v = rb_to_array_type(RARRAY_AREF(exception, i));
11905 if (RARRAY_LEN(v) != 6) {
11906 rb_raise(rb_eSyntaxError, "wrong exception entry");
11907 }
11908 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11909 if (NIL_P(RARRAY_AREF(v, 1))) {
11910 eiseq = NULL;
11911 }
11912 else {
11913 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11914 }
11915
11916 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11917 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11918 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11919 sp = NUM2UINT(RARRAY_AREF(v, 5));
11920
11921 /* TODO: Dirty Hack! Fix me */
11922 if (type == CATCH_TYPE_RESCUE ||
11923 type == CATCH_TYPE_BREAK ||
11924 type == CATCH_TYPE_NEXT) {
11925 ++sp;
11926 }
11927
11928 lcont->sp = sp;
11929
11930 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11931
11932 RB_GC_GUARD(v);
11933 }
11934 return COMPILE_OK;
11935}
11936
11937static struct st_table *
11938insn_make_insn_table(void)
11939{
11940 struct st_table *table;
11941 int i;
11942 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11943
11944 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11945 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11946 }
11947
11948 return table;
11949}
11950
11951static const rb_iseq_t *
11952iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11953{
11954 VALUE iseqw;
11955 const rb_iseq_t *loaded_iseq;
11956
11957 if (RB_TYPE_P(op, T_ARRAY)) {
11958 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11959 }
11960 else if (CLASS_OF(op) == rb_cISeq) {
11961 iseqw = op;
11962 }
11963 else {
11964 rb_raise(rb_eSyntaxError, "ISEQ is required");
11965 }
11966
11967 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11968 return loaded_iseq;
11969}
11970
11971static VALUE
11972iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11973{
11974 ID mid = 0;
11975 int orig_argc = 0;
11976 unsigned int flag = 0;
11977 struct rb_callinfo_kwarg *kw_arg = 0;
11978
11979 if (!NIL_P(op)) {
11980 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11981 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11982 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11983 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11984
11985 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11986 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11987 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11988
11989 if (!NIL_P(vkw_arg)) {
11990 int i;
11991 int len = RARRAY_LENINT(vkw_arg);
11992 size_t n = rb_callinfo_kwarg_bytes(len);
11993
11994 kw_arg = xmalloc(n);
11995 kw_arg->references = 0;
11996 kw_arg->keyword_len = len;
11997 for (i = 0; i < len; i++) {
11998 VALUE kw = RARRAY_AREF(vkw_arg, i);
11999 SYM2ID(kw); /* make immortal */
12000 kw_arg->keywords[i] = kw;
12001 }
12002 }
12003 }
12004
12005 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12006 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12007 return (VALUE)ci;
12008}
12009
12010static rb_event_flag_t
12011event_name_to_flag(VALUE sym)
12012{
12013#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12014 CHECK_EVENT(RUBY_EVENT_LINE);
12015 CHECK_EVENT(RUBY_EVENT_CLASS);
12016 CHECK_EVENT(RUBY_EVENT_END);
12017 CHECK_EVENT(RUBY_EVENT_CALL);
12018 CHECK_EVENT(RUBY_EVENT_RETURN);
12019 CHECK_EVENT(RUBY_EVENT_B_CALL);
12020 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12021 CHECK_EVENT(RUBY_EVENT_RESCUE);
12022#undef CHECK_EVENT
12023 return RUBY_EVENT_NONE;
12024}
12025
12026static int
12027iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12028 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12029{
12030 /* TODO: body should be frozen */
12031 long i, len = RARRAY_LEN(body);
12032 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12033 int j;
12034 int line_no = 0, node_id = -1, insn_idx = 0;
12035 int ret = COMPILE_OK;
12036
12037 /*
12038 * index -> LABEL *label
12039 */
12040 static struct st_table *insn_table;
12041
12042 if (insn_table == 0) {
12043 insn_table = insn_make_insn_table();
12044 }
12045
12046 for (i=0; i<len; i++) {
12047 VALUE obj = RARRAY_AREF(body, i);
12048
12049 if (SYMBOL_P(obj)) {
12050 rb_event_flag_t event;
12051 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12052 ADD_TRACE(anchor, event);
12053 }
12054 else {
12055 LABEL *label = register_label(iseq, labels_table, obj);
12056 ADD_LABEL(anchor, label);
12057 }
12058 }
12059 else if (FIXNUM_P(obj)) {
12060 line_no = NUM2INT(obj);
12061 }
12062 else if (RB_TYPE_P(obj, T_ARRAY)) {
12063 VALUE *argv = 0;
12064 int argc = RARRAY_LENINT(obj) - 1;
12065 st_data_t insn_id;
12066 VALUE insn;
12067
12068 if (node_ids) {
12069 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12070 }
12071
12072 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12073 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12074 /* TODO: exception */
12075 COMPILE_ERROR(iseq, line_no,
12076 "unknown instruction: %+"PRIsVALUE, insn);
12077 ret = COMPILE_NG;
12078 break;
12079 }
12080
12081 if (argc != insn_len((VALUE)insn_id)-1) {
12082 COMPILE_ERROR(iseq, line_no,
12083 "operand size mismatch");
12084 ret = COMPILE_NG;
12085 break;
12086 }
12087
12088 if (argc > 0) {
12089 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12090
12091 // add element before operand setup to make GC root
12092 ADD_ELEM(anchor,
12093 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12094 (enum ruby_vminsn_type)insn_id, argc, argv));
12095
12096 for (j=0; j<argc; j++) {
12097 VALUE op = rb_ary_entry(obj, j+1);
12098 switch (insn_op_type((VALUE)insn_id, j)) {
12099 case TS_OFFSET: {
12100 LABEL *label = register_label(iseq, labels_table, op);
12101 argv[j] = (VALUE)label;
12102 break;
12103 }
12104 case TS_LINDEX:
12105 case TS_NUM:
12106 (void)NUM2INT(op);
12107 argv[j] = op;
12108 break;
12109 case TS_VALUE:
12110 argv[j] = op;
12111 RB_OBJ_WRITTEN(iseq, Qundef, op);
12112 break;
12113 case TS_ISEQ:
12114 {
12115 if (op != Qnil) {
12116 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12117 argv[j] = v;
12118 RB_OBJ_WRITTEN(iseq, Qundef, v);
12119 }
12120 else {
12121 argv[j] = 0;
12122 }
12123 }
12124 break;
12125 case TS_ISE:
12126 argv[j] = op;
12127 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12128 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12129 }
12130 break;
12131 case TS_IC:
12132 {
12133 VALUE segments = rb_ary_new();
12134 op = rb_to_array_type(op);
12135
12136 for (int i = 0; i < RARRAY_LEN(op); i++) {
12137 VALUE sym = RARRAY_AREF(op, i);
12138 sym = rb_to_symbol_type(sym);
12139 rb_ary_push(segments, sym);
12140 }
12141
12142 RB_GC_GUARD(op);
12143 argv[j] = segments;
12144 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12145 ISEQ_BODY(iseq)->ic_size++;
12146 }
12147 break;
12148 case TS_IVC: /* inline ivar cache */
12149 argv[j] = op;
12150 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12151 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12152 }
12153 break;
12154 case TS_ICVARC: /* inline cvar cache */
12155 argv[j] = op;
12156 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12157 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12158 }
12159 break;
12160 case TS_CALLDATA:
12161 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12162 break;
12163 case TS_ID:
12164 argv[j] = rb_to_symbol_type(op);
12165 break;
12166 case TS_CDHASH:
12167 {
12168 int i;
12169 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12170
12171 RHASH_TBL_RAW(map)->type = &cdhash_type;
12172 op = rb_to_array_type(op);
12173 for (i=0; i<RARRAY_LEN(op); i+=2) {
12174 VALUE key = RARRAY_AREF(op, i);
12175 VALUE sym = RARRAY_AREF(op, i+1);
12176 LABEL *label =
12177 register_label(iseq, labels_table, sym);
12178 rb_hash_aset(map, key, (VALUE)label | 1);
12179 }
12180 RB_GC_GUARD(op);
12181 RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
12182 argv[j] = map;
12183 RB_OBJ_WRITTEN(iseq, Qundef, map);
12184 }
12185 break;
12186 case TS_FUNCPTR:
12187 {
12188#if SIZEOF_VALUE <= SIZEOF_LONG
12189 long funcptr = NUM2LONG(op);
12190#else
12191 LONG_LONG funcptr = NUM2LL(op);
12192#endif
12193 argv[j] = (VALUE)funcptr;
12194 }
12195 break;
12196 default:
12197 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12198 }
12199 }
12200 }
12201 else {
12202 ADD_ELEM(anchor,
12203 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12204 (enum ruby_vminsn_type)insn_id, argc, NULL));
12205 }
12206 }
12207 else {
12208 rb_raise(rb_eTypeError, "unexpected object for instruction");
12209 }
12210 }
12211 RTYPEDDATA_DATA(labels_wrapper) = 0;
12212 RB_GC_GUARD(labels_wrapper);
12213 validate_labels(iseq, labels_table);
12214 if (!ret) return ret;
12215 return iseq_setup(iseq, anchor);
12216}
12217
12218#define CHECK_ARRAY(v) rb_to_array_type(v)
12219#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12220
12221static int
12222int_param(int *dst, VALUE param, VALUE sym)
12223{
12224 VALUE val = rb_hash_aref(param, sym);
12225 if (FIXNUM_P(val)) {
12226 *dst = FIX2INT(val);
12227 return TRUE;
12228 }
12229 else if (!NIL_P(val)) {
12230 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12231 sym, val);
12232 }
12233 return FALSE;
12234}
12235
12236static const struct rb_iseq_param_keyword *
12237iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12238{
12239 int i, j;
12240 int len = RARRAY_LENINT(keywords);
12241 int default_len;
12242 VALUE key, sym, default_val;
12243 VALUE *dvs;
12244 ID *ids;
12245 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12246
12247 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12248
12249 keyword->num = len;
12250#define SYM(s) ID2SYM(rb_intern_const(#s))
12251 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12252 i = keyword->bits_start - keyword->num;
12253 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12254#undef SYM
12255
12256 /* required args */
12257 for (i = 0; i < len; i++) {
12258 VALUE val = RARRAY_AREF(keywords, i);
12259
12260 if (!SYMBOL_P(val)) {
12261 goto default_values;
12262 }
12263 ids[i] = SYM2ID(val);
12264 keyword->required_num++;
12265 }
12266
12267 default_values: /* note: we intentionally preserve `i' from previous loop */
12268 default_len = len - i;
12269 if (default_len == 0) {
12270 keyword->table = ids;
12271 return keyword;
12272 }
12273 else if (default_len < 0) {
12275 }
12276
12277 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12278
12279 for (j = 0; i < len; i++, j++) {
12280 key = RARRAY_AREF(keywords, i);
12281 CHECK_ARRAY(key);
12282
12283 switch (RARRAY_LEN(key)) {
12284 case 1:
12285 sym = RARRAY_AREF(key, 0);
12286 default_val = Qundef;
12287 break;
12288 case 2:
12289 sym = RARRAY_AREF(key, 0);
12290 default_val = RARRAY_AREF(key, 1);
12291 break;
12292 default:
12293 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12294 }
12295 ids[i] = SYM2ID(sym);
12296 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12297 }
12298
12299 keyword->table = ids;
12300 keyword->default_values = dvs;
12301
12302 return keyword;
12303}
12304
12305static void
12306iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12307{
12308 rb_gc_mark_and_move(obj);
12309}
12310
12311void
12312rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12313{
12314 INSN *iobj = 0;
12315 size_t size = sizeof(INSN);
12316 unsigned int pos = 0;
12317
12318 while (storage) {
12319#ifdef STRICT_ALIGNMENT
12320 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12321#else
12322 const size_t padding = 0; /* expected to be optimized by compiler */
12323#endif /* STRICT_ALIGNMENT */
12324 size_t offset = pos + size + padding;
12325 if (offset > storage->size || offset > storage->pos) {
12326 pos = 0;
12327 storage = storage->next;
12328 }
12329 else {
12330#ifdef STRICT_ALIGNMENT
12331 pos += (int)padding;
12332#endif /* STRICT_ALIGNMENT */
12333
12334 iobj = (INSN *)&storage->buff[pos];
12335
12336 if (iobj->operands) {
12337 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12338 }
12339 pos += (int)size;
12340 }
12341 }
12342}
12343
12344static const rb_data_type_t labels_wrapper_type = {
12345 .wrap_struct_name = "compiler/labels_wrapper",
12346 .function = {
12347 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12348 .dfree = (RUBY_DATA_FUNC)st_free_table,
12349 },
12350 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12351};
12352
12353void
12354rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12355 VALUE exception, VALUE body)
12356{
12357#define SYM(s) ID2SYM(rb_intern_const(#s))
12358 int i, len;
12359 unsigned int arg_size, local_size, stack_max;
12360 ID *tbl;
12361 struct st_table *labels_table = st_init_numtable();
12362 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12363 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12364 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12365 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12366 DECL_ANCHOR(anchor);
12367 INIT_ANCHOR(anchor);
12368
12369 len = RARRAY_LENINT(locals);
12370 ISEQ_BODY(iseq)->local_table_size = len;
12371 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12372
12373 for (i = 0; i < len; i++) {
12374 VALUE lv = RARRAY_AREF(locals, i);
12375
12376 if (sym_arg_rest == lv) {
12377 tbl[i] = 0;
12378 }
12379 else {
12380 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12381 }
12382 }
12383
12384#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12385 if (INT_PARAM(lead_num)) {
12386 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12387 }
12388 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12389 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12390 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12391 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12392#undef INT_PARAM
12393 {
12394#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12395 int x;
12396 INT_PARAM(arg_size);
12397 INT_PARAM(local_size);
12398 INT_PARAM(stack_max);
12399#undef INT_PARAM
12400 }
12401
12402 VALUE node_ids = Qfalse;
12403#ifdef USE_ISEQ_NODE_ID
12404 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12405 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12406 rb_raise(rb_eTypeError, "node_ids is not an array");
12407 }
12408#endif
12409
12410 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12411 len = RARRAY_LENINT(arg_opt_labels);
12412 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12413
12414 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12415 VALUE *opt_table = ALLOC_N(VALUE, len);
12416
12417 for (i = 0; i < len; i++) {
12418 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12419 LABEL *label = register_label(iseq, labels_table, ent);
12420 opt_table[i] = (VALUE)label;
12421 }
12422
12423 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12424 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12425 }
12426 }
12427 else if (!NIL_P(arg_opt_labels)) {
12428 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12429 arg_opt_labels);
12430 }
12431
12432 if (RB_TYPE_P(keywords, T_ARRAY)) {
12433 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12434 }
12435 else if (!NIL_P(keywords)) {
12436 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12437 keywords);
12438 }
12439
12440 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12441 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12442 }
12443
12444 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12445 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12446 }
12447
12448 if (int_param(&i, params, SYM(kwrest))) {
12449 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12450 if (keyword == NULL) {
12451 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12452 }
12453 keyword->rest_start = i;
12454 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12455 }
12456#undef SYM
12457 iseq_calc_param_size(iseq);
12458
12459 /* exception */
12460 iseq_build_from_ary_exception(iseq, labels_table, exception);
12461
12462 /* body */
12463 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12464
12465 ISEQ_BODY(iseq)->param.size = arg_size;
12466 ISEQ_BODY(iseq)->local_table_size = local_size;
12467 ISEQ_BODY(iseq)->stack_max = stack_max;
12468}
12469
12470/* for parser */
12471
12472int
12473rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12474{
12475 if (iseq) {
12476 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12477 while (body->type == ISEQ_TYPE_BLOCK ||
12478 body->type == ISEQ_TYPE_RESCUE ||
12479 body->type == ISEQ_TYPE_ENSURE ||
12480 body->type == ISEQ_TYPE_EVAL ||
12481 body->type == ISEQ_TYPE_MAIN
12482 ) {
12483 unsigned int i;
12484
12485 for (i = 0; i < body->local_table_size; i++) {
12486 if (body->local_table[i] == id) {
12487 return 1;
12488 }
12489 }
12490 iseq = body->parent_iseq;
12491 body = ISEQ_BODY(iseq);
12492 }
12493 }
12494 return 0;
12495}
12496
12497int
12498rb_local_defined(ID id, const rb_iseq_t *iseq)
12499{
12500 if (iseq) {
12501 unsigned int i;
12502 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12503
12504 for (i=0; i<body->local_table_size; i++) {
12505 if (body->local_table[i] == id) {
12506 return 1;
12507 }
12508 }
12509 }
12510 return 0;
12511}
12512
12513/* ISeq binary format */
12514
12515#ifndef IBF_ISEQ_DEBUG
12516#define IBF_ISEQ_DEBUG 0
12517#endif
12518
12519#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12520#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12521#endif
12522
12523typedef uint32_t ibf_offset_t;
12524#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12525
12526#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12527#ifdef RUBY_DEVEL
12528#define IBF_DEVEL_VERSION 5
12529#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12530#else
12531#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12532#endif
12533
12534static const char IBF_ENDIAN_MARK =
12535#ifdef WORDS_BIGENDIAN
12536 'b'
12537#else
12538 'l'
12539#endif
12540 ;
12541
12543 char magic[4]; /* YARB */
12544 uint32_t major_version;
12545 uint32_t minor_version;
12546 uint32_t size;
12547 uint32_t extra_size;
12548
12549 uint32_t iseq_list_size;
12550 uint32_t global_object_list_size;
12551 ibf_offset_t iseq_list_offset;
12552 ibf_offset_t global_object_list_offset;
12553 uint8_t endian;
12554 uint8_t wordsize; /* assume no 2048-bit CPU */
12555};
12556
12558 VALUE str;
12559 st_table *obj_table; /* obj -> obj number */
12560};
12561
12562struct ibf_dump {
12563 st_table *iseq_table; /* iseq -> iseq number */
12564 struct ibf_dump_buffer global_buffer;
12565 struct ibf_dump_buffer *current_buffer;
12566};
12567
12569 const char *buff;
12570 ibf_offset_t size;
12571
12572 VALUE obj_list; /* [obj0, ...] */
12573 unsigned int obj_list_size;
12574 ibf_offset_t obj_list_offset;
12575};
12576
12577struct ibf_load {
12578 const struct ibf_header *header;
12579 VALUE iseq_list; /* [iseq0, ...] */
12580 struct ibf_load_buffer global_buffer;
12581 VALUE loader_obj;
12582 rb_iseq_t *iseq;
12583 VALUE str;
12584 struct ibf_load_buffer *current_buffer;
12585};
12586
12588 long size;
12589 VALUE buffer[1];
12590};
12591
12592static void
12593pinned_list_mark(void *ptr)
12594{
12595 long i;
12596 struct pinned_list *list = (struct pinned_list *)ptr;
12597 for (i = 0; i < list->size; i++) {
12598 if (list->buffer[i]) {
12599 rb_gc_mark(list->buffer[i]);
12600 }
12601 }
12602}
12603
12604static const rb_data_type_t pinned_list_type = {
12605 "pinned_list",
12606 {
12607 pinned_list_mark,
12609 NULL, // No external memory to report,
12610 },
12611 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12612};
12613
12614static VALUE
12615pinned_list_fetch(VALUE list, long offset)
12616{
12617 struct pinned_list * ptr;
12618
12619 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12620
12621 if (offset >= ptr->size) {
12622 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12623 }
12624
12625 return ptr->buffer[offset];
12626}
12627
12628static void
12629pinned_list_store(VALUE list, long offset, VALUE object)
12630{
12631 struct pinned_list * ptr;
12632
12633 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12634
12635 if (offset >= ptr->size) {
12636 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12637 }
12638
12639 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12640}
12641
12642static VALUE
12643pinned_list_new(long size)
12644{
12645 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12646 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12647 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12648 ptr->size = size;
12649 return obj_list;
12650}
12651
12652static ibf_offset_t
12653ibf_dump_pos(struct ibf_dump *dump)
12654{
12655 long pos = RSTRING_LEN(dump->current_buffer->str);
12656#if SIZEOF_LONG > SIZEOF_INT
12657 if (pos >= UINT_MAX) {
12658 rb_raise(rb_eRuntimeError, "dump size exceeds");
12659 }
12660#endif
12661 return (unsigned int)pos;
12662}
12663
12664static void
12665ibf_dump_align(struct ibf_dump *dump, size_t align)
12666{
12667 ibf_offset_t pos = ibf_dump_pos(dump);
12668 if (pos % align) {
12669 static const char padding[sizeof(VALUE)];
12670 size_t size = align - ((size_t)pos % align);
12671#if SIZEOF_LONG > SIZEOF_INT
12672 if (pos + size >= UINT_MAX) {
12673 rb_raise(rb_eRuntimeError, "dump size exceeds");
12674 }
12675#endif
12676 for (; size > sizeof(padding); size -= sizeof(padding)) {
12677 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12678 }
12679 rb_str_cat(dump->current_buffer->str, padding, size);
12680 }
12681}
12682
12683static ibf_offset_t
12684ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12685{
12686 ibf_offset_t pos = ibf_dump_pos(dump);
12687#if SIZEOF_LONG > SIZEOF_INT
12688 /* ensure the resulting dump does not exceed UINT_MAX */
12689 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12690 rb_raise(rb_eRuntimeError, "dump size exceeds");
12691 }
12692#endif
12693 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12694 return pos;
12695}
12696
12697static ibf_offset_t
12698ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12699{
12700 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12701}
12702
12703static void
12704ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12705{
12706 VALUE str = dump->current_buffer->str;
12707 char *ptr = RSTRING_PTR(str);
12708 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12709 rb_bug("ibf_dump_overwrite: overflow");
12710 memcpy(ptr + offset, buff, size);
12711}
12712
12713static const void *
12714ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12715{
12716 ibf_offset_t beg = *offset;
12717 *offset += size;
12718 return load->current_buffer->buff + beg;
12719}
12720
12721static void *
12722ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12723{
12724 void *buff = ruby_xmalloc2(x, y);
12725 size_t size = x * y;
12726 memcpy(buff, load->current_buffer->buff + offset, size);
12727 return buff;
12728}
12729
12730#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12731
12732#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12733#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12734#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12735#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12736#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12737
12738static int
12739ibf_table_lookup(struct st_table *table, st_data_t key)
12740{
12741 st_data_t val;
12742
12743 if (st_lookup(table, key, &val)) {
12744 return (int)val;
12745 }
12746 else {
12747 return -1;
12748 }
12749}
12750
12751static int
12752ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12753{
12754 int index = ibf_table_lookup(table, key);
12755
12756 if (index < 0) { /* not found */
12757 index = (int)table->num_entries;
12758 st_insert(table, key, (st_data_t)index);
12759 }
12760
12761 return index;
12762}
12763
12764/* dump/load generic */
12765
12766static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12767
12768static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12769static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12770
12771static st_table *
12772ibf_dump_object_table_new(void)
12773{
12774 st_table *obj_table = st_init_numtable(); /* need free */
12775 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12776
12777 return obj_table;
12778}
12779
12780static VALUE
12781ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12782{
12783 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12784}
12785
12786static VALUE
12787ibf_dump_id(struct ibf_dump *dump, ID id)
12788{
12789 if (id == 0 || rb_id2name(id) == NULL) {
12790 return 0;
12791 }
12792 return ibf_dump_object(dump, rb_id2sym(id));
12793}
12794
12795static ID
12796ibf_load_id(const struct ibf_load *load, const ID id_index)
12797{
12798 if (id_index == 0) {
12799 return 0;
12800 }
12801 VALUE sym = ibf_load_object(load, id_index);
12802 if (rb_integer_type_p(sym)) {
12803 /* Load hidden local variables as indexes */
12804 return NUM2ULONG(sym);
12805 }
12806 return rb_sym2id(sym);
12807}
12808
12809/* dump/load: code */
12810
12811static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12812
12813static int
12814ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12815{
12816 if (iseq == NULL) {
12817 return -1;
12818 }
12819 else {
12820 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12821 }
12822}
12823
12824static unsigned char
12825ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12826{
12827 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12828 return (unsigned char)load->current_buffer->buff[(*offset)++];
12829}
12830
12831/*
12832 * Small uint serialization
12833 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12834 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12835 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12836 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12837 * ...
12838 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12839 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12840 */
12841static void
12842ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12843{
12844 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12845 ibf_dump_write(dump, &x, sizeof(VALUE));
12846 return;
12847 }
12848
12849 enum { max_byte_length = sizeof(VALUE) + 1 };
12850
12851 unsigned char bytes[max_byte_length];
12852 ibf_offset_t n;
12853
12854 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12855 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12856 }
12857
12858 x <<= 1;
12859 x |= 1;
12860 x <<= n;
12861 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12862 n++;
12863
12864 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12865}
12866
12867static VALUE
12868ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12869{
12870 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12871 union { char s[sizeof(VALUE)]; VALUE v; } x;
12872
12873 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12874 *offset += sizeof(VALUE);
12875
12876 return x.v;
12877 }
12878
12879 enum { max_byte_length = sizeof(VALUE) + 1 };
12880
12881 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12882 const unsigned char c = buffer[*offset];
12883
12884 ibf_offset_t n =
12885 c & 1 ? 1 :
12886 c == 0 ? 9 : ntz_int32(c) + 1;
12887 VALUE x = (VALUE)c >> n;
12888
12889 if (*offset + n > load->current_buffer->size) {
12890 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12891 }
12892
12893 ibf_offset_t i;
12894 for (i = 1; i < n; i++) {
12895 x <<= 8;
12896 x |= (VALUE)buffer[*offset + i];
12897 }
12898
12899 *offset += n;
12900 return x;
12901}
12902
12903static void
12904ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12905{
12906 // short: index
12907 // short: name.length
12908 // bytes: name
12909 // // omit argc (only verify with name)
12910 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12911
12912 size_t len = strlen(bf->name);
12913 ibf_dump_write_small_value(dump, (VALUE)len);
12914 ibf_dump_write(dump, bf->name, len);
12915}
12916
12917static const struct rb_builtin_function *
12918ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12919{
12920 int i = (int)ibf_load_small_value(load, offset);
12921 int len = (int)ibf_load_small_value(load, offset);
12922 const char *name = (char *)ibf_load_ptr(load, offset, len);
12923
12924 if (0) {
12925 fprintf(stderr, "%.*s!!\n", len, name);
12926 }
12927
12928 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12929 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12930 if (strncmp(table[i].name, name, len) != 0) {
12931 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12932 }
12933 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12934
12935 return &table[i];
12936}
12937
12938static ibf_offset_t
12939ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12940{
12941 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12942 const int iseq_size = body->iseq_size;
12943 int code_index;
12944 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12945
12946 ibf_offset_t offset = ibf_dump_pos(dump);
12947
12948 for (code_index=0; code_index<iseq_size;) {
12949 const VALUE insn = orig_code[code_index++];
12950 const char *types = insn_op_types(insn);
12951 int op_index;
12952
12953 /* opcode */
12954 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12955 ibf_dump_write_small_value(dump, insn);
12956
12957 /* operands */
12958 for (op_index=0; types[op_index]; op_index++, code_index++) {
12959 VALUE op = orig_code[code_index];
12960 VALUE wv;
12961
12962 switch (types[op_index]) {
12963 case TS_CDHASH:
12964 case TS_VALUE:
12965 wv = ibf_dump_object(dump, op);
12966 break;
12967 case TS_ISEQ:
12968 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12969 break;
12970 case TS_IC:
12971 {
12972 IC ic = (IC)op;
12973 VALUE arr = idlist_to_array(ic->segments);
12974 wv = ibf_dump_object(dump, arr);
12975 }
12976 break;
12977 case TS_ISE:
12978 case TS_IVC:
12979 case TS_ICVARC:
12980 {
12982 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12983 }
12984 break;
12985 case TS_CALLDATA:
12986 {
12987 goto skip_wv;
12988 }
12989 case TS_ID:
12990 wv = ibf_dump_id(dump, (ID)op);
12991 break;
12992 case TS_FUNCPTR:
12993 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12994 goto skip_wv;
12995 case TS_BUILTIN:
12996 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12997 goto skip_wv;
12998 default:
12999 wv = op;
13000 break;
13001 }
13002 ibf_dump_write_small_value(dump, wv);
13003 skip_wv:;
13004 }
13005 RUBY_ASSERT(insn_len(insn) == op_index+1);
13006 }
13007
13008 return offset;
13009}
13010
13011static VALUE *
13012ibf_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)
13013{
13014 VALUE iseqv = (VALUE)iseq;
13015 unsigned int code_index;
13016 ibf_offset_t reading_pos = bytecode_offset;
13017 VALUE *code = ALLOC_N(VALUE, iseq_size);
13018
13019 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13020 struct rb_call_data *cd_entries = load_body->call_data;
13021 int ic_index = 0;
13022
13023 load_body->iseq_encoded = code;
13024 load_body->iseq_size = 0;
13025
13026 iseq_bits_t * mark_offset_bits;
13027
13028 iseq_bits_t tmp[1] = {0};
13029
13030 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13031 mark_offset_bits = tmp;
13032 }
13033 else {
13034 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13035 }
13036 bool needs_bitmap = false;
13037
13038 for (code_index=0; code_index<iseq_size;) {
13039 /* opcode */
13040 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13041 const char *types = insn_op_types(insn);
13042 int op_index;
13043
13044 code_index++;
13045
13046 /* operands */
13047 for (op_index=0; types[op_index]; op_index++, code_index++) {
13048 const char operand_type = types[op_index];
13049 switch (operand_type) {
13050 case TS_VALUE:
13051 {
13052 VALUE op = ibf_load_small_value(load, &reading_pos);
13053 VALUE v = ibf_load_object(load, op);
13054 code[code_index] = v;
13055 if (!SPECIAL_CONST_P(v)) {
13056 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13057 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13058 needs_bitmap = true;
13059 }
13060 break;
13061 }
13062 case TS_CDHASH:
13063 {
13064 VALUE op = ibf_load_small_value(load, &reading_pos);
13065 VALUE v = ibf_load_object(load, op);
13066 v = rb_hash_dup(v); // hash dumped as frozen
13067 RHASH_TBL_RAW(v)->type = &cdhash_type;
13068 rb_hash_rehash(v); // hash function changed
13069 RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13070
13071 // Overwrite the existing hash in the object list. This
13072 // is to keep the object alive during load time.
13073 // [Bug #17984] [ruby-core:104259]
13074 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13075
13076 code[code_index] = v;
13077 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13078 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13079 needs_bitmap = true;
13080 break;
13081 }
13082 case TS_ISEQ:
13083 {
13084 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13085 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13086 code[code_index] = v;
13087 if (!SPECIAL_CONST_P(v)) {
13088 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13089 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13090 needs_bitmap = true;
13091 }
13092 break;
13093 }
13094 case TS_IC:
13095 {
13096 VALUE op = ibf_load_small_value(load, &reading_pos);
13097 VALUE arr = ibf_load_object(load, op);
13098
13099 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13100 ic->segments = array_to_idlist(arr);
13101
13102 code[code_index] = (VALUE)ic;
13103 }
13104 break;
13105 case TS_ISE:
13106 case TS_ICVARC:
13107 case TS_IVC:
13108 {
13109 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13110
13111 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13112 code[code_index] = (VALUE)ic;
13113
13114 if (operand_type == TS_IVC) {
13115 IVC cache = (IVC)ic;
13116
13117 if (insn == BIN(setinstancevariable)) {
13118 ID iv_name = (ID)code[code_index - 1];
13119 cache->iv_set_name = iv_name;
13120 }
13121 else {
13122 cache->iv_set_name = 0;
13123 }
13124
13125 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13126 }
13127
13128 }
13129 break;
13130 case TS_CALLDATA:
13131 {
13132 code[code_index] = (VALUE)cd_entries++;
13133 }
13134 break;
13135 case TS_ID:
13136 {
13137 VALUE op = ibf_load_small_value(load, &reading_pos);
13138 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13139 }
13140 break;
13141 case TS_FUNCPTR:
13142 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13143 break;
13144 case TS_BUILTIN:
13145 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13146 break;
13147 default:
13148 code[code_index] = ibf_load_small_value(load, &reading_pos);
13149 continue;
13150 }
13151 }
13152 if (insn_len(insn) != op_index+1) {
13153 rb_raise(rb_eRuntimeError, "operand size mismatch");
13154 }
13155 }
13156
13157 load_body->iseq_size = code_index;
13158
13159 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13160 load_body->mark_bits.single = mark_offset_bits[0];
13161 }
13162 else {
13163 if (needs_bitmap) {
13164 load_body->mark_bits.list = mark_offset_bits;
13165 }
13166 else {
13167 load_body->mark_bits.list = 0;
13168 ruby_xfree(mark_offset_bits);
13169 }
13170 }
13171
13172 RUBY_ASSERT(code_index == iseq_size);
13173 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13174 return code;
13175}
13176
13177static ibf_offset_t
13178ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13179{
13180 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13181
13182 if (opt_num > 0) {
13183 IBF_W_ALIGN(VALUE);
13184 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13185 }
13186 else {
13187 return ibf_dump_pos(dump);
13188 }
13189}
13190
13191static VALUE *
13192ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13193{
13194 if (opt_num > 0) {
13195 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13196 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13197 return table;
13198 }
13199 else {
13200 return NULL;
13201 }
13202}
13203
13204static ibf_offset_t
13205ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13206{
13207 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13208
13209 if (kw) {
13210 struct rb_iseq_param_keyword dump_kw = *kw;
13211 int dv_num = kw->num - kw->required_num;
13212 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13213 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13214 int i;
13215
13216 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13217 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13218
13219 dump_kw.table = IBF_W(ids, ID, kw->num);
13220 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13221 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13222 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13223 }
13224 else {
13225 return 0;
13226 }
13227}
13228
13229static const struct rb_iseq_param_keyword *
13230ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13231{
13232 if (param_keyword_offset) {
13233 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13234 int dv_num = kw->num - kw->required_num;
13235 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13236
13237 int i;
13238 for (i=0; i<dv_num; i++) {
13239 dvs[i] = ibf_load_object(load, dvs[i]);
13240 }
13241
13242 // Will be set once the local table is loaded.
13243 kw->table = NULL;
13244
13245 kw->default_values = dvs;
13246 return kw;
13247 }
13248 else {
13249 return NULL;
13250 }
13251}
13252
13253static ibf_offset_t
13254ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13255{
13256 ibf_offset_t offset = ibf_dump_pos(dump);
13257 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13258
13259 unsigned int i;
13260 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13261 ibf_dump_write_small_value(dump, entries[i].line_no);
13262#ifdef USE_ISEQ_NODE_ID
13263 ibf_dump_write_small_value(dump, entries[i].node_id);
13264#endif
13265 ibf_dump_write_small_value(dump, entries[i].events);
13266 }
13267
13268 return offset;
13269}
13270
13271static struct iseq_insn_info_entry *
13272ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13273{
13274 ibf_offset_t reading_pos = body_offset;
13275 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13276
13277 unsigned int i;
13278 for (i = 0; i < size; i++) {
13279 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13280#ifdef USE_ISEQ_NODE_ID
13281 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13282#endif
13283 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13284 }
13285
13286 return entries;
13287}
13288
13289static ibf_offset_t
13290ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13291{
13292 ibf_offset_t offset = ibf_dump_pos(dump);
13293
13294 unsigned int last = 0;
13295 unsigned int i;
13296 for (i = 0; i < size; i++) {
13297 ibf_dump_write_small_value(dump, positions[i] - last);
13298 last = positions[i];
13299 }
13300
13301 return offset;
13302}
13303
13304static unsigned int *
13305ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13306{
13307 ibf_offset_t reading_pos = positions_offset;
13308 unsigned int *positions = ALLOC_N(unsigned int, size);
13309
13310 unsigned int last = 0;
13311 unsigned int i;
13312 for (i = 0; i < size; i++) {
13313 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13314 last = positions[i];
13315 }
13316
13317 return positions;
13318}
13319
13320static ibf_offset_t
13321ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13322{
13323 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13324 const int size = body->local_table_size;
13325 ID *table = ALLOCA_N(ID, size);
13326 int i;
13327
13328 for (i=0; i<size; i++) {
13329 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13330 if (v == 0) {
13331 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13332 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13333 }
13334 table[i] = v;
13335 }
13336
13337 IBF_W_ALIGN(ID);
13338 return ibf_dump_write(dump, table, sizeof(ID) * size);
13339}
13340
13341static const ID *
13342ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13343{
13344 if (size > 0) {
13345 ID *table = IBF_R(local_table_offset, ID, size);
13346 int i;
13347
13348 for (i=0; i<size; i++) {
13349 table[i] = ibf_load_id(load, table[i]);
13350 }
13351
13352 if (size == 1 && table[0] == idERROR_INFO) {
13353 xfree(table);
13354 return rb_iseq_shared_exc_local_tbl;
13355 }
13356 else {
13357 return table;
13358 }
13359 }
13360 else {
13361 return NULL;
13362 }
13363}
13364
13365static ibf_offset_t
13366ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13367{
13368 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13369 const int size = body->local_table_size;
13370 IBF_W_ALIGN(enum lvar_state);
13371 return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
13372}
13373
13374static enum lvar_state *
13375ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13376{
13377 if (local_table == rb_iseq_shared_exc_local_tbl ||
13378 size <= 0) {
13379 return NULL;
13380 }
13381 else {
13382 enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
13383 return states;
13384 }
13385}
13386
13387static ibf_offset_t
13388ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13389{
13390 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13391
13392 if (table) {
13393 int *iseq_indices = ALLOCA_N(int, table->size);
13394 unsigned int i;
13395
13396 for (i=0; i<table->size; i++) {
13397 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13398 }
13399
13400 const ibf_offset_t offset = ibf_dump_pos(dump);
13401
13402 for (i=0; i<table->size; i++) {
13403 ibf_dump_write_small_value(dump, iseq_indices[i]);
13404 ibf_dump_write_small_value(dump, table->entries[i].type);
13405 ibf_dump_write_small_value(dump, table->entries[i].start);
13406 ibf_dump_write_small_value(dump, table->entries[i].end);
13407 ibf_dump_write_small_value(dump, table->entries[i].cont);
13408 ibf_dump_write_small_value(dump, table->entries[i].sp);
13409 }
13410 return offset;
13411 }
13412 else {
13413 return ibf_dump_pos(dump);
13414 }
13415}
13416
13417static void
13418ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13419{
13420 if (size) {
13421 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13422 table->size = size;
13423 ISEQ_BODY(parent_iseq)->catch_table = table;
13424
13425 ibf_offset_t reading_pos = catch_table_offset;
13426
13427 unsigned int i;
13428 for (i=0; i<table->size; i++) {
13429 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13430 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13431 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13432 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13433 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13434 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13435
13436 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13437 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13438 }
13439 }
13440 else {
13441 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13442 }
13443}
13444
13445static ibf_offset_t
13446ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13447{
13448 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13449 const unsigned int ci_size = body->ci_size;
13450 const struct rb_call_data *cds = body->call_data;
13451
13452 ibf_offset_t offset = ibf_dump_pos(dump);
13453
13454 unsigned int i;
13455
13456 for (i = 0; i < ci_size; i++) {
13457 const struct rb_callinfo *ci = cds[i].ci;
13458 if (ci != NULL) {
13459 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13460 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13461 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13462
13463 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13464 if (kwarg) {
13465 int len = kwarg->keyword_len;
13466 ibf_dump_write_small_value(dump, len);
13467 for (int j=0; j<len; j++) {
13468 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13469 ibf_dump_write_small_value(dump, keyword);
13470 }
13471 }
13472 else {
13473 ibf_dump_write_small_value(dump, 0);
13474 }
13475 }
13476 else {
13477 // TODO: truncate NULL ci from call_data.
13478 ibf_dump_write_small_value(dump, (VALUE)-1);
13479 }
13480 }
13481
13482 return offset;
13483}
13484
13486 ID id;
13487 VALUE name;
13488 VALUE val;
13489};
13490
13492 size_t num;
13493 struct outer_variable_pair pairs[1];
13494};
13495
13496static enum rb_id_table_iterator_result
13497store_outer_variable(ID id, VALUE val, void *dump)
13498{
13499 struct outer_variable_list *ovlist = dump;
13500 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13501 pair->id = id;
13502 pair->name = rb_id2str(id);
13503 pair->val = val;
13504 return ID_TABLE_CONTINUE;
13505}
13506
13507static int
13508outer_variable_cmp(const void *a, const void *b, void *arg)
13509{
13510 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13511 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13512
13513 if (!ap->name) {
13514 return -1;
13515 }
13516 else if (!bp->name) {
13517 return 1;
13518 }
13519
13520 return rb_str_cmp(ap->name, bp->name);
13521}
13522
13523static ibf_offset_t
13524ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13525{
13526 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13527
13528 ibf_offset_t offset = ibf_dump_pos(dump);
13529
13530 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13531 ibf_dump_write_small_value(dump, (VALUE)size);
13532 if (size > 0) {
13533 VALUE buff;
13534 size_t buffsize =
13535 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13536 offsetof(struct outer_variable_list, pairs),
13537 rb_eArgError);
13538 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13539 ovlist->num = 0;
13540 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13541 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13542 for (size_t i = 0; i < size; ++i) {
13543 ID id = ovlist->pairs[i].id;
13544 ID val = ovlist->pairs[i].val;
13545 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13546 ibf_dump_write_small_value(dump, val);
13547 }
13548 }
13549
13550 return offset;
13551}
13552
13553/* note that we dump out rb_call_info but load back rb_call_data */
13554static void
13555ibf_load_ci_entries(const struct ibf_load *load,
13556 ibf_offset_t ci_entries_offset,
13557 unsigned int ci_size,
13558 struct rb_call_data **cd_ptr)
13559{
13560 if (!ci_size) {
13561 *cd_ptr = NULL;
13562 return;
13563 }
13564
13565 ibf_offset_t reading_pos = ci_entries_offset;
13566
13567 unsigned int i;
13568
13569 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13570 *cd_ptr = cds;
13571
13572 for (i = 0; i < ci_size; i++) {
13573 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13574 if (mid_index != (VALUE)-1) {
13575 ID mid = ibf_load_id(load, mid_index);
13576 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13577 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13578
13579 struct rb_callinfo_kwarg *kwarg = NULL;
13580 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13581 if (kwlen > 0) {
13582 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13583 kwarg->references = 0;
13584 kwarg->keyword_len = kwlen;
13585 for (int j=0; j<kwlen; j++) {
13586 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13587 kwarg->keywords[j] = ibf_load_object(load, keyword);
13588 }
13589 }
13590
13591 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13592 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13593 cds[i].cc = vm_cc_empty();
13594 }
13595 else {
13596 // NULL ci
13597 cds[i].ci = NULL;
13598 cds[i].cc = NULL;
13599 }
13600 }
13601}
13602
13603static struct rb_id_table *
13604ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13605{
13606 ibf_offset_t reading_pos = outer_variables_offset;
13607
13608 struct rb_id_table *tbl = NULL;
13609
13610 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13611
13612 if (table_size > 0) {
13613 tbl = rb_id_table_create(table_size);
13614 }
13615
13616 for (size_t i = 0; i < table_size; i++) {
13617 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13618 VALUE value = ibf_load_small_value(load, &reading_pos);
13619 if (!key) key = rb_make_temporary_id(i);
13620 rb_id_table_insert(tbl, key, value);
13621 }
13622
13623 return tbl;
13624}
13625
13626static ibf_offset_t
13627ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13628{
13629 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13630
13631 unsigned int *positions;
13632
13633 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13634
13635 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13636 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13637 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13638
13639#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13640 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13641
13642 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13643 struct ibf_dump_buffer buffer;
13644 buffer.str = rb_str_new(0, 0);
13645 buffer.obj_table = ibf_dump_object_table_new();
13646 dump->current_buffer = &buffer;
13647#endif
13648
13649 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13650 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13651 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13652 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13653 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13654
13655 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13656 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13657 ruby_xfree(positions);
13658
13659 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13660 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13661 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13662 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13663 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13664 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13665 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13666 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13667 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13668
13669#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13670 ibf_offset_t local_obj_list_offset;
13671 unsigned int local_obj_list_size;
13672
13673 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13674#endif
13675
13676 ibf_offset_t body_offset = ibf_dump_pos(dump);
13677
13678 /* dump the constant body */
13679 unsigned int param_flags =
13680 (body->param.flags.has_lead << 0) |
13681 (body->param.flags.has_opt << 1) |
13682 (body->param.flags.has_rest << 2) |
13683 (body->param.flags.has_post << 3) |
13684 (body->param.flags.has_kw << 4) |
13685 (body->param.flags.has_kwrest << 5) |
13686 (body->param.flags.has_block << 6) |
13687 (body->param.flags.ambiguous_param0 << 7) |
13688 (body->param.flags.accepts_no_kwarg << 8) |
13689 (body->param.flags.ruby2_keywords << 9) |
13690 (body->param.flags.anon_rest << 10) |
13691 (body->param.flags.anon_kwrest << 11) |
13692 (body->param.flags.use_block << 12) |
13693 (body->param.flags.forwardable << 13) ;
13694
13695#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13696# define IBF_BODY_OFFSET(x) (x)
13697#else
13698# define IBF_BODY_OFFSET(x) (body_offset - (x))
13699#endif
13700
13701 ibf_dump_write_small_value(dump, body->type);
13702 ibf_dump_write_small_value(dump, body->iseq_size);
13703 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13704 ibf_dump_write_small_value(dump, bytecode_size);
13705 ibf_dump_write_small_value(dump, param_flags);
13706 ibf_dump_write_small_value(dump, body->param.size);
13707 ibf_dump_write_small_value(dump, body->param.lead_num);
13708 ibf_dump_write_small_value(dump, body->param.opt_num);
13709 ibf_dump_write_small_value(dump, body->param.rest_start);
13710 ibf_dump_write_small_value(dump, body->param.post_start);
13711 ibf_dump_write_small_value(dump, body->param.post_num);
13712 ibf_dump_write_small_value(dump, body->param.block_start);
13713 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13714 ibf_dump_write_small_value(dump, param_keyword_offset);
13715 ibf_dump_write_small_value(dump, location_pathobj_index);
13716 ibf_dump_write_small_value(dump, location_base_label_index);
13717 ibf_dump_write_small_value(dump, location_label_index);
13718 ibf_dump_write_small_value(dump, body->location.first_lineno);
13719 ibf_dump_write_small_value(dump, body->location.node_id);
13720 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13721 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13722 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13723 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13724 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13725 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13726 ibf_dump_write_small_value(dump, body->insns_info.size);
13727 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13728 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13729 ibf_dump_write_small_value(dump, catch_table_size);
13730 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13731 ibf_dump_write_small_value(dump, parent_iseq_index);
13732 ibf_dump_write_small_value(dump, local_iseq_index);
13733 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13734 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13735 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13736 ibf_dump_write_small_value(dump, body->variable.flip_count);
13737 ibf_dump_write_small_value(dump, body->local_table_size);
13738 ibf_dump_write_small_value(dump, body->ivc_size);
13739 ibf_dump_write_small_value(dump, body->icvarc_size);
13740 ibf_dump_write_small_value(dump, body->ise_size);
13741 ibf_dump_write_small_value(dump, body->ic_size);
13742 ibf_dump_write_small_value(dump, body->ci_size);
13743 ibf_dump_write_small_value(dump, body->stack_max);
13744 ibf_dump_write_small_value(dump, body->builtin_attrs);
13745 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13746
13747#undef IBF_BODY_OFFSET
13748
13749#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13750 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13751
13752 dump->current_buffer = saved_buffer;
13753 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13754
13755 ibf_offset_t offset = ibf_dump_pos(dump);
13756 ibf_dump_write_small_value(dump, iseq_start);
13757 ibf_dump_write_small_value(dump, iseq_length_bytes);
13758 ibf_dump_write_small_value(dump, body_offset);
13759
13760 ibf_dump_write_small_value(dump, local_obj_list_offset);
13761 ibf_dump_write_small_value(dump, local_obj_list_size);
13762
13763 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13764
13765 return offset;
13766#else
13767 return body_offset;
13768#endif
13769}
13770
13771static VALUE
13772ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13773{
13774 VALUE str = ibf_load_object(load, str_index);
13775 if (str != Qnil) {
13776 str = rb_fstring(str);
13777 }
13778 return str;
13779}
13780
13781static void
13782ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13783{
13784 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13785
13786 ibf_offset_t reading_pos = offset;
13787
13788#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13789 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13790 load->current_buffer = &load->global_buffer;
13791
13792 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13793 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13794 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13795
13796 struct ibf_load_buffer buffer;
13797 buffer.buff = load->global_buffer.buff + iseq_start;
13798 buffer.size = iseq_length_bytes;
13799 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13800 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13801 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13802
13803 load->current_buffer = &buffer;
13804 reading_pos = body_offset;
13805#endif
13806
13807#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13808# define IBF_BODY_OFFSET(x) (x)
13809#else
13810# define IBF_BODY_OFFSET(x) (offset - (x))
13811#endif
13812
13813 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13814 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13815 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13816 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13817 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13818 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13819 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13820 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13821 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13822 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13823 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13824 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13825 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13826 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13827 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13828 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13829 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13830 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13831 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13832 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13833 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13834 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13835 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13836 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13837 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13838 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13839 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13840 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13841 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13842 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13843 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13844 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13845 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13846 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13847 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13848 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13849 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13850
13851 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13852 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13853 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13854 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13855
13856 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13857 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13858 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13859 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13860
13861 // setup fname and dummy frame
13862 VALUE path = ibf_load_object(load, location_pathobj_index);
13863 {
13864 VALUE realpath = Qnil;
13865
13866 if (RB_TYPE_P(path, T_STRING)) {
13867 realpath = path = rb_fstring(path);
13868 }
13869 else if (RB_TYPE_P(path, T_ARRAY)) {
13870 VALUE pathobj = path;
13871 if (RARRAY_LEN(pathobj) != 2) {
13872 rb_raise(rb_eRuntimeError, "path object size mismatch");
13873 }
13874 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13875 realpath = RARRAY_AREF(pathobj, 1);
13876 if (!NIL_P(realpath)) {
13877 if (!RB_TYPE_P(realpath, T_STRING)) {
13878 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13879 "(%x), path=%+"PRIsVALUE,
13880 realpath, TYPE(realpath), path);
13881 }
13882 realpath = rb_fstring(realpath);
13883 }
13884 }
13885 else {
13886 rb_raise(rb_eRuntimeError, "unexpected path object");
13887 }
13888 rb_iseq_pathobj_set(iseq, path, realpath);
13889 }
13890
13891 // push dummy frame
13892 rb_execution_context_t *ec = GET_EC();
13893 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13894
13895#undef IBF_BODY_OFFSET
13896
13897 load_body->type = type;
13898 load_body->stack_max = stack_max;
13899 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13900 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13901 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13902 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13903 load_body->param.flags.has_kw = FALSE;
13904 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13905 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13906 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13907 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13908 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13909 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13910 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13911 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13912 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13913 load_body->param.size = param_size;
13914 load_body->param.lead_num = param_lead_num;
13915 load_body->param.opt_num = param_opt_num;
13916 load_body->param.rest_start = param_rest_start;
13917 load_body->param.post_start = param_post_start;
13918 load_body->param.post_num = param_post_num;
13919 load_body->param.block_start = param_block_start;
13920 load_body->local_table_size = local_table_size;
13921 load_body->ci_size = ci_size;
13922 load_body->insns_info.size = insns_info_size;
13923
13924 ISEQ_COVERAGE_SET(iseq, Qnil);
13925 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13926 load_body->variable.flip_count = variable_flip_count;
13927 load_body->variable.script_lines = Qnil;
13928
13929 load_body->location.first_lineno = location_first_lineno;
13930 load_body->location.node_id = location_node_id;
13931 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13932 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13933 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13934 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13935 load_body->builtin_attrs = builtin_attrs;
13936 load_body->prism = prism;
13937
13938 load_body->ivc_size = ivc_size;
13939 load_body->icvarc_size = icvarc_size;
13940 load_body->ise_size = ise_size;
13941 load_body->ic_size = ic_size;
13942
13943 if (ISEQ_IS_SIZE(load_body)) {
13944 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13945 }
13946 else {
13947 load_body->is_entries = NULL;
13948 }
13949 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13950 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13951 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13952 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13953 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13954 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13955 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13956 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13957 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13958 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13959
13960 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13961 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13962 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13963
13964 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13965 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13966 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13967
13968 // This must be done after the local table is loaded.
13969 if (load_body->param.keyword != NULL) {
13970 RUBY_ASSERT(load_body->local_table);
13971 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13972 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13973 }
13974
13975 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13976#if VM_INSN_INFO_TABLE_IMPL == 2
13977 rb_iseq_insns_info_encode_positions(iseq);
13978#endif
13979
13980 rb_iseq_translate_threaded_code(iseq);
13981
13982#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13983 load->current_buffer = &load->global_buffer;
13984#endif
13985
13986 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13987 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13988
13989#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13990 load->current_buffer = saved_buffer;
13991#endif
13992 verify_call_cache(iseq);
13993
13994 RB_GC_GUARD(dummy_frame);
13995 rb_vm_pop_frame_no_int(ec);
13996}
13997
13999{
14000 struct ibf_dump *dump;
14001 VALUE offset_list;
14002};
14003
14004static int
14005ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14006{
14007 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14008 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14009
14010 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14011 rb_ary_push(args->offset_list, UINT2NUM(offset));
14012
14013 return ST_CONTINUE;
14014}
14015
14016static void
14017ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14018{
14019 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14020
14021 struct ibf_dump_iseq_list_arg args;
14022 args.dump = dump;
14023 args.offset_list = offset_list;
14024
14025 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14026
14027 st_index_t i;
14028 st_index_t size = dump->iseq_table->num_entries;
14029 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14030
14031 for (i = 0; i < size; i++) {
14032 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14033 }
14034
14035 ibf_dump_align(dump, sizeof(ibf_offset_t));
14036 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14037 header->iseq_list_size = (unsigned int)size;
14038}
14039
14040/*
14041 * Binary format
14042 * - ibf_object_header
14043 * - ibf_object_xxx (xxx is type)
14044 */
14045
14047 unsigned int type: 5;
14048 unsigned int special_const: 1;
14049 unsigned int frozen: 1;
14050 unsigned int internal: 1;
14051};
14052
14053enum ibf_object_class_index {
14054 IBF_OBJECT_CLASS_OBJECT,
14055 IBF_OBJECT_CLASS_ARRAY,
14056 IBF_OBJECT_CLASS_STANDARD_ERROR,
14057 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14058 IBF_OBJECT_CLASS_TYPE_ERROR,
14059 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14060};
14061
14063 long srcstr;
14064 char option;
14065};
14066
14068 long len;
14069 long keyval[FLEX_ARY_LEN];
14070};
14071
14073 long class_index;
14074 long len;
14075 long beg;
14076 long end;
14077 int excl;
14078};
14079
14081 ssize_t slen;
14082 BDIGIT digits[FLEX_ARY_LEN];
14083};
14084
14085enum ibf_object_data_type {
14086 IBF_OBJECT_DATA_ENCODING,
14087};
14088
14090 long a, b;
14091};
14092
14094 long str;
14095};
14096
14097#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14098 ((((offset) - 1) / (align) + 1) * (align))
14099/* No cast, since it's UB to create an unaligned pointer.
14100 * Leave as void* for use with memcpy in those cases.
14101 * We align the offset, but the buffer pointer is only VALUE aligned,
14102 * so the returned pointer may be unaligned for `type` .*/
14103#define IBF_OBJBODY(type, offset) \
14104 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14105
14106static const void *
14107ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14108{
14109 if (offset >= load->current_buffer->size) {
14110 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14111 }
14112 return load->current_buffer->buff + offset;
14113}
14114
14115NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14116
14117static void
14118ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14119{
14120 char buff[0x100];
14121 rb_raw_obj_info(buff, sizeof(buff), obj);
14122 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14123}
14124
14125NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14126
14127static VALUE
14128ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14129{
14130 rb_raise(rb_eArgError, "unsupported");
14132}
14133
14134static void
14135ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14136{
14137 enum ibf_object_class_index cindex;
14138 if (obj == rb_cObject) {
14139 cindex = IBF_OBJECT_CLASS_OBJECT;
14140 }
14141 else if (obj == rb_cArray) {
14142 cindex = IBF_OBJECT_CLASS_ARRAY;
14143 }
14144 else if (obj == rb_eStandardError) {
14145 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14146 }
14147 else if (obj == rb_eNoMatchingPatternError) {
14148 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14149 }
14150 else if (obj == rb_eTypeError) {
14151 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14152 }
14153 else if (obj == rb_eNoMatchingPatternKeyError) {
14154 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14155 }
14156 else {
14157 rb_obj_info_dump(obj);
14158 rb_p(obj);
14159 rb_bug("unsupported class");
14160 }
14161 ibf_dump_write_small_value(dump, (VALUE)cindex);
14162}
14163
14164static VALUE
14165ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14166{
14167 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14168
14169 switch (cindex) {
14170 case IBF_OBJECT_CLASS_OBJECT:
14171 return rb_cObject;
14172 case IBF_OBJECT_CLASS_ARRAY:
14173 return rb_cArray;
14174 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14175 return rb_eStandardError;
14176 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14178 case IBF_OBJECT_CLASS_TYPE_ERROR:
14179 return rb_eTypeError;
14180 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14182 }
14183
14184 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14185}
14186
14187
14188static void
14189ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14190{
14191 double dbl = RFLOAT_VALUE(obj);
14192 (void)IBF_W(&dbl, double, 1);
14193}
14194
14195static VALUE
14196ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14197{
14198 double d;
14199 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14200 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14201 VALUE f = DBL2NUM(d);
14202 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14203 return f;
14204}
14205
14206static void
14207ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14208{
14209 long encindex = (long)rb_enc_get_index(obj);
14210 long len = RSTRING_LEN(obj);
14211 const char *ptr = RSTRING_PTR(obj);
14212
14213 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14214 rb_encoding *enc = rb_enc_from_index((int)encindex);
14215 const char *enc_name = rb_enc_name(enc);
14216 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14217 }
14218
14219 ibf_dump_write_small_value(dump, encindex);
14220 ibf_dump_write_small_value(dump, len);
14221 IBF_WP(ptr, char, len);
14222}
14223
14224static VALUE
14225ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14226{
14227 ibf_offset_t reading_pos = offset;
14228
14229 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14230 const long len = (long)ibf_load_small_value(load, &reading_pos);
14231 const char *ptr = load->current_buffer->buff + reading_pos;
14232
14233 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14234 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14235 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14236 }
14237
14238 VALUE str;
14239 if (header->frozen && !header->internal) {
14240 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14241 }
14242 else {
14243 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14244
14245 if (header->internal) rb_obj_hide(str);
14246 if (header->frozen) str = rb_fstring(str);
14247 }
14248 return str;
14249}
14250
14251static void
14252ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14253{
14254 VALUE srcstr = RREGEXP_SRC(obj);
14255 struct ibf_object_regexp regexp;
14256 regexp.option = (char)rb_reg_options(obj);
14257 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14258
14259 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14260 ibf_dump_write_small_value(dump, regexp.srcstr);
14261}
14262
14263static VALUE
14264ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14265{
14266 struct ibf_object_regexp regexp;
14267 regexp.option = ibf_load_byte(load, &offset);
14268 regexp.srcstr = ibf_load_small_value(load, &offset);
14269
14270 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14271 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14272
14273 if (header->internal) rb_obj_hide(reg);
14274 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14275
14276 return reg;
14277}
14278
14279static void
14280ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14281{
14282 long i, len = RARRAY_LEN(obj);
14283 ibf_dump_write_small_value(dump, len);
14284 for (i=0; i<len; i++) {
14285 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14286 ibf_dump_write_small_value(dump, index);
14287 }
14288}
14289
14290static VALUE
14291ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14292{
14293 ibf_offset_t reading_pos = offset;
14294
14295 const long len = (long)ibf_load_small_value(load, &reading_pos);
14296
14297 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14298 int i;
14299
14300 for (i=0; i<len; i++) {
14301 const VALUE index = ibf_load_small_value(load, &reading_pos);
14302 rb_ary_push(ary, ibf_load_object(load, index));
14303 }
14304
14305 if (header->frozen) {
14306 rb_ary_freeze(ary);
14307 rb_ractor_make_shareable(ary); // TODO: check elements
14308 }
14309
14310 return ary;
14311}
14312
14313static int
14314ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14315{
14316 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14317
14318 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14319 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14320
14321 ibf_dump_write_small_value(dump, key_index);
14322 ibf_dump_write_small_value(dump, val_index);
14323 return ST_CONTINUE;
14324}
14325
14326static void
14327ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14328{
14329 long len = RHASH_SIZE(obj);
14330 ibf_dump_write_small_value(dump, (VALUE)len);
14331
14332 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14333}
14334
14335static VALUE
14336ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14337{
14338 long len = (long)ibf_load_small_value(load, &offset);
14339 VALUE obj = rb_hash_new_with_size(len);
14340 int i;
14341
14342 for (i = 0; i < len; i++) {
14343 VALUE key_index = ibf_load_small_value(load, &offset);
14344 VALUE val_index = ibf_load_small_value(load, &offset);
14345
14346 VALUE key = ibf_load_object(load, key_index);
14347 VALUE val = ibf_load_object(load, val_index);
14348 rb_hash_aset(obj, key, val);
14349 }
14350 rb_hash_rehash(obj);
14351
14352 if (header->internal) rb_obj_hide(obj);
14353 if (header->frozen) {
14354 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14355 }
14356
14357 return obj;
14358}
14359
14360static void
14361ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14362{
14363 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14364 struct ibf_object_struct_range range;
14365 VALUE beg, end;
14366 IBF_ZERO(range);
14367 range.len = 3;
14368 range.class_index = 0;
14369
14370 rb_range_values(obj, &beg, &end, &range.excl);
14371 range.beg = (long)ibf_dump_object(dump, beg);
14372 range.end = (long)ibf_dump_object(dump, end);
14373
14374 IBF_W_ALIGN(struct ibf_object_struct_range);
14375 IBF_WV(range);
14376 }
14377 else {
14378 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14379 rb_class_name(CLASS_OF(obj)));
14380 }
14381}
14382
14383static VALUE
14384ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14385{
14386 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14387 VALUE beg = ibf_load_object(load, range->beg);
14388 VALUE end = ibf_load_object(load, range->end);
14389 VALUE obj = rb_range_new(beg, end, range->excl);
14390 if (header->internal) rb_obj_hide(obj);
14391 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14392 return obj;
14393}
14394
14395static void
14396ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14397{
14398 ssize_t len = BIGNUM_LEN(obj);
14399 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14400 BDIGIT *d = BIGNUM_DIGITS(obj);
14401
14402 (void)IBF_W(&slen, ssize_t, 1);
14403 IBF_WP(d, BDIGIT, len);
14404}
14405
14406static VALUE
14407ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14408{
14409 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14410 int sign = bignum->slen > 0;
14411 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14412 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14415 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14416 big_unpack_flags |
14417 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14418 if (header->internal) rb_obj_hide(obj);
14419 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14420 return obj;
14421}
14422
14423static void
14424ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14425{
14426 if (rb_data_is_encoding(obj)) {
14427 rb_encoding *enc = rb_to_encoding(obj);
14428 const char *name = rb_enc_name(enc);
14429 long len = strlen(name) + 1;
14430 long data[2];
14431 data[0] = IBF_OBJECT_DATA_ENCODING;
14432 data[1] = len;
14433 (void)IBF_W(data, long, 2);
14434 IBF_WP(name, char, len);
14435 }
14436 else {
14437 ibf_dump_object_unsupported(dump, obj);
14438 }
14439}
14440
14441static VALUE
14442ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14443{
14444 const long *body = IBF_OBJBODY(long, offset);
14445 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14446 /* const long len = body[1]; */
14447 const char *data = (const char *)&body[2];
14448
14449 switch (type) {
14450 case IBF_OBJECT_DATA_ENCODING:
14451 {
14452 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14453 return encobj;
14454 }
14455 }
14456
14457 return ibf_load_object_unsupported(load, header, offset);
14458}
14459
14460static void
14461ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14462{
14463 long data[2];
14464 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14465 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14466
14467 (void)IBF_W(data, long, 2);
14468}
14469
14470static VALUE
14471ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14472{
14473 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14474 VALUE a = ibf_load_object(load, nums->a);
14475 VALUE b = ibf_load_object(load, nums->b);
14476 VALUE obj = header->type == T_COMPLEX ?
14477 rb_complex_new(a, b) : rb_rational_new(a, b);
14478
14479 if (header->internal) rb_obj_hide(obj);
14480 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14481 return obj;
14482}
14483
14484static void
14485ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14486{
14487 ibf_dump_object_string(dump, rb_sym2str(obj));
14488}
14489
14490static VALUE
14491ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14492{
14493 ibf_offset_t reading_pos = offset;
14494
14495 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14496 const long len = (long)ibf_load_small_value(load, &reading_pos);
14497 const char *ptr = load->current_buffer->buff + reading_pos;
14498
14499 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14500 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14501 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14502 }
14503
14504 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14505 return ID2SYM(id);
14506}
14507
14508typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14509static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14510 ibf_dump_object_unsupported, /* T_NONE */
14511 ibf_dump_object_unsupported, /* T_OBJECT */
14512 ibf_dump_object_class, /* T_CLASS */
14513 ibf_dump_object_unsupported, /* T_MODULE */
14514 ibf_dump_object_float, /* T_FLOAT */
14515 ibf_dump_object_string, /* T_STRING */
14516 ibf_dump_object_regexp, /* T_REGEXP */
14517 ibf_dump_object_array, /* T_ARRAY */
14518 ibf_dump_object_hash, /* T_HASH */
14519 ibf_dump_object_struct, /* T_STRUCT */
14520 ibf_dump_object_bignum, /* T_BIGNUM */
14521 ibf_dump_object_unsupported, /* T_FILE */
14522 ibf_dump_object_data, /* T_DATA */
14523 ibf_dump_object_unsupported, /* T_MATCH */
14524 ibf_dump_object_complex_rational, /* T_COMPLEX */
14525 ibf_dump_object_complex_rational, /* T_RATIONAL */
14526 ibf_dump_object_unsupported, /* 0x10 */
14527 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14528 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14529 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14530 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14531 ibf_dump_object_unsupported, /* T_FIXNUM */
14532 ibf_dump_object_unsupported, /* T_UNDEF */
14533 ibf_dump_object_unsupported, /* 0x17 */
14534 ibf_dump_object_unsupported, /* 0x18 */
14535 ibf_dump_object_unsupported, /* 0x19 */
14536 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14537 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14538 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14539 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14540 ibf_dump_object_unsupported, /* 0x1e */
14541 ibf_dump_object_unsupported, /* 0x1f */
14542};
14543
14544static void
14545ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14546{
14547 unsigned char byte =
14548 (header.type << 0) |
14549 (header.special_const << 5) |
14550 (header.frozen << 6) |
14551 (header.internal << 7);
14552
14553 IBF_WV(byte);
14554}
14555
14556static struct ibf_object_header
14557ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14558{
14559 unsigned char byte = ibf_load_byte(load, offset);
14560
14561 struct ibf_object_header header;
14562 header.type = (byte >> 0) & 0x1f;
14563 header.special_const = (byte >> 5) & 0x01;
14564 header.frozen = (byte >> 6) & 0x01;
14565 header.internal = (byte >> 7) & 0x01;
14566
14567 return header;
14568}
14569
14570static ibf_offset_t
14571ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14572{
14573 struct ibf_object_header obj_header;
14574 ibf_offset_t current_offset;
14575 IBF_ZERO(obj_header);
14576 obj_header.type = TYPE(obj);
14577
14578 IBF_W_ALIGN(ibf_offset_t);
14579 current_offset = ibf_dump_pos(dump);
14580
14581 if (SPECIAL_CONST_P(obj) &&
14582 ! (SYMBOL_P(obj) ||
14583 RB_FLOAT_TYPE_P(obj))) {
14584 obj_header.special_const = TRUE;
14585 obj_header.frozen = TRUE;
14586 obj_header.internal = TRUE;
14587 ibf_dump_object_object_header(dump, obj_header);
14588 ibf_dump_write_small_value(dump, obj);
14589 }
14590 else {
14591 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14592 obj_header.special_const = FALSE;
14593 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14594 ibf_dump_object_object_header(dump, obj_header);
14595 (*dump_object_functions[obj_header.type])(dump, obj);
14596 }
14597
14598 return current_offset;
14599}
14600
14601typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14602static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14603 ibf_load_object_unsupported, /* T_NONE */
14604 ibf_load_object_unsupported, /* T_OBJECT */
14605 ibf_load_object_class, /* T_CLASS */
14606 ibf_load_object_unsupported, /* T_MODULE */
14607 ibf_load_object_float, /* T_FLOAT */
14608 ibf_load_object_string, /* T_STRING */
14609 ibf_load_object_regexp, /* T_REGEXP */
14610 ibf_load_object_array, /* T_ARRAY */
14611 ibf_load_object_hash, /* T_HASH */
14612 ibf_load_object_struct, /* T_STRUCT */
14613 ibf_load_object_bignum, /* T_BIGNUM */
14614 ibf_load_object_unsupported, /* T_FILE */
14615 ibf_load_object_data, /* T_DATA */
14616 ibf_load_object_unsupported, /* T_MATCH */
14617 ibf_load_object_complex_rational, /* T_COMPLEX */
14618 ibf_load_object_complex_rational, /* T_RATIONAL */
14619 ibf_load_object_unsupported, /* 0x10 */
14620 ibf_load_object_unsupported, /* T_NIL */
14621 ibf_load_object_unsupported, /* T_TRUE */
14622 ibf_load_object_unsupported, /* T_FALSE */
14623 ibf_load_object_symbol,
14624 ibf_load_object_unsupported, /* T_FIXNUM */
14625 ibf_load_object_unsupported, /* T_UNDEF */
14626 ibf_load_object_unsupported, /* 0x17 */
14627 ibf_load_object_unsupported, /* 0x18 */
14628 ibf_load_object_unsupported, /* 0x19 */
14629 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14630 ibf_load_object_unsupported, /* T_NODE 0x1b */
14631 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14632 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14633 ibf_load_object_unsupported, /* 0x1e */
14634 ibf_load_object_unsupported, /* 0x1f */
14635};
14636
14637static VALUE
14638ibf_load_object(const struct ibf_load *load, VALUE object_index)
14639{
14640 if (object_index == 0) {
14641 return Qnil;
14642 }
14643 else {
14644 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14645 if (!obj) {
14646 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14647 ibf_offset_t offset = offsets[object_index];
14648 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14649
14650#if IBF_ISEQ_DEBUG
14651 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14652 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14653 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14654 header.type, header.special_const, header.frozen, header.internal);
14655#endif
14656 if (offset >= load->current_buffer->size) {
14657 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14658 }
14659
14660 if (header.special_const) {
14661 ibf_offset_t reading_pos = offset;
14662
14663 obj = ibf_load_small_value(load, &reading_pos);
14664 }
14665 else {
14666 obj = (*load_object_functions[header.type])(load, &header, offset);
14667 }
14668
14669 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14670 }
14671#if IBF_ISEQ_DEBUG
14672 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14673 object_index, obj);
14674#endif
14675 return obj;
14676 }
14677}
14678
14680{
14681 struct ibf_dump *dump;
14682 VALUE offset_list;
14683};
14684
14685static int
14686ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14687{
14688 VALUE obj = (VALUE)key;
14689 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14690
14691 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14692 rb_ary_push(args->offset_list, UINT2NUM(offset));
14693
14694 return ST_CONTINUE;
14695}
14696
14697static void
14698ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14699{
14700 st_table *obj_table = dump->current_buffer->obj_table;
14701 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14702
14703 struct ibf_dump_object_list_arg args;
14704 args.dump = dump;
14705 args.offset_list = offset_list;
14706
14707 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14708
14709 IBF_W_ALIGN(ibf_offset_t);
14710 *obj_list_offset = ibf_dump_pos(dump);
14711
14712 st_index_t size = obj_table->num_entries;
14713 st_index_t i;
14714
14715 for (i=0; i<size; i++) {
14716 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14717 IBF_WV(offset);
14718 }
14719
14720 *obj_list_size = (unsigned int)size;
14721}
14722
14723static void
14724ibf_dump_mark(void *ptr)
14725{
14726 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14727 rb_gc_mark(dump->global_buffer.str);
14728
14729 rb_mark_set(dump->global_buffer.obj_table);
14730 rb_mark_set(dump->iseq_table);
14731}
14732
14733static void
14734ibf_dump_free(void *ptr)
14735{
14736 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14737 if (dump->global_buffer.obj_table) {
14738 st_free_table(dump->global_buffer.obj_table);
14739 dump->global_buffer.obj_table = 0;
14740 }
14741 if (dump->iseq_table) {
14742 st_free_table(dump->iseq_table);
14743 dump->iseq_table = 0;
14744 }
14745}
14746
14747static size_t
14748ibf_dump_memsize(const void *ptr)
14749{
14750 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14751 size_t size = 0;
14752 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14753 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14754 return size;
14755}
14756
14757static const rb_data_type_t ibf_dump_type = {
14758 "ibf_dump",
14759 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14760 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14761};
14762
14763static void
14764ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14765{
14766 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14767 dump->iseq_table = NULL;
14768
14769 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14770 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14771 dump->iseq_table = st_init_numtable(); /* need free */
14772
14773 dump->current_buffer = &dump->global_buffer;
14774}
14775
14776VALUE
14777rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14778{
14779 struct ibf_dump *dump;
14780 struct ibf_header header = {{0}};
14781 VALUE dump_obj;
14782 VALUE str;
14783
14784 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14785 ISEQ_BODY(iseq)->local_iseq != iseq) {
14786 rb_raise(rb_eRuntimeError, "should be top of iseq");
14787 }
14788 if (RTEST(ISEQ_COVERAGE(iseq))) {
14789 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14790 }
14791
14792 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14793 ibf_dump_setup(dump, dump_obj);
14794
14795 ibf_dump_write(dump, &header, sizeof(header));
14796 ibf_dump_iseq(dump, iseq);
14797
14798 header.magic[0] = 'Y'; /* YARB */
14799 header.magic[1] = 'A';
14800 header.magic[2] = 'R';
14801 header.magic[3] = 'B';
14802 header.major_version = IBF_MAJOR_VERSION;
14803 header.minor_version = IBF_MINOR_VERSION;
14804 header.endian = IBF_ENDIAN_MARK;
14805 header.wordsize = (uint8_t)SIZEOF_VALUE;
14806 ibf_dump_iseq_list(dump, &header);
14807 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14808 header.size = ibf_dump_pos(dump);
14809
14810 if (RTEST(opt)) {
14811 VALUE opt_str = opt;
14812 const char *ptr = StringValuePtr(opt_str);
14813 header.extra_size = RSTRING_LENINT(opt_str);
14814 ibf_dump_write(dump, ptr, header.extra_size);
14815 }
14816 else {
14817 header.extra_size = 0;
14818 }
14819
14820 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14821
14822 str = dump->global_buffer.str;
14823 RB_GC_GUARD(dump_obj);
14824 return str;
14825}
14826
14827static const ibf_offset_t *
14828ibf_iseq_list(const struct ibf_load *load)
14829{
14830 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14831}
14832
14833void
14834rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14835{
14836 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14837 rb_iseq_t *prev_src_iseq = load->iseq;
14838 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14839 load->iseq = iseq;
14840#if IBF_ISEQ_DEBUG
14841 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14842 iseq->aux.loader.index, offset,
14843 load->header->size);
14844#endif
14845 ibf_load_iseq_each(load, iseq, offset);
14846 ISEQ_COMPILE_DATA_CLEAR(iseq);
14847 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14848 rb_iseq_init_trace(iseq);
14849 load->iseq = prev_src_iseq;
14850}
14851
14852#if USE_LAZY_LOAD
14853const rb_iseq_t *
14854rb_iseq_complete(const rb_iseq_t *iseq)
14855{
14856 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14857 return iseq;
14858}
14859#endif
14860
14861static rb_iseq_t *
14862ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14863{
14864 int iseq_index = (int)(VALUE)index_iseq;
14865
14866#if IBF_ISEQ_DEBUG
14867 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14868 (void *)index_iseq, (void *)load->iseq_list);
14869#endif
14870 if (iseq_index == -1) {
14871 return NULL;
14872 }
14873 else {
14874 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14875
14876#if IBF_ISEQ_DEBUG
14877 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14878#endif
14879 if (iseqv) {
14880 return (rb_iseq_t *)iseqv;
14881 }
14882 else {
14883 rb_iseq_t *iseq = iseq_imemo_alloc();
14884#if IBF_ISEQ_DEBUG
14885 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14886#endif
14887 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14888 iseq->aux.loader.obj = load->loader_obj;
14889 iseq->aux.loader.index = iseq_index;
14890#if IBF_ISEQ_DEBUG
14891 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14892 (void *)iseq, (void *)load->loader_obj, iseq_index);
14893#endif
14894 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14895
14896 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14897#if IBF_ISEQ_DEBUG
14898 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14899#endif
14900 rb_ibf_load_iseq_complete(iseq);
14901 }
14902
14903#if IBF_ISEQ_DEBUG
14904 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14905 (void *)iseq, (void *)load->iseq);
14906#endif
14907 return iseq;
14908 }
14909 }
14910}
14911
14912static void
14913ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14914{
14915 struct ibf_header *header = (struct ibf_header *)bytes;
14916 load->loader_obj = loader_obj;
14917 load->global_buffer.buff = bytes;
14918 load->header = header;
14919 load->global_buffer.size = header->size;
14920 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14921 load->global_buffer.obj_list_size = header->global_object_list_size;
14922 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14923 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14924 load->iseq = NULL;
14925
14926 load->current_buffer = &load->global_buffer;
14927
14928 if (size < header->size) {
14929 rb_raise(rb_eRuntimeError, "broken binary format");
14930 }
14931 if (strncmp(header->magic, "YARB", 4) != 0) {
14932 rb_raise(rb_eRuntimeError, "unknown binary format");
14933 }
14934 if (header->major_version != IBF_MAJOR_VERSION ||
14935 header->minor_version != IBF_MINOR_VERSION) {
14936 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14937 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14938 }
14939 if (header->endian != IBF_ENDIAN_MARK) {
14940 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14941 }
14942 if (header->wordsize != SIZEOF_VALUE) {
14943 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14944 }
14945 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14946 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14947 header->iseq_list_offset);
14948 }
14949 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14950 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14951 load->global_buffer.obj_list_offset);
14952 }
14953}
14954
14955static void
14956ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14957{
14958 StringValue(str);
14959
14960 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14961 rb_raise(rb_eRuntimeError, "broken binary format");
14962 }
14963
14964 if (USE_LAZY_LOAD) {
14965 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14966 }
14967
14968 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14969 RB_OBJ_WRITE(loader_obj, &load->str, str);
14970}
14971
14972static void
14973ibf_loader_mark(void *ptr)
14974{
14975 struct ibf_load *load = (struct ibf_load *)ptr;
14976 rb_gc_mark(load->str);
14977 rb_gc_mark(load->iseq_list);
14978 rb_gc_mark(load->global_buffer.obj_list);
14979}
14980
14981static void
14982ibf_loader_free(void *ptr)
14983{
14984 struct ibf_load *load = (struct ibf_load *)ptr;
14985 ruby_xfree(load);
14986}
14987
14988static size_t
14989ibf_loader_memsize(const void *ptr)
14990{
14991 return sizeof(struct ibf_load);
14992}
14993
14994static const rb_data_type_t ibf_load_type = {
14995 "ibf_loader",
14996 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14997 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14998};
14999
15000const rb_iseq_t *
15001rb_iseq_ibf_load(VALUE str)
15002{
15003 struct ibf_load *load;
15004 rb_iseq_t *iseq;
15005 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15006
15007 ibf_load_setup(load, loader_obj, str);
15008 iseq = ibf_load_iseq(load, 0);
15009
15010 RB_GC_GUARD(loader_obj);
15011 return iseq;
15012}
15013
15014const rb_iseq_t *
15015rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15016{
15017 struct ibf_load *load;
15018 rb_iseq_t *iseq;
15019 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15020
15021 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15022 iseq = ibf_load_iseq(load, 0);
15023
15024 RB_GC_GUARD(loader_obj);
15025 return iseq;
15026}
15027
15028VALUE
15029rb_iseq_ibf_load_extra_data(VALUE str)
15030{
15031 struct ibf_load *load;
15032 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15033 VALUE extra_str;
15034
15035 ibf_load_setup(load, loader_obj, str);
15036 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15037 RB_GC_GUARD(loader_obj);
15038 return extra_str;
15039}
15040
15041#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:1676
#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:1684
#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:205
#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 FLONUM_P
Old name of RB_FLONUM_P.
#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:1441
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1444
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:677
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
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:1445
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1448
@ 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:686
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:923
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
#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:1862
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:2022
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4223
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:3799
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1746
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4162
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4148
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3567
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:3765
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4216
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:4036
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3280
#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:1515
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
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
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1547
#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.
#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
#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
void(*) RUBY_DATA_FUNC(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
#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
#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:649
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:461
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:205
#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:508
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9056
#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:288
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 iseq.h:259
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
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145