Ruby: compile.c Source File

Ruby 4.0.6p0 (2026-07-14 revision 03b6d3f8898a28604fe6cb00eae3226b821168f4)

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