Ruby 4.1.0dev (2026-03-01 revision d68e4be1873e364c5ee24ed112bce4bc86e3a406)
compile.c (d68e4be1873e364c5ee24ed112bce4bc86e3a406)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
498
499static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
500static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
501
502/*
503 * To make Array to LinkedList, use link_anchor
504 */
505
506static void
507verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
508{
509#if CPDEBUG
510 int flag = 0;
511 LINK_ELEMENT *list, *plist;
512
513 if (!compile_debug) return;
514
515 list = anchor->anchor.next;
516 plist = &anchor->anchor;
517 while (list) {
518 if (plist != list->prev) {
519 flag += 1;
520 }
521 plist = list;
522 list = list->next;
523 }
524
525 if (anchor->last != plist && anchor->last != 0) {
526 flag |= 0x70000;
527 }
528
529 if (flag != 0) {
530 rb_bug("list verify error: %08x (%s)", flag, info);
531 }
532#endif
533}
534#if CPDEBUG < 0
535#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
536#endif
537
538static void
539verify_call_cache(rb_iseq_t *iseq)
540{
541#if CPDEBUG
542 VALUE *original = rb_iseq_original_iseq(iseq);
543 size_t i = 0;
544 while (i < ISEQ_BODY(iseq)->iseq_size) {
545 VALUE insn = original[i];
546 const char *types = insn_op_types(insn);
547
548 for (int j=0; types[j]; j++) {
549 if (types[j] == TS_CALLDATA) {
550 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
551 const struct rb_callinfo *ci = cd->ci;
552 const struct rb_callcache *cc = cd->cc;
553 if (cc != vm_cc_empty()) {
554 vm_ci_dump(ci);
555 rb_bug("call cache is not initialized by vm_cc_empty()");
556 }
557 }
558 }
559 i += insn_len(insn);
560 }
561
562 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
563 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
564 const struct rb_callinfo *ci = cd->ci;
565 const struct rb_callcache *cc = cd->cc;
566 if (cc != NULL && cc != vm_cc_empty()) {
567 vm_ci_dump(ci);
568 rb_bug("call cache is not initialized by vm_cc_empty()");
569 }
570 }
571#endif
572}
573
574/*
575 * elem1, elem2 => elem1, elem2, elem
576 */
577static void
578ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
579{
580 elem->prev = anchor->last;
581 anchor->last->next = elem;
582 anchor->last = elem;
583 verify_list("add", anchor);
584}
585
586/*
587 * elem1, before, elem2 => elem1, before, elem, elem2
588 */
589static void
590APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
591{
592 elem->prev = before;
593 elem->next = before->next;
594 elem->next->prev = elem;
595 before->next = elem;
596 if (before == anchor->last) anchor->last = elem;
597 verify_list("add", anchor);
598}
599#if CPDEBUG < 0
600#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
601#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
602#endif
603
604static int
605branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
606{
607 if (!ISEQ_COVERAGE(iseq)) return 0;
608 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
609 if (first_line <= 0) return 0;
610 return 1;
611}
612
613static VALUE
614setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
615{
616 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
617 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
618 VALUE branch = rb_ary_hidden_new(6);
619
620 rb_hash_aset(structure, key, branch);
621 rb_ary_push(branch, ID2SYM(rb_intern(type)));
622 rb_ary_push(branch, INT2FIX(first_lineno));
623 rb_ary_push(branch, INT2FIX(first_column));
624 rb_ary_push(branch, INT2FIX(last_lineno));
625 rb_ary_push(branch, INT2FIX(last_column));
626 return branch;
627}
628
629static VALUE
630decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
631{
632 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
633
634 /*
635 * if !structure[node]
636 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
637 * else
638 * branches = structure[node][5]
639 * end
640 */
641
642 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
643 VALUE branch_base = rb_hash_aref(structure, key);
644 VALUE branches;
645
646 if (NIL_P(branch_base)) {
647 branch_base = setup_branch(loc, type, structure, key);
648 branches = rb_hash_new();
649 rb_obj_hide(branches);
650 rb_ary_push(branch_base, branches);
651 }
652 else {
653 branches = RARRAY_AREF(branch_base, 5);
654 }
655
656 return branches;
657}
658
659static NODE
660generate_dummy_line_node(int lineno, int node_id)
661{
662 NODE dummy = { 0 };
663 nd_set_line(&dummy, lineno);
664 nd_set_node_id(&dummy, node_id);
665 return dummy;
666}
667
668static void
669add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
670{
671 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
672
673 /*
674 * if !branches[branch_id]
675 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
676 * else
677 * counter_idx= branches[branch_id][5]
678 * end
679 */
680
681 VALUE key = INT2FIX(branch_id);
682 VALUE branch = rb_hash_aref(branches, key);
683 long counter_idx;
684
685 if (NIL_P(branch)) {
686 branch = setup_branch(loc, type, branches, key);
687 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
688 counter_idx = RARRAY_LEN(counters);
689 rb_ary_push(branch, LONG2FIX(counter_idx));
690 rb_ary_push(counters, INT2FIX(0));
691 }
692 else {
693 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
694 }
695
696 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
697 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724static NODE *
725get_nd_recv(const NODE *node)
726{
727 switch (nd_type(node)) {
728 case NODE_CALL:
729 return RNODE_CALL(node)->nd_recv;
730 case NODE_OPCALL:
731 return RNODE_OPCALL(node)->nd_recv;
732 case NODE_FCALL:
733 return 0;
734 case NODE_QCALL:
735 return RNODE_QCALL(node)->nd_recv;
736 case NODE_VCALL:
737 return 0;
738 case NODE_ATTRASGN:
739 return RNODE_ATTRASGN(node)->nd_recv;
740 case NODE_OP_ASGN1:
741 return RNODE_OP_ASGN1(node)->nd_recv;
742 case NODE_OP_ASGN2:
743 return RNODE_OP_ASGN2(node)->nd_recv;
744 default:
745 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
746 }
747}
748
749static ID
750get_node_call_nd_mid(const NODE *node)
751{
752 switch (nd_type(node)) {
753 case NODE_CALL:
754 return RNODE_CALL(node)->nd_mid;
755 case NODE_OPCALL:
756 return RNODE_OPCALL(node)->nd_mid;
757 case NODE_FCALL:
758 return RNODE_FCALL(node)->nd_mid;
759 case NODE_QCALL:
760 return RNODE_QCALL(node)->nd_mid;
761 case NODE_VCALL:
762 return RNODE_VCALL(node)->nd_mid;
763 case NODE_ATTRASGN:
764 return RNODE_ATTRASGN(node)->nd_mid;
765 default:
766 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
767 }
768}
769
770static NODE *
771get_nd_args(const NODE *node)
772{
773 switch (nd_type(node)) {
774 case NODE_CALL:
775 return RNODE_CALL(node)->nd_args;
776 case NODE_OPCALL:
777 return RNODE_OPCALL(node)->nd_args;
778 case NODE_FCALL:
779 return RNODE_FCALL(node)->nd_args;
780 case NODE_QCALL:
781 return RNODE_QCALL(node)->nd_args;
782 case NODE_VCALL:
783 return 0;
784 case NODE_ATTRASGN:
785 return RNODE_ATTRASGN(node)->nd_args;
786 default:
787 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
788 }
789}
790
791static ID
792get_node_colon_nd_mid(const NODE *node)
793{
794 switch (nd_type(node)) {
795 case NODE_COLON2:
796 return RNODE_COLON2(node)->nd_mid;
797 case NODE_COLON3:
798 return RNODE_COLON3(node)->nd_mid;
799 default:
800 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
801 }
802}
803
804static ID
805get_nd_vid(const NODE *node)
806{
807 switch (nd_type(node)) {
808 case NODE_LASGN:
809 return RNODE_LASGN(node)->nd_vid;
810 case NODE_DASGN:
811 return RNODE_DASGN(node)->nd_vid;
812 case NODE_IASGN:
813 return RNODE_IASGN(node)->nd_vid;
814 case NODE_CVASGN:
815 return RNODE_CVASGN(node)->nd_vid;
816 default:
817 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
818 }
819}
820
821static NODE *
822get_nd_value(const NODE *node)
823{
824 switch (nd_type(node)) {
825 case NODE_LASGN:
826 return RNODE_LASGN(node)->nd_value;
827 case NODE_DASGN:
828 return RNODE_DASGN(node)->nd_value;
829 default:
830 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
831 }
832}
833
834static VALUE
835get_string_value(const NODE *node)
836{
837 switch (nd_type(node)) {
838 case NODE_STR:
839 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
840 case NODE_FILE:
841 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
842 default:
843 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
844 }
845}
846
847VALUE
848rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
849{
850 DECL_ANCHOR(ret);
851 INIT_ANCHOR(ret);
852
853 (*ifunc->func)(iseq, ret, ifunc->data);
854
855 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
856
857 CHECK(iseq_setup_insn(iseq, ret));
858 return iseq_setup(iseq, ret);
859}
860
861static bool drop_unreachable_return(LINK_ANCHOR *ret);
862
863VALUE
864rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
865{
866 DECL_ANCHOR(ret);
867 INIT_ANCHOR(ret);
868
869 if (node == 0) {
870 NO_CHECK(COMPILE(ret, "nil", node));
871 iseq_set_local_table(iseq, 0, 0);
872 }
873 /* assume node is T_NODE */
874 else if (nd_type_p(node, NODE_SCOPE)) {
875 /* iseq type of top, method, class, block */
876 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
877 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_parameters_lvar_state(iseq);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(&OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1402 RBASIC_CLASS(*obj) == 0 || // hidden
1403 RB_OBJ_SHAREABLE_P(*obj));
1404}
1405
1406static INSN *
1407new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1408{
1409 INSN *iobj = compile_data_alloc_insn(iseq);
1410
1411 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1412
1413 iobj->link.type = ISEQ_ELEMENT_INSN;
1414 iobj->link.next = 0;
1415 iobj->insn_id = insn_id;
1416 iobj->insn_info.line_no = line_no;
1417 iobj->insn_info.node_id = node_id;
1418 iobj->insn_info.events = 0;
1419 iobj->operands = argv;
1420 iobj->operand_size = argc;
1421 iobj->sc_state = 0;
1422
1423 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1424
1425 return iobj;
1426}
1427
1428static INSN *
1429new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1430{
1431 VALUE *operands = 0;
1432 va_list argv;
1433 if (argc > 0) {
1434 int i;
1435 va_start(argv, argc);
1436 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1437 for (i = 0; i < argc; i++) {
1438 VALUE v = va_arg(argv, VALUE);
1439 operands[i] = v;
1440 }
1441 va_end(argv);
1442 }
1443 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1444}
1445
1446static INSN *
1447insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1448{
1449 VALUE *operands = 0;
1450 va_list argv;
1451 if (argc > 0) {
1452 int i;
1453 va_start(argv, argc);
1454 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1455 for (i = 0; i < argc; i++) {
1456 VALUE v = va_arg(argv, VALUE);
1457 operands[i] = v;
1458 }
1459 va_end(argv);
1460 }
1461
1462 iobj->insn_id = insn_id;
1463 iobj->operand_size = argc;
1464 iobj->operands = operands;
1465 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1466
1467 return iobj;
1468}
1469
1470static const struct rb_callinfo *
1471new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1472{
1473 VM_ASSERT(argc >= 0);
1474
1475 if (kw_arg) {
1476 flag |= VM_CALL_KWARG;
1477 argc += kw_arg->keyword_len;
1478 }
1479
1480 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1481 && !has_blockiseq) {
1482 flag |= VM_CALL_ARGS_SIMPLE;
1483 }
1484
1485 ISEQ_BODY(iseq)->ci_size++;
1486 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1487 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1488 return ci;
1489}
1490
1491static INSN *
1492new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1493{
1494 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1495 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1496 operands[0] = ci;
1497 operands[1] = (VALUE)blockiseq;
1498 if (blockiseq) {
1499 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1500 }
1501
1502 INSN *insn;
1503
1504 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1506 }
1507 else {
1508 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1509 }
1510
1511 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1512 RB_GC_GUARD(ci);
1513 return insn;
1514}
1515
1516static rb_iseq_t *
1517new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1518 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1519{
1520 rb_iseq_t *ret_iseq;
1521 VALUE ast_value = rb_ruby_ast_new(node);
1522
1523 debugs("[new_child_iseq]> ---------------------------------------\n");
1524 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1525 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1526 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1527 line_no, parent,
1528 isolated_depth ? isolated_depth + 1 : 0,
1529 type, ISEQ_COMPILE_DATA(iseq)->option,
1530 ISEQ_BODY(iseq)->variable.script_lines);
1531 debugs("[new_child_iseq]< ---------------------------------------\n");
1532 return ret_iseq;
1533}
1534
1535static rb_iseq_t *
1536new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1537 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1538{
1539 rb_iseq_t *ret_iseq;
1540
1541 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1542 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1543 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1544 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1545 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1546 return ret_iseq;
1547}
1548
1549static void
1550set_catch_except_p(rb_iseq_t *iseq)
1551{
1552 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1553 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1554 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1555 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1556 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1557 }
1558 }
1559}
1560
1561/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1562 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1563 if catch table exists. But we want to optimize while loop, which always has catch
1564 table entries for break/next/redo.
1565
1566 So this function sets true for limited ISeqs with break/next/redo catch table entries
1567 whose child ISeq would really raise an exception. */
1568static void
1569update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1570{
1571 unsigned int pos;
1572 size_t i;
1573 int insn;
1574 const struct iseq_catch_table *ct = body->catch_table;
1575
1576 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1577 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1578 pos = 0;
1579 while (pos < body->iseq_size) {
1580 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1581 if (insn == BIN(throw)) {
1582 set_catch_except_p(iseq);
1583 break;
1584 }
1585 pos += insn_len(insn);
1586 }
1587
1588 if (ct == NULL)
1589 return;
1590
1591 for (i = 0; i < ct->size; i++) {
1592 const struct iseq_catch_table_entry *entry =
1593 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1594 if (entry->type != CATCH_TYPE_BREAK
1595 && entry->type != CATCH_TYPE_NEXT
1596 && entry->type != CATCH_TYPE_REDO) {
1597 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1598 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1599 break;
1600 }
1601 }
1602}
1603
1604static void
1605iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1606{
1607 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1608 if (NIL_P(catch_table_ary)) return;
1609 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1610 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1611 for (i = 0; i < tlen; i++) {
1612 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1613 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1614 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1615 LINK_ELEMENT *e;
1616
1617 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1618
1619 if (ct != CATCH_TYPE_BREAK
1620 && ct != CATCH_TYPE_NEXT
1621 && ct != CATCH_TYPE_REDO) {
1622
1623 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1624 if (e == cont) {
1625 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1626 ELEM_INSERT_NEXT(end, &nop->link);
1627 break;
1628 }
1629 }
1630 }
1631 }
1632
1633 RB_GC_GUARD(catch_table_ary);
1634}
1635
1636static int
1637iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1638{
1639 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1640 return COMPILE_NG;
1641
1642 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1643
1644 if (compile_debug > 5)
1645 dump_disasm_list(FIRST_ELEMENT(anchor));
1646
1647 debugs("[compile step 3.1 (iseq_optimize)]\n");
1648 iseq_optimize(iseq, anchor);
1649
1650 if (compile_debug > 5)
1651 dump_disasm_list(FIRST_ELEMENT(anchor));
1652
1653 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1654 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1655 iseq_insns_unification(iseq, anchor);
1656 if (compile_debug > 5)
1657 dump_disasm_list(FIRST_ELEMENT(anchor));
1658 }
1659
1660 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1661 iseq_insert_nop_between_end_and_cont(iseq);
1662 if (compile_debug > 5)
1663 dump_disasm_list(FIRST_ELEMENT(anchor));
1664
1665 return COMPILE_OK;
1666}
1667
1668static int
1669iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1670{
1671 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1672 return COMPILE_NG;
1673
1674 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1675 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1676 if (compile_debug > 5)
1677 dump_disasm_list(FIRST_ELEMENT(anchor));
1678
1679 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1680 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1681
1682 debugs("[compile step 4.3 (set_optargs_table)] \n");
1683 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1684
1685 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1686 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1687
1688 debugs("[compile step 6 (update_catch_except_flags)] \n");
1689 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1690 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1691
1692 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1693 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1694 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1695 ruby_sized_xfree(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
1696 ISEQ_BODY(iseq)->catch_table = NULL;
1697 }
1698
1699#if VM_INSN_INFO_TABLE_IMPL == 2
1700 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1701 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1702 rb_iseq_insns_info_encode_positions(iseq);
1703 }
1704#endif
1705
1706 if (compile_debug > 1) {
1707 VALUE str = rb_iseq_disasm(iseq);
1708 printf("%s\n", StringValueCStr(str));
1709 }
1710 verify_call_cache(iseq);
1711 debugs("[compile step: finish]\n");
1712
1713 return COMPILE_OK;
1714}
1715
1716static int
1717iseq_set_exception_local_table(rb_iseq_t *iseq)
1718{
1719 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1720 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1721 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1722 return COMPILE_OK;
1723}
1724
1725static int
1726get_lvar_level(const rb_iseq_t *iseq)
1727{
1728 int lev = 0;
1729 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1730 lev++;
1731 iseq = ISEQ_BODY(iseq)->parent_iseq;
1732 }
1733 return lev;
1734}
1735
1736static int
1737get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1738{
1739 unsigned int i;
1740
1741 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1742 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1743 return (int)i;
1744 }
1745 }
1746 return -1;
1747}
1748
1749static int
1750get_local_var_idx(const rb_iseq_t *iseq, ID id)
1751{
1752 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1753
1754 if (idx < 0) {
1755 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1756 "get_local_var_idx: %d", idx);
1757 }
1758
1759 return idx;
1760}
1761
1762static int
1763get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1764{
1765 int lv = 0, idx = -1;
1766 const rb_iseq_t *const topmost_iseq = iseq;
1767
1768 while (iseq) {
1769 idx = get_dyna_var_idx_at_raw(iseq, id);
1770 if (idx >= 0) {
1771 break;
1772 }
1773 iseq = ISEQ_BODY(iseq)->parent_iseq;
1774 lv++;
1775 }
1776
1777 if (idx < 0) {
1778 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1779 "get_dyna_var_idx: -1");
1780 }
1781
1782 *level = lv;
1783 *ls = ISEQ_BODY(iseq)->local_table_size;
1784 return idx;
1785}
1786
1787static int
1788iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1789{
1790 const struct rb_iseq_constant_body *body;
1791 while (level > 0) {
1792 iseq = ISEQ_BODY(iseq)->parent_iseq;
1793 level--;
1794 }
1795 body = ISEQ_BODY(iseq);
1796 if (body->local_iseq == iseq && /* local variables */
1797 body->param.flags.has_block &&
1798 body->local_table_size - body->param.block_start == idx) {
1799 return TRUE;
1800 }
1801 else {
1802 return FALSE;
1803 }
1804}
1805
1806static int
1807iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1808{
1809 int level, ls;
1810 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1811 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1812 *pidx = ls - idx;
1813 *plevel = level;
1814 return TRUE;
1815 }
1816 else {
1817 return FALSE;
1818 }
1819}
1820
1821static void
1822access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1823{
1824 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1825
1826 if (isolated_depth && level >= isolated_depth) {
1827 if (id == rb_intern("yield")) {
1828 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1829 }
1830 else {
1831 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1832 }
1833 }
1834
1835 for (int i=0; i<level; i++) {
1836 VALUE val;
1837 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1838
1839 if (!ovs) {
1840 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1841 }
1842
1843 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1844 if (write && !val) {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1846 }
1847 }
1848 else {
1849 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1850 }
1851
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1853 }
1854}
1855
1856static ID
1857iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1858{
1859 for (int i=0; i<level; i++) {
1860 iseq = ISEQ_BODY(iseq)->parent_iseq;
1861 }
1862
1863 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1864 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1865 return id;
1866}
1867
1868static void
1869update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1870{
1871 for (int i=0; i<level; i++) {
1872 iseq = ISEQ_BODY(iseq)->parent_iseq;
1873 }
1874
1875 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1876 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1877 switch (states[table_idx]) {
1878 case lvar_uninitialized:
1879 states[table_idx] = lvar_initialized;
1880 break;
1881 case lvar_initialized:
1882 states[table_idx] = lvar_reassigned;
1883 break;
1884 case lvar_reassigned:
1885 /* nothing */
1886 break;
1887 default:
1888 rb_bug("unreachable");
1889 }
1890}
1891
1892static int
1893iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1894{
1895 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1896 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1897 }
1898
1899 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1900 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1901 for (int i=0; i<opt_num; i++) {
1902 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1903 }
1904
1905 return COMPILE_OK;
1906}
1907
1908static void
1909iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1910{
1911 if (iseq_local_block_param_p(iseq, idx, level)) {
1912 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1913 }
1914 else {
1915 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1916 }
1917 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1918}
1919
1920static void
1921iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1922{
1923 if (iseq_local_block_param_p(iseq, idx, level)) {
1924 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1925 }
1926 else {
1927 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1928 }
1929 update_lvar_state(iseq, level, idx);
1930 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1931}
1932
1933
1934
1935static void
1936iseq_calc_param_size(rb_iseq_t *iseq)
1937{
1938 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1939 if (body->param.flags.has_opt ||
1940 body->param.flags.has_post ||
1941 body->param.flags.has_rest ||
1942 body->param.flags.has_block ||
1943 body->param.flags.has_kw ||
1944 body->param.flags.has_kwrest) {
1945
1946 if (body->param.flags.has_block) {
1947 body->param.size = body->param.block_start + 1;
1948 }
1949 else if (body->param.flags.has_kwrest) {
1950 body->param.size = body->param.keyword->rest_start + 1;
1951 }
1952 else if (body->param.flags.has_kw) {
1953 body->param.size = body->param.keyword->bits_start + 1;
1954 }
1955 else if (body->param.flags.has_post) {
1956 body->param.size = body->param.post_start + body->param.post_num;
1957 }
1958 else if (body->param.flags.has_rest) {
1959 body->param.size = body->param.rest_start + 1;
1960 }
1961 else if (body->param.flags.has_opt) {
1962 body->param.size = body->param.lead_num + body->param.opt_num;
1963 }
1964 else {
1966 }
1967 }
1968 else {
1969 body->param.size = body->param.lead_num;
1970 }
1971}
1972
1973static int
1974iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1975 const struct rb_args_info *args, int arg_size)
1976{
1977 const rb_node_kw_arg_t *node = args->kw_args;
1978 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1979 struct rb_iseq_param_keyword *keyword;
1980 const VALUE default_values = rb_ary_hidden_new(1);
1981 const VALUE complex_mark = rb_str_tmp_new(0);
1982 int kw = 0, rkw = 0, di = 0, i;
1983
1984 body->param.flags.has_kw = TRUE;
1985 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1986
1987 while (node) {
1988 kw++;
1989 node = node->nd_next;
1990 }
1991 arg_size += kw;
1992 keyword->bits_start = arg_size++;
1993
1994 node = args->kw_args;
1995 while (node) {
1996 const NODE *val_node = get_nd_value(node->nd_body);
1997 VALUE dv;
1998
1999 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2000 ++rkw;
2001 }
2002 else {
2003 switch (nd_type(val_node)) {
2004 case NODE_SYM:
2005 dv = rb_node_sym_string_val(val_node);
2006 break;
2007 case NODE_REGX:
2008 dv = rb_node_regx_string_val(val_node);
2009 break;
2010 case NODE_LINE:
2011 dv = rb_node_line_lineno_val(val_node);
2012 break;
2013 case NODE_INTEGER:
2014 dv = rb_node_integer_literal_val(val_node);
2015 break;
2016 case NODE_FLOAT:
2017 dv = rb_node_float_literal_val(val_node);
2018 break;
2019 case NODE_RATIONAL:
2020 dv = rb_node_rational_literal_val(val_node);
2021 break;
2022 case NODE_IMAGINARY:
2023 dv = rb_node_imaginary_literal_val(val_node);
2024 break;
2025 case NODE_ENCODING:
2026 dv = rb_node_encoding_val(val_node);
2027 break;
2028 case NODE_NIL:
2029 dv = Qnil;
2030 break;
2031 case NODE_TRUE:
2032 dv = Qtrue;
2033 break;
2034 case NODE_FALSE:
2035 dv = Qfalse;
2036 break;
2037 default:
2038 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2039 dv = complex_mark;
2040 }
2041
2042 keyword->num = ++di;
2043 rb_ary_push(default_values, dv);
2044 }
2045
2046 node = node->nd_next;
2047 }
2048
2049 keyword->num = kw;
2050
2051 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2052 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2053 keyword->rest_start = arg_size++;
2054 body->param.flags.has_kwrest = TRUE;
2055
2056 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2057 }
2058 keyword->required_num = rkw;
2059 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2060
2061 if (RARRAY_LEN(default_values)) {
2062 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2063
2064 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2065 VALUE dv = RARRAY_AREF(default_values, i);
2066 if (dv == complex_mark) dv = Qundef;
2068 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2069 }
2070
2071 keyword->default_values = dvs;
2072 }
2073 return arg_size;
2074}
2075
2076static void
2077iseq_set_use_block(rb_iseq_t *iseq)
2078{
2079 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2080 if (!body->param.flags.use_block) {
2081 body->param.flags.use_block = 1;
2082
2083 rb_vm_t *vm = GET_VM();
2084
2085 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2086 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2087 set_insert(vm->unused_block_warning_table, key);
2088 }
2089 }
2090}
2091
2092static int
2093iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2094{
2095 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2096
2097 if (node_args) {
2098 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2099 const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
2100 ID rest_id = 0;
2101 int last_comma = 0;
2102 ID block_id = 0;
2103 int arg_size;
2104
2105 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2106
2107 body->param.lead_num = arg_size = (int)args->pre_args_num;
2108 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2109 debugs(" - argc: %d\n", body->param.lead_num);
2110
2111 rest_id = args->rest_arg;
2112 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2113 last_comma = 1;
2114 rest_id = 0;
2115 }
2116 block_id = args->block_arg;
2117
2118 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2119
2120 if (optimized_forward) {
2121 rest_id = 0;
2122 block_id = 0;
2123 }
2124
2125 if (args->opt_args) {
2126 const rb_node_opt_arg_t *node = args->opt_args;
2127 LABEL *label;
2128 VALUE labels = rb_ary_hidden_new(1);
2129 VALUE *opt_table;
2130 int i = 0, j;
2131
2132 while (node) {
2133 label = NEW_LABEL(nd_line(RNODE(node)));
2134 rb_ary_push(labels, (VALUE)label | 1);
2135 ADD_LABEL(optargs, label);
2136 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2137 node = node->nd_next;
2138 i += 1;
2139 }
2140
2141 /* last label */
2142 label = NEW_LABEL(nd_line(node_args));
2143 rb_ary_push(labels, (VALUE)label | 1);
2144 ADD_LABEL(optargs, label);
2145
2146 opt_table = ALLOC_N(VALUE, i+1);
2147
2148 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2149 for (j = 0; j < i+1; j++) {
2150 opt_table[j] &= ~1;
2151 }
2152 rb_ary_clear(labels);
2153
2154 body->param.flags.has_opt = TRUE;
2155 body->param.opt_num = i;
2156 body->param.opt_table = opt_table;
2157 arg_size += i;
2158 }
2159
2160 if (rest_id) {
2161 body->param.rest_start = arg_size++;
2162 body->param.flags.has_rest = TRUE;
2163 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2164 RUBY_ASSERT(body->param.rest_start != -1);
2165 }
2166
2167 if (args->first_post_arg) {
2168 body->param.post_start = arg_size;
2169 body->param.post_num = args->post_args_num;
2170 body->param.flags.has_post = TRUE;
2171 arg_size += args->post_args_num;
2172
2173 if (body->param.flags.has_rest) { /* TODO: why that? */
2174 body->param.post_start = body->param.rest_start + 1;
2175 }
2176 }
2177
2178 if (args->kw_args) {
2179 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2180 }
2181 else if (args->kw_rest_arg && !optimized_forward) {
2182 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2183 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2184 keyword->rest_start = arg_size++;
2185 body->param.keyword = keyword;
2186 body->param.flags.has_kwrest = TRUE;
2187
2188 static ID anon_kwrest = 0;
2189 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2190 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2191 }
2192 else if (args->no_kwarg) {
2193 body->param.flags.accepts_no_kwarg = TRUE;
2194 }
2195
2196 if (args->no_blockarg) {
2197 body->param.flags.accepts_no_block = TRUE;
2198 }
2199 else if (block_id) {
2200 body->param.block_start = arg_size++;
2201 body->param.flags.has_block = TRUE;
2202 iseq_set_use_block(iseq);
2203 }
2204
2205 // Only optimize specifically methods like this: `foo(...)`
2206 if (optimized_forward) {
2207 body->param.flags.use_block = 1;
2208 body->param.flags.forwardable = TRUE;
2209 arg_size = 1;
2210 }
2211
2212 iseq_calc_param_size(iseq);
2213 body->param.size = arg_size;
2214
2215 if (args->pre_init) { /* m_init */
2216 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2217 }
2218 if (args->post_init) { /* p_init */
2219 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2220 }
2221
2222 if (body->type == ISEQ_TYPE_BLOCK) {
2223 if (body->param.flags.has_opt == FALSE &&
2224 body->param.flags.has_post == FALSE &&
2225 body->param.flags.has_rest == FALSE &&
2226 body->param.flags.has_kw == FALSE &&
2227 body->param.flags.has_kwrest == FALSE) {
2228
2229 if (body->param.lead_num == 1 && last_comma == 0) {
2230 /* {|a|} */
2231 body->param.flags.ambiguous_param0 = TRUE;
2232 }
2233 }
2234 }
2235 }
2236
2237 return COMPILE_OK;
2238}
2239
2240static int
2241iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2242{
2243 unsigned int size = tbl ? tbl->size : 0;
2244 unsigned int offset = 0;
2245
2246 if (node_args) {
2247 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2248
2249 // If we have a function that only has `...` as the parameter,
2250 // then its local table should only be `...`
2251 // FIXME: I think this should be fixed in the AST rather than special case here.
2252 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2253 CHECK(size >= 3);
2254 size -= 3;
2255 offset += 3;
2256 }
2257 }
2258
2259 if (size > 0) {
2260 ID *ids = ALLOC_N(ID, size);
2261 MEMCPY(ids, tbl->ids + offset, ID, size);
2262 ISEQ_BODY(iseq)->local_table = ids;
2263
2264 enum lvar_state *states = ALLOC_N(enum lvar_state, size);
2265 // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
2266 for (unsigned int i=0; i<size; i++) {
2267 states[i] = lvar_uninitialized;
2268 // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
2269 }
2270 ISEQ_BODY(iseq)->lvar_states = states;
2271 }
2272 ISEQ_BODY(iseq)->local_table_size = size;
2273
2274 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2275 return COMPILE_OK;
2276}
2277
2278int
2279rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2280{
2281 int tval, tlit;
2282
2283 if (val == lit) {
2284 return 0;
2285 }
2286 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2287 return val != lit;
2288 }
2289 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2290 return -1;
2291 }
2292 else if (tlit != tval) {
2293 return -1;
2294 }
2295 else if (tlit == T_SYMBOL) {
2296 return val != lit;
2297 }
2298 else if (tlit == T_STRING) {
2299 return rb_str_hash_cmp(lit, val);
2300 }
2301 else if (tlit == T_BIGNUM) {
2302 long x = FIX2LONG(rb_big_cmp(lit, val));
2303
2304 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2305 * There is no need to call rb_fix2int here. */
2306 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2307 return (int)x;
2308 }
2309 else if (tlit == T_FLOAT) {
2310 return rb_float_cmp(lit, val);
2311 }
2312 else if (tlit == T_RATIONAL) {
2313 const struct RRational *rat1 = RRATIONAL(val);
2314 const struct RRational *rat2 = RRATIONAL(lit);
2315 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2316 }
2317 else if (tlit == T_COMPLEX) {
2318 const struct RComplex *comp1 = RCOMPLEX(val);
2319 const struct RComplex *comp2 = RCOMPLEX(lit);
2320 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2321 }
2322 else if (tlit == T_REGEXP) {
2323 return rb_reg_equal(val, lit) ? 0 : -1;
2324 }
2325 else {
2327 }
2328}
2329
2330st_index_t
2331rb_iseq_cdhash_hash(VALUE a)
2332{
2333 switch (OBJ_BUILTIN_TYPE(a)) {
2334 case -1:
2335 case T_SYMBOL:
2336 return (st_index_t)a;
2337 case T_STRING:
2338 return rb_str_hash(a);
2339 case T_BIGNUM:
2340 return FIX2LONG(rb_big_hash(a));
2341 case T_FLOAT:
2342 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2343 case T_RATIONAL:
2344 return rb_rational_hash(a);
2345 case T_COMPLEX:
2346 return rb_complex_hash(a);
2347 case T_REGEXP:
2348 return NUM2LONG(rb_reg_hash(a));
2349 default:
2351 }
2352}
2353
2354static const struct st_hash_type cdhash_type = {
2355 rb_iseq_cdhash_cmp,
2356 rb_iseq_cdhash_hash,
2357};
2358
2360 VALUE hash;
2361 int pos;
2362 int len;
2363};
2364
2365static int
2366cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2367{
2368 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2369 LABEL *lobj = (LABEL *)(val & ~1);
2370 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2371 return ST_CONTINUE;
2372}
2373
2374
2375static inline VALUE
2376get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2377{
2378 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2379}
2380
2381static inline VALUE
2382get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2383{
2384 VALUE val;
2385 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2386 if (tbl) {
2387 if (rb_id_table_lookup(tbl,id,&val)) {
2388 return val;
2389 }
2390 }
2391 else {
2392 tbl = rb_id_table_create(1);
2393 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2394 }
2395 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2396 rb_id_table_insert(tbl,id,val);
2397 return val;
2398}
2399
2400#define BADINSN_DUMP(anchor, list, dest) \
2401 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2402
2403#define BADINSN_ERROR \
2404 (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
2405 SIZED_FREE_N(insns_info, insns_info_size), \
2406 BADINSN_DUMP(anchor, list, NULL), \
2407 COMPILE_ERROR)
2408
2409static int
2410fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2411{
2412 int stack_max = 0, sp = 0, line = 0;
2413 LINK_ELEMENT *list;
2414
2415 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2416 if (IS_LABEL(list)) {
2417 LABEL *lobj = (LABEL *)list;
2418 lobj->set = TRUE;
2419 }
2420 }
2421
2422 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2423 switch (list->type) {
2424 case ISEQ_ELEMENT_INSN:
2425 {
2426 int j, len, insn;
2427 const char *types;
2428 VALUE *operands;
2429 INSN *iobj = (INSN *)list;
2430
2431 /* update sp */
2432 sp = calc_sp_depth(sp, iobj);
2433 if (sp < 0) {
2434 BADINSN_DUMP(anchor, list, NULL);
2435 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2436 "argument stack underflow (%d)", sp);
2437 return -1;
2438 }
2439 if (sp > stack_max) {
2440 stack_max = sp;
2441 }
2442
2443 line = iobj->insn_info.line_no;
2444 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2445 operands = iobj->operands;
2446 insn = iobj->insn_id;
2447 types = insn_op_types(insn);
2448 len = insn_len(insn);
2449
2450 /* operand check */
2451 if (iobj->operand_size != len - 1) {
2452 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2453 BADINSN_DUMP(anchor, list, NULL);
2454 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2455 "operand size miss! (%d for %d)",
2456 iobj->operand_size, len - 1);
2457 return -1;
2458 }
2459
2460 for (j = 0; types[j]; j++) {
2461 if (types[j] == TS_OFFSET) {
2462 /* label(destination position) */
2463 LABEL *lobj = (LABEL *)operands[j];
2464 if (!lobj->set) {
2465 BADINSN_DUMP(anchor, list, NULL);
2466 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2467 "unknown label: "LABEL_FORMAT, lobj->label_no);
2468 return -1;
2469 }
2470 if (lobj->sp == -1) {
2471 lobj->sp = sp;
2472 }
2473 else if (lobj->sp != sp) {
2474 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2475 RSTRING_PTR(rb_iseq_path(iseq)), line,
2476 lobj->label_no, lobj->sp, sp);
2477 }
2478 }
2479 }
2480 break;
2481 }
2482 case ISEQ_ELEMENT_LABEL:
2483 {
2484 LABEL *lobj = (LABEL *)list;
2485 if (lobj->sp == -1) {
2486 lobj->sp = sp;
2487 }
2488 else {
2489 if (lobj->sp != sp) {
2490 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2491 RSTRING_PTR(rb_iseq_path(iseq)), line,
2492 lobj->label_no, lobj->sp, sp);
2493 }
2494 sp = lobj->sp;
2495 }
2496 break;
2497 }
2498 case ISEQ_ELEMENT_TRACE:
2499 {
2500 /* ignore */
2501 break;
2502 }
2503 case ISEQ_ELEMENT_ADJUST:
2504 {
2505 ADJUST *adjust = (ADJUST *)list;
2506 int orig_sp = sp;
2507
2508 sp = adjust->label ? adjust->label->sp : 0;
2509 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2510 BADINSN_DUMP(anchor, list, NULL);
2511 COMPILE_ERROR(iseq, adjust->line_no,
2512 "iseq_set_sequence: adjust bug %d < %d",
2513 orig_sp, sp);
2514 return -1;
2515 }
2516 break;
2517 }
2518 default:
2519 BADINSN_DUMP(anchor, list, NULL);
2520 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2521 return -1;
2522 }
2523 }
2524 return stack_max;
2525}
2526
2527static int
2528add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2529 int insns_info_index, int code_index, const INSN *iobj)
2530{
2531 if (insns_info_index == 0 ||
2532 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2533#ifdef USE_ISEQ_NODE_ID
2534 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2535#endif
2536 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2537 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2538#ifdef USE_ISEQ_NODE_ID
2539 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2540#endif
2541 insns_info[insns_info_index].events = iobj->insn_info.events;
2542 positions[insns_info_index] = code_index;
2543 return TRUE;
2544 }
2545 return FALSE;
2546}
2547
2548static int
2549add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2550 int insns_info_index, int code_index, const ADJUST *adjust)
2551{
2552 insns_info[insns_info_index].line_no = adjust->line_no;
2553 insns_info[insns_info_index].node_id = -1;
2554 insns_info[insns_info_index].events = 0;
2555 positions[insns_info_index] = code_index;
2556 return TRUE;
2557}
2558
2559static ID *
2560array_to_idlist(VALUE arr)
2561{
2563 long size = RARRAY_LEN(arr);
2564 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2565 for (long i = 0; i < size; i++) {
2566 VALUE sym = RARRAY_AREF(arr, i);
2567 ids[i] = SYM2ID(sym);
2568 }
2569 ids[size] = 0;
2570 return ids;
2571}
2572
2573static VALUE
2574idlist_to_array(const ID *ids)
2575{
2576 VALUE arr = rb_ary_new();
2577 while (*ids) {
2578 rb_ary_push(arr, ID2SYM(*ids++));
2579 }
2580 return arr;
2581}
2582
2586static int
2587iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2588{
2589 struct iseq_insn_info_entry *insns_info;
2590 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2591 unsigned int *positions;
2592 LINK_ELEMENT *list;
2593 VALUE *generated_iseq;
2594 rb_event_flag_t events = 0;
2595 long data = 0;
2596
2597 int insn_num, code_index, insns_info_index, sp = 0;
2598 int stack_max = fix_sp_depth(iseq, anchor);
2599
2600 if (stack_max < 0) return COMPILE_NG;
2601
2602 /* fix label position */
2603 insn_num = code_index = 0;
2604 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2605 switch (list->type) {
2606 case ISEQ_ELEMENT_INSN:
2607 {
2608 INSN *iobj = (INSN *)list;
2609 /* update sp */
2610 sp = calc_sp_depth(sp, iobj);
2611 insn_num++;
2612 events = iobj->insn_info.events |= events;
2613 if (ISEQ_COVERAGE(iseq)) {
2614 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2615 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2616 int line = iobj->insn_info.line_no - 1;
2617 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2618 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2619 }
2620 }
2621 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2622 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2623 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2624 }
2625 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2626 }
2627 }
2628 code_index += insn_data_length(iobj);
2629 events = 0;
2630 data = 0;
2631 break;
2632 }
2633 case ISEQ_ELEMENT_LABEL:
2634 {
2635 LABEL *lobj = (LABEL *)list;
2636 lobj->position = code_index;
2637 if (lobj->sp != sp) {
2638 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2639 RSTRING_PTR(rb_iseq_path(iseq)),
2640 lobj->label_no, lobj->sp, sp);
2641 }
2642 sp = lobj->sp;
2643 break;
2644 }
2645 case ISEQ_ELEMENT_TRACE:
2646 {
2647 TRACE *trace = (TRACE *)list;
2648 events |= trace->event;
2649 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2650 break;
2651 }
2652 case ISEQ_ELEMENT_ADJUST:
2653 {
2654 ADJUST *adjust = (ADJUST *)list;
2655 if (adjust->line_no != -1) {
2656 int orig_sp = sp;
2657 sp = adjust->label ? adjust->label->sp : 0;
2658 if (orig_sp - sp > 0) {
2659 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2660 code_index++; /* insn */
2661 insn_num++;
2662 }
2663 }
2664 break;
2665 }
2666 default: break;
2667 }
2668 }
2669
2670 /* make instruction sequence */
2671 const int generated_iseq_size = code_index;
2672 generated_iseq = ALLOC_N(VALUE, code_index);
2673
2674 const int insns_info_size = insn_num;
2675 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2676
2677 const int positions_size = insn_num;
2678 positions = ALLOC_N(unsigned int, insn_num);
2679 if (ISEQ_IS_SIZE(body)) {
2680 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2681 }
2682 else {
2683 body->is_entries = NULL;
2684 }
2685
2686 if (body->ci_size) {
2687 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2688 }
2689 else {
2690 body->call_data = NULL;
2691 }
2692 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2693
2694 // Calculate the bitmask buffer size.
2695 // Round the generated_iseq size up to the nearest multiple
2696 // of the number of bits in an unsigned long.
2697
2698 // Allocate enough room for the bitmask list
2699 iseq_bits_t * mark_offset_bits;
2700 int code_size = code_index;
2701
2702 bool needs_bitmap = false;
2703
2704 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2705 if (mark_offset_bits_size == 1) {
2706 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2707 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2708 }
2709 else {
2710 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2711 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2712 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2713 }
2714
2715 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2716 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2717
2718 list = FIRST_ELEMENT(anchor);
2719 insns_info_index = code_index = sp = 0;
2720
2721 while (list) {
2722 switch (list->type) {
2723 case ISEQ_ELEMENT_INSN:
2724 {
2725 int j, len, insn;
2726 const char *types;
2727 VALUE *operands;
2728 INSN *iobj = (INSN *)list;
2729
2730 /* update sp */
2731 sp = calc_sp_depth(sp, iobj);
2732 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2733 operands = iobj->operands;
2734 insn = iobj->insn_id;
2735 generated_iseq[code_index] = insn;
2736 types = insn_op_types(insn);
2737 len = insn_len(insn);
2738
2739 for (j = 0; types[j]; j++) {
2740 char type = types[j];
2741
2742 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2743 switch (type) {
2744 case TS_OFFSET:
2745 {
2746 /* label(destination position) */
2747 LABEL *lobj = (LABEL *)operands[j];
2748 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2749 break;
2750 }
2751 case TS_CDHASH:
2752 {
2753 VALUE map = operands[j];
2754 struct cdhash_set_label_struct data;
2755 data.hash = map;
2756 data.pos = code_index;
2757 data.len = len;
2758 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2759
2760 rb_hash_rehash(map);
2761 freeze_hide_obj(map);
2763 generated_iseq[code_index + 1 + j] = map;
2764 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2765 RB_OBJ_WRITTEN(iseq, Qundef, map);
2766 needs_bitmap = true;
2767 break;
2768 }
2769 case TS_LINDEX:
2770 case TS_NUM: /* ulong */
2771 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2772 break;
2773 case TS_ISEQ: /* iseq */
2774 case TS_VALUE: /* VALUE */
2775 {
2776 VALUE v = operands[j];
2777 generated_iseq[code_index + 1 + j] = v;
2778 /* to mark ruby object */
2779 if (!SPECIAL_CONST_P(v)) {
2780 RB_OBJ_WRITTEN(iseq, Qundef, v);
2781 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2782 needs_bitmap = true;
2783 }
2784 break;
2785 }
2786 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2787 case TS_IC: /* inline cache: constants */
2788 {
2789 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2790 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2791 if (UNLIKELY(ic_index >= body->ic_size)) {
2792 BADINSN_DUMP(anchor, &iobj->link, 0);
2793 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2794 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2795 ic_index, ISEQ_IS_SIZE(body));
2796 }
2797
2798 ic->segments = array_to_idlist(operands[j]);
2799
2800 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2801 }
2802 break;
2803 case TS_IVC: /* inline ivar cache */
2804 {
2805 unsigned int ic_index = FIX2UINT(operands[j]);
2806
2807 IVC cache = ((IVC)&body->is_entries[ic_index]);
2808
2809 if (insn == BIN(setinstancevariable)) {
2810 cache->iv_set_name = SYM2ID(operands[j - 1]);
2811 }
2812 else {
2813 cache->iv_set_name = 0;
2814 }
2815
2816 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2817 }
2818 case TS_ISE: /* inline storage entry: `once` insn */
2819 case TS_ICVARC: /* inline cvar cache */
2820 {
2821 unsigned int ic_index = FIX2UINT(operands[j]);
2822 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2823 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2824 BADINSN_DUMP(anchor, &iobj->link, 0);
2825 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2826 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2827 ic_index, ISEQ_IS_SIZE(body));
2828 }
2829 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2830
2831 break;
2832 }
2833 case TS_CALLDATA:
2834 {
2835 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2836 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2837 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2838 cd->ci = source_ci;
2839 cd->cc = vm_cc_empty();
2840 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2841 break;
2842 }
2843 case TS_ID: /* ID */
2844 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2845 break;
2846 case TS_FUNCPTR:
2847 generated_iseq[code_index + 1 + j] = operands[j];
2848 break;
2849 case TS_BUILTIN:
2850 generated_iseq[code_index + 1 + j] = operands[j];
2851 break;
2852 default:
2853 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2854 "unknown operand type: %c", type);
2855 return COMPILE_NG;
2856 }
2857 }
2858 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2859 code_index += len;
2860 break;
2861 }
2862 case ISEQ_ELEMENT_LABEL:
2863 {
2864 LABEL *lobj = (LABEL *)list;
2865 if (lobj->sp != sp) {
2866 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2867 RSTRING_PTR(rb_iseq_path(iseq)),
2868 lobj->label_no, lobj->sp, sp);
2869 }
2870 sp = lobj->sp;
2871 break;
2872 }
2873 case ISEQ_ELEMENT_ADJUST:
2874 {
2875 ADJUST *adjust = (ADJUST *)list;
2876 int orig_sp = sp;
2877
2878 if (adjust->label) {
2879 sp = adjust->label->sp;
2880 }
2881 else {
2882 sp = 0;
2883 }
2884
2885 if (adjust->line_no != -1) {
2886 const int diff = orig_sp - sp;
2887 if (diff > 0) {
2888 if (insns_info_index == 0) {
2889 COMPILE_ERROR(iseq, adjust->line_no,
2890 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2891 }
2892 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2893 }
2894 if (diff > 1) {
2895 generated_iseq[code_index++] = BIN(adjuststack);
2896 generated_iseq[code_index++] = orig_sp - sp;
2897 }
2898 else if (diff == 1) {
2899 generated_iseq[code_index++] = BIN(pop);
2900 }
2901 else if (diff < 0) {
2902 int label_no = adjust->label ? adjust->label->label_no : -1;
2903 SIZED_FREE_N(generated_iseq, generated_iseq_size);
2904 SIZED_FREE_N(insns_info, insns_info_size);
2905 SIZED_FREE_N(positions, positions_size);
2906 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2907 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
2908 }
2909 debug_list(anchor, list);
2910 COMPILE_ERROR(iseq, adjust->line_no,
2911 "iseq_set_sequence: adjust bug to %d %d < %d",
2912 label_no, orig_sp, sp);
2913 return COMPILE_NG;
2914 }
2915 }
2916 break;
2917 }
2918 default:
2919 /* ignore */
2920 break;
2921 }
2922 list = list->next;
2923 }
2924
2925 body->iseq_encoded = (void *)generated_iseq;
2926 body->iseq_size = code_index;
2927 body->stack_max = stack_max;
2928
2929 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2930 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2931 }
2932 else {
2933 if (needs_bitmap) {
2934 body->mark_bits.list = mark_offset_bits;
2935 }
2936 else {
2937 body->mark_bits.list = NULL;
2938 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2939 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
2940 }
2941 }
2942
2943 /* get rid of memory leak when REALLOC failed */
2944 body->insns_info.body = insns_info;
2945 body->insns_info.positions = positions;
2946
2947 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
2948 body->insns_info.body = insns_info;
2949 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
2950 body->insns_info.positions = positions;
2951 body->insns_info.size = insns_info_index;
2952
2953 return COMPILE_OK;
2954}
2955
2956static int
2957label_get_position(LABEL *lobj)
2958{
2959 return lobj->position;
2960}
2961
2962static int
2963label_get_sp(LABEL *lobj)
2964{
2965 return lobj->sp;
2966}
2967
2968static int
2969iseq_set_exception_table(rb_iseq_t *iseq)
2970{
2971 const VALUE *tptr, *ptr;
2972 unsigned int tlen, i;
2973 struct iseq_catch_table_entry *entry;
2974
2975 ISEQ_BODY(iseq)->catch_table = NULL;
2976
2977 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2978 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2979 tlen = (int)RARRAY_LEN(catch_table_ary);
2980 tptr = RARRAY_CONST_PTR(catch_table_ary);
2981
2982 if (tlen > 0) {
2983 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2984 table->size = tlen;
2985
2986 for (i = 0; i < table->size; i++) {
2987 int pos;
2988 ptr = RARRAY_CONST_PTR(tptr[i]);
2989 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2990 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2991 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2992 RUBY_ASSERT(pos >= 0);
2993 entry->start = (unsigned int)pos;
2994 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2995 RUBY_ASSERT(pos >= 0);
2996 entry->end = (unsigned int)pos;
2997 entry->iseq = (rb_iseq_t *)ptr[3];
2998 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2999
3000 /* stack depth */
3001 if (ptr[4]) {
3002 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3003 entry->cont = label_get_position(lobj);
3004 entry->sp = label_get_sp(lobj);
3005
3006 /* TODO: Dirty Hack! Fix me */
3007 if (entry->type == CATCH_TYPE_RESCUE ||
3008 entry->type == CATCH_TYPE_BREAK ||
3009 entry->type == CATCH_TYPE_NEXT) {
3010 RUBY_ASSERT(entry->sp > 0);
3011 entry->sp--;
3012 }
3013 }
3014 else {
3015 entry->cont = 0;
3016 }
3017 }
3018 ISEQ_BODY(iseq)->catch_table = table;
3019 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3020 }
3021
3022 RB_GC_GUARD(catch_table_ary);
3023
3024 return COMPILE_OK;
3025}
3026
3027/*
3028 * set optional argument table
3029 * def foo(a, b=expr1, c=expr2)
3030 * =>
3031 * b:
3032 * expr1
3033 * c:
3034 * expr2
3035 */
3036static int
3037iseq_set_optargs_table(rb_iseq_t *iseq)
3038{
3039 int i;
3040 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3041
3042 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3043 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3044 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3045 }
3046 }
3047 return COMPILE_OK;
3048}
3049
3050static LINK_ELEMENT *
3051get_destination_insn(INSN *iobj)
3052{
3053 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3054 LINK_ELEMENT *list;
3055 rb_event_flag_t events = 0;
3056
3057 list = lobj->link.next;
3058 while (list) {
3059 switch (list->type) {
3060 case ISEQ_ELEMENT_INSN:
3061 case ISEQ_ELEMENT_ADJUST:
3062 goto found;
3063 case ISEQ_ELEMENT_LABEL:
3064 /* ignore */
3065 break;
3066 case ISEQ_ELEMENT_TRACE:
3067 {
3068 TRACE *trace = (TRACE *)list;
3069 events |= trace->event;
3070 }
3071 break;
3072 default: break;
3073 }
3074 list = list->next;
3075 }
3076 found:
3077 if (list && IS_INSN(list)) {
3078 INSN *iobj = (INSN *)list;
3079 iobj->insn_info.events |= events;
3080 }
3081 return list;
3082}
3083
3084static LINK_ELEMENT *
3085get_next_insn(INSN *iobj)
3086{
3087 LINK_ELEMENT *list = iobj->link.next;
3088
3089 while (list) {
3090 if (IS_INSN(list) || IS_ADJUST(list)) {
3091 return list;
3092 }
3093 list = list->next;
3094 }
3095 return 0;
3096}
3097
3098static LINK_ELEMENT *
3099get_prev_insn(INSN *iobj)
3100{
3101 LINK_ELEMENT *list = iobj->link.prev;
3102
3103 while (list) {
3104 if (IS_INSN(list) || IS_ADJUST(list)) {
3105 return list;
3106 }
3107 list = list->prev;
3108 }
3109 return 0;
3110}
3111
3112static void
3113unref_destination(INSN *iobj, int pos)
3114{
3115 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3116 --lobj->refcnt;
3117 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3118}
3119
3120static bool
3121replace_destination(INSN *dobj, INSN *nobj)
3122{
3123 VALUE n = OPERAND_AT(nobj, 0);
3124 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3125 LABEL *nl = (LABEL *)n;
3126 if (dl == nl) return false;
3127 --dl->refcnt;
3128 ++nl->refcnt;
3129 OPERAND_AT(dobj, 0) = n;
3130 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3131 return true;
3132}
3133
3134static LABEL*
3135find_destination(INSN *i)
3136{
3137 int pos, len = insn_len(i->insn_id);
3138 for (pos = 0; pos < len; ++pos) {
3139 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3140 return (LABEL *)OPERAND_AT(i, pos);
3141 }
3142 }
3143 return 0;
3144}
3145
3146static int
3147remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3148{
3149 LINK_ELEMENT *first = i, *end;
3150 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3151
3152 if (!i) return 0;
3153 unref_counts = ALLOCA_N(int, nlabels);
3154 MEMZERO(unref_counts, int, nlabels);
3155 end = i;
3156 do {
3157 LABEL *lab;
3158 if (IS_INSN(i)) {
3159 if (IS_INSN_ID(i, leave)) {
3160 end = i;
3161 break;
3162 }
3163 else if ((lab = find_destination((INSN *)i)) != 0) {
3164 unref_counts[lab->label_no]++;
3165 }
3166 }
3167 else if (IS_LABEL(i)) {
3168 lab = (LABEL *)i;
3169 if (lab->unremovable) return 0;
3170 if (lab->refcnt > unref_counts[lab->label_no]) {
3171 if (i == first) return 0;
3172 break;
3173 }
3174 continue;
3175 }
3176 else if (IS_TRACE(i)) {
3177 /* do nothing */
3178 }
3179 else if (IS_ADJUST(i)) {
3180 return 0;
3181 }
3182 end = i;
3183 } while ((i = i->next) != 0);
3184 i = first;
3185 do {
3186 if (IS_INSN(i)) {
3187 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3188 VALUE insn = INSN_OF(i);
3189 int pos, len = insn_len(insn);
3190 for (pos = 0; pos < len; ++pos) {
3191 switch (insn_op_types(insn)[pos]) {
3192 case TS_OFFSET:
3193 unref_destination((INSN *)i, pos);
3194 break;
3195 case TS_CALLDATA:
3196 --(body->ci_size);
3197 break;
3198 }
3199 }
3200 }
3201 ELEM_REMOVE(i);
3202 } while ((i != end) && (i = i->next) != 0);
3203 return 1;
3204}
3205
3206static int
3207iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3208{
3209 switch (OPERAND_AT(iobj, 0)) {
3210 case INT2FIX(0): /* empty array */
3211 ELEM_REMOVE(&iobj->link);
3212 return TRUE;
3213 case INT2FIX(1): /* single element array */
3214 ELEM_REMOVE(&iobj->link);
3215 return FALSE;
3216 default:
3217 iobj->insn_id = BIN(adjuststack);
3218 return TRUE;
3219 }
3220}
3221
3222static int
3223is_frozen_putstring(INSN *insn, VALUE *op)
3224{
3225 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3226 *op = OPERAND_AT(insn, 0);
3227 return 1;
3228 }
3229 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3230 *op = OPERAND_AT(insn, 0);
3231 return RB_TYPE_P(*op, T_STRING);
3232 }
3233 return 0;
3234}
3235
3236static int
3237insn_has_label_before(LINK_ELEMENT *elem)
3238{
3239 LINK_ELEMENT *prev = elem->prev;
3240 while (prev) {
3241 if (prev->type == ISEQ_ELEMENT_LABEL) {
3242 LABEL *label = (LABEL *)prev;
3243 if (label->refcnt > 0) {
3244 return 1;
3245 }
3246 }
3247 else if (prev->type == ISEQ_ELEMENT_INSN) {
3248 break;
3249 }
3250 prev = prev->prev;
3251 }
3252 return 0;
3253}
3254
3255static int
3256optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3257{
3258 /*
3259 * putobject obj
3260 * dup
3261 * checktype T_XXX
3262 * branchif l1
3263 * l2:
3264 * ...
3265 * l1:
3266 *
3267 * => obj is a T_XXX
3268 *
3269 * putobject obj (T_XXX)
3270 * jump L1
3271 * L1:
3272 *
3273 * => obj is not a T_XXX
3274 *
3275 * putobject obj (T_XXX)
3276 * jump L2
3277 * L2:
3278 */
3279 int line, node_id;
3280 INSN *niobj, *ciobj, *dup = 0;
3281 LABEL *dest = 0;
3282 VALUE type;
3283
3284 switch (INSN_OF(iobj)) {
3285 case BIN(putstring):
3286 case BIN(putchilledstring):
3288 break;
3289 case BIN(putnil):
3290 type = INT2FIX(T_NIL);
3291 break;
3292 case BIN(putobject):
3293 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3294 break;
3295 default: return FALSE;
3296 }
3297
3298 ciobj = (INSN *)get_next_insn(iobj);
3299 if (IS_INSN_ID(ciobj, jump)) {
3300 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3301 }
3302 if (IS_INSN_ID(ciobj, dup)) {
3303 ciobj = (INSN *)get_next_insn(dup = ciobj);
3304 }
3305 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3306 niobj = (INSN *)get_next_insn(ciobj);
3307 if (!niobj) {
3308 /* TODO: putobject true/false */
3309 return FALSE;
3310 }
3311 switch (INSN_OF(niobj)) {
3312 case BIN(branchif):
3313 if (OPERAND_AT(ciobj, 0) == type) {
3314 dest = (LABEL *)OPERAND_AT(niobj, 0);
3315 }
3316 break;
3317 case BIN(branchunless):
3318 if (OPERAND_AT(ciobj, 0) != type) {
3319 dest = (LABEL *)OPERAND_AT(niobj, 0);
3320 }
3321 break;
3322 default:
3323 return FALSE;
3324 }
3325 line = ciobj->insn_info.line_no;
3326 node_id = ciobj->insn_info.node_id;
3327 if (!dest) {
3328 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3329 dest = (LABEL *)niobj->link.next; /* reuse label */
3330 }
3331 else {
3332 dest = NEW_LABEL(line);
3333 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3334 }
3335 }
3336 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3337 LABEL_REF(dest);
3338 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3339 return TRUE;
3340}
3341
3342static const struct rb_callinfo *
3343ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3344{
3345 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3346 vm_ci_flag(ci) | add,
3347 vm_ci_argc(ci),
3348 vm_ci_kwarg(ci));
3349 RB_OBJ_WRITTEN(iseq, ci, nci);
3350 return nci;
3351}
3352
3353static const struct rb_callinfo *
3354ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3355{
3356 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3357 vm_ci_flag(ci),
3358 argc,
3359 vm_ci_kwarg(ci));
3360 RB_OBJ_WRITTEN(iseq, ci, nci);
3361 return nci;
3362}
3363
3364#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3365
3366static int
3367iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3368{
3369 INSN *const iobj = (INSN *)list;
3370
3371 again:
3372 optimize_checktype(iseq, iobj);
3373
3374 if (IS_INSN_ID(iobj, jump)) {
3375 INSN *niobj, *diobj, *piobj;
3376 diobj = (INSN *)get_destination_insn(iobj);
3377 niobj = (INSN *)get_next_insn(iobj);
3378
3379 if (diobj == niobj) {
3380 /*
3381 * jump LABEL
3382 * LABEL:
3383 * =>
3384 * LABEL:
3385 */
3386 unref_destination(iobj, 0);
3387 ELEM_REMOVE(&iobj->link);
3388 return COMPILE_OK;
3389 }
3390 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3391 IS_INSN_ID(diobj, jump) &&
3392 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3393 diobj->insn_info.events == 0) {
3394 /*
3395 * useless jump elimination:
3396 * jump LABEL1
3397 * ...
3398 * LABEL1:
3399 * jump LABEL2
3400 *
3401 * => in this case, first jump instruction should jump to
3402 * LABEL2 directly
3403 */
3404 if (replace_destination(iobj, diobj)) {
3405 remove_unreachable_chunk(iseq, iobj->link.next);
3406 goto again;
3407 }
3408 }
3409 else if (IS_INSN_ID(diobj, leave)) {
3410 /*
3411 * jump LABEL
3412 * ...
3413 * LABEL:
3414 * leave
3415 * =>
3416 * leave
3417 * ...
3418 * LABEL:
3419 * leave
3420 */
3421 /* replace */
3422 unref_destination(iobj, 0);
3423 iobj->insn_id = BIN(leave);
3424 iobj->operand_size = 0;
3425 iobj->insn_info = diobj->insn_info;
3426 goto again;
3427 }
3428 else if (IS_INSN(iobj->link.prev) &&
3429 (piobj = (INSN *)iobj->link.prev) &&
3430 (IS_INSN_ID(piobj, branchif) ||
3431 IS_INSN_ID(piobj, branchunless))) {
3432 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3433 if (niobj == pdiobj) {
3434 int refcnt = IS_LABEL(piobj->link.next) ?
3435 ((LABEL *)piobj->link.next)->refcnt : 0;
3436 /*
3437 * useless jump elimination (if/unless destination):
3438 * if L1
3439 * jump L2
3440 * L1:
3441 * ...
3442 * L2:
3443 *
3444 * ==>
3445 * unless L2
3446 * L1:
3447 * ...
3448 * L2:
3449 */
3450 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3451 ? BIN(branchunless) : BIN(branchif);
3452 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3453 ELEM_REMOVE(&iobj->link);
3454 }
3455 else {
3456 /* TODO: replace other branch destinations too */
3457 }
3458 return COMPILE_OK;
3459 }
3460 else if (diobj == pdiobj) {
3461 /*
3462 * useless jump elimination (if/unless before jump):
3463 * L1:
3464 * ...
3465 * if L1
3466 * jump L1
3467 *
3468 * ==>
3469 * L1:
3470 * ...
3471 * pop
3472 * jump L1
3473 */
3474 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3475 ELEM_REPLACE(&piobj->link, &popiobj->link);
3476 }
3477 }
3478 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3479 goto again;
3480 }
3481 }
3482
3483 /*
3484 * putstring "beg"
3485 * putstring "end"
3486 * newrange excl
3487 *
3488 * ==>
3489 *
3490 * putobject "beg".."end"
3491 */
3492 if (IS_INSN_ID(iobj, newrange)) {
3493 INSN *const range = iobj;
3494 INSN *beg, *end;
3495 VALUE str_beg, str_end;
3496
3497 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3498 is_frozen_putstring(end, &str_end) &&
3499 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3500 is_frozen_putstring(beg, &str_beg) &&
3501 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3502 int excl = FIX2INT(OPERAND_AT(range, 0));
3503 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3504
3505 ELEM_REMOVE(&beg->link);
3506 ELEM_REMOVE(&end->link);
3507 range->insn_id = BIN(putobject);
3508 OPERAND_AT(range, 0) = lit_range;
3509 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3510 }
3511 }
3512
3513 if (IS_INSN_ID(iobj, leave)) {
3514 remove_unreachable_chunk(iseq, iobj->link.next);
3515 }
3516
3517 /*
3518 * ...
3519 * duparray [...]
3520 * concatarray | concattoarray
3521 * =>
3522 * ...
3523 * putobject [...]
3524 * concatarray | concattoarray
3525 */
3526 if (IS_INSN_ID(iobj, duparray)) {
3527 LINK_ELEMENT *next = iobj->link.next;
3528 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3529 iobj->insn_id = BIN(putobject);
3530 }
3531 }
3532
3533 /*
3534 * duparray [...]
3535 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3536 * =>
3537 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3538 */
3539 if (IS_INSN_ID(iobj, duparray)) {
3540 LINK_ELEMENT *next = iobj->link.next;
3541 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3542 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3543 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3544
3545 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3546 VALUE ary = iobj->operands[0];
3548
3549 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3550 ELEM_REMOVE(next);
3551 }
3552 }
3553 }
3554
3555 /*
3556 * duphash {...}
3557 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3558 * =>
3559 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3560 */
3561 if (IS_INSN_ID(iobj, duphash)) {
3562 LINK_ELEMENT *next = iobj->link.next;
3563 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3564 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3565 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3566
3567 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3568 VALUE hash = iobj->operands[0];
3569 rb_obj_reveal(hash, rb_cHash);
3570 RB_OBJ_SET_SHAREABLE(hash);
3571
3572 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3573 ELEM_REMOVE(next);
3574 }
3575 }
3576 }
3577
3578 /*
3579 * newarray 0
3580 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3581 * =>
3582 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3583 */
3584 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3585 LINK_ELEMENT *next = iobj->link.next;
3586 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3587 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3588 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3589
3590 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3591 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3592 ELEM_REMOVE(next);
3593 }
3594 }
3595 }
3596
3597 /*
3598 * newhash 0
3599 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3600 * =>
3601 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3602 */
3603 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3604 LINK_ELEMENT *next = iobj->link.next;
3605 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3606 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3607 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3608
3609 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3610 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3611 ELEM_REMOVE(next);
3612 }
3613 }
3614 }
3615
3616 if (IS_INSN_ID(iobj, branchif) ||
3617 IS_INSN_ID(iobj, branchnil) ||
3618 IS_INSN_ID(iobj, branchunless)) {
3619 /*
3620 * if L1
3621 * ...
3622 * L1:
3623 * jump L2
3624 * =>
3625 * if L2
3626 */
3627 INSN *nobj = (INSN *)get_destination_insn(iobj);
3628
3629 /* This is super nasty hack!!!
3630 *
3631 * This jump-jump optimization may ignore event flags of the jump
3632 * instruction being skipped. Actually, Line 2 TracePoint event
3633 * is never fired in the following code:
3634 *
3635 * 1: raise if 1 == 2
3636 * 2: while true
3637 * 3: break
3638 * 4: end
3639 *
3640 * This is critical for coverage measurement. [Bug #15980]
3641 *
3642 * This is a stopgap measure: stop the jump-jump optimization if
3643 * coverage measurement is enabled and if the skipped instruction
3644 * has any event flag.
3645 *
3646 * Note that, still, TracePoint Line event does not occur on Line 2.
3647 * This should be fixed in future.
3648 */
3649 int stop_optimization =
3650 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3651 nobj->link.type == ISEQ_ELEMENT_INSN &&
3652 nobj->insn_info.events;
3653 if (!stop_optimization) {
3654 INSN *pobj = (INSN *)iobj->link.prev;
3655 int prev_dup = 0;
3656 if (pobj) {
3657 if (!IS_INSN(&pobj->link))
3658 pobj = 0;
3659 else if (IS_INSN_ID(pobj, dup))
3660 prev_dup = 1;
3661 }
3662
3663 for (;;) {
3664 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3665 if (!replace_destination(iobj, nobj)) break;
3666 }
3667 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3668 !!(nobj = (INSN *)nobj->link.next) &&
3669 /* basic blocks, with no labels in the middle */
3670 nobj->insn_id == iobj->insn_id) {
3671 /*
3672 * dup
3673 * if L1
3674 * ...
3675 * L1:
3676 * dup
3677 * if L2
3678 * =>
3679 * dup
3680 * if L2
3681 * ...
3682 * L1:
3683 * dup
3684 * if L2
3685 */
3686 if (!replace_destination(iobj, nobj)) break;
3687 }
3688 else if (pobj) {
3689 /*
3690 * putnil
3691 * if L1
3692 * =>
3693 * # nothing
3694 *
3695 * putobject true
3696 * if L1
3697 * =>
3698 * jump L1
3699 *
3700 * putstring ".."
3701 * if L1
3702 * =>
3703 * jump L1
3704 *
3705 * putstring ".."
3706 * dup
3707 * if L1
3708 * =>
3709 * putstring ".."
3710 * jump L1
3711 *
3712 */
3713 int cond;
3714 if (prev_dup && IS_INSN(pobj->link.prev)) {
3715 pobj = (INSN *)pobj->link.prev;
3716 }
3717 if (IS_INSN_ID(pobj, putobject)) {
3718 cond = (IS_INSN_ID(iobj, branchif) ?
3719 OPERAND_AT(pobj, 0) != Qfalse :
3720 IS_INSN_ID(iobj, branchunless) ?
3721 OPERAND_AT(pobj, 0) == Qfalse :
3722 FALSE);
3723 }
3724 else if (IS_INSN_ID(pobj, putstring) ||
3725 IS_INSN_ID(pobj, duparray) ||
3726 IS_INSN_ID(pobj, newarray)) {
3727 cond = IS_INSN_ID(iobj, branchif);
3728 }
3729 else if (IS_INSN_ID(pobj, putnil)) {
3730 cond = !IS_INSN_ID(iobj, branchif);
3731 }
3732 else break;
3733 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3734 ELEM_REMOVE(iobj->link.prev);
3735 }
3736 else if (!iseq_pop_newarray(iseq, pobj)) {
3737 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3738 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3739 }
3740 if (cond) {
3741 if (prev_dup) {
3742 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3743 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3744 }
3745 iobj->insn_id = BIN(jump);
3746 goto again;
3747 }
3748 else {
3749 unref_destination(iobj, 0);
3750 ELEM_REMOVE(&iobj->link);
3751 }
3752 break;
3753 }
3754 else break;
3755 nobj = (INSN *)get_destination_insn(nobj);
3756 }
3757 }
3758 }
3759
3760 if (IS_INSN_ID(iobj, pop)) {
3761 /*
3762 * putself / putnil / putobject obj / putstring "..."
3763 * pop
3764 * =>
3765 * # do nothing
3766 */
3767 LINK_ELEMENT *prev = iobj->link.prev;
3768 if (IS_INSN(prev)) {
3769 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3770 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3771 previ == BIN(putself) || previ == BIN(putstring) ||
3772 previ == BIN(putchilledstring) ||
3773 previ == BIN(dup) ||
3774 previ == BIN(getlocal) ||
3775 previ == BIN(getblockparam) ||
3776 previ == BIN(getblockparamproxy) ||
3777 previ == BIN(getinstancevariable) ||
3778 previ == BIN(duparray)) {
3779 /* just push operand or static value and pop soon, no
3780 * side effects */
3781 ELEM_REMOVE(prev);
3782 ELEM_REMOVE(&iobj->link);
3783 }
3784 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3785 ELEM_REMOVE(&iobj->link);
3786 }
3787 else if (previ == BIN(concatarray)) {
3788 INSN *piobj = (INSN *)prev;
3789 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3790 INSN_OF(piobj) = BIN(pop);
3791 }
3792 else if (previ == BIN(concatstrings)) {
3793 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3794 ELEM_REMOVE(prev);
3795 }
3796 else {
3797 ELEM_REMOVE(&iobj->link);
3798 INSN_OF(prev) = BIN(adjuststack);
3799 }
3800 }
3801 }
3802 }
3803
3804 if (IS_INSN_ID(iobj, newarray) ||
3805 IS_INSN_ID(iobj, duparray) ||
3806 IS_INSN_ID(iobj, concatarray) ||
3807 IS_INSN_ID(iobj, splatarray) ||
3808 0) {
3809 /*
3810 * newarray N
3811 * splatarray
3812 * =>
3813 * newarray N
3814 * newarray always puts an array
3815 */
3816 LINK_ELEMENT *next = iobj->link.next;
3817 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3818 /* remove splatarray following always-array insn */
3819 ELEM_REMOVE(next);
3820 }
3821 }
3822
3823 if (IS_INSN_ID(iobj, newarray)) {
3824 LINK_ELEMENT *next = iobj->link.next;
3825 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3826 OPERAND_AT(next, 1) == INT2FIX(0)) {
3827 VALUE op1, op2;
3828 op1 = OPERAND_AT(iobj, 0);
3829 op2 = OPERAND_AT(next, 0);
3830 ELEM_REMOVE(next);
3831
3832 if (op1 == op2) {
3833 /*
3834 * newarray 2
3835 * expandarray 2, 0
3836 * =>
3837 * swap
3838 */
3839 if (op1 == INT2FIX(2)) {
3840 INSN_OF(iobj) = BIN(swap);
3841 iobj->operand_size = 0;
3842 }
3843 /*
3844 * newarray X
3845 * expandarray X, 0
3846 * =>
3847 * opt_reverse X
3848 */
3849 else {
3850 INSN_OF(iobj) = BIN(opt_reverse);
3851 }
3852 }
3853 else {
3854 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3855 INSN_OF(iobj) = BIN(opt_reverse);
3856 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3857
3858 if (op1 > op2) {
3859 /* X > Y
3860 * newarray X
3861 * expandarray Y, 0
3862 * =>
3863 * pop * (Y-X)
3864 * opt_reverse Y
3865 */
3866 for (; diff > 0; diff--) {
3867 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3868 }
3869 }
3870 else { /* (op1 < op2) */
3871 /* X < Y
3872 * newarray X
3873 * expandarray Y, 0
3874 * =>
3875 * putnil * (Y-X)
3876 * opt_reverse Y
3877 */
3878 for (; diff < 0; diff++) {
3879 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3880 }
3881 }
3882 }
3883 }
3884 }
3885
3886 if (IS_INSN_ID(iobj, duparray)) {
3887 LINK_ELEMENT *next = iobj->link.next;
3888 /*
3889 * duparray obj
3890 * expandarray X, 0
3891 * =>
3892 * putobject obj
3893 * expandarray X, 0
3894 */
3895 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3896 INSN_OF(iobj) = BIN(putobject);
3897 }
3898 }
3899
3900 if (IS_INSN_ID(iobj, anytostring)) {
3901 LINK_ELEMENT *next = iobj->link.next;
3902 /*
3903 * anytostring
3904 * concatstrings 1
3905 * =>
3906 * anytostring
3907 */
3908 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3909 OPERAND_AT(next, 0) == INT2FIX(1)) {
3910 ELEM_REMOVE(next);
3911 }
3912 }
3913
3914 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3915 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3916 /*
3917 * putstring ""
3918 * concatstrings N
3919 * =>
3920 * concatstrings N-1
3921 */
3922 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3923 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3924 INSN *next = (INSN *)iobj->link.next;
3925 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3926 ELEM_REMOVE(&next->link);
3927 }
3928 ELEM_REMOVE(&iobj->link);
3929 }
3930 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3931 INSN *next = (INSN *)iobj->link.next;
3932 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3933 VALUE src = OPERAND_AT(iobj, 0);
3934 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3935 VALUE path = rb_iseq_path(iseq);
3936 int line = iobj->insn_info.line_no;
3937 VALUE errinfo = rb_errinfo();
3938 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3939 if (NIL_P(re)) {
3940 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3941 rb_set_errinfo(errinfo);
3942 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3943 }
3944 else {
3945 RB_OBJ_SET_SHAREABLE(re);
3946 }
3947 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3948 ELEM_REMOVE(iobj->link.next);
3949 }
3950 }
3951 }
3952
3953 if (IS_INSN_ID(iobj, concatstrings)) {
3954 /*
3955 * concatstrings N
3956 * concatstrings M
3957 * =>
3958 * concatstrings N+M-1
3959 */
3960 LINK_ELEMENT *next = iobj->link.next;
3961 INSN *jump = 0;
3962 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3963 next = get_destination_insn(jump = (INSN *)next);
3964 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3965 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3966 OPERAND_AT(iobj, 0) = INT2FIX(n);
3967 if (jump) {
3968 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3969 if (!--label->refcnt) {
3970 ELEM_REMOVE(&label->link);
3971 }
3972 else {
3973 label = NEW_LABEL(0);
3974 OPERAND_AT(jump, 0) = (VALUE)label;
3975 }
3976 label->refcnt++;
3977 ELEM_INSERT_NEXT(next, &label->link);
3978 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3979 }
3980 else {
3981 ELEM_REMOVE(next);
3982 }
3983 }
3984 }
3985
3986 if (do_tailcallopt &&
3987 (IS_INSN_ID(iobj, send) ||
3988 IS_INSN_ID(iobj, invokesuper))) {
3989 /*
3990 * send ...
3991 * leave
3992 * =>
3993 * send ..., ... | VM_CALL_TAILCALL, ...
3994 * leave # unreachable
3995 */
3996 INSN *piobj = NULL;
3997 if (iobj->link.next) {
3998 LINK_ELEMENT *next = iobj->link.next;
3999 do {
4000 if (!IS_INSN(next)) {
4001 next = next->next;
4002 continue;
4003 }
4004 switch (INSN_OF(next)) {
4005 case BIN(nop):
4006 next = next->next;
4007 break;
4008 case BIN(jump):
4009 /* if cond
4010 * return tailcall
4011 * end
4012 */
4013 next = get_destination_insn((INSN *)next);
4014 break;
4015 case BIN(leave):
4016 piobj = iobj;
4017 /* fall through */
4018 default:
4019 next = NULL;
4020 break;
4021 }
4022 } while (next);
4023 }
4024
4025 if (piobj) {
4026 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4027 if (IS_INSN_ID(piobj, send) ||
4028 IS_INSN_ID(piobj, invokesuper)) {
4029 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4030 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4031 OPERAND_AT(piobj, 0) = (VALUE)ci;
4032 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4033 }
4034 }
4035 else {
4036 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4037 OPERAND_AT(piobj, 0) = (VALUE)ci;
4038 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4039 }
4040 }
4041 }
4042
4043 if (IS_INSN_ID(iobj, dup)) {
4044 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4045 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4046
4047 /*
4048 * dup
4049 * setlocal x, y
4050 * setlocal x, y
4051 * =>
4052 * dup
4053 * setlocal x, y
4054 */
4055 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4056 set2 = set1->next;
4057 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4058 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4059 ELEM_REMOVE(set1);
4060 ELEM_REMOVE(&iobj->link);
4061 }
4062 }
4063
4064 /*
4065 * dup
4066 * setlocal x, y
4067 * dup
4068 * setlocal x, y
4069 * =>
4070 * dup
4071 * setlocal x, y
4072 */
4073 else if (IS_NEXT_INSN_ID(set1, dup) &&
4074 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4075 set2 = set1->next->next;
4076 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4077 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4078 ELEM_REMOVE(set1->next);
4079 ELEM_REMOVE(set2);
4080 }
4081 }
4082 }
4083 }
4084
4085 /*
4086 * getlocal x, y
4087 * dup
4088 * setlocal x, y
4089 * =>
4090 * dup
4091 */
4092 if (IS_INSN_ID(iobj, getlocal)) {
4093 LINK_ELEMENT *niobj = &iobj->link;
4094 if (IS_NEXT_INSN_ID(niobj, dup)) {
4095 niobj = niobj->next;
4096 }
4097 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4098 LINK_ELEMENT *set1 = niobj->next;
4099 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4100 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4101 ELEM_REMOVE(set1);
4102 ELEM_REMOVE(niobj);
4103 }
4104 }
4105 }
4106
4107 /*
4108 * opt_invokebuiltin_delegate
4109 * trace
4110 * leave
4111 * =>
4112 * opt_invokebuiltin_delegate_leave
4113 * trace
4114 * leave
4115 */
4116 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4117 if (IS_TRACE(iobj->link.next)) {
4118 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4119 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4120 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4121 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4122 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4123 }
4124 }
4125 }
4126 }
4127
4128 /*
4129 * getblockparam
4130 * branchif / branchunless
4131 * =>
4132 * getblockparamproxy
4133 * branchif / branchunless
4134 */
4135 if (IS_INSN_ID(iobj, getblockparam)) {
4136 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4137 iobj->insn_id = BIN(getblockparamproxy);
4138 }
4139 }
4140
4141 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4142 LINK_ELEMENT *niobj = &iobj->link;
4143 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4144 niobj = niobj->next;
4145 LINK_ELEMENT *siobj;
4146 unsigned int set_flags = 0, unset_flags = 0;
4147
4148 /*
4149 * Eliminate hash allocation for f(*a, kw: 1)
4150 *
4151 * splatarray false
4152 * duphash
4153 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4154 * =>
4155 * splatarray false
4156 * putobject
4157 * send ARGS_SPLAT|KW_SPLAT
4158 */
4159 if (IS_NEXT_INSN_ID(niobj, send)) {
4160 siobj = niobj->next;
4161 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4162 unset_flags = VM_CALL_ARGS_BLOCKARG;
4163 }
4164 /*
4165 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4166 *
4167 * splatarray false
4168 * duphash
4169 * getlocal / getinstancevariable / getblockparamproxy
4170 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4171 * =>
4172 * splatarray false
4173 * putobject
4174 * getlocal / getinstancevariable / getblockparamproxy
4175 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4176 */
4177 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4178 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4179 siobj = niobj->next->next;
4180 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4181 }
4182
4183 if (set_flags) {
4184 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4185 unsigned int flags = vm_ci_flag(ci);
4186 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4187 ((INSN*)niobj)->insn_id = BIN(putobject);
4188 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4189
4190 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4191 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4192 RB_OBJ_WRITTEN(iseq, ci, nci);
4193 OPERAND_AT(siobj, 0) = (VALUE)nci;
4194 }
4195 }
4196 }
4197 }
4198
4199 return COMPILE_OK;
4200}
4201
4202static int
4203insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4204{
4205 if (insn_id == BIN(opt_neq)) {
4206 VALUE original_ci = iobj->operands[0];
4207 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4208 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4209 }
4210 else {
4211 iobj->insn_id = insn_id;
4212 iobj->operand_size = insn_len(insn_id) - 1;
4213 }
4214 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4215
4216 return COMPILE_OK;
4217}
4218
4219static int
4220iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4221{
4222 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4223 IS_INSN(iobj->link.next)) {
4224 /*
4225 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4226 */
4227 INSN *niobj = (INSN *)iobj->link.next;
4228 if (IS_INSN_ID(niobj, send)) {
4229 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4230 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4231 VALUE method = INT2FIX(0);
4232 switch (vm_ci_mid(ci)) {
4233 case idMax:
4234 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4235 break;
4236 case idMin:
4237 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4238 break;
4239 case idHash:
4240 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4241 break;
4242 }
4243
4244 if (method != INT2FIX(0)) {
4245 VALUE num = iobj->operands[0];
4246 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4247 ELEM_REMOVE(&niobj->link);
4248 return COMPILE_OK;
4249 }
4250 }
4251 }
4252 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4253 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4254 IS_NEXT_INSN_ID(&niobj->link, send)) {
4255 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4256 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4257 VALUE num = iobj->operands[0];
4258 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4259 ELEM_REMOVE(&iobj->link);
4260 ELEM_REMOVE(niobj->link.next);
4261 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4262 return COMPILE_OK;
4263 }
4264 }
4265 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4266 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4267 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4268 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4269 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4270 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4271 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4272 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4273 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4274 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4275 VALUE num = iobj->operands[0];
4276 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4277 // Remove the "send" insn.
4278 ELEM_REMOVE((niobj->link.next)->next);
4279 // Remove the modified insn from its original "newarray" position...
4280 ELEM_REMOVE(&iobj->link);
4281 // and insert it after the buffer insn.
4282 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4283 return COMPILE_OK;
4284 }
4285 }
4286
4287 // Break the "else if" chain since some prior checks abort after sub-ifs.
4288 // We already found "newarray". To match `[...].include?(arg)` we look for
4289 // the instruction(s) representing the argument followed by a "send".
4290 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4291 IS_INSN_ID(niobj, putobject) ||
4292 IS_INSN_ID(niobj, putself) ||
4293 IS_INSN_ID(niobj, getlocal) ||
4294 IS_INSN_ID(niobj, getinstancevariable)) &&
4295 IS_NEXT_INSN_ID(&niobj->link, send)) {
4296
4297 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4298 const struct rb_callinfo *ci;
4299 // Allow any number (0 or more) of simple method calls on the argument
4300 // (as in `[...].include?(arg.method1.method2)`.
4301 do {
4302 sendobj = sendobj->next;
4303 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4304 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4305
4306 // If this send is for .include? with one arg we can do our opt.
4307 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4308 VALUE num = iobj->operands[0];
4309 INSN *sendins = (INSN *)sendobj;
4310 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4311 // Remove the original "newarray" insn.
4312 ELEM_REMOVE(&iobj->link);
4313 return COMPILE_OK;
4314 }
4315 }
4316 }
4317
4318 /*
4319 * duparray [...]
4320 * some insn for the arg...
4321 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4322 * =>
4323 * arg insn...
4324 * opt_duparray_send [...], :include?, 1
4325 */
4326 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4327 INSN *niobj = (INSN *)iobj->link.next;
4328 if ((IS_INSN_ID(niobj, getlocal) ||
4329 IS_INSN_ID(niobj, getinstancevariable) ||
4330 IS_INSN_ID(niobj, putself)) &&
4331 IS_NEXT_INSN_ID(&niobj->link, send)) {
4332
4333 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4334 const struct rb_callinfo *ci;
4335 // Allow any number (0 or more) of simple method calls on the argument
4336 // (as in `[...].include?(arg.method1.method2)`.
4337 do {
4338 sendobj = sendobj->next;
4339 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4340 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4341
4342 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4343 // Move the array arg from duparray to opt_duparray_send.
4344 VALUE ary = iobj->operands[0];
4346
4347 INSN *sendins = (INSN *)sendobj;
4348 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4349
4350 // Remove the duparray insn.
4351 ELEM_REMOVE(&iobj->link);
4352 return COMPILE_OK;
4353 }
4354 }
4355 }
4356
4357
4358 if (IS_INSN_ID(iobj, send)) {
4359 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4360 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4361
4362#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4363 if (vm_ci_simple(ci)) {
4364 switch (vm_ci_argc(ci)) {
4365 case 0:
4366 switch (vm_ci_mid(ci)) {
4367 case idLength: SP_INSN(length); return COMPILE_OK;
4368 case idSize: SP_INSN(size); return COMPILE_OK;
4369 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4370 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4371 case idSucc: SP_INSN(succ); return COMPILE_OK;
4372 case idNot: SP_INSN(not); return COMPILE_OK;
4373 }
4374 break;
4375 case 1:
4376 switch (vm_ci_mid(ci)) {
4377 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4378 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4379 case idMULT: SP_INSN(mult); return COMPILE_OK;
4380 case idDIV: SP_INSN(div); return COMPILE_OK;
4381 case idMOD: SP_INSN(mod); return COMPILE_OK;
4382 case idEq: SP_INSN(eq); return COMPILE_OK;
4383 case idNeq: SP_INSN(neq); return COMPILE_OK;
4384 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4385 case idLT: SP_INSN(lt); return COMPILE_OK;
4386 case idLE: SP_INSN(le); return COMPILE_OK;
4387 case idGT: SP_INSN(gt); return COMPILE_OK;
4388 case idGE: SP_INSN(ge); return COMPILE_OK;
4389 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4390 case idAREF: SP_INSN(aref); return COMPILE_OK;
4391 case idAnd: SP_INSN(and); return COMPILE_OK;
4392 case idOr: SP_INSN(or); return COMPILE_OK;
4393 }
4394 break;
4395 case 2:
4396 switch (vm_ci_mid(ci)) {
4397 case idASET: SP_INSN(aset); return COMPILE_OK;
4398 }
4399 break;
4400 }
4401 }
4402
4403 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4404 iobj->insn_id = BIN(opt_send_without_block);
4405 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4406 }
4407 }
4408#undef SP_INSN
4409
4410 return COMPILE_OK;
4411}
4412
4413static inline int
4414tailcallable_p(rb_iseq_t *iseq)
4415{
4416 switch (ISEQ_BODY(iseq)->type) {
4417 case ISEQ_TYPE_TOP:
4418 case ISEQ_TYPE_EVAL:
4419 case ISEQ_TYPE_MAIN:
4420 /* not tail callable because cfp will be over popped */
4421 case ISEQ_TYPE_RESCUE:
4422 case ISEQ_TYPE_ENSURE:
4423 /* rescue block can't tail call because of errinfo */
4424 return FALSE;
4425 default:
4426 return TRUE;
4427 }
4428}
4429
4430static int
4431iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4432{
4433 LINK_ELEMENT *list;
4434 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4435 const int do_tailcallopt = tailcallable_p(iseq) &&
4436 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4437 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4438 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4439 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4440 int rescue_level = 0;
4441 int tailcallopt = do_tailcallopt;
4442
4443 list = FIRST_ELEMENT(anchor);
4444
4445 int do_block_optimization = 0;
4446 LABEL * block_loop_label = NULL;
4447
4448 // If we're optimizing a block
4449 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4450 do_block_optimization = 1;
4451
4452 // If the block starts with a nop and a label,
4453 // record the label so we can detect if it's a jump target
4454 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4455 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4456 block_loop_label = (LABEL *)le->next;
4457 }
4458 }
4459
4460 while (list) {
4461 if (IS_INSN(list)) {
4462 if (do_peepholeopt) {
4463 iseq_peephole_optimize(iseq, list, tailcallopt);
4464 }
4465 if (do_si) {
4466 iseq_specialized_instruction(iseq, (INSN *)list);
4467 }
4468 if (do_ou) {
4469 insn_operands_unification((INSN *)list);
4470 }
4471
4472 if (do_without_ints) {
4473 INSN *item = (INSN *)list;
4474 if (IS_INSN_ID(item, jump)) {
4475 item->insn_id = BIN(jump_without_ints);
4476 }
4477 else if (IS_INSN_ID(item, branchif)) {
4478 item->insn_id = BIN(branchif_without_ints);
4479 }
4480 else if (IS_INSN_ID(item, branchunless)) {
4481 item->insn_id = BIN(branchunless_without_ints);
4482 }
4483 else if (IS_INSN_ID(item, branchnil)) {
4484 item->insn_id = BIN(branchnil_without_ints);
4485 }
4486 }
4487
4488 if (do_block_optimization) {
4489 INSN * item = (INSN *)list;
4490 // Give up if there is a throw
4491 if (IS_INSN_ID(item, throw)) {
4492 do_block_optimization = 0;
4493 }
4494 else {
4495 // If the instruction has a jump target, check if the
4496 // jump target is the block loop label
4497 const char *types = insn_op_types(item->insn_id);
4498 for (int j = 0; types[j]; j++) {
4499 if (types[j] == TS_OFFSET) {
4500 // If the jump target is equal to the block loop
4501 // label, then we can't do the optimization because
4502 // the leading `nop` instruction fires the block
4503 // entry tracepoint
4504 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4505 if (target == block_loop_label) {
4506 do_block_optimization = 0;
4507 }
4508 }
4509 }
4510 }
4511 }
4512 }
4513 if (IS_LABEL(list)) {
4514 switch (((LABEL *)list)->rescued) {
4515 case LABEL_RESCUE_BEG:
4516 rescue_level++;
4517 tailcallopt = FALSE;
4518 break;
4519 case LABEL_RESCUE_END:
4520 if (!--rescue_level) tailcallopt = do_tailcallopt;
4521 break;
4522 }
4523 }
4524 list = list->next;
4525 }
4526
4527 if (do_block_optimization) {
4528 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4529 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4530 ELEM_REMOVE(le);
4531 }
4532 }
4533 return COMPILE_OK;
4534}
4535
4536#if OPT_INSTRUCTIONS_UNIFICATION
4537static INSN *
4538new_unified_insn(rb_iseq_t *iseq,
4539 int insn_id, int size, LINK_ELEMENT *seq_list)
4540{
4541 INSN *iobj = 0;
4542 LINK_ELEMENT *list = seq_list;
4543 int i, argc = 0;
4544 VALUE *operands = 0, *ptr = 0;
4545
4546
4547 /* count argc */
4548 for (i = 0; i < size; i++) {
4549 iobj = (INSN *)list;
4550 argc += iobj->operand_size;
4551 list = list->next;
4552 }
4553
4554 if (argc > 0) {
4555 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4556 }
4557
4558 /* copy operands */
4559 list = seq_list;
4560 for (i = 0; i < size; i++) {
4561 iobj = (INSN *)list;
4562 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4563 ptr += iobj->operand_size;
4564 list = list->next;
4565 }
4566
4567 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4568}
4569#endif
4570
4571/*
4572 * This scheme can get more performance if do this optimize with
4573 * label address resolving.
4574 * It's future work (if compile time was bottle neck).
4575 */
4576static int
4577iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4578{
4579#if OPT_INSTRUCTIONS_UNIFICATION
4580 LINK_ELEMENT *list;
4581 INSN *iobj, *niobj;
4582 int id, k;
4583 intptr_t j;
4584
4585 list = FIRST_ELEMENT(anchor);
4586 while (list) {
4587 if (IS_INSN(list)) {
4588 iobj = (INSN *)list;
4589 id = iobj->insn_id;
4590 if (unified_insns_data[id] != 0) {
4591 const int *const *entry = unified_insns_data[id];
4592 for (j = 1; j < (intptr_t)entry[0]; j++) {
4593 const int *unified = entry[j];
4594 LINK_ELEMENT *li = list->next;
4595 for (k = 2; k < unified[1]; k++) {
4596 if (!IS_INSN(li) ||
4597 ((INSN *)li)->insn_id != unified[k]) {
4598 goto miss;
4599 }
4600 li = li->next;
4601 }
4602 /* matched */
4603 niobj =
4604 new_unified_insn(iseq, unified[0], unified[1] - 1,
4605 list);
4606
4607 /* insert to list */
4608 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4609 niobj->link.next = li;
4610 if (li) {
4611 li->prev = (LINK_ELEMENT *)niobj;
4612 }
4613
4614 list->prev->next = (LINK_ELEMENT *)niobj;
4615 list = (LINK_ELEMENT *)niobj;
4616 break;
4617 miss:;
4618 }
4619 }
4620 }
4621 list = list->next;
4622 }
4623#endif
4624 return COMPILE_OK;
4625}
4626
4627static int
4628all_string_result_p(const NODE *node)
4629{
4630 if (!node) return FALSE;
4631 switch (nd_type(node)) {
4632 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4633 return TRUE;
4634 case NODE_IF: case NODE_UNLESS:
4635 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4636 if (all_string_result_p(RNODE_IF(node)->nd_body))
4637 return all_string_result_p(RNODE_IF(node)->nd_else);
4638 return FALSE;
4639 case NODE_AND: case NODE_OR:
4640 if (!RNODE_AND(node)->nd_2nd)
4641 return all_string_result_p(RNODE_AND(node)->nd_1st);
4642 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4643 return FALSE;
4644 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4645 default:
4646 return FALSE;
4647 }
4648}
4649
4651 rb_iseq_t *const iseq;
4652 LINK_ANCHOR *const ret;
4653 VALUE lit;
4654 const NODE *lit_node;
4655 int cnt;
4656 int dregx;
4657};
4658
4659static int
4660append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4661{
4662 VALUE s = rb_str_new_mutable_parser_string(str);
4663 if (args->dregx) {
4664 VALUE error = rb_reg_check_preprocess(s);
4665 if (!NIL_P(error)) {
4666 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4667 return COMPILE_NG;
4668 }
4669 }
4670 if (NIL_P(args->lit)) {
4671 args->lit = s;
4672 args->lit_node = node;
4673 }
4674 else {
4675 rb_str_buf_append(args->lit, s);
4676 }
4677 return COMPILE_OK;
4678}
4679
4680static void
4681flush_dstr_fragment(struct dstr_ctxt *args)
4682{
4683 if (!NIL_P(args->lit)) {
4684 rb_iseq_t *iseq = args->iseq;
4685 VALUE lit = args->lit;
4686 args->lit = Qnil;
4687 lit = rb_fstring(lit);
4688 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4689 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4690 args->cnt++;
4691 }
4692}
4693
4694static int
4695compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4696{
4697 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4698 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4699
4700 if (str) {
4701 CHECK(append_dstr_fragment(args, node, str));
4702 }
4703
4704 while (list) {
4705 const NODE *const head = list->nd_head;
4706 if (nd_type_p(head, NODE_STR)) {
4707 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4708 }
4709 else if (nd_type_p(head, NODE_DSTR)) {
4710 CHECK(compile_dstr_fragments_0(args, head));
4711 }
4712 else {
4713 flush_dstr_fragment(args);
4714 rb_iseq_t *iseq = args->iseq;
4715 CHECK(COMPILE(args->ret, "each string", head));
4716 args->cnt++;
4717 }
4718 list = (struct RNode_LIST *)list->nd_next;
4719 }
4720 return COMPILE_OK;
4721}
4722
4723static int
4724compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4725{
4726 struct dstr_ctxt args = {
4727 .iseq = iseq, .ret = ret,
4728 .lit = Qnil, .lit_node = NULL,
4729 .cnt = 0, .dregx = dregx,
4730 };
4731 CHECK(compile_dstr_fragments_0(&args, node));
4732 flush_dstr_fragment(&args);
4733
4734 *cntp = args.cnt;
4735
4736 return COMPILE_OK;
4737}
4738
4739static int
4740compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4741{
4742 while (node && nd_type_p(node, NODE_BLOCK)) {
4743 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4744 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4745 node = RNODE_BLOCK(node)->nd_next;
4746 }
4747 if (node) {
4748 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4749 }
4750 return COMPILE_OK;
4751}
4752
4753static int
4754compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4755{
4756 int cnt;
4757 if (!RNODE_DSTR(node)->nd_next) {
4758 VALUE lit = rb_node_dstr_string_val(node);
4759 ADD_INSN1(ret, node, putstring, lit);
4760 RB_OBJ_SET_SHAREABLE(lit);
4761 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4762 }
4763 else {
4764 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4765 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4766 }
4767 return COMPILE_OK;
4768}
4769
4770static int
4771compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4772{
4773 int cnt;
4774 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4775
4776 if (!RNODE_DREGX(node)->nd_next) {
4777 if (!popped) {
4778 VALUE src = rb_node_dregx_string_val(node);
4779 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4780 RB_OBJ_SET_SHAREABLE(match);
4781 ADD_INSN1(ret, node, putobject, match);
4782 RB_OBJ_WRITTEN(iseq, Qundef, match);
4783 }
4784 return COMPILE_OK;
4785 }
4786
4787 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4788 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4789
4790 if (popped) {
4791 ADD_INSN(ret, node, pop);
4792 }
4793
4794 return COMPILE_OK;
4795}
4796
4797static int
4798compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4799 LABEL *then_label, LABEL *else_label)
4800{
4801 const int line = nd_line(node);
4802 LABEL *lend = NEW_LABEL(line);
4803 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4804 + VM_SVAR_FLIPFLOP_START;
4805 VALUE key = INT2FIX(cnt);
4806
4807 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4808 ADD_INSNL(ret, node, branchif, lend);
4809
4810 /* *flip == 0 */
4811 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4812 ADD_INSNL(ret, node, branchunless, else_label);
4813 ADD_INSN1(ret, node, putobject, Qtrue);
4814 ADD_INSN1(ret, node, setspecial, key);
4815 if (!again) {
4816 ADD_INSNL(ret, node, jump, then_label);
4817 }
4818
4819 /* *flip == 1 */
4820 ADD_LABEL(ret, lend);
4821 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4822 ADD_INSNL(ret, node, branchunless, then_label);
4823 ADD_INSN1(ret, node, putobject, Qfalse);
4824 ADD_INSN1(ret, node, setspecial, key);
4825 ADD_INSNL(ret, node, jump, then_label);
4826
4827 return COMPILE_OK;
4828}
4829
4830static int
4831compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4832 LABEL *then_label, LABEL *else_label);
4833
4834#define COMPILE_SINGLE 2
4835static int
4836compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4837 LABEL *then_label, LABEL *else_label)
4838{
4839 DECL_ANCHOR(seq);
4840 INIT_ANCHOR(seq);
4841 LABEL *label = NEW_LABEL(nd_line(cond));
4842 if (!then_label) then_label = label;
4843 else if (!else_label) else_label = label;
4844
4845 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4846
4847 if (LIST_INSN_SIZE_ONE(seq)) {
4848 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4849 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4850 return COMPILE_OK;
4851 }
4852 if (!label->refcnt) {
4853 return COMPILE_SINGLE;
4854 }
4855 ADD_LABEL(seq, label);
4856 ADD_SEQ(ret, seq);
4857 return COMPILE_OK;
4858}
4859
4860static int
4861compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4862 LABEL *then_label, LABEL *else_label)
4863{
4864 int ok;
4865 DECL_ANCHOR(ignore);
4866
4867 again:
4868 switch (nd_type(cond)) {
4869 case NODE_AND:
4870 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4871 cond = RNODE_AND(cond)->nd_2nd;
4872 if (ok == COMPILE_SINGLE) {
4873 INIT_ANCHOR(ignore);
4874 ret = ignore;
4875 then_label = NEW_LABEL(nd_line(cond));
4876 }
4877 goto again;
4878 case NODE_OR:
4879 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4880 cond = RNODE_OR(cond)->nd_2nd;
4881 if (ok == COMPILE_SINGLE) {
4882 INIT_ANCHOR(ignore);
4883 ret = ignore;
4884 else_label = NEW_LABEL(nd_line(cond));
4885 }
4886 goto again;
4887 case NODE_SYM:
4888 case NODE_LINE:
4889 case NODE_FILE:
4890 case NODE_ENCODING:
4891 case NODE_INTEGER: /* NODE_INTEGER is always true */
4892 case NODE_FLOAT: /* NODE_FLOAT is always true */
4893 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4894 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4895 case NODE_TRUE:
4896 case NODE_STR:
4897 case NODE_REGX:
4898 case NODE_ZLIST:
4899 case NODE_LAMBDA:
4900 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4901 ADD_INSNL(ret, cond, jump, then_label);
4902 return COMPILE_OK;
4903 case NODE_FALSE:
4904 case NODE_NIL:
4905 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4906 ADD_INSNL(ret, cond, jump, else_label);
4907 return COMPILE_OK;
4908 case NODE_LIST:
4909 case NODE_ARGSCAT:
4910 case NODE_DREGX:
4911 case NODE_DSTR:
4912 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4913 ADD_INSNL(ret, cond, jump, then_label);
4914 return COMPILE_OK;
4915 case NODE_FLIP2:
4916 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4917 return COMPILE_OK;
4918 case NODE_FLIP3:
4919 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4920 return COMPILE_OK;
4921 case NODE_DEFINED:
4922 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4923 break;
4924 default:
4925 {
4926 DECL_ANCHOR(cond_seq);
4927 INIT_ANCHOR(cond_seq);
4928
4929 CHECK(COMPILE(cond_seq, "branch condition", cond));
4930
4931 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4932 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4933 if (insn->insn_id == BIN(putobject)) {
4934 if (RTEST(insn->operands[0])) {
4935 ADD_INSNL(ret, cond, jump, then_label);
4936 // maybe unreachable
4937 return COMPILE_OK;
4938 }
4939 else {
4940 ADD_INSNL(ret, cond, jump, else_label);
4941 return COMPILE_OK;
4942 }
4943 }
4944 }
4945 ADD_SEQ(ret, cond_seq);
4946 }
4947 break;
4948 }
4949
4950 ADD_INSNL(ret, cond, branchunless, else_label);
4951 ADD_INSNL(ret, cond, jump, then_label);
4952 return COMPILE_OK;
4953}
4954
4955#define HASH_BRACE 1
4956
4957static int
4958keyword_node_p(const NODE *const node)
4959{
4960 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4961}
4962
4963static VALUE
4964get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4965{
4966 switch (nd_type(node)) {
4967 case NODE_SYM:
4968 return rb_node_sym_string_val(node);
4969 default:
4970 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4971 }
4972}
4973
4974static VALUE
4975node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4976{
4977 NODE *node = node_hash->nd_head;
4978 VALUE hash = rb_hash_new();
4979 VALUE ary = rb_ary_new();
4980
4981 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4982 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4983 VALUE idx = rb_hash_aref(hash, key);
4984 if (!NIL_P(idx)) {
4985 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4986 (*count_ptr)--;
4987 }
4988 rb_hash_aset(hash, key, INT2FIX(i));
4989 rb_ary_store(ary, i, Qtrue);
4990 (*count_ptr)++;
4991 }
4992
4993 return ary;
4994}
4995
4996static int
4997compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4998 const NODE *const root_node,
4999 struct rb_callinfo_kwarg **const kw_arg_ptr,
5000 unsigned int *flag)
5001{
5002 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5003 RUBY_ASSERT(kw_arg_ptr != NULL);
5004 RUBY_ASSERT(flag != NULL);
5005
5006 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5007 const NODE *node = RNODE_HASH(root_node)->nd_head;
5008 int seen_nodes = 0;
5009
5010 while (node) {
5011 const NODE *key_node = RNODE_LIST(node)->nd_head;
5012 seen_nodes++;
5013
5014 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5015 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5016 /* can be keywords */
5017 }
5018 else {
5019 if (flag) {
5020 *flag |= VM_CALL_KW_SPLAT;
5021 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5022 /* A new hash will be created for the keyword arguments
5023 * in this case, so mark the method as passing mutable
5024 * keyword splat.
5025 */
5026 *flag |= VM_CALL_KW_SPLAT_MUT;
5027 }
5028 }
5029 return FALSE;
5030 }
5031 node = RNODE_LIST(node)->nd_next; /* skip value node */
5032 node = RNODE_LIST(node)->nd_next;
5033 }
5034
5035 /* may be keywords */
5036 node = RNODE_HASH(root_node)->nd_head;
5037 {
5038 int len = 0;
5039 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5040 struct rb_callinfo_kwarg *kw_arg =
5041 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5042 VALUE *keywords = kw_arg->keywords;
5043 int i = 0;
5044 int j = 0;
5045 kw_arg->references = 0;
5046 kw_arg->keyword_len = len;
5047
5048 *kw_arg_ptr = kw_arg;
5049
5050 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5051 const NODE *key_node = RNODE_LIST(node)->nd_head;
5052 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5053 int popped = TRUE;
5054 if (rb_ary_entry(key_index, i)) {
5055 keywords[j] = get_symbol_value(iseq, key_node);
5056 j++;
5057 popped = FALSE;
5058 }
5059 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5060 }
5061 RUBY_ASSERT(j == len);
5062 return TRUE;
5063 }
5064 }
5065 return FALSE;
5066}
5067
5068static int
5069compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5070{
5071 int len = 0;
5072
5073 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5074 if (CPDEBUG > 0) {
5075 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5076 }
5077
5078 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5079 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5080 }
5081 else {
5082 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5083 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5084 }
5085 }
5086
5087 return len;
5088}
5089
5090static inline bool
5091frozen_string_literal_p(const rb_iseq_t *iseq)
5092{
5093 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5094}
5095
5096static inline bool
5097static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5098{
5099 switch (nd_type(node)) {
5100 case NODE_SYM:
5101 case NODE_REGX:
5102 case NODE_LINE:
5103 case NODE_ENCODING:
5104 case NODE_INTEGER:
5105 case NODE_FLOAT:
5106 case NODE_RATIONAL:
5107 case NODE_IMAGINARY:
5108 case NODE_NIL:
5109 case NODE_TRUE:
5110 case NODE_FALSE:
5111 return TRUE;
5112 case NODE_STR:
5113 case NODE_FILE:
5114 return hash_key || frozen_string_literal_p(iseq);
5115 default:
5116 return FALSE;
5117 }
5118}
5119
5120static inline VALUE
5121static_literal_value(const NODE *node, rb_iseq_t *iseq)
5122{
5123 switch (nd_type(node)) {
5124 case NODE_INTEGER:
5125 {
5126 VALUE lit = rb_node_integer_literal_val(node);
5127 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5128 return lit;
5129 }
5130 case NODE_FLOAT:
5131 {
5132 VALUE lit = rb_node_float_literal_val(node);
5133 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5134 return lit;
5135 }
5136 case NODE_RATIONAL:
5137 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5138 case NODE_IMAGINARY:
5139 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5140 case NODE_NIL:
5141 return Qnil;
5142 case NODE_TRUE:
5143 return Qtrue;
5144 case NODE_FALSE:
5145 return Qfalse;
5146 case NODE_SYM:
5147 return rb_node_sym_string_val(node);
5148 case NODE_REGX:
5149 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5150 case NODE_LINE:
5151 return rb_node_line_lineno_val(node);
5152 case NODE_ENCODING:
5153 return rb_node_encoding_val(node);
5154 case NODE_FILE:
5155 case NODE_STR:
5156 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5157 VALUE lit = get_string_value(node);
5158 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5159 RB_OBJ_SET_SHAREABLE(str);
5160 return str;
5161 }
5162 else {
5163 return get_string_value(node);
5164 }
5165 default:
5166 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5167 }
5168}
5169
5170static int
5171compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5172{
5173 const NODE *line_node = node;
5174
5175 if (nd_type_p(node, NODE_ZLIST)) {
5176 if (!popped) {
5177 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5178 }
5179 return 0;
5180 }
5181
5182 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5183
5184 if (popped) {
5185 for (; node; node = RNODE_LIST(node)->nd_next) {
5186 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5187 }
5188 return 1;
5189 }
5190
5191 /* Compilation of an array literal.
5192 * The following code is essentially the same as:
5193 *
5194 * for (int count = 0; node; count++; node->nd_next) {
5195 * compile(node->nd_head);
5196 * }
5197 * ADD_INSN(newarray, count);
5198 *
5199 * However, there are three points.
5200 *
5201 * - The code above causes stack overflow for a big string literal.
5202 * The following limits the stack length up to max_stack_len.
5203 *
5204 * [x1,x2,...,x10000] =>
5205 * push x1 ; push x2 ; ...; push x256; newarray 256;
5206 * push x257; push x258; ...; push x512; pushtoarray 256;
5207 * push x513; push x514; ...; push x768; pushtoarray 256;
5208 * ...
5209 *
5210 * - Long subarray can be optimized by pre-allocating a hidden array.
5211 *
5212 * [1,2,3,...,100] =>
5213 * duparray [1,2,3,...,100]
5214 *
5215 * [x, 1,2,3,...,100, z] =>
5216 * push x; newarray 1;
5217 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5218 * push z; pushtoarray 1;
5219 *
5220 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5221 * to only push it onto the array if it is not empty
5222 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5223 *
5224 * [1,2,3,**kw] =>
5225 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5226 */
5227
5228 const int max_stack_len = 0x100;
5229 const int min_tmp_ary_len = 0x40;
5230 int stack_len = 0;
5231
5232 /* Either create a new array, or push to the existing array */
5233#define FLUSH_CHUNK \
5234 if (stack_len) { \
5235 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5236 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5237 first_chunk = FALSE; \
5238 stack_len = 0; \
5239 }
5240
5241 while (node) {
5242 int count = 1;
5243
5244 /* pre-allocation check (this branch can be omittable) */
5245 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5246 /* count the elements that are optimizable */
5247 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5248 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5249 count++;
5250
5251 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5252 /* The literal contains only optimizable elements, or the subarray is long enough */
5253 VALUE ary = rb_ary_hidden_new(count);
5254
5255 /* Create a hidden array */
5256 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5257 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5258 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5259
5260 /* Emit optimized code */
5261 FLUSH_CHUNK;
5262 if (first_chunk) {
5263 ADD_INSN1(ret, line_node, duparray, ary);
5264 first_chunk = FALSE;
5265 }
5266 else {
5267 ADD_INSN1(ret, line_node, putobject, ary);
5268 ADD_INSN(ret, line_node, concattoarray);
5269 }
5270 RB_OBJ_SET_SHAREABLE(ary);
5271 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5272 }
5273 }
5274
5275 /* Base case: Compile "count" elements */
5276 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5277 if (CPDEBUG > 0) {
5278 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5279 }
5280
5281 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5282 /* Create array or push existing non-keyword elements onto array */
5283 if (stack_len == 0 && first_chunk) {
5284 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5285 }
5286 else {
5287 FLUSH_CHUNK;
5288 }
5289 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5290 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5291 return 1;
5292 }
5293 else {
5294 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5295 stack_len++;
5296 }
5297
5298 /* If there are many pushed elements, flush them to avoid stack overflow */
5299 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5300 }
5301 }
5302
5303 FLUSH_CHUNK;
5304#undef FLUSH_CHUNK
5305 return 1;
5306}
5307
5308static inline int
5309static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5310{
5311 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);
5312}
5313
5314static int
5315compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5316{
5317 const NODE *line_node = node;
5318
5319 node = RNODE_HASH(node)->nd_head;
5320
5321 if (!node || nd_type_p(node, NODE_ZLIST)) {
5322 if (!popped) {
5323 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5324 }
5325 return 0;
5326 }
5327
5328 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5329
5330 if (popped) {
5331 for (; node; node = RNODE_LIST(node)->nd_next) {
5332 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5333 }
5334 return 1;
5335 }
5336
5337 /* Compilation of a hash literal (or keyword arguments).
5338 * This is very similar to compile_array, but there are some differences:
5339 *
5340 * - It contains key-value pairs. So we need to take every two elements.
5341 * We can assume that the length is always even.
5342 *
5343 * - Merging is done by a method call (id_core_hash_merge_ptr).
5344 * Sometimes we need to insert the receiver, so "anchor" is needed.
5345 * In addition, a method call is much slower than concatarray.
5346 * So it pays only when the subsequence is really long.
5347 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5348 *
5349 * - We need to handle keyword splat: **kw.
5350 * For **kw, the key part (node->nd_head) is NULL, and the value part
5351 * (node->nd_next->nd_head) is "kw".
5352 * The code is a bit difficult to avoid hash allocation for **{}.
5353 */
5354
5355 const int max_stack_len = 0x100;
5356 const int min_tmp_hash_len = 0x800;
5357 int stack_len = 0;
5358 int first_chunk = 1;
5359 DECL_ANCHOR(anchor);
5360 INIT_ANCHOR(anchor);
5361
5362 /* Convert pushed elements to a hash, and merge if needed */
5363#define FLUSH_CHUNK() \
5364 if (stack_len) { \
5365 if (first_chunk) { \
5366 APPEND_LIST(ret, anchor); \
5367 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5368 } \
5369 else { \
5370 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5371 ADD_INSN(ret, line_node, swap); \
5372 APPEND_LIST(ret, anchor); \
5373 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5374 } \
5375 INIT_ANCHOR(anchor); \
5376 first_chunk = stack_len = 0; \
5377 }
5378
5379 while (node) {
5380 int count = 1;
5381
5382 /* pre-allocation check (this branch can be omittable) */
5383 if (static_literal_node_pair_p(node, iseq)) {
5384 /* count the elements that are optimizable */
5385 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5386 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5387 count++;
5388
5389 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5390 /* The literal contains only optimizable elements, or the subsequence is long enough */
5391 VALUE ary = rb_ary_hidden_new(count);
5392
5393 /* Create a hidden hash */
5394 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5395 VALUE elem[2];
5396 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5397 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5398 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5399 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5400 rb_ary_cat(ary, elem, 2);
5401 }
5402 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5403 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5404 hash = RB_OBJ_SET_FROZEN_SHAREABLE(rb_obj_hide(hash));
5405
5406 /* Emit optimized code */
5407 FLUSH_CHUNK();
5408 if (first_chunk) {
5409 ADD_INSN1(ret, line_node, duphash, hash);
5410 first_chunk = 0;
5411 }
5412 else {
5413 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5414 ADD_INSN(ret, line_node, swap);
5415
5416 ADD_INSN1(ret, line_node, putobject, hash);
5417
5418 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5419 }
5420 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5421 }
5422 }
5423
5424 /* Base case: Compile "count" elements */
5425 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5426
5427 if (CPDEBUG > 0) {
5428 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5429 }
5430
5431 if (RNODE_LIST(node)->nd_head) {
5432 /* Normal key-value pair */
5433 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5434 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5435 stack_len += 2;
5436
5437 /* If there are many pushed elements, flush them to avoid stack overflow */
5438 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5439 }
5440 else {
5441 /* kwsplat case: foo(..., **kw, ...) */
5442 FLUSH_CHUNK();
5443
5444 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5445 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5446 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5447 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5448 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5449
5450 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5451 if (empty_kw) {
5452 if (only_kw && method_call_keywords) {
5453 /* **{} appears at the only keyword argument in method call,
5454 * so it won't be modified.
5455 * kw is a special NODE_LIT that contains a special empty hash,
5456 * so this emits: putobject {}.
5457 * This is only done for method calls and not for literal hashes,
5458 * because literal hashes should always result in a new hash.
5459 */
5460 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5461 }
5462 else if (first_kw) {
5463 /* **{} appears as the first keyword argument, so it may be modified.
5464 * We need to create a fresh hash object.
5465 */
5466 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5467 }
5468 /* Any empty keyword splats that are not the first can be ignored.
5469 * since merging an empty hash into the existing hash is the same
5470 * as not merging it. */
5471 }
5472 else {
5473 if (only_kw && method_call_keywords) {
5474 /* **kw is only keyword argument in method call.
5475 * Use directly. This will be not be flagged as mutable.
5476 * This is only done for method calls and not for literal hashes,
5477 * because literal hashes should always result in a new hash.
5478 */
5479 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5480 }
5481 else {
5482 /* There is more than one keyword argument, or this is not a method
5483 * call. In that case, we need to add an empty hash (if first keyword),
5484 * or merge the hash to the accumulated hash (if not the first keyword).
5485 */
5486 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5487 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5488 else ADD_INSN(ret, line_node, swap);
5489
5490 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5491
5492 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5493 }
5494 }
5495
5496 first_chunk = 0;
5497 }
5498 }
5499 }
5500
5501 FLUSH_CHUNK();
5502#undef FLUSH_CHUNK
5503 return 1;
5504}
5505
5506VALUE
5507rb_node_case_when_optimizable_literal(const NODE *const node)
5508{
5509 switch (nd_type(node)) {
5510 case NODE_INTEGER:
5511 return rb_node_integer_literal_val(node);
5512 case NODE_FLOAT: {
5513 VALUE v = rb_node_float_literal_val(node);
5514 double ival;
5515
5516 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5517 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5518 }
5519 return v;
5520 }
5521 case NODE_RATIONAL:
5522 case NODE_IMAGINARY:
5523 return Qundef;
5524 case NODE_NIL:
5525 return Qnil;
5526 case NODE_TRUE:
5527 return Qtrue;
5528 case NODE_FALSE:
5529 return Qfalse;
5530 case NODE_SYM:
5531 return rb_node_sym_string_val(node);
5532 case NODE_LINE:
5533 return rb_node_line_lineno_val(node);
5534 case NODE_STR:
5535 return rb_node_str_string_val(node);
5536 case NODE_FILE:
5537 return rb_node_file_path_val(node);
5538 }
5539 return Qundef;
5540}
5541
5542static int
5543when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5544 LABEL *l1, int only_special_literals, VALUE literals)
5545{
5546 while (vals) {
5547 const NODE *val = RNODE_LIST(vals)->nd_head;
5548 VALUE lit = rb_node_case_when_optimizable_literal(val);
5549
5550 if (UNDEF_P(lit)) {
5551 only_special_literals = 0;
5552 }
5553 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5554 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5555 }
5556
5557 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5558 debugp_param("nd_lit", get_string_value(val));
5559 lit = get_string_value(val);
5560 ADD_INSN1(cond_seq, val, putobject, lit);
5561 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5562 }
5563 else {
5564 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5565 }
5566
5567 // Emit pattern === target
5568 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5569 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5570 ADD_INSNL(cond_seq, val, branchif, l1);
5571 vals = RNODE_LIST(vals)->nd_next;
5572 }
5573 return only_special_literals;
5574}
5575
5576static int
5577when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5578 LABEL *l1, int only_special_literals, VALUE literals)
5579{
5580 const NODE *line_node = vals;
5581
5582 switch (nd_type(vals)) {
5583 case NODE_LIST:
5584 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5585 return COMPILE_NG;
5586 break;
5587 case NODE_SPLAT:
5588 ADD_INSN (cond_seq, line_node, dup);
5589 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5590 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5591 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5592 ADD_INSNL(cond_seq, line_node, branchif, l1);
5593 break;
5594 case NODE_ARGSCAT:
5595 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5596 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5597 break;
5598 case NODE_ARGSPUSH:
5599 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5600 ADD_INSN (cond_seq, line_node, dup);
5601 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5602 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5603 ADD_INSNL(cond_seq, line_node, branchif, l1);
5604 break;
5605 default:
5606 ADD_INSN (cond_seq, line_node, dup);
5607 CHECK(COMPILE(cond_seq, "when val", vals));
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 }
5613 return COMPILE_OK;
5614}
5615
5616/* Multiple Assignment Handling
5617 *
5618 * In order to handle evaluation of multiple assignment such that the left hand side
5619 * is evaluated before the right hand side, we need to process the left hand side
5620 * and see if there are any attributes that need to be assigned, or constants set
5621 * on explicit objects. If so, we add instructions to evaluate the receiver of
5622 * any assigned attributes or constants before we process the right hand side.
5623 *
5624 * For a multiple assignment such as:
5625 *
5626 * l1.m1, l2[0] = r3, r4
5627 *
5628 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5629 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5630 * On the VM stack, this looks like:
5631 *
5632 * self # putself
5633 * l1 # send
5634 * l1, self # putself
5635 * l1, l2 # send
5636 * l1, l2, 0 # putobject 0
5637 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5638 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5639 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5640 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5641 * l1, l2, 0, [r3, r4], r4, m1= # send
5642 * l1, l2, 0, [r3, r4], r4 # pop
5643 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5644 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5645 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5646 * l1, l2, 0, [r3, r4], r4, []= # send
5647 * l1, l2, 0, [r3, r4], r4 # pop
5648 * l1, l2, 0, [r3, r4] # pop
5649 * [r3, r4], l2, 0, [r3, r4] # setn 3
5650 * [r3, r4], l2, 0 # pop
5651 * [r3, r4], l2 # pop
5652 * [r3, r4] # pop
5653 *
5654 * This is made more complex when you have to handle splats, post args,
5655 * and arbitrary levels of nesting. You need to keep track of the total
5656 * number of attributes to set, and for each attribute, how many entries
5657 * are on the stack before the final attribute, in order to correctly
5658 * calculate the topn value to use to get the receiver of the attribute
5659 * setter method.
5660 *
5661 * A brief description of the VM stack for simple multiple assignment
5662 * with no splat (rhs_array will not be present if the return value of
5663 * the multiple assignment is not needed):
5664 *
5665 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5666 *
5667 * For multiple assignment with splats, while processing the part before
5668 * the splat (splat+post here is an array of the splat and the post arguments):
5669 *
5670 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5671 *
5672 * When processing the splat and post arguments:
5673 *
5674 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5675 *
5676 * When processing nested multiple assignment, existing values on the stack
5677 * are kept. So for:
5678 *
5679 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5680 *
5681 * The stack layout would be the following before processing the nested
5682 * multiple assignment:
5683 *
5684 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5685 *
5686 * In order to handle this correctly, we need to keep track of the nesting
5687 * level for each attribute assignment, as well as the attribute number
5688 * (left hand side attributes are processed left to right) and number of
5689 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5690 * this information.
5691 *
5692 * We also need to track information for the entire multiple assignment, such
5693 * as the total number of arguments, and the current nesting level, to
5694 * handle both nested multiple assignment as well as cases where the
5695 * rhs is not needed. We also need to keep track of all attribute
5696 * assignments in this, which we do using a linked listed. struct masgn_state
5697 * tracks this information.
5698 */
5699
5701 INSN *before_insn;
5702 struct masgn_lhs_node *next;
5703 const NODE *line_node;
5704 int argn;
5705 int num_args;
5706 int lhs_pos;
5707};
5708
5710 struct masgn_lhs_node *first_memo;
5711 struct masgn_lhs_node *last_memo;
5712 int lhs_level;
5713 int num_args;
5714 bool nested;
5715};
5716
5717static int
5718add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5719{
5720 if (!state) {
5721 rb_bug("no masgn_state");
5722 }
5723
5724 struct masgn_lhs_node *memo;
5725 memo = malloc(sizeof(struct masgn_lhs_node));
5726 if (!memo) {
5727 return COMPILE_NG;
5728 }
5729
5730 memo->before_insn = before_insn;
5731 memo->line_node = line_node;
5732 memo->argn = state->num_args + 1;
5733 memo->num_args = argc;
5734 state->num_args += argc;
5735 memo->lhs_pos = lhs_pos;
5736 memo->next = NULL;
5737 if (!state->first_memo) {
5738 state->first_memo = memo;
5739 }
5740 else {
5741 state->last_memo->next = memo;
5742 }
5743 state->last_memo = memo;
5744
5745 return COMPILE_OK;
5746}
5747
5748static 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);
5749
5750static int
5751compile_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)
5752{
5753 switch (nd_type(node)) {
5754 case NODE_ATTRASGN: {
5755 INSN *iobj;
5756 const NODE *line_node = node;
5757
5758 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5759
5760 bool safenav_call = false;
5761 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5762 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5763 ASSUME(iobj);
5764 ELEM_REMOVE(insn_element);
5765 if (!IS_INSN_ID(iobj, send)) {
5766 safenav_call = true;
5767 iobj = (INSN *)get_prev_insn(iobj);
5768 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5769 }
5770 (pre->last = iobj->link.prev)->next = 0;
5771
5772 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5773 int argc = vm_ci_argc(ci) + 1;
5774 ci = ci_argc_set(iseq, ci, argc);
5775 OPERAND_AT(iobj, 0) = (VALUE)ci;
5776 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5777
5778 if (argc == 1) {
5779 ADD_INSN(lhs, line_node, swap);
5780 }
5781 else {
5782 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5783 }
5784
5785 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5786 return COMPILE_NG;
5787 }
5788
5789 iobj->link.prev = lhs->last;
5790 lhs->last->next = &iobj->link;
5791 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5792 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5793 int argc = vm_ci_argc(ci);
5794 bool dupsplat = false;
5795 ci = ci_argc_set(iseq, ci, argc - 1);
5796 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5797 /* Given h[*a], _ = ary
5798 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5799 * `a` must be dupped, because it will be appended with ary[0]
5800 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5801 */
5802 dupsplat = true;
5803 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5804 }
5805 OPERAND_AT(iobj, 0) = (VALUE)ci;
5806 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5807
5808 /* Given: h[*a], h[*b, 1] = ary
5809 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5810 * so this uses splatarray true on a to dup it before using pushtoarray
5811 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5812 * so you can use pushtoarray directly
5813 */
5814 int line_no = nd_line(line_node);
5815 int node_id = nd_node_id(line_node);
5816
5817 if (dupsplat) {
5818 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5819 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5820 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5821 }
5822 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5823 }
5824 if (!safenav_call) {
5825 ADD_INSN(lhs, line_node, pop);
5826 if (argc != 1) {
5827 ADD_INSN(lhs, line_node, pop);
5828 }
5829 }
5830 for (int i=0; i < argc; i++) {
5831 ADD_INSN(post, line_node, pop);
5832 }
5833 break;
5834 }
5835 case NODE_MASGN: {
5836 DECL_ANCHOR(nest_rhs);
5837 INIT_ANCHOR(nest_rhs);
5838 DECL_ANCHOR(nest_lhs);
5839 INIT_ANCHOR(nest_lhs);
5840
5841 int prev_level = state->lhs_level;
5842 bool prev_nested = state->nested;
5843 state->nested = 1;
5844 state->lhs_level = lhs_pos - 1;
5845 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5846 state->lhs_level = prev_level;
5847 state->nested = prev_nested;
5848
5849 ADD_SEQ(lhs, nest_rhs);
5850 ADD_SEQ(lhs, nest_lhs);
5851 break;
5852 }
5853 case NODE_CDECL:
5854 if (!RNODE_CDECL(node)->nd_vid) {
5855 /* Special handling only needed for expr::C, not for C */
5856 INSN *iobj;
5857
5858 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5859
5860 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5861 iobj = (INSN *)insn_element; /* setconstant insn */
5862 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5863 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5864 ELEM_REMOVE(insn_element);
5865 pre->last = iobj->link.prev;
5866 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5867
5868 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5869 return COMPILE_NG;
5870 }
5871
5872 ADD_INSN(post, node, pop);
5873 break;
5874 }
5875 /* Fallthrough */
5876 default: {
5877 DECL_ANCHOR(anchor);
5878 INIT_ANCHOR(anchor);
5879 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5880 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5881 ADD_SEQ(lhs, anchor);
5882 }
5883 }
5884
5885 return COMPILE_OK;
5886}
5887
5888static int
5889compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5890{
5891 if (lhsn) {
5892 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5893 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5894 }
5895 return COMPILE_OK;
5896}
5897
5898static int
5899compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5900 const NODE *rhsn, const NODE *orig_lhsn)
5901{
5902 VALUE mem[64];
5903 const int memsize = numberof(mem);
5904 int memindex = 0;
5905 int llen = 0, rlen = 0;
5906 int i;
5907 const NODE *lhsn = orig_lhsn;
5908
5909#define MEMORY(v) { \
5910 int i; \
5911 if (memindex == memsize) return 0; \
5912 for (i=0; i<memindex; i++) { \
5913 if (mem[i] == (v)) return 0; \
5914 } \
5915 mem[memindex++] = (v); \
5916}
5917
5918 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5919 return 0;
5920 }
5921
5922 while (lhsn) {
5923 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5924 switch (nd_type(ln)) {
5925 case NODE_LASGN:
5926 case NODE_DASGN:
5927 case NODE_IASGN:
5928 case NODE_CVASGN:
5929 MEMORY(get_nd_vid(ln));
5930 break;
5931 default:
5932 return 0;
5933 }
5934 lhsn = RNODE_LIST(lhsn)->nd_next;
5935 llen++;
5936 }
5937
5938 while (rhsn) {
5939 if (llen <= rlen) {
5940 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5941 }
5942 else {
5943 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5944 }
5945 rhsn = RNODE_LIST(rhsn)->nd_next;
5946 rlen++;
5947 }
5948
5949 if (llen > rlen) {
5950 for (i=0; i<llen-rlen; i++) {
5951 ADD_INSN(ret, orig_lhsn, putnil);
5952 }
5953 }
5954
5955 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5956 return 1;
5957}
5958
5959static int
5960compile_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)
5961{
5962 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5963 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5964 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5965 const NODE *lhsn_count = lhsn;
5966 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5967
5968 int llen = 0;
5969 int lpos = 0;
5970
5971 while (lhsn_count) {
5972 llen++;
5973 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5974 }
5975 while (lhsn) {
5976 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5977 lpos++;
5978 lhsn = RNODE_LIST(lhsn)->nd_next;
5979 }
5980
5981 if (lhs_splat) {
5982 if (nd_type_p(splatn, NODE_POSTARG)) {
5983 /*a, b, *r, p1, p2 */
5984 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5985 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5986 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5987 int ppos = 0;
5988 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5989
5990 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5991
5992 if (NODE_NAMED_REST_P(restn)) {
5993 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5994 }
5995 while (postn) {
5996 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5997 ppos++;
5998 postn = RNODE_LIST(postn)->nd_next;
5999 }
6000 }
6001 else {
6002 /* a, b, *r */
6003 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6004 }
6005 }
6006
6007 if (!state->nested) {
6008 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6009 }
6010
6011 if (!popped) {
6012 ADD_INSN(rhs, node, dup);
6013 }
6014 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6015 return COMPILE_OK;
6016}
6017
6018static int
6019compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6020{
6021 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6022 struct masgn_state state;
6023 state.lhs_level = popped ? 0 : 1;
6024 state.nested = 0;
6025 state.num_args = 0;
6026 state.first_memo = NULL;
6027 state.last_memo = NULL;
6028
6029 DECL_ANCHOR(pre);
6030 INIT_ANCHOR(pre);
6031 DECL_ANCHOR(rhs);
6032 INIT_ANCHOR(rhs);
6033 DECL_ANCHOR(lhs);
6034 INIT_ANCHOR(lhs);
6035 DECL_ANCHOR(post);
6036 INIT_ANCHOR(post);
6037 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6038
6039 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6040 while (memo) {
6041 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6042 for (int i = 0; i < memo->num_args; i++) {
6043 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6044 }
6045 tmp_memo = memo->next;
6046 free(memo);
6047 memo = tmp_memo;
6048 }
6049 CHECK(ok);
6050
6051 ADD_SEQ(ret, pre);
6052 ADD_SEQ(ret, rhs);
6053 ADD_SEQ(ret, lhs);
6054 if (!popped && state.num_args >= 1) {
6055 /* make sure rhs array is returned before popping */
6056 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6057 }
6058 ADD_SEQ(ret, post);
6059 }
6060 return COMPILE_OK;
6061}
6062
6063static VALUE
6064collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6065{
6066 VALUE arr = rb_ary_new();
6067 for (;;) {
6068 switch (nd_type(node)) {
6069 case NODE_CONST:
6070 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6071 RB_OBJ_SET_SHAREABLE(arr);
6072 return arr;
6073 case NODE_COLON3:
6074 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6075 rb_ary_unshift(arr, ID2SYM(idNULL));
6076 RB_OBJ_SET_SHAREABLE(arr);
6077 return arr;
6078 case NODE_COLON2:
6079 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6080 node = RNODE_COLON2(node)->nd_head;
6081 break;
6082 default:
6083 return Qfalse;
6084 }
6085 }
6086}
6087
6088static int
6089compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6090 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6091{
6092 switch (nd_type(node)) {
6093 case NODE_CONST:
6094 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6095 ADD_INSN1(body, node, putobject, Qtrue);
6096 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6097 break;
6098 case NODE_COLON3:
6099 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6100 ADD_INSN(body, node, pop);
6101 ADD_INSN1(body, node, putobject, rb_cObject);
6102 ADD_INSN1(body, node, putobject, Qtrue);
6103 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6104 break;
6105 case NODE_COLON2:
6106 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6107 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6108 ADD_INSN1(body, node, putobject, Qfalse);
6109 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6110 break;
6111 default:
6112 CHECK(COMPILE(pref, "const colon2 prefix", node));
6113 break;
6114 }
6115 return COMPILE_OK;
6116}
6117
6118static int
6119compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6120{
6121 if (nd_type_p(cpath, NODE_COLON3)) {
6122 /* toplevel class ::Foo */
6123 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6124 return VM_DEFINECLASS_FLAG_SCOPED;
6125 }
6126 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6127 /* Bar::Foo */
6128 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6129 return VM_DEFINECLASS_FLAG_SCOPED;
6130 }
6131 else {
6132 /* class at cbase Foo */
6133 ADD_INSN1(ret, cpath, putspecialobject,
6134 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6135 return 0;
6136 }
6137}
6138
6139static inline int
6140private_recv_p(const NODE *node)
6141{
6142 NODE *recv = get_nd_recv(node);
6143 if (recv && nd_type_p(recv, NODE_SELF)) {
6144 return RNODE_SELF(recv)->nd_state != 0;
6145 }
6146 return 0;
6147}
6148
6149static void
6150defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6151 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6152
6153static int
6154compile_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);
6155
6156static void
6157defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6158 const NODE *const node, LABEL **lfinish, VALUE needstr,
6159 bool keep_result)
6160{
6161 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6162 enum node_type type;
6163 const int line = nd_line(node);
6164 const NODE *line_node = node;
6165
6166 switch (type = nd_type(node)) {
6167
6168 /* easy literals */
6169 case NODE_NIL:
6170 expr_type = DEFINED_NIL;
6171 break;
6172 case NODE_SELF:
6173 expr_type = DEFINED_SELF;
6174 break;
6175 case NODE_TRUE:
6176 expr_type = DEFINED_TRUE;
6177 break;
6178 case NODE_FALSE:
6179 expr_type = DEFINED_FALSE;
6180 break;
6181
6182 case NODE_HASH:
6183 case NODE_LIST:{
6184 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6185
6186 if (vals) {
6187 do {
6188 if (RNODE_LIST(vals)->nd_head) {
6189 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6190
6191 if (!lfinish[1]) {
6192 lfinish[1] = NEW_LABEL(line);
6193 }
6194 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6195 }
6196 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6197 }
6198 }
6199 /* fall through */
6200 case NODE_STR:
6201 case NODE_SYM:
6202 case NODE_REGX:
6203 case NODE_LINE:
6204 case NODE_FILE:
6205 case NODE_ENCODING:
6206 case NODE_INTEGER:
6207 case NODE_FLOAT:
6208 case NODE_RATIONAL:
6209 case NODE_IMAGINARY:
6210 case NODE_ZLIST:
6211 case NODE_AND:
6212 case NODE_OR:
6213 default:
6214 expr_type = DEFINED_EXPR;
6215 break;
6216
6217 case NODE_SPLAT:
6218 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6219 if (!lfinish[1]) {
6220 lfinish[1] = NEW_LABEL(line);
6221 }
6222 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6223 expr_type = DEFINED_EXPR;
6224 break;
6225
6226 /* variables */
6227 case NODE_LVAR:
6228 case NODE_DVAR:
6229 expr_type = DEFINED_LVAR;
6230 break;
6231
6232#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6233 case NODE_IVAR:
6234 ADD_INSN3(ret, line_node, definedivar,
6235 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6236 return;
6237
6238 case NODE_GVAR:
6239 ADD_INSN(ret, line_node, putnil);
6240 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6241 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6242 return;
6243
6244 case NODE_CVAR:
6245 ADD_INSN(ret, line_node, putnil);
6246 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6247 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6248 return;
6249
6250 case NODE_CONST:
6251 ADD_INSN(ret, line_node, putnil);
6252 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6253 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6254 return;
6255 case NODE_COLON2:
6256 if (!lfinish[1]) {
6257 lfinish[1] = NEW_LABEL(line);
6258 }
6259 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6260 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6261 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6262
6263 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6264 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6265 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6266 }
6267 else {
6268 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6269 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6270 }
6271 return;
6272 case NODE_COLON3:
6273 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6274 ADD_INSN3(ret, line_node, defined,
6275 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6276 return;
6277
6278 /* method dispatch */
6279 case NODE_CALL:
6280 case NODE_OPCALL:
6281 case NODE_VCALL:
6282 case NODE_FCALL:
6283 case NODE_ATTRASGN:{
6284 const int explicit_receiver =
6285 (type == NODE_CALL || type == NODE_OPCALL ||
6286 (type == NODE_ATTRASGN && !private_recv_p(node)));
6287
6288 if (get_nd_args(node) || explicit_receiver) {
6289 if (!lfinish[1]) {
6290 lfinish[1] = NEW_LABEL(line);
6291 }
6292 if (!lfinish[2]) {
6293 lfinish[2] = NEW_LABEL(line);
6294 }
6295 }
6296 if (get_nd_args(node)) {
6297 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6298 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6299 }
6300 if (explicit_receiver) {
6301 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6302 switch (nd_type(get_nd_recv(node))) {
6303 case NODE_CALL:
6304 case NODE_OPCALL:
6305 case NODE_VCALL:
6306 case NODE_FCALL:
6307 case NODE_ATTRASGN:
6308 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6309 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6310 break;
6311 default:
6312 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6313 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6314 break;
6315 }
6316 if (keep_result) {
6317 ADD_INSN(ret, line_node, dup);
6318 }
6319 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6320 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6321 }
6322 else {
6323 ADD_INSN(ret, line_node, putself);
6324 if (keep_result) {
6325 ADD_INSN(ret, line_node, dup);
6326 }
6327 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6328 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6329 }
6330 return;
6331 }
6332
6333 case NODE_YIELD:
6334 ADD_INSN(ret, line_node, putnil);
6335 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6336 PUSH_VAL(DEFINED_YIELD));
6337 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6338 return;
6339
6340 case NODE_BACK_REF:
6341 case NODE_NTH_REF:
6342 ADD_INSN(ret, line_node, putnil);
6343 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6344 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6345 PUSH_VAL(DEFINED_GVAR));
6346 return;
6347
6348 case NODE_SUPER:
6349 case NODE_ZSUPER:
6350 ADD_INSN(ret, line_node, putnil);
6351 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6352 PUSH_VAL(DEFINED_ZSUPER));
6353 return;
6354
6355#undef PUSH_VAL
6356 case NODE_OP_ASGN1:
6357 case NODE_OP_ASGN2:
6358 case NODE_OP_ASGN_OR:
6359 case NODE_OP_ASGN_AND:
6360 case NODE_MASGN:
6361 case NODE_LASGN:
6362 case NODE_DASGN:
6363 case NODE_GASGN:
6364 case NODE_IASGN:
6365 case NODE_CDECL:
6366 case NODE_CVASGN:
6367 case NODE_OP_CDECL:
6368 expr_type = DEFINED_ASGN;
6369 break;
6370 }
6371
6372 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6373
6374 if (needstr != Qfalse) {
6375 VALUE str = rb_iseq_defined_string(expr_type);
6376 ADD_INSN1(ret, line_node, putobject, str);
6377 }
6378 else {
6379 ADD_INSN1(ret, line_node, putobject, Qtrue);
6380 }
6381}
6382
6383static void
6384build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6385{
6386 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6387 iseq_set_exception_local_table(iseq);
6388}
6389
6390static void
6391defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6392 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6393{
6394 LINK_ELEMENT *lcur = ret->last;
6395 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6396 if (lfinish[1]) {
6397 int line = nd_line(node);
6398 LABEL *lstart = NEW_LABEL(line);
6399 LABEL *lend = NEW_LABEL(line);
6400 const rb_iseq_t *rescue;
6402 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6403 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6404 rb_str_concat(rb_str_new2("defined guard in "),
6405 ISEQ_BODY(iseq)->location.label),
6406 ISEQ_TYPE_RESCUE, 0);
6407 lstart->rescued = LABEL_RESCUE_BEG;
6408 lend->rescued = LABEL_RESCUE_END;
6409 APPEND_LABEL(ret, lcur, lstart);
6410 ADD_LABEL(ret, lend);
6411 if (!ignore) {
6412 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6413 }
6414 }
6415}
6416
6417static int
6418compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6419{
6420 const int line = nd_line(node);
6421 const NODE *line_node = node;
6422 if (!RNODE_DEFINED(node)->nd_head) {
6423 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6424 ADD_INSN1(ret, line_node, putobject, str);
6425 }
6426 else {
6427 LABEL *lfinish[3];
6428 LINK_ELEMENT *last = ret->last;
6429 lfinish[0] = NEW_LABEL(line);
6430 lfinish[1] = 0;
6431 lfinish[2] = 0;
6432 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6433 if (lfinish[1]) {
6434 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6435 ADD_INSN(ret, line_node, swap);
6436 if (lfinish[2]) {
6437 ADD_LABEL(ret, lfinish[2]);
6438 }
6439 ADD_INSN(ret, line_node, pop);
6440 ADD_LABEL(ret, lfinish[1]);
6441 }
6442 ADD_LABEL(ret, lfinish[0]);
6443 }
6444 return COMPILE_OK;
6445}
6446
6447static VALUE
6448make_name_for_block(const rb_iseq_t *orig_iseq)
6449{
6450 int level = 1;
6451 const rb_iseq_t *iseq = orig_iseq;
6452
6453 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6454 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6455 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6456 level++;
6457 }
6458 iseq = ISEQ_BODY(iseq)->parent_iseq;
6459 }
6460 }
6461
6462 if (level == 1) {
6463 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6464 }
6465 else {
6466 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6467 }
6468}
6469
6470static void
6471push_ensure_entry(rb_iseq_t *iseq,
6473 struct ensure_range *er, const void *const node)
6474{
6475 enl->ensure_node = node;
6476 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6477 enl->erange = er;
6478 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6479}
6480
6481static void
6482add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6483 LABEL *lstart, LABEL *lend)
6484{
6485 struct ensure_range *ne =
6486 compile_data_alloc(iseq, sizeof(struct ensure_range));
6487
6488 while (erange->next != 0) {
6489 erange = erange->next;
6490 }
6491 ne->next = 0;
6492 ne->begin = lend;
6493 ne->end = erange->end;
6494 erange->end = lstart;
6495
6496 erange->next = ne;
6497}
6498
6499static bool
6500can_add_ensure_iseq(const rb_iseq_t *iseq)
6501{
6503 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6504 while (e) {
6505 if (e->ensure_node) return false;
6506 e = e->prev;
6507 }
6508 }
6509 return true;
6510}
6511
6512static void
6513add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6514{
6515 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6516
6518 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6519 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6520 DECL_ANCHOR(ensure);
6521
6522 INIT_ANCHOR(ensure);
6523 while (enlp) {
6524 if (enlp->erange != NULL) {
6525 DECL_ANCHOR(ensure_part);
6526 LABEL *lstart = NEW_LABEL(0);
6527 LABEL *lend = NEW_LABEL(0);
6528 INIT_ANCHOR(ensure_part);
6529
6530 add_ensure_range(iseq, enlp->erange, lstart, lend);
6531
6532 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6533 ADD_LABEL(ensure_part, lstart);
6534 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6535 ADD_LABEL(ensure_part, lend);
6536 ADD_SEQ(ensure, ensure_part);
6537 }
6538 else {
6539 if (!is_return) {
6540 break;
6541 }
6542 }
6543 enlp = enlp->prev;
6544 }
6545 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6546 ADD_SEQ(ret, ensure);
6547}
6548
6549#if RUBY_DEBUG
6550static int
6551check_keyword(const NODE *node)
6552{
6553 /* This check is essentially a code clone of compile_keyword_arg. */
6554
6555 if (nd_type_p(node, NODE_LIST)) {
6556 while (RNODE_LIST(node)->nd_next) {
6557 node = RNODE_LIST(node)->nd_next;
6558 }
6559 node = RNODE_LIST(node)->nd_head;
6560 }
6561
6562 return keyword_node_p(node);
6563}
6564#endif
6565
6566static bool
6567keyword_node_single_splat_p(NODE *kwnode)
6568{
6569 RUBY_ASSERT(keyword_node_p(kwnode));
6570
6571 NODE *node = RNODE_HASH(kwnode)->nd_head;
6572 return RNODE_LIST(node)->nd_head == NULL &&
6573 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6574}
6575
6576static void
6577compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6578 NODE *kwnode, unsigned int *flag_ptr)
6579{
6580 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6581 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6582 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6583 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6584 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6585}
6586
6587#define SPLATARRAY_FALSE 0
6588#define SPLATARRAY_TRUE 1
6589#define DUP_SINGLE_KW_SPLAT 2
6590
6591static int
6592setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6593 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6594{
6595 if (!argn) return 0;
6596
6597 NODE *kwnode = NULL;
6598
6599 switch (nd_type(argn)) {
6600 case NODE_LIST: {
6601 // f(x, y, z)
6602 int len = compile_args(iseq, args, argn, &kwnode);
6603 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6604
6605 if (kwnode) {
6606 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6607 len -= 1;
6608 }
6609 else {
6610 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6611 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6612 }
6613 else {
6614 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6615 }
6616 }
6617 }
6618
6619 return len;
6620 }
6621 case NODE_SPLAT: {
6622 // f(*a)
6623 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6624 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6625 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6626 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6627 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6628 return 1;
6629 }
6630 case NODE_ARGSCAT: {
6631 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6632 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6633 bool args_pushed = false;
6634
6635 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6636 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6637 if (kwnode) rest_len--;
6638 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6639 args_pushed = true;
6640 }
6641 else {
6642 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6643 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6644 }
6645
6646 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6647 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6648 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6649 argc += 1;
6650 }
6651 else if (!args_pushed) {
6652 ADD_INSN(args, argn, concattoarray);
6653 }
6654
6655 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6656 if (kwnode) {
6657 // kwsplat
6658 *flag_ptr |= VM_CALL_KW_SPLAT;
6659 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6660 argc += 1;
6661 }
6662
6663 return argc;
6664 }
6665 case NODE_ARGSPUSH: {
6666 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6667 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6668
6669 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6670 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6671 if (kwnode) rest_len--;
6672 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6673 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6674 }
6675 else {
6676 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6677 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6678 }
6679 else {
6680 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6681 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6682 }
6683 }
6684
6685 if (kwnode) {
6686 // f(*a, k:1)
6687 *flag_ptr |= VM_CALL_KW_SPLAT;
6688 if (!keyword_node_single_splat_p(kwnode)) {
6689 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6690 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6691 }
6692 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6693 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6694 }
6695 else {
6696 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6697 }
6698 argc += 1;
6699 }
6700
6701 return argc;
6702 }
6703 default: {
6704 UNKNOWN_NODE("setup_arg", argn, Qnil);
6705 }
6706 }
6707}
6708
6709static void
6710setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6711{
6712 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6713 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6714 }
6715}
6716
6717static bool
6718setup_args_dup_rest_p(const NODE *argn)
6719{
6720 switch(nd_type(argn)) {
6721 case NODE_LVAR:
6722 case NODE_DVAR:
6723 case NODE_GVAR:
6724 case NODE_IVAR:
6725 case NODE_CVAR:
6726 case NODE_CONST:
6727 case NODE_COLON3:
6728 case NODE_INTEGER:
6729 case NODE_FLOAT:
6730 case NODE_RATIONAL:
6731 case NODE_IMAGINARY:
6732 case NODE_STR:
6733 case NODE_SYM:
6734 case NODE_REGX:
6735 case NODE_SELF:
6736 case NODE_NIL:
6737 case NODE_TRUE:
6738 case NODE_FALSE:
6739 case NODE_LAMBDA:
6740 case NODE_NTH_REF:
6741 case NODE_BACK_REF:
6742 return false;
6743 case NODE_COLON2:
6744 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6745 case NODE_LIST:
6746 while (argn) {
6747 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6748 return true;
6749 }
6750 argn = RNODE_LIST(argn)->nd_next;
6751 }
6752 return false;
6753 default:
6754 return true;
6755 }
6756}
6757
6758static VALUE
6759setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6760 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6761{
6762 VALUE ret;
6763 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6764
6765 if (argn) {
6766 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6767 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6768
6769 if (check_arg) {
6770 switch(nd_type(check_arg)) {
6771 case(NODE_SPLAT):
6772 // avoid caller side array allocation for f(*arg)
6773 dup_rest = SPLATARRAY_FALSE;
6774 break;
6775 case(NODE_ARGSCAT):
6776 // avoid caller side array allocation for f(1, *arg)
6777 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6778 break;
6779 case(NODE_ARGSPUSH):
6780 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6781 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6782 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6783 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6784 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6785 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6786
6787 if (dup_rest == SPLATARRAY_FALSE) {
6788 // require allocation for keyword key/value/splat that may modify splatted argument
6789 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6790 while (node) {
6791 NODE *key_node = RNODE_LIST(node)->nd_head;
6792 if (key_node && setup_args_dup_rest_p(key_node)) {
6793 dup_rest = SPLATARRAY_TRUE;
6794 break;
6795 }
6796
6797 node = RNODE_LIST(node)->nd_next;
6798 NODE *value_node = RNODE_LIST(node)->nd_head;
6799 if (setup_args_dup_rest_p(value_node)) {
6800 dup_rest = SPLATARRAY_TRUE;
6801 break;
6802 }
6803
6804 node = RNODE_LIST(node)->nd_next;
6805 }
6806 }
6807 break;
6808 default:
6809 break;
6810 }
6811 }
6812
6813 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6814 // for block pass that may modify splatted argument, dup rest and kwrest if given
6815 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6816 }
6817 }
6818 initial_dup_rest = dup_rest;
6819
6820 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6821 DECL_ANCHOR(arg_block);
6822 INIT_ANCHOR(arg_block);
6823
6824 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6825 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6826
6827 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6828 const NODE * arg_node =
6829 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6830
6831 int argc = 0;
6832
6833 // Only compile leading args:
6834 // foo(x, y, ...)
6835 // ^^^^
6836 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6837 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6838 }
6839
6840 *flag |= VM_CALL_FORWARDING;
6841
6842 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6843 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6844 return INT2FIX(argc);
6845 }
6846 else {
6847 *flag |= VM_CALL_ARGS_BLOCKARG;
6848
6849 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6850 }
6851
6852 if (LIST_INSN_SIZE_ONE(arg_block)) {
6853 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6854 if (IS_INSN(elem)) {
6855 INSN *iobj = (INSN *)elem;
6856 if (iobj->insn_id == BIN(getblockparam)) {
6857 iobj->insn_id = BIN(getblockparamproxy);
6858 }
6859 }
6860 }
6861 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6862 ADD_SEQ(args, arg_block);
6863 }
6864 else {
6865 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6866 }
6867 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6868 return ret;
6869}
6870
6871static void
6872build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6873{
6874 const NODE *body = ptr;
6875 int line = nd_line(body);
6876 VALUE argc = INT2FIX(0);
6877 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6878
6879 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6880 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6881 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6882 iseq_set_local_table(iseq, 0, 0);
6883}
6884
6885static void
6886compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6887{
6888 const NODE *vars;
6889 LINK_ELEMENT *last;
6890 int line = nd_line(node);
6891 const NODE *line_node = node;
6892 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6893
6894#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6895 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6896#else
6897 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6898#endif
6899 ADD_INSN(ret, line_node, dup);
6900 ADD_INSNL(ret, line_node, branchunless, fail_label);
6901
6902 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6903 INSN *cap;
6904 if (RNODE_BLOCK(vars)->nd_next) {
6905 ADD_INSN(ret, line_node, dup);
6906 }
6907 last = ret->last;
6908 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6909 last = last->next; /* putobject :var */
6910 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6911 NULL, INT2FIX(0), NULL);
6912 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6913#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6914 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6915 /* only one name */
6916 DECL_ANCHOR(nom);
6917
6918 INIT_ANCHOR(nom);
6919 ADD_INSNL(nom, line_node, jump, end_label);
6920 ADD_LABEL(nom, fail_label);
6921# if 0 /* $~ must be MatchData or nil */
6922 ADD_INSN(nom, line_node, pop);
6923 ADD_INSN(nom, line_node, putnil);
6924# endif
6925 ADD_LABEL(nom, end_label);
6926 (nom->last->next = cap->link.next)->prev = nom->last;
6927 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6928 return;
6929 }
6930#endif
6931 }
6932 ADD_INSNL(ret, line_node, jump, end_label);
6933 ADD_LABEL(ret, fail_label);
6934 ADD_INSN(ret, line_node, pop);
6935 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6936 last = ret->last;
6937 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6938 last = last->next; /* putobject :var */
6939 ((INSN*)last)->insn_id = BIN(putnil);
6940 ((INSN*)last)->operand_size = 0;
6941 }
6942 ADD_LABEL(ret, end_label);
6943}
6944
6945static int
6946optimizable_range_item_p(const NODE *n)
6947{
6948 if (!n) return FALSE;
6949 switch (nd_type(n)) {
6950 case NODE_LINE:
6951 return TRUE;
6952 case NODE_INTEGER:
6953 return TRUE;
6954 case NODE_NIL:
6955 return TRUE;
6956 default:
6957 return FALSE;
6958 }
6959}
6960
6961static VALUE
6962optimized_range_item(const NODE *n)
6963{
6964 switch (nd_type(n)) {
6965 case NODE_LINE:
6966 return rb_node_line_lineno_val(n);
6967 case NODE_INTEGER:
6968 return rb_node_integer_literal_val(n);
6969 case NODE_FLOAT:
6970 return rb_node_float_literal_val(n);
6971 case NODE_RATIONAL:
6972 return rb_node_rational_literal_val(n);
6973 case NODE_IMAGINARY:
6974 return rb_node_imaginary_literal_val(n);
6975 case NODE_NIL:
6976 return Qnil;
6977 default:
6978 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6979 }
6980}
6981
6982static int
6983compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6984{
6985 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6986 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6987
6988 const int line = nd_line(node);
6989 const NODE *line_node = node;
6990 DECL_ANCHOR(cond_seq);
6991 LABEL *then_label, *else_label, *end_label;
6992 VALUE branches = Qfalse;
6993
6994 INIT_ANCHOR(cond_seq);
6995 then_label = NEW_LABEL(line);
6996 else_label = NEW_LABEL(line);
6997 end_label = 0;
6998
6999 NODE *cond = RNODE_IF(node)->nd_cond;
7000 if (nd_type(cond) == NODE_BLOCK) {
7001 cond = RNODE_BLOCK(cond)->nd_head;
7002 }
7003
7004 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7005 ADD_SEQ(ret, cond_seq);
7006
7007 if (then_label->refcnt && else_label->refcnt) {
7008 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7009 }
7010
7011 if (then_label->refcnt) {
7012 ADD_LABEL(ret, then_label);
7013
7014 DECL_ANCHOR(then_seq);
7015 INIT_ANCHOR(then_seq);
7016 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7017
7018 if (else_label->refcnt) {
7019 const NODE *const coverage_node = node_body ? node_body : node;
7020 add_trace_branch_coverage(
7021 iseq,
7022 ret,
7023 nd_code_loc(coverage_node),
7024 nd_node_id(coverage_node),
7025 0,
7026 type == NODE_IF ? "then" : "else",
7027 branches);
7028 end_label = NEW_LABEL(line);
7029 ADD_INSNL(then_seq, line_node, jump, end_label);
7030 if (!popped) {
7031 ADD_INSN(then_seq, line_node, pop);
7032 }
7033 }
7034 ADD_SEQ(ret, then_seq);
7035 }
7036
7037 if (else_label->refcnt) {
7038 ADD_LABEL(ret, else_label);
7039
7040 DECL_ANCHOR(else_seq);
7041 INIT_ANCHOR(else_seq);
7042 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7043
7044 if (then_label->refcnt) {
7045 const NODE *const coverage_node = node_else ? node_else : node;
7046 add_trace_branch_coverage(
7047 iseq,
7048 ret,
7049 nd_code_loc(coverage_node),
7050 nd_node_id(coverage_node),
7051 1,
7052 type == NODE_IF ? "else" : "then",
7053 branches);
7054 }
7055 ADD_SEQ(ret, else_seq);
7056 }
7057
7058 if (end_label) {
7059 ADD_LABEL(ret, end_label);
7060 }
7061
7062 return COMPILE_OK;
7063}
7064
7065static int
7066compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7067{
7068 const NODE *vals;
7069 const NODE *node = orig_node;
7070 LABEL *endlabel, *elselabel;
7071 DECL_ANCHOR(head);
7072 DECL_ANCHOR(body_seq);
7073 DECL_ANCHOR(cond_seq);
7074 int only_special_literals = 1;
7075 VALUE literals = rb_hash_new();
7076 int line;
7077 enum node_type type;
7078 const NODE *line_node;
7079 VALUE branches = Qfalse;
7080 int branch_id = 0;
7081
7082 INIT_ANCHOR(head);
7083 INIT_ANCHOR(body_seq);
7084 INIT_ANCHOR(cond_seq);
7085
7086 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7087
7088 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7089
7090 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7091
7092 node = RNODE_CASE(node)->nd_body;
7093 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7094 type = nd_type(node);
7095 line = nd_line(node);
7096 line_node = node;
7097
7098 endlabel = NEW_LABEL(line);
7099 elselabel = NEW_LABEL(line);
7100
7101 ADD_SEQ(ret, head); /* case VAL */
7102
7103 while (type == NODE_WHEN) {
7104 LABEL *l1;
7105
7106 l1 = NEW_LABEL(line);
7107 ADD_LABEL(body_seq, l1);
7108 ADD_INSN(body_seq, line_node, pop);
7109
7110 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7111 add_trace_branch_coverage(
7112 iseq,
7113 body_seq,
7114 nd_code_loc(coverage_node),
7115 nd_node_id(coverage_node),
7116 branch_id++,
7117 "when",
7118 branches);
7119
7120 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7121 ADD_INSNL(body_seq, line_node, jump, endlabel);
7122
7123 vals = RNODE_WHEN(node)->nd_head;
7124 if (vals) {
7125 switch (nd_type(vals)) {
7126 case NODE_LIST:
7127 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7128 if (only_special_literals < 0) return COMPILE_NG;
7129 break;
7130 case NODE_SPLAT:
7131 case NODE_ARGSCAT:
7132 case NODE_ARGSPUSH:
7133 only_special_literals = 0;
7134 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7135 break;
7136 default:
7137 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7138 }
7139 }
7140 else {
7141 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7142 }
7143
7144 node = RNODE_WHEN(node)->nd_next;
7145 if (!node) {
7146 break;
7147 }
7148 type = nd_type(node);
7149 line = nd_line(node);
7150 line_node = node;
7151 }
7152 /* else */
7153 if (node) {
7154 ADD_LABEL(cond_seq, elselabel);
7155 ADD_INSN(cond_seq, line_node, pop);
7156 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7157 CHECK(COMPILE_(cond_seq, "else", node, popped));
7158 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7159 }
7160 else {
7161 debugs("== else (implicit)\n");
7162 ADD_LABEL(cond_seq, elselabel);
7163 ADD_INSN(cond_seq, orig_node, pop);
7164 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7165 if (!popped) {
7166 ADD_INSN(cond_seq, orig_node, putnil);
7167 }
7168 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7169 }
7170
7171 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7172 ADD_INSN(ret, orig_node, dup);
7173 rb_obj_hide(literals);
7174 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7175 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7176 LABEL_REF(elselabel);
7177 }
7178
7179 ADD_SEQ(ret, cond_seq);
7180 ADD_SEQ(ret, body_seq);
7181 ADD_LABEL(ret, endlabel);
7182 return COMPILE_OK;
7183}
7184
7185static int
7186compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7187{
7188 const NODE *vals;
7189 const NODE *val;
7190 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7191 LABEL *endlabel;
7192 DECL_ANCHOR(body_seq);
7193 VALUE branches = Qfalse;
7194 int branch_id = 0;
7195
7196 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7197
7198 INIT_ANCHOR(body_seq);
7199 endlabel = NEW_LABEL(nd_line(node));
7200
7201 while (node && nd_type_p(node, NODE_WHEN)) {
7202 const int line = nd_line(node);
7203 LABEL *l1 = NEW_LABEL(line);
7204 ADD_LABEL(body_seq, l1);
7205
7206 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7207 add_trace_branch_coverage(
7208 iseq,
7209 body_seq,
7210 nd_code_loc(coverage_node),
7211 nd_node_id(coverage_node),
7212 branch_id++,
7213 "when",
7214 branches);
7215
7216 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7217 ADD_INSNL(body_seq, node, jump, endlabel);
7218
7219 vals = RNODE_WHEN(node)->nd_head;
7220 if (!vals) {
7221 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7222 }
7223 switch (nd_type(vals)) {
7224 case NODE_LIST:
7225 while (vals) {
7226 LABEL *lnext;
7227 val = RNODE_LIST(vals)->nd_head;
7228 lnext = NEW_LABEL(nd_line(val));
7229 debug_compile("== when2\n", (void)0);
7230 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7231 ADD_LABEL(ret, lnext);
7232 vals = RNODE_LIST(vals)->nd_next;
7233 }
7234 break;
7235 case NODE_SPLAT:
7236 case NODE_ARGSCAT:
7237 case NODE_ARGSPUSH:
7238 ADD_INSN(ret, vals, putnil);
7239 CHECK(COMPILE(ret, "when2/cond splat", vals));
7240 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7241 ADD_INSNL(ret, vals, branchif, l1);
7242 break;
7243 default:
7244 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7245 }
7246 node = RNODE_WHEN(node)->nd_next;
7247 }
7248 /* else */
7249 const NODE *const coverage_node = node ? node : orig_node;
7250 add_trace_branch_coverage(
7251 iseq,
7252 ret,
7253 nd_code_loc(coverage_node),
7254 nd_node_id(coverage_node),
7255 branch_id,
7256 "else",
7257 branches);
7258 CHECK(COMPILE_(ret, "else", node, popped));
7259 ADD_INSNL(ret, orig_node, jump, endlabel);
7260
7261 ADD_SEQ(ret, body_seq);
7262 ADD_LABEL(ret, endlabel);
7263 return COMPILE_OK;
7264}
7265
7266static 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);
7267
7268static 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);
7269static 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);
7270static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7271static 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);
7272static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7273
7274#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7275#define CASE3_BI_OFFSET_ERROR_STRING 1
7276#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7277#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7278#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7279
7280static int
7281iseq_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)
7282{
7283 const int line = nd_line(node);
7284 const NODE *line_node = node;
7285
7286 switch (nd_type(node)) {
7287 case NODE_ARYPTN: {
7288 /*
7289 * if pattern.use_rest_num?
7290 * rest_num = 0
7291 * end
7292 * if pattern.has_constant_node?
7293 * unless pattern.constant === obj
7294 * goto match_failed
7295 * end
7296 * end
7297 * unless obj.respond_to?(:deconstruct)
7298 * goto match_failed
7299 * end
7300 * d = obj.deconstruct
7301 * unless Array === d
7302 * goto type_error
7303 * end
7304 * min_argc = pattern.pre_args_num + pattern.post_args_num
7305 * if pattern.has_rest_arg?
7306 * unless d.length >= min_argc
7307 * goto match_failed
7308 * end
7309 * else
7310 * unless d.length == min_argc
7311 * goto match_failed
7312 * end
7313 * end
7314 * pattern.pre_args_num.each do |i|
7315 * unless pattern.pre_args[i].match?(d[i])
7316 * goto match_failed
7317 * end
7318 * end
7319 * if pattern.use_rest_num?
7320 * rest_num = d.length - min_argc
7321 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7322 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7323 * goto match_failed
7324 * end
7325 * end
7326 * end
7327 * pattern.post_args_num.each do |i|
7328 * j = pattern.pre_args_num + i
7329 * j += rest_num
7330 * unless pattern.post_args[i].match?(d[j])
7331 * goto match_failed
7332 * end
7333 * end
7334 * goto matched
7335 * type_error:
7336 * FrozenCore.raise TypeError
7337 * match_failed:
7338 * goto unmatched
7339 */
7340 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7341 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7342 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7343
7344 const int min_argc = pre_args_num + post_args_num;
7345 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7346 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7347
7348 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7349 int i;
7350 match_failed = NEW_LABEL(line);
7351 type_error = NEW_LABEL(line);
7352 deconstruct = NEW_LABEL(line);
7353 deconstructed = NEW_LABEL(line);
7354
7355 if (use_rest_num) {
7356 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7357 ADD_INSN(ret, line_node, swap);
7358 if (base_index) {
7359 base_index++;
7360 }
7361 }
7362
7363 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7364
7365 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7366
7367 ADD_INSN(ret, line_node, dup);
7368 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7369 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7370 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7371 if (in_single_pattern) {
7372 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7373 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7374 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7375 INT2FIX(min_argc), base_index + 1 /* (1) */));
7376 }
7377 ADD_INSNL(ret, line_node, branchunless, match_failed);
7378
7379 for (i = 0; i < pre_args_num; i++) {
7380 ADD_INSN(ret, line_node, dup);
7381 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7382 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7383 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));
7384 args = RNODE_LIST(args)->nd_next;
7385 }
7386
7387 if (RNODE_ARYPTN(node)->rest_arg) {
7388 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7389 ADD_INSN(ret, line_node, dup);
7390 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7391 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7392 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7393 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7394 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7395 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7396 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7397
7398 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));
7399 }
7400 else {
7401 if (post_args_num > 0) {
7402 ADD_INSN(ret, line_node, dup);
7403 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7404 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7405 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7406 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7407 ADD_INSN(ret, line_node, pop);
7408 }
7409 }
7410 }
7411
7412 args = RNODE_ARYPTN(node)->post_args;
7413 for (i = 0; i < post_args_num; i++) {
7414 ADD_INSN(ret, line_node, dup);
7415
7416 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7417 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7418 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7419
7420 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7421 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));
7422 args = RNODE_LIST(args)->nd_next;
7423 }
7424
7425 ADD_INSN(ret, line_node, pop);
7426 if (use_rest_num) {
7427 ADD_INSN(ret, line_node, pop);
7428 }
7429 ADD_INSNL(ret, line_node, jump, matched);
7430 ADD_INSN(ret, line_node, putnil);
7431 if (use_rest_num) {
7432 ADD_INSN(ret, line_node, putnil);
7433 }
7434
7435 ADD_LABEL(ret, type_error);
7436 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7437 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7438 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7439 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7440 ADD_INSN(ret, line_node, pop);
7441
7442 ADD_LABEL(ret, match_failed);
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, unmatched);
7448
7449 break;
7450 }
7451 case NODE_FNDPTN: {
7452 /*
7453 * if pattern.has_constant_node?
7454 * unless pattern.constant === obj
7455 * goto match_failed
7456 * end
7457 * end
7458 * unless obj.respond_to?(:deconstruct)
7459 * goto match_failed
7460 * end
7461 * d = obj.deconstruct
7462 * unless Array === d
7463 * goto type_error
7464 * end
7465 * unless d.length >= pattern.args_num
7466 * goto match_failed
7467 * end
7468 *
7469 * begin
7470 * len = d.length
7471 * limit = d.length - pattern.args_num
7472 * i = 0
7473 * while i <= limit
7474 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7475 * if pattern.has_pre_rest_arg_id
7476 * unless pattern.pre_rest_arg.match?(d[0, i])
7477 * goto find_failed
7478 * end
7479 * end
7480 * if pattern.has_post_rest_arg_id
7481 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7482 * goto find_failed
7483 * end
7484 * end
7485 * goto find_succeeded
7486 * end
7487 * i+=1
7488 * end
7489 * find_failed:
7490 * goto match_failed
7491 * find_succeeded:
7492 * end
7493 *
7494 * goto matched
7495 * type_error:
7496 * FrozenCore.raise TypeError
7497 * match_failed:
7498 * goto unmatched
7499 */
7500 const NODE *args = RNODE_FNDPTN(node)->args;
7501 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7502
7503 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7504 match_failed = NEW_LABEL(line);
7505 type_error = NEW_LABEL(line);
7506 deconstruct = NEW_LABEL(line);
7507 deconstructed = NEW_LABEL(line);
7508
7509 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7510
7511 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7512
7513 ADD_INSN(ret, line_node, dup);
7514 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7515 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7516 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7517 if (in_single_pattern) {
7518 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) */));
7519 }
7520 ADD_INSNL(ret, line_node, branchunless, match_failed);
7521
7522 {
7523 LABEL *while_begin = NEW_LABEL(nd_line(node));
7524 LABEL *next_loop = NEW_LABEL(nd_line(node));
7525 LABEL *find_succeeded = NEW_LABEL(line);
7526 LABEL *find_failed = NEW_LABEL(nd_line(node));
7527 int j;
7528
7529 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7530 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7531
7532 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7533 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7534 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7535
7536 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7537
7538 ADD_LABEL(ret, while_begin);
7539
7540 ADD_INSN(ret, line_node, dup);
7541 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7542 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7543 ADD_INSNL(ret, line_node, branchunless, find_failed);
7544
7545 for (j = 0; j < args_num; j++) {
7546 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7547 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7548 if (j != 0) {
7549 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7550 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7551 }
7552 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7553
7554 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));
7555 args = RNODE_LIST(args)->nd_next;
7556 }
7557
7558 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7559 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7560 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7561 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7562 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7563 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));
7564 }
7565 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7566 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7567 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7568 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7569 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7570 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7571 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7572 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));
7573 }
7574 ADD_INSNL(ret, line_node, jump, find_succeeded);
7575
7576 ADD_LABEL(ret, next_loop);
7577 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7578 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7579 ADD_INSNL(ret, line_node, jump, while_begin);
7580
7581 ADD_LABEL(ret, find_failed);
7582 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7583 if (in_single_pattern) {
7584 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7585 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7586 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7587 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7588 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7589
7590 ADD_INSN1(ret, line_node, putobject, Qfalse);
7591 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7592
7593 ADD_INSN(ret, line_node, pop);
7594 ADD_INSN(ret, line_node, pop);
7595 }
7596 ADD_INSNL(ret, line_node, jump, match_failed);
7597 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7598
7599 ADD_LABEL(ret, find_succeeded);
7600 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7601 }
7602
7603 ADD_INSN(ret, line_node, pop);
7604 ADD_INSNL(ret, line_node, jump, matched);
7605 ADD_INSN(ret, line_node, putnil);
7606
7607 ADD_LABEL(ret, type_error);
7608 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7609 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7610 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7611 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7612 ADD_INSN(ret, line_node, pop);
7613
7614 ADD_LABEL(ret, match_failed);
7615 ADD_INSN(ret, line_node, pop);
7616 ADD_INSNL(ret, line_node, jump, unmatched);
7617
7618 break;
7619 }
7620 case NODE_HSHPTN: {
7621 /*
7622 * keys = nil
7623 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7624 * keys = pattern.kw_args_node.keys
7625 * end
7626 * if pattern.has_constant_node?
7627 * unless pattern.constant === obj
7628 * goto match_failed
7629 * end
7630 * end
7631 * unless obj.respond_to?(:deconstruct_keys)
7632 * goto match_failed
7633 * end
7634 * d = obj.deconstruct_keys(keys)
7635 * unless Hash === d
7636 * goto type_error
7637 * end
7638 * if pattern.has_kw_rest_arg_node?
7639 * d = d.dup
7640 * end
7641 * if pattern.has_kw_args_node?
7642 * pattern.kw_args_node.each |k,|
7643 * unless d.key?(k)
7644 * goto match_failed
7645 * end
7646 * end
7647 * pattern.kw_args_node.each |k, pat|
7648 * if pattern.has_kw_rest_arg_node?
7649 * unless pat.match?(d.delete(k))
7650 * goto match_failed
7651 * end
7652 * else
7653 * unless pat.match?(d[k])
7654 * goto match_failed
7655 * end
7656 * end
7657 * end
7658 * else
7659 * unless d.empty?
7660 * goto match_failed
7661 * end
7662 * end
7663 * if pattern.has_kw_rest_arg_node?
7664 * if pattern.no_rest_keyword?
7665 * unless d.empty?
7666 * goto match_failed
7667 * end
7668 * else
7669 * unless pattern.kw_rest_arg_node.match?(d)
7670 * goto match_failed
7671 * end
7672 * end
7673 * end
7674 * goto matched
7675 * type_error:
7676 * FrozenCore.raise TypeError
7677 * match_failed:
7678 * goto unmatched
7679 */
7680 LABEL *match_failed, *type_error;
7681 VALUE keys = Qnil;
7682
7683 match_failed = NEW_LABEL(line);
7684 type_error = NEW_LABEL(line);
7685
7686 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7687 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7688 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7689 while (kw_args) {
7690 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7691 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7692 }
7693 }
7694
7695 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7696
7697 ADD_INSN(ret, line_node, dup);
7698 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7699 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7700 if (in_single_pattern) {
7701 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7702 }
7703 ADD_INSNL(ret, line_node, branchunless, match_failed);
7704
7705 if (NIL_P(keys)) {
7706 ADD_INSN(ret, line_node, putnil);
7707 }
7708 else {
7709 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7710 ADD_INSN1(ret, line_node, duparray, keys);
7711 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7712 }
7713 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7714
7715 ADD_INSN(ret, line_node, dup);
7716 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7717 ADD_INSNL(ret, line_node, branchunless, type_error);
7718
7719 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7720 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7721 }
7722
7723 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7724 int i;
7725 int keys_num;
7726 const NODE *args;
7727 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7728 if (args) {
7729 DECL_ANCHOR(match_values);
7730 INIT_ANCHOR(match_values);
7731 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7732 for (i = 0; i < keys_num; i++) {
7733 NODE *key_node = RNODE_LIST(args)->nd_head;
7734 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7735 VALUE key = get_symbol_value(iseq, key_node);
7736
7737 ADD_INSN(ret, line_node, dup);
7738 ADD_INSN1(ret, line_node, putobject, key);
7739 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7740 if (in_single_pattern) {
7741 LABEL *match_succeeded;
7742 match_succeeded = NEW_LABEL(line);
7743
7744 ADD_INSN(ret, line_node, dup);
7745 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7746
7747 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7748 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7749 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7750 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7751 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7752 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7753 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7754 ADD_INSN1(ret, line_node, putobject, key); // (7)
7755 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7756
7757 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7758
7759 ADD_LABEL(ret, match_succeeded);
7760 }
7761 ADD_INSNL(ret, line_node, branchunless, match_failed);
7762
7763 ADD_INSN(match_values, line_node, dup);
7764 ADD_INSN1(match_values, line_node, putobject, key);
7765 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7766 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7767 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7768 }
7769 ADD_SEQ(ret, match_values);
7770 }
7771 }
7772 else {
7773 ADD_INSN(ret, line_node, dup);
7774 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7775 if (in_single_pattern) {
7776 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7777 }
7778 ADD_INSNL(ret, line_node, branchunless, match_failed);
7779 }
7780
7781 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7782 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7783 ADD_INSN(ret, line_node, dup);
7784 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7785 if (in_single_pattern) {
7786 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7787 }
7788 ADD_INSNL(ret, line_node, branchunless, match_failed);
7789 }
7790 else {
7791 ADD_INSN(ret, line_node, dup); // (11)
7792 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));
7793 }
7794 }
7795
7796 ADD_INSN(ret, line_node, pop);
7797 ADD_INSNL(ret, line_node, jump, matched);
7798 ADD_INSN(ret, line_node, putnil);
7799
7800 ADD_LABEL(ret, type_error);
7801 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7802 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7803 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7804 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7805 ADD_INSN(ret, line_node, pop);
7806
7807 ADD_LABEL(ret, match_failed);
7808 ADD_INSN(ret, line_node, pop);
7809 ADD_INSNL(ret, line_node, jump, unmatched);
7810 break;
7811 }
7812 case NODE_SYM:
7813 case NODE_REGX:
7814 case NODE_LINE:
7815 case NODE_INTEGER:
7816 case NODE_FLOAT:
7817 case NODE_RATIONAL:
7818 case NODE_IMAGINARY:
7819 case NODE_FILE:
7820 case NODE_ENCODING:
7821 case NODE_STR:
7822 case NODE_XSTR:
7823 case NODE_DSTR:
7824 case NODE_DSYM:
7825 case NODE_DREGX:
7826 case NODE_LIST:
7827 case NODE_ZLIST:
7828 case NODE_LAMBDA:
7829 case NODE_DOT2:
7830 case NODE_DOT3:
7831 case NODE_CONST:
7832 case NODE_LVAR:
7833 case NODE_DVAR:
7834 case NODE_IVAR:
7835 case NODE_CVAR:
7836 case NODE_GVAR:
7837 case NODE_TRUE:
7838 case NODE_FALSE:
7839 case NODE_SELF:
7840 case NODE_NIL:
7841 case NODE_COLON2:
7842 case NODE_COLON3:
7843 case NODE_BEGIN:
7844 case NODE_BLOCK:
7845 case NODE_ONCE:
7846 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7847 if (in_single_pattern) {
7848 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7849 }
7850 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7851 if (in_single_pattern) {
7852 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7853 }
7854 ADD_INSNL(ret, line_node, branchif, matched);
7855 ADD_INSNL(ret, line_node, jump, unmatched);
7856 break;
7857 case NODE_LASGN: {
7858 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7859 ID id = RNODE_LASGN(node)->nd_vid;
7860 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7861
7862 if (in_alt_pattern) {
7863 const char *name = rb_id2name(id);
7864 if (name && strlen(name) > 0 && name[0] != '_') {
7865 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7866 rb_id2str(id));
7867 return COMPILE_NG;
7868 }
7869 }
7870
7871 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7872 ADD_INSNL(ret, line_node, jump, matched);
7873 break;
7874 }
7875 case NODE_DASGN: {
7876 int idx, lv, ls;
7877 ID id = RNODE_DASGN(node)->nd_vid;
7878
7879 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7880
7881 if (in_alt_pattern) {
7882 const char *name = rb_id2name(id);
7883 if (name && strlen(name) > 0 && name[0] != '_') {
7884 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7885 rb_id2str(id));
7886 return COMPILE_NG;
7887 }
7888 }
7889
7890 if (idx < 0) {
7891 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7892 rb_id2str(id));
7893 return COMPILE_NG;
7894 }
7895 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7896 ADD_INSNL(ret, line_node, jump, matched);
7897 break;
7898 }
7899 case NODE_IF:
7900 case NODE_UNLESS: {
7901 LABEL *match_failed;
7902 match_failed = unmatched;
7903 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7904 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7905 if (in_single_pattern) {
7906 LABEL *match_succeeded;
7907 match_succeeded = NEW_LABEL(line);
7908
7909 ADD_INSN(ret, line_node, dup);
7910 if (nd_type_p(node, NODE_IF)) {
7911 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7912 }
7913 else {
7914 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7915 }
7916
7917 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7918 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7919 ADD_INSN1(ret, line_node, putobject, Qfalse);
7920 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7921
7922 ADD_INSN(ret, line_node, pop);
7923 ADD_INSN(ret, line_node, pop);
7924
7925 ADD_LABEL(ret, match_succeeded);
7926 }
7927 if (nd_type_p(node, NODE_IF)) {
7928 ADD_INSNL(ret, line_node, branchunless, match_failed);
7929 }
7930 else {
7931 ADD_INSNL(ret, line_node, branchif, match_failed);
7932 }
7933 ADD_INSNL(ret, line_node, jump, matched);
7934 break;
7935 }
7936 case NODE_HASH: {
7937 NODE *n;
7938 LABEL *match_failed;
7939 match_failed = NEW_LABEL(line);
7940
7941 n = RNODE_HASH(node)->nd_head;
7942 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7943 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7944 return COMPILE_NG;
7945 }
7946
7947 ADD_INSN(ret, line_node, dup); // (1)
7948 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));
7949 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));
7950 ADD_INSN(ret, line_node, putnil);
7951
7952 ADD_LABEL(ret, match_failed);
7953 ADD_INSN(ret, line_node, pop);
7954 ADD_INSNL(ret, line_node, jump, unmatched);
7955 break;
7956 }
7957 case NODE_OR: {
7958 LABEL *match_succeeded, *fin;
7959 match_succeeded = NEW_LABEL(line);
7960 fin = NEW_LABEL(line);
7961
7962 ADD_INSN(ret, line_node, dup); // (1)
7963 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));
7964 ADD_LABEL(ret, match_succeeded);
7965 ADD_INSN(ret, line_node, pop);
7966 ADD_INSNL(ret, line_node, jump, matched);
7967 ADD_INSN(ret, line_node, putnil);
7968 ADD_LABEL(ret, fin);
7969 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7970 break;
7971 }
7972 default:
7973 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7974 }
7975 return COMPILE_OK;
7976}
7977
7978static int
7979iseq_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)
7980{
7981 LABEL *fin = NEW_LABEL(nd_line(node));
7982 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7983 ADD_LABEL(ret, fin);
7984 return COMPILE_OK;
7985}
7986
7987static int
7988iseq_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)
7989{
7990 const NODE *line_node = node;
7991
7992 if (RNODE_ARYPTN(node)->nd_pconst) {
7993 ADD_INSN(ret, line_node, dup); // (1)
7994 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7995 if (in_single_pattern) {
7996 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7997 }
7998 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7999 if (in_single_pattern) {
8000 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8001 }
8002 ADD_INSNL(ret, line_node, branchunless, match_failed);
8003 }
8004 return COMPILE_OK;
8005}
8006
8007
8008static int
8009iseq_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)
8010{
8011 const NODE *line_node = node;
8012
8013 // NOTE: this optimization allows us to re-use the #deconstruct value
8014 // (or its absence).
8015 if (use_deconstructed_cache) {
8016 // If value is nil then we haven't tried to deconstruct
8017 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8018 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8019
8020 // If false then the value is not deconstructable
8021 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8022 ADD_INSNL(ret, line_node, branchunless, match_failed);
8023
8024 // Drop value, add deconstructed to the stack and jump
8025 ADD_INSN(ret, line_node, pop); // (1)
8026 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8027 ADD_INSNL(ret, line_node, jump, deconstructed);
8028 }
8029 else {
8030 ADD_INSNL(ret, line_node, jump, deconstruct);
8031 }
8032
8033 ADD_LABEL(ret, deconstruct);
8034 ADD_INSN(ret, line_node, dup);
8035 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8036 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8037
8038 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8039 if (use_deconstructed_cache) {
8040 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8041 }
8042
8043 if (in_single_pattern) {
8044 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8045 }
8046
8047 ADD_INSNL(ret, line_node, branchunless, match_failed);
8048
8049 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8050
8051 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8052 if (use_deconstructed_cache) {
8053 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8054 }
8055
8056 ADD_INSN(ret, line_node, dup);
8057 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8058 ADD_INSNL(ret, line_node, branchunless, type_error);
8059
8060 ADD_LABEL(ret, deconstructed);
8061
8062 return COMPILE_OK;
8063}
8064
8065static int
8066iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8067{
8068 /*
8069 * if match_succeeded?
8070 * goto match_succeeded
8071 * end
8072 * error_string = FrozenCore.sprintf(errmsg, matchee)
8073 * key_error_p = false
8074 * match_succeeded:
8075 */
8076 const int line = nd_line(node);
8077 const NODE *line_node = node;
8078 LABEL *match_succeeded = NEW_LABEL(line);
8079
8080 ADD_INSN(ret, line_node, dup);
8081 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8082
8083 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8084 ADD_INSN1(ret, line_node, putobject, errmsg);
8085 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8086 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8087 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8088
8089 ADD_INSN1(ret, line_node, putobject, Qfalse);
8090 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8091
8092 ADD_INSN(ret, line_node, pop);
8093 ADD_INSN(ret, line_node, pop);
8094 ADD_LABEL(ret, match_succeeded);
8095
8096 return COMPILE_OK;
8097}
8098
8099static int
8100iseq_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)
8101{
8102 /*
8103 * if match_succeeded?
8104 * goto match_succeeded
8105 * end
8106 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8107 * key_error_p = false
8108 * match_succeeded:
8109 */
8110 const int line = nd_line(node);
8111 const NODE *line_node = node;
8112 LABEL *match_succeeded = NEW_LABEL(line);
8113
8114 ADD_INSN(ret, line_node, dup);
8115 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8116
8117 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8118 ADD_INSN1(ret, line_node, putobject, errmsg);
8119 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8120 ADD_INSN(ret, line_node, dup);
8121 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8122 ADD_INSN1(ret, line_node, putobject, pattern_length);
8123 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8124 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8125
8126 ADD_INSN1(ret, line_node, putobject, Qfalse);
8127 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8128
8129 ADD_INSN(ret, line_node, pop);
8130 ADD_INSN(ret, line_node, pop);
8131 ADD_LABEL(ret, match_succeeded);
8132
8133 return COMPILE_OK;
8134}
8135
8136static int
8137iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8138{
8139 /*
8140 * if match_succeeded?
8141 * goto match_succeeded
8142 * end
8143 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8144 * key_error_p = false
8145 * match_succeeded:
8146 */
8147 const int line = nd_line(node);
8148 const NODE *line_node = node;
8149 LABEL *match_succeeded = NEW_LABEL(line);
8150
8151 ADD_INSN(ret, line_node, dup);
8152 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8153
8154 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8155 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8156 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8157 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8158 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8159 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8160
8161 ADD_INSN1(ret, line_node, putobject, Qfalse);
8162 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8163
8164 ADD_INSN(ret, line_node, pop);
8165 ADD_INSN(ret, line_node, pop);
8166
8167 ADD_LABEL(ret, match_succeeded);
8168 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8169 ADD_INSN(ret, line_node, pop);
8170 ADD_INSN(ret, line_node, pop);
8171
8172 return COMPILE_OK;
8173}
8174
8175static int
8176compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8177{
8178 const NODE *pattern;
8179 const NODE *node = orig_node;
8180 LABEL *endlabel, *elselabel;
8181 DECL_ANCHOR(head);
8182 DECL_ANCHOR(body_seq);
8183 DECL_ANCHOR(cond_seq);
8184 int line;
8185 enum node_type type;
8186 const NODE *line_node;
8187 VALUE branches = 0;
8188 int branch_id = 0;
8189 bool single_pattern;
8190
8191 INIT_ANCHOR(head);
8192 INIT_ANCHOR(body_seq);
8193 INIT_ANCHOR(cond_seq);
8194
8195 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8196
8197 node = RNODE_CASE3(node)->nd_body;
8198 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8199 type = nd_type(node);
8200 line = nd_line(node);
8201 line_node = node;
8202 single_pattern = !RNODE_IN(node)->nd_next;
8203
8204 endlabel = NEW_LABEL(line);
8205 elselabel = NEW_LABEL(line);
8206
8207 if (single_pattern) {
8208 /* allocate stack for ... */
8209 ADD_INSN(head, line_node, putnil); /* key_error_key */
8210 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8211 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8212 ADD_INSN(head, line_node, putnil); /* error_string */
8213 }
8214 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8215
8216 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8217
8218 ADD_SEQ(ret, head); /* case VAL */
8219
8220 while (type == NODE_IN) {
8221 LABEL *l1;
8222
8223 if (branch_id) {
8224 ADD_INSN(body_seq, line_node, putnil);
8225 }
8226 l1 = NEW_LABEL(line);
8227 ADD_LABEL(body_seq, l1);
8228 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8229
8230 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8231 add_trace_branch_coverage(
8232 iseq,
8233 body_seq,
8234 nd_code_loc(coverage_node),
8235 nd_node_id(coverage_node),
8236 branch_id++,
8237 "in",
8238 branches);
8239
8240 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8241 ADD_INSNL(body_seq, line_node, jump, endlabel);
8242
8243 pattern = RNODE_IN(node)->nd_head;
8244 if (pattern) {
8245 int pat_line = nd_line(pattern);
8246 LABEL *next_pat = NEW_LABEL(pat_line);
8247 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8248 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8249 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8250 ADD_LABEL(cond_seq, next_pat);
8251 LABEL_UNREMOVABLE(next_pat);
8252 }
8253 else {
8254 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8255 return COMPILE_NG;
8256 }
8257
8258 node = RNODE_IN(node)->nd_next;
8259 if (!node) {
8260 break;
8261 }
8262 type = nd_type(node);
8263 line = nd_line(node);
8264 line_node = node;
8265 }
8266 /* else */
8267 if (node) {
8268 ADD_LABEL(cond_seq, elselabel);
8269 ADD_INSN(cond_seq, line_node, pop);
8270 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8271 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8272 CHECK(COMPILE_(cond_seq, "else", node, popped));
8273 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8274 ADD_INSN(cond_seq, line_node, putnil);
8275 if (popped) {
8276 ADD_INSN(cond_seq, line_node, putnil);
8277 }
8278 }
8279 else {
8280 debugs("== else (implicit)\n");
8281 ADD_LABEL(cond_seq, elselabel);
8282 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8283 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8284
8285 if (single_pattern) {
8286 /*
8287 * if key_error_p
8288 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8289 * else
8290 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8291 * end
8292 */
8293 LABEL *key_error, *fin;
8294 struct rb_callinfo_kwarg *kw_arg;
8295
8296 key_error = NEW_LABEL(line);
8297 fin = NEW_LABEL(line);
8298
8299 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8300 kw_arg->references = 0;
8301 kw_arg->keyword_len = 2;
8302 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8303 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8304
8305 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8306 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8307 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8308 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8309 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8310 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8311 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8312 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8313 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8314 ADD_INSNL(cond_seq, orig_node, jump, fin);
8315
8316 ADD_LABEL(cond_seq, key_error);
8317 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8318 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8319 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8320 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8321 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8322 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8323 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8324 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8325 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8326 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8327
8328 ADD_LABEL(cond_seq, fin);
8329 }
8330 else {
8331 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8332 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8333 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8334 }
8335 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8336 if (!popped) {
8337 ADD_INSN(cond_seq, orig_node, putnil);
8338 }
8339 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8340 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8341 if (popped) {
8342 ADD_INSN(cond_seq, line_node, putnil);
8343 }
8344 }
8345
8346 ADD_SEQ(ret, cond_seq);
8347 ADD_SEQ(ret, body_seq);
8348 ADD_LABEL(ret, endlabel);
8349 return COMPILE_OK;
8350}
8351
8352#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8353#undef CASE3_BI_OFFSET_ERROR_STRING
8354#undef CASE3_BI_OFFSET_KEY_ERROR_P
8355#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8356#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8357
8358static int
8359compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8360{
8361 const int line = (int)nd_line(node);
8362 const NODE *line_node = node;
8363
8364 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8365 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8366 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8367 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8368 VALUE branches = Qfalse;
8369
8371
8372 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8373 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8374 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8375 LABEL *end_label = NEW_LABEL(line);
8376 LABEL *adjust_label = NEW_LABEL(line);
8377
8378 LABEL *next_catch_label = NEW_LABEL(line);
8379 LABEL *tmp_label = NULL;
8380
8381 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8382 push_ensure_entry(iseq, &enl, NULL, NULL);
8383
8384 if (RNODE_WHILE(node)->nd_state == 1) {
8385 ADD_INSNL(ret, line_node, jump, next_label);
8386 }
8387 else {
8388 tmp_label = NEW_LABEL(line);
8389 ADD_INSNL(ret, line_node, jump, tmp_label);
8390 }
8391 ADD_LABEL(ret, adjust_label);
8392 ADD_INSN(ret, line_node, putnil);
8393 ADD_LABEL(ret, next_catch_label);
8394 ADD_INSN(ret, line_node, pop);
8395 ADD_INSNL(ret, line_node, jump, next_label);
8396 if (tmp_label) ADD_LABEL(ret, tmp_label);
8397
8398 ADD_LABEL(ret, redo_label);
8399 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8400
8401 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8402 add_trace_branch_coverage(
8403 iseq,
8404 ret,
8405 nd_code_loc(coverage_node),
8406 nd_node_id(coverage_node),
8407 0,
8408 "body",
8409 branches);
8410
8411 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8412 ADD_LABEL(ret, next_label); /* next */
8413
8414 if (type == NODE_WHILE) {
8415 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8416 redo_label, end_label));
8417 }
8418 else {
8419 /* until */
8420 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8421 end_label, redo_label));
8422 }
8423
8424 ADD_LABEL(ret, end_label);
8425 ADD_ADJUST_RESTORE(ret, adjust_label);
8426
8427 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8428 /* ADD_INSN(ret, line_node, putundef); */
8429 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8430 return COMPILE_NG;
8431 }
8432 else {
8433 ADD_INSN(ret, line_node, putnil);
8434 }
8435
8436 ADD_LABEL(ret, break_label); /* break */
8437
8438 if (popped) {
8439 ADD_INSN(ret, line_node, pop);
8440 }
8441
8442 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8443 break_label);
8444 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8445 next_catch_label);
8446 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8447 ISEQ_COMPILE_DATA(iseq)->redo_label);
8448
8449 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8450 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8451 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8452 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8453 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8454 return COMPILE_OK;
8455}
8456
8457static int
8458compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8459{
8460 const int line = nd_line(node);
8461 const NODE *line_node = node;
8462 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8463 LABEL *retry_label = NEW_LABEL(line);
8464 LABEL *retry_end_l = NEW_LABEL(line);
8465 const rb_iseq_t *child_iseq;
8466
8467 ADD_LABEL(ret, retry_label);
8468 if (nd_type_p(node, NODE_FOR)) {
8469 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8470
8471 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8472 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8473 ISEQ_TYPE_BLOCK, line);
8474 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8475 }
8476 else {
8477 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8478 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8479 ISEQ_TYPE_BLOCK, line);
8480 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8481 }
8482
8483 {
8484 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8485 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8486 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8487 //
8488 // Normally, "send" instruction is at the last.
8489 // However, qcall under branch coverage measurement adds some instructions after the "send".
8490 //
8491 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8492 INSN *iobj;
8493 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8494 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8495 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8496 iobj = (INSN*) get_prev_insn(iobj);
8497 }
8498 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8499
8500 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8501 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8502 if (&iobj->link == LAST_ELEMENT(ret)) {
8503 ret->last = (LINK_ELEMENT*) retry_end_l;
8504 }
8505 }
8506
8507 if (popped) {
8508 ADD_INSN(ret, line_node, pop);
8509 }
8510
8511 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8512
8513 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8514 return COMPILE_OK;
8515}
8516
8517static int
8518compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8519{
8520 /* massign to var in "for"
8521 * (args.length == 1 && Array.try_convert(args[0])) || args
8522 */
8523 const NODE *line_node = node;
8524 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8525 LABEL *not_single = NEW_LABEL(nd_line(var));
8526 LABEL *not_ary = NEW_LABEL(nd_line(var));
8527 CHECK(COMPILE(ret, "for var", var));
8528 ADD_INSN(ret, line_node, dup);
8529 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8530 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8531 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8532 ADD_INSNL(ret, line_node, branchunless, not_single);
8533 ADD_INSN(ret, line_node, dup);
8534 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8535 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8536 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8537 ADD_INSN(ret, line_node, swap);
8538 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8539 ADD_INSN(ret, line_node, dup);
8540 ADD_INSNL(ret, line_node, branchunless, not_ary);
8541 ADD_INSN(ret, line_node, swap);
8542 ADD_LABEL(ret, not_ary);
8543 ADD_INSN(ret, line_node, pop);
8544 ADD_LABEL(ret, not_single);
8545 return COMPILE_OK;
8546}
8547
8548static int
8549compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8550{
8551 const NODE *line_node = node;
8552 unsigned long throw_flag = 0;
8553
8554 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8555 /* while/until */
8556 LABEL *splabel = NEW_LABEL(0);
8557 ADD_LABEL(ret, splabel);
8558 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8559 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8560 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8561 add_ensure_iseq(ret, iseq, 0);
8562 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8563 ADD_ADJUST_RESTORE(ret, splabel);
8564
8565 if (!popped) {
8566 ADD_INSN(ret, line_node, putnil);
8567 }
8568 }
8569 else {
8570 const rb_iseq_t *ip = iseq;
8571
8572 while (ip) {
8573 if (!ISEQ_COMPILE_DATA(ip)) {
8574 ip = 0;
8575 break;
8576 }
8577
8578 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8579 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8580 }
8581 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8582 throw_flag = 0;
8583 }
8584 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8585 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8586 return COMPILE_NG;
8587 }
8588 else {
8589 ip = ISEQ_BODY(ip)->parent_iseq;
8590 continue;
8591 }
8592
8593 /* escape from block */
8594 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8595 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8596 if (popped) {
8597 ADD_INSN(ret, line_node, pop);
8598 }
8599 return COMPILE_OK;
8600 }
8601 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8602 return COMPILE_NG;
8603 }
8604 return COMPILE_OK;
8605}
8606
8607static int
8608compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8609{
8610 const NODE *line_node = node;
8611 unsigned long throw_flag = 0;
8612
8613 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8614 LABEL *splabel = NEW_LABEL(0);
8615 debugs("next in while loop\n");
8616 ADD_LABEL(ret, splabel);
8617 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8618 add_ensure_iseq(ret, iseq, 0);
8619 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8620 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8621 ADD_ADJUST_RESTORE(ret, splabel);
8622 if (!popped) {
8623 ADD_INSN(ret, line_node, putnil);
8624 }
8625 }
8626 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8627 LABEL *splabel = NEW_LABEL(0);
8628 debugs("next in block\n");
8629 ADD_LABEL(ret, splabel);
8630 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8631 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8632 add_ensure_iseq(ret, iseq, 0);
8633 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8634 ADD_ADJUST_RESTORE(ret, splabel);
8635
8636 if (!popped) {
8637 ADD_INSN(ret, line_node, putnil);
8638 }
8639 }
8640 else {
8641 const rb_iseq_t *ip = iseq;
8642
8643 while (ip) {
8644 if (!ISEQ_COMPILE_DATA(ip)) {
8645 ip = 0;
8646 break;
8647 }
8648
8649 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8650 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8651 /* while loop */
8652 break;
8653 }
8654 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8655 break;
8656 }
8657 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8658 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8659 return COMPILE_NG;
8660 }
8661
8662 ip = ISEQ_BODY(ip)->parent_iseq;
8663 }
8664 if (ip != 0) {
8665 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8666 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8667
8668 if (popped) {
8669 ADD_INSN(ret, line_node, pop);
8670 }
8671 }
8672 else {
8673 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8674 return COMPILE_NG;
8675 }
8676 }
8677 return COMPILE_OK;
8678}
8679
8680static int
8681compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8682{
8683 const NODE *line_node = node;
8684
8685 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8686 LABEL *splabel = NEW_LABEL(0);
8687 debugs("redo in while");
8688 ADD_LABEL(ret, splabel);
8689 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8690 add_ensure_iseq(ret, iseq, 0);
8691 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8692 ADD_ADJUST_RESTORE(ret, splabel);
8693 if (!popped) {
8694 ADD_INSN(ret, line_node, putnil);
8695 }
8696 }
8697 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8698 LABEL *splabel = NEW_LABEL(0);
8699
8700 debugs("redo in block");
8701 ADD_LABEL(ret, splabel);
8702 add_ensure_iseq(ret, iseq, 0);
8703 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8704 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8705 ADD_ADJUST_RESTORE(ret, splabel);
8706
8707 if (!popped) {
8708 ADD_INSN(ret, line_node, putnil);
8709 }
8710 }
8711 else {
8712 const rb_iseq_t *ip = iseq;
8713
8714 while (ip) {
8715 if (!ISEQ_COMPILE_DATA(ip)) {
8716 ip = 0;
8717 break;
8718 }
8719
8720 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8721 break;
8722 }
8723 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8724 break;
8725 }
8726 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8727 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8728 return COMPILE_NG;
8729 }
8730
8731 ip = ISEQ_BODY(ip)->parent_iseq;
8732 }
8733 if (ip != 0) {
8734 ADD_INSN(ret, line_node, putnil);
8735 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8736
8737 if (popped) {
8738 ADD_INSN(ret, line_node, pop);
8739 }
8740 }
8741 else {
8742 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8743 return COMPILE_NG;
8744 }
8745 }
8746 return COMPILE_OK;
8747}
8748
8749static int
8750compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8751{
8752 const NODE *line_node = node;
8753
8754 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8755 ADD_INSN(ret, line_node, putnil);
8756 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8757
8758 if (popped) {
8759 ADD_INSN(ret, line_node, pop);
8760 }
8761 }
8762 else {
8763 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8764 return COMPILE_NG;
8765 }
8766 return COMPILE_OK;
8767}
8768
8769static int
8770compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8771{
8772 const int line = nd_line(node);
8773 const NODE *line_node = node;
8774 LABEL *lstart = NEW_LABEL(line);
8775 LABEL *lend = NEW_LABEL(line);
8776 LABEL *lcont = NEW_LABEL(line);
8777 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8778 rb_str_concat(rb_str_new2("rescue in "),
8779 ISEQ_BODY(iseq)->location.label),
8780 ISEQ_TYPE_RESCUE, line);
8781
8782 lstart->rescued = LABEL_RESCUE_BEG;
8783 lend->rescued = LABEL_RESCUE_END;
8784 ADD_LABEL(ret, lstart);
8785
8786 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8787 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8788 {
8789 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8790 }
8791 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8792
8793 ADD_LABEL(ret, lend);
8794 if (RNODE_RESCUE(node)->nd_else) {
8795 ADD_INSN(ret, line_node, pop);
8796 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8797 }
8798 ADD_INSN(ret, line_node, nop);
8799 ADD_LABEL(ret, lcont);
8800
8801 if (popped) {
8802 ADD_INSN(ret, line_node, pop);
8803 }
8804
8805 /* register catch entry */
8806 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8807 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8808 return COMPILE_OK;
8809}
8810
8811static int
8812compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8813{
8814 const int line = nd_line(node);
8815 const NODE *line_node = node;
8816 const NODE *resq = node;
8817 const NODE *narg;
8818 LABEL *label_miss, *label_hit;
8819
8820 while (resq) {
8821 label_miss = NEW_LABEL(line);
8822 label_hit = NEW_LABEL(line);
8823
8824 narg = RNODE_RESBODY(resq)->nd_args;
8825 if (narg) {
8826 switch (nd_type(narg)) {
8827 case NODE_LIST:
8828 while (narg) {
8829 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8830 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8831 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8832 ADD_INSNL(ret, line_node, branchif, label_hit);
8833 narg = RNODE_LIST(narg)->nd_next;
8834 }
8835 break;
8836 case NODE_SPLAT:
8837 case NODE_ARGSCAT:
8838 case NODE_ARGSPUSH:
8839 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8840 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8841 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8842 ADD_INSNL(ret, line_node, branchif, label_hit);
8843 break;
8844 default:
8845 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8846 }
8847 }
8848 else {
8849 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8850 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8851 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8852 ADD_INSNL(ret, line_node, branchif, label_hit);
8853 }
8854 ADD_INSNL(ret, line_node, jump, label_miss);
8855 ADD_LABEL(ret, label_hit);
8856 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8857
8858 if (RNODE_RESBODY(resq)->nd_exc_var) {
8859 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8860 }
8861
8862 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) {
8863 // empty body
8864 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8865 }
8866 else {
8867 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8868 }
8869
8870 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8871 ADD_INSN(ret, line_node, nop);
8872 }
8873 ADD_INSN(ret, line_node, leave);
8874 ADD_LABEL(ret, label_miss);
8875 resq = RNODE_RESBODY(resq)->nd_next;
8876 }
8877 return COMPILE_OK;
8878}
8879
8880static int
8881compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8882{
8883 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8884 const NODE *line_node = node;
8885 DECL_ANCHOR(ensr);
8886 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8887 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8888 ISEQ_TYPE_ENSURE, line);
8889 LABEL *lstart = NEW_LABEL(line);
8890 LABEL *lend = NEW_LABEL(line);
8891 LABEL *lcont = NEW_LABEL(line);
8892 LINK_ELEMENT *last;
8893 int last_leave = 0;
8894 struct ensure_range er;
8896 struct ensure_range *erange;
8897
8898 INIT_ANCHOR(ensr);
8899 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8900 last = ensr->last;
8901 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8902
8903 er.begin = lstart;
8904 er.end = lend;
8905 er.next = 0;
8906 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8907
8908 ADD_LABEL(ret, lstart);
8909 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8910 ADD_LABEL(ret, lend);
8911 ADD_SEQ(ret, ensr);
8912 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8913 ADD_LABEL(ret, lcont);
8914 if (last_leave) ADD_INSN(ret, line_node, pop);
8915
8916 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8917 if (lstart->link.next != &lend->link) {
8918 while (erange) {
8919 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8920 ensure, lcont);
8921 erange = erange->next;
8922 }
8923 }
8924
8925 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8926 return COMPILE_OK;
8927}
8928
8929static int
8930compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8931{
8932 const NODE *line_node = node;
8933
8934 if (iseq) {
8935 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8936 const rb_iseq_t *is = iseq;
8937 enum rb_iseq_type t = type;
8938 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8939 LABEL *splabel = 0;
8940
8941 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8942 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8943 t = ISEQ_BODY(is)->type;
8944 }
8945 switch (t) {
8946 case ISEQ_TYPE_TOP:
8947 case ISEQ_TYPE_MAIN:
8948 if (retval) {
8949 rb_warn("argument of top-level return is ignored");
8950 }
8951 if (is == iseq) {
8952 /* plain top-level, leave directly */
8953 type = ISEQ_TYPE_METHOD;
8954 }
8955 break;
8956 default:
8957 break;
8958 }
8959
8960 if (type == ISEQ_TYPE_METHOD) {
8961 splabel = NEW_LABEL(0);
8962 ADD_LABEL(ret, splabel);
8963 ADD_ADJUST(ret, line_node, 0);
8964 }
8965
8966 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8967
8968 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8969 add_ensure_iseq(ret, iseq, 1);
8970 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8971 ADD_INSN(ret, line_node, leave);
8972 ADD_ADJUST_RESTORE(ret, splabel);
8973
8974 if (!popped) {
8975 ADD_INSN(ret, line_node, putnil);
8976 }
8977 }
8978 else {
8979 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8980 if (popped) {
8981 ADD_INSN(ret, line_node, pop);
8982 }
8983 }
8984 }
8985 return COMPILE_OK;
8986}
8987
8988static bool
8989drop_unreachable_return(LINK_ANCHOR *ret)
8990{
8991 LINK_ELEMENT *i = ret->last, *last;
8992 if (!i) return false;
8993 if (IS_TRACE(i)) i = i->prev;
8994 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8995 last = i = i->prev;
8996 if (IS_ADJUST(i)) i = i->prev;
8997 if (!IS_INSN(i)) return false;
8998 switch (INSN_OF(i)) {
8999 case BIN(leave):
9000 case BIN(jump):
9001 break;
9002 default:
9003 return false;
9004 }
9005 (ret->last = last->prev)->next = NULL;
9006 return true;
9007}
9008
9009static int
9010compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9011{
9012 CHECK(COMPILE_(ret, "nd_body", node, popped));
9013
9014 if (!popped && !all_string_result_p(node)) {
9015 const NODE *line_node = node;
9016 const unsigned int flag = VM_CALL_FCALL;
9017
9018 // Note, this dup could be removed if we are willing to change anytostring. It pops
9019 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9020 ADD_INSN(ret, line_node, dup);
9021 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9022 ADD_INSN(ret, line_node, anytostring);
9023 }
9024 return COMPILE_OK;
9025}
9026
9027static void
9028compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9029{
9030 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9031
9032 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9033 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9034}
9035
9036static LABEL *
9037qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9038{
9039 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9040 VALUE br = 0;
9041
9042 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
9043 *branches = br;
9044 ADD_INSN(recv, line_node, dup);
9045 ADD_INSNL(recv, line_node, branchnil, else_label);
9046 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9047 return else_label;
9048}
9049
9050static void
9051qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9052{
9053 LABEL *end_label;
9054 if (!else_label) return;
9055 end_label = NEW_LABEL(nd_line(line_node));
9056 ADD_INSNL(ret, line_node, jump, end_label);
9057 ADD_LABEL(ret, else_label);
9058 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9059 ADD_LABEL(ret, end_label);
9060}
9061
9062static int
9063compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9064{
9065 /* optimization shortcut
9066 * "literal".freeze -> opt_str_freeze("literal")
9067 */
9068 if (get_nd_recv(node) &&
9069 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9070 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9071 get_nd_args(node) == NULL &&
9072 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9073 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9074 VALUE str = get_string_value(get_nd_recv(node));
9075 if (get_node_call_nd_mid(node) == idUMinus) {
9076 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9077 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9078 }
9079 else {
9080 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9081 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9082 }
9083 RB_OBJ_WRITTEN(iseq, Qundef, str);
9084 if (popped) {
9085 ADD_INSN(ret, line_node, pop);
9086 }
9087 return TRUE;
9088 }
9089 return FALSE;
9090}
9091
9092static int
9093iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9094{
9095 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9096}
9097
9098static const struct rb_builtin_function *
9099iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9100{
9101 int i;
9102 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9103 for (i=0; table[i].index != -1; i++) {
9104 if (strcmp(table[i].name, name) == 0) {
9105 return &table[i];
9106 }
9107 }
9108 return NULL;
9109}
9110
9111static const char *
9112iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9113{
9114 const char *name = rb_id2name(mid);
9115 static const char prefix[] = "__builtin_";
9116 const size_t prefix_len = sizeof(prefix) - 1;
9117
9118 switch (type) {
9119 case NODE_CALL:
9120 if (recv) {
9121 switch (nd_type(recv)) {
9122 case NODE_VCALL:
9123 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9124 return name;
9125 }
9126 break;
9127 case NODE_CONST:
9128 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9129 return name;
9130 }
9131 break;
9132 default: break;
9133 }
9134 }
9135 break;
9136 case NODE_VCALL:
9137 case NODE_FCALL:
9138 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9139 return &name[prefix_len];
9140 }
9141 break;
9142 default: break;
9143 }
9144 return NULL;
9145}
9146
9147static int
9148delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9149{
9150
9151 if (argc == 0) {
9152 *pstart_index = 0;
9153 return TRUE;
9154 }
9155 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9156 unsigned int start=0;
9157
9158 // local_table: [p1, p2, p3, l1, l2, l3]
9159 // arguments: [p3, l1, l2] -> 2
9160 for (start = 0;
9161 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9162 start++) {
9163 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9164
9165 for (unsigned int i=start; i-start<argc; i++) {
9166 if (IS_INSN(elem) &&
9167 INSN_OF(elem) == BIN(getlocal)) {
9168 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9169 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9170
9171 if (local_level == 0) {
9172 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9173 if (0) { // for debug
9174 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9175 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9176 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9177 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9178 }
9179 if (i == index) {
9180 elem = elem->next;
9181 continue; /* for */
9182 }
9183 else {
9184 goto next;
9185 }
9186 }
9187 else {
9188 goto fail; // level != 0 is unsupported
9189 }
9190 }
9191 else {
9192 goto fail; // insn is not a getlocal
9193 }
9194 }
9195 goto success;
9196 next:;
9197 }
9198 fail:
9199 return FALSE;
9200 success:
9201 *pstart_index = start;
9202 return TRUE;
9203 }
9204 else {
9205 return FALSE;
9206 }
9207}
9208
9209// Compile Primitive.attr! :leaf, ...
9210static int
9211compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9212{
9213 VALUE symbol;
9214 VALUE string;
9215 if (!node) goto no_arg;
9216 while (node) {
9217 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9218 const NODE *next = RNODE_LIST(node)->nd_next;
9219
9220 node = RNODE_LIST(node)->nd_head;
9221 if (!node) goto no_arg;
9222 switch (nd_type(node)) {
9223 case NODE_SYM:
9224 symbol = rb_node_sym_string_val(node);
9225 break;
9226 default:
9227 goto bad_arg;
9228 }
9229
9230 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9231
9232 string = rb_sym2str(symbol);
9233 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9234 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9235 }
9236 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9237 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9238 }
9239 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9240 iseq_set_use_block(iseq);
9241 }
9242 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9243 // Let the iseq act like a C method in backtraces
9244 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9245 }
9246 else if (strcmp(RSTRING_PTR(string), "without_interrupts") == 0) {
9247 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9248 }
9249 else {
9250 goto unknown_arg;
9251 }
9252 node = next;
9253 }
9254 return COMPILE_OK;
9255 no_arg:
9256 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9257 return COMPILE_NG;
9258 non_symbol_arg:
9259 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9260 return COMPILE_NG;
9261 unknown_arg:
9262 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9263 return COMPILE_NG;
9264 bad_arg:
9265 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9266}
9267
9268static int
9269compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9270{
9271 VALUE name;
9272
9273 if (!node) goto no_arg;
9274 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9275 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9276 node = RNODE_LIST(node)->nd_head;
9277 if (!node) goto no_arg;
9278 switch (nd_type(node)) {
9279 case NODE_SYM:
9280 name = rb_node_sym_string_val(node);
9281 break;
9282 default:
9283 goto bad_arg;
9284 }
9285 if (!SYMBOL_P(name)) goto non_symbol_arg;
9286 if (!popped) {
9287 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9288 }
9289 return COMPILE_OK;
9290 no_arg:
9291 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9292 return COMPILE_NG;
9293 too_many_arg:
9294 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9295 return COMPILE_NG;
9296 non_symbol_arg:
9297 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9298 rb_builtin_class_name(name));
9299 return COMPILE_NG;
9300 bad_arg:
9301 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9302}
9303
9304static NODE *
9305mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9306{
9307 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9308 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9309 return RNODE_IF(node)->nd_body;
9310 }
9311 else {
9312 rb_bug("mandatory_node: can't find mandatory node");
9313 }
9314}
9315
9316static int
9317compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9318{
9319 // arguments
9320 struct rb_args_info args = {
9321 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9322 };
9323 rb_node_args_t args_node;
9324 rb_node_init(RNODE(&args_node), NODE_ARGS);
9325 args_node.nd_ainfo = args;
9326
9327 // local table without non-mandatory parameters
9328 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9329 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9330
9331 VALUE idtmp = 0;
9332 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9333 tbl->size = table_size;
9334
9335 int i;
9336
9337 // lead parameters
9338 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9339 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9340 }
9341 // local variables
9342 for (; i<table_size; i++) {
9343 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9344 }
9345
9346 rb_node_scope_t scope_node;
9347 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9348 scope_node.nd_tbl = tbl;
9349 scope_node.nd_body = mandatory_node(iseq, node);
9350 scope_node.nd_parent = NULL;
9351 scope_node.nd_args = &args_node;
9352
9353 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9354
9355 const rb_iseq_t *mandatory_only_iseq =
9356 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9357 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9358 nd_line(line_node), NULL, 0,
9359 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9360 ISEQ_BODY(iseq)->variable.script_lines);
9361 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9362
9363 ALLOCV_END(idtmp);
9364 return COMPILE_OK;
9365}
9366
9367static int
9368compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9369 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9370{
9371 NODE *args_node = get_nd_args(node);
9372
9373 if (parent_block != NULL) {
9374 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9375 return COMPILE_NG;
9376 }
9377 else {
9378# define BUILTIN_INLINE_PREFIX "_bi"
9379 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9380 bool cconst = false;
9381 retry:;
9382 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9383
9384 if (bf == NULL) {
9385 if (strcmp("cstmt!", builtin_func) == 0 ||
9386 strcmp("cexpr!", builtin_func) == 0) {
9387 // ok
9388 }
9389 else if (strcmp("cconst!", builtin_func) == 0) {
9390 cconst = true;
9391 }
9392 else if (strcmp("cinit!", builtin_func) == 0) {
9393 // ignore
9394 return COMPILE_OK;
9395 }
9396 else if (strcmp("attr!", builtin_func) == 0) {
9397 return compile_builtin_attr(iseq, args_node);
9398 }
9399 else if (strcmp("arg!", builtin_func) == 0) {
9400 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9401 }
9402 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9403 if (popped) {
9404 rb_bug("mandatory_only? should be in if condition");
9405 }
9406 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9407 rb_bug("mandatory_only? should be put on top");
9408 }
9409
9410 ADD_INSN1(ret, line_node, putobject, Qfalse);
9411 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9412 }
9413 else if (1) {
9414 rb_bug("can't find builtin function:%s", builtin_func);
9415 }
9416 else {
9417 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9418 return COMPILE_NG;
9419 }
9420
9421 int inline_index = nd_line(node);
9422 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9423 builtin_func = inline_func;
9424 args_node = NULL;
9425 goto retry;
9426 }
9427
9428 if (cconst) {
9429 typedef VALUE(*builtin_func0)(void *, VALUE);
9430 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9431 ADD_INSN1(ret, line_node, putobject, const_val);
9432 return COMPILE_OK;
9433 }
9434
9435 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9436
9437 unsigned int flag = 0;
9438 struct rb_callinfo_kwarg *keywords = NULL;
9439 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9440
9441 if (FIX2INT(argc) != bf->argc) {
9442 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9443 builtin_func, bf->argc, FIX2INT(argc));
9444 return COMPILE_NG;
9445 }
9446
9447 unsigned int start_index;
9448 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9449 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9450 }
9451 else {
9452 ADD_SEQ(ret, args);
9453 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9454 }
9455
9456 if (popped) ADD_INSN(ret, line_node, pop);
9457 return COMPILE_OK;
9458 }
9459}
9460
9461static int
9462compile_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)
9463{
9464 /* call: obj.method(...)
9465 * fcall: func(...)
9466 * vcall: func
9467 */
9468 DECL_ANCHOR(recv);
9469 DECL_ANCHOR(args);
9470 ID mid = get_node_call_nd_mid(node);
9471 VALUE argc;
9472 unsigned int flag = 0;
9473 struct rb_callinfo_kwarg *keywords = NULL;
9474 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9475 LABEL *else_label = NULL;
9476 VALUE branches = Qfalse;
9477
9478 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9479
9480 INIT_ANCHOR(recv);
9481 INIT_ANCHOR(args);
9482
9483#if OPT_SUPPORT_JOKE
9484 if (nd_type_p(node, NODE_VCALL)) {
9485 ID id_bitblt;
9486 ID id_answer;
9487
9488 CONST_ID(id_bitblt, "bitblt");
9489 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9490
9491 if (mid == id_bitblt) {
9492 ADD_INSN(ret, line_node, bitblt);
9493 return COMPILE_OK;
9494 }
9495 else if (mid == id_answer) {
9496 ADD_INSN(ret, line_node, answer);
9497 return COMPILE_OK;
9498 }
9499 }
9500 /* only joke */
9501 {
9502 ID goto_id;
9503 ID label_id;
9504
9505 CONST_ID(goto_id, "__goto__");
9506 CONST_ID(label_id, "__label__");
9507
9508 if (nd_type_p(node, NODE_FCALL) &&
9509 (mid == goto_id || mid == label_id)) {
9510 LABEL *label;
9511 st_data_t data;
9512 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9513 VALUE label_name;
9514
9515 if (!labels_table) {
9516 labels_table = st_init_numtable();
9517 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9518 }
9519 {
9520 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9521 return COMPILE_NG;
9522 }
9523
9524 if (mid == goto_id) {
9525 ADD_INSNL(ret, line_node, jump, label);
9526 }
9527 else {
9528 ADD_LABEL(ret, label);
9529 }
9530 return COMPILE_OK;
9531 }
9532 }
9533#endif
9534
9535 const char *builtin_func;
9536 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9537 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9538 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9539 }
9540
9541 /* receiver */
9542 if (!assume_receiver) {
9543 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9544 int idx, level;
9545
9546 if (mid == idCall &&
9547 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9548 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9549 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9550 }
9551 else if (private_recv_p(node)) {
9552 ADD_INSN(recv, node, putself);
9553 flag |= VM_CALL_FCALL;
9554 }
9555 else {
9556 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9557 }
9558
9559 if (type == NODE_QCALL) {
9560 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9561 }
9562 }
9563 else if (type == NODE_FCALL || type == NODE_VCALL) {
9564 ADD_CALL_RECEIVER(recv, line_node);
9565 }
9566 }
9567
9568 /* args */
9569 if (type != NODE_VCALL) {
9570 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9571 CHECK(!NIL_P(argc));
9572 }
9573 else {
9574 argc = INT2FIX(0);
9575 }
9576
9577 ADD_SEQ(ret, recv);
9578
9579 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9580 mid == rb_intern("new") &&
9581 parent_block == NULL &&
9582 !(flag & VM_CALL_ARGS_BLOCKARG);
9583
9584 if (inline_new) {
9585 ADD_INSN(ret, node, putnil);
9586 ADD_INSN(ret, node, swap);
9587 }
9588
9589 ADD_SEQ(ret, args);
9590
9591 debugp_param("call args argc", argc);
9592 debugp_param("call method", ID2SYM(mid));
9593
9594 switch ((int)type) {
9595 case NODE_VCALL:
9596 flag |= VM_CALL_VCALL;
9597 /* VCALL is funcall, so fall through */
9598 case NODE_FCALL:
9599 flag |= VM_CALL_FCALL;
9600 }
9601
9602 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9603 ADD_INSN(ret, line_node, splatkw);
9604 }
9605
9606 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9607 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9608
9609 if (inline_new) {
9610 // Jump unless the receiver uses the "basic" implementation of "new"
9611 VALUE ci;
9612 if (flag & VM_CALL_FORWARDING) {
9613 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9614 }
9615 else {
9616 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9617 }
9618 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9619 LABEL_REF(not_basic_new);
9620
9621 // optimized path
9622 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9623 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9624
9625 ADD_LABEL(ret, not_basic_new);
9626 // Fall back to normal send
9627 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9628 ADD_INSN(ret, line_node, swap);
9629
9630 ADD_LABEL(ret, not_basic_new_finish);
9631 ADD_INSN(ret, line_node, pop);
9632 }
9633 else {
9634 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9635 }
9636
9637 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9638 if (popped) {
9639 ADD_INSN(ret, line_node, pop);
9640 }
9641 return COMPILE_OK;
9642}
9643
9644static int
9645compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9646{
9647 const int line = nd_line(node);
9648 VALUE argc;
9649 unsigned int flag = 0;
9650 int asgnflag = 0;
9651 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9652
9653 /*
9654 * a[x] (op)= y
9655 *
9656 * nil # nil
9657 * eval a # nil a
9658 * eval x # nil a x
9659 * dupn 2 # nil a x a x
9660 * send :[] # nil a x a[x]
9661 * eval y # nil a x a[x] y
9662 * send op # nil a x ret
9663 * setn 3 # ret a x ret
9664 * send []= # ret ?
9665 * pop # ret
9666 */
9667
9668 /*
9669 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9670 * NODE_OP_ASGN nd_recv
9671 * nd_args->nd_head
9672 * nd_args->nd_body
9673 * nd_mid
9674 */
9675
9676 if (!popped) {
9677 ADD_INSN(ret, node, putnil);
9678 }
9679 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9680 CHECK(asgnflag != -1);
9681 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9682 case NODE_ZLIST:
9683 argc = INT2FIX(0);
9684 break;
9685 default:
9686 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9687 CHECK(!NIL_P(argc));
9688 }
9689 int dup_argn = FIX2INT(argc) + 1;
9690 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9691 flag |= asgnflag;
9692 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9693
9694 if (id == idOROP || id == idANDOP) {
9695 /* a[x] ||= y or a[x] &&= y
9696
9697 unless/if a[x]
9698 a[x]= y
9699 else
9700 nil
9701 end
9702 */
9703 LABEL *label = NEW_LABEL(line);
9704 LABEL *lfin = NEW_LABEL(line);
9705
9706 ADD_INSN(ret, node, dup);
9707 if (id == idOROP) {
9708 ADD_INSNL(ret, node, branchif, label);
9709 }
9710 else { /* idANDOP */
9711 ADD_INSNL(ret, node, branchunless, label);
9712 }
9713 ADD_INSN(ret, node, pop);
9714
9715 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9716 if (!popped) {
9717 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9718 }
9719 if (flag & VM_CALL_ARGS_SPLAT) {
9720 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9721 ADD_INSN(ret, node, swap);
9722 ADD_INSN1(ret, node, splatarray, Qtrue);
9723 ADD_INSN(ret, node, swap);
9724 flag |= VM_CALL_ARGS_SPLAT_MUT;
9725 }
9726 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9727 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9728 }
9729 else {
9730 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9731 }
9732 ADD_INSN(ret, node, pop);
9733 ADD_INSNL(ret, node, jump, lfin);
9734 ADD_LABEL(ret, label);
9735 if (!popped) {
9736 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9737 }
9738 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9739 ADD_LABEL(ret, lfin);
9740 }
9741 else {
9742 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9743 ADD_SEND(ret, node, id, INT2FIX(1));
9744 if (!popped) {
9745 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9746 }
9747 if (flag & VM_CALL_ARGS_SPLAT) {
9748 if (flag & VM_CALL_KW_SPLAT) {
9749 ADD_INSN1(ret, node, topn, INT2FIX(2));
9750 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9751 ADD_INSN1(ret, node, splatarray, Qtrue);
9752 flag |= VM_CALL_ARGS_SPLAT_MUT;
9753 }
9754 ADD_INSN(ret, node, swap);
9755 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9756 ADD_INSN1(ret, node, setn, INT2FIX(2));
9757 ADD_INSN(ret, node, pop);
9758 }
9759 else {
9760 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9761 ADD_INSN(ret, node, swap);
9762 ADD_INSN1(ret, node, splatarray, Qtrue);
9763 ADD_INSN(ret, node, swap);
9764 flag |= VM_CALL_ARGS_SPLAT_MUT;
9765 }
9766 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9767 }
9768 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9769 }
9770 else {
9771 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9772 }
9773 ADD_INSN(ret, node, pop);
9774 }
9775 return COMPILE_OK;
9776}
9777
9778static int
9779compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9780{
9781 const int line = nd_line(node);
9782 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9783 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9784 int asgnflag;
9785 LABEL *lfin = NEW_LABEL(line);
9786 LABEL *lcfin = NEW_LABEL(line);
9787 LABEL *lskip = 0;
9788 /*
9789 class C; attr_accessor :c; end
9790 r = C.new
9791 r.a &&= v # asgn2
9792
9793 eval r # r
9794 dup # r r
9795 eval r.a # r o
9796
9797 # or
9798 dup # r o o
9799 if lcfin # r o
9800 pop # r
9801 eval v # r v
9802 swap # v r
9803 topn 1 # v r v
9804 send a= # v ?
9805 jump lfin # v ?
9806
9807 lcfin: # r o
9808 swap # o r
9809
9810 lfin: # o ?
9811 pop # o
9812
9813 # or (popped)
9814 if lcfin # r
9815 eval v # r v
9816 send a= # ?
9817 jump lfin # ?
9818
9819 lcfin: # r
9820
9821 lfin: # ?
9822 pop #
9823
9824 # and
9825 dup # r o o
9826 unless lcfin
9827 pop # r
9828 eval v # r v
9829 swap # v r
9830 topn 1 # v r v
9831 send a= # v ?
9832 jump lfin # v ?
9833
9834 # others
9835 eval v # r o v
9836 send ?? # r w
9837 send a= # w
9838
9839 */
9840
9841 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9842 CHECK(asgnflag != -1);
9843 if (RNODE_OP_ASGN2(node)->nd_aid) {
9844 lskip = NEW_LABEL(line);
9845 ADD_INSN(ret, node, dup);
9846 ADD_INSNL(ret, node, branchnil, lskip);
9847 }
9848 ADD_INSN(ret, node, dup);
9849 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9850
9851 if (atype == idOROP || atype == idANDOP) {
9852 if (!popped) {
9853 ADD_INSN(ret, node, dup);
9854 }
9855 if (atype == idOROP) {
9856 ADD_INSNL(ret, node, branchif, lcfin);
9857 }
9858 else { /* idANDOP */
9859 ADD_INSNL(ret, node, branchunless, lcfin);
9860 }
9861 if (!popped) {
9862 ADD_INSN(ret, node, pop);
9863 }
9864 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9865 if (!popped) {
9866 ADD_INSN(ret, node, swap);
9867 ADD_INSN1(ret, node, topn, INT2FIX(1));
9868 }
9869 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9870 ADD_INSNL(ret, node, jump, lfin);
9871
9872 ADD_LABEL(ret, lcfin);
9873 if (!popped) {
9874 ADD_INSN(ret, node, swap);
9875 }
9876
9877 ADD_LABEL(ret, lfin);
9878 }
9879 else {
9880 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9881 ADD_SEND(ret, node, atype, INT2FIX(1));
9882 if (!popped) {
9883 ADD_INSN(ret, node, swap);
9884 ADD_INSN1(ret, node, topn, INT2FIX(1));
9885 }
9886 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9887 }
9888 if (lskip && popped) {
9889 ADD_LABEL(ret, lskip);
9890 }
9891 ADD_INSN(ret, node, pop);
9892 if (lskip && !popped) {
9893 ADD_LABEL(ret, lskip);
9894 }
9895 return COMPILE_OK;
9896}
9897
9898static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9899
9900static int
9901compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9902{
9903 const int line = nd_line(node);
9904 LABEL *lfin = 0;
9905 LABEL *lassign = 0;
9906 ID mid;
9907
9908 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9909 case NODE_COLON3:
9910 ADD_INSN1(ret, node, putobject, rb_cObject);
9911 break;
9912 case NODE_COLON2:
9913 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9914 break;
9915 default:
9916 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9917 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9918 return COMPILE_NG;
9919 }
9920 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9921 /* cref */
9922 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9923 lassign = NEW_LABEL(line);
9924 ADD_INSN(ret, node, dup); /* cref cref */
9925 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9926 ID2SYM(mid), Qtrue); /* cref bool */
9927 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9928 }
9929 ADD_INSN(ret, node, dup); /* cref cref */
9930 ADD_INSN1(ret, node, putobject, Qtrue);
9931 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9932
9933 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9934 lfin = NEW_LABEL(line);
9935 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9936 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9937 ADD_INSNL(ret, node, branchif, lfin);
9938 else /* idANDOP */
9939 ADD_INSNL(ret, node, branchunless, lfin);
9940 /* cref [obj] */
9941 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9942 if (lassign) ADD_LABEL(ret, lassign);
9943 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9944 /* cref value */
9945 if (popped)
9946 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9947 else {
9948 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9949 ADD_INSN(ret, node, swap); /* cref value value cref */
9950 }
9951 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9952 ADD_LABEL(ret, lfin); /* cref [value] */
9953 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9954 ADD_INSN(ret, node, pop); /* [value] */
9955 }
9956 else {
9957 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9958 /* cref obj value */
9959 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9960 /* cref value */
9961 ADD_INSN(ret, node, swap); /* value cref */
9962 if (!popped) {
9963 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9964 ADD_INSN(ret, node, swap); /* value value cref */
9965 }
9966 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9967 }
9968 return COMPILE_OK;
9969}
9970
9971static int
9972compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9973{
9974 const int line = nd_line(node);
9975 LABEL *lfin = NEW_LABEL(line);
9976 LABEL *lassign;
9977
9978 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9979 LABEL *lfinish[2];
9980 lfinish[0] = lfin;
9981 lfinish[1] = 0;
9982 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9983 lassign = lfinish[1];
9984 if (!lassign) {
9985 lassign = NEW_LABEL(line);
9986 }
9987 ADD_INSNL(ret, node, branchunless, lassign);
9988 }
9989 else {
9990 lassign = NEW_LABEL(line);
9991 }
9992
9993 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9994
9995 if (!popped) {
9996 ADD_INSN(ret, node, dup);
9997 }
9998
9999 if (type == NODE_OP_ASGN_AND) {
10000 ADD_INSNL(ret, node, branchunless, lfin);
10001 }
10002 else {
10003 ADD_INSNL(ret, node, branchif, lfin);
10004 }
10005
10006 if (!popped) {
10007 ADD_INSN(ret, node, pop);
10008 }
10009
10010 ADD_LABEL(ret, lassign);
10011 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10012 ADD_LABEL(ret, lfin);
10013 return COMPILE_OK;
10014}
10015
10016static int
10017compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10018{
10019 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10020 DECL_ANCHOR(args);
10021 int argc;
10022 unsigned int flag = 0;
10023 struct rb_callinfo_kwarg *keywords = NULL;
10024 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10025 int use_block = 1;
10026
10027 INIT_ANCHOR(args);
10028 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10029
10030 if (type == NODE_SUPER) {
10031 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10032 CHECK(!NIL_P(vargc));
10033 argc = FIX2INT(vargc);
10034 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10035 ADD_INSN(args, node, splatkw);
10036 }
10037
10038 if (flag & VM_CALL_ARGS_BLOCKARG) {
10039 use_block = 0;
10040 }
10041 }
10042 else {
10043 /* NODE_ZSUPER */
10044 int i;
10045 const rb_iseq_t *liseq = body->local_iseq;
10046 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10047 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10048 int lvar_level = get_lvar_level(iseq);
10049
10050 argc = local_body->param.lead_num;
10051
10052 /* normal arguments */
10053 for (i = 0; i < local_body->param.lead_num; i++) {
10054 int idx = local_body->local_table_size - i;
10055 ADD_GETLOCAL(args, node, idx, lvar_level);
10056 }
10057
10058 /* forward ... */
10059 if (local_body->param.flags.forwardable) {
10060 flag |= VM_CALL_FORWARDING;
10061 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10062 ADD_GETLOCAL(args, node, idx, lvar_level);
10063 }
10064
10065 if (local_body->param.flags.has_opt) {
10066 /* optional arguments */
10067 int j;
10068 for (j = 0; j < local_body->param.opt_num; j++) {
10069 int idx = local_body->local_table_size - (i + j);
10070 ADD_GETLOCAL(args, node, idx, lvar_level);
10071 }
10072 i += j;
10073 argc = i;
10074 }
10075 if (local_body->param.flags.has_rest) {
10076 /* rest argument */
10077 int idx = local_body->local_table_size - local_body->param.rest_start;
10078 ADD_GETLOCAL(args, node, idx, lvar_level);
10079 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10080
10081 argc = local_body->param.rest_start + 1;
10082 flag |= VM_CALL_ARGS_SPLAT;
10083 }
10084 if (local_body->param.flags.has_post) {
10085 /* post arguments */
10086 int post_len = local_body->param.post_num;
10087 int post_start = local_body->param.post_start;
10088
10089 if (local_body->param.flags.has_rest) {
10090 int j;
10091 for (j=0; j<post_len; j++) {
10092 int idx = local_body->local_table_size - (post_start + j);
10093 ADD_GETLOCAL(args, node, idx, lvar_level);
10094 }
10095 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10096 flag |= VM_CALL_ARGS_SPLAT_MUT;
10097 /* argc is settled at above */
10098 }
10099 else {
10100 int j;
10101 for (j=0; j<post_len; j++) {
10102 int idx = local_body->local_table_size - (post_start + j);
10103 ADD_GETLOCAL(args, node, idx, lvar_level);
10104 }
10105 argc = post_len + post_start;
10106 }
10107 }
10108
10109 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10110 int local_size = local_body->local_table_size;
10111 argc++;
10112
10113 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10114
10115 if (local_body->param.flags.has_kwrest) {
10116 int idx = local_body->local_table_size - local_kwd->rest_start;
10117 ADD_GETLOCAL(args, node, idx, lvar_level);
10118 RUBY_ASSERT(local_kwd->num > 0);
10119 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10120 }
10121 else {
10122 ADD_INSN1(args, node, newhash, INT2FIX(0));
10123 }
10124 for (i = 0; i < local_kwd->num; ++i) {
10125 ID id = local_kwd->table[i];
10126 int idx = local_size - get_local_var_idx(liseq, id);
10127 ADD_INSN1(args, node, putobject, ID2SYM(id));
10128 ADD_GETLOCAL(args, node, idx, lvar_level);
10129 }
10130 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10131 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10132 }
10133 else if (local_body->param.flags.has_kwrest) {
10134 int idx = local_body->local_table_size - local_kwd->rest_start;
10135 ADD_GETLOCAL(args, node, idx, lvar_level);
10136 argc++;
10137 flag |= VM_CALL_KW_SPLAT;
10138 }
10139 }
10140
10141 if (use_block && parent_block == NULL) {
10142 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10143 }
10144
10145 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10146 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10147 ADD_INSN(ret, node, putself);
10148 ADD_SEQ(ret, args);
10149
10150 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10151
10152 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10153 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10154 }
10155 else {
10156 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10157 }
10158
10159 if (popped) {
10160 ADD_INSN(ret, node, pop);
10161 }
10162 return COMPILE_OK;
10163}
10164
10165static int
10166compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10167{
10168 DECL_ANCHOR(args);
10169 VALUE argc;
10170 unsigned int flag = 0;
10171 struct rb_callinfo_kwarg *keywords = NULL;
10172
10173 INIT_ANCHOR(args);
10174
10175 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10176 case ISEQ_TYPE_TOP:
10177 case ISEQ_TYPE_MAIN:
10178 case ISEQ_TYPE_CLASS:
10179 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10180 return COMPILE_NG;
10181 default: /* valid */;
10182 }
10183
10184 if (RNODE_YIELD(node)->nd_head) {
10185 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10186 CHECK(!NIL_P(argc));
10187 }
10188 else {
10189 argc = INT2FIX(0);
10190 }
10191
10192 ADD_SEQ(ret, args);
10193 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10194 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10195
10196 if (popped) {
10197 ADD_INSN(ret, node, pop);
10198 }
10199
10200 int level = 0;
10201 const rb_iseq_t *tmp_iseq = iseq;
10202 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10203 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10204 }
10205 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10206
10207 return COMPILE_OK;
10208}
10209
10210static int
10211compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10212{
10213 DECL_ANCHOR(recv);
10214 DECL_ANCHOR(val);
10215
10216 INIT_ANCHOR(recv);
10217 INIT_ANCHOR(val);
10218 switch ((int)type) {
10219 case NODE_MATCH:
10220 {
10221 VALUE re = rb_node_regx_string_val(node);
10222 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10223 ADD_INSN1(recv, node, putobject, re);
10224 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10225 INT2FIX(0));
10226 }
10227 break;
10228 case NODE_MATCH2:
10229 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10230 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10231 break;
10232 case NODE_MATCH3:
10233 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10234 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10235 break;
10236 }
10237
10238 ADD_SEQ(ret, recv);
10239 ADD_SEQ(ret, val);
10240 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10241
10242 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10243 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10244 }
10245
10246 if (popped) {
10247 ADD_INSN(ret, node, pop);
10248 }
10249 return COMPILE_OK;
10250}
10251
10252static int
10253compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10254{
10255 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10256 /* constant */
10257 VALUE segments;
10258 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10259 (segments = collect_const_segments(iseq, node))) {
10260 ISEQ_BODY(iseq)->ic_size++;
10261 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10262 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10263 }
10264 else {
10265 /* constant */
10266 DECL_ANCHOR(pref);
10267 DECL_ANCHOR(body);
10268
10269 INIT_ANCHOR(pref);
10270 INIT_ANCHOR(body);
10271 CHECK(compile_const_prefix(iseq, node, pref, body));
10272 if (LIST_INSN_SIZE_ZERO(pref)) {
10273 ADD_INSN(ret, node, putnil);
10274 ADD_SEQ(ret, body);
10275 }
10276 else {
10277 ADD_SEQ(ret, pref);
10278 ADD_SEQ(ret, body);
10279 }
10280 }
10281 }
10282 else {
10283 /* function call */
10284 ADD_CALL_RECEIVER(ret, node);
10285 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10286 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10287 }
10288 if (popped) {
10289 ADD_INSN(ret, node, pop);
10290 }
10291 return COMPILE_OK;
10292}
10293
10294static int
10295compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10296{
10297 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10298
10299 /* add cache insn */
10300 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10301 ISEQ_BODY(iseq)->ic_size++;
10302 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10303 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10304 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10305 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10306 }
10307 else {
10308 ADD_INSN1(ret, node, putobject, rb_cObject);
10309 ADD_INSN1(ret, node, putobject, Qtrue);
10310 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10311 }
10312
10313 if (popped) {
10314 ADD_INSN(ret, node, pop);
10315 }
10316 return COMPILE_OK;
10317}
10318
10319static int
10320compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10321{
10322 VALUE flag = INT2FIX(excl);
10323 const NODE *b = RNODE_DOT2(node)->nd_beg;
10324 const NODE *e = RNODE_DOT2(node)->nd_end;
10325
10326 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10327 if (!popped) {
10328 VALUE bv = optimized_range_item(b);
10329 VALUE ev = optimized_range_item(e);
10330 VALUE val = rb_range_new(bv, ev, excl);
10332 ADD_INSN1(ret, node, putobject, val);
10333 RB_OBJ_WRITTEN(iseq, Qundef, val);
10334 }
10335 }
10336 else {
10337 CHECK(COMPILE_(ret, "min", b, popped));
10338 CHECK(COMPILE_(ret, "max", e, popped));
10339 if (!popped) {
10340 ADD_INSN1(ret, node, newrange, flag);
10341 }
10342 }
10343 return COMPILE_OK;
10344}
10345
10346static int
10347compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10348{
10349 if (!popped) {
10350 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10351 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10352 }
10353 else {
10354 const rb_iseq_t *ip = iseq;
10355 int level = 0;
10356 while (ip) {
10357 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10358 break;
10359 }
10360 ip = ISEQ_BODY(ip)->parent_iseq;
10361 level++;
10362 }
10363 if (ip) {
10364 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10365 }
10366 else {
10367 ADD_INSN(ret, node, putnil);
10368 }
10369 }
10370 }
10371 return COMPILE_OK;
10372}
10373
10374static int
10375compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10376{
10377 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10378 LABEL *end_label = NEW_LABEL(nd_line(node));
10379 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10380
10381 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10382 /* required argument. do nothing */
10383 COMPILE_ERROR(ERROR_ARGS "unreachable");
10384 return COMPILE_NG;
10385 }
10386 else if (nd_type_p(default_value, NODE_SYM) ||
10387 nd_type_p(default_value, NODE_REGX) ||
10388 nd_type_p(default_value, NODE_LINE) ||
10389 nd_type_p(default_value, NODE_INTEGER) ||
10390 nd_type_p(default_value, NODE_FLOAT) ||
10391 nd_type_p(default_value, NODE_RATIONAL) ||
10392 nd_type_p(default_value, NODE_IMAGINARY) ||
10393 nd_type_p(default_value, NODE_NIL) ||
10394 nd_type_p(default_value, NODE_TRUE) ||
10395 nd_type_p(default_value, NODE_FALSE)) {
10396 COMPILE_ERROR(ERROR_ARGS "unreachable");
10397 return COMPILE_NG;
10398 }
10399 else {
10400 /* if keywordcheck(_kw_bits, nth_keyword)
10401 * kw = default_value
10402 * end
10403 */
10404 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10405 int keyword_idx = body->param.keyword->num;
10406
10407 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10408 ADD_INSNL(ret, node, branchif, end_label);
10409 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10410 ADD_LABEL(ret, end_label);
10411 }
10412 return COMPILE_OK;
10413}
10414
10415static int
10416compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10417{
10418 DECL_ANCHOR(recv);
10419 DECL_ANCHOR(args);
10420 unsigned int flag = 0;
10421 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10422 VALUE argc;
10423 LABEL *else_label = NULL;
10424 VALUE branches = Qfalse;
10425
10426 INIT_ANCHOR(recv);
10427 INIT_ANCHOR(args);
10428 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10429 CHECK(!NIL_P(argc));
10430
10431 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10432 CHECK(asgnflag != -1);
10433 flag |= (unsigned int)asgnflag;
10434
10435 debugp_param("argc", argc);
10436 debugp_param("nd_mid", ID2SYM(mid));
10437
10438 if (!rb_is_attrset_id(mid)) {
10439 /* safe nav attr */
10440 mid = rb_id_attrset(mid);
10441 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10442 }
10443 if (!popped) {
10444 ADD_INSN(ret, node, putnil);
10445 ADD_SEQ(ret, recv);
10446 ADD_SEQ(ret, args);
10447
10448 if (flag & VM_CALL_ARGS_SPLAT) {
10449 ADD_INSN(ret, node, dup);
10450 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10451 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10452 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10453 ADD_INSN (ret, node, pop);
10454 }
10455 else {
10456 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10457 }
10458 }
10459 else {
10460 ADD_SEQ(ret, recv);
10461 ADD_SEQ(ret, args);
10462 }
10463 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10464 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10465 ADD_INSN(ret, node, pop);
10466 return COMPILE_OK;
10467}
10468
10469static int
10470compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10471{
10472 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10473 ADD_SEQ(ret, sub);
10474
10475 if (copy) {
10476 /*
10477 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10478 * NEW_LIST(value, loc), loc);
10479 */
10480 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10481 }
10482 else {
10483 /*
10484 * NEW_CALL(fcore, rb_intern("make_shareable"),
10485 * NEW_LIST(value, loc), loc);
10486 */
10487 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10488 }
10489
10490 return COMPILE_OK;
10491}
10492
10493static VALUE
10494node_const_decl_val(const NODE *node)
10495{
10496 VALUE path;
10497 switch (nd_type(node)) {
10498 case NODE_CDECL:
10499 if (RNODE_CDECL(node)->nd_vid) {
10500 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10501 goto end;
10502 }
10503 else {
10504 node = RNODE_CDECL(node)->nd_else;
10505 }
10506 break;
10507 case NODE_COLON2:
10508 break;
10509 case NODE_COLON3:
10510 // ::Const
10511 path = rb_str_new_cstr("::");
10512 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10513 goto end;
10514 default:
10515 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10517 }
10518
10519 path = rb_ary_new();
10520 if (node) {
10521 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10522 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10523 }
10524 if (node && nd_type_p(node, NODE_CONST)) {
10525 // Const::Name
10526 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10527 }
10528 else if (node && nd_type_p(node, NODE_COLON3)) {
10529 // ::Const::Name
10530 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10531 rb_ary_push(path, rb_str_new(0, 0));
10532 }
10533 else {
10534 // expression::Name
10535 rb_ary_push(path, rb_str_new_cstr("..."));
10536 }
10537 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10538 }
10539 end:
10540 path = rb_fstring(path);
10541 return path;
10542}
10543
10544static VALUE
10545const_decl_path(NODE *dest)
10546{
10547 VALUE path = Qnil;
10548 if (!nd_type_p(dest, NODE_CALL)) {
10549 path = node_const_decl_val(dest);
10550 }
10551 return path;
10552}
10553
10554static int
10555compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10556{
10557 /*
10558 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10559 */
10560 VALUE path = const_decl_path(dest);
10561 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10562 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10563 ADD_INSN1(ret, value, putobject, path);
10564 RB_OBJ_WRITTEN(iseq, Qundef, path);
10565 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10566
10567 return COMPILE_OK;
10568}
10569
10570#ifndef SHAREABLE_BARE_EXPRESSION
10571#define SHAREABLE_BARE_EXPRESSION 1
10572#endif
10573
10574static int
10575compile_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)
10576{
10577# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10578 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10579 VALUE lit = Qnil;
10580 DECL_ANCHOR(anchor);
10581
10582 enum node_type type = node ? nd_type(node) : NODE_NIL;
10583 switch (type) {
10584 case NODE_TRUE:
10585 *value_p = Qtrue;
10586 goto compile;
10587 case NODE_FALSE:
10588 *value_p = Qfalse;
10589 goto compile;
10590 case NODE_NIL:
10591 *value_p = Qnil;
10592 goto compile;
10593 case NODE_SYM:
10594 *value_p = rb_node_sym_string_val(node);
10595 goto compile;
10596 case NODE_REGX:
10597 *value_p = rb_node_regx_string_val(node);
10598 goto compile;
10599 case NODE_LINE:
10600 *value_p = rb_node_line_lineno_val(node);
10601 goto compile;
10602 case NODE_INTEGER:
10603 *value_p = rb_node_integer_literal_val(node);
10604 goto compile;
10605 case NODE_FLOAT:
10606 *value_p = rb_node_float_literal_val(node);
10607 goto compile;
10608 case NODE_RATIONAL:
10609 *value_p = rb_node_rational_literal_val(node);
10610 goto compile;
10611 case NODE_IMAGINARY:
10612 *value_p = rb_node_imaginary_literal_val(node);
10613 goto compile;
10614 case NODE_ENCODING:
10615 *value_p = rb_node_encoding_val(node);
10616
10617 compile:
10618 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10619 *shareable_literal_p = 1;
10620 return COMPILE_OK;
10621
10622 case NODE_DSTR:
10623 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10624 if (shareable == rb_parser_shareable_literal) {
10625 /*
10626 * NEW_CALL(node, idUMinus, 0, loc);
10627 *
10628 * -"#{var}"
10629 */
10630 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10631 }
10632 *value_p = Qundef;
10633 *shareable_literal_p = 1;
10634 return COMPILE_OK;
10635
10636 case NODE_STR:{
10637 VALUE lit = rb_node_str_string_val(node);
10638 ADD_INSN1(ret, node, putobject, lit);
10639 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10640 *value_p = lit;
10641 *shareable_literal_p = 1;
10642
10643 return COMPILE_OK;
10644 }
10645
10646 case NODE_FILE:{
10647 VALUE lit = rb_node_file_path_val(node);
10648 ADD_INSN1(ret, node, putobject, lit);
10649 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10650 *value_p = lit;
10651 *shareable_literal_p = 1;
10652
10653 return COMPILE_OK;
10654 }
10655
10656 case NODE_ZLIST:{
10657 VALUE lit = rb_ary_new();
10658 OBJ_FREEZE(lit);
10659 ADD_INSN1(ret, node, putobject, lit);
10660 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10661 *value_p = lit;
10662 *shareable_literal_p = 1;
10663
10664 return COMPILE_OK;
10665 }
10666
10667 case NODE_LIST:{
10668 INIT_ANCHOR(anchor);
10669 lit = rb_ary_new();
10670 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10671 VALUE val;
10672 int shareable_literal_p2;
10673 NODE *elt = RNODE_LIST(n)->nd_head;
10674 if (elt) {
10675 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10676 if (shareable_literal_p2) {
10677 /* noop */
10678 }
10679 else if (RTEST(lit)) {
10680 rb_ary_clear(lit);
10681 lit = Qfalse;
10682 }
10683 }
10684 if (RTEST(lit)) {
10685 if (!UNDEF_P(val)) {
10686 rb_ary_push(lit, val);
10687 }
10688 else {
10689 rb_ary_clear(lit);
10690 lit = Qnil; /* make shareable at runtime */
10691 }
10692 }
10693 }
10694 break;
10695 }
10696 case NODE_HASH:{
10697 if (!RNODE_HASH(node)->nd_brace) {
10698 *value_p = Qundef;
10699 *shareable_literal_p = 0;
10700 return COMPILE_OK;
10701 }
10702 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10703 if (!RNODE_LIST(n)->nd_head) {
10704 // If the hash node have a keyword splat, fall back to the default case.
10705 goto compile_shareable;
10706 }
10707 }
10708
10709 INIT_ANCHOR(anchor);
10710 lit = rb_hash_new();
10711 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10712 VALUE key_val = 0;
10713 VALUE value_val = 0;
10714 int shareable_literal_p2;
10715 NODE *key = RNODE_LIST(n)->nd_head;
10716 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10717 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10718 if (shareable_literal_p2) {
10719 /* noop */
10720 }
10721 else if (RTEST(lit)) {
10722 rb_hash_clear(lit);
10723 lit = Qfalse;
10724 }
10725 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10726 if (shareable_literal_p2) {
10727 /* noop */
10728 }
10729 else if (RTEST(lit)) {
10730 rb_hash_clear(lit);
10731 lit = Qfalse;
10732 }
10733 if (RTEST(lit)) {
10734 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10735 rb_hash_aset(lit, key_val, value_val);
10736 }
10737 else {
10738 rb_hash_clear(lit);
10739 lit = Qnil; /* make shareable at runtime */
10740 }
10741 }
10742 }
10743 break;
10744 }
10745
10746 default:
10747
10748 compile_shareable:
10749 if (shareable == rb_parser_shareable_literal &&
10750 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10751 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10752 *value_p = Qundef;
10753 *shareable_literal_p = 1;
10754 return COMPILE_OK;
10755 }
10756 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10757 *value_p = Qundef;
10758 *shareable_literal_p = 0;
10759 return COMPILE_OK;
10760 }
10761
10762 /* Array or Hash that does not have keyword splat */
10763 if (!lit) {
10764 if (nd_type(node) == NODE_LIST) {
10765 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10766 }
10767 else if (nd_type(node) == NODE_HASH) {
10768 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10769 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10770 }
10771 *value_p = Qundef;
10772 *shareable_literal_p = 0;
10773 ADD_SEQ(ret, anchor);
10774 return COMPILE_OK;
10775 }
10776 if (NIL_P(lit)) {
10777 // if shareable_literal, all elements should have been ensured
10778 // as shareable
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 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10787 *value_p = Qundef;
10788 *shareable_literal_p = 1;
10789 }
10790 else {
10792 ADD_INSN1(ret, node, putobject, val);
10793 RB_OBJ_WRITTEN(iseq, Qundef, val);
10794 *value_p = val;
10795 *shareable_literal_p = 1;
10796 }
10797
10798 return COMPILE_OK;
10799}
10800
10801static int
10802compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10803{
10804 int literal_p = 0;
10805 VALUE val;
10806 DECL_ANCHOR(anchor);
10807 INIT_ANCHOR(anchor);
10808
10809 switch (shareable) {
10810 case rb_parser_shareable_none:
10811 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10812 return COMPILE_OK;
10813
10814 case rb_parser_shareable_literal:
10815 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10816 ADD_SEQ(ret, anchor);
10817 return COMPILE_OK;
10818
10819 case rb_parser_shareable_copy:
10820 case rb_parser_shareable_everything:
10821 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10822 if (!literal_p) {
10823 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10824 }
10825 else {
10826 ADD_SEQ(ret, anchor);
10827 }
10828 return COMPILE_OK;
10829 default:
10830 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10831 }
10832}
10833
10834static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10842static int
10843iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10844{
10845 if (node == 0) {
10846 if (!popped) {
10847 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10848 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10849 debugs("node: NODE_NIL(implicit)\n");
10850 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10851 }
10852 return COMPILE_OK;
10853 }
10854 return iseq_compile_each0(iseq, ret, node, popped);
10855}
10856
10857static int
10858iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10859{
10860 const int line = (int)nd_line(node);
10861 const enum node_type type = nd_type(node);
10862 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10863
10864 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10865 /* ignore */
10866 }
10867 else {
10868 if (nd_fl_newline(node)) {
10869 int event = RUBY_EVENT_LINE;
10870 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10871 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10872 event |= RUBY_EVENT_COVERAGE_LINE;
10873 }
10874 ADD_TRACE(ret, event);
10875 }
10876 }
10877
10878 debug_node_start(node);
10879#undef BEFORE_RETURN
10880#define BEFORE_RETURN debug_node_end()
10881
10882 switch (type) {
10883 case NODE_BLOCK:
10884 CHECK(compile_block(iseq, ret, node, popped));
10885 break;
10886 case NODE_IF:
10887 case NODE_UNLESS:
10888 CHECK(compile_if(iseq, ret, node, popped, type));
10889 break;
10890 case NODE_CASE:
10891 CHECK(compile_case(iseq, ret, node, popped));
10892 break;
10893 case NODE_CASE2:
10894 CHECK(compile_case2(iseq, ret, node, popped));
10895 break;
10896 case NODE_CASE3:
10897 CHECK(compile_case3(iseq, ret, node, popped));
10898 break;
10899 case NODE_WHILE:
10900 case NODE_UNTIL:
10901 CHECK(compile_loop(iseq, ret, node, popped, type));
10902 break;
10903 case NODE_FOR:
10904 case NODE_ITER:
10905 CHECK(compile_iter(iseq, ret, node, popped));
10906 break;
10907 case NODE_FOR_MASGN:
10908 CHECK(compile_for_masgn(iseq, ret, node, popped));
10909 break;
10910 case NODE_BREAK:
10911 CHECK(compile_break(iseq, ret, node, popped));
10912 break;
10913 case NODE_NEXT:
10914 CHECK(compile_next(iseq, ret, node, popped));
10915 break;
10916 case NODE_REDO:
10917 CHECK(compile_redo(iseq, ret, node, popped));
10918 break;
10919 case NODE_RETRY:
10920 CHECK(compile_retry(iseq, ret, node, popped));
10921 break;
10922 case NODE_BEGIN:{
10923 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10924 break;
10925 }
10926 case NODE_RESCUE:
10927 CHECK(compile_rescue(iseq, ret, node, popped));
10928 break;
10929 case NODE_RESBODY:
10930 CHECK(compile_resbody(iseq, ret, node, popped));
10931 break;
10932 case NODE_ENSURE:
10933 CHECK(compile_ensure(iseq, ret, node, popped));
10934 break;
10935
10936 case NODE_AND:
10937 case NODE_OR:{
10938 LABEL *end_label = NEW_LABEL(line);
10939 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10940 if (!popped) {
10941 ADD_INSN(ret, node, dup);
10942 }
10943 if (type == NODE_AND) {
10944 ADD_INSNL(ret, node, branchunless, end_label);
10945 }
10946 else {
10947 ADD_INSNL(ret, node, branchif, end_label);
10948 }
10949 if (!popped) {
10950 ADD_INSN(ret, node, pop);
10951 }
10952 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10953 ADD_LABEL(ret, end_label);
10954 break;
10955 }
10956
10957 case NODE_MASGN:{
10958 compile_massign(iseq, ret, node, popped);
10959 break;
10960 }
10961
10962 case NODE_LASGN:{
10963 ID id = RNODE_LASGN(node)->nd_vid;
10964 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10965
10966 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10967 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10968
10969 if (!popped) {
10970 ADD_INSN(ret, node, dup);
10971 }
10972 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10973 break;
10974 }
10975 case NODE_DASGN: {
10976 int idx, lv, ls;
10977 ID id = RNODE_DASGN(node)->nd_vid;
10978 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10979 debugi("dassn id", rb_id2str(id) ? id : '*');
10980
10981 if (!popped) {
10982 ADD_INSN(ret, node, dup);
10983 }
10984
10985 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10986
10987 if (idx < 0) {
10988 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10989 rb_id2str(id));
10990 goto ng;
10991 }
10992 ADD_SETLOCAL(ret, node, ls - idx, lv);
10993 break;
10994 }
10995 case NODE_GASGN:{
10996 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10997
10998 if (!popped) {
10999 ADD_INSN(ret, node, dup);
11000 }
11001 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11002 break;
11003 }
11004 case NODE_IASGN:{
11005 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11006 if (!popped) {
11007 ADD_INSN(ret, node, dup);
11008 }
11009 ADD_INSN2(ret, node, setinstancevariable,
11010 ID2SYM(RNODE_IASGN(node)->nd_vid),
11011 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11012 break;
11013 }
11014 case NODE_CDECL:{
11015 if (RNODE_CDECL(node)->nd_vid) {
11016 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11017
11018 if (!popped) {
11019 ADD_INSN(ret, node, dup);
11020 }
11021
11022 ADD_INSN1(ret, node, putspecialobject,
11023 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11024 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11025 }
11026 else {
11027 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11028 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11029 ADD_INSN(ret, node, swap);
11030
11031 if (!popped) {
11032 ADD_INSN1(ret, node, topn, INT2FIX(1));
11033 ADD_INSN(ret, node, swap);
11034 }
11035
11036 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11037 }
11038 break;
11039 }
11040 case NODE_CVASGN:{
11041 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11042 if (!popped) {
11043 ADD_INSN(ret, node, dup);
11044 }
11045 ADD_INSN2(ret, node, setclassvariable,
11046 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11047 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11048 break;
11049 }
11050 case NODE_OP_ASGN1:
11051 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11052 break;
11053 case NODE_OP_ASGN2:
11054 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11055 break;
11056 case NODE_OP_CDECL:
11057 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11058 break;
11059 case NODE_OP_ASGN_AND:
11060 case NODE_OP_ASGN_OR:
11061 CHECK(compile_op_log(iseq, ret, node, popped, type));
11062 break;
11063 case NODE_CALL: /* obj.foo */
11064 case NODE_OPCALL: /* foo[] */
11065 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11066 break;
11067 }
11068 case NODE_QCALL: /* obj&.foo */
11069 case NODE_FCALL: /* foo() */
11070 case NODE_VCALL: /* foo (variable or call) */
11071 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11072 goto ng;
11073 }
11074 break;
11075 case NODE_SUPER:
11076 case NODE_ZSUPER:
11077 CHECK(compile_super(iseq, ret, node, popped, type));
11078 break;
11079 case NODE_LIST:{
11080 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11081 break;
11082 }
11083 case NODE_ZLIST:{
11084 if (!popped) {
11085 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11086 }
11087 break;
11088 }
11089 case NODE_HASH:
11090 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11091 break;
11092 case NODE_RETURN:
11093 CHECK(compile_return(iseq, ret, node, popped));
11094 break;
11095 case NODE_YIELD:
11096 CHECK(compile_yield(iseq, ret, node, popped));
11097 break;
11098 case NODE_LVAR:{
11099 if (!popped) {
11100 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11101 }
11102 break;
11103 }
11104 case NODE_DVAR:{
11105 int lv, idx, ls;
11106 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11107 if (!popped) {
11108 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11109 if (idx < 0) {
11110 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11111 rb_id2str(RNODE_DVAR(node)->nd_vid));
11112 goto ng;
11113 }
11114 ADD_GETLOCAL(ret, node, ls - idx, lv);
11115 }
11116 break;
11117 }
11118 case NODE_GVAR:{
11119 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11120 if (popped) {
11121 ADD_INSN(ret, node, pop);
11122 }
11123 break;
11124 }
11125 case NODE_IVAR:{
11126 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11127 if (!popped) {
11128 ADD_INSN2(ret, node, getinstancevariable,
11129 ID2SYM(RNODE_IVAR(node)->nd_vid),
11130 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11131 }
11132 break;
11133 }
11134 case NODE_CONST:{
11135 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11136
11137 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11138 body->ic_size++;
11139 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11140 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11141 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11142 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11143 }
11144 else {
11145 ADD_INSN(ret, node, putnil);
11146 ADD_INSN1(ret, node, putobject, Qtrue);
11147 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11148 }
11149
11150 if (popped) {
11151 ADD_INSN(ret, node, pop);
11152 }
11153 break;
11154 }
11155 case NODE_CVAR:{
11156 if (!popped) {
11157 ADD_INSN2(ret, node, getclassvariable,
11158 ID2SYM(RNODE_CVAR(node)->nd_vid),
11159 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11160 }
11161 break;
11162 }
11163 case NODE_NTH_REF:{
11164 if (!popped) {
11165 if (!RNODE_NTH_REF(node)->nd_nth) {
11166 ADD_INSN(ret, node, putnil);
11167 break;
11168 }
11169 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11170 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11171 }
11172 break;
11173 }
11174 case NODE_BACK_REF:{
11175 if (!popped) {
11176 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11177 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11178 }
11179 break;
11180 }
11181 case NODE_MATCH:
11182 case NODE_MATCH2:
11183 case NODE_MATCH3:
11184 CHECK(compile_match(iseq, ret, node, popped, type));
11185 break;
11186 case NODE_SYM:{
11187 if (!popped) {
11188 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11189 }
11190 break;
11191 }
11192 case NODE_LINE:{
11193 if (!popped) {
11194 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11195 }
11196 break;
11197 }
11198 case NODE_ENCODING:{
11199 if (!popped) {
11200 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11201 }
11202 break;
11203 }
11204 case NODE_INTEGER:{
11205 VALUE lit = rb_node_integer_literal_val(node);
11206 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11207 debugp_param("integer", lit);
11208 if (!popped) {
11209 ADD_INSN1(ret, node, putobject, lit);
11210 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11211 }
11212 break;
11213 }
11214 case NODE_FLOAT:{
11215 VALUE lit = rb_node_float_literal_val(node);
11216 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11217 debugp_param("float", lit);
11218 if (!popped) {
11219 ADD_INSN1(ret, node, putobject, lit);
11220 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11221 }
11222 break;
11223 }
11224 case NODE_RATIONAL:{
11225 VALUE lit = rb_node_rational_literal_val(node);
11227 debugp_param("rational", lit);
11228 if (!popped) {
11229 ADD_INSN1(ret, node, putobject, lit);
11230 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11231 }
11232 break;
11233 }
11234 case NODE_IMAGINARY:{
11235 VALUE lit = rb_node_imaginary_literal_val(node);
11237 debugp_param("imaginary", lit);
11238 if (!popped) {
11239 ADD_INSN1(ret, node, putobject, lit);
11240 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11241 }
11242 break;
11243 }
11244 case NODE_FILE:
11245 case NODE_STR:{
11246 debugp_param("nd_lit", get_string_value(node));
11247 if (!popped) {
11248 VALUE lit = get_string_value(node);
11249 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11250 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11251 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11252 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11253 RB_OBJ_SET_SHAREABLE(lit);
11254 }
11255 switch (option->frozen_string_literal) {
11256 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11257 ADD_INSN1(ret, node, putchilledstring, lit);
11258 break;
11259 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11260 ADD_INSN1(ret, node, putstring, lit);
11261 break;
11262 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11263 ADD_INSN1(ret, node, putobject, lit);
11264 break;
11265 default:
11266 rb_bug("invalid frozen_string_literal");
11267 }
11268 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11269 }
11270 break;
11271 }
11272 case NODE_DSTR:{
11273 compile_dstr(iseq, ret, node);
11274
11275 if (popped) {
11276 ADD_INSN(ret, node, pop);
11277 }
11278 break;
11279 }
11280 case NODE_XSTR:{
11281 ADD_CALL_RECEIVER(ret, node);
11282 VALUE str = rb_node_str_string_val(node);
11283 ADD_INSN1(ret, node, putobject, str);
11284 RB_OBJ_WRITTEN(iseq, Qundef, str);
11285 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11286
11287 if (popped) {
11288 ADD_INSN(ret, node, pop);
11289 }
11290 break;
11291 }
11292 case NODE_DXSTR:{
11293 ADD_CALL_RECEIVER(ret, node);
11294 compile_dstr(iseq, ret, node);
11295 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11296
11297 if (popped) {
11298 ADD_INSN(ret, node, pop);
11299 }
11300 break;
11301 }
11302 case NODE_EVSTR:
11303 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11304 break;
11305 case NODE_REGX:{
11306 if (!popped) {
11307 VALUE lit = rb_node_regx_string_val(node);
11308 RB_OBJ_SET_SHAREABLE(lit);
11309 ADD_INSN1(ret, node, putobject, lit);
11310 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11311 }
11312 break;
11313 }
11314 case NODE_DREGX:
11315 compile_dregx(iseq, ret, node, popped);
11316 break;
11317 case NODE_ONCE:{
11318 int ic_index = body->ise_size++;
11319 const rb_iseq_t *block_iseq;
11320 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11321
11322 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11323 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11324
11325 if (popped) {
11326 ADD_INSN(ret, node, pop);
11327 }
11328 break;
11329 }
11330 case NODE_ARGSCAT:{
11331 if (popped) {
11332 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11333 ADD_INSN1(ret, node, splatarray, Qfalse);
11334 ADD_INSN(ret, node, pop);
11335 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11336 ADD_INSN1(ret, node, splatarray, Qfalse);
11337 ADD_INSN(ret, node, pop);
11338 }
11339 else {
11340 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11341 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11342 if (nd_type_p(body_node, NODE_LIST)) {
11343 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11344 }
11345 else {
11346 CHECK(COMPILE(ret, "argscat body", body_node));
11347 ADD_INSN(ret, node, concattoarray);
11348 }
11349 }
11350 break;
11351 }
11352 case NODE_ARGSPUSH:{
11353 if (popped) {
11354 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11355 ADD_INSN1(ret, node, splatarray, Qfalse);
11356 ADD_INSN(ret, node, pop);
11357 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11358 }
11359 else {
11360 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11361 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11362 if (keyword_node_p(body_node)) {
11363 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11364 ADD_INSN(ret, node, pushtoarraykwsplat);
11365 }
11366 else if (static_literal_node_p(body_node, iseq, false)) {
11367 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11368 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11369 }
11370 else {
11371 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11372 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11373 }
11374 }
11375 break;
11376 }
11377 case NODE_SPLAT:{
11378 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11379 ADD_INSN1(ret, node, splatarray, Qtrue);
11380
11381 if (popped) {
11382 ADD_INSN(ret, node, pop);
11383 }
11384 break;
11385 }
11386 case NODE_DEFN:{
11387 ID mid = RNODE_DEFN(node)->nd_mid;
11388 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11389 rb_id2str(mid),
11390 ISEQ_TYPE_METHOD, line);
11391
11392 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11393 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11394 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11395
11396 if (!popped) {
11397 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11398 }
11399
11400 break;
11401 }
11402 case NODE_DEFS:{
11403 ID mid = RNODE_DEFS(node)->nd_mid;
11404 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11405 rb_id2str(mid),
11406 ISEQ_TYPE_METHOD, line);
11407
11408 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11409 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11410 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11411 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11412
11413 if (!popped) {
11414 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11415 }
11416 break;
11417 }
11418 case NODE_ALIAS:{
11419 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11420 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11421 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11422 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11423 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11424
11425 if (popped) {
11426 ADD_INSN(ret, node, pop);
11427 }
11428 break;
11429 }
11430 case NODE_VALIAS:{
11431 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11432 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11433 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11434 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11435
11436 if (popped) {
11437 ADD_INSN(ret, node, pop);
11438 }
11439 break;
11440 }
11441 case NODE_UNDEF:{
11442 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11443
11444 for (long i = 0; i < ary->len; i++) {
11445 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11446 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11447 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11448 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11449
11450 if (i < ary->len - 1) {
11451 ADD_INSN(ret, node, pop);
11452 }
11453 }
11454
11455 if (popped) {
11456 ADD_INSN(ret, node, pop);
11457 }
11458 break;
11459 }
11460 case NODE_CLASS:{
11461 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11462 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11463 ISEQ_TYPE_CLASS, line);
11464 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11465 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11466 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11467
11468 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11469 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11470 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11471
11472 if (popped) {
11473 ADD_INSN(ret, node, pop);
11474 }
11475 break;
11476 }
11477 case NODE_MODULE:{
11478 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11479 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11480 ISEQ_TYPE_CLASS, line);
11481 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11482 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11483
11484 ADD_INSN (ret, node, putnil); /* dummy */
11485 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11486 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11487
11488 if (popped) {
11489 ADD_INSN(ret, node, pop);
11490 }
11491 break;
11492 }
11493 case NODE_SCLASS:{
11494 ID singletonclass;
11495 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11496 ISEQ_TYPE_CLASS, line);
11497
11498 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11499 ADD_INSN (ret, node, putnil);
11500 CONST_ID(singletonclass, "singletonclass");
11501 ADD_INSN3(ret, node, defineclass,
11502 ID2SYM(singletonclass), singleton_class,
11503 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11504 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11505
11506 if (popped) {
11507 ADD_INSN(ret, node, pop);
11508 }
11509 break;
11510 }
11511 case NODE_COLON2:
11512 CHECK(compile_colon2(iseq, ret, node, popped));
11513 break;
11514 case NODE_COLON3:
11515 CHECK(compile_colon3(iseq, ret, node, popped));
11516 break;
11517 case NODE_DOT2:
11518 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11519 break;
11520 case NODE_DOT3:
11521 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11522 break;
11523 case NODE_FLIP2:
11524 case NODE_FLIP3:{
11525 LABEL *lend = NEW_LABEL(line);
11526 LABEL *ltrue = NEW_LABEL(line);
11527 LABEL *lfalse = NEW_LABEL(line);
11528 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11529 ltrue, lfalse));
11530 ADD_LABEL(ret, ltrue);
11531 ADD_INSN1(ret, node, putobject, Qtrue);
11532 ADD_INSNL(ret, node, jump, lend);
11533 ADD_LABEL(ret, lfalse);
11534 ADD_INSN1(ret, node, putobject, Qfalse);
11535 ADD_LABEL(ret, lend);
11536 break;
11537 }
11538 case NODE_SELF:{
11539 if (!popped) {
11540 ADD_INSN(ret, node, putself);
11541 }
11542 break;
11543 }
11544 case NODE_NIL:{
11545 if (!popped) {
11546 ADD_INSN(ret, node, putnil);
11547 }
11548 break;
11549 }
11550 case NODE_TRUE:{
11551 if (!popped) {
11552 ADD_INSN1(ret, node, putobject, Qtrue);
11553 }
11554 break;
11555 }
11556 case NODE_FALSE:{
11557 if (!popped) {
11558 ADD_INSN1(ret, node, putobject, Qfalse);
11559 }
11560 break;
11561 }
11562 case NODE_ERRINFO:
11563 CHECK(compile_errinfo(iseq, ret, node, popped));
11564 break;
11565 case NODE_DEFINED:
11566 if (!popped) {
11567 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11568 }
11569 break;
11570 case NODE_POSTEXE:{
11571 /* compiled to:
11572 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11573 */
11574 int is_index = body->ise_size++;
11576 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11577 const rb_iseq_t *once_iseq =
11578 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11579
11580 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11581 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11582
11583 if (popped) {
11584 ADD_INSN(ret, node, pop);
11585 }
11586 break;
11587 }
11588 case NODE_KW_ARG:
11589 CHECK(compile_kw_arg(iseq, ret, node, popped));
11590 break;
11591 case NODE_DSYM:{
11592 compile_dstr(iseq, ret, node);
11593 if (!popped) {
11594 ADD_INSN(ret, node, intern);
11595 }
11596 else {
11597 ADD_INSN(ret, node, pop);
11598 }
11599 break;
11600 }
11601 case NODE_ATTRASGN:
11602 CHECK(compile_attrasgn(iseq, ret, node, popped));
11603 break;
11604 case NODE_LAMBDA:{
11605 /* compile same as lambda{...} */
11606 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11607 VALUE argc = INT2FIX(0);
11608
11609 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11610 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11611 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11612
11613 if (popped) {
11614 ADD_INSN(ret, node, pop);
11615 }
11616 break;
11617 }
11618 default:
11619 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11620 ng:
11621 debug_node_end();
11622 return COMPILE_NG;
11623 }
11624
11625 debug_node_end();
11626 return COMPILE_OK;
11627}
11628
11629/***************************/
11630/* instruction information */
11631/***************************/
11632
11633static int
11634insn_data_length(INSN *iobj)
11635{
11636 return insn_len(iobj->insn_id);
11637}
11638
11639static int
11640calc_sp_depth(int depth, INSN *insn)
11641{
11642 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11643}
11644
11645static VALUE
11646opobj_inspect(VALUE obj)
11647{
11648 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11649 switch (BUILTIN_TYPE(obj)) {
11650 case T_STRING:
11651 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11652 break;
11653 case T_ARRAY:
11654 obj = rb_ary_dup(obj);
11655 break;
11656 default:
11657 break;
11658 }
11659 }
11660 return rb_inspect(obj);
11661}
11662
11663
11664
11665static VALUE
11666insn_data_to_s_detail(INSN *iobj)
11667{
11668 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11669
11670 if (iobj->operands) {
11671 const char *types = insn_op_types(iobj->insn_id);
11672 int j;
11673
11674 for (j = 0; types[j]; j++) {
11675 char type = types[j];
11676
11677 switch (type) {
11678 case TS_OFFSET: /* label(destination position) */
11679 {
11680 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11681 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11682 break;
11683 }
11684 break;
11685 case TS_ISEQ: /* iseq */
11686 {
11687 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11688 VALUE val = Qnil;
11689 if (0 && iseq) { /* TODO: invalidate now */
11690 val = (VALUE)iseq;
11691 }
11692 rb_str_concat(str, opobj_inspect(val));
11693 }
11694 break;
11695 case TS_LINDEX:
11696 case TS_NUM: /* ulong */
11697 case TS_VALUE: /* VALUE */
11698 {
11699 VALUE v = OPERAND_AT(iobj, j);
11700 if (!CLASS_OF(v))
11701 rb_str_cat2(str, "<hidden>");
11702 else {
11703 rb_str_concat(str, opobj_inspect(v));
11704 }
11705 break;
11706 }
11707 case TS_ID: /* ID */
11708 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11709 break;
11710 case TS_IC: /* inline cache */
11711 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11712 break;
11713 case TS_IVC: /* inline ivar cache */
11714 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11715 break;
11716 case TS_ICVARC: /* inline cvar cache */
11717 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11718 break;
11719 case TS_ISE: /* inline storage entry */
11720 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11721 break;
11722 case TS_CALLDATA: /* we store these as call infos at compile time */
11723 {
11724 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11725 rb_str_cat2(str, "<calldata:");
11726 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11727 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11728 break;
11729 }
11730 case TS_CDHASH: /* case/when condition cache */
11731 rb_str_cat2(str, "<ch>");
11732 break;
11733 case TS_FUNCPTR:
11734 {
11735 void *func = (void *)OPERAND_AT(iobj, j);
11736#ifdef HAVE_DLADDR
11737 Dl_info info;
11738 if (dladdr(func, &info) && info.dli_sname) {
11739 rb_str_cat2(str, info.dli_sname);
11740 break;
11741 }
11742#endif
11743 rb_str_catf(str, "<%p>", func);
11744 }
11745 break;
11746 case TS_BUILTIN:
11747 rb_str_cat2(str, "<TS_BUILTIN>");
11748 break;
11749 default:{
11750 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11751 }
11752 }
11753 if (types[j + 1]) {
11754 rb_str_cat2(str, ", ");
11755 }
11756 }
11757 }
11758 return str;
11759}
11760
11761static void
11762dump_disasm_list(const LINK_ELEMENT *link)
11763{
11764 dump_disasm_list_with_cursor(link, NULL, NULL);
11765}
11766
11767static void
11768dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11769{
11770 int pos = 0;
11771 INSN *iobj;
11772 LABEL *lobj;
11773 VALUE str;
11774
11775 printf("-- raw disasm--------\n");
11776
11777 while (link) {
11778 if (curr) printf(curr == link ? "*" : " ");
11779 switch (link->type) {
11780 case ISEQ_ELEMENT_INSN:
11781 {
11782 iobj = (INSN *)link;
11783 str = insn_data_to_s_detail(iobj);
11784 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11785 pos += insn_data_length(iobj);
11786 break;
11787 }
11788 case ISEQ_ELEMENT_LABEL:
11789 {
11790 lobj = (LABEL *)link;
11791 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11792 dest == lobj ? " <---" : "");
11793 break;
11794 }
11795 case ISEQ_ELEMENT_TRACE:
11796 {
11797 TRACE *trace = (TRACE *)link;
11798 printf(" trace: %0x\n", trace->event);
11799 break;
11800 }
11801 case ISEQ_ELEMENT_ADJUST:
11802 {
11803 ADJUST *adjust = (ADJUST *)link;
11804 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11805 break;
11806 }
11807 default:
11808 /* ignore */
11809 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11810 }
11811 link = link->next;
11812 }
11813 printf("---------------------\n");
11814 fflush(stdout);
11815}
11816
11817int
11818rb_insn_len(VALUE insn)
11819{
11820 return insn_len(insn);
11821}
11822
11823const char *
11824rb_insns_name(int i)
11825{
11826 return insn_name(i);
11827}
11828
11829VALUE
11830rb_insns_name_array(void)
11831{
11832 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11833 int i;
11834 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11835 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11836 }
11837 return rb_ary_freeze(ary);
11838}
11839
11840static LABEL *
11841register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11842{
11843 LABEL *label = 0;
11844 st_data_t tmp;
11845 obj = rb_to_symbol_type(obj);
11846
11847 if (st_lookup(labels_table, obj, &tmp) == 0) {
11848 label = NEW_LABEL(0);
11849 st_insert(labels_table, obj, (st_data_t)label);
11850 }
11851 else {
11852 label = (LABEL *)tmp;
11853 }
11854 LABEL_REF(label);
11855 return label;
11856}
11857
11858static VALUE
11859get_exception_sym2type(VALUE sym)
11860{
11861 static VALUE symRescue, symEnsure, symRetry;
11862 static VALUE symBreak, symRedo, symNext;
11863
11864 if (symRescue == 0) {
11865 symRescue = ID2SYM(rb_intern_const("rescue"));
11866 symEnsure = ID2SYM(rb_intern_const("ensure"));
11867 symRetry = ID2SYM(rb_intern_const("retry"));
11868 symBreak = ID2SYM(rb_intern_const("break"));
11869 symRedo = ID2SYM(rb_intern_const("redo"));
11870 symNext = ID2SYM(rb_intern_const("next"));
11871 }
11872
11873 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11874 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11875 if (sym == symRetry) return CATCH_TYPE_RETRY;
11876 if (sym == symBreak) return CATCH_TYPE_BREAK;
11877 if (sym == symRedo) return CATCH_TYPE_REDO;
11878 if (sym == symNext) return CATCH_TYPE_NEXT;
11879 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11880 return 0;
11881}
11882
11883static int
11884iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11885 VALUE exception)
11886{
11887 int i;
11888
11889 for (i=0; i<RARRAY_LEN(exception); i++) {
11890 const rb_iseq_t *eiseq;
11891 VALUE v, type;
11892 LABEL *lstart, *lend, *lcont;
11893 unsigned int sp;
11894
11895 v = rb_to_array_type(RARRAY_AREF(exception, i));
11896 if (RARRAY_LEN(v) != 6) {
11897 rb_raise(rb_eSyntaxError, "wrong exception entry");
11898 }
11899 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11900 if (NIL_P(RARRAY_AREF(v, 1))) {
11901 eiseq = NULL;
11902 }
11903 else {
11904 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11905 }
11906
11907 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11908 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11909 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11910 sp = NUM2UINT(RARRAY_AREF(v, 5));
11911
11912 /* TODO: Dirty Hack! Fix me */
11913 if (type == CATCH_TYPE_RESCUE ||
11914 type == CATCH_TYPE_BREAK ||
11915 type == CATCH_TYPE_NEXT) {
11916 ++sp;
11917 }
11918
11919 lcont->sp = sp;
11920
11921 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11922
11923 RB_GC_GUARD(v);
11924 }
11925 return COMPILE_OK;
11926}
11927
11928static struct st_table *
11929insn_make_insn_table(void)
11930{
11931 struct st_table *table;
11932 int i;
11933 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11934
11935 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11936 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11937 }
11938
11939 return table;
11940}
11941
11942static const rb_iseq_t *
11943iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11944{
11945 VALUE iseqw;
11946 const rb_iseq_t *loaded_iseq;
11947
11948 if (RB_TYPE_P(op, T_ARRAY)) {
11949 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11950 }
11951 else if (CLASS_OF(op) == rb_cISeq) {
11952 iseqw = op;
11953 }
11954 else {
11955 rb_raise(rb_eSyntaxError, "ISEQ is required");
11956 }
11957
11958 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11959 return loaded_iseq;
11960}
11961
11962static VALUE
11963iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11964{
11965 ID mid = 0;
11966 int orig_argc = 0;
11967 unsigned int flag = 0;
11968 struct rb_callinfo_kwarg *kw_arg = 0;
11969
11970 if (!NIL_P(op)) {
11971 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11972 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11973 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11974 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11975
11976 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11977 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11978 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11979
11980 if (!NIL_P(vkw_arg)) {
11981 int i;
11982 int len = RARRAY_LENINT(vkw_arg);
11983 size_t n = rb_callinfo_kwarg_bytes(len);
11984
11985 kw_arg = xmalloc(n);
11986 kw_arg->references = 0;
11987 kw_arg->keyword_len = len;
11988 for (i = 0; i < len; i++) {
11989 VALUE kw = RARRAY_AREF(vkw_arg, i);
11990 SYM2ID(kw); /* make immortal */
11991 kw_arg->keywords[i] = kw;
11992 }
11993 }
11994 }
11995
11996 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11997 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11998 return (VALUE)ci;
11999}
12000
12001static rb_event_flag_t
12002event_name_to_flag(VALUE sym)
12003{
12004#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12005 CHECK_EVENT(RUBY_EVENT_LINE);
12006 CHECK_EVENT(RUBY_EVENT_CLASS);
12007 CHECK_EVENT(RUBY_EVENT_END);
12008 CHECK_EVENT(RUBY_EVENT_CALL);
12009 CHECK_EVENT(RUBY_EVENT_RETURN);
12010 CHECK_EVENT(RUBY_EVENT_B_CALL);
12011 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12012 CHECK_EVENT(RUBY_EVENT_RESCUE);
12013#undef CHECK_EVENT
12014 return RUBY_EVENT_NONE;
12015}
12016
12017static int
12018iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12019 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12020{
12021 /* TODO: body should be frozen */
12022 long i, len = RARRAY_LEN(body);
12023 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12024 int j;
12025 int line_no = 0, node_id = -1, insn_idx = 0;
12026 int ret = COMPILE_OK;
12027
12028 /*
12029 * index -> LABEL *label
12030 */
12031 static struct st_table *insn_table;
12032
12033 if (insn_table == 0) {
12034 insn_table = insn_make_insn_table();
12035 }
12036
12037 for (i=0; i<len; i++) {
12038 VALUE obj = RARRAY_AREF(body, i);
12039
12040 if (SYMBOL_P(obj)) {
12041 rb_event_flag_t event;
12042 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12043 ADD_TRACE(anchor, event);
12044 }
12045 else {
12046 LABEL *label = register_label(iseq, labels_table, obj);
12047 ADD_LABEL(anchor, label);
12048 }
12049 }
12050 else if (FIXNUM_P(obj)) {
12051 line_no = NUM2INT(obj);
12052 }
12053 else if (RB_TYPE_P(obj, T_ARRAY)) {
12054 VALUE *argv = 0;
12055 int argc = RARRAY_LENINT(obj) - 1;
12056 st_data_t insn_id;
12057 VALUE insn;
12058
12059 if (node_ids) {
12060 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12061 }
12062
12063 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12064 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12065 /* TODO: exception */
12066 COMPILE_ERROR(iseq, line_no,
12067 "unknown instruction: %+"PRIsVALUE, insn);
12068 ret = COMPILE_NG;
12069 break;
12070 }
12071
12072 if (argc != insn_len((VALUE)insn_id)-1) {
12073 COMPILE_ERROR(iseq, line_no,
12074 "operand size mismatch");
12075 ret = COMPILE_NG;
12076 break;
12077 }
12078
12079 if (argc > 0) {
12080 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12081
12082 // add element before operand setup to make GC root
12083 ADD_ELEM(anchor,
12084 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12085 (enum ruby_vminsn_type)insn_id, argc, argv));
12086
12087 for (j=0; j<argc; j++) {
12088 VALUE op = rb_ary_entry(obj, j+1);
12089 switch (insn_op_type((VALUE)insn_id, j)) {
12090 case TS_OFFSET: {
12091 LABEL *label = register_label(iseq, labels_table, op);
12092 argv[j] = (VALUE)label;
12093 break;
12094 }
12095 case TS_LINDEX:
12096 case TS_NUM:
12097 (void)NUM2INT(op);
12098 argv[j] = op;
12099 break;
12100 case TS_VALUE:
12101 argv[j] = op;
12102 RB_OBJ_WRITTEN(iseq, Qundef, op);
12103 break;
12104 case TS_ISEQ:
12105 {
12106 if (op != Qnil) {
12107 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12108 argv[j] = v;
12109 RB_OBJ_WRITTEN(iseq, Qundef, v);
12110 }
12111 else {
12112 argv[j] = 0;
12113 }
12114 }
12115 break;
12116 case TS_ISE:
12117 argv[j] = op;
12118 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12119 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12120 }
12121 break;
12122 case TS_IC:
12123 {
12124 VALUE segments = rb_ary_new();
12125 op = rb_to_array_type(op);
12126
12127 for (int i = 0; i < RARRAY_LEN(op); i++) {
12128 VALUE sym = RARRAY_AREF(op, i);
12129 sym = rb_to_symbol_type(sym);
12130 rb_ary_push(segments, sym);
12131 }
12132
12133 RB_GC_GUARD(op);
12134 argv[j] = segments;
12135 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12136 ISEQ_BODY(iseq)->ic_size++;
12137 }
12138 break;
12139 case TS_IVC: /* inline ivar cache */
12140 argv[j] = op;
12141 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12142 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12143 }
12144 break;
12145 case TS_ICVARC: /* inline cvar cache */
12146 argv[j] = op;
12147 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12148 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12149 }
12150 break;
12151 case TS_CALLDATA:
12152 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12153 break;
12154 case TS_ID:
12155 argv[j] = rb_to_symbol_type(op);
12156 break;
12157 case TS_CDHASH:
12158 {
12159 int i;
12160 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12161
12162 RHASH_TBL_RAW(map)->type = &cdhash_type;
12163 op = rb_to_array_type(op);
12164 for (i=0; i<RARRAY_LEN(op); i+=2) {
12165 VALUE key = RARRAY_AREF(op, i);
12166 VALUE sym = RARRAY_AREF(op, i+1);
12167 LABEL *label =
12168 register_label(iseq, labels_table, sym);
12169 rb_hash_aset(map, key, (VALUE)label | 1);
12170 }
12171 RB_GC_GUARD(op);
12172 RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
12173 argv[j] = map;
12174 RB_OBJ_WRITTEN(iseq, Qundef, map);
12175 }
12176 break;
12177 case TS_FUNCPTR:
12178 {
12179#if SIZEOF_VALUE <= SIZEOF_LONG
12180 long funcptr = NUM2LONG(op);
12181#else
12182 LONG_LONG funcptr = NUM2LL(op);
12183#endif
12184 argv[j] = (VALUE)funcptr;
12185 }
12186 break;
12187 default:
12188 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12189 }
12190 }
12191 }
12192 else {
12193 ADD_ELEM(anchor,
12194 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12195 (enum ruby_vminsn_type)insn_id, argc, NULL));
12196 }
12197 }
12198 else {
12199 rb_raise(rb_eTypeError, "unexpected object for instruction");
12200 }
12201 }
12202 RTYPEDDATA_DATA(labels_wrapper) = 0;
12203 RB_GC_GUARD(labels_wrapper);
12204 validate_labels(iseq, labels_table);
12205 if (!ret) return ret;
12206 return iseq_setup(iseq, anchor);
12207}
12208
12209#define CHECK_ARRAY(v) rb_to_array_type(v)
12210#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12211
12212static int
12213int_param(int *dst, VALUE param, VALUE sym)
12214{
12215 VALUE val = rb_hash_aref(param, sym);
12216 if (FIXNUM_P(val)) {
12217 *dst = FIX2INT(val);
12218 return TRUE;
12219 }
12220 else if (!NIL_P(val)) {
12221 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12222 sym, val);
12223 }
12224 return FALSE;
12225}
12226
12227static const struct rb_iseq_param_keyword *
12228iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12229{
12230 int i, j;
12231 int len = RARRAY_LENINT(keywords);
12232 int default_len;
12233 VALUE key, sym, default_val;
12234 VALUE *dvs;
12235 ID *ids;
12236 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12237
12238 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12239
12240 keyword->num = len;
12241#define SYM(s) ID2SYM(rb_intern_const(#s))
12242 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12243 i = keyword->bits_start - keyword->num;
12244 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12245#undef SYM
12246
12247 /* required args */
12248 for (i = 0; i < len; i++) {
12249 VALUE val = RARRAY_AREF(keywords, i);
12250
12251 if (!SYMBOL_P(val)) {
12252 goto default_values;
12253 }
12254 ids[i] = SYM2ID(val);
12255 keyword->required_num++;
12256 }
12257
12258 default_values: /* note: we intentionally preserve `i' from previous loop */
12259 default_len = len - i;
12260 if (default_len == 0) {
12261 keyword->table = ids;
12262 return keyword;
12263 }
12264 else if (default_len < 0) {
12266 }
12267
12268 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12269
12270 for (j = 0; i < len; i++, j++) {
12271 key = RARRAY_AREF(keywords, i);
12272 CHECK_ARRAY(key);
12273
12274 switch (RARRAY_LEN(key)) {
12275 case 1:
12276 sym = RARRAY_AREF(key, 0);
12277 default_val = Qundef;
12278 break;
12279 case 2:
12280 sym = RARRAY_AREF(key, 0);
12281 default_val = RARRAY_AREF(key, 1);
12282 break;
12283 default:
12284 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12285 }
12286 ids[i] = SYM2ID(sym);
12287 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12288 }
12289
12290 keyword->table = ids;
12291 keyword->default_values = dvs;
12292
12293 return keyword;
12294}
12295
12296static void
12297iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12298{
12299 rb_gc_mark_and_move(obj);
12300}
12301
12302void
12303rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12304{
12305 INSN *iobj = 0;
12306 size_t size = sizeof(INSN);
12307 unsigned int pos = 0;
12308
12309 while (storage) {
12310#ifdef STRICT_ALIGNMENT
12311 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12312#else
12313 const size_t padding = 0; /* expected to be optimized by compiler */
12314#endif /* STRICT_ALIGNMENT */
12315 size_t offset = pos + size + padding;
12316 if (offset > storage->size || offset > storage->pos) {
12317 pos = 0;
12318 storage = storage->next;
12319 }
12320 else {
12321#ifdef STRICT_ALIGNMENT
12322 pos += (int)padding;
12323#endif /* STRICT_ALIGNMENT */
12324
12325 iobj = (INSN *)&storage->buff[pos];
12326
12327 if (iobj->operands) {
12328 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12329 }
12330 pos += (int)size;
12331 }
12332 }
12333}
12334
12335static const rb_data_type_t labels_wrapper_type = {
12336 .wrap_struct_name = "compiler/labels_wrapper",
12337 .function = {
12338 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12339 .dfree = (RUBY_DATA_FUNC)st_free_table,
12340 },
12341 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12342};
12343
12344void
12345rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12346 VALUE exception, VALUE body)
12347{
12348#define SYM(s) ID2SYM(rb_intern_const(#s))
12349 int i, len;
12350 unsigned int arg_size, local_size, stack_max;
12351 ID *tbl;
12352 struct st_table *labels_table = st_init_numtable();
12353 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12354 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12355 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12356 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12357 DECL_ANCHOR(anchor);
12358 INIT_ANCHOR(anchor);
12359
12360 len = RARRAY_LENINT(locals);
12361 ISEQ_BODY(iseq)->local_table_size = len;
12362 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12363
12364 for (i = 0; i < len; i++) {
12365 VALUE lv = RARRAY_AREF(locals, i);
12366
12367 if (sym_arg_rest == lv) {
12368 tbl[i] = 0;
12369 }
12370 else {
12371 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12372 }
12373 }
12374
12375#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12376 if (INT_PARAM(lead_num)) {
12377 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12378 }
12379 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12380 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12381 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12382 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12383#undef INT_PARAM
12384 {
12385#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12386 int x;
12387 INT_PARAM(arg_size);
12388 INT_PARAM(local_size);
12389 INT_PARAM(stack_max);
12390#undef INT_PARAM
12391 }
12392
12393 VALUE node_ids = Qfalse;
12394#ifdef USE_ISEQ_NODE_ID
12395 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12396 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12397 rb_raise(rb_eTypeError, "node_ids is not an array");
12398 }
12399#endif
12400
12401 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12402 len = RARRAY_LENINT(arg_opt_labels);
12403 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12404
12405 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12406 VALUE *opt_table = ALLOC_N(VALUE, len);
12407
12408 for (i = 0; i < len; i++) {
12409 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12410 LABEL *label = register_label(iseq, labels_table, ent);
12411 opt_table[i] = (VALUE)label;
12412 }
12413
12414 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12415 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12416 }
12417 }
12418 else if (!NIL_P(arg_opt_labels)) {
12419 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12420 arg_opt_labels);
12421 }
12422
12423 if (RB_TYPE_P(keywords, T_ARRAY)) {
12424 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12425 }
12426 else if (!NIL_P(keywords)) {
12427 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12428 keywords);
12429 }
12430
12431 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12432 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12433 }
12434
12435 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12436 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12437 }
12438
12439 if (int_param(&i, params, SYM(kwrest))) {
12440 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12441 if (keyword == NULL) {
12442 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12443 }
12444 keyword->rest_start = i;
12445 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12446 }
12447#undef SYM
12448 iseq_calc_param_size(iseq);
12449
12450 /* exception */
12451 iseq_build_from_ary_exception(iseq, labels_table, exception);
12452
12453 /* body */
12454 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12455
12456 ISEQ_BODY(iseq)->param.size = arg_size;
12457 ISEQ_BODY(iseq)->local_table_size = local_size;
12458 ISEQ_BODY(iseq)->stack_max = stack_max;
12459}
12460
12461/* for parser */
12462
12463int
12464rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12465{
12466 if (iseq) {
12467 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12468 while (body->type == ISEQ_TYPE_BLOCK ||
12469 body->type == ISEQ_TYPE_RESCUE ||
12470 body->type == ISEQ_TYPE_ENSURE ||
12471 body->type == ISEQ_TYPE_EVAL ||
12472 body->type == ISEQ_TYPE_MAIN
12473 ) {
12474 unsigned int i;
12475
12476 for (i = 0; i < body->local_table_size; i++) {
12477 if (body->local_table[i] == id) {
12478 return 1;
12479 }
12480 }
12481 iseq = body->parent_iseq;
12482 body = ISEQ_BODY(iseq);
12483 }
12484 }
12485 return 0;
12486}
12487
12488int
12489rb_local_defined(ID id, const rb_iseq_t *iseq)
12490{
12491 if (iseq) {
12492 unsigned int i;
12493 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12494
12495 for (i=0; i<body->local_table_size; i++) {
12496 if (body->local_table[i] == id) {
12497 return 1;
12498 }
12499 }
12500 }
12501 return 0;
12502}
12503
12504/* ISeq binary format */
12505
12506#ifndef IBF_ISEQ_DEBUG
12507#define IBF_ISEQ_DEBUG 0
12508#endif
12509
12510#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12511#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12512#endif
12513
12514typedef uint32_t ibf_offset_t;
12515#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12516
12517#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12518#ifdef RUBY_DEVEL
12519#define IBF_DEVEL_VERSION 5
12520#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12521#else
12522#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12523#endif
12524
12525static const char IBF_ENDIAN_MARK =
12526#ifdef WORDS_BIGENDIAN
12527 'b'
12528#else
12529 'l'
12530#endif
12531 ;
12532
12534 char magic[4]; /* YARB */
12535 uint32_t major_version;
12536 uint32_t minor_version;
12537 uint32_t size;
12538 uint32_t extra_size;
12539
12540 uint32_t iseq_list_size;
12541 uint32_t global_object_list_size;
12542 ibf_offset_t iseq_list_offset;
12543 ibf_offset_t global_object_list_offset;
12544 uint8_t endian;
12545 uint8_t wordsize; /* assume no 2048-bit CPU */
12546};
12547
12549 VALUE str;
12550 st_table *obj_table; /* obj -> obj number */
12551};
12552
12553struct ibf_dump {
12554 st_table *iseq_table; /* iseq -> iseq number */
12555 struct ibf_dump_buffer global_buffer;
12556 struct ibf_dump_buffer *current_buffer;
12557};
12558
12560 const char *buff;
12561 ibf_offset_t size;
12562
12563 VALUE obj_list; /* [obj0, ...] */
12564 unsigned int obj_list_size;
12565 ibf_offset_t obj_list_offset;
12566};
12567
12568struct ibf_load {
12569 const struct ibf_header *header;
12570 VALUE iseq_list; /* [iseq0, ...] */
12571 struct ibf_load_buffer global_buffer;
12572 VALUE loader_obj;
12573 rb_iseq_t *iseq;
12574 VALUE str;
12575 struct ibf_load_buffer *current_buffer;
12576};
12577
12579 long size;
12580 VALUE buffer[1];
12581};
12582
12583static void
12584pinned_list_mark(void *ptr)
12585{
12586 long i;
12587 struct pinned_list *list = (struct pinned_list *)ptr;
12588 for (i = 0; i < list->size; i++) {
12589 if (list->buffer[i]) {
12590 rb_gc_mark(list->buffer[i]);
12591 }
12592 }
12593}
12594
12595static const rb_data_type_t pinned_list_type = {
12596 "pinned_list",
12597 {
12598 pinned_list_mark,
12600 NULL, // No external memory to report,
12601 },
12602 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12603};
12604
12605static VALUE
12606pinned_list_fetch(VALUE list, long offset)
12607{
12608 struct pinned_list * ptr;
12609
12610 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12611
12612 if (offset >= ptr->size) {
12613 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12614 }
12615
12616 return ptr->buffer[offset];
12617}
12618
12619static void
12620pinned_list_store(VALUE list, long offset, VALUE object)
12621{
12622 struct pinned_list * ptr;
12623
12624 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12625
12626 if (offset >= ptr->size) {
12627 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12628 }
12629
12630 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12631}
12632
12633static VALUE
12634pinned_list_new(long size)
12635{
12636 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12637 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12638 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12639 ptr->size = size;
12640 return obj_list;
12641}
12642
12643static ibf_offset_t
12644ibf_dump_pos(struct ibf_dump *dump)
12645{
12646 long pos = RSTRING_LEN(dump->current_buffer->str);
12647#if SIZEOF_LONG > SIZEOF_INT
12648 if (pos >= UINT_MAX) {
12649 rb_raise(rb_eRuntimeError, "dump size exceeds");
12650 }
12651#endif
12652 return (unsigned int)pos;
12653}
12654
12655static void
12656ibf_dump_align(struct ibf_dump *dump, size_t align)
12657{
12658 ibf_offset_t pos = ibf_dump_pos(dump);
12659 if (pos % align) {
12660 static const char padding[sizeof(VALUE)];
12661 size_t size = align - ((size_t)pos % align);
12662#if SIZEOF_LONG > SIZEOF_INT
12663 if (pos + size >= UINT_MAX) {
12664 rb_raise(rb_eRuntimeError, "dump size exceeds");
12665 }
12666#endif
12667 for (; size > sizeof(padding); size -= sizeof(padding)) {
12668 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12669 }
12670 rb_str_cat(dump->current_buffer->str, padding, size);
12671 }
12672}
12673
12674static ibf_offset_t
12675ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12676{
12677 ibf_offset_t pos = ibf_dump_pos(dump);
12678#if SIZEOF_LONG > SIZEOF_INT
12679 /* ensure the resulting dump does not exceed UINT_MAX */
12680 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12681 rb_raise(rb_eRuntimeError, "dump size exceeds");
12682 }
12683#endif
12684 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12685 return pos;
12686}
12687
12688static ibf_offset_t
12689ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12690{
12691 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12692}
12693
12694static void
12695ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12696{
12697 VALUE str = dump->current_buffer->str;
12698 char *ptr = RSTRING_PTR(str);
12699 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12700 rb_bug("ibf_dump_overwrite: overflow");
12701 memcpy(ptr + offset, buff, size);
12702}
12703
12704static const void *
12705ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12706{
12707 ibf_offset_t beg = *offset;
12708 *offset += size;
12709 return load->current_buffer->buff + beg;
12710}
12711
12712static void *
12713ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12714{
12715 void *buff = ruby_xmalloc2(x, y);
12716 size_t size = x * y;
12717 memcpy(buff, load->current_buffer->buff + offset, size);
12718 return buff;
12719}
12720
12721#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12722
12723#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12724#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12725#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12726#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12727#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12728
12729static int
12730ibf_table_lookup(struct st_table *table, st_data_t key)
12731{
12732 st_data_t val;
12733
12734 if (st_lookup(table, key, &val)) {
12735 return (int)val;
12736 }
12737 else {
12738 return -1;
12739 }
12740}
12741
12742static int
12743ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12744{
12745 int index = ibf_table_lookup(table, key);
12746
12747 if (index < 0) { /* not found */
12748 index = (int)table->num_entries;
12749 st_insert(table, key, (st_data_t)index);
12750 }
12751
12752 return index;
12753}
12754
12755/* dump/load generic */
12756
12757static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12758
12759static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12760static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12761
12762static st_table *
12763ibf_dump_object_table_new(void)
12764{
12765 st_table *obj_table = st_init_numtable(); /* need free */
12766 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12767
12768 return obj_table;
12769}
12770
12771static VALUE
12772ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12773{
12774 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12775}
12776
12777static VALUE
12778ibf_dump_id(struct ibf_dump *dump, ID id)
12779{
12780 if (id == 0 || rb_id2name(id) == NULL) {
12781 return 0;
12782 }
12783 return ibf_dump_object(dump, rb_id2sym(id));
12784}
12785
12786static ID
12787ibf_load_id(const struct ibf_load *load, const ID id_index)
12788{
12789 if (id_index == 0) {
12790 return 0;
12791 }
12792 VALUE sym = ibf_load_object(load, id_index);
12793 if (rb_integer_type_p(sym)) {
12794 /* Load hidden local variables as indexes */
12795 return NUM2ULONG(sym);
12796 }
12797 return rb_sym2id(sym);
12798}
12799
12800/* dump/load: code */
12801
12802static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12803
12804static int
12805ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12806{
12807 if (iseq == NULL) {
12808 return -1;
12809 }
12810 else {
12811 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12812 }
12813}
12814
12815static unsigned char
12816ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12817{
12818 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12819 return (unsigned char)load->current_buffer->buff[(*offset)++];
12820}
12821
12822/*
12823 * Small uint serialization
12824 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12825 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12826 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12827 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12828 * ...
12829 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12830 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12831 */
12832static void
12833ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12834{
12835 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12836 ibf_dump_write(dump, &x, sizeof(VALUE));
12837 return;
12838 }
12839
12840 enum { max_byte_length = sizeof(VALUE) + 1 };
12841
12842 unsigned char bytes[max_byte_length];
12843 ibf_offset_t n;
12844
12845 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12846 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12847 }
12848
12849 x <<= 1;
12850 x |= 1;
12851 x <<= n;
12852 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12853 n++;
12854
12855 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12856}
12857
12858static VALUE
12859ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12860{
12861 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12862 union { char s[sizeof(VALUE)]; VALUE v; } x;
12863
12864 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12865 *offset += sizeof(VALUE);
12866
12867 return x.v;
12868 }
12869
12870 enum { max_byte_length = sizeof(VALUE) + 1 };
12871
12872 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12873 const unsigned char c = buffer[*offset];
12874
12875 ibf_offset_t n =
12876 c & 1 ? 1 :
12877 c == 0 ? 9 : ntz_int32(c) + 1;
12878 VALUE x = (VALUE)c >> n;
12879
12880 if (*offset + n > load->current_buffer->size) {
12881 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12882 }
12883
12884 ibf_offset_t i;
12885 for (i = 1; i < n; i++) {
12886 x <<= 8;
12887 x |= (VALUE)buffer[*offset + i];
12888 }
12889
12890 *offset += n;
12891 return x;
12892}
12893
12894static void
12895ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12896{
12897 // short: index
12898 // short: name.length
12899 // bytes: name
12900 // // omit argc (only verify with name)
12901 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12902
12903 size_t len = strlen(bf->name);
12904 ibf_dump_write_small_value(dump, (VALUE)len);
12905 ibf_dump_write(dump, bf->name, len);
12906}
12907
12908static const struct rb_builtin_function *
12909ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12910{
12911 int i = (int)ibf_load_small_value(load, offset);
12912 int len = (int)ibf_load_small_value(load, offset);
12913 const char *name = (char *)ibf_load_ptr(load, offset, len);
12914
12915 if (0) {
12916 fprintf(stderr, "%.*s!!\n", len, name);
12917 }
12918
12919 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12920 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12921 if (strncmp(table[i].name, name, len) != 0) {
12922 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12923 }
12924 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12925
12926 return &table[i];
12927}
12928
12929static ibf_offset_t
12930ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12931{
12932 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12933 const int iseq_size = body->iseq_size;
12934 int code_index;
12935 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12936
12937 ibf_offset_t offset = ibf_dump_pos(dump);
12938
12939 for (code_index=0; code_index<iseq_size;) {
12940 const VALUE insn = orig_code[code_index++];
12941 const char *types = insn_op_types(insn);
12942 int op_index;
12943
12944 /* opcode */
12945 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12946 ibf_dump_write_small_value(dump, insn);
12947
12948 /* operands */
12949 for (op_index=0; types[op_index]; op_index++, code_index++) {
12950 VALUE op = orig_code[code_index];
12951 VALUE wv;
12952
12953 switch (types[op_index]) {
12954 case TS_CDHASH:
12955 case TS_VALUE:
12956 wv = ibf_dump_object(dump, op);
12957 break;
12958 case TS_ISEQ:
12959 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12960 break;
12961 case TS_IC:
12962 {
12963 IC ic = (IC)op;
12964 VALUE arr = idlist_to_array(ic->segments);
12965 wv = ibf_dump_object(dump, arr);
12966 }
12967 break;
12968 case TS_ISE:
12969 case TS_IVC:
12970 case TS_ICVARC:
12971 {
12973 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12974 }
12975 break;
12976 case TS_CALLDATA:
12977 {
12978 goto skip_wv;
12979 }
12980 case TS_ID:
12981 wv = ibf_dump_id(dump, (ID)op);
12982 break;
12983 case TS_FUNCPTR:
12984 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12985 goto skip_wv;
12986 case TS_BUILTIN:
12987 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12988 goto skip_wv;
12989 default:
12990 wv = op;
12991 break;
12992 }
12993 ibf_dump_write_small_value(dump, wv);
12994 skip_wv:;
12995 }
12996 RUBY_ASSERT(insn_len(insn) == op_index+1);
12997 }
12998
12999 return offset;
13000}
13001
13002static VALUE *
13003ibf_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)
13004{
13005 VALUE iseqv = (VALUE)iseq;
13006 unsigned int code_index;
13007 ibf_offset_t reading_pos = bytecode_offset;
13008 VALUE *code = ALLOC_N(VALUE, iseq_size);
13009
13010 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13011 struct rb_call_data *cd_entries = load_body->call_data;
13012 int ic_index = 0;
13013
13014 load_body->iseq_encoded = code;
13015 load_body->iseq_size = 0;
13016
13017 iseq_bits_t * mark_offset_bits;
13018
13019 iseq_bits_t tmp[1] = {0};
13020
13021 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13022 mark_offset_bits = tmp;
13023 }
13024 else {
13025 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13026 }
13027 bool needs_bitmap = false;
13028
13029 for (code_index=0; code_index<iseq_size;) {
13030 /* opcode */
13031 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13032 const char *types = insn_op_types(insn);
13033 int op_index;
13034
13035 code_index++;
13036
13037 /* operands */
13038 for (op_index=0; types[op_index]; op_index++, code_index++) {
13039 const char operand_type = types[op_index];
13040 switch (operand_type) {
13041 case TS_VALUE:
13042 {
13043 VALUE op = ibf_load_small_value(load, &reading_pos);
13044 VALUE v = ibf_load_object(load, op);
13045 code[code_index] = v;
13046 if (!SPECIAL_CONST_P(v)) {
13047 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13048 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13049 needs_bitmap = true;
13050 }
13051 break;
13052 }
13053 case TS_CDHASH:
13054 {
13055 VALUE op = ibf_load_small_value(load, &reading_pos);
13056 VALUE v = ibf_load_object(load, op);
13057 v = rb_hash_dup(v); // hash dumped as frozen
13058 RHASH_TBL_RAW(v)->type = &cdhash_type;
13059 rb_hash_rehash(v); // hash function changed
13060 RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13061
13062 // Overwrite the existing hash in the object list. This
13063 // is to keep the object alive during load time.
13064 // [Bug #17984] [ruby-core:104259]
13065 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13066
13067 code[code_index] = v;
13068 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13069 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13070 needs_bitmap = true;
13071 break;
13072 }
13073 case TS_ISEQ:
13074 {
13075 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13076 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13077 code[code_index] = v;
13078 if (!SPECIAL_CONST_P(v)) {
13079 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13080 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13081 needs_bitmap = true;
13082 }
13083 break;
13084 }
13085 case TS_IC:
13086 {
13087 VALUE op = ibf_load_small_value(load, &reading_pos);
13088 VALUE arr = ibf_load_object(load, op);
13089
13090 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13091 ic->segments = array_to_idlist(arr);
13092
13093 code[code_index] = (VALUE)ic;
13094 }
13095 break;
13096 case TS_ISE:
13097 case TS_ICVARC:
13098 case TS_IVC:
13099 {
13100 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13101
13102 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13103 code[code_index] = (VALUE)ic;
13104
13105 if (operand_type == TS_IVC) {
13106 IVC cache = (IVC)ic;
13107
13108 if (insn == BIN(setinstancevariable)) {
13109 ID iv_name = (ID)code[code_index - 1];
13110 cache->iv_set_name = iv_name;
13111 }
13112 else {
13113 cache->iv_set_name = 0;
13114 }
13115
13116 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13117 }
13118
13119 }
13120 break;
13121 case TS_CALLDATA:
13122 {
13123 code[code_index] = (VALUE)cd_entries++;
13124 }
13125 break;
13126 case TS_ID:
13127 {
13128 VALUE op = ibf_load_small_value(load, &reading_pos);
13129 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13130 }
13131 break;
13132 case TS_FUNCPTR:
13133 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13134 break;
13135 case TS_BUILTIN:
13136 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13137 break;
13138 default:
13139 code[code_index] = ibf_load_small_value(load, &reading_pos);
13140 continue;
13141 }
13142 }
13143 if (insn_len(insn) != op_index+1) {
13144 rb_raise(rb_eRuntimeError, "operand size mismatch");
13145 }
13146 }
13147
13148 load_body->iseq_size = code_index;
13149
13150 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13151 load_body->mark_bits.single = mark_offset_bits[0];
13152 }
13153 else {
13154 if (needs_bitmap) {
13155 load_body->mark_bits.list = mark_offset_bits;
13156 }
13157 else {
13158 load_body->mark_bits.list = 0;
13159 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(iseq_size));
13160 }
13161 }
13162
13163 RUBY_ASSERT(code_index == iseq_size);
13164 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13165 return code;
13166}
13167
13168static ibf_offset_t
13169ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13170{
13171 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13172
13173 if (opt_num > 0) {
13174 IBF_W_ALIGN(VALUE);
13175 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13176 }
13177 else {
13178 return ibf_dump_pos(dump);
13179 }
13180}
13181
13182static VALUE *
13183ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13184{
13185 if (opt_num > 0) {
13186 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13187 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13188 return table;
13189 }
13190 else {
13191 return NULL;
13192 }
13193}
13194
13195static ibf_offset_t
13196ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13197{
13198 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13199
13200 if (kw) {
13201 struct rb_iseq_param_keyword dump_kw = *kw;
13202 int dv_num = kw->num - kw->required_num;
13203 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13204 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13205 int i;
13206
13207 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13208 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13209
13210 dump_kw.table = IBF_W(ids, ID, kw->num);
13211 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13212 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13213 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13214 }
13215 else {
13216 return 0;
13217 }
13218}
13219
13220static const struct rb_iseq_param_keyword *
13221ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13222{
13223 if (param_keyword_offset) {
13224 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13225 int dv_num = kw->num - kw->required_num;
13226 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13227
13228 int i;
13229 for (i=0; i<dv_num; i++) {
13230 dvs[i] = ibf_load_object(load, dvs[i]);
13231 }
13232
13233 // Will be set once the local table is loaded.
13234 kw->table = NULL;
13235
13236 kw->default_values = dvs;
13237 return kw;
13238 }
13239 else {
13240 return NULL;
13241 }
13242}
13243
13244static ibf_offset_t
13245ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13246{
13247 ibf_offset_t offset = ibf_dump_pos(dump);
13248 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13249
13250 unsigned int i;
13251 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13252 ibf_dump_write_small_value(dump, entries[i].line_no);
13253#ifdef USE_ISEQ_NODE_ID
13254 ibf_dump_write_small_value(dump, entries[i].node_id);
13255#endif
13256 ibf_dump_write_small_value(dump, entries[i].events);
13257 }
13258
13259 return offset;
13260}
13261
13262static struct iseq_insn_info_entry *
13263ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13264{
13265 ibf_offset_t reading_pos = body_offset;
13266 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13267
13268 unsigned int i;
13269 for (i = 0; i < size; i++) {
13270 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13271#ifdef USE_ISEQ_NODE_ID
13272 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13273#endif
13274 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13275 }
13276
13277 return entries;
13278}
13279
13280static ibf_offset_t
13281ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13282{
13283 ibf_offset_t offset = ibf_dump_pos(dump);
13284
13285 unsigned int last = 0;
13286 unsigned int i;
13287 for (i = 0; i < size; i++) {
13288 ibf_dump_write_small_value(dump, positions[i] - last);
13289 last = positions[i];
13290 }
13291
13292 return offset;
13293}
13294
13295static unsigned int *
13296ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13297{
13298 ibf_offset_t reading_pos = positions_offset;
13299 unsigned int *positions = ALLOC_N(unsigned int, size);
13300
13301 unsigned int last = 0;
13302 unsigned int i;
13303 for (i = 0; i < size; i++) {
13304 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13305 last = positions[i];
13306 }
13307
13308 return positions;
13309}
13310
13311static ibf_offset_t
13312ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13313{
13314 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13315 const int size = body->local_table_size;
13316 ID *table = ALLOCA_N(ID, size);
13317 int i;
13318
13319 for (i=0; i<size; i++) {
13320 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13321 if (v == 0) {
13322 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13323 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13324 }
13325 table[i] = v;
13326 }
13327
13328 IBF_W_ALIGN(ID);
13329 return ibf_dump_write(dump, table, sizeof(ID) * size);
13330}
13331
13332static const ID *
13333ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13334{
13335 if (size > 0) {
13336 ID *table = IBF_R(local_table_offset, ID, size);
13337 int i;
13338
13339 for (i=0; i<size; i++) {
13340 table[i] = ibf_load_id(load, table[i]);
13341 }
13342
13343 if (size == 1 && table[0] == idERROR_INFO) {
13344 ruby_sized_xfree(table, sizeof(ID) * size);
13345 return rb_iseq_shared_exc_local_tbl;
13346 }
13347 else {
13348 return table;
13349 }
13350 }
13351 else {
13352 return NULL;
13353 }
13354}
13355
13356static ibf_offset_t
13357ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13358{
13359 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13360 const int size = body->local_table_size;
13361 IBF_W_ALIGN(enum lvar_state);
13362 return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
13363}
13364
13365static enum lvar_state *
13366ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13367{
13368 if (local_table == rb_iseq_shared_exc_local_tbl ||
13369 size <= 0) {
13370 return NULL;
13371 }
13372 else {
13373 enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
13374 return states;
13375 }
13376}
13377
13378static ibf_offset_t
13379ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13380{
13381 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13382
13383 if (table) {
13384 int *iseq_indices = ALLOCA_N(int, table->size);
13385 unsigned int i;
13386
13387 for (i=0; i<table->size; i++) {
13388 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13389 }
13390
13391 const ibf_offset_t offset = ibf_dump_pos(dump);
13392
13393 for (i=0; i<table->size; i++) {
13394 ibf_dump_write_small_value(dump, iseq_indices[i]);
13395 ibf_dump_write_small_value(dump, table->entries[i].type);
13396 ibf_dump_write_small_value(dump, table->entries[i].start);
13397 ibf_dump_write_small_value(dump, table->entries[i].end);
13398 ibf_dump_write_small_value(dump, table->entries[i].cont);
13399 ibf_dump_write_small_value(dump, table->entries[i].sp);
13400 }
13401 return offset;
13402 }
13403 else {
13404 return ibf_dump_pos(dump);
13405 }
13406}
13407
13408static void
13409ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13410{
13411 if (size) {
13412 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13413 table->size = size;
13414 ISEQ_BODY(parent_iseq)->catch_table = table;
13415
13416 ibf_offset_t reading_pos = catch_table_offset;
13417
13418 unsigned int i;
13419 for (i=0; i<table->size; i++) {
13420 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13421 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13422 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13423 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13424 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13425 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13426
13427 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13428 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13429 }
13430 }
13431 else {
13432 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13433 }
13434}
13435
13436static ibf_offset_t
13437ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13438{
13439 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13440 const unsigned int ci_size = body->ci_size;
13441 const struct rb_call_data *cds = body->call_data;
13442
13443 ibf_offset_t offset = ibf_dump_pos(dump);
13444
13445 unsigned int i;
13446
13447 for (i = 0; i < ci_size; i++) {
13448 const struct rb_callinfo *ci = cds[i].ci;
13449 if (ci != NULL) {
13450 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13451 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13452 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13453
13454 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13455 if (kwarg) {
13456 int len = kwarg->keyword_len;
13457 ibf_dump_write_small_value(dump, len);
13458 for (int j=0; j<len; j++) {
13459 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13460 ibf_dump_write_small_value(dump, keyword);
13461 }
13462 }
13463 else {
13464 ibf_dump_write_small_value(dump, 0);
13465 }
13466 }
13467 else {
13468 // TODO: truncate NULL ci from call_data.
13469 ibf_dump_write_small_value(dump, (VALUE)-1);
13470 }
13471 }
13472
13473 return offset;
13474}
13475
13477 ID id;
13478 VALUE name;
13479 VALUE val;
13480};
13481
13483 size_t num;
13484 struct outer_variable_pair pairs[1];
13485};
13486
13487static enum rb_id_table_iterator_result
13488store_outer_variable(ID id, VALUE val, void *dump)
13489{
13490 struct outer_variable_list *ovlist = dump;
13491 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13492 pair->id = id;
13493 pair->name = rb_id2str(id);
13494 pair->val = val;
13495 return ID_TABLE_CONTINUE;
13496}
13497
13498static int
13499outer_variable_cmp(const void *a, const void *b, void *arg)
13500{
13501 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13502 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13503
13504 if (!ap->name) {
13505 return -1;
13506 }
13507 else if (!bp->name) {
13508 return 1;
13509 }
13510
13511 return rb_str_cmp(ap->name, bp->name);
13512}
13513
13514static ibf_offset_t
13515ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13516{
13517 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13518
13519 ibf_offset_t offset = ibf_dump_pos(dump);
13520
13521 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13522 ibf_dump_write_small_value(dump, (VALUE)size);
13523 if (size > 0) {
13524 VALUE buff;
13525 size_t buffsize =
13526 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13527 offsetof(struct outer_variable_list, pairs),
13528 rb_eArgError);
13529 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13530 ovlist->num = 0;
13531 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13532 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13533 for (size_t i = 0; i < size; ++i) {
13534 ID id = ovlist->pairs[i].id;
13535 ID val = ovlist->pairs[i].val;
13536 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13537 ibf_dump_write_small_value(dump, val);
13538 }
13539 }
13540
13541 return offset;
13542}
13543
13544/* note that we dump out rb_call_info but load back rb_call_data */
13545static void
13546ibf_load_ci_entries(const struct ibf_load *load,
13547 ibf_offset_t ci_entries_offset,
13548 unsigned int ci_size,
13549 struct rb_call_data **cd_ptr)
13550{
13551 if (!ci_size) {
13552 *cd_ptr = NULL;
13553 return;
13554 }
13555
13556 ibf_offset_t reading_pos = ci_entries_offset;
13557
13558 unsigned int i;
13559
13560 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13561 *cd_ptr = cds;
13562
13563 for (i = 0; i < ci_size; i++) {
13564 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13565 if (mid_index != (VALUE)-1) {
13566 ID mid = ibf_load_id(load, mid_index);
13567 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13568 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13569
13570 struct rb_callinfo_kwarg *kwarg = NULL;
13571 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13572 if (kwlen > 0) {
13573 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13574 kwarg->references = 0;
13575 kwarg->keyword_len = kwlen;
13576 for (int j=0; j<kwlen; j++) {
13577 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13578 kwarg->keywords[j] = ibf_load_object(load, keyword);
13579 }
13580 }
13581
13582 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13583 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13584 cds[i].cc = vm_cc_empty();
13585 }
13586 else {
13587 // NULL ci
13588 cds[i].ci = NULL;
13589 cds[i].cc = NULL;
13590 }
13591 }
13592}
13593
13594static struct rb_id_table *
13595ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13596{
13597 ibf_offset_t reading_pos = outer_variables_offset;
13598
13599 struct rb_id_table *tbl = NULL;
13600
13601 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13602
13603 if (table_size > 0) {
13604 tbl = rb_id_table_create(table_size);
13605 }
13606
13607 for (size_t i = 0; i < table_size; i++) {
13608 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13609 VALUE value = ibf_load_small_value(load, &reading_pos);
13610 if (!key) key = rb_make_temporary_id(i);
13611 rb_id_table_insert(tbl, key, value);
13612 }
13613
13614 return tbl;
13615}
13616
13617static ibf_offset_t
13618ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13619{
13620 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13621
13622 unsigned int *positions;
13623
13624 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13625
13626 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13627 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13628 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13629
13630#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13631 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13632
13633 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13634 struct ibf_dump_buffer buffer;
13635 buffer.str = rb_str_new(0, 0);
13636 buffer.obj_table = ibf_dump_object_table_new();
13637 dump->current_buffer = &buffer;
13638#endif
13639
13640 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13641 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13642 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13643 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13644 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13645
13646 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13647 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13648 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13649
13650 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13651 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13652 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13653 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13654 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13655 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13656 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13657 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13658 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13659
13660#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13661 ibf_offset_t local_obj_list_offset;
13662 unsigned int local_obj_list_size;
13663
13664 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13665#endif
13666
13667 ibf_offset_t body_offset = ibf_dump_pos(dump);
13668
13669 /* dump the constant body */
13670 unsigned int param_flags =
13671 (body->param.flags.has_lead << 0) |
13672 (body->param.flags.has_opt << 1) |
13673 (body->param.flags.has_rest << 2) |
13674 (body->param.flags.has_post << 3) |
13675 (body->param.flags.has_kw << 4) |
13676 (body->param.flags.has_kwrest << 5) |
13677 (body->param.flags.has_block << 6) |
13678 (body->param.flags.ambiguous_param0 << 7) |
13679 (body->param.flags.accepts_no_kwarg << 8) |
13680 (body->param.flags.ruby2_keywords << 9) |
13681 (body->param.flags.anon_rest << 10) |
13682 (body->param.flags.anon_kwrest << 11) |
13683 (body->param.flags.use_block << 12) |
13684 (body->param.flags.forwardable << 13) |
13685 (body->param.flags.accepts_no_block << 14);
13686
13687#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13688# define IBF_BODY_OFFSET(x) (x)
13689#else
13690# define IBF_BODY_OFFSET(x) (body_offset - (x))
13691#endif
13692
13693 ibf_dump_write_small_value(dump, body->type);
13694 ibf_dump_write_small_value(dump, body->iseq_size);
13695 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13696 ibf_dump_write_small_value(dump, bytecode_size);
13697 ibf_dump_write_small_value(dump, param_flags);
13698 ibf_dump_write_small_value(dump, body->param.size);
13699 ibf_dump_write_small_value(dump, body->param.lead_num);
13700 ibf_dump_write_small_value(dump, body->param.opt_num);
13701 ibf_dump_write_small_value(dump, body->param.rest_start);
13702 ibf_dump_write_small_value(dump, body->param.post_start);
13703 ibf_dump_write_small_value(dump, body->param.post_num);
13704 ibf_dump_write_small_value(dump, body->param.block_start);
13705 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13706 ibf_dump_write_small_value(dump, param_keyword_offset);
13707 ibf_dump_write_small_value(dump, location_pathobj_index);
13708 ibf_dump_write_small_value(dump, location_base_label_index);
13709 ibf_dump_write_small_value(dump, location_label_index);
13710 ibf_dump_write_small_value(dump, body->location.first_lineno);
13711 ibf_dump_write_small_value(dump, body->location.node_id);
13712 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13713 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13714 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13715 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13716 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13717 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13718 ibf_dump_write_small_value(dump, body->insns_info.size);
13719 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13720 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13721 ibf_dump_write_small_value(dump, catch_table_size);
13722 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13723 ibf_dump_write_small_value(dump, parent_iseq_index);
13724 ibf_dump_write_small_value(dump, local_iseq_index);
13725 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13726 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13727 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13728 ibf_dump_write_small_value(dump, body->variable.flip_count);
13729 ibf_dump_write_small_value(dump, body->local_table_size);
13730 ibf_dump_write_small_value(dump, body->ivc_size);
13731 ibf_dump_write_small_value(dump, body->icvarc_size);
13732 ibf_dump_write_small_value(dump, body->ise_size);
13733 ibf_dump_write_small_value(dump, body->ic_size);
13734 ibf_dump_write_small_value(dump, body->ci_size);
13735 ibf_dump_write_small_value(dump, body->stack_max);
13736 ibf_dump_write_small_value(dump, body->builtin_attrs);
13737 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13738
13739#undef IBF_BODY_OFFSET
13740
13741#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13742 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13743
13744 dump->current_buffer = saved_buffer;
13745 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13746
13747 ibf_offset_t offset = ibf_dump_pos(dump);
13748 ibf_dump_write_small_value(dump, iseq_start);
13749 ibf_dump_write_small_value(dump, iseq_length_bytes);
13750 ibf_dump_write_small_value(dump, body_offset);
13751
13752 ibf_dump_write_small_value(dump, local_obj_list_offset);
13753 ibf_dump_write_small_value(dump, local_obj_list_size);
13754
13755 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13756
13757 return offset;
13758#else
13759 return body_offset;
13760#endif
13761}
13762
13763static VALUE
13764ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13765{
13766 VALUE str = ibf_load_object(load, str_index);
13767 if (str != Qnil) {
13768 str = rb_fstring(str);
13769 }
13770 return str;
13771}
13772
13773static void
13774ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13775{
13776 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13777
13778 ibf_offset_t reading_pos = offset;
13779
13780#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13781 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13782 load->current_buffer = &load->global_buffer;
13783
13784 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13785 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13786 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13787
13788 struct ibf_load_buffer buffer;
13789 buffer.buff = load->global_buffer.buff + iseq_start;
13790 buffer.size = iseq_length_bytes;
13791 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13792 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13793 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13794
13795 load->current_buffer = &buffer;
13796 reading_pos = body_offset;
13797#endif
13798
13799#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13800# define IBF_BODY_OFFSET(x) (x)
13801#else
13802# define IBF_BODY_OFFSET(x) (offset - (x))
13803#endif
13804
13805 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13806 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13807 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13808 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13809 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13810 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13811 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13812 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13813 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13814 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13815 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13816 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13817 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13818 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13819 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13820 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13821 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13822 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13823 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13824 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13825 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13826 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13827 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13828 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13829 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13830 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13831 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13832 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13833 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13834 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13835 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13836 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13837 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13838 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13839 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13840 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13841 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13842
13843 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13844 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13845 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13846 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13847
13848 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13849 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13850 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13851 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13852
13853 // setup fname and dummy frame
13854 VALUE path = ibf_load_object(load, location_pathobj_index);
13855 {
13856 VALUE realpath = Qnil;
13857
13858 if (RB_TYPE_P(path, T_STRING)) {
13859 realpath = path = rb_fstring(path);
13860 }
13861 else if (RB_TYPE_P(path, T_ARRAY)) {
13862 VALUE pathobj = path;
13863 if (RARRAY_LEN(pathobj) != 2) {
13864 rb_raise(rb_eRuntimeError, "path object size mismatch");
13865 }
13866 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13867 realpath = RARRAY_AREF(pathobj, 1);
13868 if (!NIL_P(realpath)) {
13869 if (!RB_TYPE_P(realpath, T_STRING)) {
13870 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13871 "(%x), path=%+"PRIsVALUE,
13872 realpath, TYPE(realpath), path);
13873 }
13874 realpath = rb_fstring(realpath);
13875 }
13876 }
13877 else {
13878 rb_raise(rb_eRuntimeError, "unexpected path object");
13879 }
13880 rb_iseq_pathobj_set(iseq, path, realpath);
13881 }
13882
13883 // push dummy frame
13884 rb_execution_context_t *ec = GET_EC();
13885 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13886
13887#undef IBF_BODY_OFFSET
13888
13889 load_body->type = type;
13890 load_body->stack_max = stack_max;
13891 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13892 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13893 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13894 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13895 load_body->param.flags.has_kw = FALSE;
13896 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13897 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13898 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13899 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13900 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13901 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13902 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13903 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13904 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13905 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
13906 load_body->param.size = param_size;
13907 load_body->param.lead_num = param_lead_num;
13908 load_body->param.opt_num = param_opt_num;
13909 load_body->param.rest_start = param_rest_start;
13910 load_body->param.post_start = param_post_start;
13911 load_body->param.post_num = param_post_num;
13912 load_body->param.block_start = param_block_start;
13913 load_body->local_table_size = local_table_size;
13914 load_body->ci_size = ci_size;
13915 load_body->insns_info.size = insns_info_size;
13916
13917 ISEQ_COVERAGE_SET(iseq, Qnil);
13918 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13919 load_body->variable.flip_count = variable_flip_count;
13920 load_body->variable.script_lines = Qnil;
13921
13922 load_body->location.first_lineno = location_first_lineno;
13923 load_body->location.node_id = location_node_id;
13924 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13925 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13926 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13927 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13928 load_body->builtin_attrs = builtin_attrs;
13929 load_body->prism = prism;
13930
13931 load_body->ivc_size = ivc_size;
13932 load_body->icvarc_size = icvarc_size;
13933 load_body->ise_size = ise_size;
13934 load_body->ic_size = ic_size;
13935
13936 if (ISEQ_IS_SIZE(load_body)) {
13937 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13938 }
13939 else {
13940 load_body->is_entries = NULL;
13941 }
13942 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13943 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13944 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13945 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13946 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13947 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13948 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13949 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13950 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13951 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13952
13953 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13954 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13955 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13956
13957 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13958 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13959 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13960
13961 // This must be done after the local table is loaded.
13962 if (load_body->param.keyword != NULL) {
13963 RUBY_ASSERT(load_body->local_table);
13964 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13965 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13966 }
13967
13968 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13969#if VM_INSN_INFO_TABLE_IMPL == 2
13970 rb_iseq_insns_info_encode_positions(iseq);
13971#endif
13972
13973 rb_iseq_translate_threaded_code(iseq);
13974
13975#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13976 load->current_buffer = &load->global_buffer;
13977#endif
13978
13979 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13980 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13981
13982#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13983 load->current_buffer = saved_buffer;
13984#endif
13985 verify_call_cache(iseq);
13986
13987 RB_GC_GUARD(dummy_frame);
13988 rb_vm_pop_frame_no_int(ec);
13989}
13990
13992{
13993 struct ibf_dump *dump;
13994 VALUE offset_list;
13995};
13996
13997static int
13998ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13999{
14000 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14001 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14002
14003 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14004 rb_ary_push(args->offset_list, UINT2NUM(offset));
14005
14006 return ST_CONTINUE;
14007}
14008
14009static void
14010ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14011{
14012 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14013
14014 struct ibf_dump_iseq_list_arg args;
14015 args.dump = dump;
14016 args.offset_list = offset_list;
14017
14018 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14019
14020 st_index_t i;
14021 st_index_t size = dump->iseq_table->num_entries;
14022 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14023
14024 for (i = 0; i < size; i++) {
14025 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14026 }
14027
14028 ibf_dump_align(dump, sizeof(ibf_offset_t));
14029 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14030 header->iseq_list_size = (unsigned int)size;
14031}
14032
14033/*
14034 * Binary format
14035 * - ibf_object_header
14036 * - ibf_object_xxx (xxx is type)
14037 */
14038
14040 unsigned int type: 5;
14041 unsigned int special_const: 1;
14042 unsigned int frozen: 1;
14043 unsigned int internal: 1;
14044};
14045
14046enum ibf_object_class_index {
14047 IBF_OBJECT_CLASS_OBJECT,
14048 IBF_OBJECT_CLASS_ARRAY,
14049 IBF_OBJECT_CLASS_STANDARD_ERROR,
14050 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14051 IBF_OBJECT_CLASS_TYPE_ERROR,
14052 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14053};
14054
14056 long srcstr;
14057 char option;
14058};
14059
14061 long len;
14062 long keyval[FLEX_ARY_LEN];
14063};
14064
14066 long class_index;
14067 long len;
14068 long beg;
14069 long end;
14070 int excl;
14071};
14072
14074 ssize_t slen;
14075 BDIGIT digits[FLEX_ARY_LEN];
14076};
14077
14078enum ibf_object_data_type {
14079 IBF_OBJECT_DATA_ENCODING,
14080};
14081
14083 long a, b;
14084};
14085
14087 long str;
14088};
14089
14090#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14091 ((((offset) - 1) / (align) + 1) * (align))
14092/* No cast, since it's UB to create an unaligned pointer.
14093 * Leave as void* for use with memcpy in those cases.
14094 * We align the offset, but the buffer pointer is only VALUE aligned,
14095 * so the returned pointer may be unaligned for `type` .*/
14096#define IBF_OBJBODY(type, offset) \
14097 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14098
14099static const void *
14100ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14101{
14102 if (offset >= load->current_buffer->size) {
14103 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14104 }
14105 return load->current_buffer->buff + offset;
14106}
14107
14108NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14109
14110static void
14111ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14112{
14113 char buff[0x100];
14114 rb_raw_obj_info(buff, sizeof(buff), obj);
14115 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14116}
14117
14118NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14119
14120static VALUE
14121ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14122{
14123 rb_raise(rb_eArgError, "unsupported");
14125}
14126
14127static void
14128ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14129{
14130 enum ibf_object_class_index cindex;
14131 if (obj == rb_cObject) {
14132 cindex = IBF_OBJECT_CLASS_OBJECT;
14133 }
14134 else if (obj == rb_cArray) {
14135 cindex = IBF_OBJECT_CLASS_ARRAY;
14136 }
14137 else if (obj == rb_eStandardError) {
14138 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14139 }
14140 else if (obj == rb_eNoMatchingPatternError) {
14141 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14142 }
14143 else if (obj == rb_eTypeError) {
14144 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14145 }
14146 else if (obj == rb_eNoMatchingPatternKeyError) {
14147 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14148 }
14149 else {
14150 rb_obj_info_dump(obj);
14151 rb_p(obj);
14152 rb_bug("unsupported class");
14153 }
14154 ibf_dump_write_small_value(dump, (VALUE)cindex);
14155}
14156
14157static VALUE
14158ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14159{
14160 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14161
14162 switch (cindex) {
14163 case IBF_OBJECT_CLASS_OBJECT:
14164 return rb_cObject;
14165 case IBF_OBJECT_CLASS_ARRAY:
14166 return rb_cArray;
14167 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14168 return rb_eStandardError;
14169 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14171 case IBF_OBJECT_CLASS_TYPE_ERROR:
14172 return rb_eTypeError;
14173 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14175 }
14176
14177 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14178}
14179
14180
14181static void
14182ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14183{
14184 double dbl = RFLOAT_VALUE(obj);
14185 (void)IBF_W(&dbl, double, 1);
14186}
14187
14188static VALUE
14189ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14190{
14191 double d;
14192 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14193 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14194 VALUE f = DBL2NUM(d);
14195 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14196 return f;
14197}
14198
14199static void
14200ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14201{
14202 long encindex = (long)rb_enc_get_index(obj);
14203 long len = RSTRING_LEN(obj);
14204 const char *ptr = RSTRING_PTR(obj);
14205
14206 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14207 rb_encoding *enc = rb_enc_from_index((int)encindex);
14208 const char *enc_name = rb_enc_name(enc);
14209 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14210 }
14211
14212 ibf_dump_write_small_value(dump, encindex);
14213 ibf_dump_write_small_value(dump, len);
14214 IBF_WP(ptr, char, len);
14215}
14216
14217static VALUE
14218ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14219{
14220 ibf_offset_t reading_pos = offset;
14221
14222 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14223 const long len = (long)ibf_load_small_value(load, &reading_pos);
14224 const char *ptr = load->current_buffer->buff + reading_pos;
14225
14226 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14227 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14228 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14229 }
14230
14231 VALUE str;
14232 if (header->frozen && !header->internal) {
14233 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14234 }
14235 else {
14236 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14237
14238 if (header->internal) rb_obj_hide(str);
14239 if (header->frozen) str = rb_fstring(str);
14240 }
14241 return str;
14242}
14243
14244static void
14245ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14246{
14247 VALUE srcstr = RREGEXP_SRC(obj);
14248 struct ibf_object_regexp regexp;
14249 regexp.option = (char)rb_reg_options(obj);
14250 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14251
14252 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14253 ibf_dump_write_small_value(dump, regexp.srcstr);
14254}
14255
14256static VALUE
14257ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14258{
14259 struct ibf_object_regexp regexp;
14260 regexp.option = ibf_load_byte(load, &offset);
14261 regexp.srcstr = ibf_load_small_value(load, &offset);
14262
14263 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14264 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14265
14266 if (header->internal) rb_obj_hide(reg);
14267 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14268
14269 return reg;
14270}
14271
14272static void
14273ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14274{
14275 long i, len = RARRAY_LEN(obj);
14276 ibf_dump_write_small_value(dump, len);
14277 for (i=0; i<len; i++) {
14278 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14279 ibf_dump_write_small_value(dump, index);
14280 }
14281}
14282
14283static VALUE
14284ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14285{
14286 ibf_offset_t reading_pos = offset;
14287
14288 const long len = (long)ibf_load_small_value(load, &reading_pos);
14289
14290 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14291 int i;
14292
14293 for (i=0; i<len; i++) {
14294 const VALUE index = ibf_load_small_value(load, &reading_pos);
14295 rb_ary_push(ary, ibf_load_object(load, index));
14296 }
14297
14298 if (header->frozen) {
14299 rb_ary_freeze(ary);
14300 rb_ractor_make_shareable(ary); // TODO: check elements
14301 }
14302
14303 return ary;
14304}
14305
14306static int
14307ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14308{
14309 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14310
14311 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14312 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14313
14314 ibf_dump_write_small_value(dump, key_index);
14315 ibf_dump_write_small_value(dump, val_index);
14316 return ST_CONTINUE;
14317}
14318
14319static void
14320ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14321{
14322 long len = RHASH_SIZE(obj);
14323 ibf_dump_write_small_value(dump, (VALUE)len);
14324
14325 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14326}
14327
14328static VALUE
14329ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14330{
14331 long len = (long)ibf_load_small_value(load, &offset);
14332 VALUE obj = rb_hash_new_with_size(len);
14333 int i;
14334
14335 for (i = 0; i < len; i++) {
14336 VALUE key_index = ibf_load_small_value(load, &offset);
14337 VALUE val_index = ibf_load_small_value(load, &offset);
14338
14339 VALUE key = ibf_load_object(load, key_index);
14340 VALUE val = ibf_load_object(load, val_index);
14341 rb_hash_aset(obj, key, val);
14342 }
14343 rb_hash_rehash(obj);
14344
14345 if (header->internal) rb_obj_hide(obj);
14346 if (header->frozen) {
14347 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14348 }
14349
14350 return obj;
14351}
14352
14353static void
14354ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14355{
14356 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14357 struct ibf_object_struct_range range;
14358 VALUE beg, end;
14359 IBF_ZERO(range);
14360 range.len = 3;
14361 range.class_index = 0;
14362
14363 rb_range_values(obj, &beg, &end, &range.excl);
14364 range.beg = (long)ibf_dump_object(dump, beg);
14365 range.end = (long)ibf_dump_object(dump, end);
14366
14367 IBF_W_ALIGN(struct ibf_object_struct_range);
14368 IBF_WV(range);
14369 }
14370 else {
14371 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14372 rb_class_name(CLASS_OF(obj)));
14373 }
14374}
14375
14376static VALUE
14377ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14378{
14379 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14380 VALUE beg = ibf_load_object(load, range->beg);
14381 VALUE end = ibf_load_object(load, range->end);
14382 VALUE obj = rb_range_new(beg, end, range->excl);
14383 if (header->internal) rb_obj_hide(obj);
14384 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14385 return obj;
14386}
14387
14388static void
14389ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14390{
14391 ssize_t len = BIGNUM_LEN(obj);
14392 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14393 BDIGIT *d = BIGNUM_DIGITS(obj);
14394
14395 (void)IBF_W(&slen, ssize_t, 1);
14396 IBF_WP(d, BDIGIT, len);
14397}
14398
14399static VALUE
14400ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14401{
14402 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14403 int sign = bignum->slen > 0;
14404 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14405 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14408 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14409 big_unpack_flags |
14410 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14411 if (header->internal) rb_obj_hide(obj);
14412 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14413 return obj;
14414}
14415
14416static void
14417ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14418{
14419 if (rb_data_is_encoding(obj)) {
14420 rb_encoding *enc = rb_to_encoding(obj);
14421 const char *name = rb_enc_name(enc);
14422 long len = strlen(name) + 1;
14423 long data[2];
14424 data[0] = IBF_OBJECT_DATA_ENCODING;
14425 data[1] = len;
14426 (void)IBF_W(data, long, 2);
14427 IBF_WP(name, char, len);
14428 }
14429 else {
14430 ibf_dump_object_unsupported(dump, obj);
14431 }
14432}
14433
14434static VALUE
14435ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14436{
14437 const long *body = IBF_OBJBODY(long, offset);
14438 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14439 /* const long len = body[1]; */
14440 const char *data = (const char *)&body[2];
14441
14442 switch (type) {
14443 case IBF_OBJECT_DATA_ENCODING:
14444 {
14445 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14446 return encobj;
14447 }
14448 }
14449
14450 return ibf_load_object_unsupported(load, header, offset);
14451}
14452
14453static void
14454ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14455{
14456 long data[2];
14457 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14458 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14459
14460 (void)IBF_W(data, long, 2);
14461}
14462
14463static VALUE
14464ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14465{
14466 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14467 VALUE a = ibf_load_object(load, nums->a);
14468 VALUE b = ibf_load_object(load, nums->b);
14469 VALUE obj = header->type == T_COMPLEX ?
14470 rb_complex_new(a, b) : rb_rational_new(a, b);
14471
14472 if (header->internal) rb_obj_hide(obj);
14473 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14474 return obj;
14475}
14476
14477static void
14478ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14479{
14480 ibf_dump_object_string(dump, rb_sym2str(obj));
14481}
14482
14483static VALUE
14484ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14485{
14486 ibf_offset_t reading_pos = offset;
14487
14488 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14489 const long len = (long)ibf_load_small_value(load, &reading_pos);
14490 const char *ptr = load->current_buffer->buff + reading_pos;
14491
14492 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14493 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14494 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14495 }
14496
14497 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14498 return ID2SYM(id);
14499}
14500
14501typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14502static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14503 ibf_dump_object_unsupported, /* T_NONE */
14504 ibf_dump_object_unsupported, /* T_OBJECT */
14505 ibf_dump_object_class, /* T_CLASS */
14506 ibf_dump_object_unsupported, /* T_MODULE */
14507 ibf_dump_object_float, /* T_FLOAT */
14508 ibf_dump_object_string, /* T_STRING */
14509 ibf_dump_object_regexp, /* T_REGEXP */
14510 ibf_dump_object_array, /* T_ARRAY */
14511 ibf_dump_object_hash, /* T_HASH */
14512 ibf_dump_object_struct, /* T_STRUCT */
14513 ibf_dump_object_bignum, /* T_BIGNUM */
14514 ibf_dump_object_unsupported, /* T_FILE */
14515 ibf_dump_object_data, /* T_DATA */
14516 ibf_dump_object_unsupported, /* T_MATCH */
14517 ibf_dump_object_complex_rational, /* T_COMPLEX */
14518 ibf_dump_object_complex_rational, /* T_RATIONAL */
14519 ibf_dump_object_unsupported, /* 0x10 */
14520 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14521 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14522 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14523 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14524 ibf_dump_object_unsupported, /* T_FIXNUM */
14525 ibf_dump_object_unsupported, /* T_UNDEF */
14526 ibf_dump_object_unsupported, /* 0x17 */
14527 ibf_dump_object_unsupported, /* 0x18 */
14528 ibf_dump_object_unsupported, /* 0x19 */
14529 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14530 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14531 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14532 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14533 ibf_dump_object_unsupported, /* 0x1e */
14534 ibf_dump_object_unsupported, /* 0x1f */
14535};
14536
14537static void
14538ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14539{
14540 unsigned char byte =
14541 (header.type << 0) |
14542 (header.special_const << 5) |
14543 (header.frozen << 6) |
14544 (header.internal << 7);
14545
14546 IBF_WV(byte);
14547}
14548
14549static struct ibf_object_header
14550ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14551{
14552 unsigned char byte = ibf_load_byte(load, offset);
14553
14554 struct ibf_object_header header;
14555 header.type = (byte >> 0) & 0x1f;
14556 header.special_const = (byte >> 5) & 0x01;
14557 header.frozen = (byte >> 6) & 0x01;
14558 header.internal = (byte >> 7) & 0x01;
14559
14560 return header;
14561}
14562
14563static ibf_offset_t
14564ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14565{
14566 struct ibf_object_header obj_header;
14567 ibf_offset_t current_offset;
14568 IBF_ZERO(obj_header);
14569 obj_header.type = TYPE(obj);
14570
14571 IBF_W_ALIGN(ibf_offset_t);
14572 current_offset = ibf_dump_pos(dump);
14573
14574 if (SPECIAL_CONST_P(obj) &&
14575 ! (SYMBOL_P(obj) ||
14576 RB_FLOAT_TYPE_P(obj))) {
14577 obj_header.special_const = TRUE;
14578 obj_header.frozen = TRUE;
14579 obj_header.internal = TRUE;
14580 ibf_dump_object_object_header(dump, obj_header);
14581 ibf_dump_write_small_value(dump, obj);
14582 }
14583 else {
14584 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14585 obj_header.special_const = FALSE;
14586 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14587 ibf_dump_object_object_header(dump, obj_header);
14588 (*dump_object_functions[obj_header.type])(dump, obj);
14589 }
14590
14591 return current_offset;
14592}
14593
14594typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14595static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14596 ibf_load_object_unsupported, /* T_NONE */
14597 ibf_load_object_unsupported, /* T_OBJECT */
14598 ibf_load_object_class, /* T_CLASS */
14599 ibf_load_object_unsupported, /* T_MODULE */
14600 ibf_load_object_float, /* T_FLOAT */
14601 ibf_load_object_string, /* T_STRING */
14602 ibf_load_object_regexp, /* T_REGEXP */
14603 ibf_load_object_array, /* T_ARRAY */
14604 ibf_load_object_hash, /* T_HASH */
14605 ibf_load_object_struct, /* T_STRUCT */
14606 ibf_load_object_bignum, /* T_BIGNUM */
14607 ibf_load_object_unsupported, /* T_FILE */
14608 ibf_load_object_data, /* T_DATA */
14609 ibf_load_object_unsupported, /* T_MATCH */
14610 ibf_load_object_complex_rational, /* T_COMPLEX */
14611 ibf_load_object_complex_rational, /* T_RATIONAL */
14612 ibf_load_object_unsupported, /* 0x10 */
14613 ibf_load_object_unsupported, /* T_NIL */
14614 ibf_load_object_unsupported, /* T_TRUE */
14615 ibf_load_object_unsupported, /* T_FALSE */
14616 ibf_load_object_symbol,
14617 ibf_load_object_unsupported, /* T_FIXNUM */
14618 ibf_load_object_unsupported, /* T_UNDEF */
14619 ibf_load_object_unsupported, /* 0x17 */
14620 ibf_load_object_unsupported, /* 0x18 */
14621 ibf_load_object_unsupported, /* 0x19 */
14622 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14623 ibf_load_object_unsupported, /* T_NODE 0x1b */
14624 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14625 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14626 ibf_load_object_unsupported, /* 0x1e */
14627 ibf_load_object_unsupported, /* 0x1f */
14628};
14629
14630static VALUE
14631ibf_load_object(const struct ibf_load *load, VALUE object_index)
14632{
14633 if (object_index == 0) {
14634 return Qnil;
14635 }
14636 else {
14637 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14638 if (!obj) {
14639 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14640 ibf_offset_t offset = offsets[object_index];
14641 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14642
14643#if IBF_ISEQ_DEBUG
14644 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14645 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14646 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14647 header.type, header.special_const, header.frozen, header.internal);
14648#endif
14649 if (offset >= load->current_buffer->size) {
14650 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14651 }
14652
14653 if (header.special_const) {
14654 ibf_offset_t reading_pos = offset;
14655
14656 obj = ibf_load_small_value(load, &reading_pos);
14657 }
14658 else {
14659 obj = (*load_object_functions[header.type])(load, &header, offset);
14660 }
14661
14662 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14663 }
14664#if IBF_ISEQ_DEBUG
14665 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14666 object_index, obj);
14667#endif
14668 return obj;
14669 }
14670}
14671
14673{
14674 struct ibf_dump *dump;
14675 VALUE offset_list;
14676};
14677
14678static int
14679ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14680{
14681 VALUE obj = (VALUE)key;
14682 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14683
14684 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14685 rb_ary_push(args->offset_list, UINT2NUM(offset));
14686
14687 return ST_CONTINUE;
14688}
14689
14690static void
14691ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14692{
14693 st_table *obj_table = dump->current_buffer->obj_table;
14694 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14695
14696 struct ibf_dump_object_list_arg args;
14697 args.dump = dump;
14698 args.offset_list = offset_list;
14699
14700 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14701
14702 IBF_W_ALIGN(ibf_offset_t);
14703 *obj_list_offset = ibf_dump_pos(dump);
14704
14705 st_index_t size = obj_table->num_entries;
14706 st_index_t i;
14707
14708 for (i=0; i<size; i++) {
14709 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14710 IBF_WV(offset);
14711 }
14712
14713 *obj_list_size = (unsigned int)size;
14714}
14715
14716static void
14717ibf_dump_mark(void *ptr)
14718{
14719 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14720 rb_gc_mark(dump->global_buffer.str);
14721
14722 rb_mark_set(dump->global_buffer.obj_table);
14723 rb_mark_set(dump->iseq_table);
14724}
14725
14726static void
14727ibf_dump_free(void *ptr)
14728{
14729 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14730 if (dump->global_buffer.obj_table) {
14731 st_free_table(dump->global_buffer.obj_table);
14732 dump->global_buffer.obj_table = 0;
14733 }
14734 if (dump->iseq_table) {
14735 st_free_table(dump->iseq_table);
14736 dump->iseq_table = 0;
14737 }
14738}
14739
14740static size_t
14741ibf_dump_memsize(const void *ptr)
14742{
14743 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14744 size_t size = 0;
14745 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14746 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14747 return size;
14748}
14749
14750static const rb_data_type_t ibf_dump_type = {
14751 "ibf_dump",
14752 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14753 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14754};
14755
14756static void
14757ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14758{
14759 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14760 dump->iseq_table = NULL;
14761
14762 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14763 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14764 dump->iseq_table = st_init_numtable(); /* need free */
14765
14766 dump->current_buffer = &dump->global_buffer;
14767}
14768
14769VALUE
14770rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14771{
14772 struct ibf_dump *dump;
14773 struct ibf_header header = {{0}};
14774 VALUE dump_obj;
14775 VALUE str;
14776
14777 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14778 ISEQ_BODY(iseq)->local_iseq != iseq) {
14779 rb_raise(rb_eRuntimeError, "should be top of iseq");
14780 }
14781 if (RTEST(ISEQ_COVERAGE(iseq))) {
14782 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14783 }
14784
14785 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14786 ibf_dump_setup(dump, dump_obj);
14787
14788 ibf_dump_write(dump, &header, sizeof(header));
14789 ibf_dump_iseq(dump, iseq);
14790
14791 header.magic[0] = 'Y'; /* YARB */
14792 header.magic[1] = 'A';
14793 header.magic[2] = 'R';
14794 header.magic[3] = 'B';
14795 header.major_version = IBF_MAJOR_VERSION;
14796 header.minor_version = IBF_MINOR_VERSION;
14797 header.endian = IBF_ENDIAN_MARK;
14798 header.wordsize = (uint8_t)SIZEOF_VALUE;
14799 ibf_dump_iseq_list(dump, &header);
14800 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14801 header.size = ibf_dump_pos(dump);
14802
14803 if (RTEST(opt)) {
14804 VALUE opt_str = opt;
14805 const char *ptr = StringValuePtr(opt_str);
14806 header.extra_size = RSTRING_LENINT(opt_str);
14807 ibf_dump_write(dump, ptr, header.extra_size);
14808 }
14809 else {
14810 header.extra_size = 0;
14811 }
14812
14813 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14814
14815 str = dump->global_buffer.str;
14816 RB_GC_GUARD(dump_obj);
14817 return str;
14818}
14819
14820static const ibf_offset_t *
14821ibf_iseq_list(const struct ibf_load *load)
14822{
14823 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14824}
14825
14826void
14827rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14828{
14829 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14830 rb_iseq_t *prev_src_iseq = load->iseq;
14831 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14832 load->iseq = iseq;
14833#if IBF_ISEQ_DEBUG
14834 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14835 iseq->aux.loader.index, offset,
14836 load->header->size);
14837#endif
14838 ibf_load_iseq_each(load, iseq, offset);
14839 ISEQ_COMPILE_DATA_CLEAR(iseq);
14840 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14841 rb_iseq_init_trace(iseq);
14842 load->iseq = prev_src_iseq;
14843}
14844
14845#if USE_LAZY_LOAD
14846const rb_iseq_t *
14847rb_iseq_complete(const rb_iseq_t *iseq)
14848{
14849 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14850 return iseq;
14851}
14852#endif
14853
14854static rb_iseq_t *
14855ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14856{
14857 int iseq_index = (int)(VALUE)index_iseq;
14858
14859#if IBF_ISEQ_DEBUG
14860 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14861 (void *)index_iseq, (void *)load->iseq_list);
14862#endif
14863 if (iseq_index == -1) {
14864 return NULL;
14865 }
14866 else {
14867 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14868
14869#if IBF_ISEQ_DEBUG
14870 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14871#endif
14872 if (iseqv) {
14873 return (rb_iseq_t *)iseqv;
14874 }
14875 else {
14876 rb_iseq_t *iseq = iseq_imemo_alloc();
14877#if IBF_ISEQ_DEBUG
14878 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14879#endif
14880 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14881 iseq->aux.loader.obj = load->loader_obj;
14882 iseq->aux.loader.index = iseq_index;
14883#if IBF_ISEQ_DEBUG
14884 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14885 (void *)iseq, (void *)load->loader_obj, iseq_index);
14886#endif
14887 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14888
14889 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14890#if IBF_ISEQ_DEBUG
14891 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14892#endif
14893 rb_ibf_load_iseq_complete(iseq);
14894 }
14895
14896#if IBF_ISEQ_DEBUG
14897 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14898 (void *)iseq, (void *)load->iseq);
14899#endif
14900 return iseq;
14901 }
14902 }
14903}
14904
14905static void
14906ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14907{
14908 struct ibf_header *header = (struct ibf_header *)bytes;
14909 load->loader_obj = loader_obj;
14910 load->global_buffer.buff = bytes;
14911 load->header = header;
14912 load->global_buffer.size = header->size;
14913 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14914 load->global_buffer.obj_list_size = header->global_object_list_size;
14915 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14916 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14917 load->iseq = NULL;
14918
14919 load->current_buffer = &load->global_buffer;
14920
14921 if (size < header->size) {
14922 rb_raise(rb_eRuntimeError, "broken binary format");
14923 }
14924 if (strncmp(header->magic, "YARB", 4) != 0) {
14925 rb_raise(rb_eRuntimeError, "unknown binary format");
14926 }
14927 if (header->major_version != IBF_MAJOR_VERSION ||
14928 header->minor_version != IBF_MINOR_VERSION) {
14929 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14930 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14931 }
14932 if (header->endian != IBF_ENDIAN_MARK) {
14933 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14934 }
14935 if (header->wordsize != SIZEOF_VALUE) {
14936 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14937 }
14938 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14939 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14940 header->iseq_list_offset);
14941 }
14942 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14943 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14944 load->global_buffer.obj_list_offset);
14945 }
14946}
14947
14948static void
14949ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14950{
14951 StringValue(str);
14952
14953 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14954 rb_raise(rb_eRuntimeError, "broken binary format");
14955 }
14956
14957 if (USE_LAZY_LOAD) {
14958 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14959 }
14960
14961 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14962 RB_OBJ_WRITE(loader_obj, &load->str, str);
14963}
14964
14965static void
14966ibf_loader_mark(void *ptr)
14967{
14968 struct ibf_load *load = (struct ibf_load *)ptr;
14969 rb_gc_mark(load->str);
14970 rb_gc_mark(load->iseq_list);
14971 rb_gc_mark(load->global_buffer.obj_list);
14972}
14973
14974static void
14975ibf_loader_free(void *ptr)
14976{
14977 struct ibf_load *load = (struct ibf_load *)ptr;
14978 SIZED_FREE(load);
14979}
14980
14981static size_t
14982ibf_loader_memsize(const void *ptr)
14983{
14984 return sizeof(struct ibf_load);
14985}
14986
14987static const rb_data_type_t ibf_load_type = {
14988 "ibf_loader",
14989 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14990 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14991};
14992
14993const rb_iseq_t *
14994rb_iseq_ibf_load(VALUE str)
14995{
14996 struct ibf_load *load;
14997 rb_iseq_t *iseq;
14998 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14999
15000 ibf_load_setup(load, loader_obj, str);
15001 iseq = ibf_load_iseq(load, 0);
15002
15003 RB_GC_GUARD(loader_obj);
15004 return iseq;
15005}
15006
15007const rb_iseq_t *
15008rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15009{
15010 struct ibf_load *load;
15011 rb_iseq_t *iseq;
15012 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15013
15014 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15015 iseq = ibf_load_iseq(load, 0);
15016
15017 RB_GC_GUARD(loader_obj);
15018 return iseq;
15019}
15020
15021VALUE
15022rb_iseq_ibf_load_extra_data(VALUE str)
15023{
15024 struct ibf_load *load;
15025 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15026 VALUE extra_str;
15027
15028 ibf_load_setup(load, loader_obj, str);
15029 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15030 RB_GC_GUARD(loader_obj);
15031 return extra_str;
15032}
15033
15034#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:133
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:125
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:129
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:487
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1428
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1415
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1418
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1431
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:673
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1416
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1432
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1420
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1435
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:61
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_cHash
Hash class.
Definition hash.c:109
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:923
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1117
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1141
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1862
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:69
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1985
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4227
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:3816
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1729
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4179
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4165
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3584
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:3782
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4233
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:4053
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3294
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:1012
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1031
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:981
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1552
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
#define RUBY_TYPED_FREE_IMMEDIATELY
Macros to see if each corresponding flag is defined.
Definition rtypeddata.h:119
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:736
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:514
#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:561
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9063
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:30
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:289
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:260
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:211
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:218
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145