Ruby 3.5.0dev (2025-11-03 revision 4a3d8346a6d0e068508631541f6bc43e8b154ea1)
compile.c (4a3d8346a6d0e068508631541f6bc43e8b154ea1)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
498
499static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
500static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
501
502/*
503 * To make Array to LinkedList, use link_anchor
504 */
505
506static void
507verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
508{
509#if CPDEBUG
510 int flag = 0;
511 LINK_ELEMENT *list, *plist;
512
513 if (!compile_debug) return;
514
515 list = anchor->anchor.next;
516 plist = &anchor->anchor;
517 while (list) {
518 if (plist != list->prev) {
519 flag += 1;
520 }
521 plist = list;
522 list = list->next;
523 }
524
525 if (anchor->last != plist && anchor->last != 0) {
526 flag |= 0x70000;
527 }
528
529 if (flag != 0) {
530 rb_bug("list verify error: %08x (%s)", flag, info);
531 }
532#endif
533}
534#if CPDEBUG < 0
535#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
536#endif
537
538static void
539verify_call_cache(rb_iseq_t *iseq)
540{
541#if CPDEBUG
542 VALUE *original = rb_iseq_original_iseq(iseq);
543 size_t i = 0;
544 while (i < ISEQ_BODY(iseq)->iseq_size) {
545 VALUE insn = original[i];
546 const char *types = insn_op_types(insn);
547
548 for (int j=0; types[j]; j++) {
549 if (types[j] == TS_CALLDATA) {
550 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
551 const struct rb_callinfo *ci = cd->ci;
552 const struct rb_callcache *cc = cd->cc;
553 if (cc != vm_cc_empty()) {
554 vm_ci_dump(ci);
555 rb_bug("call cache is not initialized by vm_cc_empty()");
556 }
557 }
558 }
559 i += insn_len(insn);
560 }
561
562 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
563 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
564 const struct rb_callinfo *ci = cd->ci;
565 const struct rb_callcache *cc = cd->cc;
566 if (cc != NULL && cc != vm_cc_empty()) {
567 vm_ci_dump(ci);
568 rb_bug("call cache is not initialized by vm_cc_empty()");
569 }
570 }
571#endif
572}
573
574/*
575 * elem1, elem2 => elem1, elem2, elem
576 */
577static void
578ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
579{
580 elem->prev = anchor->last;
581 anchor->last->next = elem;
582 anchor->last = elem;
583 verify_list("add", anchor);
584}
585
586/*
587 * elem1, before, elem2 => elem1, before, elem, elem2
588 */
589static void
590APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
591{
592 elem->prev = before;
593 elem->next = before->next;
594 elem->next->prev = elem;
595 before->next = elem;
596 if (before == anchor->last) anchor->last = elem;
597 verify_list("add", anchor);
598}
599#if CPDEBUG < 0
600#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
601#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
602#endif
603
604static int
605branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
606{
607 if (!ISEQ_COVERAGE(iseq)) return 0;
608 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
609 if (first_line <= 0) return 0;
610 return 1;
611}
612
613#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
614
615static VALUE
616setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
617{
618 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
619 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
620 VALUE branch = rb_ary_hidden_new(6);
621
622 rb_hash_aset(structure, key, branch);
623 rb_ary_push(branch, ID2SYM(rb_intern(type)));
624 rb_ary_push(branch, INT2FIX(first_lineno));
625 rb_ary_push(branch, INT2FIX(first_column));
626 rb_ary_push(branch, INT2FIX(last_lineno));
627 rb_ary_push(branch, INT2FIX(last_column));
628 return branch;
629}
630
631static VALUE
632decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
633{
634 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
635
636 /*
637 * if !structure[node]
638 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
639 * else
640 * branches = structure[node][5]
641 * end
642 */
643
644 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
645 VALUE branch_base = rb_hash_aref(structure, key);
646 VALUE branches;
647
648 if (NIL_P(branch_base)) {
649 branch_base = setup_branch(loc, type, structure, key);
650 branches = rb_hash_new();
651 rb_obj_hide(branches);
652 rb_ary_push(branch_base, branches);
653 }
654 else {
655 branches = RARRAY_AREF(branch_base, 5);
656 }
657
658 return branches;
659}
660
661static NODE
662generate_dummy_line_node(int lineno, int node_id)
663{
664 NODE dummy = { 0 };
665 nd_set_line(&dummy, lineno);
666 nd_set_node_id(&dummy, node_id);
667 return dummy;
668}
669
670static void
671add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
672{
673 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
674
675 /*
676 * if !branches[branch_id]
677 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
678 * else
679 * counter_idx= branches[branch_id][5]
680 * end
681 */
682
683 VALUE key = INT2FIX(branch_id);
684 VALUE branch = rb_hash_aref(branches, key);
685 long counter_idx;
686
687 if (NIL_P(branch)) {
688 branch = setup_branch(loc, type, branches, key);
689 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
690 counter_idx = RARRAY_LEN(counters);
691 rb_ary_push(branch, LONG2FIX(counter_idx));
692 rb_ary_push(counters, INT2FIX(0));
693 }
694 else {
695 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
696 }
697
698 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
699 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
700}
701
702#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
703
704static int
705validate_label(st_data_t name, st_data_t label, st_data_t arg)
706{
707 rb_iseq_t *iseq = (rb_iseq_t *)arg;
708 LABEL *lobj = (LABEL *)label;
709 if (!lobj->link.next) {
710 do {
711 COMPILE_ERROR(iseq, lobj->position,
712 "%"PRIsVALUE": undefined label",
713 rb_sym2str((VALUE)name));
714 } while (0);
715 }
716 return ST_CONTINUE;
717}
718
719static void
720validate_labels(rb_iseq_t *iseq, st_table *labels_table)
721{
722 st_foreach(labels_table, validate_label, (st_data_t)iseq);
723 st_free_table(labels_table);
724}
725
726static NODE *
727get_nd_recv(const NODE *node)
728{
729 switch (nd_type(node)) {
730 case NODE_CALL:
731 return RNODE_CALL(node)->nd_recv;
732 case NODE_OPCALL:
733 return RNODE_OPCALL(node)->nd_recv;
734 case NODE_FCALL:
735 return 0;
736 case NODE_QCALL:
737 return RNODE_QCALL(node)->nd_recv;
738 case NODE_VCALL:
739 return 0;
740 case NODE_ATTRASGN:
741 return RNODE_ATTRASGN(node)->nd_recv;
742 case NODE_OP_ASGN1:
743 return RNODE_OP_ASGN1(node)->nd_recv;
744 case NODE_OP_ASGN2:
745 return RNODE_OP_ASGN2(node)->nd_recv;
746 default:
747 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
748 }
749}
750
751static ID
752get_node_call_nd_mid(const NODE *node)
753{
754 switch (nd_type(node)) {
755 case NODE_CALL:
756 return RNODE_CALL(node)->nd_mid;
757 case NODE_OPCALL:
758 return RNODE_OPCALL(node)->nd_mid;
759 case NODE_FCALL:
760 return RNODE_FCALL(node)->nd_mid;
761 case NODE_QCALL:
762 return RNODE_QCALL(node)->nd_mid;
763 case NODE_VCALL:
764 return RNODE_VCALL(node)->nd_mid;
765 case NODE_ATTRASGN:
766 return RNODE_ATTRASGN(node)->nd_mid;
767 default:
768 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
769 }
770}
771
772static NODE *
773get_nd_args(const NODE *node)
774{
775 switch (nd_type(node)) {
776 case NODE_CALL:
777 return RNODE_CALL(node)->nd_args;
778 case NODE_OPCALL:
779 return RNODE_OPCALL(node)->nd_args;
780 case NODE_FCALL:
781 return RNODE_FCALL(node)->nd_args;
782 case NODE_QCALL:
783 return RNODE_QCALL(node)->nd_args;
784 case NODE_VCALL:
785 return 0;
786 case NODE_ATTRASGN:
787 return RNODE_ATTRASGN(node)->nd_args;
788 default:
789 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
790 }
791}
792
793static ID
794get_node_colon_nd_mid(const NODE *node)
795{
796 switch (nd_type(node)) {
797 case NODE_COLON2:
798 return RNODE_COLON2(node)->nd_mid;
799 case NODE_COLON3:
800 return RNODE_COLON3(node)->nd_mid;
801 default:
802 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
803 }
804}
805
806static ID
807get_nd_vid(const NODE *node)
808{
809 switch (nd_type(node)) {
810 case NODE_LASGN:
811 return RNODE_LASGN(node)->nd_vid;
812 case NODE_DASGN:
813 return RNODE_DASGN(node)->nd_vid;
814 case NODE_IASGN:
815 return RNODE_IASGN(node)->nd_vid;
816 case NODE_CVASGN:
817 return RNODE_CVASGN(node)->nd_vid;
818 default:
819 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
820 }
821}
822
823static NODE *
824get_nd_value(const NODE *node)
825{
826 switch (nd_type(node)) {
827 case NODE_LASGN:
828 return RNODE_LASGN(node)->nd_value;
829 case NODE_DASGN:
830 return RNODE_DASGN(node)->nd_value;
831 default:
832 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
833 }
834}
835
836static VALUE
837get_string_value(const NODE *node)
838{
839 switch (nd_type(node)) {
840 case NODE_STR:
841 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
842 case NODE_FILE:
843 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
844 default:
845 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
846 }
847}
848
849VALUE
850rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
851{
852 DECL_ANCHOR(ret);
853 INIT_ANCHOR(ret);
854
855 (*ifunc->func)(iseq, ret, ifunc->data);
856
857 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
858
859 CHECK(iseq_setup_insn(iseq, ret));
860 return iseq_setup(iseq, ret);
861}
862
863static bool drop_unreachable_return(LINK_ANCHOR *ret);
864
865VALUE
866rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
867{
868 DECL_ANCHOR(ret);
869 INIT_ANCHOR(ret);
870
871 if (node == 0) {
872 NO_CHECK(COMPILE(ret, "nil", node));
873 iseq_set_local_table(iseq, 0, 0);
874 }
875 /* assume node is T_NODE */
876 else if (nd_type_p(node, NODE_SCOPE)) {
877 /* iseq type of top, method, class, block */
878 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
879 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
880 iseq_set_parameters_lvar_state(iseq);
881
882 switch (ISEQ_BODY(iseq)->type) {
883 case ISEQ_TYPE_BLOCK:
884 {
885 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
886 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
887
888 start->rescued = LABEL_RESCUE_BEG;
889 end->rescued = LABEL_RESCUE_END;
890
891 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
892 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
893 ADD_LABEL(ret, start);
894 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
895 ADD_LABEL(ret, end);
896 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
897 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
898
899 /* wide range catch handler must put at last */
900 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
901 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
902 break;
903 }
904 case ISEQ_TYPE_CLASS:
905 {
906 ADD_TRACE(ret, RUBY_EVENT_CLASS);
907 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
908 ADD_TRACE(ret, RUBY_EVENT_END);
909 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
910 break;
911 }
912 case ISEQ_TYPE_METHOD:
913 {
914 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
915 ADD_TRACE(ret, RUBY_EVENT_CALL);
916 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
917 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
918 ADD_TRACE(ret, RUBY_EVENT_RETURN);
919 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
920 break;
921 }
922 default: {
923 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
924 break;
925 }
926 }
927 }
928 else {
929 const char *m;
930#define INVALID_ISEQ_TYPE(type) \
931 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
932 switch (ISEQ_BODY(iseq)->type) {
933 case INVALID_ISEQ_TYPE(METHOD);
934 case INVALID_ISEQ_TYPE(CLASS);
935 case INVALID_ISEQ_TYPE(BLOCK);
936 case INVALID_ISEQ_TYPE(EVAL);
937 case INVALID_ISEQ_TYPE(MAIN);
938 case INVALID_ISEQ_TYPE(TOP);
939#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
940 case ISEQ_TYPE_RESCUE:
941 iseq_set_exception_local_table(iseq);
942 CHECK(COMPILE(ret, "rescue", node));
943 break;
944 case ISEQ_TYPE_ENSURE:
945 iseq_set_exception_local_table(iseq);
946 CHECK(COMPILE_POPPED(ret, "ensure", node));
947 break;
948 case ISEQ_TYPE_PLAIN:
949 CHECK(COMPILE(ret, "ensure", node));
950 break;
951 default:
952 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
953 return COMPILE_NG;
954 invalid_iseq_type:
955 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
956 return COMPILE_NG;
957 }
958 }
959
960 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
961 NODE dummy_line_node = generate_dummy_line_node(0, -1);
962 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
963 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
964 }
965 else if (!drop_unreachable_return(ret)) {
966 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
967 }
968
969#if OPT_SUPPORT_JOKE
970 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
971 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
972 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
973 validate_labels(iseq, labels_table);
974 }
975#endif
976 CHECK(iseq_setup_insn(iseq, ret));
977 return iseq_setup(iseq, ret);
978}
979
980static int
981rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
982{
983#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
984 const void * const *table = rb_vm_get_insns_address_table();
985 unsigned int i;
986 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
987
988 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
989 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
990 int len = insn_len(insn);
991 encoded[i] = (VALUE)table[insn];
992 i += len;
993 }
994 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
995#endif
996
997#if USE_YJIT
998 rb_yjit_live_iseq_count++;
999 rb_yjit_iseq_alloc_count++;
1000#endif
1001
1002 return COMPILE_OK;
1003}
1004
1005VALUE *
1006rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1007{
1008 VALUE *original_code;
1009
1010 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1011 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1012 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1013
1014#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1015 {
1016 unsigned int i;
1017
1018 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1019 const void *addr = (const void *)original_code[i];
1020 const int insn = rb_vm_insn_addr2insn(addr);
1021
1022 original_code[i] = insn;
1023 i += insn_len(insn);
1024 }
1025 }
1026#endif
1027 return original_code;
1028}
1029
1030/*********************************************/
1031/* definition of data structure for compiler */
1032/*********************************************/
1033
1034/*
1035 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1036 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1037 * generate SPARCV8PLUS code with unaligned memory access instructions.
1038 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1039 */
1040#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1041 #define STRICT_ALIGNMENT
1042#endif
1043
1044/*
1045 * Some OpenBSD platforms (including sparc64) require strict alignment.
1046 */
1047#if defined(__OpenBSD__)
1048 #include <sys/endian.h>
1049 #ifdef __STRICT_ALIGNMENT
1050 #define STRICT_ALIGNMENT
1051 #endif
1052#endif
1053
1054#ifdef STRICT_ALIGNMENT
1055 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1056 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1057 #else
1058 #define ALIGNMENT_SIZE SIZEOF_VALUE
1059 #endif
1060 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1061 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1062 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1063#else
1064 #define PADDING_SIZE_MAX 0
1065#endif /* STRICT_ALIGNMENT */
1066
1067#ifdef STRICT_ALIGNMENT
1068/* calculate padding size for aligned memory access */
1069static size_t
1070calc_padding(void *ptr, size_t size)
1071{
1072 size_t mis;
1073 size_t padding = 0;
1074
1075 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1076 if (mis > 0) {
1077 padding = ALIGNMENT_SIZE - mis;
1078 }
1079/*
1080 * On 32-bit sparc or equivalents, when a single VALUE is requested
1081 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1082 */
1083#if ALIGNMENT_SIZE > SIZEOF_VALUE
1084 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1085 padding = 0;
1086 }
1087#endif
1088
1089 return padding;
1090}
1091#endif /* STRICT_ALIGNMENT */
1092
1093static void *
1094compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1095{
1096 void *ptr = 0;
1097 struct iseq_compile_data_storage *storage = *arena;
1098#ifdef STRICT_ALIGNMENT
1099 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1100#else
1101 const size_t padding = 0; /* expected to be optimized by compiler */
1102#endif /* STRICT_ALIGNMENT */
1103
1104 if (size >= INT_MAX - padding) rb_memerror();
1105 if (storage->pos + size + padding > storage->size) {
1106 unsigned int alloc_size = storage->size;
1107
1108 while (alloc_size < size + PADDING_SIZE_MAX) {
1109 if (alloc_size >= INT_MAX / 2) rb_memerror();
1110 alloc_size *= 2;
1111 }
1112 storage->next = (void *)ALLOC_N(char, alloc_size +
1113 offsetof(struct iseq_compile_data_storage, buff));
1114 storage = *arena = storage->next;
1115 storage->next = 0;
1116 storage->pos = 0;
1117 storage->size = alloc_size;
1118#ifdef STRICT_ALIGNMENT
1119 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1120#endif /* STRICT_ALIGNMENT */
1121 }
1122
1123#ifdef STRICT_ALIGNMENT
1124 storage->pos += (int)padding;
1125#endif /* STRICT_ALIGNMENT */
1126
1127 ptr = (void *)&storage->buff[storage->pos];
1128 storage->pos += (int)size;
1129 return ptr;
1130}
1131
1132static void *
1133compile_data_alloc(rb_iseq_t *iseq, size_t size)
1134{
1135 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1136 return compile_data_alloc_with_arena(arena, size);
1137}
1138
1139static inline void *
1140compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1141{
1142 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1143 return compile_data_alloc(iseq, size);
1144}
1145
1146static inline void *
1147compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1148{
1149 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1150 void *p = compile_data_alloc(iseq, size);
1151 memset(p, 0, size);
1152 return p;
1153}
1154
1155static INSN *
1156compile_data_alloc_insn(rb_iseq_t *iseq)
1157{
1158 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1159 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1160}
1161
1162static LABEL *
1163compile_data_alloc_label(rb_iseq_t *iseq)
1164{
1165 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1166}
1167
1168static ADJUST *
1169compile_data_alloc_adjust(rb_iseq_t *iseq)
1170{
1171 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1172}
1173
1174static TRACE *
1175compile_data_alloc_trace(rb_iseq_t *iseq)
1176{
1177 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1178}
1179
1180/*
1181 * elem1, elemX => elem1, elem2, elemX
1182 */
1183static void
1184ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1185{
1186 elem2->next = elem1->next;
1187 elem2->prev = elem1;
1188 elem1->next = elem2;
1189 if (elem2->next) {
1190 elem2->next->prev = elem2;
1191 }
1192}
1193
1194/*
1195 * elem1, elemX => elemX, elem2, elem1
1196 */
1197static void
1198ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1199{
1200 elem2->prev = elem1->prev;
1201 elem2->next = elem1;
1202 elem1->prev = elem2;
1203 if (elem2->prev) {
1204 elem2->prev->next = elem2;
1205 }
1206}
1207
1208/*
1209 * elemX, elem1, elemY => elemX, elem2, elemY
1210 */
1211static void
1212ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1213{
1214 elem2->prev = elem1->prev;
1215 elem2->next = elem1->next;
1216 if (elem1->prev) {
1217 elem1->prev->next = elem2;
1218 }
1219 if (elem1->next) {
1220 elem1->next->prev = elem2;
1221 }
1222}
1223
1224static void
1225ELEM_REMOVE(LINK_ELEMENT *elem)
1226{
1227 elem->prev->next = elem->next;
1228 if (elem->next) {
1229 elem->next->prev = elem->prev;
1230 }
1231}
1232
1233static LINK_ELEMENT *
1234FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1235{
1236 return anchor->anchor.next;
1237}
1238
1239static LINK_ELEMENT *
1240LAST_ELEMENT(LINK_ANCHOR *const anchor)
1241{
1242 return anchor->last;
1243}
1244
1245static LINK_ELEMENT *
1246ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1247{
1248 while (elem) {
1249 switch (elem->type) {
1250 case ISEQ_ELEMENT_INSN:
1251 case ISEQ_ELEMENT_ADJUST:
1252 return elem;
1253 default:
1254 elem = elem->next;
1255 }
1256 }
1257 return NULL;
1258}
1259
1260static int
1261LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1262{
1263 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1264 if (first_insn != NULL &&
1265 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1266 return TRUE;
1267 }
1268 else {
1269 return FALSE;
1270 }
1271}
1272
1273static int
1274LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1275{
1276 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1277 return TRUE;
1278 }
1279 else {
1280 return FALSE;
1281 }
1282}
1283
1284/*
1285 * anc1: e1, e2, e3
1286 * anc2: e4, e5
1287 *#=>
1288 * anc1: e1, e2, e3, e4, e5
1289 * anc2: e4, e5 (broken)
1290 */
1291static void
1292APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1293{
1294 if (anc2->anchor.next) {
1295 /* LINK_ANCHOR must not loop */
1296 RUBY_ASSERT(anc2->last != &anc2->anchor);
1297 anc1->last->next = anc2->anchor.next;
1298 anc2->anchor.next->prev = anc1->last;
1299 anc1->last = anc2->last;
1300 }
1301 else {
1302 RUBY_ASSERT(anc2->last == &anc2->anchor);
1303 }
1304 verify_list("append", anc1);
1305}
1306#if CPDEBUG < 0
1307#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1308#endif
1309
1310#if CPDEBUG && 0
1311static void
1312debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1313{
1314 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1315 printf("----\n");
1316 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1317 (void *)anchor->anchor.next, (void *)anchor->last);
1318 while (list) {
1319 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1320 (void *)list->prev, (int)list->type);
1321 list = list->next;
1322 }
1323 printf("----\n");
1324
1325 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1326 verify_list("debug list", anchor);
1327}
1328#if CPDEBUG < 0
1329#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1330#endif
1331#else
1332#define debug_list(anc, cur) ((void)0)
1333#endif
1334
1335static TRACE *
1336new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1337{
1338 TRACE *trace = compile_data_alloc_trace(iseq);
1339
1340 trace->link.type = ISEQ_ELEMENT_TRACE;
1341 trace->link.next = NULL;
1342 trace->event = event;
1343 trace->data = data;
1344
1345 return trace;
1346}
1347
1348static LABEL *
1349new_label_body(rb_iseq_t *iseq, long line)
1350{
1351 LABEL *labelobj = compile_data_alloc_label(iseq);
1352
1353 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1354 labelobj->link.next = 0;
1355
1356 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1357 labelobj->sc_state = 0;
1358 labelobj->sp = -1;
1359 labelobj->refcnt = 0;
1360 labelobj->set = 0;
1361 labelobj->rescued = LABEL_RESCUE_NONE;
1362 labelobj->unremovable = 0;
1363 labelobj->position = -1;
1364 return labelobj;
1365}
1366
1367static ADJUST *
1368new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1369{
1370 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1371 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1372 adjust->link.next = 0;
1373 adjust->label = label;
1374 adjust->line_no = line;
1375 LABEL_UNREMOVABLE(label);
1376 return adjust;
1377}
1378
1379static void
1380iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1381{
1382 const char *types = insn_op_types(insn->insn_id);
1383 for (int j = 0; types[j]; j++) {
1384 char type = types[j];
1385 switch (type) {
1386 case TS_CDHASH:
1387 case TS_ISEQ:
1388 case TS_VALUE:
1389 case TS_IC: // constant path array
1390 case TS_CALLDATA: // ci is stored.
1391 func(&OPERAND_AT(insn, j), data);
1392 break;
1393 default:
1394 break;
1395 }
1396 }
1397}
1398
1399static void
1400iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1401{
1402 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1404 RBASIC_CLASS(*obj) == 0 || // hidden
1405 RB_OBJ_SHAREABLE_P(*obj));
1406}
1407
1408static INSN *
1409new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1410{
1411 INSN *iobj = compile_data_alloc_insn(iseq);
1412
1413 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1414
1415 iobj->link.type = ISEQ_ELEMENT_INSN;
1416 iobj->link.next = 0;
1417 iobj->insn_id = insn_id;
1418 iobj->insn_info.line_no = line_no;
1419 iobj->insn_info.node_id = node_id;
1420 iobj->insn_info.events = 0;
1421 iobj->operands = argv;
1422 iobj->operand_size = argc;
1423 iobj->sc_state = 0;
1424
1425 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1426
1427 return iobj;
1428}
1429
1430static INSN *
1431new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1432{
1433 VALUE *operands = 0;
1434 va_list argv;
1435 if (argc > 0) {
1436 int i;
1437 va_start(argv, argc);
1438 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1439 for (i = 0; i < argc; i++) {
1440 VALUE v = va_arg(argv, VALUE);
1441 operands[i] = v;
1442 }
1443 va_end(argv);
1444 }
1445 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1446}
1447
1448static INSN *
1449insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1450{
1451 VALUE *operands = 0;
1452 va_list argv;
1453 if (argc > 0) {
1454 int i;
1455 va_start(argv, argc);
1456 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1457 for (i = 0; i < argc; i++) {
1458 VALUE v = va_arg(argv, VALUE);
1459 operands[i] = v;
1460 }
1461 va_end(argv);
1462 }
1463
1464 iobj->insn_id = insn_id;
1465 iobj->operand_size = argc;
1466 iobj->operands = operands;
1467 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1468
1469 return iobj;
1470}
1471
1472static const struct rb_callinfo *
1473new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1474{
1475 VM_ASSERT(argc >= 0);
1476
1477 if (kw_arg) {
1478 flag |= VM_CALL_KWARG;
1479 argc += kw_arg->keyword_len;
1480 }
1481
1482 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1483 && !has_blockiseq) {
1484 flag |= VM_CALL_ARGS_SIMPLE;
1485 }
1486
1487 ISEQ_BODY(iseq)->ci_size++;
1488 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1489 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1490 return ci;
1491}
1492
1493static INSN *
1494new_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)
1495{
1496 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1497 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1498 operands[0] = ci;
1499 operands[1] = (VALUE)blockiseq;
1500 if (blockiseq) {
1501 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1502 }
1503
1504 INSN *insn;
1505
1506 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1507 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1508 }
1509 else {
1510 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1511 }
1512
1513 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1514 RB_GC_GUARD(ci);
1515 return insn;
1516}
1517
1518static rb_iseq_t *
1519new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1520 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1521{
1522 rb_iseq_t *ret_iseq;
1523 VALUE ast_value = rb_ruby_ast_new(node);
1524
1525 debugs("[new_child_iseq]> ---------------------------------------\n");
1526 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1527 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1528 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1529 line_no, parent,
1530 isolated_depth ? isolated_depth + 1 : 0,
1531 type, ISEQ_COMPILE_DATA(iseq)->option,
1532 ISEQ_BODY(iseq)->variable.script_lines);
1533 debugs("[new_child_iseq]< ---------------------------------------\n");
1534 return ret_iseq;
1535}
1536
1537static rb_iseq_t *
1538new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1539 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1540{
1541 rb_iseq_t *ret_iseq;
1542
1543 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1544 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1545 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1546 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1547 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1548 return ret_iseq;
1549}
1550
1551static void
1552set_catch_except_p(rb_iseq_t *iseq)
1553{
1554 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1555 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1556 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1557 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1558 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1559 }
1560 }
1561}
1562
1563/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1564 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1565 if catch table exists. But we want to optimize while loop, which always has catch
1566 table entries for break/next/redo.
1567
1568 So this function sets true for limited ISeqs with break/next/redo catch table entries
1569 whose child ISeq would really raise an exception. */
1570static void
1571update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1572{
1573 unsigned int pos;
1574 size_t i;
1575 int insn;
1576 const struct iseq_catch_table *ct = body->catch_table;
1577
1578 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1579 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1580 pos = 0;
1581 while (pos < body->iseq_size) {
1582 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1583 if (insn == BIN(throw)) {
1584 set_catch_except_p(iseq);
1585 break;
1586 }
1587 pos += insn_len(insn);
1588 }
1589
1590 if (ct == NULL)
1591 return;
1592
1593 for (i = 0; i < ct->size; i++) {
1594 const struct iseq_catch_table_entry *entry =
1595 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1596 if (entry->type != CATCH_TYPE_BREAK
1597 && entry->type != CATCH_TYPE_NEXT
1598 && entry->type != CATCH_TYPE_REDO) {
1599 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1600 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1601 break;
1602 }
1603 }
1604}
1605
1606static void
1607iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1608{
1609 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1610 if (NIL_P(catch_table_ary)) return;
1611 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1612 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1613 for (i = 0; i < tlen; i++) {
1614 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1615 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1616 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1617 LINK_ELEMENT *e;
1618
1619 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1620
1621 if (ct != CATCH_TYPE_BREAK
1622 && ct != CATCH_TYPE_NEXT
1623 && ct != CATCH_TYPE_REDO) {
1624
1625 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1626 if (e == cont) {
1627 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1628 ELEM_INSERT_NEXT(end, &nop->link);
1629 break;
1630 }
1631 }
1632 }
1633 }
1634
1635 RB_GC_GUARD(catch_table_ary);
1636}
1637
1638static int
1639iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1640{
1641 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1642 return COMPILE_NG;
1643
1644 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1645
1646 if (compile_debug > 5)
1647 dump_disasm_list(FIRST_ELEMENT(anchor));
1648
1649 debugs("[compile step 3.1 (iseq_optimize)]\n");
1650 iseq_optimize(iseq, anchor);
1651
1652 if (compile_debug > 5)
1653 dump_disasm_list(FIRST_ELEMENT(anchor));
1654
1655 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1656 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1657 iseq_insns_unification(iseq, anchor);
1658 if (compile_debug > 5)
1659 dump_disasm_list(FIRST_ELEMENT(anchor));
1660 }
1661
1662 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1663 iseq_insert_nop_between_end_and_cont(iseq);
1664 if (compile_debug > 5)
1665 dump_disasm_list(FIRST_ELEMENT(anchor));
1666
1667 return COMPILE_OK;
1668}
1669
1670static int
1671iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1672{
1673 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1674 return COMPILE_NG;
1675
1676 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1677 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1678 if (compile_debug > 5)
1679 dump_disasm_list(FIRST_ELEMENT(anchor));
1680
1681 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1682 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1683
1684 debugs("[compile step 4.3 (set_optargs_table)] \n");
1685 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1686
1687 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1688 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1689
1690 debugs("[compile step 6 (update_catch_except_flags)] \n");
1691 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1692 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1693
1694 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1695 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1696 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1697 xfree(ISEQ_BODY(iseq)->catch_table);
1698 ISEQ_BODY(iseq)->catch_table = NULL;
1699 }
1700
1701#if VM_INSN_INFO_TABLE_IMPL == 2
1702 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1703 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1704 rb_iseq_insns_info_encode_positions(iseq);
1705 }
1706#endif
1707
1708 if (compile_debug > 1) {
1709 VALUE str = rb_iseq_disasm(iseq);
1710 printf("%s\n", StringValueCStr(str));
1711 }
1712 verify_call_cache(iseq);
1713 debugs("[compile step: finish]\n");
1714
1715 return COMPILE_OK;
1716}
1717
1718static int
1719iseq_set_exception_local_table(rb_iseq_t *iseq)
1720{
1721 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1722 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1723 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1724 return COMPILE_OK;
1725}
1726
1727static int
1728get_lvar_level(const rb_iseq_t *iseq)
1729{
1730 int lev = 0;
1731 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1732 lev++;
1733 iseq = ISEQ_BODY(iseq)->parent_iseq;
1734 }
1735 return lev;
1736}
1737
1738static int
1739get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1740{
1741 unsigned int i;
1742
1743 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1744 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1745 return (int)i;
1746 }
1747 }
1748 return -1;
1749}
1750
1751static int
1752get_local_var_idx(const rb_iseq_t *iseq, ID id)
1753{
1754 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1755
1756 if (idx < 0) {
1757 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1758 "get_local_var_idx: %d", idx);
1759 }
1760
1761 return idx;
1762}
1763
1764static int
1765get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1766{
1767 int lv = 0, idx = -1;
1768 const rb_iseq_t *const topmost_iseq = iseq;
1769
1770 while (iseq) {
1771 idx = get_dyna_var_idx_at_raw(iseq, id);
1772 if (idx >= 0) {
1773 break;
1774 }
1775 iseq = ISEQ_BODY(iseq)->parent_iseq;
1776 lv++;
1777 }
1778
1779 if (idx < 0) {
1780 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1781 "get_dyna_var_idx: -1");
1782 }
1783
1784 *level = lv;
1785 *ls = ISEQ_BODY(iseq)->local_table_size;
1786 return idx;
1787}
1788
1789static int
1790iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1791{
1792 const struct rb_iseq_constant_body *body;
1793 while (level > 0) {
1794 iseq = ISEQ_BODY(iseq)->parent_iseq;
1795 level--;
1796 }
1797 body = ISEQ_BODY(iseq);
1798 if (body->local_iseq == iseq && /* local variables */
1799 body->param.flags.has_block &&
1800 body->local_table_size - body->param.block_start == idx) {
1801 return TRUE;
1802 }
1803 else {
1804 return FALSE;
1805 }
1806}
1807
1808static int
1809iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1810{
1811 int level, ls;
1812 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1813 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1814 *pidx = ls - idx;
1815 *plevel = level;
1816 return TRUE;
1817 }
1818 else {
1819 return FALSE;
1820 }
1821}
1822
1823static void
1824access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1825{
1826 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1827
1828 if (isolated_depth && level >= isolated_depth) {
1829 if (id == rb_intern("yield")) {
1830 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1831 }
1832 else {
1833 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1834 }
1835 }
1836
1837 for (int i=0; i<level; i++) {
1838 VALUE val;
1839 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1840
1841 if (!ovs) {
1842 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1843 }
1844
1845 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1846 if (write && !val) {
1847 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1848 }
1849 }
1850 else {
1851 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1852 }
1853
1854 iseq = ISEQ_BODY(iseq)->parent_iseq;
1855 }
1856}
1857
1858static ID
1859iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1860{
1861 for (int i=0; i<level; i++) {
1862 iseq = ISEQ_BODY(iseq)->parent_iseq;
1863 }
1864
1865 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1866 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1867 return id;
1868}
1869
1870static void
1871update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1872{
1873 for (int i=0; i<level; i++) {
1874 iseq = ISEQ_BODY(iseq)->parent_iseq;
1875 }
1876
1877 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1878 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1879 switch (states[table_idx]) {
1880 case lvar_uninitialized:
1881 states[table_idx] = lvar_initialized;
1882 break;
1883 case lvar_initialized:
1884 states[table_idx] = lvar_reassigned;
1885 break;
1886 case lvar_reassigned:
1887 /* nothing */
1888 break;
1889 default:
1890 rb_bug("unreachable");
1891 }
1892}
1893
1894static int
1895iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1896{
1897 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1898 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1899 }
1900
1901 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1902 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1903 for (int i=0; i<opt_num; i++) {
1904 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1905 }
1906
1907 return COMPILE_OK;
1908}
1909
1910static void
1911iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1912{
1913 if (iseq_local_block_param_p(iseq, idx, level)) {
1914 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1915 }
1916 else {
1917 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1918 }
1919 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1920}
1921
1922static void
1923iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1924{
1925 if (iseq_local_block_param_p(iseq, idx, level)) {
1926 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1927 }
1928 else {
1929 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1930 }
1931 update_lvar_state(iseq, level, idx);
1932 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1933}
1934
1935
1936
1937static void
1938iseq_calc_param_size(rb_iseq_t *iseq)
1939{
1940 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1941 if (body->param.flags.has_opt ||
1942 body->param.flags.has_post ||
1943 body->param.flags.has_rest ||
1944 body->param.flags.has_block ||
1945 body->param.flags.has_kw ||
1946 body->param.flags.has_kwrest) {
1947
1948 if (body->param.flags.has_block) {
1949 body->param.size = body->param.block_start + 1;
1950 }
1951 else if (body->param.flags.has_kwrest) {
1952 body->param.size = body->param.keyword->rest_start + 1;
1953 }
1954 else if (body->param.flags.has_kw) {
1955 body->param.size = body->param.keyword->bits_start + 1;
1956 }
1957 else if (body->param.flags.has_post) {
1958 body->param.size = body->param.post_start + body->param.post_num;
1959 }
1960 else if (body->param.flags.has_rest) {
1961 body->param.size = body->param.rest_start + 1;
1962 }
1963 else if (body->param.flags.has_opt) {
1964 body->param.size = body->param.lead_num + body->param.opt_num;
1965 }
1966 else {
1968 }
1969 }
1970 else {
1971 body->param.size = body->param.lead_num;
1972 }
1973}
1974
1975static int
1976iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1977 const struct rb_args_info *args, int arg_size)
1978{
1979 const rb_node_kw_arg_t *node = args->kw_args;
1980 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1981 struct rb_iseq_param_keyword *keyword;
1982 const VALUE default_values = rb_ary_hidden_new(1);
1983 const VALUE complex_mark = rb_str_tmp_new(0);
1984 int kw = 0, rkw = 0, di = 0, i;
1985
1986 body->param.flags.has_kw = TRUE;
1987 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1988
1989 while (node) {
1990 kw++;
1991 node = node->nd_next;
1992 }
1993 arg_size += kw;
1994 keyword->bits_start = arg_size++;
1995
1996 node = args->kw_args;
1997 while (node) {
1998 const NODE *val_node = get_nd_value(node->nd_body);
1999 VALUE dv;
2000
2001 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2002 ++rkw;
2003 }
2004 else {
2005 switch (nd_type(val_node)) {
2006 case NODE_SYM:
2007 dv = rb_node_sym_string_val(val_node);
2008 break;
2009 case NODE_REGX:
2010 dv = rb_node_regx_string_val(val_node);
2011 break;
2012 case NODE_LINE:
2013 dv = rb_node_line_lineno_val(val_node);
2014 break;
2015 case NODE_INTEGER:
2016 dv = rb_node_integer_literal_val(val_node);
2017 break;
2018 case NODE_FLOAT:
2019 dv = rb_node_float_literal_val(val_node);
2020 break;
2021 case NODE_RATIONAL:
2022 dv = rb_node_rational_literal_val(val_node);
2023 break;
2024 case NODE_IMAGINARY:
2025 dv = rb_node_imaginary_literal_val(val_node);
2026 break;
2027 case NODE_ENCODING:
2028 dv = rb_node_encoding_val(val_node);
2029 break;
2030 case NODE_NIL:
2031 dv = Qnil;
2032 break;
2033 case NODE_TRUE:
2034 dv = Qtrue;
2035 break;
2036 case NODE_FALSE:
2037 dv = Qfalse;
2038 break;
2039 default:
2040 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2041 dv = complex_mark;
2042 }
2043
2044 keyword->num = ++di;
2045 rb_ary_push(default_values, dv);
2046 }
2047
2048 node = node->nd_next;
2049 }
2050
2051 keyword->num = kw;
2052
2053 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2054 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2055 keyword->rest_start = arg_size++;
2056 body->param.flags.has_kwrest = TRUE;
2057
2058 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2059 }
2060 keyword->required_num = rkw;
2061 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2062
2063 if (RARRAY_LEN(default_values)) {
2064 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2065
2066 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2067 VALUE dv = RARRAY_AREF(default_values, i);
2068 if (dv == complex_mark) dv = Qundef;
2070 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2071 }
2072
2073 keyword->default_values = dvs;
2074 }
2075 return arg_size;
2076}
2077
2078static void
2079iseq_set_use_block(rb_iseq_t *iseq)
2080{
2081 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2082 if (!body->param.flags.use_block) {
2083 body->param.flags.use_block = 1;
2084
2085 rb_vm_t *vm = GET_VM();
2086
2087 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2088 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2089 set_insert(vm->unused_block_warning_table, key);
2090 }
2091 }
2092}
2093
2094static int
2095iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2096{
2097 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2098
2099 if (node_args) {
2100 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2101 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2102 ID rest_id = 0;
2103 int last_comma = 0;
2104 ID block_id = 0;
2105 int arg_size;
2106
2107 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2108
2109 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2110 body->param.lead_num = arg_size = (int)args->pre_args_num;
2111 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2112 debugs(" - argc: %d\n", body->param.lead_num);
2113
2114 rest_id = args->rest_arg;
2115 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2116 last_comma = 1;
2117 rest_id = 0;
2118 }
2119 block_id = args->block_arg;
2120
2121 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2122
2123 if (optimized_forward) {
2124 rest_id = 0;
2125 block_id = 0;
2126 }
2127
2128 if (args->opt_args) {
2129 const rb_node_opt_arg_t *node = args->opt_args;
2130 LABEL *label;
2131 VALUE labels = rb_ary_hidden_new(1);
2132 VALUE *opt_table;
2133 int i = 0, j;
2134
2135 while (node) {
2136 label = NEW_LABEL(nd_line(RNODE(node)));
2137 rb_ary_push(labels, (VALUE)label | 1);
2138 ADD_LABEL(optargs, label);
2139 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2140 node = node->nd_next;
2141 i += 1;
2142 }
2143
2144 /* last label */
2145 label = NEW_LABEL(nd_line(node_args));
2146 rb_ary_push(labels, (VALUE)label | 1);
2147 ADD_LABEL(optargs, label);
2148
2149 opt_table = ALLOC_N(VALUE, i+1);
2150
2151 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2152 for (j = 0; j < i+1; j++) {
2153 opt_table[j] &= ~1;
2154 }
2155 rb_ary_clear(labels);
2156
2157 body->param.flags.has_opt = TRUE;
2158 body->param.opt_num = i;
2159 body->param.opt_table = opt_table;
2160 arg_size += i;
2161 }
2162
2163 if (rest_id) {
2164 body->param.rest_start = arg_size++;
2165 body->param.flags.has_rest = TRUE;
2166 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2167 RUBY_ASSERT(body->param.rest_start != -1);
2168 }
2169
2170 if (args->first_post_arg) {
2171 body->param.post_start = arg_size;
2172 body->param.post_num = args->post_args_num;
2173 body->param.flags.has_post = TRUE;
2174 arg_size += args->post_args_num;
2175
2176 if (body->param.flags.has_rest) { /* TODO: why that? */
2177 body->param.post_start = body->param.rest_start + 1;
2178 }
2179 }
2180
2181 if (args->kw_args) {
2182 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2183 }
2184 else if (args->kw_rest_arg && !optimized_forward) {
2185 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2186 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2187 keyword->rest_start = arg_size++;
2188 body->param.keyword = keyword;
2189 body->param.flags.has_kwrest = TRUE;
2190
2191 static ID anon_kwrest = 0;
2192 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2193 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2194 }
2195 else if (args->no_kwarg) {
2196 body->param.flags.accepts_no_kwarg = TRUE;
2197 }
2198
2199 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 (xfree(generated_iseq), \
2405 xfree(insns_info), \
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 generated_iseq = ALLOC_N(VALUE, code_index);
2672 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2673 positions = ALLOC_N(unsigned int, insn_num);
2674 if (ISEQ_IS_SIZE(body)) {
2675 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2676 }
2677 else {
2678 body->is_entries = NULL;
2679 }
2680
2681 if (body->ci_size) {
2682 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2683 }
2684 else {
2685 body->call_data = NULL;
2686 }
2687 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2688
2689 // Calculate the bitmask buffer size.
2690 // Round the generated_iseq size up to the nearest multiple
2691 // of the number of bits in an unsigned long.
2692
2693 // Allocate enough room for the bitmask list
2694 iseq_bits_t * mark_offset_bits;
2695 int code_size = code_index;
2696
2697 bool needs_bitmap = false;
2698
2699 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2700 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2701 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2702 }
2703 else {
2704 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2705 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2706 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2707 }
2708
2709 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2710 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2711
2712 list = FIRST_ELEMENT(anchor);
2713 insns_info_index = code_index = sp = 0;
2714
2715 while (list) {
2716 switch (list->type) {
2717 case ISEQ_ELEMENT_INSN:
2718 {
2719 int j, len, insn;
2720 const char *types;
2721 VALUE *operands;
2722 INSN *iobj = (INSN *)list;
2723
2724 /* update sp */
2725 sp = calc_sp_depth(sp, iobj);
2726 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2727 operands = iobj->operands;
2728 insn = iobj->insn_id;
2729 generated_iseq[code_index] = insn;
2730 types = insn_op_types(insn);
2731 len = insn_len(insn);
2732
2733 for (j = 0; types[j]; j++) {
2734 char type = types[j];
2735
2736 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2737 switch (type) {
2738 case TS_OFFSET:
2739 {
2740 /* label(destination position) */
2741 LABEL *lobj = (LABEL *)operands[j];
2742 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2743 break;
2744 }
2745 case TS_CDHASH:
2746 {
2747 VALUE map = operands[j];
2748 struct cdhash_set_label_struct data;
2749 data.hash = map;
2750 data.pos = code_index;
2751 data.len = len;
2752 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2753
2754 rb_hash_rehash(map);
2755 freeze_hide_obj(map);
2757 generated_iseq[code_index + 1 + j] = map;
2758 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2759 RB_OBJ_WRITTEN(iseq, Qundef, map);
2760 needs_bitmap = true;
2761 break;
2762 }
2763 case TS_LINDEX:
2764 case TS_NUM: /* ulong */
2765 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2766 break;
2767 case TS_ISEQ: /* iseq */
2768 case TS_VALUE: /* VALUE */
2769 {
2770 VALUE v = operands[j];
2771 generated_iseq[code_index + 1 + j] = v;
2772 /* to mark ruby object */
2773 if (!SPECIAL_CONST_P(v)) {
2774 RB_OBJ_WRITTEN(iseq, Qundef, v);
2775 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2776 needs_bitmap = true;
2777 }
2778 break;
2779 }
2780 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2781 case TS_IC: /* inline cache: constants */
2782 {
2783 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2784 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2785 if (UNLIKELY(ic_index >= body->ic_size)) {
2786 BADINSN_DUMP(anchor, &iobj->link, 0);
2787 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2788 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2789 ic_index, ISEQ_IS_SIZE(body));
2790 }
2791
2792 ic->segments = array_to_idlist(operands[j]);
2793
2794 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2795 }
2796 break;
2797 case TS_IVC: /* inline ivar cache */
2798 {
2799 unsigned int ic_index = FIX2UINT(operands[j]);
2800
2801 IVC cache = ((IVC)&body->is_entries[ic_index]);
2802
2803 if (insn == BIN(setinstancevariable)) {
2804 cache->iv_set_name = SYM2ID(operands[j - 1]);
2805 }
2806 else {
2807 cache->iv_set_name = 0;
2808 }
2809
2810 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2811 }
2812 case TS_ISE: /* inline storage entry: `once` insn */
2813 case TS_ICVARC: /* inline cvar cache */
2814 {
2815 unsigned int ic_index = FIX2UINT(operands[j]);
2816 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2817 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2818 BADINSN_DUMP(anchor, &iobj->link, 0);
2819 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2820 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2821 ic_index, ISEQ_IS_SIZE(body));
2822 }
2823 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2824
2825 break;
2826 }
2827 case TS_CALLDATA:
2828 {
2829 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2830 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2831 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2832 cd->ci = source_ci;
2833 cd->cc = vm_cc_empty();
2834 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2835 break;
2836 }
2837 case TS_ID: /* ID */
2838 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2839 break;
2840 case TS_FUNCPTR:
2841 generated_iseq[code_index + 1 + j] = operands[j];
2842 break;
2843 case TS_BUILTIN:
2844 generated_iseq[code_index + 1 + j] = operands[j];
2845 break;
2846 default:
2847 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2848 "unknown operand type: %c", type);
2849 return COMPILE_NG;
2850 }
2851 }
2852 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2853 code_index += len;
2854 break;
2855 }
2856 case ISEQ_ELEMENT_LABEL:
2857 {
2858 LABEL *lobj = (LABEL *)list;
2859 if (lobj->sp != sp) {
2860 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2861 RSTRING_PTR(rb_iseq_path(iseq)),
2862 lobj->label_no, lobj->sp, sp);
2863 }
2864 sp = lobj->sp;
2865 break;
2866 }
2867 case ISEQ_ELEMENT_ADJUST:
2868 {
2869 ADJUST *adjust = (ADJUST *)list;
2870 int orig_sp = sp;
2871
2872 if (adjust->label) {
2873 sp = adjust->label->sp;
2874 }
2875 else {
2876 sp = 0;
2877 }
2878
2879 if (adjust->line_no != -1) {
2880 const int diff = orig_sp - sp;
2881 if (diff > 0) {
2882 if (insns_info_index == 0) {
2883 COMPILE_ERROR(iseq, adjust->line_no,
2884 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2885 }
2886 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2887 }
2888 if (diff > 1) {
2889 generated_iseq[code_index++] = BIN(adjuststack);
2890 generated_iseq[code_index++] = orig_sp - sp;
2891 }
2892 else if (diff == 1) {
2893 generated_iseq[code_index++] = BIN(pop);
2894 }
2895 else if (diff < 0) {
2896 int label_no = adjust->label ? adjust->label->label_no : -1;
2897 xfree(generated_iseq);
2898 xfree(insns_info);
2899 xfree(positions);
2900 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2901 xfree(mark_offset_bits);
2902 }
2903 debug_list(anchor, list);
2904 COMPILE_ERROR(iseq, adjust->line_no,
2905 "iseq_set_sequence: adjust bug to %d %d < %d",
2906 label_no, orig_sp, sp);
2907 return COMPILE_NG;
2908 }
2909 }
2910 break;
2911 }
2912 default:
2913 /* ignore */
2914 break;
2915 }
2916 list = list->next;
2917 }
2918
2919 body->iseq_encoded = (void *)generated_iseq;
2920 body->iseq_size = code_index;
2921 body->stack_max = stack_max;
2922
2923 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2924 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2925 }
2926 else {
2927 if (needs_bitmap) {
2928 body->mark_bits.list = mark_offset_bits;
2929 }
2930 else {
2931 body->mark_bits.list = NULL;
2932 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2933 ruby_xfree(mark_offset_bits);
2934 }
2935 }
2936
2937 /* get rid of memory leak when REALLOC failed */
2938 body->insns_info.body = insns_info;
2939 body->insns_info.positions = positions;
2940
2941 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2942 body->insns_info.body = insns_info;
2943 REALLOC_N(positions, unsigned int, insns_info_index);
2944 body->insns_info.positions = positions;
2945 body->insns_info.size = insns_info_index;
2946
2947 return COMPILE_OK;
2948}
2949
2950static int
2951label_get_position(LABEL *lobj)
2952{
2953 return lobj->position;
2954}
2955
2956static int
2957label_get_sp(LABEL *lobj)
2958{
2959 return lobj->sp;
2960}
2961
2962static int
2963iseq_set_exception_table(rb_iseq_t *iseq)
2964{
2965 const VALUE *tptr, *ptr;
2966 unsigned int tlen, i;
2967 struct iseq_catch_table_entry *entry;
2968
2969 ISEQ_BODY(iseq)->catch_table = NULL;
2970
2971 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2972 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2973 tlen = (int)RARRAY_LEN(catch_table_ary);
2974 tptr = RARRAY_CONST_PTR(catch_table_ary);
2975
2976 if (tlen > 0) {
2977 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2978 table->size = tlen;
2979
2980 for (i = 0; i < table->size; i++) {
2981 int pos;
2982 ptr = RARRAY_CONST_PTR(tptr[i]);
2983 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2984 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2985 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2986 RUBY_ASSERT(pos >= 0);
2987 entry->start = (unsigned int)pos;
2988 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2989 RUBY_ASSERT(pos >= 0);
2990 entry->end = (unsigned int)pos;
2991 entry->iseq = (rb_iseq_t *)ptr[3];
2992 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2993
2994 /* stack depth */
2995 if (ptr[4]) {
2996 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2997 entry->cont = label_get_position(lobj);
2998 entry->sp = label_get_sp(lobj);
2999
3000 /* TODO: Dirty Hack! Fix me */
3001 if (entry->type == CATCH_TYPE_RESCUE ||
3002 entry->type == CATCH_TYPE_BREAK ||
3003 entry->type == CATCH_TYPE_NEXT) {
3004 RUBY_ASSERT(entry->sp > 0);
3005 entry->sp--;
3006 }
3007 }
3008 else {
3009 entry->cont = 0;
3010 }
3011 }
3012 ISEQ_BODY(iseq)->catch_table = table;
3013 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3014 }
3015
3016 RB_GC_GUARD(catch_table_ary);
3017
3018 return COMPILE_OK;
3019}
3020
3021/*
3022 * set optional argument table
3023 * def foo(a, b=expr1, c=expr2)
3024 * =>
3025 * b:
3026 * expr1
3027 * c:
3028 * expr2
3029 */
3030static int
3031iseq_set_optargs_table(rb_iseq_t *iseq)
3032{
3033 int i;
3034 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3035
3036 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3037 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3038 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3039 }
3040 }
3041 return COMPILE_OK;
3042}
3043
3044static LINK_ELEMENT *
3045get_destination_insn(INSN *iobj)
3046{
3047 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3048 LINK_ELEMENT *list;
3049 rb_event_flag_t events = 0;
3050
3051 list = lobj->link.next;
3052 while (list) {
3053 switch (list->type) {
3054 case ISEQ_ELEMENT_INSN:
3055 case ISEQ_ELEMENT_ADJUST:
3056 goto found;
3057 case ISEQ_ELEMENT_LABEL:
3058 /* ignore */
3059 break;
3060 case ISEQ_ELEMENT_TRACE:
3061 {
3062 TRACE *trace = (TRACE *)list;
3063 events |= trace->event;
3064 }
3065 break;
3066 default: break;
3067 }
3068 list = list->next;
3069 }
3070 found:
3071 if (list && IS_INSN(list)) {
3072 INSN *iobj = (INSN *)list;
3073 iobj->insn_info.events |= events;
3074 }
3075 return list;
3076}
3077
3078static LINK_ELEMENT *
3079get_next_insn(INSN *iobj)
3080{
3081 LINK_ELEMENT *list = iobj->link.next;
3082
3083 while (list) {
3084 if (IS_INSN(list) || IS_ADJUST(list)) {
3085 return list;
3086 }
3087 list = list->next;
3088 }
3089 return 0;
3090}
3091
3092static LINK_ELEMENT *
3093get_prev_insn(INSN *iobj)
3094{
3095 LINK_ELEMENT *list = iobj->link.prev;
3096
3097 while (list) {
3098 if (IS_INSN(list) || IS_ADJUST(list)) {
3099 return list;
3100 }
3101 list = list->prev;
3102 }
3103 return 0;
3104}
3105
3106static void
3107unref_destination(INSN *iobj, int pos)
3108{
3109 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3110 --lobj->refcnt;
3111 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3112}
3113
3114static bool
3115replace_destination(INSN *dobj, INSN *nobj)
3116{
3117 VALUE n = OPERAND_AT(nobj, 0);
3118 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3119 LABEL *nl = (LABEL *)n;
3120 if (dl == nl) return false;
3121 --dl->refcnt;
3122 ++nl->refcnt;
3123 OPERAND_AT(dobj, 0) = n;
3124 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3125 return true;
3126}
3127
3128static LABEL*
3129find_destination(INSN *i)
3130{
3131 int pos, len = insn_len(i->insn_id);
3132 for (pos = 0; pos < len; ++pos) {
3133 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3134 return (LABEL *)OPERAND_AT(i, pos);
3135 }
3136 }
3137 return 0;
3138}
3139
3140static int
3141remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3142{
3143 LINK_ELEMENT *first = i, *end;
3144 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3145
3146 if (!i) return 0;
3147 unref_counts = ALLOCA_N(int, nlabels);
3148 MEMZERO(unref_counts, int, nlabels);
3149 end = i;
3150 do {
3151 LABEL *lab;
3152 if (IS_INSN(i)) {
3153 if (IS_INSN_ID(i, leave)) {
3154 end = i;
3155 break;
3156 }
3157 else if ((lab = find_destination((INSN *)i)) != 0) {
3158 unref_counts[lab->label_no]++;
3159 }
3160 }
3161 else if (IS_LABEL(i)) {
3162 lab = (LABEL *)i;
3163 if (lab->unremovable) return 0;
3164 if (lab->refcnt > unref_counts[lab->label_no]) {
3165 if (i == first) return 0;
3166 break;
3167 }
3168 continue;
3169 }
3170 else if (IS_TRACE(i)) {
3171 /* do nothing */
3172 }
3173 else if (IS_ADJUST(i)) {
3174 return 0;
3175 }
3176 end = i;
3177 } while ((i = i->next) != 0);
3178 i = first;
3179 do {
3180 if (IS_INSN(i)) {
3181 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3182 VALUE insn = INSN_OF(i);
3183 int pos, len = insn_len(insn);
3184 for (pos = 0; pos < len; ++pos) {
3185 switch (insn_op_types(insn)[pos]) {
3186 case TS_OFFSET:
3187 unref_destination((INSN *)i, pos);
3188 break;
3189 case TS_CALLDATA:
3190 --(body->ci_size);
3191 break;
3192 }
3193 }
3194 }
3195 ELEM_REMOVE(i);
3196 } while ((i != end) && (i = i->next) != 0);
3197 return 1;
3198}
3199
3200static int
3201iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3202{
3203 switch (OPERAND_AT(iobj, 0)) {
3204 case INT2FIX(0): /* empty array */
3205 ELEM_REMOVE(&iobj->link);
3206 return TRUE;
3207 case INT2FIX(1): /* single element array */
3208 ELEM_REMOVE(&iobj->link);
3209 return FALSE;
3210 default:
3211 iobj->insn_id = BIN(adjuststack);
3212 return TRUE;
3213 }
3214}
3215
3216static int
3217is_frozen_putstring(INSN *insn, VALUE *op)
3218{
3219 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3220 *op = OPERAND_AT(insn, 0);
3221 return 1;
3222 }
3223 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3224 *op = OPERAND_AT(insn, 0);
3225 return RB_TYPE_P(*op, T_STRING);
3226 }
3227 return 0;
3228}
3229
3230static int
3231insn_has_label_before(LINK_ELEMENT *elem)
3232{
3233 LINK_ELEMENT *prev = elem->prev;
3234 while (prev) {
3235 if (prev->type == ISEQ_ELEMENT_LABEL) {
3236 LABEL *label = (LABEL *)prev;
3237 if (label->refcnt > 0) {
3238 return 1;
3239 }
3240 }
3241 else if (prev->type == ISEQ_ELEMENT_INSN) {
3242 break;
3243 }
3244 prev = prev->prev;
3245 }
3246 return 0;
3247}
3248
3249static int
3250optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3251{
3252 /*
3253 * putobject obj
3254 * dup
3255 * checktype T_XXX
3256 * branchif l1
3257 * l2:
3258 * ...
3259 * l1:
3260 *
3261 * => obj is a T_XXX
3262 *
3263 * putobject obj (T_XXX)
3264 * jump L1
3265 * L1:
3266 *
3267 * => obj is not a T_XXX
3268 *
3269 * putobject obj (T_XXX)
3270 * jump L2
3271 * L2:
3272 */
3273 int line, node_id;
3274 INSN *niobj, *ciobj, *dup = 0;
3275 LABEL *dest = 0;
3276 VALUE type;
3277
3278 switch (INSN_OF(iobj)) {
3279 case BIN(putstring):
3280 case BIN(putchilledstring):
3282 break;
3283 case BIN(putnil):
3284 type = INT2FIX(T_NIL);
3285 break;
3286 case BIN(putobject):
3287 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3288 break;
3289 default: return FALSE;
3290 }
3291
3292 ciobj = (INSN *)get_next_insn(iobj);
3293 if (IS_INSN_ID(ciobj, jump)) {
3294 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3295 }
3296 if (IS_INSN_ID(ciobj, dup)) {
3297 ciobj = (INSN *)get_next_insn(dup = ciobj);
3298 }
3299 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3300 niobj = (INSN *)get_next_insn(ciobj);
3301 if (!niobj) {
3302 /* TODO: putobject true/false */
3303 return FALSE;
3304 }
3305 switch (INSN_OF(niobj)) {
3306 case BIN(branchif):
3307 if (OPERAND_AT(ciobj, 0) == type) {
3308 dest = (LABEL *)OPERAND_AT(niobj, 0);
3309 }
3310 break;
3311 case BIN(branchunless):
3312 if (OPERAND_AT(ciobj, 0) != type) {
3313 dest = (LABEL *)OPERAND_AT(niobj, 0);
3314 }
3315 break;
3316 default:
3317 return FALSE;
3318 }
3319 line = ciobj->insn_info.line_no;
3320 node_id = ciobj->insn_info.node_id;
3321 if (!dest) {
3322 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3323 dest = (LABEL *)niobj->link.next; /* reuse label */
3324 }
3325 else {
3326 dest = NEW_LABEL(line);
3327 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3328 }
3329 }
3330 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3331 LABEL_REF(dest);
3332 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3333 return TRUE;
3334}
3335
3336static const struct rb_callinfo *
3337ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3338{
3339 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3340 vm_ci_flag(ci) | add,
3341 vm_ci_argc(ci),
3342 vm_ci_kwarg(ci));
3343 RB_OBJ_WRITTEN(iseq, ci, nci);
3344 return nci;
3345}
3346
3347static const struct rb_callinfo *
3348ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3349{
3350 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3351 vm_ci_flag(ci),
3352 argc,
3353 vm_ci_kwarg(ci));
3354 RB_OBJ_WRITTEN(iseq, ci, nci);
3355 return nci;
3356}
3357
3358#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3359
3360static int
3361iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3362{
3363 INSN *const iobj = (INSN *)list;
3364
3365 again:
3366 optimize_checktype(iseq, iobj);
3367
3368 if (IS_INSN_ID(iobj, jump)) {
3369 INSN *niobj, *diobj, *piobj;
3370 diobj = (INSN *)get_destination_insn(iobj);
3371 niobj = (INSN *)get_next_insn(iobj);
3372
3373 if (diobj == niobj) {
3374 /*
3375 * jump LABEL
3376 * LABEL:
3377 * =>
3378 * LABEL:
3379 */
3380 unref_destination(iobj, 0);
3381 ELEM_REMOVE(&iobj->link);
3382 return COMPILE_OK;
3383 }
3384 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3385 IS_INSN_ID(diobj, jump) &&
3386 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3387 diobj->insn_info.events == 0) {
3388 /*
3389 * useless jump elimination:
3390 * jump LABEL1
3391 * ...
3392 * LABEL1:
3393 * jump LABEL2
3394 *
3395 * => in this case, first jump instruction should jump to
3396 * LABEL2 directly
3397 */
3398 if (replace_destination(iobj, diobj)) {
3399 remove_unreachable_chunk(iseq, iobj->link.next);
3400 goto again;
3401 }
3402 }
3403 else if (IS_INSN_ID(diobj, leave)) {
3404 /*
3405 * jump LABEL
3406 * ...
3407 * LABEL:
3408 * leave
3409 * =>
3410 * leave
3411 * ...
3412 * LABEL:
3413 * leave
3414 */
3415 /* replace */
3416 unref_destination(iobj, 0);
3417 iobj->insn_id = BIN(leave);
3418 iobj->operand_size = 0;
3419 iobj->insn_info = diobj->insn_info;
3420 goto again;
3421 }
3422 else if (IS_INSN(iobj->link.prev) &&
3423 (piobj = (INSN *)iobj->link.prev) &&
3424 (IS_INSN_ID(piobj, branchif) ||
3425 IS_INSN_ID(piobj, branchunless))) {
3426 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3427 if (niobj == pdiobj) {
3428 int refcnt = IS_LABEL(piobj->link.next) ?
3429 ((LABEL *)piobj->link.next)->refcnt : 0;
3430 /*
3431 * useless jump elimination (if/unless destination):
3432 * if L1
3433 * jump L2
3434 * L1:
3435 * ...
3436 * L2:
3437 *
3438 * ==>
3439 * unless L2
3440 * L1:
3441 * ...
3442 * L2:
3443 */
3444 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3445 ? BIN(branchunless) : BIN(branchif);
3446 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3447 ELEM_REMOVE(&iobj->link);
3448 }
3449 else {
3450 /* TODO: replace other branch destinations too */
3451 }
3452 return COMPILE_OK;
3453 }
3454 else if (diobj == pdiobj) {
3455 /*
3456 * useless jump elimination (if/unless before jump):
3457 * L1:
3458 * ...
3459 * if L1
3460 * jump L1
3461 *
3462 * ==>
3463 * L1:
3464 * ...
3465 * pop
3466 * jump L1
3467 */
3468 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3469 ELEM_REPLACE(&piobj->link, &popiobj->link);
3470 }
3471 }
3472 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3473 goto again;
3474 }
3475 }
3476
3477 /*
3478 * putstring "beg"
3479 * putstring "end"
3480 * newrange excl
3481 *
3482 * ==>
3483 *
3484 * putobject "beg".."end"
3485 */
3486 if (IS_INSN_ID(iobj, newrange)) {
3487 INSN *const range = iobj;
3488 INSN *beg, *end;
3489 VALUE str_beg, str_end;
3490
3491 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3492 is_frozen_putstring(end, &str_end) &&
3493 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3494 is_frozen_putstring(beg, &str_beg) &&
3495 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3496 int excl = FIX2INT(OPERAND_AT(range, 0));
3497 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3498
3499 ELEM_REMOVE(&beg->link);
3500 ELEM_REMOVE(&end->link);
3501 range->insn_id = BIN(putobject);
3502 OPERAND_AT(range, 0) = lit_range;
3503 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3504 }
3505 }
3506
3507 if (IS_INSN_ID(iobj, leave)) {
3508 remove_unreachable_chunk(iseq, iobj->link.next);
3509 }
3510
3511 /*
3512 * ...
3513 * duparray [...]
3514 * concatarray | concattoarray
3515 * =>
3516 * ...
3517 * putobject [...]
3518 * concatarray | concattoarray
3519 */
3520 if (IS_INSN_ID(iobj, duparray)) {
3521 LINK_ELEMENT *next = iobj->link.next;
3522 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3523 iobj->insn_id = BIN(putobject);
3524 }
3525 }
3526
3527 /*
3528 * duparray [...]
3529 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3530 * =>
3531 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3532 */
3533 if (IS_INSN_ID(iobj, duparray)) {
3534 LINK_ELEMENT *next = iobj->link.next;
3535 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3536 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3537 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3538
3539 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3540 VALUE ary = iobj->operands[0];
3542
3543 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3544 ELEM_REMOVE(next);
3545 }
3546 }
3547 }
3548
3549 /*
3550 * duphash {...}
3551 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3552 * =>
3553 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3554 */
3555 if (IS_INSN_ID(iobj, duphash)) {
3556 LINK_ELEMENT *next = iobj->link.next;
3557 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3558 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3559 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3560
3561 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3562 VALUE hash = iobj->operands[0];
3563 rb_obj_reveal(hash, rb_cHash);
3564 RB_OBJ_SET_SHAREABLE(hash);
3565
3566 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3567 ELEM_REMOVE(next);
3568 }
3569 }
3570 }
3571
3572 /*
3573 * newarray 0
3574 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3575 * =>
3576 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3577 */
3578 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3579 LINK_ELEMENT *next = iobj->link.next;
3580 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3581 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3582 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3583
3584 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3585 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3586 ELEM_REMOVE(next);
3587 }
3588 }
3589 }
3590
3591 /*
3592 * newhash 0
3593 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3594 * =>
3595 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3596 */
3597 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3598 LINK_ELEMENT *next = iobj->link.next;
3599 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3600 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3601 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3602
3603 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3604 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3605 ELEM_REMOVE(next);
3606 }
3607 }
3608 }
3609
3610 if (IS_INSN_ID(iobj, branchif) ||
3611 IS_INSN_ID(iobj, branchnil) ||
3612 IS_INSN_ID(iobj, branchunless)) {
3613 /*
3614 * if L1
3615 * ...
3616 * L1:
3617 * jump L2
3618 * =>
3619 * if L2
3620 */
3621 INSN *nobj = (INSN *)get_destination_insn(iobj);
3622
3623 /* This is super nasty hack!!!
3624 *
3625 * This jump-jump optimization may ignore event flags of the jump
3626 * instruction being skipped. Actually, Line 2 TracePoint event
3627 * is never fired in the following code:
3628 *
3629 * 1: raise if 1 == 2
3630 * 2: while true
3631 * 3: break
3632 * 4: end
3633 *
3634 * This is critical for coverage measurement. [Bug #15980]
3635 *
3636 * This is a stopgap measure: stop the jump-jump optimization if
3637 * coverage measurement is enabled and if the skipped instruction
3638 * has any event flag.
3639 *
3640 * Note that, still, TracePoint Line event does not occur on Line 2.
3641 * This should be fixed in future.
3642 */
3643 int stop_optimization =
3644 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3645 nobj->link.type == ISEQ_ELEMENT_INSN &&
3646 nobj->insn_info.events;
3647 if (!stop_optimization) {
3648 INSN *pobj = (INSN *)iobj->link.prev;
3649 int prev_dup = 0;
3650 if (pobj) {
3651 if (!IS_INSN(&pobj->link))
3652 pobj = 0;
3653 else if (IS_INSN_ID(pobj, dup))
3654 prev_dup = 1;
3655 }
3656
3657 for (;;) {
3658 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3659 if (!replace_destination(iobj, nobj)) break;
3660 }
3661 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3662 !!(nobj = (INSN *)nobj->link.next) &&
3663 /* basic blocks, with no labels in the middle */
3664 nobj->insn_id == iobj->insn_id) {
3665 /*
3666 * dup
3667 * if L1
3668 * ...
3669 * L1:
3670 * dup
3671 * if L2
3672 * =>
3673 * dup
3674 * if L2
3675 * ...
3676 * L1:
3677 * dup
3678 * if L2
3679 */
3680 if (!replace_destination(iobj, nobj)) break;
3681 }
3682 else if (pobj) {
3683 /*
3684 * putnil
3685 * if L1
3686 * =>
3687 * # nothing
3688 *
3689 * putobject true
3690 * if L1
3691 * =>
3692 * jump L1
3693 *
3694 * putstring ".."
3695 * if L1
3696 * =>
3697 * jump L1
3698 *
3699 * putstring ".."
3700 * dup
3701 * if L1
3702 * =>
3703 * putstring ".."
3704 * jump L1
3705 *
3706 */
3707 int cond;
3708 if (prev_dup && IS_INSN(pobj->link.prev)) {
3709 pobj = (INSN *)pobj->link.prev;
3710 }
3711 if (IS_INSN_ID(pobj, putobject)) {
3712 cond = (IS_INSN_ID(iobj, branchif) ?
3713 OPERAND_AT(pobj, 0) != Qfalse :
3714 IS_INSN_ID(iobj, branchunless) ?
3715 OPERAND_AT(pobj, 0) == Qfalse :
3716 FALSE);
3717 }
3718 else if (IS_INSN_ID(pobj, putstring) ||
3719 IS_INSN_ID(pobj, duparray) ||
3720 IS_INSN_ID(pobj, newarray)) {
3721 cond = IS_INSN_ID(iobj, branchif);
3722 }
3723 else if (IS_INSN_ID(pobj, putnil)) {
3724 cond = !IS_INSN_ID(iobj, branchif);
3725 }
3726 else break;
3727 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3728 ELEM_REMOVE(iobj->link.prev);
3729 }
3730 else if (!iseq_pop_newarray(iseq, pobj)) {
3731 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3732 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3733 }
3734 if (cond) {
3735 if (prev_dup) {
3736 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3737 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3738 }
3739 iobj->insn_id = BIN(jump);
3740 goto again;
3741 }
3742 else {
3743 unref_destination(iobj, 0);
3744 ELEM_REMOVE(&iobj->link);
3745 }
3746 break;
3747 }
3748 else break;
3749 nobj = (INSN *)get_destination_insn(nobj);
3750 }
3751 }
3752 }
3753
3754 if (IS_INSN_ID(iobj, pop)) {
3755 /*
3756 * putself / putnil / putobject obj / putstring "..."
3757 * pop
3758 * =>
3759 * # do nothing
3760 */
3761 LINK_ELEMENT *prev = iobj->link.prev;
3762 if (IS_INSN(prev)) {
3763 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3764 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3765 previ == BIN(putself) || previ == BIN(putstring) ||
3766 previ == BIN(putchilledstring) ||
3767 previ == BIN(dup) ||
3768 previ == BIN(getlocal) ||
3769 previ == BIN(getblockparam) ||
3770 previ == BIN(getblockparamproxy) ||
3771 previ == BIN(getinstancevariable) ||
3772 previ == BIN(duparray)) {
3773 /* just push operand or static value and pop soon, no
3774 * side effects */
3775 ELEM_REMOVE(prev);
3776 ELEM_REMOVE(&iobj->link);
3777 }
3778 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3779 ELEM_REMOVE(&iobj->link);
3780 }
3781 else if (previ == BIN(concatarray)) {
3782 INSN *piobj = (INSN *)prev;
3783 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3784 INSN_OF(piobj) = BIN(pop);
3785 }
3786 else if (previ == BIN(concatstrings)) {
3787 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3788 ELEM_REMOVE(prev);
3789 }
3790 else {
3791 ELEM_REMOVE(&iobj->link);
3792 INSN_OF(prev) = BIN(adjuststack);
3793 }
3794 }
3795 }
3796 }
3797
3798 if (IS_INSN_ID(iobj, newarray) ||
3799 IS_INSN_ID(iobj, duparray) ||
3800 IS_INSN_ID(iobj, concatarray) ||
3801 IS_INSN_ID(iobj, splatarray) ||
3802 0) {
3803 /*
3804 * newarray N
3805 * splatarray
3806 * =>
3807 * newarray N
3808 * newarray always puts an array
3809 */
3810 LINK_ELEMENT *next = iobj->link.next;
3811 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3812 /* remove splatarray following always-array insn */
3813 ELEM_REMOVE(next);
3814 }
3815 }
3816
3817 if (IS_INSN_ID(iobj, newarray)) {
3818 LINK_ELEMENT *next = iobj->link.next;
3819 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3820 OPERAND_AT(next, 1) == INT2FIX(0)) {
3821 VALUE op1, op2;
3822 op1 = OPERAND_AT(iobj, 0);
3823 op2 = OPERAND_AT(next, 0);
3824 ELEM_REMOVE(next);
3825
3826 if (op1 == op2) {
3827 /*
3828 * newarray 2
3829 * expandarray 2, 0
3830 * =>
3831 * swap
3832 */
3833 if (op1 == INT2FIX(2)) {
3834 INSN_OF(iobj) = BIN(swap);
3835 iobj->operand_size = 0;
3836 }
3837 /*
3838 * newarray X
3839 * expandarray X, 0
3840 * =>
3841 * opt_reverse X
3842 */
3843 else {
3844 INSN_OF(iobj) = BIN(opt_reverse);
3845 }
3846 }
3847 else {
3848 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3849 INSN_OF(iobj) = BIN(opt_reverse);
3850 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3851
3852 if (op1 > op2) {
3853 /* X > Y
3854 * newarray X
3855 * expandarray Y, 0
3856 * =>
3857 * pop * (Y-X)
3858 * opt_reverse Y
3859 */
3860 for (; diff > 0; diff--) {
3861 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3862 }
3863 }
3864 else { /* (op1 < op2) */
3865 /* X < Y
3866 * newarray X
3867 * expandarray Y, 0
3868 * =>
3869 * putnil * (Y-X)
3870 * opt_reverse Y
3871 */
3872 for (; diff < 0; diff++) {
3873 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3874 }
3875 }
3876 }
3877 }
3878 }
3879
3880 if (IS_INSN_ID(iobj, duparray)) {
3881 LINK_ELEMENT *next = iobj->link.next;
3882 /*
3883 * duparray obj
3884 * expandarray X, 0
3885 * =>
3886 * putobject obj
3887 * expandarray X, 0
3888 */
3889 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3890 INSN_OF(iobj) = BIN(putobject);
3891 }
3892 }
3893
3894 if (IS_INSN_ID(iobj, anytostring)) {
3895 LINK_ELEMENT *next = iobj->link.next;
3896 /*
3897 * anytostring
3898 * concatstrings 1
3899 * =>
3900 * anytostring
3901 */
3902 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3903 OPERAND_AT(next, 0) == INT2FIX(1)) {
3904 ELEM_REMOVE(next);
3905 }
3906 }
3907
3908 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3909 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3910 /*
3911 * putstring ""
3912 * concatstrings N
3913 * =>
3914 * concatstrings N-1
3915 */
3916 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3917 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3918 INSN *next = (INSN *)iobj->link.next;
3919 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3920 ELEM_REMOVE(&next->link);
3921 }
3922 ELEM_REMOVE(&iobj->link);
3923 }
3924 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3925 INSN *next = (INSN *)iobj->link.next;
3926 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3927 VALUE src = OPERAND_AT(iobj, 0);
3928 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3929 VALUE path = rb_iseq_path(iseq);
3930 int line = iobj->insn_info.line_no;
3931 VALUE errinfo = rb_errinfo();
3932 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3933 if (NIL_P(re)) {
3934 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3935 rb_set_errinfo(errinfo);
3936 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3937 }
3938 else {
3939 RB_OBJ_SET_SHAREABLE(re);
3940 }
3941 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3942 ELEM_REMOVE(iobj->link.next);
3943 }
3944 }
3945 }
3946
3947 if (IS_INSN_ID(iobj, concatstrings)) {
3948 /*
3949 * concatstrings N
3950 * concatstrings M
3951 * =>
3952 * concatstrings N+M-1
3953 */
3954 LINK_ELEMENT *next = iobj->link.next;
3955 INSN *jump = 0;
3956 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3957 next = get_destination_insn(jump = (INSN *)next);
3958 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3959 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3960 OPERAND_AT(iobj, 0) = INT2FIX(n);
3961 if (jump) {
3962 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3963 if (!--label->refcnt) {
3964 ELEM_REMOVE(&label->link);
3965 }
3966 else {
3967 label = NEW_LABEL(0);
3968 OPERAND_AT(jump, 0) = (VALUE)label;
3969 }
3970 label->refcnt++;
3971 ELEM_INSERT_NEXT(next, &label->link);
3972 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3973 }
3974 else {
3975 ELEM_REMOVE(next);
3976 }
3977 }
3978 }
3979
3980 if (do_tailcallopt &&
3981 (IS_INSN_ID(iobj, send) ||
3982 IS_INSN_ID(iobj, invokesuper))) {
3983 /*
3984 * send ...
3985 * leave
3986 * =>
3987 * send ..., ... | VM_CALL_TAILCALL, ...
3988 * leave # unreachable
3989 */
3990 INSN *piobj = NULL;
3991 if (iobj->link.next) {
3992 LINK_ELEMENT *next = iobj->link.next;
3993 do {
3994 if (!IS_INSN(next)) {
3995 next = next->next;
3996 continue;
3997 }
3998 switch (INSN_OF(next)) {
3999 case BIN(nop):
4000 next = next->next;
4001 break;
4002 case BIN(jump):
4003 /* if cond
4004 * return tailcall
4005 * end
4006 */
4007 next = get_destination_insn((INSN *)next);
4008 break;
4009 case BIN(leave):
4010 piobj = iobj;
4011 /* fall through */
4012 default:
4013 next = NULL;
4014 break;
4015 }
4016 } while (next);
4017 }
4018
4019 if (piobj) {
4020 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4021 if (IS_INSN_ID(piobj, send) ||
4022 IS_INSN_ID(piobj, invokesuper)) {
4023 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4024 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4025 OPERAND_AT(piobj, 0) = (VALUE)ci;
4026 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4027 }
4028 }
4029 else {
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 }
4036
4037 if (IS_INSN_ID(iobj, dup)) {
4038 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4039 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4040
4041 /*
4042 * dup
4043 * setlocal x, y
4044 * setlocal x, y
4045 * =>
4046 * dup
4047 * setlocal x, y
4048 */
4049 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4050 set2 = set1->next;
4051 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4052 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4053 ELEM_REMOVE(set1);
4054 ELEM_REMOVE(&iobj->link);
4055 }
4056 }
4057
4058 /*
4059 * dup
4060 * setlocal x, y
4061 * dup
4062 * setlocal x, y
4063 * =>
4064 * dup
4065 * setlocal x, y
4066 */
4067 else if (IS_NEXT_INSN_ID(set1, dup) &&
4068 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4069 set2 = set1->next->next;
4070 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4071 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4072 ELEM_REMOVE(set1->next);
4073 ELEM_REMOVE(set2);
4074 }
4075 }
4076 }
4077 }
4078
4079 /*
4080 * getlocal x, y
4081 * dup
4082 * setlocal x, y
4083 * =>
4084 * dup
4085 */
4086 if (IS_INSN_ID(iobj, getlocal)) {
4087 LINK_ELEMENT *niobj = &iobj->link;
4088 if (IS_NEXT_INSN_ID(niobj, dup)) {
4089 niobj = niobj->next;
4090 }
4091 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4092 LINK_ELEMENT *set1 = niobj->next;
4093 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4094 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4095 ELEM_REMOVE(set1);
4096 ELEM_REMOVE(niobj);
4097 }
4098 }
4099 }
4100
4101 /*
4102 * opt_invokebuiltin_delegate
4103 * trace
4104 * leave
4105 * =>
4106 * opt_invokebuiltin_delegate_leave
4107 * trace
4108 * leave
4109 */
4110 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4111 if (IS_TRACE(iobj->link.next)) {
4112 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4113 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4114 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4115 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4116 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4117 }
4118 }
4119 }
4120 }
4121
4122 /*
4123 * getblockparam
4124 * branchif / branchunless
4125 * =>
4126 * getblockparamproxy
4127 * branchif / branchunless
4128 */
4129 if (IS_INSN_ID(iobj, getblockparam)) {
4130 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4131 iobj->insn_id = BIN(getblockparamproxy);
4132 }
4133 }
4134
4135 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4136 LINK_ELEMENT *niobj = &iobj->link;
4137 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4138 niobj = niobj->next;
4139 LINK_ELEMENT *siobj;
4140 unsigned int set_flags = 0, unset_flags = 0;
4141
4142 /*
4143 * Eliminate hash allocation for f(*a, kw: 1)
4144 *
4145 * splatarray false
4146 * duphash
4147 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4148 * =>
4149 * splatarray false
4150 * putobject
4151 * send ARGS_SPLAT|KW_SPLAT
4152 */
4153 if (IS_NEXT_INSN_ID(niobj, send)) {
4154 siobj = niobj->next;
4155 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4156 unset_flags = VM_CALL_ARGS_BLOCKARG;
4157 }
4158 /*
4159 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4160 *
4161 * splatarray false
4162 * duphash
4163 * getlocal / getinstancevariable / getblockparamproxy
4164 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4165 * =>
4166 * splatarray false
4167 * putobject
4168 * getlocal / getinstancevariable / getblockparamproxy
4169 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4170 */
4171 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4172 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4173 siobj = niobj->next->next;
4174 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4175 }
4176
4177 if (set_flags) {
4178 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4179 unsigned int flags = vm_ci_flag(ci);
4180 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4181 ((INSN*)niobj)->insn_id = BIN(putobject);
4182 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4183
4184 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4185 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4186 RB_OBJ_WRITTEN(iseq, ci, nci);
4187 OPERAND_AT(siobj, 0) = (VALUE)nci;
4188 }
4189 }
4190 }
4191 }
4192
4193 return COMPILE_OK;
4194}
4195
4196static int
4197insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4198{
4199 if (insn_id == BIN(opt_neq)) {
4200 VALUE original_ci = iobj->operands[0];
4201 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4202 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4203 }
4204 else {
4205 iobj->insn_id = insn_id;
4206 iobj->operand_size = insn_len(insn_id) - 1;
4207 }
4208 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4209
4210 return COMPILE_OK;
4211}
4212
4213static int
4214iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4215{
4216 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4217 IS_INSN(iobj->link.next)) {
4218 /*
4219 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4220 */
4221 INSN *niobj = (INSN *)iobj->link.next;
4222 if (IS_INSN_ID(niobj, send)) {
4223 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4224 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4225 VALUE method = INT2FIX(0);
4226 switch (vm_ci_mid(ci)) {
4227 case idMax:
4228 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4229 break;
4230 case idMin:
4231 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4232 break;
4233 case idHash:
4234 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4235 break;
4236 }
4237
4238 if (method != INT2FIX(0)) {
4239 VALUE num = iobj->operands[0];
4240 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4241 ELEM_REMOVE(&niobj->link);
4242 return COMPILE_OK;
4243 }
4244 }
4245 }
4246 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4247 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4248 IS_NEXT_INSN_ID(&niobj->link, send)) {
4249 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4250 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4251 VALUE num = iobj->operands[0];
4252 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4253 ELEM_REMOVE(&iobj->link);
4254 ELEM_REMOVE(niobj->link.next);
4255 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4256 return COMPILE_OK;
4257 }
4258 }
4259 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4260 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4261 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4262 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4263 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4264 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4265 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4266 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4267 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4268 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4269 VALUE num = iobj->operands[0];
4270 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4271 // Remove the "send" insn.
4272 ELEM_REMOVE((niobj->link.next)->next);
4273 // Remove the modified insn from its original "newarray" position...
4274 ELEM_REMOVE(&iobj->link);
4275 // and insert it after the buffer insn.
4276 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4277 return COMPILE_OK;
4278 }
4279 }
4280
4281 // Break the "else if" chain since some prior checks abort after sub-ifs.
4282 // We already found "newarray". To match `[...].include?(arg)` we look for
4283 // the instruction(s) representing the argument followed by a "send".
4284 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4285 IS_INSN_ID(niobj, putobject) ||
4286 IS_INSN_ID(niobj, putself) ||
4287 IS_INSN_ID(niobj, getlocal) ||
4288 IS_INSN_ID(niobj, getinstancevariable)) &&
4289 IS_NEXT_INSN_ID(&niobj->link, send)) {
4290
4291 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4292 const struct rb_callinfo *ci;
4293 // Allow any number (0 or more) of simple method calls on the argument
4294 // (as in `[...].include?(arg.method1.method2)`.
4295 do {
4296 sendobj = sendobj->next;
4297 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4298 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4299
4300 // If this send is for .include? with one arg we can do our opt.
4301 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4302 VALUE num = iobj->operands[0];
4303 INSN *sendins = (INSN *)sendobj;
4304 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4305 // Remove the original "newarray" insn.
4306 ELEM_REMOVE(&iobj->link);
4307 return COMPILE_OK;
4308 }
4309 }
4310 }
4311
4312 /*
4313 * duparray [...]
4314 * some insn for the arg...
4315 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4316 * =>
4317 * arg insn...
4318 * opt_duparray_send [...], :include?, 1
4319 */
4320 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4321 INSN *niobj = (INSN *)iobj->link.next;
4322 if ((IS_INSN_ID(niobj, getlocal) ||
4323 IS_INSN_ID(niobj, getinstancevariable) ||
4324 IS_INSN_ID(niobj, putself)) &&
4325 IS_NEXT_INSN_ID(&niobj->link, send)) {
4326
4327 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4328 const struct rb_callinfo *ci;
4329 // Allow any number (0 or more) of simple method calls on the argument
4330 // (as in `[...].include?(arg.method1.method2)`.
4331 do {
4332 sendobj = sendobj->next;
4333 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4334 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4335
4336 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4337 // Move the array arg from duparray to opt_duparray_send.
4338 VALUE ary = iobj->operands[0];
4340
4341 INSN *sendins = (INSN *)sendobj;
4342 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4343
4344 // Remove the duparray insn.
4345 ELEM_REMOVE(&iobj->link);
4346 return COMPILE_OK;
4347 }
4348 }
4349 }
4350
4351
4352 if (IS_INSN_ID(iobj, send)) {
4353 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4354 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4355
4356#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4357 if (vm_ci_simple(ci)) {
4358 switch (vm_ci_argc(ci)) {
4359 case 0:
4360 switch (vm_ci_mid(ci)) {
4361 case idLength: SP_INSN(length); return COMPILE_OK;
4362 case idSize: SP_INSN(size); return COMPILE_OK;
4363 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4364 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4365 case idSucc: SP_INSN(succ); return COMPILE_OK;
4366 case idNot: SP_INSN(not); return COMPILE_OK;
4367 }
4368 break;
4369 case 1:
4370 switch (vm_ci_mid(ci)) {
4371 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4372 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4373 case idMULT: SP_INSN(mult); return COMPILE_OK;
4374 case idDIV: SP_INSN(div); return COMPILE_OK;
4375 case idMOD: SP_INSN(mod); return COMPILE_OK;
4376 case idEq: SP_INSN(eq); return COMPILE_OK;
4377 case idNeq: SP_INSN(neq); return COMPILE_OK;
4378 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4379 case idLT: SP_INSN(lt); return COMPILE_OK;
4380 case idLE: SP_INSN(le); return COMPILE_OK;
4381 case idGT: SP_INSN(gt); return COMPILE_OK;
4382 case idGE: SP_INSN(ge); return COMPILE_OK;
4383 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4384 case idAREF: SP_INSN(aref); return COMPILE_OK;
4385 case idAnd: SP_INSN(and); return COMPILE_OK;
4386 case idOr: SP_INSN(or); return COMPILE_OK;
4387 }
4388 break;
4389 case 2:
4390 switch (vm_ci_mid(ci)) {
4391 case idASET: SP_INSN(aset); return COMPILE_OK;
4392 }
4393 break;
4394 }
4395 }
4396
4397 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4398 iobj->insn_id = BIN(opt_send_without_block);
4399 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4400 }
4401 }
4402#undef SP_INSN
4403
4404 return COMPILE_OK;
4405}
4406
4407static inline int
4408tailcallable_p(rb_iseq_t *iseq)
4409{
4410 switch (ISEQ_BODY(iseq)->type) {
4411 case ISEQ_TYPE_TOP:
4412 case ISEQ_TYPE_EVAL:
4413 case ISEQ_TYPE_MAIN:
4414 /* not tail callable because cfp will be over popped */
4415 case ISEQ_TYPE_RESCUE:
4416 case ISEQ_TYPE_ENSURE:
4417 /* rescue block can't tail call because of errinfo */
4418 return FALSE;
4419 default:
4420 return TRUE;
4421 }
4422}
4423
4424static int
4425iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4426{
4427 LINK_ELEMENT *list;
4428 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4429 const int do_tailcallopt = tailcallable_p(iseq) &&
4430 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4431 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4432 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4433 int rescue_level = 0;
4434 int tailcallopt = do_tailcallopt;
4435
4436 list = FIRST_ELEMENT(anchor);
4437
4438 int do_block_optimization = 0;
4439 LABEL * block_loop_label = NULL;
4440
4441 // If we're optimizing a block
4442 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4443 do_block_optimization = 1;
4444
4445 // If the block starts with a nop and a label,
4446 // record the label so we can detect if it's a jump target
4447 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4448 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4449 block_loop_label = (LABEL *)le->next;
4450 }
4451 }
4452
4453 while (list) {
4454 if (IS_INSN(list)) {
4455 if (do_peepholeopt) {
4456 iseq_peephole_optimize(iseq, list, tailcallopt);
4457 }
4458 if (do_si) {
4459 iseq_specialized_instruction(iseq, (INSN *)list);
4460 }
4461 if (do_ou) {
4462 insn_operands_unification((INSN *)list);
4463 }
4464
4465 if (do_block_optimization) {
4466 INSN * item = (INSN *)list;
4467 // Give up if there is a throw
4468 if (IS_INSN_ID(item, throw)) {
4469 do_block_optimization = 0;
4470 }
4471 else {
4472 // If the instruction has a jump target, check if the
4473 // jump target is the block loop label
4474 const char *types = insn_op_types(item->insn_id);
4475 for (int j = 0; types[j]; j++) {
4476 if (types[j] == TS_OFFSET) {
4477 // If the jump target is equal to the block loop
4478 // label, then we can't do the optimization because
4479 // the leading `nop` instruction fires the block
4480 // entry tracepoint
4481 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4482 if (target == block_loop_label) {
4483 do_block_optimization = 0;
4484 }
4485 }
4486 }
4487 }
4488 }
4489 }
4490 if (IS_LABEL(list)) {
4491 switch (((LABEL *)list)->rescued) {
4492 case LABEL_RESCUE_BEG:
4493 rescue_level++;
4494 tailcallopt = FALSE;
4495 break;
4496 case LABEL_RESCUE_END:
4497 if (!--rescue_level) tailcallopt = do_tailcallopt;
4498 break;
4499 }
4500 }
4501 list = list->next;
4502 }
4503
4504 if (do_block_optimization) {
4505 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4506 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4507 ELEM_REMOVE(le);
4508 }
4509 }
4510 return COMPILE_OK;
4511}
4512
4513#if OPT_INSTRUCTIONS_UNIFICATION
4514static INSN *
4515new_unified_insn(rb_iseq_t *iseq,
4516 int insn_id, int size, LINK_ELEMENT *seq_list)
4517{
4518 INSN *iobj = 0;
4519 LINK_ELEMENT *list = seq_list;
4520 int i, argc = 0;
4521 VALUE *operands = 0, *ptr = 0;
4522
4523
4524 /* count argc */
4525 for (i = 0; i < size; i++) {
4526 iobj = (INSN *)list;
4527 argc += iobj->operand_size;
4528 list = list->next;
4529 }
4530
4531 if (argc > 0) {
4532 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4533 }
4534
4535 /* copy operands */
4536 list = seq_list;
4537 for (i = 0; i < size; i++) {
4538 iobj = (INSN *)list;
4539 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4540 ptr += iobj->operand_size;
4541 list = list->next;
4542 }
4543
4544 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4545}
4546#endif
4547
4548/*
4549 * This scheme can get more performance if do this optimize with
4550 * label address resolving.
4551 * It's future work (if compile time was bottle neck).
4552 */
4553static int
4554iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4555{
4556#if OPT_INSTRUCTIONS_UNIFICATION
4557 LINK_ELEMENT *list;
4558 INSN *iobj, *niobj;
4559 int id, k;
4560 intptr_t j;
4561
4562 list = FIRST_ELEMENT(anchor);
4563 while (list) {
4564 if (IS_INSN(list)) {
4565 iobj = (INSN *)list;
4566 id = iobj->insn_id;
4567 if (unified_insns_data[id] != 0) {
4568 const int *const *entry = unified_insns_data[id];
4569 for (j = 1; j < (intptr_t)entry[0]; j++) {
4570 const int *unified = entry[j];
4571 LINK_ELEMENT *li = list->next;
4572 for (k = 2; k < unified[1]; k++) {
4573 if (!IS_INSN(li) ||
4574 ((INSN *)li)->insn_id != unified[k]) {
4575 goto miss;
4576 }
4577 li = li->next;
4578 }
4579 /* matched */
4580 niobj =
4581 new_unified_insn(iseq, unified[0], unified[1] - 1,
4582 list);
4583
4584 /* insert to list */
4585 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4586 niobj->link.next = li;
4587 if (li) {
4588 li->prev = (LINK_ELEMENT *)niobj;
4589 }
4590
4591 list->prev->next = (LINK_ELEMENT *)niobj;
4592 list = (LINK_ELEMENT *)niobj;
4593 break;
4594 miss:;
4595 }
4596 }
4597 }
4598 list = list->next;
4599 }
4600#endif
4601 return COMPILE_OK;
4602}
4603
4604static int
4605all_string_result_p(const NODE *node)
4606{
4607 if (!node) return FALSE;
4608 switch (nd_type(node)) {
4609 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4610 return TRUE;
4611 case NODE_IF: case NODE_UNLESS:
4612 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4613 if (all_string_result_p(RNODE_IF(node)->nd_body))
4614 return all_string_result_p(RNODE_IF(node)->nd_else);
4615 return FALSE;
4616 case NODE_AND: case NODE_OR:
4617 if (!RNODE_AND(node)->nd_2nd)
4618 return all_string_result_p(RNODE_AND(node)->nd_1st);
4619 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4620 return FALSE;
4621 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4622 default:
4623 return FALSE;
4624 }
4625}
4626
4628 rb_iseq_t *const iseq;
4629 LINK_ANCHOR *const ret;
4630 VALUE lit;
4631 const NODE *lit_node;
4632 int cnt;
4633 int dregx;
4634};
4635
4636static int
4637append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4638{
4639 VALUE s = rb_str_new_mutable_parser_string(str);
4640 if (args->dregx) {
4641 VALUE error = rb_reg_check_preprocess(s);
4642 if (!NIL_P(error)) {
4643 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4644 return COMPILE_NG;
4645 }
4646 }
4647 if (NIL_P(args->lit)) {
4648 args->lit = s;
4649 args->lit_node = node;
4650 }
4651 else {
4652 rb_str_buf_append(args->lit, s);
4653 }
4654 return COMPILE_OK;
4655}
4656
4657static void
4658flush_dstr_fragment(struct dstr_ctxt *args)
4659{
4660 if (!NIL_P(args->lit)) {
4661 rb_iseq_t *iseq = args->iseq;
4662 VALUE lit = args->lit;
4663 args->lit = Qnil;
4664 lit = rb_fstring(lit);
4665 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4666 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4667 args->cnt++;
4668 }
4669}
4670
4671static int
4672compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4673{
4674 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4675 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4676
4677 if (str) {
4678 CHECK(append_dstr_fragment(args, node, str));
4679 }
4680
4681 while (list) {
4682 const NODE *const head = list->nd_head;
4683 if (nd_type_p(head, NODE_STR)) {
4684 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4685 }
4686 else if (nd_type_p(head, NODE_DSTR)) {
4687 CHECK(compile_dstr_fragments_0(args, head));
4688 }
4689 else {
4690 flush_dstr_fragment(args);
4691 rb_iseq_t *iseq = args->iseq;
4692 CHECK(COMPILE(args->ret, "each string", head));
4693 args->cnt++;
4694 }
4695 list = (struct RNode_LIST *)list->nd_next;
4696 }
4697 return COMPILE_OK;
4698}
4699
4700static int
4701compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4702{
4703 struct dstr_ctxt args = {
4704 .iseq = iseq, .ret = ret,
4705 .lit = Qnil, .lit_node = NULL,
4706 .cnt = 0, .dregx = dregx,
4707 };
4708 CHECK(compile_dstr_fragments_0(&args, node));
4709 flush_dstr_fragment(&args);
4710
4711 *cntp = args.cnt;
4712
4713 return COMPILE_OK;
4714}
4715
4716static int
4717compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4718{
4719 while (node && nd_type_p(node, NODE_BLOCK)) {
4720 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4721 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4722 node = RNODE_BLOCK(node)->nd_next;
4723 }
4724 if (node) {
4725 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4726 }
4727 return COMPILE_OK;
4728}
4729
4730static int
4731compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4732{
4733 int cnt;
4734 if (!RNODE_DSTR(node)->nd_next) {
4735 VALUE lit = rb_node_dstr_string_val(node);
4736 ADD_INSN1(ret, node, putstring, lit);
4737 RB_OBJ_SET_SHAREABLE(lit);
4738 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4739 }
4740 else {
4741 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4742 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4743 }
4744 return COMPILE_OK;
4745}
4746
4747static int
4748compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4749{
4750 int cnt;
4751 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4752
4753 if (!RNODE_DREGX(node)->nd_next) {
4754 if (!popped) {
4755 VALUE src = rb_node_dregx_string_val(node);
4756 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4757 RB_OBJ_SET_SHAREABLE(match);
4758 ADD_INSN1(ret, node, putobject, match);
4759 RB_OBJ_WRITTEN(iseq, Qundef, match);
4760 }
4761 return COMPILE_OK;
4762 }
4763
4764 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4765 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4766
4767 if (popped) {
4768 ADD_INSN(ret, node, pop);
4769 }
4770
4771 return COMPILE_OK;
4772}
4773
4774static int
4775compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4776 LABEL *then_label, LABEL *else_label)
4777{
4778 const int line = nd_line(node);
4779 LABEL *lend = NEW_LABEL(line);
4780 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4781 + VM_SVAR_FLIPFLOP_START;
4782 VALUE key = INT2FIX(cnt);
4783
4784 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4785 ADD_INSNL(ret, node, branchif, lend);
4786
4787 /* *flip == 0 */
4788 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4789 ADD_INSNL(ret, node, branchunless, else_label);
4790 ADD_INSN1(ret, node, putobject, Qtrue);
4791 ADD_INSN1(ret, node, setspecial, key);
4792 if (!again) {
4793 ADD_INSNL(ret, node, jump, then_label);
4794 }
4795
4796 /* *flip == 1 */
4797 ADD_LABEL(ret, lend);
4798 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4799 ADD_INSNL(ret, node, branchunless, then_label);
4800 ADD_INSN1(ret, node, putobject, Qfalse);
4801 ADD_INSN1(ret, node, setspecial, key);
4802 ADD_INSNL(ret, node, jump, then_label);
4803
4804 return COMPILE_OK;
4805}
4806
4807static int
4808compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4809 LABEL *then_label, LABEL *else_label);
4810
4811#define COMPILE_SINGLE 2
4812static int
4813compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4814 LABEL *then_label, LABEL *else_label)
4815{
4816 DECL_ANCHOR(seq);
4817 INIT_ANCHOR(seq);
4818 LABEL *label = NEW_LABEL(nd_line(cond));
4819 if (!then_label) then_label = label;
4820 else if (!else_label) else_label = label;
4821
4822 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4823
4824 if (LIST_INSN_SIZE_ONE(seq)) {
4825 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4826 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4827 return COMPILE_OK;
4828 }
4829 if (!label->refcnt) {
4830 return COMPILE_SINGLE;
4831 }
4832 ADD_LABEL(seq, label);
4833 ADD_SEQ(ret, seq);
4834 return COMPILE_OK;
4835}
4836
4837static int
4838compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4839 LABEL *then_label, LABEL *else_label)
4840{
4841 int ok;
4842 DECL_ANCHOR(ignore);
4843
4844 again:
4845 switch (nd_type(cond)) {
4846 case NODE_AND:
4847 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4848 cond = RNODE_AND(cond)->nd_2nd;
4849 if (ok == COMPILE_SINGLE) {
4850 INIT_ANCHOR(ignore);
4851 ret = ignore;
4852 then_label = NEW_LABEL(nd_line(cond));
4853 }
4854 goto again;
4855 case NODE_OR:
4856 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4857 cond = RNODE_OR(cond)->nd_2nd;
4858 if (ok == COMPILE_SINGLE) {
4859 INIT_ANCHOR(ignore);
4860 ret = ignore;
4861 else_label = NEW_LABEL(nd_line(cond));
4862 }
4863 goto again;
4864 case NODE_SYM:
4865 case NODE_LINE:
4866 case NODE_FILE:
4867 case NODE_ENCODING:
4868 case NODE_INTEGER: /* NODE_INTEGER is always true */
4869 case NODE_FLOAT: /* NODE_FLOAT is always true */
4870 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4871 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4872 case NODE_TRUE:
4873 case NODE_STR:
4874 case NODE_REGX:
4875 case NODE_ZLIST:
4876 case NODE_LAMBDA:
4877 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4878 ADD_INSNL(ret, cond, jump, then_label);
4879 return COMPILE_OK;
4880 case NODE_FALSE:
4881 case NODE_NIL:
4882 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4883 ADD_INSNL(ret, cond, jump, else_label);
4884 return COMPILE_OK;
4885 case NODE_LIST:
4886 case NODE_ARGSCAT:
4887 case NODE_DREGX:
4888 case NODE_DSTR:
4889 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4890 ADD_INSNL(ret, cond, jump, then_label);
4891 return COMPILE_OK;
4892 case NODE_FLIP2:
4893 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4894 return COMPILE_OK;
4895 case NODE_FLIP3:
4896 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4897 return COMPILE_OK;
4898 case NODE_DEFINED:
4899 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4900 break;
4901 default:
4902 {
4903 DECL_ANCHOR(cond_seq);
4904 INIT_ANCHOR(cond_seq);
4905
4906 CHECK(COMPILE(cond_seq, "branch condition", cond));
4907
4908 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4909 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4910 if (insn->insn_id == BIN(putobject)) {
4911 if (RTEST(insn->operands[0])) {
4912 ADD_INSNL(ret, cond, jump, then_label);
4913 // maybe unreachable
4914 return COMPILE_OK;
4915 }
4916 else {
4917 ADD_INSNL(ret, cond, jump, else_label);
4918 return COMPILE_OK;
4919 }
4920 }
4921 }
4922 ADD_SEQ(ret, cond_seq);
4923 }
4924 break;
4925 }
4926
4927 ADD_INSNL(ret, cond, branchunless, else_label);
4928 ADD_INSNL(ret, cond, jump, then_label);
4929 return COMPILE_OK;
4930}
4931
4932#define HASH_BRACE 1
4933
4934static int
4935keyword_node_p(const NODE *const node)
4936{
4937 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4938}
4939
4940static VALUE
4941get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4942{
4943 switch (nd_type(node)) {
4944 case NODE_SYM:
4945 return rb_node_sym_string_val(node);
4946 default:
4947 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4948 }
4949}
4950
4951static VALUE
4952node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4953{
4954 NODE *node = node_hash->nd_head;
4955 VALUE hash = rb_hash_new();
4956 VALUE ary = rb_ary_new();
4957
4958 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4959 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4960 VALUE idx = rb_hash_aref(hash, key);
4961 if (!NIL_P(idx)) {
4962 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4963 (*count_ptr)--;
4964 }
4965 rb_hash_aset(hash, key, INT2FIX(i));
4966 rb_ary_store(ary, i, Qtrue);
4967 (*count_ptr)++;
4968 }
4969
4970 return ary;
4971}
4972
4973static int
4974compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4975 const NODE *const root_node,
4976 struct rb_callinfo_kwarg **const kw_arg_ptr,
4977 unsigned int *flag)
4978{
4979 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4980 RUBY_ASSERT(kw_arg_ptr != NULL);
4981 RUBY_ASSERT(flag != NULL);
4982
4983 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4984 const NODE *node = RNODE_HASH(root_node)->nd_head;
4985 int seen_nodes = 0;
4986
4987 while (node) {
4988 const NODE *key_node = RNODE_LIST(node)->nd_head;
4989 seen_nodes++;
4990
4991 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4992 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4993 /* can be keywords */
4994 }
4995 else {
4996 if (flag) {
4997 *flag |= VM_CALL_KW_SPLAT;
4998 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4999 /* A new hash will be created for the keyword arguments
5000 * in this case, so mark the method as passing mutable
5001 * keyword splat.
5002 */
5003 *flag |= VM_CALL_KW_SPLAT_MUT;
5004 }
5005 }
5006 return FALSE;
5007 }
5008 node = RNODE_LIST(node)->nd_next; /* skip value node */
5009 node = RNODE_LIST(node)->nd_next;
5010 }
5011
5012 /* may be keywords */
5013 node = RNODE_HASH(root_node)->nd_head;
5014 {
5015 int len = 0;
5016 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5017 struct rb_callinfo_kwarg *kw_arg =
5018 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5019 VALUE *keywords = kw_arg->keywords;
5020 int i = 0;
5021 int j = 0;
5022 kw_arg->references = 0;
5023 kw_arg->keyword_len = len;
5024
5025 *kw_arg_ptr = kw_arg;
5026
5027 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5028 const NODE *key_node = RNODE_LIST(node)->nd_head;
5029 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5030 int popped = TRUE;
5031 if (rb_ary_entry(key_index, i)) {
5032 keywords[j] = get_symbol_value(iseq, key_node);
5033 j++;
5034 popped = FALSE;
5035 }
5036 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5037 }
5038 RUBY_ASSERT(j == len);
5039 return TRUE;
5040 }
5041 }
5042 return FALSE;
5043}
5044
5045static int
5046compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5047{
5048 int len = 0;
5049
5050 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5051 if (CPDEBUG > 0) {
5052 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5053 }
5054
5055 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5056 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5057 }
5058 else {
5059 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5060 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5061 }
5062 }
5063
5064 return len;
5065}
5066
5067static inline bool
5068frozen_string_literal_p(const rb_iseq_t *iseq)
5069{
5070 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5071}
5072
5073static inline bool
5074static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5075{
5076 switch (nd_type(node)) {
5077 case NODE_SYM:
5078 case NODE_REGX:
5079 case NODE_LINE:
5080 case NODE_ENCODING:
5081 case NODE_INTEGER:
5082 case NODE_FLOAT:
5083 case NODE_RATIONAL:
5084 case NODE_IMAGINARY:
5085 case NODE_NIL:
5086 case NODE_TRUE:
5087 case NODE_FALSE:
5088 return TRUE;
5089 case NODE_STR:
5090 case NODE_FILE:
5091 return hash_key || frozen_string_literal_p(iseq);
5092 default:
5093 return FALSE;
5094 }
5095}
5096
5097static inline VALUE
5098static_literal_value(const NODE *node, rb_iseq_t *iseq)
5099{
5100 switch (nd_type(node)) {
5101 case NODE_INTEGER:
5102 {
5103 VALUE lit = rb_node_integer_literal_val(node);
5104 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5105 return lit;
5106 }
5107 case NODE_FLOAT:
5108 {
5109 VALUE lit = rb_node_float_literal_val(node);
5110 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5111 return lit;
5112 }
5113 case NODE_RATIONAL:
5114 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5115 case NODE_IMAGINARY:
5116 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5117 case NODE_NIL:
5118 return Qnil;
5119 case NODE_TRUE:
5120 return Qtrue;
5121 case NODE_FALSE:
5122 return Qfalse;
5123 case NODE_SYM:
5124 return rb_node_sym_string_val(node);
5125 case NODE_REGX:
5126 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5127 case NODE_LINE:
5128 return rb_node_line_lineno_val(node);
5129 case NODE_ENCODING:
5130 return rb_node_encoding_val(node);
5131 case NODE_FILE:
5132 case NODE_STR:
5133 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5134 VALUE lit = get_string_value(node);
5135 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5136 RB_OBJ_SET_SHAREABLE(str);
5137 return str;
5138 }
5139 else {
5140 return get_string_value(node);
5141 }
5142 default:
5143 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5144 }
5145}
5146
5147static int
5148compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5149{
5150 const NODE *line_node = node;
5151
5152 if (nd_type_p(node, NODE_ZLIST)) {
5153 if (!popped) {
5154 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5155 }
5156 return 0;
5157 }
5158
5159 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5160
5161 if (popped) {
5162 for (; node; node = RNODE_LIST(node)->nd_next) {
5163 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5164 }
5165 return 1;
5166 }
5167
5168 /* Compilation of an array literal.
5169 * The following code is essentially the same as:
5170 *
5171 * for (int count = 0; node; count++; node->nd_next) {
5172 * compile(node->nd_head);
5173 * }
5174 * ADD_INSN(newarray, count);
5175 *
5176 * However, there are three points.
5177 *
5178 * - The code above causes stack overflow for a big string literal.
5179 * The following limits the stack length up to max_stack_len.
5180 *
5181 * [x1,x2,...,x10000] =>
5182 * push x1 ; push x2 ; ...; push x256; newarray 256;
5183 * push x257; push x258; ...; push x512; pushtoarray 256;
5184 * push x513; push x514; ...; push x768; pushtoarray 256;
5185 * ...
5186 *
5187 * - Long subarray can be optimized by pre-allocating a hidden array.
5188 *
5189 * [1,2,3,...,100] =>
5190 * duparray [1,2,3,...,100]
5191 *
5192 * [x, 1,2,3,...,100, z] =>
5193 * push x; newarray 1;
5194 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5195 * push z; pushtoarray 1;
5196 *
5197 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5198 * to only push it onto the array if it is not empty
5199 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5200 *
5201 * [1,2,3,**kw] =>
5202 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5203 */
5204
5205 const int max_stack_len = 0x100;
5206 const int min_tmp_ary_len = 0x40;
5207 int stack_len = 0;
5208
5209 /* Either create a new array, or push to the existing array */
5210#define FLUSH_CHUNK \
5211 if (stack_len) { \
5212 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5213 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5214 first_chunk = FALSE; \
5215 stack_len = 0; \
5216 }
5217
5218 while (node) {
5219 int count = 1;
5220
5221 /* pre-allocation check (this branch can be omittable) */
5222 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5223 /* count the elements that are optimizable */
5224 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5225 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5226 count++;
5227
5228 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5229 /* The literal contains only optimizable elements, or the subarray is long enough */
5230 VALUE ary = rb_ary_hidden_new(count);
5231
5232 /* Create a hidden array */
5233 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5234 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5235 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5236
5237 /* Emit optimized code */
5238 FLUSH_CHUNK;
5239 if (first_chunk) {
5240 ADD_INSN1(ret, line_node, duparray, ary);
5241 first_chunk = FALSE;
5242 }
5243 else {
5244 ADD_INSN1(ret, line_node, putobject, ary);
5245 ADD_INSN(ret, line_node, concattoarray);
5246 }
5247 RB_OBJ_SET_SHAREABLE(ary);
5248 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5249 }
5250 }
5251
5252 /* Base case: Compile "count" elements */
5253 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5254 if (CPDEBUG > 0) {
5255 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5256 }
5257
5258 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5259 /* Create array or push existing non-keyword elements onto array */
5260 if (stack_len == 0 && first_chunk) {
5261 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5262 }
5263 else {
5264 FLUSH_CHUNK;
5265 }
5266 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5267 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5268 return 1;
5269 }
5270 else {
5271 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5272 stack_len++;
5273 }
5274
5275 /* If there are many pushed elements, flush them to avoid stack overflow */
5276 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5277 }
5278 }
5279
5280 FLUSH_CHUNK;
5281#undef FLUSH_CHUNK
5282 return 1;
5283}
5284
5285static inline int
5286static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5287{
5288 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);
5289}
5290
5291static int
5292compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5293{
5294 const NODE *line_node = node;
5295
5296 node = RNODE_HASH(node)->nd_head;
5297
5298 if (!node || nd_type_p(node, NODE_ZLIST)) {
5299 if (!popped) {
5300 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5301 }
5302 return 0;
5303 }
5304
5305 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5306
5307 if (popped) {
5308 for (; node; node = RNODE_LIST(node)->nd_next) {
5309 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5310 }
5311 return 1;
5312 }
5313
5314 /* Compilation of a hash literal (or keyword arguments).
5315 * This is very similar to compile_array, but there are some differences:
5316 *
5317 * - It contains key-value pairs. So we need to take every two elements.
5318 * We can assume that the length is always even.
5319 *
5320 * - Merging is done by a method call (id_core_hash_merge_ptr).
5321 * Sometimes we need to insert the receiver, so "anchor" is needed.
5322 * In addition, a method call is much slower than concatarray.
5323 * So it pays only when the subsequence is really long.
5324 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5325 *
5326 * - We need to handle keyword splat: **kw.
5327 * For **kw, the key part (node->nd_head) is NULL, and the value part
5328 * (node->nd_next->nd_head) is "kw".
5329 * The code is a bit difficult to avoid hash allocation for **{}.
5330 */
5331
5332 const int max_stack_len = 0x100;
5333 const int min_tmp_hash_len = 0x800;
5334 int stack_len = 0;
5335 int first_chunk = 1;
5336 DECL_ANCHOR(anchor);
5337 INIT_ANCHOR(anchor);
5338
5339 /* Convert pushed elements to a hash, and merge if needed */
5340#define FLUSH_CHUNK() \
5341 if (stack_len) { \
5342 if (first_chunk) { \
5343 APPEND_LIST(ret, anchor); \
5344 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5345 } \
5346 else { \
5347 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5348 ADD_INSN(ret, line_node, swap); \
5349 APPEND_LIST(ret, anchor); \
5350 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5351 } \
5352 INIT_ANCHOR(anchor); \
5353 first_chunk = stack_len = 0; \
5354 }
5355
5356 while (node) {
5357 int count = 1;
5358
5359 /* pre-allocation check (this branch can be omittable) */
5360 if (static_literal_node_pair_p(node, iseq)) {
5361 /* count the elements that are optimizable */
5362 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5363 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5364 count++;
5365
5366 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5367 /* The literal contains only optimizable elements, or the subsequence is long enough */
5368 VALUE ary = rb_ary_hidden_new(count);
5369
5370 /* Create a hidden hash */
5371 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5372 VALUE elem[2];
5373 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5374 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5375 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5376 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5377 rb_ary_cat(ary, elem, 2);
5378 }
5379 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5380 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5381 hash = RB_OBJ_SET_FROZEN_SHAREABLE(rb_obj_hide(hash));
5382
5383 /* Emit optimized code */
5384 FLUSH_CHUNK();
5385 if (first_chunk) {
5386 ADD_INSN1(ret, line_node, duphash, hash);
5387 first_chunk = 0;
5388 }
5389 else {
5390 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5391 ADD_INSN(ret, line_node, swap);
5392
5393 ADD_INSN1(ret, line_node, putobject, hash);
5394
5395 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5396 }
5397 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5398 }
5399 }
5400
5401 /* Base case: Compile "count" elements */
5402 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5403
5404 if (CPDEBUG > 0) {
5405 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5406 }
5407
5408 if (RNODE_LIST(node)->nd_head) {
5409 /* Normal key-value pair */
5410 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5411 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5412 stack_len += 2;
5413
5414 /* If there are many pushed elements, flush them to avoid stack overflow */
5415 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5416 }
5417 else {
5418 /* kwsplat case: foo(..., **kw, ...) */
5419 FLUSH_CHUNK();
5420
5421 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5422 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5423 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5424 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5425 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5426
5427 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5428 if (empty_kw) {
5429 if (only_kw && method_call_keywords) {
5430 /* **{} appears at the only keyword argument in method call,
5431 * so it won't be modified.
5432 * kw is a special NODE_LIT that contains a special empty hash,
5433 * so this emits: putobject {}.
5434 * This is only done for method calls and not for literal hashes,
5435 * because literal hashes should always result in a new hash.
5436 */
5437 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5438 }
5439 else if (first_kw) {
5440 /* **{} appears as the first keyword argument, so it may be modified.
5441 * We need to create a fresh hash object.
5442 */
5443 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5444 }
5445 /* Any empty keyword splats that are not the first can be ignored.
5446 * since merging an empty hash into the existing hash is the same
5447 * as not merging it. */
5448 }
5449 else {
5450 if (only_kw && method_call_keywords) {
5451 /* **kw is only keyword argument in method call.
5452 * Use directly. This will be not be flagged as mutable.
5453 * This is only done for method calls and not for literal hashes,
5454 * because literal hashes should always result in a new hash.
5455 */
5456 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5457 }
5458 else {
5459 /* There is more than one keyword argument, or this is not a method
5460 * call. In that case, we need to add an empty hash (if first keyword),
5461 * or merge the hash to the accumulated hash (if not the first keyword).
5462 */
5463 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5464 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5465 else ADD_INSN(ret, line_node, swap);
5466
5467 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5468
5469 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5470 }
5471 }
5472
5473 first_chunk = 0;
5474 }
5475 }
5476 }
5477
5478 FLUSH_CHUNK();
5479#undef FLUSH_CHUNK
5480 return 1;
5481}
5482
5483VALUE
5484rb_node_case_when_optimizable_literal(const NODE *const node)
5485{
5486 switch (nd_type(node)) {
5487 case NODE_INTEGER:
5488 return rb_node_integer_literal_val(node);
5489 case NODE_FLOAT: {
5490 VALUE v = rb_node_float_literal_val(node);
5491 double ival;
5492
5493 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5494 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5495 }
5496 return v;
5497 }
5498 case NODE_RATIONAL:
5499 case NODE_IMAGINARY:
5500 return Qundef;
5501 case NODE_NIL:
5502 return Qnil;
5503 case NODE_TRUE:
5504 return Qtrue;
5505 case NODE_FALSE:
5506 return Qfalse;
5507 case NODE_SYM:
5508 return rb_node_sym_string_val(node);
5509 case NODE_LINE:
5510 return rb_node_line_lineno_val(node);
5511 case NODE_STR:
5512 return rb_node_str_string_val(node);
5513 case NODE_FILE:
5514 return rb_node_file_path_val(node);
5515 }
5516 return Qundef;
5517}
5518
5519static int
5520when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5521 LABEL *l1, int only_special_literals, VALUE literals)
5522{
5523 while (vals) {
5524 const NODE *val = RNODE_LIST(vals)->nd_head;
5525 VALUE lit = rb_node_case_when_optimizable_literal(val);
5526
5527 if (UNDEF_P(lit)) {
5528 only_special_literals = 0;
5529 }
5530 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5531 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5532 }
5533
5534 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5535 debugp_param("nd_lit", get_string_value(val));
5536 lit = get_string_value(val);
5537 ADD_INSN1(cond_seq, val, putobject, lit);
5538 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5539 }
5540 else {
5541 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5542 }
5543
5544 // Emit pattern === target
5545 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5546 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5547 ADD_INSNL(cond_seq, val, branchif, l1);
5548 vals = RNODE_LIST(vals)->nd_next;
5549 }
5550 return only_special_literals;
5551}
5552
5553static int
5554when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5555 LABEL *l1, int only_special_literals, VALUE literals)
5556{
5557 const NODE *line_node = vals;
5558
5559 switch (nd_type(vals)) {
5560 case NODE_LIST:
5561 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5562 return COMPILE_NG;
5563 break;
5564 case NODE_SPLAT:
5565 ADD_INSN (cond_seq, line_node, dup);
5566 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5567 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5568 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5569 ADD_INSNL(cond_seq, line_node, branchif, l1);
5570 break;
5571 case NODE_ARGSCAT:
5572 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5573 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5574 break;
5575 case NODE_ARGSPUSH:
5576 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5577 ADD_INSN (cond_seq, line_node, dup);
5578 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5579 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5580 ADD_INSNL(cond_seq, line_node, branchif, l1);
5581 break;
5582 default:
5583 ADD_INSN (cond_seq, line_node, dup);
5584 CHECK(COMPILE(cond_seq, "when val", vals));
5585 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5586 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5587 ADD_INSNL(cond_seq, line_node, branchif, l1);
5588 break;
5589 }
5590 return COMPILE_OK;
5591}
5592
5593/* Multiple Assignment Handling
5594 *
5595 * In order to handle evaluation of multiple assignment such that the left hand side
5596 * is evaluated before the right hand side, we need to process the left hand side
5597 * and see if there are any attributes that need to be assigned, or constants set
5598 * on explicit objects. If so, we add instructions to evaluate the receiver of
5599 * any assigned attributes or constants before we process the right hand side.
5600 *
5601 * For a multiple assignment such as:
5602 *
5603 * l1.m1, l2[0] = r3, r4
5604 *
5605 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5606 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5607 * On the VM stack, this looks like:
5608 *
5609 * self # putself
5610 * l1 # send
5611 * l1, self # putself
5612 * l1, l2 # send
5613 * l1, l2, 0 # putobject 0
5614 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5615 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5616 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5617 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5618 * l1, l2, 0, [r3, r4], r4, m1= # send
5619 * l1, l2, 0, [r3, r4], r4 # pop
5620 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5621 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5622 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5623 * l1, l2, 0, [r3, r4], r4, []= # send
5624 * l1, l2, 0, [r3, r4], r4 # pop
5625 * l1, l2, 0, [r3, r4] # pop
5626 * [r3, r4], l2, 0, [r3, r4] # setn 3
5627 * [r3, r4], l2, 0 # pop
5628 * [r3, r4], l2 # pop
5629 * [r3, r4] # pop
5630 *
5631 * This is made more complex when you have to handle splats, post args,
5632 * and arbitrary levels of nesting. You need to keep track of the total
5633 * number of attributes to set, and for each attribute, how many entries
5634 * are on the stack before the final attribute, in order to correctly
5635 * calculate the topn value to use to get the receiver of the attribute
5636 * setter method.
5637 *
5638 * A brief description of the VM stack for simple multiple assignment
5639 * with no splat (rhs_array will not be present if the return value of
5640 * the multiple assignment is not needed):
5641 *
5642 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5643 *
5644 * For multiple assignment with splats, while processing the part before
5645 * the splat (splat+post here is an array of the splat and the post arguments):
5646 *
5647 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5648 *
5649 * When processing the splat and post arguments:
5650 *
5651 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5652 *
5653 * When processing nested multiple assignment, existing values on the stack
5654 * are kept. So for:
5655 *
5656 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5657 *
5658 * The stack layout would be the following before processing the nested
5659 * multiple assignment:
5660 *
5661 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5662 *
5663 * In order to handle this correctly, we need to keep track of the nesting
5664 * level for each attribute assignment, as well as the attribute number
5665 * (left hand side attributes are processed left to right) and number of
5666 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5667 * this information.
5668 *
5669 * We also need to track information for the entire multiple assignment, such
5670 * as the total number of arguments, and the current nesting level, to
5671 * handle both nested multiple assignment as well as cases where the
5672 * rhs is not needed. We also need to keep track of all attribute
5673 * assignments in this, which we do using a linked listed. struct masgn_state
5674 * tracks this information.
5675 */
5676
5678 INSN *before_insn;
5679 struct masgn_lhs_node *next;
5680 const NODE *line_node;
5681 int argn;
5682 int num_args;
5683 int lhs_pos;
5684};
5685
5687 struct masgn_lhs_node *first_memo;
5688 struct masgn_lhs_node *last_memo;
5689 int lhs_level;
5690 int num_args;
5691 bool nested;
5692};
5693
5694static int
5695add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5696{
5697 if (!state) {
5698 rb_bug("no masgn_state");
5699 }
5700
5701 struct masgn_lhs_node *memo;
5702 memo = malloc(sizeof(struct masgn_lhs_node));
5703 if (!memo) {
5704 return COMPILE_NG;
5705 }
5706
5707 memo->before_insn = before_insn;
5708 memo->line_node = line_node;
5709 memo->argn = state->num_args + 1;
5710 memo->num_args = argc;
5711 state->num_args += argc;
5712 memo->lhs_pos = lhs_pos;
5713 memo->next = NULL;
5714 if (!state->first_memo) {
5715 state->first_memo = memo;
5716 }
5717 else {
5718 state->last_memo->next = memo;
5719 }
5720 state->last_memo = memo;
5721
5722 return COMPILE_OK;
5723}
5724
5725static 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);
5726
5727static int
5728compile_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)
5729{
5730 switch (nd_type(node)) {
5731 case NODE_ATTRASGN: {
5732 INSN *iobj;
5733 const NODE *line_node = node;
5734
5735 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5736
5737 bool safenav_call = false;
5738 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5739 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5740 ASSUME(iobj);
5741 ELEM_REMOVE(insn_element);
5742 if (!IS_INSN_ID(iobj, send)) {
5743 safenav_call = true;
5744 iobj = (INSN *)get_prev_insn(iobj);
5745 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5746 }
5747 (pre->last = iobj->link.prev)->next = 0;
5748
5749 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5750 int argc = vm_ci_argc(ci) + 1;
5751 ci = ci_argc_set(iseq, ci, argc);
5752 OPERAND_AT(iobj, 0) = (VALUE)ci;
5753 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5754
5755 if (argc == 1) {
5756 ADD_INSN(lhs, line_node, swap);
5757 }
5758 else {
5759 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5760 }
5761
5762 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5763 return COMPILE_NG;
5764 }
5765
5766 iobj->link.prev = lhs->last;
5767 lhs->last->next = &iobj->link;
5768 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5769 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5770 int argc = vm_ci_argc(ci);
5771 bool dupsplat = false;
5772 ci = ci_argc_set(iseq, ci, argc - 1);
5773 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5774 /* Given h[*a], _ = ary
5775 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5776 * `a` must be dupped, because it will be appended with ary[0]
5777 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5778 */
5779 dupsplat = true;
5780 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5781 }
5782 OPERAND_AT(iobj, 0) = (VALUE)ci;
5783 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5784
5785 /* Given: h[*a], h[*b, 1] = ary
5786 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5787 * so this uses splatarray true on a to dup it before using pushtoarray
5788 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5789 * so you can use pushtoarray directly
5790 */
5791 int line_no = nd_line(line_node);
5792 int node_id = nd_node_id(line_node);
5793
5794 if (dupsplat) {
5795 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5796 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5797 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5798 }
5799 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5800 }
5801 if (!safenav_call) {
5802 ADD_INSN(lhs, line_node, pop);
5803 if (argc != 1) {
5804 ADD_INSN(lhs, line_node, pop);
5805 }
5806 }
5807 for (int i=0; i < argc; i++) {
5808 ADD_INSN(post, line_node, pop);
5809 }
5810 break;
5811 }
5812 case NODE_MASGN: {
5813 DECL_ANCHOR(nest_rhs);
5814 INIT_ANCHOR(nest_rhs);
5815 DECL_ANCHOR(nest_lhs);
5816 INIT_ANCHOR(nest_lhs);
5817
5818 int prev_level = state->lhs_level;
5819 bool prev_nested = state->nested;
5820 state->nested = 1;
5821 state->lhs_level = lhs_pos - 1;
5822 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5823 state->lhs_level = prev_level;
5824 state->nested = prev_nested;
5825
5826 ADD_SEQ(lhs, nest_rhs);
5827 ADD_SEQ(lhs, nest_lhs);
5828 break;
5829 }
5830 case NODE_CDECL:
5831 if (!RNODE_CDECL(node)->nd_vid) {
5832 /* Special handling only needed for expr::C, not for C */
5833 INSN *iobj;
5834
5835 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5836
5837 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5838 iobj = (INSN *)insn_element; /* setconstant insn */
5839 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5840 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5841 ELEM_REMOVE(insn_element);
5842 pre->last = iobj->link.prev;
5843 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5844
5845 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5846 return COMPILE_NG;
5847 }
5848
5849 ADD_INSN(post, node, pop);
5850 break;
5851 }
5852 /* Fallthrough */
5853 default: {
5854 DECL_ANCHOR(anchor);
5855 INIT_ANCHOR(anchor);
5856 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5857 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5858 ADD_SEQ(lhs, anchor);
5859 }
5860 }
5861
5862 return COMPILE_OK;
5863}
5864
5865static int
5866compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5867{
5868 if (lhsn) {
5869 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5870 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5871 }
5872 return COMPILE_OK;
5873}
5874
5875static int
5876compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5877 const NODE *rhsn, const NODE *orig_lhsn)
5878{
5879 VALUE mem[64];
5880 const int memsize = numberof(mem);
5881 int memindex = 0;
5882 int llen = 0, rlen = 0;
5883 int i;
5884 const NODE *lhsn = orig_lhsn;
5885
5886#define MEMORY(v) { \
5887 int i; \
5888 if (memindex == memsize) return 0; \
5889 for (i=0; i<memindex; i++) { \
5890 if (mem[i] == (v)) return 0; \
5891 } \
5892 mem[memindex++] = (v); \
5893}
5894
5895 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5896 return 0;
5897 }
5898
5899 while (lhsn) {
5900 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5901 switch (nd_type(ln)) {
5902 case NODE_LASGN:
5903 case NODE_DASGN:
5904 case NODE_IASGN:
5905 case NODE_CVASGN:
5906 MEMORY(get_nd_vid(ln));
5907 break;
5908 default:
5909 return 0;
5910 }
5911 lhsn = RNODE_LIST(lhsn)->nd_next;
5912 llen++;
5913 }
5914
5915 while (rhsn) {
5916 if (llen <= rlen) {
5917 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5918 }
5919 else {
5920 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5921 }
5922 rhsn = RNODE_LIST(rhsn)->nd_next;
5923 rlen++;
5924 }
5925
5926 if (llen > rlen) {
5927 for (i=0; i<llen-rlen; i++) {
5928 ADD_INSN(ret, orig_lhsn, putnil);
5929 }
5930 }
5931
5932 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5933 return 1;
5934}
5935
5936static int
5937compile_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)
5938{
5939 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5940 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5941 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5942 const NODE *lhsn_count = lhsn;
5943 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5944
5945 int llen = 0;
5946 int lpos = 0;
5947
5948 while (lhsn_count) {
5949 llen++;
5950 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5951 }
5952 while (lhsn) {
5953 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5954 lpos++;
5955 lhsn = RNODE_LIST(lhsn)->nd_next;
5956 }
5957
5958 if (lhs_splat) {
5959 if (nd_type_p(splatn, NODE_POSTARG)) {
5960 /*a, b, *r, p1, p2 */
5961 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5962 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5963 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5964 int ppos = 0;
5965 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5966
5967 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5968
5969 if (NODE_NAMED_REST_P(restn)) {
5970 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5971 }
5972 while (postn) {
5973 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5974 ppos++;
5975 postn = RNODE_LIST(postn)->nd_next;
5976 }
5977 }
5978 else {
5979 /* a, b, *r */
5980 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5981 }
5982 }
5983
5984 if (!state->nested) {
5985 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5986 }
5987
5988 if (!popped) {
5989 ADD_INSN(rhs, node, dup);
5990 }
5991 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5992 return COMPILE_OK;
5993}
5994
5995static int
5996compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5997{
5998 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5999 struct masgn_state state;
6000 state.lhs_level = popped ? 0 : 1;
6001 state.nested = 0;
6002 state.num_args = 0;
6003 state.first_memo = NULL;
6004 state.last_memo = NULL;
6005
6006 DECL_ANCHOR(pre);
6007 INIT_ANCHOR(pre);
6008 DECL_ANCHOR(rhs);
6009 INIT_ANCHOR(rhs);
6010 DECL_ANCHOR(lhs);
6011 INIT_ANCHOR(lhs);
6012 DECL_ANCHOR(post);
6013 INIT_ANCHOR(post);
6014 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6015
6016 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6017 while (memo) {
6018 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6019 for (int i = 0; i < memo->num_args; i++) {
6020 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6021 }
6022 tmp_memo = memo->next;
6023 free(memo);
6024 memo = tmp_memo;
6025 }
6026 CHECK(ok);
6027
6028 ADD_SEQ(ret, pre);
6029 ADD_SEQ(ret, rhs);
6030 ADD_SEQ(ret, lhs);
6031 if (!popped && state.num_args >= 1) {
6032 /* make sure rhs array is returned before popping */
6033 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6034 }
6035 ADD_SEQ(ret, post);
6036 }
6037 return COMPILE_OK;
6038}
6039
6040static VALUE
6041collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6042{
6043 VALUE arr = rb_ary_new();
6044 for (;;) {
6045 switch (nd_type(node)) {
6046 case NODE_CONST:
6047 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6048 RB_OBJ_SET_SHAREABLE(arr);
6049 return arr;
6050 case NODE_COLON3:
6051 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6052 rb_ary_unshift(arr, ID2SYM(idNULL));
6053 RB_OBJ_SET_SHAREABLE(arr);
6054 return arr;
6055 case NODE_COLON2:
6056 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6057 node = RNODE_COLON2(node)->nd_head;
6058 break;
6059 default:
6060 return Qfalse;
6061 }
6062 }
6063}
6064
6065static int
6066compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6067 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6068{
6069 switch (nd_type(node)) {
6070 case NODE_CONST:
6071 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6072 ADD_INSN1(body, node, putobject, Qtrue);
6073 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6074 break;
6075 case NODE_COLON3:
6076 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6077 ADD_INSN(body, node, pop);
6078 ADD_INSN1(body, node, putobject, rb_cObject);
6079 ADD_INSN1(body, node, putobject, Qtrue);
6080 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6081 break;
6082 case NODE_COLON2:
6083 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6084 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6085 ADD_INSN1(body, node, putobject, Qfalse);
6086 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6087 break;
6088 default:
6089 CHECK(COMPILE(pref, "const colon2 prefix", node));
6090 break;
6091 }
6092 return COMPILE_OK;
6093}
6094
6095static int
6096compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6097{
6098 if (nd_type_p(cpath, NODE_COLON3)) {
6099 /* toplevel class ::Foo */
6100 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6101 return VM_DEFINECLASS_FLAG_SCOPED;
6102 }
6103 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6104 /* Bar::Foo */
6105 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6106 return VM_DEFINECLASS_FLAG_SCOPED;
6107 }
6108 else {
6109 /* class at cbase Foo */
6110 ADD_INSN1(ret, cpath, putspecialobject,
6111 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6112 return 0;
6113 }
6114}
6115
6116static inline int
6117private_recv_p(const NODE *node)
6118{
6119 NODE *recv = get_nd_recv(node);
6120 if (recv && nd_type_p(recv, NODE_SELF)) {
6121 return RNODE_SELF(recv)->nd_state != 0;
6122 }
6123 return 0;
6124}
6125
6126static void
6127defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6128 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6129
6130static int
6131compile_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);
6132
6133static void
6134defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6135 const NODE *const node, LABEL **lfinish, VALUE needstr,
6136 bool keep_result)
6137{
6138 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6139 enum node_type type;
6140 const int line = nd_line(node);
6141 const NODE *line_node = node;
6142
6143 switch (type = nd_type(node)) {
6144
6145 /* easy literals */
6146 case NODE_NIL:
6147 expr_type = DEFINED_NIL;
6148 break;
6149 case NODE_SELF:
6150 expr_type = DEFINED_SELF;
6151 break;
6152 case NODE_TRUE:
6153 expr_type = DEFINED_TRUE;
6154 break;
6155 case NODE_FALSE:
6156 expr_type = DEFINED_FALSE;
6157 break;
6158
6159 case NODE_HASH:
6160 case NODE_LIST:{
6161 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6162
6163 if (vals) {
6164 do {
6165 if (RNODE_LIST(vals)->nd_head) {
6166 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6167
6168 if (!lfinish[1]) {
6169 lfinish[1] = NEW_LABEL(line);
6170 }
6171 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6172 }
6173 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6174 }
6175 }
6176 /* fall through */
6177 case NODE_STR:
6178 case NODE_SYM:
6179 case NODE_REGX:
6180 case NODE_LINE:
6181 case NODE_FILE:
6182 case NODE_ENCODING:
6183 case NODE_INTEGER:
6184 case NODE_FLOAT:
6185 case NODE_RATIONAL:
6186 case NODE_IMAGINARY:
6187 case NODE_ZLIST:
6188 case NODE_AND:
6189 case NODE_OR:
6190 default:
6191 expr_type = DEFINED_EXPR;
6192 break;
6193
6194 case NODE_SPLAT:
6195 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6196 if (!lfinish[1]) {
6197 lfinish[1] = NEW_LABEL(line);
6198 }
6199 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6200 expr_type = DEFINED_EXPR;
6201 break;
6202
6203 /* variables */
6204 case NODE_LVAR:
6205 case NODE_DVAR:
6206 expr_type = DEFINED_LVAR;
6207 break;
6208
6209#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6210 case NODE_IVAR:
6211 ADD_INSN3(ret, line_node, definedivar,
6212 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6213 return;
6214
6215 case NODE_GVAR:
6216 ADD_INSN(ret, line_node, putnil);
6217 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6218 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6219 return;
6220
6221 case NODE_CVAR:
6222 ADD_INSN(ret, line_node, putnil);
6223 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6224 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6225 return;
6226
6227 case NODE_CONST:
6228 ADD_INSN(ret, line_node, putnil);
6229 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6230 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6231 return;
6232 case NODE_COLON2:
6233 if (!lfinish[1]) {
6234 lfinish[1] = NEW_LABEL(line);
6235 }
6236 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6237 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6238 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6239
6240 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6241 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6242 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6243 }
6244 else {
6245 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6246 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6247 }
6248 return;
6249 case NODE_COLON3:
6250 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6251 ADD_INSN3(ret, line_node, defined,
6252 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6253 return;
6254
6255 /* method dispatch */
6256 case NODE_CALL:
6257 case NODE_OPCALL:
6258 case NODE_VCALL:
6259 case NODE_FCALL:
6260 case NODE_ATTRASGN:{
6261 const int explicit_receiver =
6262 (type == NODE_CALL || type == NODE_OPCALL ||
6263 (type == NODE_ATTRASGN && !private_recv_p(node)));
6264
6265 if (get_nd_args(node) || explicit_receiver) {
6266 if (!lfinish[1]) {
6267 lfinish[1] = NEW_LABEL(line);
6268 }
6269 if (!lfinish[2]) {
6270 lfinish[2] = NEW_LABEL(line);
6271 }
6272 }
6273 if (get_nd_args(node)) {
6274 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6275 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6276 }
6277 if (explicit_receiver) {
6278 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6279 switch (nd_type(get_nd_recv(node))) {
6280 case NODE_CALL:
6281 case NODE_OPCALL:
6282 case NODE_VCALL:
6283 case NODE_FCALL:
6284 case NODE_ATTRASGN:
6285 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6286 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6287 break;
6288 default:
6289 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6290 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6291 break;
6292 }
6293 if (keep_result) {
6294 ADD_INSN(ret, line_node, dup);
6295 }
6296 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6297 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6298 }
6299 else {
6300 ADD_INSN(ret, line_node, putself);
6301 if (keep_result) {
6302 ADD_INSN(ret, line_node, dup);
6303 }
6304 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6305 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6306 }
6307 return;
6308 }
6309
6310 case NODE_YIELD:
6311 ADD_INSN(ret, line_node, putnil);
6312 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6313 PUSH_VAL(DEFINED_YIELD));
6314 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6315 return;
6316
6317 case NODE_BACK_REF:
6318 case NODE_NTH_REF:
6319 ADD_INSN(ret, line_node, putnil);
6320 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6321 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6322 PUSH_VAL(DEFINED_GVAR));
6323 return;
6324
6325 case NODE_SUPER:
6326 case NODE_ZSUPER:
6327 ADD_INSN(ret, line_node, putnil);
6328 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6329 PUSH_VAL(DEFINED_ZSUPER));
6330 return;
6331
6332#undef PUSH_VAL
6333 case NODE_OP_ASGN1:
6334 case NODE_OP_ASGN2:
6335 case NODE_OP_ASGN_OR:
6336 case NODE_OP_ASGN_AND:
6337 case NODE_MASGN:
6338 case NODE_LASGN:
6339 case NODE_DASGN:
6340 case NODE_GASGN:
6341 case NODE_IASGN:
6342 case NODE_CDECL:
6343 case NODE_CVASGN:
6344 case NODE_OP_CDECL:
6345 expr_type = DEFINED_ASGN;
6346 break;
6347 }
6348
6349 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6350
6351 if (needstr != Qfalse) {
6352 VALUE str = rb_iseq_defined_string(expr_type);
6353 ADD_INSN1(ret, line_node, putobject, str);
6354 }
6355 else {
6356 ADD_INSN1(ret, line_node, putobject, Qtrue);
6357 }
6358}
6359
6360static void
6361build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6362{
6363 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6364 iseq_set_exception_local_table(iseq);
6365}
6366
6367static void
6368defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6369 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6370{
6371 LINK_ELEMENT *lcur = ret->last;
6372 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6373 if (lfinish[1]) {
6374 int line = nd_line(node);
6375 LABEL *lstart = NEW_LABEL(line);
6376 LABEL *lend = NEW_LABEL(line);
6377 const rb_iseq_t *rescue;
6379 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6380 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6381 rb_str_concat(rb_str_new2("defined guard in "),
6382 ISEQ_BODY(iseq)->location.label),
6383 ISEQ_TYPE_RESCUE, 0);
6384 lstart->rescued = LABEL_RESCUE_BEG;
6385 lend->rescued = LABEL_RESCUE_END;
6386 APPEND_LABEL(ret, lcur, lstart);
6387 ADD_LABEL(ret, lend);
6388 if (!ignore) {
6389 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6390 }
6391 }
6392}
6393
6394static int
6395compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6396{
6397 const int line = nd_line(node);
6398 const NODE *line_node = node;
6399 if (!RNODE_DEFINED(node)->nd_head) {
6400 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6401 ADD_INSN1(ret, line_node, putobject, str);
6402 }
6403 else {
6404 LABEL *lfinish[3];
6405 LINK_ELEMENT *last = ret->last;
6406 lfinish[0] = NEW_LABEL(line);
6407 lfinish[1] = 0;
6408 lfinish[2] = 0;
6409 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6410 if (lfinish[1]) {
6411 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6412 ADD_INSN(ret, line_node, swap);
6413 if (lfinish[2]) {
6414 ADD_LABEL(ret, lfinish[2]);
6415 }
6416 ADD_INSN(ret, line_node, pop);
6417 ADD_LABEL(ret, lfinish[1]);
6418 }
6419 ADD_LABEL(ret, lfinish[0]);
6420 }
6421 return COMPILE_OK;
6422}
6423
6424static VALUE
6425make_name_for_block(const rb_iseq_t *orig_iseq)
6426{
6427 int level = 1;
6428 const rb_iseq_t *iseq = orig_iseq;
6429
6430 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6431 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6432 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6433 level++;
6434 }
6435 iseq = ISEQ_BODY(iseq)->parent_iseq;
6436 }
6437 }
6438
6439 if (level == 1) {
6440 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6441 }
6442 else {
6443 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6444 }
6445}
6446
6447static void
6448push_ensure_entry(rb_iseq_t *iseq,
6450 struct ensure_range *er, const void *const node)
6451{
6452 enl->ensure_node = node;
6453 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6454 enl->erange = er;
6455 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6456}
6457
6458static void
6459add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6460 LABEL *lstart, LABEL *lend)
6461{
6462 struct ensure_range *ne =
6463 compile_data_alloc(iseq, sizeof(struct ensure_range));
6464
6465 while (erange->next != 0) {
6466 erange = erange->next;
6467 }
6468 ne->next = 0;
6469 ne->begin = lend;
6470 ne->end = erange->end;
6471 erange->end = lstart;
6472
6473 erange->next = ne;
6474}
6475
6476static bool
6477can_add_ensure_iseq(const rb_iseq_t *iseq)
6478{
6480 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6481 while (e) {
6482 if (e->ensure_node) return false;
6483 e = e->prev;
6484 }
6485 }
6486 return true;
6487}
6488
6489static void
6490add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6491{
6492 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6493
6495 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6496 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6497 DECL_ANCHOR(ensure);
6498
6499 INIT_ANCHOR(ensure);
6500 while (enlp) {
6501 if (enlp->erange != NULL) {
6502 DECL_ANCHOR(ensure_part);
6503 LABEL *lstart = NEW_LABEL(0);
6504 LABEL *lend = NEW_LABEL(0);
6505 INIT_ANCHOR(ensure_part);
6506
6507 add_ensure_range(iseq, enlp->erange, lstart, lend);
6508
6509 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6510 ADD_LABEL(ensure_part, lstart);
6511 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6512 ADD_LABEL(ensure_part, lend);
6513 ADD_SEQ(ensure, ensure_part);
6514 }
6515 else {
6516 if (!is_return) {
6517 break;
6518 }
6519 }
6520 enlp = enlp->prev;
6521 }
6522 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6523 ADD_SEQ(ret, ensure);
6524}
6525
6526#if RUBY_DEBUG
6527static int
6528check_keyword(const NODE *node)
6529{
6530 /* This check is essentially a code clone of compile_keyword_arg. */
6531
6532 if (nd_type_p(node, NODE_LIST)) {
6533 while (RNODE_LIST(node)->nd_next) {
6534 node = RNODE_LIST(node)->nd_next;
6535 }
6536 node = RNODE_LIST(node)->nd_head;
6537 }
6538
6539 return keyword_node_p(node);
6540}
6541#endif
6542
6543static bool
6544keyword_node_single_splat_p(NODE *kwnode)
6545{
6546 RUBY_ASSERT(keyword_node_p(kwnode));
6547
6548 NODE *node = RNODE_HASH(kwnode)->nd_head;
6549 return RNODE_LIST(node)->nd_head == NULL &&
6550 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6551}
6552
6553static void
6554compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6555 NODE *kwnode, unsigned int *flag_ptr)
6556{
6557 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6558 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6559 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6560 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6561 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6562}
6563
6564#define SPLATARRAY_FALSE 0
6565#define SPLATARRAY_TRUE 1
6566#define DUP_SINGLE_KW_SPLAT 2
6567
6568static int
6569setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6570 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6571{
6572 if (!argn) return 0;
6573
6574 NODE *kwnode = NULL;
6575
6576 switch (nd_type(argn)) {
6577 case NODE_LIST: {
6578 // f(x, y, z)
6579 int len = compile_args(iseq, args, argn, &kwnode);
6580 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6581
6582 if (kwnode) {
6583 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6584 len -= 1;
6585 }
6586 else {
6587 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6588 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6589 }
6590 else {
6591 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6592 }
6593 }
6594 }
6595
6596 return len;
6597 }
6598 case NODE_SPLAT: {
6599 // f(*a)
6600 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6601 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6602 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6603 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6604 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6605 return 1;
6606 }
6607 case NODE_ARGSCAT: {
6608 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6609 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6610 bool args_pushed = false;
6611
6612 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6613 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6614 if (kwnode) rest_len--;
6615 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6616 args_pushed = true;
6617 }
6618 else {
6619 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6620 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6621 }
6622
6623 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6624 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6625 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6626 argc += 1;
6627 }
6628 else if (!args_pushed) {
6629 ADD_INSN(args, argn, concattoarray);
6630 }
6631
6632 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6633 if (kwnode) {
6634 // kwsplat
6635 *flag_ptr |= VM_CALL_KW_SPLAT;
6636 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6637 argc += 1;
6638 }
6639
6640 return argc;
6641 }
6642 case NODE_ARGSPUSH: {
6643 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6644 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6645
6646 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6647 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6648 if (kwnode) rest_len--;
6649 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6650 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6651 }
6652 else {
6653 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6654 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6655 }
6656 else {
6657 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6658 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6659 }
6660 }
6661
6662 if (kwnode) {
6663 // f(*a, k:1)
6664 *flag_ptr |= VM_CALL_KW_SPLAT;
6665 if (!keyword_node_single_splat_p(kwnode)) {
6666 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6667 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6668 }
6669 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6670 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6671 }
6672 else {
6673 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6674 }
6675 argc += 1;
6676 }
6677
6678 return argc;
6679 }
6680 default: {
6681 UNKNOWN_NODE("setup_arg", argn, Qnil);
6682 }
6683 }
6684}
6685
6686static void
6687setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6688{
6689 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6690 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6691 }
6692}
6693
6694static bool
6695setup_args_dup_rest_p(const NODE *argn)
6696{
6697 switch(nd_type(argn)) {
6698 case NODE_LVAR:
6699 case NODE_DVAR:
6700 case NODE_GVAR:
6701 case NODE_IVAR:
6702 case NODE_CVAR:
6703 case NODE_CONST:
6704 case NODE_COLON3:
6705 case NODE_INTEGER:
6706 case NODE_FLOAT:
6707 case NODE_RATIONAL:
6708 case NODE_IMAGINARY:
6709 case NODE_STR:
6710 case NODE_SYM:
6711 case NODE_REGX:
6712 case NODE_SELF:
6713 case NODE_NIL:
6714 case NODE_TRUE:
6715 case NODE_FALSE:
6716 case NODE_LAMBDA:
6717 case NODE_NTH_REF:
6718 case NODE_BACK_REF:
6719 return false;
6720 case NODE_COLON2:
6721 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6722 case NODE_LIST:
6723 while (argn) {
6724 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6725 return true;
6726 }
6727 argn = RNODE_LIST(argn)->nd_next;
6728 }
6729 return false;
6730 default:
6731 return true;
6732 }
6733}
6734
6735static VALUE
6736setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6737 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6738{
6739 VALUE ret;
6740 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6741
6742 if (argn) {
6743 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6744 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6745
6746 if (check_arg) {
6747 switch(nd_type(check_arg)) {
6748 case(NODE_SPLAT):
6749 // avoid caller side array allocation for f(*arg)
6750 dup_rest = SPLATARRAY_FALSE;
6751 break;
6752 case(NODE_ARGSCAT):
6753 // avoid caller side array allocation for f(1, *arg)
6754 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6755 break;
6756 case(NODE_ARGSPUSH):
6757 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6758 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6759 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6760 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6761 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6762 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6763
6764 if (dup_rest == SPLATARRAY_FALSE) {
6765 // require allocation for keyword key/value/splat that may modify splatted argument
6766 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6767 while (node) {
6768 NODE *key_node = RNODE_LIST(node)->nd_head;
6769 if (key_node && setup_args_dup_rest_p(key_node)) {
6770 dup_rest = SPLATARRAY_TRUE;
6771 break;
6772 }
6773
6774 node = RNODE_LIST(node)->nd_next;
6775 NODE *value_node = RNODE_LIST(node)->nd_head;
6776 if (setup_args_dup_rest_p(value_node)) {
6777 dup_rest = SPLATARRAY_TRUE;
6778 break;
6779 }
6780
6781 node = RNODE_LIST(node)->nd_next;
6782 }
6783 }
6784 break;
6785 default:
6786 break;
6787 }
6788 }
6789
6790 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6791 // for block pass that may modify splatted argument, dup rest and kwrest if given
6792 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6793 }
6794 }
6795 initial_dup_rest = dup_rest;
6796
6797 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6798 DECL_ANCHOR(arg_block);
6799 INIT_ANCHOR(arg_block);
6800
6801 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6802 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6803
6804 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6805 const NODE * arg_node =
6806 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6807
6808 int argc = 0;
6809
6810 // Only compile leading args:
6811 // foo(x, y, ...)
6812 // ^^^^
6813 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6814 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6815 }
6816
6817 *flag |= VM_CALL_FORWARDING;
6818
6819 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6820 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6821 return INT2FIX(argc);
6822 }
6823 else {
6824 *flag |= VM_CALL_ARGS_BLOCKARG;
6825
6826 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6827 }
6828
6829 if (LIST_INSN_SIZE_ONE(arg_block)) {
6830 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6831 if (IS_INSN(elem)) {
6832 INSN *iobj = (INSN *)elem;
6833 if (iobj->insn_id == BIN(getblockparam)) {
6834 iobj->insn_id = BIN(getblockparamproxy);
6835 }
6836 }
6837 }
6838 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6839 ADD_SEQ(args, arg_block);
6840 }
6841 else {
6842 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6843 }
6844 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6845 return ret;
6846}
6847
6848static void
6849build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6850{
6851 const NODE *body = ptr;
6852 int line = nd_line(body);
6853 VALUE argc = INT2FIX(0);
6854 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6855
6856 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6857 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6858 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6859 iseq_set_local_table(iseq, 0, 0);
6860}
6861
6862static void
6863compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6864{
6865 const NODE *vars;
6866 LINK_ELEMENT *last;
6867 int line = nd_line(node);
6868 const NODE *line_node = node;
6869 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6870
6871#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6872 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6873#else
6874 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6875#endif
6876 ADD_INSN(ret, line_node, dup);
6877 ADD_INSNL(ret, line_node, branchunless, fail_label);
6878
6879 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6880 INSN *cap;
6881 if (RNODE_BLOCK(vars)->nd_next) {
6882 ADD_INSN(ret, line_node, dup);
6883 }
6884 last = ret->last;
6885 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6886 last = last->next; /* putobject :var */
6887 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6888 NULL, INT2FIX(0), NULL);
6889 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6890#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6891 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6892 /* only one name */
6893 DECL_ANCHOR(nom);
6894
6895 INIT_ANCHOR(nom);
6896 ADD_INSNL(nom, line_node, jump, end_label);
6897 ADD_LABEL(nom, fail_label);
6898# if 0 /* $~ must be MatchData or nil */
6899 ADD_INSN(nom, line_node, pop);
6900 ADD_INSN(nom, line_node, putnil);
6901# endif
6902 ADD_LABEL(nom, end_label);
6903 (nom->last->next = cap->link.next)->prev = nom->last;
6904 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6905 return;
6906 }
6907#endif
6908 }
6909 ADD_INSNL(ret, line_node, jump, end_label);
6910 ADD_LABEL(ret, fail_label);
6911 ADD_INSN(ret, line_node, pop);
6912 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6913 last = ret->last;
6914 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6915 last = last->next; /* putobject :var */
6916 ((INSN*)last)->insn_id = BIN(putnil);
6917 ((INSN*)last)->operand_size = 0;
6918 }
6919 ADD_LABEL(ret, end_label);
6920}
6921
6922static int
6923optimizable_range_item_p(const NODE *n)
6924{
6925 if (!n) return FALSE;
6926 switch (nd_type(n)) {
6927 case NODE_LINE:
6928 return TRUE;
6929 case NODE_INTEGER:
6930 return TRUE;
6931 case NODE_NIL:
6932 return TRUE;
6933 default:
6934 return FALSE;
6935 }
6936}
6937
6938static VALUE
6939optimized_range_item(const NODE *n)
6940{
6941 switch (nd_type(n)) {
6942 case NODE_LINE:
6943 return rb_node_line_lineno_val(n);
6944 case NODE_INTEGER:
6945 return rb_node_integer_literal_val(n);
6946 case NODE_FLOAT:
6947 return rb_node_float_literal_val(n);
6948 case NODE_RATIONAL:
6949 return rb_node_rational_literal_val(n);
6950 case NODE_IMAGINARY:
6951 return rb_node_imaginary_literal_val(n);
6952 case NODE_NIL:
6953 return Qnil;
6954 default:
6955 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6956 }
6957}
6958
6959static int
6960compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6961{
6962 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6963 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6964
6965 const int line = nd_line(node);
6966 const NODE *line_node = node;
6967 DECL_ANCHOR(cond_seq);
6968 LABEL *then_label, *else_label, *end_label;
6969 VALUE branches = Qfalse;
6970
6971 INIT_ANCHOR(cond_seq);
6972 then_label = NEW_LABEL(line);
6973 else_label = NEW_LABEL(line);
6974 end_label = 0;
6975
6976 NODE *cond = RNODE_IF(node)->nd_cond;
6977 if (nd_type(cond) == NODE_BLOCK) {
6978 cond = RNODE_BLOCK(cond)->nd_head;
6979 }
6980
6981 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6982 ADD_SEQ(ret, cond_seq);
6983
6984 if (then_label->refcnt && else_label->refcnt) {
6985 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6986 }
6987
6988 if (then_label->refcnt) {
6989 ADD_LABEL(ret, then_label);
6990
6991 DECL_ANCHOR(then_seq);
6992 INIT_ANCHOR(then_seq);
6993 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6994
6995 if (else_label->refcnt) {
6996 const NODE *const coverage_node = node_body ? node_body : node;
6997 add_trace_branch_coverage(
6998 iseq,
6999 ret,
7000 nd_code_loc(coverage_node),
7001 nd_node_id(coverage_node),
7002 0,
7003 type == NODE_IF ? "then" : "else",
7004 branches);
7005 end_label = NEW_LABEL(line);
7006 ADD_INSNL(then_seq, line_node, jump, end_label);
7007 if (!popped) {
7008 ADD_INSN(then_seq, line_node, pop);
7009 }
7010 }
7011 ADD_SEQ(ret, then_seq);
7012 }
7013
7014 if (else_label->refcnt) {
7015 ADD_LABEL(ret, else_label);
7016
7017 DECL_ANCHOR(else_seq);
7018 INIT_ANCHOR(else_seq);
7019 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7020
7021 if (then_label->refcnt) {
7022 const NODE *const coverage_node = node_else ? node_else : node;
7023 add_trace_branch_coverage(
7024 iseq,
7025 ret,
7026 nd_code_loc(coverage_node),
7027 nd_node_id(coverage_node),
7028 1,
7029 type == NODE_IF ? "else" : "then",
7030 branches);
7031 }
7032 ADD_SEQ(ret, else_seq);
7033 }
7034
7035 if (end_label) {
7036 ADD_LABEL(ret, end_label);
7037 }
7038
7039 return COMPILE_OK;
7040}
7041
7042static int
7043compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7044{
7045 const NODE *vals;
7046 const NODE *node = orig_node;
7047 LABEL *endlabel, *elselabel;
7048 DECL_ANCHOR(head);
7049 DECL_ANCHOR(body_seq);
7050 DECL_ANCHOR(cond_seq);
7051 int only_special_literals = 1;
7052 VALUE literals = rb_hash_new();
7053 int line;
7054 enum node_type type;
7055 const NODE *line_node;
7056 VALUE branches = Qfalse;
7057 int branch_id = 0;
7058
7059 INIT_ANCHOR(head);
7060 INIT_ANCHOR(body_seq);
7061 INIT_ANCHOR(cond_seq);
7062
7063 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7064
7065 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7066
7067 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7068
7069 node = RNODE_CASE(node)->nd_body;
7070 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7071 type = nd_type(node);
7072 line = nd_line(node);
7073 line_node = node;
7074
7075 endlabel = NEW_LABEL(line);
7076 elselabel = NEW_LABEL(line);
7077
7078 ADD_SEQ(ret, head); /* case VAL */
7079
7080 while (type == NODE_WHEN) {
7081 LABEL *l1;
7082
7083 l1 = NEW_LABEL(line);
7084 ADD_LABEL(body_seq, l1);
7085 ADD_INSN(body_seq, line_node, pop);
7086
7087 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7088 add_trace_branch_coverage(
7089 iseq,
7090 body_seq,
7091 nd_code_loc(coverage_node),
7092 nd_node_id(coverage_node),
7093 branch_id++,
7094 "when",
7095 branches);
7096
7097 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7098 ADD_INSNL(body_seq, line_node, jump, endlabel);
7099
7100 vals = RNODE_WHEN(node)->nd_head;
7101 if (vals) {
7102 switch (nd_type(vals)) {
7103 case NODE_LIST:
7104 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7105 if (only_special_literals < 0) return COMPILE_NG;
7106 break;
7107 case NODE_SPLAT:
7108 case NODE_ARGSCAT:
7109 case NODE_ARGSPUSH:
7110 only_special_literals = 0;
7111 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7112 break;
7113 default:
7114 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7115 }
7116 }
7117 else {
7118 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7119 }
7120
7121 node = RNODE_WHEN(node)->nd_next;
7122 if (!node) {
7123 break;
7124 }
7125 type = nd_type(node);
7126 line = nd_line(node);
7127 line_node = node;
7128 }
7129 /* else */
7130 if (node) {
7131 ADD_LABEL(cond_seq, elselabel);
7132 ADD_INSN(cond_seq, line_node, pop);
7133 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7134 CHECK(COMPILE_(cond_seq, "else", node, popped));
7135 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7136 }
7137 else {
7138 debugs("== else (implicit)\n");
7139 ADD_LABEL(cond_seq, elselabel);
7140 ADD_INSN(cond_seq, orig_node, pop);
7141 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7142 if (!popped) {
7143 ADD_INSN(cond_seq, orig_node, putnil);
7144 }
7145 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7146 }
7147
7148 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7149 ADD_INSN(ret, orig_node, dup);
7150 rb_obj_hide(literals);
7151 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7152 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7153 LABEL_REF(elselabel);
7154 }
7155
7156 ADD_SEQ(ret, cond_seq);
7157 ADD_SEQ(ret, body_seq);
7158 ADD_LABEL(ret, endlabel);
7159 return COMPILE_OK;
7160}
7161
7162static int
7163compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7164{
7165 const NODE *vals;
7166 const NODE *val;
7167 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7168 LABEL *endlabel;
7169 DECL_ANCHOR(body_seq);
7170 VALUE branches = Qfalse;
7171 int branch_id = 0;
7172
7173 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7174
7175 INIT_ANCHOR(body_seq);
7176 endlabel = NEW_LABEL(nd_line(node));
7177
7178 while (node && nd_type_p(node, NODE_WHEN)) {
7179 const int line = nd_line(node);
7180 LABEL *l1 = NEW_LABEL(line);
7181 ADD_LABEL(body_seq, l1);
7182
7183 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7184 add_trace_branch_coverage(
7185 iseq,
7186 body_seq,
7187 nd_code_loc(coverage_node),
7188 nd_node_id(coverage_node),
7189 branch_id++,
7190 "when",
7191 branches);
7192
7193 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7194 ADD_INSNL(body_seq, node, jump, endlabel);
7195
7196 vals = RNODE_WHEN(node)->nd_head;
7197 if (!vals) {
7198 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7199 }
7200 switch (nd_type(vals)) {
7201 case NODE_LIST:
7202 while (vals) {
7203 LABEL *lnext;
7204 val = RNODE_LIST(vals)->nd_head;
7205 lnext = NEW_LABEL(nd_line(val));
7206 debug_compile("== when2\n", (void)0);
7207 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7208 ADD_LABEL(ret, lnext);
7209 vals = RNODE_LIST(vals)->nd_next;
7210 }
7211 break;
7212 case NODE_SPLAT:
7213 case NODE_ARGSCAT:
7214 case NODE_ARGSPUSH:
7215 ADD_INSN(ret, vals, putnil);
7216 CHECK(COMPILE(ret, "when2/cond splat", vals));
7217 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7218 ADD_INSNL(ret, vals, branchif, l1);
7219 break;
7220 default:
7221 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7222 }
7223 node = RNODE_WHEN(node)->nd_next;
7224 }
7225 /* else */
7226 const NODE *const coverage_node = node ? node : orig_node;
7227 add_trace_branch_coverage(
7228 iseq,
7229 ret,
7230 nd_code_loc(coverage_node),
7231 nd_node_id(coverage_node),
7232 branch_id,
7233 "else",
7234 branches);
7235 CHECK(COMPILE_(ret, "else", node, popped));
7236 ADD_INSNL(ret, orig_node, jump, endlabel);
7237
7238 ADD_SEQ(ret, body_seq);
7239 ADD_LABEL(ret, endlabel);
7240 return COMPILE_OK;
7241}
7242
7243static 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);
7244
7245static 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);
7246static 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);
7247static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7248static 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);
7249static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7250
7251#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7252#define CASE3_BI_OFFSET_ERROR_STRING 1
7253#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7254#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7255#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7256
7257static int
7258iseq_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)
7259{
7260 const int line = nd_line(node);
7261 const NODE *line_node = node;
7262
7263 switch (nd_type(node)) {
7264 case NODE_ARYPTN: {
7265 /*
7266 * if pattern.use_rest_num?
7267 * rest_num = 0
7268 * end
7269 * if pattern.has_constant_node?
7270 * unless pattern.constant === obj
7271 * goto match_failed
7272 * end
7273 * end
7274 * unless obj.respond_to?(:deconstruct)
7275 * goto match_failed
7276 * end
7277 * d = obj.deconstruct
7278 * unless Array === d
7279 * goto type_error
7280 * end
7281 * min_argc = pattern.pre_args_num + pattern.post_args_num
7282 * if pattern.has_rest_arg?
7283 * unless d.length >= min_argc
7284 * goto match_failed
7285 * end
7286 * else
7287 * unless d.length == min_argc
7288 * goto match_failed
7289 * end
7290 * end
7291 * pattern.pre_args_num.each do |i|
7292 * unless pattern.pre_args[i].match?(d[i])
7293 * goto match_failed
7294 * end
7295 * end
7296 * if pattern.use_rest_num?
7297 * rest_num = d.length - min_argc
7298 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7299 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7300 * goto match_failed
7301 * end
7302 * end
7303 * end
7304 * pattern.post_args_num.each do |i|
7305 * j = pattern.pre_args_num + i
7306 * j += rest_num
7307 * unless pattern.post_args[i].match?(d[j])
7308 * goto match_failed
7309 * end
7310 * end
7311 * goto matched
7312 * type_error:
7313 * FrozenCore.raise TypeError
7314 * match_failed:
7315 * goto unmatched
7316 */
7317 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7318 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7319 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7320
7321 const int min_argc = pre_args_num + post_args_num;
7322 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7323 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7324
7325 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7326 int i;
7327 match_failed = NEW_LABEL(line);
7328 type_error = NEW_LABEL(line);
7329 deconstruct = NEW_LABEL(line);
7330 deconstructed = NEW_LABEL(line);
7331
7332 if (use_rest_num) {
7333 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7334 ADD_INSN(ret, line_node, swap);
7335 if (base_index) {
7336 base_index++;
7337 }
7338 }
7339
7340 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7341
7342 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7343
7344 ADD_INSN(ret, line_node, dup);
7345 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7346 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7347 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7348 if (in_single_pattern) {
7349 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7350 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7351 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7352 INT2FIX(min_argc), base_index + 1 /* (1) */));
7353 }
7354 ADD_INSNL(ret, line_node, branchunless, match_failed);
7355
7356 for (i = 0; i < pre_args_num; i++) {
7357 ADD_INSN(ret, line_node, dup);
7358 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7359 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7360 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));
7361 args = RNODE_LIST(args)->nd_next;
7362 }
7363
7364 if (RNODE_ARYPTN(node)->rest_arg) {
7365 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7366 ADD_INSN(ret, line_node, dup);
7367 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7368 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7369 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7370 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7371 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7372 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7373 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7374
7375 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));
7376 }
7377 else {
7378 if (post_args_num > 0) {
7379 ADD_INSN(ret, line_node, dup);
7380 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7381 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7382 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7383 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7384 ADD_INSN(ret, line_node, pop);
7385 }
7386 }
7387 }
7388
7389 args = RNODE_ARYPTN(node)->post_args;
7390 for (i = 0; i < post_args_num; i++) {
7391 ADD_INSN(ret, line_node, dup);
7392
7393 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7394 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7395 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7396
7397 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7398 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));
7399 args = RNODE_LIST(args)->nd_next;
7400 }
7401
7402 ADD_INSN(ret, line_node, pop);
7403 if (use_rest_num) {
7404 ADD_INSN(ret, line_node, pop);
7405 }
7406 ADD_INSNL(ret, line_node, jump, matched);
7407 ADD_INSN(ret, line_node, putnil);
7408 if (use_rest_num) {
7409 ADD_INSN(ret, line_node, putnil);
7410 }
7411
7412 ADD_LABEL(ret, type_error);
7413 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7414 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7415 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7416 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7417 ADD_INSN(ret, line_node, pop);
7418
7419 ADD_LABEL(ret, match_failed);
7420 ADD_INSN(ret, line_node, pop);
7421 if (use_rest_num) {
7422 ADD_INSN(ret, line_node, pop);
7423 }
7424 ADD_INSNL(ret, line_node, jump, unmatched);
7425
7426 break;
7427 }
7428 case NODE_FNDPTN: {
7429 /*
7430 * if pattern.has_constant_node?
7431 * unless pattern.constant === obj
7432 * goto match_failed
7433 * end
7434 * end
7435 * unless obj.respond_to?(:deconstruct)
7436 * goto match_failed
7437 * end
7438 * d = obj.deconstruct
7439 * unless Array === d
7440 * goto type_error
7441 * end
7442 * unless d.length >= pattern.args_num
7443 * goto match_failed
7444 * end
7445 *
7446 * begin
7447 * len = d.length
7448 * limit = d.length - pattern.args_num
7449 * i = 0
7450 * while i <= limit
7451 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7452 * if pattern.has_pre_rest_arg_id
7453 * unless pattern.pre_rest_arg.match?(d[0, i])
7454 * goto find_failed
7455 * end
7456 * end
7457 * if pattern.has_post_rest_arg_id
7458 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7459 * goto find_failed
7460 * end
7461 * end
7462 * goto find_succeeded
7463 * end
7464 * i+=1
7465 * end
7466 * find_failed:
7467 * goto match_failed
7468 * find_succeeded:
7469 * end
7470 *
7471 * goto matched
7472 * type_error:
7473 * FrozenCore.raise TypeError
7474 * match_failed:
7475 * goto unmatched
7476 */
7477 const NODE *args = RNODE_FNDPTN(node)->args;
7478 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7479
7480 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7481 match_failed = NEW_LABEL(line);
7482 type_error = NEW_LABEL(line);
7483 deconstruct = NEW_LABEL(line);
7484 deconstructed = NEW_LABEL(line);
7485
7486 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7487
7488 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7489
7490 ADD_INSN(ret, line_node, dup);
7491 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7492 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7493 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7494 if (in_single_pattern) {
7495 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) */));
7496 }
7497 ADD_INSNL(ret, line_node, branchunless, match_failed);
7498
7499 {
7500 LABEL *while_begin = NEW_LABEL(nd_line(node));
7501 LABEL *next_loop = NEW_LABEL(nd_line(node));
7502 LABEL *find_succeeded = NEW_LABEL(line);
7503 LABEL *find_failed = NEW_LABEL(nd_line(node));
7504 int j;
7505
7506 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7507 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7508
7509 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7510 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7511 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7512
7513 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7514
7515 ADD_LABEL(ret, while_begin);
7516
7517 ADD_INSN(ret, line_node, dup);
7518 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7519 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7520 ADD_INSNL(ret, line_node, branchunless, find_failed);
7521
7522 for (j = 0; j < args_num; j++) {
7523 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7524 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7525 if (j != 0) {
7526 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7527 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7528 }
7529 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7530
7531 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));
7532 args = RNODE_LIST(args)->nd_next;
7533 }
7534
7535 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7536 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7537 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7538 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7539 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7540 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));
7541 }
7542 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7543 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7544 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7545 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7546 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7547 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7548 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7549 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));
7550 }
7551 ADD_INSNL(ret, line_node, jump, find_succeeded);
7552
7553 ADD_LABEL(ret, next_loop);
7554 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7555 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7556 ADD_INSNL(ret, line_node, jump, while_begin);
7557
7558 ADD_LABEL(ret, find_failed);
7559 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7560 if (in_single_pattern) {
7561 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7562 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7563 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7564 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7565 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7566
7567 ADD_INSN1(ret, line_node, putobject, Qfalse);
7568 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7569
7570 ADD_INSN(ret, line_node, pop);
7571 ADD_INSN(ret, line_node, pop);
7572 }
7573 ADD_INSNL(ret, line_node, jump, match_failed);
7574 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7575
7576 ADD_LABEL(ret, find_succeeded);
7577 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7578 }
7579
7580 ADD_INSN(ret, line_node, pop);
7581 ADD_INSNL(ret, line_node, jump, matched);
7582 ADD_INSN(ret, line_node, putnil);
7583
7584 ADD_LABEL(ret, type_error);
7585 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7586 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7587 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7588 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7589 ADD_INSN(ret, line_node, pop);
7590
7591 ADD_LABEL(ret, match_failed);
7592 ADD_INSN(ret, line_node, pop);
7593 ADD_INSNL(ret, line_node, jump, unmatched);
7594
7595 break;
7596 }
7597 case NODE_HSHPTN: {
7598 /*
7599 * keys = nil
7600 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7601 * keys = pattern.kw_args_node.keys
7602 * end
7603 * if pattern.has_constant_node?
7604 * unless pattern.constant === obj
7605 * goto match_failed
7606 * end
7607 * end
7608 * unless obj.respond_to?(:deconstruct_keys)
7609 * goto match_failed
7610 * end
7611 * d = obj.deconstruct_keys(keys)
7612 * unless Hash === d
7613 * goto type_error
7614 * end
7615 * if pattern.has_kw_rest_arg_node?
7616 * d = d.dup
7617 * end
7618 * if pattern.has_kw_args_node?
7619 * pattern.kw_args_node.each |k,|
7620 * unless d.key?(k)
7621 * goto match_failed
7622 * end
7623 * end
7624 * pattern.kw_args_node.each |k, pat|
7625 * if pattern.has_kw_rest_arg_node?
7626 * unless pat.match?(d.delete(k))
7627 * goto match_failed
7628 * end
7629 * else
7630 * unless pat.match?(d[k])
7631 * goto match_failed
7632 * end
7633 * end
7634 * end
7635 * else
7636 * unless d.empty?
7637 * goto match_failed
7638 * end
7639 * end
7640 * if pattern.has_kw_rest_arg_node?
7641 * if pattern.no_rest_keyword?
7642 * unless d.empty?
7643 * goto match_failed
7644 * end
7645 * else
7646 * unless pattern.kw_rest_arg_node.match?(d)
7647 * goto match_failed
7648 * end
7649 * end
7650 * end
7651 * goto matched
7652 * type_error:
7653 * FrozenCore.raise TypeError
7654 * match_failed:
7655 * goto unmatched
7656 */
7657 LABEL *match_failed, *type_error;
7658 VALUE keys = Qnil;
7659
7660 match_failed = NEW_LABEL(line);
7661 type_error = NEW_LABEL(line);
7662
7663 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7664 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7665 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7666 while (kw_args) {
7667 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7668 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7669 }
7670 }
7671
7672 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7673
7674 ADD_INSN(ret, line_node, dup);
7675 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7676 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7677 if (in_single_pattern) {
7678 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7679 }
7680 ADD_INSNL(ret, line_node, branchunless, match_failed);
7681
7682 if (NIL_P(keys)) {
7683 ADD_INSN(ret, line_node, putnil);
7684 }
7685 else {
7686 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7687 ADD_INSN1(ret, line_node, duparray, keys);
7688 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7689 }
7690 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7691
7692 ADD_INSN(ret, line_node, dup);
7693 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7694 ADD_INSNL(ret, line_node, branchunless, type_error);
7695
7696 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7697 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7698 }
7699
7700 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7701 int i;
7702 int keys_num;
7703 const NODE *args;
7704 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7705 if (args) {
7706 DECL_ANCHOR(match_values);
7707 INIT_ANCHOR(match_values);
7708 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7709 for (i = 0; i < keys_num; i++) {
7710 NODE *key_node = RNODE_LIST(args)->nd_head;
7711 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7712 VALUE key = get_symbol_value(iseq, key_node);
7713
7714 ADD_INSN(ret, line_node, dup);
7715 ADD_INSN1(ret, line_node, putobject, key);
7716 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7717 if (in_single_pattern) {
7718 LABEL *match_succeeded;
7719 match_succeeded = NEW_LABEL(line);
7720
7721 ADD_INSN(ret, line_node, dup);
7722 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7723
7724 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7725 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7726 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7727 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7728 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7729 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7730 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7731 ADD_INSN1(ret, line_node, putobject, key); // (7)
7732 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7733
7734 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7735
7736 ADD_LABEL(ret, match_succeeded);
7737 }
7738 ADD_INSNL(ret, line_node, branchunless, match_failed);
7739
7740 ADD_INSN(match_values, line_node, dup);
7741 ADD_INSN1(match_values, line_node, putobject, key);
7742 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7743 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7744 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7745 }
7746 ADD_SEQ(ret, match_values);
7747 }
7748 }
7749 else {
7750 ADD_INSN(ret, line_node, dup);
7751 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7752 if (in_single_pattern) {
7753 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7754 }
7755 ADD_INSNL(ret, line_node, branchunless, match_failed);
7756 }
7757
7758 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7759 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7760 ADD_INSN(ret, line_node, dup);
7761 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7762 if (in_single_pattern) {
7763 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7764 }
7765 ADD_INSNL(ret, line_node, branchunless, match_failed);
7766 }
7767 else {
7768 ADD_INSN(ret, line_node, dup); // (11)
7769 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));
7770 }
7771 }
7772
7773 ADD_INSN(ret, line_node, pop);
7774 ADD_INSNL(ret, line_node, jump, matched);
7775 ADD_INSN(ret, line_node, putnil);
7776
7777 ADD_LABEL(ret, type_error);
7778 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7779 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7780 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7781 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7782 ADD_INSN(ret, line_node, pop);
7783
7784 ADD_LABEL(ret, match_failed);
7785 ADD_INSN(ret, line_node, pop);
7786 ADD_INSNL(ret, line_node, jump, unmatched);
7787 break;
7788 }
7789 case NODE_SYM:
7790 case NODE_REGX:
7791 case NODE_LINE:
7792 case NODE_INTEGER:
7793 case NODE_FLOAT:
7794 case NODE_RATIONAL:
7795 case NODE_IMAGINARY:
7796 case NODE_FILE:
7797 case NODE_ENCODING:
7798 case NODE_STR:
7799 case NODE_XSTR:
7800 case NODE_DSTR:
7801 case NODE_DSYM:
7802 case NODE_DREGX:
7803 case NODE_LIST:
7804 case NODE_ZLIST:
7805 case NODE_LAMBDA:
7806 case NODE_DOT2:
7807 case NODE_DOT3:
7808 case NODE_CONST:
7809 case NODE_LVAR:
7810 case NODE_DVAR:
7811 case NODE_IVAR:
7812 case NODE_CVAR:
7813 case NODE_GVAR:
7814 case NODE_TRUE:
7815 case NODE_FALSE:
7816 case NODE_SELF:
7817 case NODE_NIL:
7818 case NODE_COLON2:
7819 case NODE_COLON3:
7820 case NODE_BEGIN:
7821 case NODE_BLOCK:
7822 case NODE_ONCE:
7823 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7824 if (in_single_pattern) {
7825 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7826 }
7827 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7828 if (in_single_pattern) {
7829 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7830 }
7831 ADD_INSNL(ret, line_node, branchif, matched);
7832 ADD_INSNL(ret, line_node, jump, unmatched);
7833 break;
7834 case NODE_LASGN: {
7835 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7836 ID id = RNODE_LASGN(node)->nd_vid;
7837 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7838
7839 if (in_alt_pattern) {
7840 const char *name = rb_id2name(id);
7841 if (name && strlen(name) > 0 && name[0] != '_') {
7842 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7843 rb_id2str(id));
7844 return COMPILE_NG;
7845 }
7846 }
7847
7848 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7849 ADD_INSNL(ret, line_node, jump, matched);
7850 break;
7851 }
7852 case NODE_DASGN: {
7853 int idx, lv, ls;
7854 ID id = RNODE_DASGN(node)->nd_vid;
7855
7856 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7857
7858 if (in_alt_pattern) {
7859 const char *name = rb_id2name(id);
7860 if (name && strlen(name) > 0 && name[0] != '_') {
7861 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7862 rb_id2str(id));
7863 return COMPILE_NG;
7864 }
7865 }
7866
7867 if (idx < 0) {
7868 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7869 rb_id2str(id));
7870 return COMPILE_NG;
7871 }
7872 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7873 ADD_INSNL(ret, line_node, jump, matched);
7874 break;
7875 }
7876 case NODE_IF:
7877 case NODE_UNLESS: {
7878 LABEL *match_failed;
7879 match_failed = unmatched;
7880 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7881 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7882 if (in_single_pattern) {
7883 LABEL *match_succeeded;
7884 match_succeeded = NEW_LABEL(line);
7885
7886 ADD_INSN(ret, line_node, dup);
7887 if (nd_type_p(node, NODE_IF)) {
7888 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7889 }
7890 else {
7891 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7892 }
7893
7894 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7895 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7896 ADD_INSN1(ret, line_node, putobject, Qfalse);
7897 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7898
7899 ADD_INSN(ret, line_node, pop);
7900 ADD_INSN(ret, line_node, pop);
7901
7902 ADD_LABEL(ret, match_succeeded);
7903 }
7904 if (nd_type_p(node, NODE_IF)) {
7905 ADD_INSNL(ret, line_node, branchunless, match_failed);
7906 }
7907 else {
7908 ADD_INSNL(ret, line_node, branchif, match_failed);
7909 }
7910 ADD_INSNL(ret, line_node, jump, matched);
7911 break;
7912 }
7913 case NODE_HASH: {
7914 NODE *n;
7915 LABEL *match_failed;
7916 match_failed = NEW_LABEL(line);
7917
7918 n = RNODE_HASH(node)->nd_head;
7919 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7920 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7921 return COMPILE_NG;
7922 }
7923
7924 ADD_INSN(ret, line_node, dup); // (1)
7925 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));
7926 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));
7927 ADD_INSN(ret, line_node, putnil);
7928
7929 ADD_LABEL(ret, match_failed);
7930 ADD_INSN(ret, line_node, pop);
7931 ADD_INSNL(ret, line_node, jump, unmatched);
7932 break;
7933 }
7934 case NODE_OR: {
7935 LABEL *match_succeeded, *fin;
7936 match_succeeded = NEW_LABEL(line);
7937 fin = NEW_LABEL(line);
7938
7939 ADD_INSN(ret, line_node, dup); // (1)
7940 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));
7941 ADD_LABEL(ret, match_succeeded);
7942 ADD_INSN(ret, line_node, pop);
7943 ADD_INSNL(ret, line_node, jump, matched);
7944 ADD_INSN(ret, line_node, putnil);
7945 ADD_LABEL(ret, fin);
7946 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7947 break;
7948 }
7949 default:
7950 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7951 }
7952 return COMPILE_OK;
7953}
7954
7955static int
7956iseq_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)
7957{
7958 LABEL *fin = NEW_LABEL(nd_line(node));
7959 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7960 ADD_LABEL(ret, fin);
7961 return COMPILE_OK;
7962}
7963
7964static int
7965iseq_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)
7966{
7967 const NODE *line_node = node;
7968
7969 if (RNODE_ARYPTN(node)->nd_pconst) {
7970 ADD_INSN(ret, line_node, dup); // (1)
7971 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7972 if (in_single_pattern) {
7973 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7974 }
7975 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7976 if (in_single_pattern) {
7977 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7978 }
7979 ADD_INSNL(ret, line_node, branchunless, match_failed);
7980 }
7981 return COMPILE_OK;
7982}
7983
7984
7985static int
7986iseq_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)
7987{
7988 const NODE *line_node = node;
7989
7990 // NOTE: this optimization allows us to re-use the #deconstruct value
7991 // (or its absence).
7992 if (use_deconstructed_cache) {
7993 // If value is nil then we haven't tried to deconstruct
7994 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7995 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7996
7997 // If false then the value is not deconstructable
7998 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7999 ADD_INSNL(ret, line_node, branchunless, match_failed);
8000
8001 // Drop value, add deconstructed to the stack and jump
8002 ADD_INSN(ret, line_node, pop); // (1)
8003 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8004 ADD_INSNL(ret, line_node, jump, deconstructed);
8005 }
8006 else {
8007 ADD_INSNL(ret, line_node, jump, deconstruct);
8008 }
8009
8010 ADD_LABEL(ret, deconstruct);
8011 ADD_INSN(ret, line_node, dup);
8012 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8013 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8014
8015 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8016 if (use_deconstructed_cache) {
8017 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8018 }
8019
8020 if (in_single_pattern) {
8021 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8022 }
8023
8024 ADD_INSNL(ret, line_node, branchunless, match_failed);
8025
8026 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8027
8028 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8029 if (use_deconstructed_cache) {
8030 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8031 }
8032
8033 ADD_INSN(ret, line_node, dup);
8034 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8035 ADD_INSNL(ret, line_node, branchunless, type_error);
8036
8037 ADD_LABEL(ret, deconstructed);
8038
8039 return COMPILE_OK;
8040}
8041
8042static int
8043iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8044{
8045 /*
8046 * if match_succeeded?
8047 * goto match_succeeded
8048 * end
8049 * error_string = FrozenCore.sprintf(errmsg, matchee)
8050 * key_error_p = false
8051 * match_succeeded:
8052 */
8053 const int line = nd_line(node);
8054 const NODE *line_node = node;
8055 LABEL *match_succeeded = NEW_LABEL(line);
8056
8057 ADD_INSN(ret, line_node, dup);
8058 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8059
8060 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8061 ADD_INSN1(ret, line_node, putobject, errmsg);
8062 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8063 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8064 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8065
8066 ADD_INSN1(ret, line_node, putobject, Qfalse);
8067 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8068
8069 ADD_INSN(ret, line_node, pop);
8070 ADD_INSN(ret, line_node, pop);
8071 ADD_LABEL(ret, match_succeeded);
8072
8073 return COMPILE_OK;
8074}
8075
8076static int
8077iseq_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)
8078{
8079 /*
8080 * if match_succeeded?
8081 * goto match_succeeded
8082 * end
8083 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8084 * key_error_p = false
8085 * match_succeeded:
8086 */
8087 const int line = nd_line(node);
8088 const NODE *line_node = node;
8089 LABEL *match_succeeded = NEW_LABEL(line);
8090
8091 ADD_INSN(ret, line_node, dup);
8092 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8093
8094 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8095 ADD_INSN1(ret, line_node, putobject, errmsg);
8096 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8097 ADD_INSN(ret, line_node, dup);
8098 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8099 ADD_INSN1(ret, line_node, putobject, pattern_length);
8100 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8101 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8102
8103 ADD_INSN1(ret, line_node, putobject, Qfalse);
8104 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8105
8106 ADD_INSN(ret, line_node, pop);
8107 ADD_INSN(ret, line_node, pop);
8108 ADD_LABEL(ret, match_succeeded);
8109
8110 return COMPILE_OK;
8111}
8112
8113static int
8114iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8115{
8116 /*
8117 * if match_succeeded?
8118 * goto match_succeeded
8119 * end
8120 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8121 * key_error_p = false
8122 * match_succeeded:
8123 */
8124 const int line = nd_line(node);
8125 const NODE *line_node = node;
8126 LABEL *match_succeeded = NEW_LABEL(line);
8127
8128 ADD_INSN(ret, line_node, dup);
8129 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8130
8131 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8132 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8133 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8134 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8135 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8136 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8137
8138 ADD_INSN1(ret, line_node, putobject, Qfalse);
8139 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8140
8141 ADD_INSN(ret, line_node, pop);
8142 ADD_INSN(ret, line_node, pop);
8143
8144 ADD_LABEL(ret, match_succeeded);
8145 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8146 ADD_INSN(ret, line_node, pop);
8147 ADD_INSN(ret, line_node, pop);
8148
8149 return COMPILE_OK;
8150}
8151
8152static int
8153compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8154{
8155 const NODE *pattern;
8156 const NODE *node = orig_node;
8157 LABEL *endlabel, *elselabel;
8158 DECL_ANCHOR(head);
8159 DECL_ANCHOR(body_seq);
8160 DECL_ANCHOR(cond_seq);
8161 int line;
8162 enum node_type type;
8163 const NODE *line_node;
8164 VALUE branches = 0;
8165 int branch_id = 0;
8166 bool single_pattern;
8167
8168 INIT_ANCHOR(head);
8169 INIT_ANCHOR(body_seq);
8170 INIT_ANCHOR(cond_seq);
8171
8172 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8173
8174 node = RNODE_CASE3(node)->nd_body;
8175 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8176 type = nd_type(node);
8177 line = nd_line(node);
8178 line_node = node;
8179 single_pattern = !RNODE_IN(node)->nd_next;
8180
8181 endlabel = NEW_LABEL(line);
8182 elselabel = NEW_LABEL(line);
8183
8184 if (single_pattern) {
8185 /* allocate stack for ... */
8186 ADD_INSN(head, line_node, putnil); /* key_error_key */
8187 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8188 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8189 ADD_INSN(head, line_node, putnil); /* error_string */
8190 }
8191 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8192
8193 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8194
8195 ADD_SEQ(ret, head); /* case VAL */
8196
8197 while (type == NODE_IN) {
8198 LABEL *l1;
8199
8200 if (branch_id) {
8201 ADD_INSN(body_seq, line_node, putnil);
8202 }
8203 l1 = NEW_LABEL(line);
8204 ADD_LABEL(body_seq, l1);
8205 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8206
8207 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8208 add_trace_branch_coverage(
8209 iseq,
8210 body_seq,
8211 nd_code_loc(coverage_node),
8212 nd_node_id(coverage_node),
8213 branch_id++,
8214 "in",
8215 branches);
8216
8217 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8218 ADD_INSNL(body_seq, line_node, jump, endlabel);
8219
8220 pattern = RNODE_IN(node)->nd_head;
8221 if (pattern) {
8222 int pat_line = nd_line(pattern);
8223 LABEL *next_pat = NEW_LABEL(pat_line);
8224 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8225 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8226 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8227 ADD_LABEL(cond_seq, next_pat);
8228 LABEL_UNREMOVABLE(next_pat);
8229 }
8230 else {
8231 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8232 return COMPILE_NG;
8233 }
8234
8235 node = RNODE_IN(node)->nd_next;
8236 if (!node) {
8237 break;
8238 }
8239 type = nd_type(node);
8240 line = nd_line(node);
8241 line_node = node;
8242 }
8243 /* else */
8244 if (node) {
8245 ADD_LABEL(cond_seq, elselabel);
8246 ADD_INSN(cond_seq, line_node, pop);
8247 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8248 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8249 CHECK(COMPILE_(cond_seq, "else", node, popped));
8250 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8251 ADD_INSN(cond_seq, line_node, putnil);
8252 if (popped) {
8253 ADD_INSN(cond_seq, line_node, putnil);
8254 }
8255 }
8256 else {
8257 debugs("== else (implicit)\n");
8258 ADD_LABEL(cond_seq, elselabel);
8259 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8260 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8261
8262 if (single_pattern) {
8263 /*
8264 * if key_error_p
8265 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8266 * else
8267 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8268 * end
8269 */
8270 LABEL *key_error, *fin;
8271 struct rb_callinfo_kwarg *kw_arg;
8272
8273 key_error = NEW_LABEL(line);
8274 fin = NEW_LABEL(line);
8275
8276 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8277 kw_arg->references = 0;
8278 kw_arg->keyword_len = 2;
8279 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8280 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8281
8282 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8283 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8284 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8285 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8286 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8287 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8288 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8289 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8290 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8291 ADD_INSNL(cond_seq, orig_node, jump, fin);
8292
8293 ADD_LABEL(cond_seq, key_error);
8294 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8295 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8296 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8297 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8298 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8299 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8300 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8301 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8302 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8303 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8304
8305 ADD_LABEL(cond_seq, fin);
8306 }
8307 else {
8308 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8309 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8310 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8311 }
8312 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8313 if (!popped) {
8314 ADD_INSN(cond_seq, orig_node, putnil);
8315 }
8316 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8317 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8318 if (popped) {
8319 ADD_INSN(cond_seq, line_node, putnil);
8320 }
8321 }
8322
8323 ADD_SEQ(ret, cond_seq);
8324 ADD_SEQ(ret, body_seq);
8325 ADD_LABEL(ret, endlabel);
8326 return COMPILE_OK;
8327}
8328
8329#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8330#undef CASE3_BI_OFFSET_ERROR_STRING
8331#undef CASE3_BI_OFFSET_KEY_ERROR_P
8332#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8333#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8334
8335static int
8336compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8337{
8338 const int line = (int)nd_line(node);
8339 const NODE *line_node = node;
8340
8341 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8342 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8343 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8344 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8345 VALUE branches = Qfalse;
8346
8348
8349 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8350 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8351 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8352 LABEL *end_label = NEW_LABEL(line);
8353 LABEL *adjust_label = NEW_LABEL(line);
8354
8355 LABEL *next_catch_label = NEW_LABEL(line);
8356 LABEL *tmp_label = NULL;
8357
8358 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8359 push_ensure_entry(iseq, &enl, NULL, NULL);
8360
8361 if (RNODE_WHILE(node)->nd_state == 1) {
8362 ADD_INSNL(ret, line_node, jump, next_label);
8363 }
8364 else {
8365 tmp_label = NEW_LABEL(line);
8366 ADD_INSNL(ret, line_node, jump, tmp_label);
8367 }
8368 ADD_LABEL(ret, adjust_label);
8369 ADD_INSN(ret, line_node, putnil);
8370 ADD_LABEL(ret, next_catch_label);
8371 ADD_INSN(ret, line_node, pop);
8372 ADD_INSNL(ret, line_node, jump, next_label);
8373 if (tmp_label) ADD_LABEL(ret, tmp_label);
8374
8375 ADD_LABEL(ret, redo_label);
8376 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8377
8378 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8379 add_trace_branch_coverage(
8380 iseq,
8381 ret,
8382 nd_code_loc(coverage_node),
8383 nd_node_id(coverage_node),
8384 0,
8385 "body",
8386 branches);
8387
8388 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8389 ADD_LABEL(ret, next_label); /* next */
8390
8391 if (type == NODE_WHILE) {
8392 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8393 redo_label, end_label));
8394 }
8395 else {
8396 /* until */
8397 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8398 end_label, redo_label));
8399 }
8400
8401 ADD_LABEL(ret, end_label);
8402 ADD_ADJUST_RESTORE(ret, adjust_label);
8403
8404 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8405 /* ADD_INSN(ret, line_node, putundef); */
8406 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8407 return COMPILE_NG;
8408 }
8409 else {
8410 ADD_INSN(ret, line_node, putnil);
8411 }
8412
8413 ADD_LABEL(ret, break_label); /* break */
8414
8415 if (popped) {
8416 ADD_INSN(ret, line_node, pop);
8417 }
8418
8419 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8420 break_label);
8421 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8422 next_catch_label);
8423 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8424 ISEQ_COMPILE_DATA(iseq)->redo_label);
8425
8426 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8427 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8428 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8429 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8430 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8431 return COMPILE_OK;
8432}
8433
8434static int
8435compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8436{
8437 const int line = nd_line(node);
8438 const NODE *line_node = node;
8439 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8440 LABEL *retry_label = NEW_LABEL(line);
8441 LABEL *retry_end_l = NEW_LABEL(line);
8442 const rb_iseq_t *child_iseq;
8443
8444 ADD_LABEL(ret, retry_label);
8445 if (nd_type_p(node, NODE_FOR)) {
8446 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8447
8448 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8449 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8450 ISEQ_TYPE_BLOCK, line);
8451 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8452 }
8453 else {
8454 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8455 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8456 ISEQ_TYPE_BLOCK, line);
8457 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8458 }
8459
8460 {
8461 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8462 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8463 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8464 //
8465 // Normally, "send" instruction is at the last.
8466 // However, qcall under branch coverage measurement adds some instructions after the "send".
8467 //
8468 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8469 INSN *iobj;
8470 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8471 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8472 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8473 iobj = (INSN*) get_prev_insn(iobj);
8474 }
8475 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8476
8477 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8478 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8479 if (&iobj->link == LAST_ELEMENT(ret)) {
8480 ret->last = (LINK_ELEMENT*) retry_end_l;
8481 }
8482 }
8483
8484 if (popped) {
8485 ADD_INSN(ret, line_node, pop);
8486 }
8487
8488 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8489
8490 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8491 return COMPILE_OK;
8492}
8493
8494static int
8495compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8496{
8497 /* massign to var in "for"
8498 * (args.length == 1 && Array.try_convert(args[0])) || args
8499 */
8500 const NODE *line_node = node;
8501 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8502 LABEL *not_single = NEW_LABEL(nd_line(var));
8503 LABEL *not_ary = NEW_LABEL(nd_line(var));
8504 CHECK(COMPILE(ret, "for var", var));
8505 ADD_INSN(ret, line_node, dup);
8506 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8507 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8508 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8509 ADD_INSNL(ret, line_node, branchunless, not_single);
8510 ADD_INSN(ret, line_node, dup);
8511 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8512 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8513 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8514 ADD_INSN(ret, line_node, swap);
8515 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8516 ADD_INSN(ret, line_node, dup);
8517 ADD_INSNL(ret, line_node, branchunless, not_ary);
8518 ADD_INSN(ret, line_node, swap);
8519 ADD_LABEL(ret, not_ary);
8520 ADD_INSN(ret, line_node, pop);
8521 ADD_LABEL(ret, not_single);
8522 return COMPILE_OK;
8523}
8524
8525static int
8526compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8527{
8528 const NODE *line_node = node;
8529 unsigned long throw_flag = 0;
8530
8531 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8532 /* while/until */
8533 LABEL *splabel = NEW_LABEL(0);
8534 ADD_LABEL(ret, splabel);
8535 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8536 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8537 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8538 add_ensure_iseq(ret, iseq, 0);
8539 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8540 ADD_ADJUST_RESTORE(ret, splabel);
8541
8542 if (!popped) {
8543 ADD_INSN(ret, line_node, putnil);
8544 }
8545 }
8546 else {
8547 const rb_iseq_t *ip = iseq;
8548
8549 while (ip) {
8550 if (!ISEQ_COMPILE_DATA(ip)) {
8551 ip = 0;
8552 break;
8553 }
8554
8555 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8556 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8557 }
8558 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8559 throw_flag = 0;
8560 }
8561 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8562 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8563 return COMPILE_NG;
8564 }
8565 else {
8566 ip = ISEQ_BODY(ip)->parent_iseq;
8567 continue;
8568 }
8569
8570 /* escape from block */
8571 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8572 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8573 if (popped) {
8574 ADD_INSN(ret, line_node, pop);
8575 }
8576 return COMPILE_OK;
8577 }
8578 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8579 return COMPILE_NG;
8580 }
8581 return COMPILE_OK;
8582}
8583
8584static int
8585compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8586{
8587 const NODE *line_node = node;
8588 unsigned long throw_flag = 0;
8589
8590 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8591 LABEL *splabel = NEW_LABEL(0);
8592 debugs("next in while loop\n");
8593 ADD_LABEL(ret, splabel);
8594 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8595 add_ensure_iseq(ret, iseq, 0);
8596 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8597 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8598 ADD_ADJUST_RESTORE(ret, splabel);
8599 if (!popped) {
8600 ADD_INSN(ret, line_node, putnil);
8601 }
8602 }
8603 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8604 LABEL *splabel = NEW_LABEL(0);
8605 debugs("next in block\n");
8606 ADD_LABEL(ret, splabel);
8607 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8608 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8609 add_ensure_iseq(ret, iseq, 0);
8610 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8611 ADD_ADJUST_RESTORE(ret, splabel);
8612
8613 if (!popped) {
8614 ADD_INSN(ret, line_node, putnil);
8615 }
8616 }
8617 else {
8618 const rb_iseq_t *ip = iseq;
8619
8620 while (ip) {
8621 if (!ISEQ_COMPILE_DATA(ip)) {
8622 ip = 0;
8623 break;
8624 }
8625
8626 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8627 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8628 /* while loop */
8629 break;
8630 }
8631 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8632 break;
8633 }
8634 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8635 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8636 return COMPILE_NG;
8637 }
8638
8639 ip = ISEQ_BODY(ip)->parent_iseq;
8640 }
8641 if (ip != 0) {
8642 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8643 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8644
8645 if (popped) {
8646 ADD_INSN(ret, line_node, pop);
8647 }
8648 }
8649 else {
8650 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8651 return COMPILE_NG;
8652 }
8653 }
8654 return COMPILE_OK;
8655}
8656
8657static int
8658compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8659{
8660 const NODE *line_node = node;
8661
8662 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8663 LABEL *splabel = NEW_LABEL(0);
8664 debugs("redo in while");
8665 ADD_LABEL(ret, splabel);
8666 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8667 add_ensure_iseq(ret, iseq, 0);
8668 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8669 ADD_ADJUST_RESTORE(ret, splabel);
8670 if (!popped) {
8671 ADD_INSN(ret, line_node, putnil);
8672 }
8673 }
8674 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8675 LABEL *splabel = NEW_LABEL(0);
8676
8677 debugs("redo in block");
8678 ADD_LABEL(ret, splabel);
8679 add_ensure_iseq(ret, iseq, 0);
8680 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8681 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8682 ADD_ADJUST_RESTORE(ret, splabel);
8683
8684 if (!popped) {
8685 ADD_INSN(ret, line_node, putnil);
8686 }
8687 }
8688 else {
8689 const rb_iseq_t *ip = iseq;
8690
8691 while (ip) {
8692 if (!ISEQ_COMPILE_DATA(ip)) {
8693 ip = 0;
8694 break;
8695 }
8696
8697 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8698 break;
8699 }
8700 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8701 break;
8702 }
8703 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8704 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8705 return COMPILE_NG;
8706 }
8707
8708 ip = ISEQ_BODY(ip)->parent_iseq;
8709 }
8710 if (ip != 0) {
8711 ADD_INSN(ret, line_node, putnil);
8712 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8713
8714 if (popped) {
8715 ADD_INSN(ret, line_node, pop);
8716 }
8717 }
8718 else {
8719 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8720 return COMPILE_NG;
8721 }
8722 }
8723 return COMPILE_OK;
8724}
8725
8726static int
8727compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8728{
8729 const NODE *line_node = node;
8730
8731 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8732 ADD_INSN(ret, line_node, putnil);
8733 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8734
8735 if (popped) {
8736 ADD_INSN(ret, line_node, pop);
8737 }
8738 }
8739 else {
8740 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8741 return COMPILE_NG;
8742 }
8743 return COMPILE_OK;
8744}
8745
8746static int
8747compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8748{
8749 const int line = nd_line(node);
8750 const NODE *line_node = node;
8751 LABEL *lstart = NEW_LABEL(line);
8752 LABEL *lend = NEW_LABEL(line);
8753 LABEL *lcont = NEW_LABEL(line);
8754 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8755 rb_str_concat(rb_str_new2("rescue in "),
8756 ISEQ_BODY(iseq)->location.label),
8757 ISEQ_TYPE_RESCUE, line);
8758
8759 lstart->rescued = LABEL_RESCUE_BEG;
8760 lend->rescued = LABEL_RESCUE_END;
8761 ADD_LABEL(ret, lstart);
8762
8763 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8764 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8765 {
8766 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8767 }
8768 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8769
8770 ADD_LABEL(ret, lend);
8771 if (RNODE_RESCUE(node)->nd_else) {
8772 ADD_INSN(ret, line_node, pop);
8773 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8774 }
8775 ADD_INSN(ret, line_node, nop);
8776 ADD_LABEL(ret, lcont);
8777
8778 if (popped) {
8779 ADD_INSN(ret, line_node, pop);
8780 }
8781
8782 /* register catch entry */
8783 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8784 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8785 return COMPILE_OK;
8786}
8787
8788static int
8789compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8790{
8791 const int line = nd_line(node);
8792 const NODE *line_node = node;
8793 const NODE *resq = node;
8794 const NODE *narg;
8795 LABEL *label_miss, *label_hit;
8796
8797 while (resq) {
8798 label_miss = NEW_LABEL(line);
8799 label_hit = NEW_LABEL(line);
8800
8801 narg = RNODE_RESBODY(resq)->nd_args;
8802 if (narg) {
8803 switch (nd_type(narg)) {
8804 case NODE_LIST:
8805 while (narg) {
8806 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8807 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8808 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8809 ADD_INSNL(ret, line_node, branchif, label_hit);
8810 narg = RNODE_LIST(narg)->nd_next;
8811 }
8812 break;
8813 case NODE_SPLAT:
8814 case NODE_ARGSCAT:
8815 case NODE_ARGSPUSH:
8816 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8817 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8818 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8819 ADD_INSNL(ret, line_node, branchif, label_hit);
8820 break;
8821 default:
8822 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8823 }
8824 }
8825 else {
8826 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8827 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8828 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8829 ADD_INSNL(ret, line_node, branchif, label_hit);
8830 }
8831 ADD_INSNL(ret, line_node, jump, label_miss);
8832 ADD_LABEL(ret, label_hit);
8833 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8834
8835 if (RNODE_RESBODY(resq)->nd_exc_var) {
8836 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8837 }
8838
8839 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) {
8840 // empty body
8841 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8842 }
8843 else {
8844 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8845 }
8846
8847 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8848 ADD_INSN(ret, line_node, nop);
8849 }
8850 ADD_INSN(ret, line_node, leave);
8851 ADD_LABEL(ret, label_miss);
8852 resq = RNODE_RESBODY(resq)->nd_next;
8853 }
8854 return COMPILE_OK;
8855}
8856
8857static int
8858compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8859{
8860 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8861 const NODE *line_node = node;
8862 DECL_ANCHOR(ensr);
8863 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8864 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8865 ISEQ_TYPE_ENSURE, line);
8866 LABEL *lstart = NEW_LABEL(line);
8867 LABEL *lend = NEW_LABEL(line);
8868 LABEL *lcont = NEW_LABEL(line);
8869 LINK_ELEMENT *last;
8870 int last_leave = 0;
8871 struct ensure_range er;
8873 struct ensure_range *erange;
8874
8875 INIT_ANCHOR(ensr);
8876 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8877 last = ensr->last;
8878 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8879
8880 er.begin = lstart;
8881 er.end = lend;
8882 er.next = 0;
8883 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8884
8885 ADD_LABEL(ret, lstart);
8886 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8887 ADD_LABEL(ret, lend);
8888 ADD_SEQ(ret, ensr);
8889 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8890 ADD_LABEL(ret, lcont);
8891 if (last_leave) ADD_INSN(ret, line_node, pop);
8892
8893 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8894 if (lstart->link.next != &lend->link) {
8895 while (erange) {
8896 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8897 ensure, lcont);
8898 erange = erange->next;
8899 }
8900 }
8901
8902 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8903 return COMPILE_OK;
8904}
8905
8906static int
8907compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8908{
8909 const NODE *line_node = node;
8910
8911 if (iseq) {
8912 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8913 const rb_iseq_t *is = iseq;
8914 enum rb_iseq_type t = type;
8915 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8916 LABEL *splabel = 0;
8917
8918 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8919 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8920 t = ISEQ_BODY(is)->type;
8921 }
8922 switch (t) {
8923 case ISEQ_TYPE_TOP:
8924 case ISEQ_TYPE_MAIN:
8925 if (retval) {
8926 rb_warn("argument of top-level return is ignored");
8927 }
8928 if (is == iseq) {
8929 /* plain top-level, leave directly */
8930 type = ISEQ_TYPE_METHOD;
8931 }
8932 break;
8933 default:
8934 break;
8935 }
8936
8937 if (type == ISEQ_TYPE_METHOD) {
8938 splabel = NEW_LABEL(0);
8939 ADD_LABEL(ret, splabel);
8940 ADD_ADJUST(ret, line_node, 0);
8941 }
8942
8943 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8944
8945 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8946 add_ensure_iseq(ret, iseq, 1);
8947 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8948 ADD_INSN(ret, line_node, leave);
8949 ADD_ADJUST_RESTORE(ret, splabel);
8950
8951 if (!popped) {
8952 ADD_INSN(ret, line_node, putnil);
8953 }
8954 }
8955 else {
8956 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8957 if (popped) {
8958 ADD_INSN(ret, line_node, pop);
8959 }
8960 }
8961 }
8962 return COMPILE_OK;
8963}
8964
8965static bool
8966drop_unreachable_return(LINK_ANCHOR *ret)
8967{
8968 LINK_ELEMENT *i = ret->last, *last;
8969 if (!i) return false;
8970 if (IS_TRACE(i)) i = i->prev;
8971 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8972 last = i = i->prev;
8973 if (IS_ADJUST(i)) i = i->prev;
8974 if (!IS_INSN(i)) return false;
8975 switch (INSN_OF(i)) {
8976 case BIN(leave):
8977 case BIN(jump):
8978 break;
8979 default:
8980 return false;
8981 }
8982 (ret->last = last->prev)->next = NULL;
8983 return true;
8984}
8985
8986static int
8987compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8988{
8989 CHECK(COMPILE_(ret, "nd_body", node, popped));
8990
8991 if (!popped && !all_string_result_p(node)) {
8992 const NODE *line_node = node;
8993 const unsigned int flag = VM_CALL_FCALL;
8994
8995 // Note, this dup could be removed if we are willing to change anytostring. It pops
8996 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8997 ADD_INSN(ret, line_node, dup);
8998 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8999 ADD_INSN(ret, line_node, anytostring);
9000 }
9001 return COMPILE_OK;
9002}
9003
9004static void
9005compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9006{
9007 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9008
9009 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9010 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9011}
9012
9013static LABEL *
9014qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9015{
9016 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9017 VALUE br = 0;
9018
9019 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
9020 *branches = br;
9021 ADD_INSN(recv, line_node, dup);
9022 ADD_INSNL(recv, line_node, branchnil, else_label);
9023 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9024 return else_label;
9025}
9026
9027static void
9028qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9029{
9030 LABEL *end_label;
9031 if (!else_label) return;
9032 end_label = NEW_LABEL(nd_line(line_node));
9033 ADD_INSNL(ret, line_node, jump, end_label);
9034 ADD_LABEL(ret, else_label);
9035 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9036 ADD_LABEL(ret, end_label);
9037}
9038
9039static int
9040compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9041{
9042 /* optimization shortcut
9043 * "literal".freeze -> opt_str_freeze("literal")
9044 */
9045 if (get_nd_recv(node) &&
9046 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9047 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9048 get_nd_args(node) == NULL &&
9049 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9050 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9051 VALUE str = get_string_value(get_nd_recv(node));
9052 if (get_node_call_nd_mid(node) == idUMinus) {
9053 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9054 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9055 }
9056 else {
9057 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9058 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9059 }
9060 RB_OBJ_WRITTEN(iseq, Qundef, str);
9061 if (popped) {
9062 ADD_INSN(ret, line_node, pop);
9063 }
9064 return TRUE;
9065 }
9066 return FALSE;
9067}
9068
9069static int
9070iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9071{
9072 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9073}
9074
9075static const struct rb_builtin_function *
9076iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9077{
9078 int i;
9079 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9080 for (i=0; table[i].index != -1; i++) {
9081 if (strcmp(table[i].name, name) == 0) {
9082 return &table[i];
9083 }
9084 }
9085 return NULL;
9086}
9087
9088static const char *
9089iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9090{
9091 const char *name = rb_id2name(mid);
9092 static const char prefix[] = "__builtin_";
9093 const size_t prefix_len = sizeof(prefix) - 1;
9094
9095 switch (type) {
9096 case NODE_CALL:
9097 if (recv) {
9098 switch (nd_type(recv)) {
9099 case NODE_VCALL:
9100 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9101 return name;
9102 }
9103 break;
9104 case NODE_CONST:
9105 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9106 return name;
9107 }
9108 break;
9109 default: break;
9110 }
9111 }
9112 break;
9113 case NODE_VCALL:
9114 case NODE_FCALL:
9115 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9116 return &name[prefix_len];
9117 }
9118 break;
9119 default: break;
9120 }
9121 return NULL;
9122}
9123
9124static int
9125delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9126{
9127
9128 if (argc == 0) {
9129 *pstart_index = 0;
9130 return TRUE;
9131 }
9132 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9133 unsigned int start=0;
9134
9135 // local_table: [p1, p2, p3, l1, l2, l3]
9136 // arguments: [p3, l1, l2] -> 2
9137 for (start = 0;
9138 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9139 start++) {
9140 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9141
9142 for (unsigned int i=start; i-start<argc; i++) {
9143 if (IS_INSN(elem) &&
9144 INSN_OF(elem) == BIN(getlocal)) {
9145 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9146 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9147
9148 if (local_level == 0) {
9149 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9150 if (0) { // for debug
9151 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9152 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9153 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9154 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9155 }
9156 if (i == index) {
9157 elem = elem->next;
9158 continue; /* for */
9159 }
9160 else {
9161 goto next;
9162 }
9163 }
9164 else {
9165 goto fail; // level != 0 is unsupported
9166 }
9167 }
9168 else {
9169 goto fail; // insn is not a getlocal
9170 }
9171 }
9172 goto success;
9173 next:;
9174 }
9175 fail:
9176 return FALSE;
9177 success:
9178 *pstart_index = start;
9179 return TRUE;
9180 }
9181 else {
9182 return FALSE;
9183 }
9184}
9185
9186// Compile Primitive.attr! :leaf, ...
9187static int
9188compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9189{
9190 VALUE symbol;
9191 VALUE string;
9192 if (!node) goto no_arg;
9193 while (node) {
9194 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9195 const NODE *next = RNODE_LIST(node)->nd_next;
9196
9197 node = RNODE_LIST(node)->nd_head;
9198 if (!node) goto no_arg;
9199 switch (nd_type(node)) {
9200 case NODE_SYM:
9201 symbol = rb_node_sym_string_val(node);
9202 break;
9203 default:
9204 goto bad_arg;
9205 }
9206
9207 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9208
9209 string = rb_sym2str(symbol);
9210 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9211 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9212 }
9213 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9214 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9215 }
9216 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9217 iseq_set_use_block(iseq);
9218 }
9219 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9220 // Let the iseq act like a C method in backtraces
9221 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9222 }
9223 else {
9224 goto unknown_arg;
9225 }
9226 node = next;
9227 }
9228 return COMPILE_OK;
9229 no_arg:
9230 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9231 return COMPILE_NG;
9232 non_symbol_arg:
9233 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9234 return COMPILE_NG;
9235 unknown_arg:
9236 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9237 return COMPILE_NG;
9238 bad_arg:
9239 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9240}
9241
9242static int
9243compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9244{
9245 VALUE name;
9246
9247 if (!node) goto no_arg;
9248 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9249 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9250 node = RNODE_LIST(node)->nd_head;
9251 if (!node) goto no_arg;
9252 switch (nd_type(node)) {
9253 case NODE_SYM:
9254 name = rb_node_sym_string_val(node);
9255 break;
9256 default:
9257 goto bad_arg;
9258 }
9259 if (!SYMBOL_P(name)) goto non_symbol_arg;
9260 if (!popped) {
9261 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9262 }
9263 return COMPILE_OK;
9264 no_arg:
9265 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9266 return COMPILE_NG;
9267 too_many_arg:
9268 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9269 return COMPILE_NG;
9270 non_symbol_arg:
9271 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9272 rb_builtin_class_name(name));
9273 return COMPILE_NG;
9274 bad_arg:
9275 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9276}
9277
9278static NODE *
9279mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9280{
9281 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9282 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9283 return RNODE_IF(node)->nd_body;
9284 }
9285 else {
9286 rb_bug("mandatory_node: can't find mandatory node");
9287 }
9288}
9289
9290static int
9291compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9292{
9293 // arguments
9294 struct rb_args_info args = {
9295 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9296 };
9297 rb_node_args_t args_node;
9298 rb_node_init(RNODE(&args_node), NODE_ARGS);
9299 args_node.nd_ainfo = args;
9300
9301 // local table without non-mandatory parameters
9302 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9303 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9304
9305 VALUE idtmp = 0;
9306 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9307 tbl->size = table_size;
9308
9309 int i;
9310
9311 // lead parameters
9312 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9313 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9314 }
9315 // local variables
9316 for (; i<table_size; i++) {
9317 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9318 }
9319
9320 rb_node_scope_t scope_node;
9321 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9322 scope_node.nd_tbl = tbl;
9323 scope_node.nd_body = mandatory_node(iseq, node);
9324 scope_node.nd_parent = NULL;
9325 scope_node.nd_args = &args_node;
9326
9327 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9328
9329 const rb_iseq_t *mandatory_only_iseq =
9330 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9331 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9332 nd_line(line_node), NULL, 0,
9333 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9334 ISEQ_BODY(iseq)->variable.script_lines);
9335 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9336
9337 ALLOCV_END(idtmp);
9338 return COMPILE_OK;
9339}
9340
9341static int
9342compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9343 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9344{
9345 NODE *args_node = get_nd_args(node);
9346
9347 if (parent_block != NULL) {
9348 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9349 return COMPILE_NG;
9350 }
9351 else {
9352# define BUILTIN_INLINE_PREFIX "_bi"
9353 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9354 bool cconst = false;
9355 retry:;
9356 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9357
9358 if (bf == NULL) {
9359 if (strcmp("cstmt!", builtin_func) == 0 ||
9360 strcmp("cexpr!", builtin_func) == 0) {
9361 // ok
9362 }
9363 else if (strcmp("cconst!", builtin_func) == 0) {
9364 cconst = true;
9365 }
9366 else if (strcmp("cinit!", builtin_func) == 0) {
9367 // ignore
9368 return COMPILE_OK;
9369 }
9370 else if (strcmp("attr!", builtin_func) == 0) {
9371 return compile_builtin_attr(iseq, args_node);
9372 }
9373 else if (strcmp("arg!", builtin_func) == 0) {
9374 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9375 }
9376 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9377 if (popped) {
9378 rb_bug("mandatory_only? should be in if condition");
9379 }
9380 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9381 rb_bug("mandatory_only? should be put on top");
9382 }
9383
9384 ADD_INSN1(ret, line_node, putobject, Qfalse);
9385 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9386 }
9387 else if (1) {
9388 rb_bug("can't find builtin function:%s", builtin_func);
9389 }
9390 else {
9391 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9392 return COMPILE_NG;
9393 }
9394
9395 int inline_index = nd_line(node);
9396 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9397 builtin_func = inline_func;
9398 args_node = NULL;
9399 goto retry;
9400 }
9401
9402 if (cconst) {
9403 typedef VALUE(*builtin_func0)(void *, VALUE);
9404 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9405 ADD_INSN1(ret, line_node, putobject, const_val);
9406 return COMPILE_OK;
9407 }
9408
9409 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9410
9411 unsigned int flag = 0;
9412 struct rb_callinfo_kwarg *keywords = NULL;
9413 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9414
9415 if (FIX2INT(argc) != bf->argc) {
9416 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9417 builtin_func, bf->argc, FIX2INT(argc));
9418 return COMPILE_NG;
9419 }
9420
9421 unsigned int start_index;
9422 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9423 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9424 }
9425 else {
9426 ADD_SEQ(ret, args);
9427 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9428 }
9429
9430 if (popped) ADD_INSN(ret, line_node, pop);
9431 return COMPILE_OK;
9432 }
9433}
9434
9435static int
9436compile_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)
9437{
9438 /* call: obj.method(...)
9439 * fcall: func(...)
9440 * vcall: func
9441 */
9442 DECL_ANCHOR(recv);
9443 DECL_ANCHOR(args);
9444 ID mid = get_node_call_nd_mid(node);
9445 VALUE argc;
9446 unsigned int flag = 0;
9447 struct rb_callinfo_kwarg *keywords = NULL;
9448 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9449 LABEL *else_label = NULL;
9450 VALUE branches = Qfalse;
9451
9452 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9453
9454 INIT_ANCHOR(recv);
9455 INIT_ANCHOR(args);
9456
9457#if OPT_SUPPORT_JOKE
9458 if (nd_type_p(node, NODE_VCALL)) {
9459 ID id_bitblt;
9460 ID id_answer;
9461
9462 CONST_ID(id_bitblt, "bitblt");
9463 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9464
9465 if (mid == id_bitblt) {
9466 ADD_INSN(ret, line_node, bitblt);
9467 return COMPILE_OK;
9468 }
9469 else if (mid == id_answer) {
9470 ADD_INSN(ret, line_node, answer);
9471 return COMPILE_OK;
9472 }
9473 }
9474 /* only joke */
9475 {
9476 ID goto_id;
9477 ID label_id;
9478
9479 CONST_ID(goto_id, "__goto__");
9480 CONST_ID(label_id, "__label__");
9481
9482 if (nd_type_p(node, NODE_FCALL) &&
9483 (mid == goto_id || mid == label_id)) {
9484 LABEL *label;
9485 st_data_t data;
9486 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9487 VALUE label_name;
9488
9489 if (!labels_table) {
9490 labels_table = st_init_numtable();
9491 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9492 }
9493 {
9494 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9495 return COMPILE_NG;
9496 }
9497
9498 if (mid == goto_id) {
9499 ADD_INSNL(ret, line_node, jump, label);
9500 }
9501 else {
9502 ADD_LABEL(ret, label);
9503 }
9504 return COMPILE_OK;
9505 }
9506 }
9507#endif
9508
9509 const char *builtin_func;
9510 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9511 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9512 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9513 }
9514
9515 /* receiver */
9516 if (!assume_receiver) {
9517 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9518 int idx, level;
9519
9520 if (mid == idCall &&
9521 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9522 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9523 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9524 }
9525 else if (private_recv_p(node)) {
9526 ADD_INSN(recv, node, putself);
9527 flag |= VM_CALL_FCALL;
9528 }
9529 else {
9530 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9531 }
9532
9533 if (type == NODE_QCALL) {
9534 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9535 }
9536 }
9537 else if (type == NODE_FCALL || type == NODE_VCALL) {
9538 ADD_CALL_RECEIVER(recv, line_node);
9539 }
9540 }
9541
9542 /* args */
9543 if (type != NODE_VCALL) {
9544 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9545 CHECK(!NIL_P(argc));
9546 }
9547 else {
9548 argc = INT2FIX(0);
9549 }
9550
9551 ADD_SEQ(ret, recv);
9552
9553 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9554 mid == rb_intern("new") &&
9555 parent_block == NULL &&
9556 !(flag & VM_CALL_ARGS_BLOCKARG);
9557
9558 if (inline_new) {
9559 ADD_INSN(ret, node, putnil);
9560 ADD_INSN(ret, node, swap);
9561 }
9562
9563 ADD_SEQ(ret, args);
9564
9565 debugp_param("call args argc", argc);
9566 debugp_param("call method", ID2SYM(mid));
9567
9568 switch ((int)type) {
9569 case NODE_VCALL:
9570 flag |= VM_CALL_VCALL;
9571 /* VCALL is funcall, so fall through */
9572 case NODE_FCALL:
9573 flag |= VM_CALL_FCALL;
9574 }
9575
9576 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9577 ADD_INSN(ret, line_node, splatkw);
9578 }
9579
9580 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9581 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9582
9583 if (inline_new) {
9584 // Jump unless the receiver uses the "basic" implementation of "new"
9585 VALUE ci;
9586 if (flag & VM_CALL_FORWARDING) {
9587 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9588 }
9589 else {
9590 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9591 }
9592 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9593 LABEL_REF(not_basic_new);
9594
9595 // optimized path
9596 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9597 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9598
9599 ADD_LABEL(ret, not_basic_new);
9600 // Fall back to normal send
9601 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9602 ADD_INSN(ret, line_node, swap);
9603
9604 ADD_LABEL(ret, not_basic_new_finish);
9605 ADD_INSN(ret, line_node, pop);
9606 }
9607 else {
9608 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9609 }
9610
9611 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9612 if (popped) {
9613 ADD_INSN(ret, line_node, pop);
9614 }
9615 return COMPILE_OK;
9616}
9617
9618static int
9619compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9620{
9621 const int line = nd_line(node);
9622 VALUE argc;
9623 unsigned int flag = 0;
9624 int asgnflag = 0;
9625 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9626
9627 /*
9628 * a[x] (op)= y
9629 *
9630 * nil # nil
9631 * eval a # nil a
9632 * eval x # nil a x
9633 * dupn 2 # nil a x a x
9634 * send :[] # nil a x a[x]
9635 * eval y # nil a x a[x] y
9636 * send op # nil a x ret
9637 * setn 3 # ret a x ret
9638 * send []= # ret ?
9639 * pop # ret
9640 */
9641
9642 /*
9643 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9644 * NODE_OP_ASGN nd_recv
9645 * nd_args->nd_head
9646 * nd_args->nd_body
9647 * nd_mid
9648 */
9649
9650 if (!popped) {
9651 ADD_INSN(ret, node, putnil);
9652 }
9653 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9654 CHECK(asgnflag != -1);
9655 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9656 case NODE_ZLIST:
9657 argc = INT2FIX(0);
9658 break;
9659 default:
9660 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9661 CHECK(!NIL_P(argc));
9662 }
9663 int dup_argn = FIX2INT(argc) + 1;
9664 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9665 flag |= asgnflag;
9666 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9667
9668 if (id == idOROP || id == idANDOP) {
9669 /* a[x] ||= y or a[x] &&= y
9670
9671 unless/if a[x]
9672 a[x]= y
9673 else
9674 nil
9675 end
9676 */
9677 LABEL *label = NEW_LABEL(line);
9678 LABEL *lfin = NEW_LABEL(line);
9679
9680 ADD_INSN(ret, node, dup);
9681 if (id == idOROP) {
9682 ADD_INSNL(ret, node, branchif, label);
9683 }
9684 else { /* idANDOP */
9685 ADD_INSNL(ret, node, branchunless, label);
9686 }
9687 ADD_INSN(ret, node, pop);
9688
9689 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9690 if (!popped) {
9691 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9692 }
9693 if (flag & VM_CALL_ARGS_SPLAT) {
9694 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9695 ADD_INSN(ret, node, swap);
9696 ADD_INSN1(ret, node, splatarray, Qtrue);
9697 ADD_INSN(ret, node, swap);
9698 flag |= VM_CALL_ARGS_SPLAT_MUT;
9699 }
9700 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9701 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9702 }
9703 else {
9704 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9705 }
9706 ADD_INSN(ret, node, pop);
9707 ADD_INSNL(ret, node, jump, lfin);
9708 ADD_LABEL(ret, label);
9709 if (!popped) {
9710 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9711 }
9712 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9713 ADD_LABEL(ret, lfin);
9714 }
9715 else {
9716 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9717 ADD_SEND(ret, node, id, INT2FIX(1));
9718 if (!popped) {
9719 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9720 }
9721 if (flag & VM_CALL_ARGS_SPLAT) {
9722 if (flag & VM_CALL_KW_SPLAT) {
9723 ADD_INSN1(ret, node, topn, INT2FIX(2));
9724 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9725 ADD_INSN1(ret, node, splatarray, Qtrue);
9726 flag |= VM_CALL_ARGS_SPLAT_MUT;
9727 }
9728 ADD_INSN(ret, node, swap);
9729 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9730 ADD_INSN1(ret, node, setn, INT2FIX(2));
9731 ADD_INSN(ret, node, pop);
9732 }
9733 else {
9734 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9735 ADD_INSN(ret, node, swap);
9736 ADD_INSN1(ret, node, splatarray, Qtrue);
9737 ADD_INSN(ret, node, swap);
9738 flag |= VM_CALL_ARGS_SPLAT_MUT;
9739 }
9740 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9741 }
9742 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9743 }
9744 else {
9745 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9746 }
9747 ADD_INSN(ret, node, pop);
9748 }
9749 return COMPILE_OK;
9750}
9751
9752static int
9753compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9754{
9755 const int line = nd_line(node);
9756 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9757 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9758 int asgnflag;
9759 LABEL *lfin = NEW_LABEL(line);
9760 LABEL *lcfin = NEW_LABEL(line);
9761 LABEL *lskip = 0;
9762 /*
9763 class C; attr_accessor :c; end
9764 r = C.new
9765 r.a &&= v # asgn2
9766
9767 eval r # r
9768 dup # r r
9769 eval r.a # r o
9770
9771 # or
9772 dup # r o o
9773 if lcfin # r o
9774 pop # r
9775 eval v # r v
9776 swap # v r
9777 topn 1 # v r v
9778 send a= # v ?
9779 jump lfin # v ?
9780
9781 lcfin: # r o
9782 swap # o r
9783
9784 lfin: # o ?
9785 pop # o
9786
9787 # or (popped)
9788 if lcfin # r
9789 eval v # r v
9790 send a= # ?
9791 jump lfin # ?
9792
9793 lcfin: # r
9794
9795 lfin: # ?
9796 pop #
9797
9798 # and
9799 dup # r o o
9800 unless lcfin
9801 pop # r
9802 eval v # r v
9803 swap # v r
9804 topn 1 # v r v
9805 send a= # v ?
9806 jump lfin # v ?
9807
9808 # others
9809 eval v # r o v
9810 send ?? # r w
9811 send a= # w
9812
9813 */
9814
9815 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9816 CHECK(asgnflag != -1);
9817 if (RNODE_OP_ASGN2(node)->nd_aid) {
9818 lskip = NEW_LABEL(line);
9819 ADD_INSN(ret, node, dup);
9820 ADD_INSNL(ret, node, branchnil, lskip);
9821 }
9822 ADD_INSN(ret, node, dup);
9823 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9824
9825 if (atype == idOROP || atype == idANDOP) {
9826 if (!popped) {
9827 ADD_INSN(ret, node, dup);
9828 }
9829 if (atype == idOROP) {
9830 ADD_INSNL(ret, node, branchif, lcfin);
9831 }
9832 else { /* idANDOP */
9833 ADD_INSNL(ret, node, branchunless, lcfin);
9834 }
9835 if (!popped) {
9836 ADD_INSN(ret, node, pop);
9837 }
9838 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9839 if (!popped) {
9840 ADD_INSN(ret, node, swap);
9841 ADD_INSN1(ret, node, topn, INT2FIX(1));
9842 }
9843 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9844 ADD_INSNL(ret, node, jump, lfin);
9845
9846 ADD_LABEL(ret, lcfin);
9847 if (!popped) {
9848 ADD_INSN(ret, node, swap);
9849 }
9850
9851 ADD_LABEL(ret, lfin);
9852 }
9853 else {
9854 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9855 ADD_SEND(ret, node, atype, INT2FIX(1));
9856 if (!popped) {
9857 ADD_INSN(ret, node, swap);
9858 ADD_INSN1(ret, node, topn, INT2FIX(1));
9859 }
9860 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9861 }
9862 if (lskip && popped) {
9863 ADD_LABEL(ret, lskip);
9864 }
9865 ADD_INSN(ret, node, pop);
9866 if (lskip && !popped) {
9867 ADD_LABEL(ret, lskip);
9868 }
9869 return COMPILE_OK;
9870}
9871
9872static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9873
9874static int
9875compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9876{
9877 const int line = nd_line(node);
9878 LABEL *lfin = 0;
9879 LABEL *lassign = 0;
9880 ID mid;
9881
9882 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9883 case NODE_COLON3:
9884 ADD_INSN1(ret, node, putobject, rb_cObject);
9885 break;
9886 case NODE_COLON2:
9887 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9888 break;
9889 default:
9890 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9891 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9892 return COMPILE_NG;
9893 }
9894 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9895 /* cref */
9896 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9897 lassign = NEW_LABEL(line);
9898 ADD_INSN(ret, node, dup); /* cref cref */
9899 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9900 ID2SYM(mid), Qtrue); /* cref bool */
9901 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9902 }
9903 ADD_INSN(ret, node, dup); /* cref cref */
9904 ADD_INSN1(ret, node, putobject, Qtrue);
9905 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9906
9907 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9908 lfin = NEW_LABEL(line);
9909 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9910 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9911 ADD_INSNL(ret, node, branchif, lfin);
9912 else /* idANDOP */
9913 ADD_INSNL(ret, node, branchunless, lfin);
9914 /* cref [obj] */
9915 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9916 if (lassign) ADD_LABEL(ret, lassign);
9917 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9918 /* cref value */
9919 if (popped)
9920 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9921 else {
9922 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9923 ADD_INSN(ret, node, swap); /* cref value value cref */
9924 }
9925 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9926 ADD_LABEL(ret, lfin); /* cref [value] */
9927 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9928 ADD_INSN(ret, node, pop); /* [value] */
9929 }
9930 else {
9931 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9932 /* cref obj value */
9933 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9934 /* cref value */
9935 ADD_INSN(ret, node, swap); /* value cref */
9936 if (!popped) {
9937 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9938 ADD_INSN(ret, node, swap); /* value value cref */
9939 }
9940 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9941 }
9942 return COMPILE_OK;
9943}
9944
9945static int
9946compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9947{
9948 const int line = nd_line(node);
9949 LABEL *lfin = NEW_LABEL(line);
9950 LABEL *lassign;
9951
9952 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9953 LABEL *lfinish[2];
9954 lfinish[0] = lfin;
9955 lfinish[1] = 0;
9956 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9957 lassign = lfinish[1];
9958 if (!lassign) {
9959 lassign = NEW_LABEL(line);
9960 }
9961 ADD_INSNL(ret, node, branchunless, lassign);
9962 }
9963 else {
9964 lassign = NEW_LABEL(line);
9965 }
9966
9967 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9968
9969 if (!popped) {
9970 ADD_INSN(ret, node, dup);
9971 }
9972
9973 if (type == NODE_OP_ASGN_AND) {
9974 ADD_INSNL(ret, node, branchunless, lfin);
9975 }
9976 else {
9977 ADD_INSNL(ret, node, branchif, lfin);
9978 }
9979
9980 if (!popped) {
9981 ADD_INSN(ret, node, pop);
9982 }
9983
9984 ADD_LABEL(ret, lassign);
9985 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9986 ADD_LABEL(ret, lfin);
9987 return COMPILE_OK;
9988}
9989
9990static int
9991compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9992{
9993 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9994 DECL_ANCHOR(args);
9995 int argc;
9996 unsigned int flag = 0;
9997 struct rb_callinfo_kwarg *keywords = NULL;
9998 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9999 int use_block = 1;
10000
10001 INIT_ANCHOR(args);
10002 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10003
10004 if (type == NODE_SUPER) {
10005 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10006 CHECK(!NIL_P(vargc));
10007 argc = FIX2INT(vargc);
10008 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10009 ADD_INSN(args, node, splatkw);
10010 }
10011
10012 if (flag & VM_CALL_ARGS_BLOCKARG) {
10013 use_block = 0;
10014 }
10015 }
10016 else {
10017 /* NODE_ZSUPER */
10018 int i;
10019 const rb_iseq_t *liseq = body->local_iseq;
10020 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10021 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10022 int lvar_level = get_lvar_level(iseq);
10023
10024 argc = local_body->param.lead_num;
10025
10026 /* normal arguments */
10027 for (i = 0; i < local_body->param.lead_num; i++) {
10028 int idx = local_body->local_table_size - i;
10029 ADD_GETLOCAL(args, node, idx, lvar_level);
10030 }
10031
10032 /* forward ... */
10033 if (local_body->param.flags.forwardable) {
10034 flag |= VM_CALL_FORWARDING;
10035 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10036 ADD_GETLOCAL(args, node, idx, lvar_level);
10037 }
10038
10039 if (local_body->param.flags.has_opt) {
10040 /* optional arguments */
10041 int j;
10042 for (j = 0; j < local_body->param.opt_num; j++) {
10043 int idx = local_body->local_table_size - (i + j);
10044 ADD_GETLOCAL(args, node, idx, lvar_level);
10045 }
10046 i += j;
10047 argc = i;
10048 }
10049 if (local_body->param.flags.has_rest) {
10050 /* rest argument */
10051 int idx = local_body->local_table_size - local_body->param.rest_start;
10052 ADD_GETLOCAL(args, node, idx, lvar_level);
10053 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10054
10055 argc = local_body->param.rest_start + 1;
10056 flag |= VM_CALL_ARGS_SPLAT;
10057 }
10058 if (local_body->param.flags.has_post) {
10059 /* post arguments */
10060 int post_len = local_body->param.post_num;
10061 int post_start = local_body->param.post_start;
10062
10063 if (local_body->param.flags.has_rest) {
10064 int j;
10065 for (j=0; j<post_len; j++) {
10066 int idx = local_body->local_table_size - (post_start + j);
10067 ADD_GETLOCAL(args, node, idx, lvar_level);
10068 }
10069 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10070 flag |= VM_CALL_ARGS_SPLAT_MUT;
10071 /* argc is settled at above */
10072 }
10073 else {
10074 int j;
10075 for (j=0; j<post_len; j++) {
10076 int idx = local_body->local_table_size - (post_start + j);
10077 ADD_GETLOCAL(args, node, idx, lvar_level);
10078 }
10079 argc = post_len + post_start;
10080 }
10081 }
10082
10083 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10084 int local_size = local_body->local_table_size;
10085 argc++;
10086
10087 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10088
10089 if (local_body->param.flags.has_kwrest) {
10090 int idx = local_body->local_table_size - local_kwd->rest_start;
10091 ADD_GETLOCAL(args, node, idx, lvar_level);
10092 RUBY_ASSERT(local_kwd->num > 0);
10093 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10094 }
10095 else {
10096 ADD_INSN1(args, node, newhash, INT2FIX(0));
10097 }
10098 for (i = 0; i < local_kwd->num; ++i) {
10099 ID id = local_kwd->table[i];
10100 int idx = local_size - get_local_var_idx(liseq, id);
10101 ADD_INSN1(args, node, putobject, ID2SYM(id));
10102 ADD_GETLOCAL(args, node, idx, lvar_level);
10103 }
10104 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10105 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10106 }
10107 else if (local_body->param.flags.has_kwrest) {
10108 int idx = local_body->local_table_size - local_kwd->rest_start;
10109 ADD_GETLOCAL(args, node, idx, lvar_level);
10110 argc++;
10111 flag |= VM_CALL_KW_SPLAT;
10112 }
10113 }
10114
10115 if (use_block && parent_block == NULL) {
10116 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10117 }
10118
10119 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10120 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10121 ADD_INSN(ret, node, putself);
10122 ADD_SEQ(ret, args);
10123
10124 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10125
10126 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10127 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10128 }
10129 else {
10130 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10131 }
10132
10133 if (popped) {
10134 ADD_INSN(ret, node, pop);
10135 }
10136 return COMPILE_OK;
10137}
10138
10139static int
10140compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10141{
10142 DECL_ANCHOR(args);
10143 VALUE argc;
10144 unsigned int flag = 0;
10145 struct rb_callinfo_kwarg *keywords = NULL;
10146
10147 INIT_ANCHOR(args);
10148
10149 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10150 case ISEQ_TYPE_TOP:
10151 case ISEQ_TYPE_MAIN:
10152 case ISEQ_TYPE_CLASS:
10153 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10154 return COMPILE_NG;
10155 default: /* valid */;
10156 }
10157
10158 if (RNODE_YIELD(node)->nd_head) {
10159 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10160 CHECK(!NIL_P(argc));
10161 }
10162 else {
10163 argc = INT2FIX(0);
10164 }
10165
10166 ADD_SEQ(ret, args);
10167 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10168 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10169
10170 if (popped) {
10171 ADD_INSN(ret, node, pop);
10172 }
10173
10174 int level = 0;
10175 const rb_iseq_t *tmp_iseq = iseq;
10176 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10177 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10178 }
10179 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10180
10181 return COMPILE_OK;
10182}
10183
10184static int
10185compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10186{
10187 DECL_ANCHOR(recv);
10188 DECL_ANCHOR(val);
10189
10190 INIT_ANCHOR(recv);
10191 INIT_ANCHOR(val);
10192 switch ((int)type) {
10193 case NODE_MATCH:
10194 {
10195 VALUE re = rb_node_regx_string_val(node);
10196 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10197 ADD_INSN1(recv, node, putobject, re);
10198 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10199 INT2FIX(0));
10200 }
10201 break;
10202 case NODE_MATCH2:
10203 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10204 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10205 break;
10206 case NODE_MATCH3:
10207 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10208 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10209 break;
10210 }
10211
10212 ADD_SEQ(ret, recv);
10213 ADD_SEQ(ret, val);
10214 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10215
10216 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10217 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10218 }
10219
10220 if (popped) {
10221 ADD_INSN(ret, node, pop);
10222 }
10223 return COMPILE_OK;
10224}
10225
10226static int
10227compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10228{
10229 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10230 /* constant */
10231 VALUE segments;
10232 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10233 (segments = collect_const_segments(iseq, node))) {
10234 ISEQ_BODY(iseq)->ic_size++;
10235 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10236 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10237 }
10238 else {
10239 /* constant */
10240 DECL_ANCHOR(pref);
10241 DECL_ANCHOR(body);
10242
10243 INIT_ANCHOR(pref);
10244 INIT_ANCHOR(body);
10245 CHECK(compile_const_prefix(iseq, node, pref, body));
10246 if (LIST_INSN_SIZE_ZERO(pref)) {
10247 ADD_INSN(ret, node, putnil);
10248 ADD_SEQ(ret, body);
10249 }
10250 else {
10251 ADD_SEQ(ret, pref);
10252 ADD_SEQ(ret, body);
10253 }
10254 }
10255 }
10256 else {
10257 /* function call */
10258 ADD_CALL_RECEIVER(ret, node);
10259 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10260 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10261 }
10262 if (popped) {
10263 ADD_INSN(ret, node, pop);
10264 }
10265 return COMPILE_OK;
10266}
10267
10268static int
10269compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10270{
10271 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10272
10273 /* add cache insn */
10274 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10275 ISEQ_BODY(iseq)->ic_size++;
10276 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10277 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10278 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10279 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10280 }
10281 else {
10282 ADD_INSN1(ret, node, putobject, rb_cObject);
10283 ADD_INSN1(ret, node, putobject, Qtrue);
10284 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10285 }
10286
10287 if (popped) {
10288 ADD_INSN(ret, node, pop);
10289 }
10290 return COMPILE_OK;
10291}
10292
10293static int
10294compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10295{
10296 VALUE flag = INT2FIX(excl);
10297 const NODE *b = RNODE_DOT2(node)->nd_beg;
10298 const NODE *e = RNODE_DOT2(node)->nd_end;
10299
10300 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10301 if (!popped) {
10302 VALUE bv = optimized_range_item(b);
10303 VALUE ev = optimized_range_item(e);
10304 VALUE val = rb_range_new(bv, ev, excl);
10306 ADD_INSN1(ret, node, putobject, val);
10307 RB_OBJ_WRITTEN(iseq, Qundef, val);
10308 }
10309 }
10310 else {
10311 CHECK(COMPILE_(ret, "min", b, popped));
10312 CHECK(COMPILE_(ret, "max", e, popped));
10313 if (!popped) {
10314 ADD_INSN1(ret, node, newrange, flag);
10315 }
10316 }
10317 return COMPILE_OK;
10318}
10319
10320static int
10321compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10322{
10323 if (!popped) {
10324 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10325 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10326 }
10327 else {
10328 const rb_iseq_t *ip = iseq;
10329 int level = 0;
10330 while (ip) {
10331 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10332 break;
10333 }
10334 ip = ISEQ_BODY(ip)->parent_iseq;
10335 level++;
10336 }
10337 if (ip) {
10338 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10339 }
10340 else {
10341 ADD_INSN(ret, node, putnil);
10342 }
10343 }
10344 }
10345 return COMPILE_OK;
10346}
10347
10348static int
10349compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10350{
10351 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10352 LABEL *end_label = NEW_LABEL(nd_line(node));
10353 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10354
10355 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10356 /* required argument. do nothing */
10357 COMPILE_ERROR(ERROR_ARGS "unreachable");
10358 return COMPILE_NG;
10359 }
10360 else if (nd_type_p(default_value, NODE_SYM) ||
10361 nd_type_p(default_value, NODE_REGX) ||
10362 nd_type_p(default_value, NODE_LINE) ||
10363 nd_type_p(default_value, NODE_INTEGER) ||
10364 nd_type_p(default_value, NODE_FLOAT) ||
10365 nd_type_p(default_value, NODE_RATIONAL) ||
10366 nd_type_p(default_value, NODE_IMAGINARY) ||
10367 nd_type_p(default_value, NODE_NIL) ||
10368 nd_type_p(default_value, NODE_TRUE) ||
10369 nd_type_p(default_value, NODE_FALSE)) {
10370 COMPILE_ERROR(ERROR_ARGS "unreachable");
10371 return COMPILE_NG;
10372 }
10373 else {
10374 /* if keywordcheck(_kw_bits, nth_keyword)
10375 * kw = default_value
10376 * end
10377 */
10378 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10379 int keyword_idx = body->param.keyword->num;
10380
10381 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10382 ADD_INSNL(ret, node, branchif, end_label);
10383 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10384 ADD_LABEL(ret, end_label);
10385 }
10386 return COMPILE_OK;
10387}
10388
10389static int
10390compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10391{
10392 DECL_ANCHOR(recv);
10393 DECL_ANCHOR(args);
10394 unsigned int flag = 0;
10395 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10396 VALUE argc;
10397 LABEL *else_label = NULL;
10398 VALUE branches = Qfalse;
10399
10400 INIT_ANCHOR(recv);
10401 INIT_ANCHOR(args);
10402 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10403 CHECK(!NIL_P(argc));
10404
10405 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10406 CHECK(asgnflag != -1);
10407 flag |= (unsigned int)asgnflag;
10408
10409 debugp_param("argc", argc);
10410 debugp_param("nd_mid", ID2SYM(mid));
10411
10412 if (!rb_is_attrset_id(mid)) {
10413 /* safe nav attr */
10414 mid = rb_id_attrset(mid);
10415 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10416 }
10417 if (!popped) {
10418 ADD_INSN(ret, node, putnil);
10419 ADD_SEQ(ret, recv);
10420 ADD_SEQ(ret, args);
10421
10422 if (flag & VM_CALL_ARGS_SPLAT) {
10423 ADD_INSN(ret, node, dup);
10424 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10425 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10426 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10427 ADD_INSN (ret, node, pop);
10428 }
10429 else {
10430 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10431 }
10432 }
10433 else {
10434 ADD_SEQ(ret, recv);
10435 ADD_SEQ(ret, args);
10436 }
10437 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10438 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10439 ADD_INSN(ret, node, pop);
10440 return COMPILE_OK;
10441}
10442
10443static int
10444compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10445{
10446 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10447 ADD_SEQ(ret, sub);
10448
10449 if (copy) {
10450 /*
10451 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10452 * NEW_LIST(value, loc), loc);
10453 */
10454 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10455 }
10456 else {
10457 /*
10458 * NEW_CALL(fcore, rb_intern("make_shareable"),
10459 * NEW_LIST(value, loc), loc);
10460 */
10461 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10462 }
10463
10464 return COMPILE_OK;
10465}
10466
10467static VALUE
10468node_const_decl_val(const NODE *node)
10469{
10470 VALUE path;
10471 switch (nd_type(node)) {
10472 case NODE_CDECL:
10473 if (RNODE_CDECL(node)->nd_vid) {
10474 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10475 goto end;
10476 }
10477 else {
10478 node = RNODE_CDECL(node)->nd_else;
10479 }
10480 break;
10481 case NODE_COLON2:
10482 break;
10483 case NODE_COLON3:
10484 // ::Const
10485 path = rb_str_new_cstr("::");
10486 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10487 goto end;
10488 default:
10489 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10491 }
10492
10493 path = rb_ary_new();
10494 if (node) {
10495 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10496 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10497 }
10498 if (node && nd_type_p(node, NODE_CONST)) {
10499 // Const::Name
10500 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10501 }
10502 else if (node && nd_type_p(node, NODE_COLON3)) {
10503 // ::Const::Name
10504 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10505 rb_ary_push(path, rb_str_new(0, 0));
10506 }
10507 else {
10508 // expression::Name
10509 rb_ary_push(path, rb_str_new_cstr("..."));
10510 }
10511 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10512 }
10513 end:
10514 path = rb_fstring(path);
10515 return path;
10516}
10517
10518static VALUE
10519const_decl_path(NODE *dest)
10520{
10521 VALUE path = Qnil;
10522 if (!nd_type_p(dest, NODE_CALL)) {
10523 path = node_const_decl_val(dest);
10524 }
10525 return path;
10526}
10527
10528static int
10529compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10530{
10531 /*
10532 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10533 */
10534 VALUE path = const_decl_path(dest);
10535 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10536 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10537 ADD_INSN1(ret, value, putobject, path);
10538 RB_OBJ_WRITTEN(iseq, Qundef, path);
10539 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10540
10541 return COMPILE_OK;
10542}
10543
10544#ifndef SHAREABLE_BARE_EXPRESSION
10545#define SHAREABLE_BARE_EXPRESSION 1
10546#endif
10547
10548static int
10549compile_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)
10550{
10551# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10552 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10553 VALUE lit = Qnil;
10554 DECL_ANCHOR(anchor);
10555
10556 enum node_type type = node ? nd_type(node) : NODE_NIL;
10557 switch (type) {
10558 case NODE_TRUE:
10559 *value_p = Qtrue;
10560 goto compile;
10561 case NODE_FALSE:
10562 *value_p = Qfalse;
10563 goto compile;
10564 case NODE_NIL:
10565 *value_p = Qnil;
10566 goto compile;
10567 case NODE_SYM:
10568 *value_p = rb_node_sym_string_val(node);
10569 goto compile;
10570 case NODE_REGX:
10571 *value_p = rb_node_regx_string_val(node);
10572 goto compile;
10573 case NODE_LINE:
10574 *value_p = rb_node_line_lineno_val(node);
10575 goto compile;
10576 case NODE_INTEGER:
10577 *value_p = rb_node_integer_literal_val(node);
10578 goto compile;
10579 case NODE_FLOAT:
10580 *value_p = rb_node_float_literal_val(node);
10581 goto compile;
10582 case NODE_RATIONAL:
10583 *value_p = rb_node_rational_literal_val(node);
10584 goto compile;
10585 case NODE_IMAGINARY:
10586 *value_p = rb_node_imaginary_literal_val(node);
10587 goto compile;
10588 case NODE_ENCODING:
10589 *value_p = rb_node_encoding_val(node);
10590
10591 compile:
10592 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10593 *shareable_literal_p = 1;
10594 return COMPILE_OK;
10595
10596 case NODE_DSTR:
10597 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10598 if (shareable == rb_parser_shareable_literal) {
10599 /*
10600 * NEW_CALL(node, idUMinus, 0, loc);
10601 *
10602 * -"#{var}"
10603 */
10604 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10605 }
10606 *value_p = Qundef;
10607 *shareable_literal_p = 1;
10608 return COMPILE_OK;
10609
10610 case NODE_STR:{
10611 VALUE lit = rb_node_str_string_val(node);
10612 ADD_INSN1(ret, node, putobject, lit);
10613 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10614 *value_p = lit;
10615 *shareable_literal_p = 1;
10616
10617 return COMPILE_OK;
10618 }
10619
10620 case NODE_FILE:{
10621 VALUE lit = rb_node_file_path_val(node);
10622 ADD_INSN1(ret, node, putobject, lit);
10623 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10624 *value_p = lit;
10625 *shareable_literal_p = 1;
10626
10627 return COMPILE_OK;
10628 }
10629
10630 case NODE_ZLIST:{
10631 VALUE lit = rb_ary_new();
10632 OBJ_FREEZE(lit);
10633 ADD_INSN1(ret, node, putobject, lit);
10634 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10635 *value_p = lit;
10636 *shareable_literal_p = 1;
10637
10638 return COMPILE_OK;
10639 }
10640
10641 case NODE_LIST:{
10642 INIT_ANCHOR(anchor);
10643 lit = rb_ary_new();
10644 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10645 VALUE val;
10646 int shareable_literal_p2;
10647 NODE *elt = RNODE_LIST(n)->nd_head;
10648 if (elt) {
10649 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10650 if (shareable_literal_p2) {
10651 /* noop */
10652 }
10653 else if (RTEST(lit)) {
10654 rb_ary_clear(lit);
10655 lit = Qfalse;
10656 }
10657 }
10658 if (RTEST(lit)) {
10659 if (!UNDEF_P(val)) {
10660 rb_ary_push(lit, val);
10661 }
10662 else {
10663 rb_ary_clear(lit);
10664 lit = Qnil; /* make shareable at runtime */
10665 }
10666 }
10667 }
10668 break;
10669 }
10670 case NODE_HASH:{
10671 if (!RNODE_HASH(node)->nd_brace) {
10672 *value_p = Qundef;
10673 *shareable_literal_p = 0;
10674 return COMPILE_OK;
10675 }
10676 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10677 if (!RNODE_LIST(n)->nd_head) {
10678 // If the hash node have a keyword splat, fall back to the default case.
10679 goto compile_shareable;
10680 }
10681 }
10682
10683 INIT_ANCHOR(anchor);
10684 lit = rb_hash_new();
10685 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10686 VALUE key_val = 0;
10687 VALUE value_val = 0;
10688 int shareable_literal_p2;
10689 NODE *key = RNODE_LIST(n)->nd_head;
10690 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10691 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10692 if (shareable_literal_p2) {
10693 /* noop */
10694 }
10695 else if (RTEST(lit)) {
10696 rb_hash_clear(lit);
10697 lit = Qfalse;
10698 }
10699 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10700 if (shareable_literal_p2) {
10701 /* noop */
10702 }
10703 else if (RTEST(lit)) {
10704 rb_hash_clear(lit);
10705 lit = Qfalse;
10706 }
10707 if (RTEST(lit)) {
10708 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10709 rb_hash_aset(lit, key_val, value_val);
10710 }
10711 else {
10712 rb_hash_clear(lit);
10713 lit = Qnil; /* make shareable at runtime */
10714 }
10715 }
10716 }
10717 break;
10718 }
10719
10720 default:
10721
10722 compile_shareable:
10723 if (shareable == rb_parser_shareable_literal &&
10724 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10725 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10726 *value_p = Qundef;
10727 *shareable_literal_p = 1;
10728 return COMPILE_OK;
10729 }
10730 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10731 *value_p = Qundef;
10732 *shareable_literal_p = 0;
10733 return COMPILE_OK;
10734 }
10735
10736 /* Array or Hash that does not have keyword splat */
10737 if (!lit) {
10738 if (nd_type(node) == NODE_LIST) {
10739 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10740 }
10741 else if (nd_type(node) == NODE_HASH) {
10742 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10743 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10744 }
10745 *value_p = Qundef;
10746 *shareable_literal_p = 0;
10747 ADD_SEQ(ret, anchor);
10748 return COMPILE_OK;
10749 }
10750 if (NIL_P(lit)) {
10751 // if shareable_literal, all elements should have been ensured
10752 // as shareable
10753 if (nd_type(node) == NODE_LIST) {
10754 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10755 }
10756 else if (nd_type(node) == NODE_HASH) {
10757 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10758 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10759 }
10760 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10761 *value_p = Qundef;
10762 *shareable_literal_p = 1;
10763 }
10764 else {
10766 ADD_INSN1(ret, node, putobject, val);
10767 RB_OBJ_WRITTEN(iseq, Qundef, val);
10768 *value_p = val;
10769 *shareable_literal_p = 1;
10770 }
10771
10772 return COMPILE_OK;
10773}
10774
10775static int
10776compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10777{
10778 int literal_p = 0;
10779 VALUE val;
10780 DECL_ANCHOR(anchor);
10781 INIT_ANCHOR(anchor);
10782
10783 switch (shareable) {
10784 case rb_parser_shareable_none:
10785 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10786 return COMPILE_OK;
10787
10788 case rb_parser_shareable_literal:
10789 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10790 ADD_SEQ(ret, anchor);
10791 return COMPILE_OK;
10792
10793 case rb_parser_shareable_copy:
10794 case rb_parser_shareable_everything:
10795 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10796 if (!literal_p) {
10797 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10798 }
10799 else {
10800 ADD_SEQ(ret, anchor);
10801 }
10802 return COMPILE_OK;
10803 default:
10804 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10805 }
10806}
10807
10808static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10816static int
10817iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10818{
10819 if (node == 0) {
10820 if (!popped) {
10821 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10822 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10823 debugs("node: NODE_NIL(implicit)\n");
10824 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10825 }
10826 return COMPILE_OK;
10827 }
10828 return iseq_compile_each0(iseq, ret, node, popped);
10829}
10830
10831static int
10832iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10833{
10834 const int line = (int)nd_line(node);
10835 const enum node_type type = nd_type(node);
10836 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10837
10838 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10839 /* ignore */
10840 }
10841 else {
10842 if (nd_fl_newline(node)) {
10843 int event = RUBY_EVENT_LINE;
10844 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10845 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10846 event |= RUBY_EVENT_COVERAGE_LINE;
10847 }
10848 ADD_TRACE(ret, event);
10849 }
10850 }
10851
10852 debug_node_start(node);
10853#undef BEFORE_RETURN
10854#define BEFORE_RETURN debug_node_end()
10855
10856 switch (type) {
10857 case NODE_BLOCK:
10858 CHECK(compile_block(iseq, ret, node, popped));
10859 break;
10860 case NODE_IF:
10861 case NODE_UNLESS:
10862 CHECK(compile_if(iseq, ret, node, popped, type));
10863 break;
10864 case NODE_CASE:
10865 CHECK(compile_case(iseq, ret, node, popped));
10866 break;
10867 case NODE_CASE2:
10868 CHECK(compile_case2(iseq, ret, node, popped));
10869 break;
10870 case NODE_CASE3:
10871 CHECK(compile_case3(iseq, ret, node, popped));
10872 break;
10873 case NODE_WHILE:
10874 case NODE_UNTIL:
10875 CHECK(compile_loop(iseq, ret, node, popped, type));
10876 break;
10877 case NODE_FOR:
10878 case NODE_ITER:
10879 CHECK(compile_iter(iseq, ret, node, popped));
10880 break;
10881 case NODE_FOR_MASGN:
10882 CHECK(compile_for_masgn(iseq, ret, node, popped));
10883 break;
10884 case NODE_BREAK:
10885 CHECK(compile_break(iseq, ret, node, popped));
10886 break;
10887 case NODE_NEXT:
10888 CHECK(compile_next(iseq, ret, node, popped));
10889 break;
10890 case NODE_REDO:
10891 CHECK(compile_redo(iseq, ret, node, popped));
10892 break;
10893 case NODE_RETRY:
10894 CHECK(compile_retry(iseq, ret, node, popped));
10895 break;
10896 case NODE_BEGIN:{
10897 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10898 break;
10899 }
10900 case NODE_RESCUE:
10901 CHECK(compile_rescue(iseq, ret, node, popped));
10902 break;
10903 case NODE_RESBODY:
10904 CHECK(compile_resbody(iseq, ret, node, popped));
10905 break;
10906 case NODE_ENSURE:
10907 CHECK(compile_ensure(iseq, ret, node, popped));
10908 break;
10909
10910 case NODE_AND:
10911 case NODE_OR:{
10912 LABEL *end_label = NEW_LABEL(line);
10913 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10914 if (!popped) {
10915 ADD_INSN(ret, node, dup);
10916 }
10917 if (type == NODE_AND) {
10918 ADD_INSNL(ret, node, branchunless, end_label);
10919 }
10920 else {
10921 ADD_INSNL(ret, node, branchif, end_label);
10922 }
10923 if (!popped) {
10924 ADD_INSN(ret, node, pop);
10925 }
10926 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10927 ADD_LABEL(ret, end_label);
10928 break;
10929 }
10930
10931 case NODE_MASGN:{
10932 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10933 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10934 compile_massign(iseq, ret, node, popped);
10935 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10936 break;
10937 }
10938
10939 case NODE_LASGN:{
10940 ID id = RNODE_LASGN(node)->nd_vid;
10941 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10942
10943 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10944 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10945
10946 if (!popped) {
10947 ADD_INSN(ret, node, dup);
10948 }
10949 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10950 break;
10951 }
10952 case NODE_DASGN: {
10953 int idx, lv, ls;
10954 ID id = RNODE_DASGN(node)->nd_vid;
10955 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10956 debugi("dassn id", rb_id2str(id) ? id : '*');
10957
10958 if (!popped) {
10959 ADD_INSN(ret, node, dup);
10960 }
10961
10962 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10963
10964 if (idx < 0) {
10965 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10966 rb_id2str(id));
10967 goto ng;
10968 }
10969 ADD_SETLOCAL(ret, node, ls - idx, lv);
10970 break;
10971 }
10972 case NODE_GASGN:{
10973 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10974
10975 if (!popped) {
10976 ADD_INSN(ret, node, dup);
10977 }
10978 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10979 break;
10980 }
10981 case NODE_IASGN:{
10982 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10983 if (!popped) {
10984 ADD_INSN(ret, node, dup);
10985 }
10986 ADD_INSN2(ret, node, setinstancevariable,
10987 ID2SYM(RNODE_IASGN(node)->nd_vid),
10988 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10989 break;
10990 }
10991 case NODE_CDECL:{
10992 if (RNODE_CDECL(node)->nd_vid) {
10993 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10994
10995 if (!popped) {
10996 ADD_INSN(ret, node, dup);
10997 }
10998
10999 ADD_INSN1(ret, node, putspecialobject,
11000 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11001 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11002 }
11003 else {
11004 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11005 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11006 ADD_INSN(ret, node, swap);
11007
11008 if (!popped) {
11009 ADD_INSN1(ret, node, topn, INT2FIX(1));
11010 ADD_INSN(ret, node, swap);
11011 }
11012
11013 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11014 }
11015 break;
11016 }
11017 case NODE_CVASGN:{
11018 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11019 if (!popped) {
11020 ADD_INSN(ret, node, dup);
11021 }
11022 ADD_INSN2(ret, node, setclassvariable,
11023 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11024 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11025 break;
11026 }
11027 case NODE_OP_ASGN1:
11028 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11029 break;
11030 case NODE_OP_ASGN2:
11031 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11032 break;
11033 case NODE_OP_CDECL:
11034 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11035 break;
11036 case NODE_OP_ASGN_AND:
11037 case NODE_OP_ASGN_OR:
11038 CHECK(compile_op_log(iseq, ret, node, popped, type));
11039 break;
11040 case NODE_CALL: /* obj.foo */
11041 case NODE_OPCALL: /* foo[] */
11042 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11043 break;
11044 }
11045 case NODE_QCALL: /* obj&.foo */
11046 case NODE_FCALL: /* foo() */
11047 case NODE_VCALL: /* foo (variable or call) */
11048 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11049 goto ng;
11050 }
11051 break;
11052 case NODE_SUPER:
11053 case NODE_ZSUPER:
11054 CHECK(compile_super(iseq, ret, node, popped, type));
11055 break;
11056 case NODE_LIST:{
11057 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11058 break;
11059 }
11060 case NODE_ZLIST:{
11061 if (!popped) {
11062 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11063 }
11064 break;
11065 }
11066 case NODE_HASH:
11067 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11068 break;
11069 case NODE_RETURN:
11070 CHECK(compile_return(iseq, ret, node, popped));
11071 break;
11072 case NODE_YIELD:
11073 CHECK(compile_yield(iseq, ret, node, popped));
11074 break;
11075 case NODE_LVAR:{
11076 if (!popped) {
11077 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11078 }
11079 break;
11080 }
11081 case NODE_DVAR:{
11082 int lv, idx, ls;
11083 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11084 if (!popped) {
11085 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11086 if (idx < 0) {
11087 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11088 rb_id2str(RNODE_DVAR(node)->nd_vid));
11089 goto ng;
11090 }
11091 ADD_GETLOCAL(ret, node, ls - idx, lv);
11092 }
11093 break;
11094 }
11095 case NODE_GVAR:{
11096 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11097 if (popped) {
11098 ADD_INSN(ret, node, pop);
11099 }
11100 break;
11101 }
11102 case NODE_IVAR:{
11103 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11104 if (!popped) {
11105 ADD_INSN2(ret, node, getinstancevariable,
11106 ID2SYM(RNODE_IVAR(node)->nd_vid),
11107 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11108 }
11109 break;
11110 }
11111 case NODE_CONST:{
11112 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11113
11114 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11115 body->ic_size++;
11116 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11117 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11118 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11119 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11120 }
11121 else {
11122 ADD_INSN(ret, node, putnil);
11123 ADD_INSN1(ret, node, putobject, Qtrue);
11124 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11125 }
11126
11127 if (popped) {
11128 ADD_INSN(ret, node, pop);
11129 }
11130 break;
11131 }
11132 case NODE_CVAR:{
11133 if (!popped) {
11134 ADD_INSN2(ret, node, getclassvariable,
11135 ID2SYM(RNODE_CVAR(node)->nd_vid),
11136 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11137 }
11138 break;
11139 }
11140 case NODE_NTH_REF:{
11141 if (!popped) {
11142 if (!RNODE_NTH_REF(node)->nd_nth) {
11143 ADD_INSN(ret, node, putnil);
11144 break;
11145 }
11146 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11147 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11148 }
11149 break;
11150 }
11151 case NODE_BACK_REF:{
11152 if (!popped) {
11153 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11154 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11155 }
11156 break;
11157 }
11158 case NODE_MATCH:
11159 case NODE_MATCH2:
11160 case NODE_MATCH3:
11161 CHECK(compile_match(iseq, ret, node, popped, type));
11162 break;
11163 case NODE_SYM:{
11164 if (!popped) {
11165 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11166 }
11167 break;
11168 }
11169 case NODE_LINE:{
11170 if (!popped) {
11171 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11172 }
11173 break;
11174 }
11175 case NODE_ENCODING:{
11176 if (!popped) {
11177 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11178 }
11179 break;
11180 }
11181 case NODE_INTEGER:{
11182 VALUE lit = rb_node_integer_literal_val(node);
11183 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11184 debugp_param("integer", lit);
11185 if (!popped) {
11186 ADD_INSN1(ret, node, putobject, lit);
11187 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11188 }
11189 break;
11190 }
11191 case NODE_FLOAT:{
11192 VALUE lit = rb_node_float_literal_val(node);
11193 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11194 debugp_param("float", lit);
11195 if (!popped) {
11196 ADD_INSN1(ret, node, putobject, lit);
11197 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11198 }
11199 break;
11200 }
11201 case NODE_RATIONAL:{
11202 VALUE lit = rb_node_rational_literal_val(node);
11204 debugp_param("rational", lit);
11205 if (!popped) {
11206 ADD_INSN1(ret, node, putobject, lit);
11207 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11208 }
11209 break;
11210 }
11211 case NODE_IMAGINARY:{
11212 VALUE lit = rb_node_imaginary_literal_val(node);
11214 debugp_param("imaginary", lit);
11215 if (!popped) {
11216 ADD_INSN1(ret, node, putobject, lit);
11217 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11218 }
11219 break;
11220 }
11221 case NODE_FILE:
11222 case NODE_STR:{
11223 debugp_param("nd_lit", get_string_value(node));
11224 if (!popped) {
11225 VALUE lit = get_string_value(node);
11226 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11227 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11228 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11229 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11230 RB_OBJ_SET_SHAREABLE(lit);
11231 }
11232 switch (option->frozen_string_literal) {
11233 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11234 ADD_INSN1(ret, node, putchilledstring, lit);
11235 break;
11236 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11237 ADD_INSN1(ret, node, putstring, lit);
11238 break;
11239 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11240 ADD_INSN1(ret, node, putobject, lit);
11241 break;
11242 default:
11243 rb_bug("invalid frozen_string_literal");
11244 }
11245 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11246 }
11247 break;
11248 }
11249 case NODE_DSTR:{
11250 compile_dstr(iseq, ret, node);
11251
11252 if (popped) {
11253 ADD_INSN(ret, node, pop);
11254 }
11255 break;
11256 }
11257 case NODE_XSTR:{
11258 ADD_CALL_RECEIVER(ret, node);
11259 VALUE str = rb_node_str_string_val(node);
11260 ADD_INSN1(ret, node, putobject, str);
11261 RB_OBJ_WRITTEN(iseq, Qundef, str);
11262 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11263
11264 if (popped) {
11265 ADD_INSN(ret, node, pop);
11266 }
11267 break;
11268 }
11269 case NODE_DXSTR:{
11270 ADD_CALL_RECEIVER(ret, node);
11271 compile_dstr(iseq, ret, node);
11272 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11273
11274 if (popped) {
11275 ADD_INSN(ret, node, pop);
11276 }
11277 break;
11278 }
11279 case NODE_EVSTR:
11280 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11281 break;
11282 case NODE_REGX:{
11283 if (!popped) {
11284 VALUE lit = rb_node_regx_string_val(node);
11285 RB_OBJ_SET_SHAREABLE(lit);
11286 ADD_INSN1(ret, node, putobject, lit);
11287 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11288 }
11289 break;
11290 }
11291 case NODE_DREGX:
11292 compile_dregx(iseq, ret, node, popped);
11293 break;
11294 case NODE_ONCE:{
11295 int ic_index = body->ise_size++;
11296 const rb_iseq_t *block_iseq;
11297 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11298
11299 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11300 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11301
11302 if (popped) {
11303 ADD_INSN(ret, node, pop);
11304 }
11305 break;
11306 }
11307 case NODE_ARGSCAT:{
11308 if (popped) {
11309 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11310 ADD_INSN1(ret, node, splatarray, Qfalse);
11311 ADD_INSN(ret, node, pop);
11312 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11313 ADD_INSN1(ret, node, splatarray, Qfalse);
11314 ADD_INSN(ret, node, pop);
11315 }
11316 else {
11317 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11318 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11319 if (nd_type_p(body_node, NODE_LIST)) {
11320 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11321 }
11322 else {
11323 CHECK(COMPILE(ret, "argscat body", body_node));
11324 ADD_INSN(ret, node, concattoarray);
11325 }
11326 }
11327 break;
11328 }
11329 case NODE_ARGSPUSH:{
11330 if (popped) {
11331 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11332 ADD_INSN1(ret, node, splatarray, Qfalse);
11333 ADD_INSN(ret, node, pop);
11334 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11335 }
11336 else {
11337 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11338 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11339 if (keyword_node_p(body_node)) {
11340 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11341 ADD_INSN(ret, node, pushtoarraykwsplat);
11342 }
11343 else if (static_literal_node_p(body_node, iseq, false)) {
11344 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11345 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11346 }
11347 else {
11348 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11349 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11350 }
11351 }
11352 break;
11353 }
11354 case NODE_SPLAT:{
11355 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11356 ADD_INSN1(ret, node, splatarray, Qtrue);
11357
11358 if (popped) {
11359 ADD_INSN(ret, node, pop);
11360 }
11361 break;
11362 }
11363 case NODE_DEFN:{
11364 ID mid = RNODE_DEFN(node)->nd_mid;
11365 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11366 rb_id2str(mid),
11367 ISEQ_TYPE_METHOD, line);
11368
11369 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11370 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11371 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11372
11373 if (!popped) {
11374 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11375 }
11376
11377 break;
11378 }
11379 case NODE_DEFS:{
11380 ID mid = RNODE_DEFS(node)->nd_mid;
11381 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11382 rb_id2str(mid),
11383 ISEQ_TYPE_METHOD, line);
11384
11385 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11386 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11387 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11388 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11389
11390 if (!popped) {
11391 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11392 }
11393 break;
11394 }
11395 case NODE_ALIAS:{
11396 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11397 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11398 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11399 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11400 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11401
11402 if (popped) {
11403 ADD_INSN(ret, node, pop);
11404 }
11405 break;
11406 }
11407 case NODE_VALIAS:{
11408 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11409 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11410 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11411 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11412
11413 if (popped) {
11414 ADD_INSN(ret, node, pop);
11415 }
11416 break;
11417 }
11418 case NODE_UNDEF:{
11419 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11420
11421 for (long i = 0; i < ary->len; i++) {
11422 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11423 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11424 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11425 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11426
11427 if (i < ary->len - 1) {
11428 ADD_INSN(ret, node, pop);
11429 }
11430 }
11431
11432 if (popped) {
11433 ADD_INSN(ret, node, pop);
11434 }
11435 break;
11436 }
11437 case NODE_CLASS:{
11438 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11439 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11440 ISEQ_TYPE_CLASS, line);
11441 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11442 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11443 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11444
11445 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11446 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11447 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11448
11449 if (popped) {
11450 ADD_INSN(ret, node, pop);
11451 }
11452 break;
11453 }
11454 case NODE_MODULE:{
11455 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11456 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11457 ISEQ_TYPE_CLASS, line);
11458 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11459 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11460
11461 ADD_INSN (ret, node, putnil); /* dummy */
11462 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11463 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11464
11465 if (popped) {
11466 ADD_INSN(ret, node, pop);
11467 }
11468 break;
11469 }
11470 case NODE_SCLASS:{
11471 ID singletonclass;
11472 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11473 ISEQ_TYPE_CLASS, line);
11474
11475 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11476 ADD_INSN (ret, node, putnil);
11477 CONST_ID(singletonclass, "singletonclass");
11478 ADD_INSN3(ret, node, defineclass,
11479 ID2SYM(singletonclass), singleton_class,
11480 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11481 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11482
11483 if (popped) {
11484 ADD_INSN(ret, node, pop);
11485 }
11486 break;
11487 }
11488 case NODE_COLON2:
11489 CHECK(compile_colon2(iseq, ret, node, popped));
11490 break;
11491 case NODE_COLON3:
11492 CHECK(compile_colon3(iseq, ret, node, popped));
11493 break;
11494 case NODE_DOT2:
11495 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11496 break;
11497 case NODE_DOT3:
11498 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11499 break;
11500 case NODE_FLIP2:
11501 case NODE_FLIP3:{
11502 LABEL *lend = NEW_LABEL(line);
11503 LABEL *ltrue = NEW_LABEL(line);
11504 LABEL *lfalse = NEW_LABEL(line);
11505 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11506 ltrue, lfalse));
11507 ADD_LABEL(ret, ltrue);
11508 ADD_INSN1(ret, node, putobject, Qtrue);
11509 ADD_INSNL(ret, node, jump, lend);
11510 ADD_LABEL(ret, lfalse);
11511 ADD_INSN1(ret, node, putobject, Qfalse);
11512 ADD_LABEL(ret, lend);
11513 break;
11514 }
11515 case NODE_SELF:{
11516 if (!popped) {
11517 ADD_INSN(ret, node, putself);
11518 }
11519 break;
11520 }
11521 case NODE_NIL:{
11522 if (!popped) {
11523 ADD_INSN(ret, node, putnil);
11524 }
11525 break;
11526 }
11527 case NODE_TRUE:{
11528 if (!popped) {
11529 ADD_INSN1(ret, node, putobject, Qtrue);
11530 }
11531 break;
11532 }
11533 case NODE_FALSE:{
11534 if (!popped) {
11535 ADD_INSN1(ret, node, putobject, Qfalse);
11536 }
11537 break;
11538 }
11539 case NODE_ERRINFO:
11540 CHECK(compile_errinfo(iseq, ret, node, popped));
11541 break;
11542 case NODE_DEFINED:
11543 if (!popped) {
11544 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11545 }
11546 break;
11547 case NODE_POSTEXE:{
11548 /* compiled to:
11549 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11550 */
11551 int is_index = body->ise_size++;
11553 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11554 const rb_iseq_t *once_iseq =
11555 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11556
11557 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11558 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11559
11560 if (popped) {
11561 ADD_INSN(ret, node, pop);
11562 }
11563 break;
11564 }
11565 case NODE_KW_ARG:
11566 CHECK(compile_kw_arg(iseq, ret, node, popped));
11567 break;
11568 case NODE_DSYM:{
11569 compile_dstr(iseq, ret, node);
11570 if (!popped) {
11571 ADD_INSN(ret, node, intern);
11572 }
11573 else {
11574 ADD_INSN(ret, node, pop);
11575 }
11576 break;
11577 }
11578 case NODE_ATTRASGN:
11579 CHECK(compile_attrasgn(iseq, ret, node, popped));
11580 break;
11581 case NODE_LAMBDA:{
11582 /* compile same as lambda{...} */
11583 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11584 VALUE argc = INT2FIX(0);
11585
11586 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11587 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11588 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11589
11590 if (popped) {
11591 ADD_INSN(ret, node, pop);
11592 }
11593 break;
11594 }
11595 default:
11596 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11597 ng:
11598 debug_node_end();
11599 return COMPILE_NG;
11600 }
11601
11602 debug_node_end();
11603 return COMPILE_OK;
11604}
11605
11606/***************************/
11607/* instruction information */
11608/***************************/
11609
11610static int
11611insn_data_length(INSN *iobj)
11612{
11613 return insn_len(iobj->insn_id);
11614}
11615
11616static int
11617calc_sp_depth(int depth, INSN *insn)
11618{
11619 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11620}
11621
11622static VALUE
11623opobj_inspect(VALUE obj)
11624{
11625 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11626 switch (BUILTIN_TYPE(obj)) {
11627 case T_STRING:
11628 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11629 break;
11630 case T_ARRAY:
11631 obj = rb_ary_dup(obj);
11632 break;
11633 default:
11634 break;
11635 }
11636 }
11637 return rb_inspect(obj);
11638}
11639
11640
11641
11642static VALUE
11643insn_data_to_s_detail(INSN *iobj)
11644{
11645 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11646
11647 if (iobj->operands) {
11648 const char *types = insn_op_types(iobj->insn_id);
11649 int j;
11650
11651 for (j = 0; types[j]; j++) {
11652 char type = types[j];
11653
11654 switch (type) {
11655 case TS_OFFSET: /* label(destination position) */
11656 {
11657 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11658 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11659 break;
11660 }
11661 break;
11662 case TS_ISEQ: /* iseq */
11663 {
11664 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11665 VALUE val = Qnil;
11666 if (0 && iseq) { /* TODO: invalidate now */
11667 val = (VALUE)iseq;
11668 }
11669 rb_str_concat(str, opobj_inspect(val));
11670 }
11671 break;
11672 case TS_LINDEX:
11673 case TS_NUM: /* ulong */
11674 case TS_VALUE: /* VALUE */
11675 {
11676 VALUE v = OPERAND_AT(iobj, j);
11677 if (!CLASS_OF(v))
11678 rb_str_cat2(str, "<hidden>");
11679 else {
11680 rb_str_concat(str, opobj_inspect(v));
11681 }
11682 break;
11683 }
11684 case TS_ID: /* ID */
11685 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11686 break;
11687 case TS_IC: /* inline cache */
11688 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11689 break;
11690 case TS_IVC: /* inline ivar cache */
11691 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11692 break;
11693 case TS_ICVARC: /* inline cvar cache */
11694 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11695 break;
11696 case TS_ISE: /* inline storage entry */
11697 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11698 break;
11699 case TS_CALLDATA: /* we store these as call infos at compile time */
11700 {
11701 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11702 rb_str_cat2(str, "<calldata:");
11703 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11704 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11705 break;
11706 }
11707 case TS_CDHASH: /* case/when condition cache */
11708 rb_str_cat2(str, "<ch>");
11709 break;
11710 case TS_FUNCPTR:
11711 {
11712 void *func = (void *)OPERAND_AT(iobj, j);
11713#ifdef HAVE_DLADDR
11714 Dl_info info;
11715 if (dladdr(func, &info) && info.dli_sname) {
11716 rb_str_cat2(str, info.dli_sname);
11717 break;
11718 }
11719#endif
11720 rb_str_catf(str, "<%p>", func);
11721 }
11722 break;
11723 case TS_BUILTIN:
11724 rb_str_cat2(str, "<TS_BUILTIN>");
11725 break;
11726 default:{
11727 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11728 }
11729 }
11730 if (types[j + 1]) {
11731 rb_str_cat2(str, ", ");
11732 }
11733 }
11734 }
11735 return str;
11736}
11737
11738static void
11739dump_disasm_list(const LINK_ELEMENT *link)
11740{
11741 dump_disasm_list_with_cursor(link, NULL, NULL);
11742}
11743
11744static void
11745dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11746{
11747 int pos = 0;
11748 INSN *iobj;
11749 LABEL *lobj;
11750 VALUE str;
11751
11752 printf("-- raw disasm--------\n");
11753
11754 while (link) {
11755 if (curr) printf(curr == link ? "*" : " ");
11756 switch (link->type) {
11757 case ISEQ_ELEMENT_INSN:
11758 {
11759 iobj = (INSN *)link;
11760 str = insn_data_to_s_detail(iobj);
11761 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11762 pos += insn_data_length(iobj);
11763 break;
11764 }
11765 case ISEQ_ELEMENT_LABEL:
11766 {
11767 lobj = (LABEL *)link;
11768 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11769 dest == lobj ? " <---" : "");
11770 break;
11771 }
11772 case ISEQ_ELEMENT_TRACE:
11773 {
11774 TRACE *trace = (TRACE *)link;
11775 printf(" trace: %0x\n", trace->event);
11776 break;
11777 }
11778 case ISEQ_ELEMENT_ADJUST:
11779 {
11780 ADJUST *adjust = (ADJUST *)link;
11781 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11782 break;
11783 }
11784 default:
11785 /* ignore */
11786 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11787 }
11788 link = link->next;
11789 }
11790 printf("---------------------\n");
11791 fflush(stdout);
11792}
11793
11794int
11795rb_insn_len(VALUE insn)
11796{
11797 return insn_len(insn);
11798}
11799
11800const char *
11801rb_insns_name(int i)
11802{
11803 return insn_name(i);
11804}
11805
11806VALUE
11807rb_insns_name_array(void)
11808{
11809 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11810 int i;
11811 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11812 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11813 }
11814 return rb_ary_freeze(ary);
11815}
11816
11817static LABEL *
11818register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11819{
11820 LABEL *label = 0;
11821 st_data_t tmp;
11822 obj = rb_to_symbol_type(obj);
11823
11824 if (st_lookup(labels_table, obj, &tmp) == 0) {
11825 label = NEW_LABEL(0);
11826 st_insert(labels_table, obj, (st_data_t)label);
11827 }
11828 else {
11829 label = (LABEL *)tmp;
11830 }
11831 LABEL_REF(label);
11832 return label;
11833}
11834
11835static VALUE
11836get_exception_sym2type(VALUE sym)
11837{
11838 static VALUE symRescue, symEnsure, symRetry;
11839 static VALUE symBreak, symRedo, symNext;
11840
11841 if (symRescue == 0) {
11842 symRescue = ID2SYM(rb_intern_const("rescue"));
11843 symEnsure = ID2SYM(rb_intern_const("ensure"));
11844 symRetry = ID2SYM(rb_intern_const("retry"));
11845 symBreak = ID2SYM(rb_intern_const("break"));
11846 symRedo = ID2SYM(rb_intern_const("redo"));
11847 symNext = ID2SYM(rb_intern_const("next"));
11848 }
11849
11850 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11851 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11852 if (sym == symRetry) return CATCH_TYPE_RETRY;
11853 if (sym == symBreak) return CATCH_TYPE_BREAK;
11854 if (sym == symRedo) return CATCH_TYPE_REDO;
11855 if (sym == symNext) return CATCH_TYPE_NEXT;
11856 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11857 return 0;
11858}
11859
11860static int
11861iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11862 VALUE exception)
11863{
11864 int i;
11865
11866 for (i=0; i<RARRAY_LEN(exception); i++) {
11867 const rb_iseq_t *eiseq;
11868 VALUE v, type;
11869 LABEL *lstart, *lend, *lcont;
11870 unsigned int sp;
11871
11872 v = rb_to_array_type(RARRAY_AREF(exception, i));
11873 if (RARRAY_LEN(v) != 6) {
11874 rb_raise(rb_eSyntaxError, "wrong exception entry");
11875 }
11876 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11877 if (NIL_P(RARRAY_AREF(v, 1))) {
11878 eiseq = NULL;
11879 }
11880 else {
11881 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11882 }
11883
11884 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11885 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11886 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11887 sp = NUM2UINT(RARRAY_AREF(v, 5));
11888
11889 /* TODO: Dirty Hack! Fix me */
11890 if (type == CATCH_TYPE_RESCUE ||
11891 type == CATCH_TYPE_BREAK ||
11892 type == CATCH_TYPE_NEXT) {
11893 ++sp;
11894 }
11895
11896 lcont->sp = sp;
11897
11898 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11899
11900 RB_GC_GUARD(v);
11901 }
11902 return COMPILE_OK;
11903}
11904
11905static struct st_table *
11906insn_make_insn_table(void)
11907{
11908 struct st_table *table;
11909 int i;
11910 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11911
11912 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11913 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11914 }
11915
11916 return table;
11917}
11918
11919static const rb_iseq_t *
11920iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11921{
11922 VALUE iseqw;
11923 const rb_iseq_t *loaded_iseq;
11924
11925 if (RB_TYPE_P(op, T_ARRAY)) {
11926 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11927 }
11928 else if (CLASS_OF(op) == rb_cISeq) {
11929 iseqw = op;
11930 }
11931 else {
11932 rb_raise(rb_eSyntaxError, "ISEQ is required");
11933 }
11934
11935 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11936 return loaded_iseq;
11937}
11938
11939static VALUE
11940iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11941{
11942 ID mid = 0;
11943 int orig_argc = 0;
11944 unsigned int flag = 0;
11945 struct rb_callinfo_kwarg *kw_arg = 0;
11946
11947 if (!NIL_P(op)) {
11948 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11949 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11950 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11951 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11952
11953 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11954 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11955 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11956
11957 if (!NIL_P(vkw_arg)) {
11958 int i;
11959 int len = RARRAY_LENINT(vkw_arg);
11960 size_t n = rb_callinfo_kwarg_bytes(len);
11961
11962 kw_arg = xmalloc(n);
11963 kw_arg->references = 0;
11964 kw_arg->keyword_len = len;
11965 for (i = 0; i < len; i++) {
11966 VALUE kw = RARRAY_AREF(vkw_arg, i);
11967 SYM2ID(kw); /* make immortal */
11968 kw_arg->keywords[i] = kw;
11969 }
11970 }
11971 }
11972
11973 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11974 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11975 return (VALUE)ci;
11976}
11977
11978static rb_event_flag_t
11979event_name_to_flag(VALUE sym)
11980{
11981#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11982 CHECK_EVENT(RUBY_EVENT_LINE);
11983 CHECK_EVENT(RUBY_EVENT_CLASS);
11984 CHECK_EVENT(RUBY_EVENT_END);
11985 CHECK_EVENT(RUBY_EVENT_CALL);
11986 CHECK_EVENT(RUBY_EVENT_RETURN);
11987 CHECK_EVENT(RUBY_EVENT_B_CALL);
11988 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11989 CHECK_EVENT(RUBY_EVENT_RESCUE);
11990#undef CHECK_EVENT
11991 return RUBY_EVENT_NONE;
11992}
11993
11994static int
11995iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11996 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11997{
11998 /* TODO: body should be frozen */
11999 long i, len = RARRAY_LEN(body);
12000 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12001 int j;
12002 int line_no = 0, node_id = -1, insn_idx = 0;
12003 int ret = COMPILE_OK;
12004
12005 /*
12006 * index -> LABEL *label
12007 */
12008 static struct st_table *insn_table;
12009
12010 if (insn_table == 0) {
12011 insn_table = insn_make_insn_table();
12012 }
12013
12014 for (i=0; i<len; i++) {
12015 VALUE obj = RARRAY_AREF(body, i);
12016
12017 if (SYMBOL_P(obj)) {
12018 rb_event_flag_t event;
12019 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12020 ADD_TRACE(anchor, event);
12021 }
12022 else {
12023 LABEL *label = register_label(iseq, labels_table, obj);
12024 ADD_LABEL(anchor, label);
12025 }
12026 }
12027 else if (FIXNUM_P(obj)) {
12028 line_no = NUM2INT(obj);
12029 }
12030 else if (RB_TYPE_P(obj, T_ARRAY)) {
12031 VALUE *argv = 0;
12032 int argc = RARRAY_LENINT(obj) - 1;
12033 st_data_t insn_id;
12034 VALUE insn;
12035
12036 if (node_ids) {
12037 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12038 }
12039
12040 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12041 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12042 /* TODO: exception */
12043 COMPILE_ERROR(iseq, line_no,
12044 "unknown instruction: %+"PRIsVALUE, insn);
12045 ret = COMPILE_NG;
12046 break;
12047 }
12048
12049 if (argc != insn_len((VALUE)insn_id)-1) {
12050 COMPILE_ERROR(iseq, line_no,
12051 "operand size mismatch");
12052 ret = COMPILE_NG;
12053 break;
12054 }
12055
12056 if (argc > 0) {
12057 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12058
12059 // add element before operand setup to make GC root
12060 ADD_ELEM(anchor,
12061 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12062 (enum ruby_vminsn_type)insn_id, argc, argv));
12063
12064 for (j=0; j<argc; j++) {
12065 VALUE op = rb_ary_entry(obj, j+1);
12066 switch (insn_op_type((VALUE)insn_id, j)) {
12067 case TS_OFFSET: {
12068 LABEL *label = register_label(iseq, labels_table, op);
12069 argv[j] = (VALUE)label;
12070 break;
12071 }
12072 case TS_LINDEX:
12073 case TS_NUM:
12074 (void)NUM2INT(op);
12075 argv[j] = op;
12076 break;
12077 case TS_VALUE:
12078 argv[j] = op;
12079 RB_OBJ_WRITTEN(iseq, Qundef, op);
12080 break;
12081 case TS_ISEQ:
12082 {
12083 if (op != Qnil) {
12084 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12085 argv[j] = v;
12086 RB_OBJ_WRITTEN(iseq, Qundef, v);
12087 }
12088 else {
12089 argv[j] = 0;
12090 }
12091 }
12092 break;
12093 case TS_ISE:
12094 argv[j] = op;
12095 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12096 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12097 }
12098 break;
12099 case TS_IC:
12100 {
12101 VALUE segments = rb_ary_new();
12102 op = rb_to_array_type(op);
12103
12104 for (int i = 0; i < RARRAY_LEN(op); i++) {
12105 VALUE sym = RARRAY_AREF(op, i);
12106 sym = rb_to_symbol_type(sym);
12107 rb_ary_push(segments, sym);
12108 }
12109
12110 RB_GC_GUARD(op);
12111 argv[j] = segments;
12112 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12113 ISEQ_BODY(iseq)->ic_size++;
12114 }
12115 break;
12116 case TS_IVC: /* inline ivar cache */
12117 argv[j] = op;
12118 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12119 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12120 }
12121 break;
12122 case TS_ICVARC: /* inline cvar cache */
12123 argv[j] = op;
12124 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12125 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12126 }
12127 break;
12128 case TS_CALLDATA:
12129 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12130 break;
12131 case TS_ID:
12132 argv[j] = rb_to_symbol_type(op);
12133 break;
12134 case TS_CDHASH:
12135 {
12136 int i;
12137 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12138
12139 RHASH_TBL_RAW(map)->type = &cdhash_type;
12140 op = rb_to_array_type(op);
12141 for (i=0; i<RARRAY_LEN(op); i+=2) {
12142 VALUE key = RARRAY_AREF(op, i);
12143 VALUE sym = RARRAY_AREF(op, i+1);
12144 LABEL *label =
12145 register_label(iseq, labels_table, sym);
12146 rb_hash_aset(map, key, (VALUE)label | 1);
12147 }
12148 RB_GC_GUARD(op);
12149 RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
12150 argv[j] = map;
12151 RB_OBJ_WRITTEN(iseq, Qundef, map);
12152 }
12153 break;
12154 case TS_FUNCPTR:
12155 {
12156#if SIZEOF_VALUE <= SIZEOF_LONG
12157 long funcptr = NUM2LONG(op);
12158#else
12159 LONG_LONG funcptr = NUM2LL(op);
12160#endif
12161 argv[j] = (VALUE)funcptr;
12162 }
12163 break;
12164 default:
12165 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12166 }
12167 }
12168 }
12169 else {
12170 ADD_ELEM(anchor,
12171 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12172 (enum ruby_vminsn_type)insn_id, argc, NULL));
12173 }
12174 }
12175 else {
12176 rb_raise(rb_eTypeError, "unexpected object for instruction");
12177 }
12178 }
12179 RTYPEDDATA_DATA(labels_wrapper) = 0;
12180 RB_GC_GUARD(labels_wrapper);
12181 validate_labels(iseq, labels_table);
12182 if (!ret) return ret;
12183 return iseq_setup(iseq, anchor);
12184}
12185
12186#define CHECK_ARRAY(v) rb_to_array_type(v)
12187#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12188
12189static int
12190int_param(int *dst, VALUE param, VALUE sym)
12191{
12192 VALUE val = rb_hash_aref(param, sym);
12193 if (FIXNUM_P(val)) {
12194 *dst = FIX2INT(val);
12195 return TRUE;
12196 }
12197 else if (!NIL_P(val)) {
12198 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12199 sym, val);
12200 }
12201 return FALSE;
12202}
12203
12204static const struct rb_iseq_param_keyword *
12205iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12206{
12207 int i, j;
12208 int len = RARRAY_LENINT(keywords);
12209 int default_len;
12210 VALUE key, sym, default_val;
12211 VALUE *dvs;
12212 ID *ids;
12213 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12214
12215 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12216
12217 keyword->num = len;
12218#define SYM(s) ID2SYM(rb_intern_const(#s))
12219 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12220 i = keyword->bits_start - keyword->num;
12221 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12222#undef SYM
12223
12224 /* required args */
12225 for (i = 0; i < len; i++) {
12226 VALUE val = RARRAY_AREF(keywords, i);
12227
12228 if (!SYMBOL_P(val)) {
12229 goto default_values;
12230 }
12231 ids[i] = SYM2ID(val);
12232 keyword->required_num++;
12233 }
12234
12235 default_values: /* note: we intentionally preserve `i' from previous loop */
12236 default_len = len - i;
12237 if (default_len == 0) {
12238 keyword->table = ids;
12239 return keyword;
12240 }
12241 else if (default_len < 0) {
12243 }
12244
12245 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12246
12247 for (j = 0; i < len; i++, j++) {
12248 key = RARRAY_AREF(keywords, i);
12249 CHECK_ARRAY(key);
12250
12251 switch (RARRAY_LEN(key)) {
12252 case 1:
12253 sym = RARRAY_AREF(key, 0);
12254 default_val = Qundef;
12255 break;
12256 case 2:
12257 sym = RARRAY_AREF(key, 0);
12258 default_val = RARRAY_AREF(key, 1);
12259 break;
12260 default:
12261 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12262 }
12263 ids[i] = SYM2ID(sym);
12264 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12265 }
12266
12267 keyword->table = ids;
12268 keyword->default_values = dvs;
12269
12270 return keyword;
12271}
12272
12273static void
12274iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12275{
12276 rb_gc_mark_and_move(obj);
12277}
12278
12279void
12280rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12281{
12282 INSN *iobj = 0;
12283 size_t size = sizeof(INSN);
12284 unsigned int pos = 0;
12285
12286 while (storage) {
12287#ifdef STRICT_ALIGNMENT
12288 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12289#else
12290 const size_t padding = 0; /* expected to be optimized by compiler */
12291#endif /* STRICT_ALIGNMENT */
12292 size_t offset = pos + size + padding;
12293 if (offset > storage->size || offset > storage->pos) {
12294 pos = 0;
12295 storage = storage->next;
12296 }
12297 else {
12298#ifdef STRICT_ALIGNMENT
12299 pos += (int)padding;
12300#endif /* STRICT_ALIGNMENT */
12301
12302 iobj = (INSN *)&storage->buff[pos];
12303
12304 if (iobj->operands) {
12305 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12306 }
12307 pos += (int)size;
12308 }
12309 }
12310}
12311
12312static const rb_data_type_t labels_wrapper_type = {
12313 .wrap_struct_name = "compiler/labels_wrapper",
12314 .function = {
12315 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12316 .dfree = (RUBY_DATA_FUNC)st_free_table,
12317 },
12318 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12319};
12320
12321void
12322rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12323 VALUE exception, VALUE body)
12324{
12325#define SYM(s) ID2SYM(rb_intern_const(#s))
12326 int i, len;
12327 unsigned int arg_size, local_size, stack_max;
12328 ID *tbl;
12329 struct st_table *labels_table = st_init_numtable();
12330 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12331 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12332 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12333 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12334 DECL_ANCHOR(anchor);
12335 INIT_ANCHOR(anchor);
12336
12337 len = RARRAY_LENINT(locals);
12338 ISEQ_BODY(iseq)->local_table_size = len;
12339 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12340
12341 for (i = 0; i < len; i++) {
12342 VALUE lv = RARRAY_AREF(locals, i);
12343
12344 if (sym_arg_rest == lv) {
12345 tbl[i] = 0;
12346 }
12347 else {
12348 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12349 }
12350 }
12351
12352#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12353 if (INT_PARAM(lead_num)) {
12354 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12355 }
12356 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12357 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12358 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12359 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12360#undef INT_PARAM
12361 {
12362#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12363 int x;
12364 INT_PARAM(arg_size);
12365 INT_PARAM(local_size);
12366 INT_PARAM(stack_max);
12367#undef INT_PARAM
12368 }
12369
12370 VALUE node_ids = Qfalse;
12371#ifdef USE_ISEQ_NODE_ID
12372 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12373 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12374 rb_raise(rb_eTypeError, "node_ids is not an array");
12375 }
12376#endif
12377
12378 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12379 len = RARRAY_LENINT(arg_opt_labels);
12380 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12381
12382 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12383 VALUE *opt_table = ALLOC_N(VALUE, len);
12384
12385 for (i = 0; i < len; i++) {
12386 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12387 LABEL *label = register_label(iseq, labels_table, ent);
12388 opt_table[i] = (VALUE)label;
12389 }
12390
12391 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12392 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12393 }
12394 }
12395 else if (!NIL_P(arg_opt_labels)) {
12396 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12397 arg_opt_labels);
12398 }
12399
12400 if (RB_TYPE_P(keywords, T_ARRAY)) {
12401 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12402 }
12403 else if (!NIL_P(keywords)) {
12404 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12405 keywords);
12406 }
12407
12408 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12409 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12410 }
12411
12412 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12413 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12414 }
12415
12416 if (int_param(&i, params, SYM(kwrest))) {
12417 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12418 if (keyword == NULL) {
12419 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12420 }
12421 keyword->rest_start = i;
12422 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12423 }
12424#undef SYM
12425 iseq_calc_param_size(iseq);
12426
12427 /* exception */
12428 iseq_build_from_ary_exception(iseq, labels_table, exception);
12429
12430 /* body */
12431 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12432
12433 ISEQ_BODY(iseq)->param.size = arg_size;
12434 ISEQ_BODY(iseq)->local_table_size = local_size;
12435 ISEQ_BODY(iseq)->stack_max = stack_max;
12436}
12437
12438/* for parser */
12439
12440int
12441rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12442{
12443 if (iseq) {
12444 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12445 while (body->type == ISEQ_TYPE_BLOCK ||
12446 body->type == ISEQ_TYPE_RESCUE ||
12447 body->type == ISEQ_TYPE_ENSURE ||
12448 body->type == ISEQ_TYPE_EVAL ||
12449 body->type == ISEQ_TYPE_MAIN
12450 ) {
12451 unsigned int i;
12452
12453 for (i = 0; i < body->local_table_size; i++) {
12454 if (body->local_table[i] == id) {
12455 return 1;
12456 }
12457 }
12458 iseq = body->parent_iseq;
12459 body = ISEQ_BODY(iseq);
12460 }
12461 }
12462 return 0;
12463}
12464
12465int
12466rb_local_defined(ID id, const rb_iseq_t *iseq)
12467{
12468 if (iseq) {
12469 unsigned int i;
12470 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12471
12472 for (i=0; i<body->local_table_size; i++) {
12473 if (body->local_table[i] == id) {
12474 return 1;
12475 }
12476 }
12477 }
12478 return 0;
12479}
12480
12481/* ISeq binary format */
12482
12483#ifndef IBF_ISEQ_DEBUG
12484#define IBF_ISEQ_DEBUG 0
12485#endif
12486
12487#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12488#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12489#endif
12490
12491typedef uint32_t ibf_offset_t;
12492#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12493
12494#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12495#ifdef RUBY_DEVEL
12496#define IBF_DEVEL_VERSION 5
12497#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12498#else
12499#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12500#endif
12501
12502static const char IBF_ENDIAN_MARK =
12503#ifdef WORDS_BIGENDIAN
12504 'b'
12505#else
12506 'l'
12507#endif
12508 ;
12509
12511 char magic[4]; /* YARB */
12512 uint32_t major_version;
12513 uint32_t minor_version;
12514 uint32_t size;
12515 uint32_t extra_size;
12516
12517 uint32_t iseq_list_size;
12518 uint32_t global_object_list_size;
12519 ibf_offset_t iseq_list_offset;
12520 ibf_offset_t global_object_list_offset;
12521 uint8_t endian;
12522 uint8_t wordsize; /* assume no 2048-bit CPU */
12523};
12524
12526 VALUE str;
12527 st_table *obj_table; /* obj -> obj number */
12528};
12529
12530struct ibf_dump {
12531 st_table *iseq_table; /* iseq -> iseq number */
12532 struct ibf_dump_buffer global_buffer;
12533 struct ibf_dump_buffer *current_buffer;
12534};
12535
12537 const char *buff;
12538 ibf_offset_t size;
12539
12540 VALUE obj_list; /* [obj0, ...] */
12541 unsigned int obj_list_size;
12542 ibf_offset_t obj_list_offset;
12543};
12544
12545struct ibf_load {
12546 const struct ibf_header *header;
12547 VALUE iseq_list; /* [iseq0, ...] */
12548 struct ibf_load_buffer global_buffer;
12549 VALUE loader_obj;
12550 rb_iseq_t *iseq;
12551 VALUE str;
12552 struct ibf_load_buffer *current_buffer;
12553};
12554
12556 long size;
12557 VALUE buffer[1];
12558};
12559
12560static void
12561pinned_list_mark(void *ptr)
12562{
12563 long i;
12564 struct pinned_list *list = (struct pinned_list *)ptr;
12565 for (i = 0; i < list->size; i++) {
12566 if (list->buffer[i]) {
12567 rb_gc_mark(list->buffer[i]);
12568 }
12569 }
12570}
12571
12572static const rb_data_type_t pinned_list_type = {
12573 "pinned_list",
12574 {
12575 pinned_list_mark,
12577 NULL, // No external memory to report,
12578 },
12579 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12580};
12581
12582static VALUE
12583pinned_list_fetch(VALUE list, long offset)
12584{
12585 struct pinned_list * ptr;
12586
12587 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12588
12589 if (offset >= ptr->size) {
12590 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12591 }
12592
12593 return ptr->buffer[offset];
12594}
12595
12596static void
12597pinned_list_store(VALUE list, long offset, VALUE object)
12598{
12599 struct pinned_list * ptr;
12600
12601 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12602
12603 if (offset >= ptr->size) {
12604 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12605 }
12606
12607 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12608}
12609
12610static VALUE
12611pinned_list_new(long size)
12612{
12613 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12614 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12615 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12616 ptr->size = size;
12617 return obj_list;
12618}
12619
12620static ibf_offset_t
12621ibf_dump_pos(struct ibf_dump *dump)
12622{
12623 long pos = RSTRING_LEN(dump->current_buffer->str);
12624#if SIZEOF_LONG > SIZEOF_INT
12625 if (pos >= UINT_MAX) {
12626 rb_raise(rb_eRuntimeError, "dump size exceeds");
12627 }
12628#endif
12629 return (unsigned int)pos;
12630}
12631
12632static void
12633ibf_dump_align(struct ibf_dump *dump, size_t align)
12634{
12635 ibf_offset_t pos = ibf_dump_pos(dump);
12636 if (pos % align) {
12637 static const char padding[sizeof(VALUE)];
12638 size_t size = align - ((size_t)pos % align);
12639#if SIZEOF_LONG > SIZEOF_INT
12640 if (pos + size >= UINT_MAX) {
12641 rb_raise(rb_eRuntimeError, "dump size exceeds");
12642 }
12643#endif
12644 for (; size > sizeof(padding); size -= sizeof(padding)) {
12645 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12646 }
12647 rb_str_cat(dump->current_buffer->str, padding, size);
12648 }
12649}
12650
12651static ibf_offset_t
12652ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12653{
12654 ibf_offset_t pos = ibf_dump_pos(dump);
12655#if SIZEOF_LONG > SIZEOF_INT
12656 /* ensure the resulting dump does not exceed UINT_MAX */
12657 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12658 rb_raise(rb_eRuntimeError, "dump size exceeds");
12659 }
12660#endif
12661 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12662 return pos;
12663}
12664
12665static ibf_offset_t
12666ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12667{
12668 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12669}
12670
12671static void
12672ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12673{
12674 VALUE str = dump->current_buffer->str;
12675 char *ptr = RSTRING_PTR(str);
12676 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12677 rb_bug("ibf_dump_overwrite: overflow");
12678 memcpy(ptr + offset, buff, size);
12679}
12680
12681static const void *
12682ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12683{
12684 ibf_offset_t beg = *offset;
12685 *offset += size;
12686 return load->current_buffer->buff + beg;
12687}
12688
12689static void *
12690ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12691{
12692 void *buff = ruby_xmalloc2(x, y);
12693 size_t size = x * y;
12694 memcpy(buff, load->current_buffer->buff + offset, size);
12695 return buff;
12696}
12697
12698#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12699
12700#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12701#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12702#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12703#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12704#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12705
12706static int
12707ibf_table_lookup(struct st_table *table, st_data_t key)
12708{
12709 st_data_t val;
12710
12711 if (st_lookup(table, key, &val)) {
12712 return (int)val;
12713 }
12714 else {
12715 return -1;
12716 }
12717}
12718
12719static int
12720ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12721{
12722 int index = ibf_table_lookup(table, key);
12723
12724 if (index < 0) { /* not found */
12725 index = (int)table->num_entries;
12726 st_insert(table, key, (st_data_t)index);
12727 }
12728
12729 return index;
12730}
12731
12732/* dump/load generic */
12733
12734static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12735
12736static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12737static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12738
12739static st_table *
12740ibf_dump_object_table_new(void)
12741{
12742 st_table *obj_table = st_init_numtable(); /* need free */
12743 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12744
12745 return obj_table;
12746}
12747
12748static VALUE
12749ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12750{
12751 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12752}
12753
12754static VALUE
12755ibf_dump_id(struct ibf_dump *dump, ID id)
12756{
12757 if (id == 0 || rb_id2name(id) == NULL) {
12758 return 0;
12759 }
12760 return ibf_dump_object(dump, rb_id2sym(id));
12761}
12762
12763static ID
12764ibf_load_id(const struct ibf_load *load, const ID id_index)
12765{
12766 if (id_index == 0) {
12767 return 0;
12768 }
12769 VALUE sym = ibf_load_object(load, id_index);
12770 if (rb_integer_type_p(sym)) {
12771 /* Load hidden local variables as indexes */
12772 return NUM2ULONG(sym);
12773 }
12774 return rb_sym2id(sym);
12775}
12776
12777/* dump/load: code */
12778
12779static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12780
12781static int
12782ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12783{
12784 if (iseq == NULL) {
12785 return -1;
12786 }
12787 else {
12788 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12789 }
12790}
12791
12792static unsigned char
12793ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12794{
12795 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12796 return (unsigned char)load->current_buffer->buff[(*offset)++];
12797}
12798
12799/*
12800 * Small uint serialization
12801 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12802 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12803 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12804 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12805 * ...
12806 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12807 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12808 */
12809static void
12810ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12811{
12812 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12813 ibf_dump_write(dump, &x, sizeof(VALUE));
12814 return;
12815 }
12816
12817 enum { max_byte_length = sizeof(VALUE) + 1 };
12818
12819 unsigned char bytes[max_byte_length];
12820 ibf_offset_t n;
12821
12822 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12823 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12824 }
12825
12826 x <<= 1;
12827 x |= 1;
12828 x <<= n;
12829 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12830 n++;
12831
12832 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12833}
12834
12835static VALUE
12836ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12837{
12838 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12839 union { char s[sizeof(VALUE)]; VALUE v; } x;
12840
12841 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12842 *offset += sizeof(VALUE);
12843
12844 return x.v;
12845 }
12846
12847 enum { max_byte_length = sizeof(VALUE) + 1 };
12848
12849 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12850 const unsigned char c = buffer[*offset];
12851
12852 ibf_offset_t n =
12853 c & 1 ? 1 :
12854 c == 0 ? 9 : ntz_int32(c) + 1;
12855 VALUE x = (VALUE)c >> n;
12856
12857 if (*offset + n > load->current_buffer->size) {
12858 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12859 }
12860
12861 ibf_offset_t i;
12862 for (i = 1; i < n; i++) {
12863 x <<= 8;
12864 x |= (VALUE)buffer[*offset + i];
12865 }
12866
12867 *offset += n;
12868 return x;
12869}
12870
12871static void
12872ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12873{
12874 // short: index
12875 // short: name.length
12876 // bytes: name
12877 // // omit argc (only verify with name)
12878 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12879
12880 size_t len = strlen(bf->name);
12881 ibf_dump_write_small_value(dump, (VALUE)len);
12882 ibf_dump_write(dump, bf->name, len);
12883}
12884
12885static const struct rb_builtin_function *
12886ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12887{
12888 int i = (int)ibf_load_small_value(load, offset);
12889 int len = (int)ibf_load_small_value(load, offset);
12890 const char *name = (char *)ibf_load_ptr(load, offset, len);
12891
12892 if (0) {
12893 fprintf(stderr, "%.*s!!\n", len, name);
12894 }
12895
12896 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12897 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12898 if (strncmp(table[i].name, name, len) != 0) {
12899 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12900 }
12901 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12902
12903 return &table[i];
12904}
12905
12906static ibf_offset_t
12907ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12908{
12909 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12910 const int iseq_size = body->iseq_size;
12911 int code_index;
12912 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12913
12914 ibf_offset_t offset = ibf_dump_pos(dump);
12915
12916 for (code_index=0; code_index<iseq_size;) {
12917 const VALUE insn = orig_code[code_index++];
12918 const char *types = insn_op_types(insn);
12919 int op_index;
12920
12921 /* opcode */
12922 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12923 ibf_dump_write_small_value(dump, insn);
12924
12925 /* operands */
12926 for (op_index=0; types[op_index]; op_index++, code_index++) {
12927 VALUE op = orig_code[code_index];
12928 VALUE wv;
12929
12930 switch (types[op_index]) {
12931 case TS_CDHASH:
12932 case TS_VALUE:
12933 wv = ibf_dump_object(dump, op);
12934 break;
12935 case TS_ISEQ:
12936 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12937 break;
12938 case TS_IC:
12939 {
12940 IC ic = (IC)op;
12941 VALUE arr = idlist_to_array(ic->segments);
12942 wv = ibf_dump_object(dump, arr);
12943 }
12944 break;
12945 case TS_ISE:
12946 case TS_IVC:
12947 case TS_ICVARC:
12948 {
12950 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12951 }
12952 break;
12953 case TS_CALLDATA:
12954 {
12955 goto skip_wv;
12956 }
12957 case TS_ID:
12958 wv = ibf_dump_id(dump, (ID)op);
12959 break;
12960 case TS_FUNCPTR:
12961 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12962 goto skip_wv;
12963 case TS_BUILTIN:
12964 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12965 goto skip_wv;
12966 default:
12967 wv = op;
12968 break;
12969 }
12970 ibf_dump_write_small_value(dump, wv);
12971 skip_wv:;
12972 }
12973 RUBY_ASSERT(insn_len(insn) == op_index+1);
12974 }
12975
12976 return offset;
12977}
12978
12979static VALUE *
12980ibf_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)
12981{
12982 VALUE iseqv = (VALUE)iseq;
12983 unsigned int code_index;
12984 ibf_offset_t reading_pos = bytecode_offset;
12985 VALUE *code = ALLOC_N(VALUE, iseq_size);
12986
12987 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12988 struct rb_call_data *cd_entries = load_body->call_data;
12989 int ic_index = 0;
12990
12991 load_body->iseq_encoded = code;
12992 load_body->iseq_size = 0;
12993
12994 iseq_bits_t * mark_offset_bits;
12995
12996 iseq_bits_t tmp[1] = {0};
12997
12998 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12999 mark_offset_bits = tmp;
13000 }
13001 else {
13002 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13003 }
13004 bool needs_bitmap = false;
13005
13006 for (code_index=0; code_index<iseq_size;) {
13007 /* opcode */
13008 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13009 const char *types = insn_op_types(insn);
13010 int op_index;
13011
13012 code_index++;
13013
13014 /* operands */
13015 for (op_index=0; types[op_index]; op_index++, code_index++) {
13016 const char operand_type = types[op_index];
13017 switch (operand_type) {
13018 case TS_VALUE:
13019 {
13020 VALUE op = ibf_load_small_value(load, &reading_pos);
13021 VALUE v = ibf_load_object(load, op);
13022 code[code_index] = v;
13023 if (!SPECIAL_CONST_P(v)) {
13024 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13025 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13026 needs_bitmap = true;
13027 }
13028 break;
13029 }
13030 case TS_CDHASH:
13031 {
13032 VALUE op = ibf_load_small_value(load, &reading_pos);
13033 VALUE v = ibf_load_object(load, op);
13034 v = rb_hash_dup(v); // hash dumped as frozen
13035 RHASH_TBL_RAW(v)->type = &cdhash_type;
13036 rb_hash_rehash(v); // hash function changed
13037 RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13038
13039 // Overwrite the existing hash in the object list. This
13040 // is to keep the object alive during load time.
13041 // [Bug #17984] [ruby-core:104259]
13042 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13043
13044 code[code_index] = v;
13045 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13046 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13047 needs_bitmap = true;
13048 break;
13049 }
13050 case TS_ISEQ:
13051 {
13052 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13053 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13054 code[code_index] = v;
13055 if (!SPECIAL_CONST_P(v)) {
13056 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13057 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13058 needs_bitmap = true;
13059 }
13060 break;
13061 }
13062 case TS_IC:
13063 {
13064 VALUE op = ibf_load_small_value(load, &reading_pos);
13065 VALUE arr = ibf_load_object(load, op);
13066
13067 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13068 ic->segments = array_to_idlist(arr);
13069
13070 code[code_index] = (VALUE)ic;
13071 }
13072 break;
13073 case TS_ISE:
13074 case TS_ICVARC:
13075 case TS_IVC:
13076 {
13077 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13078
13079 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13080 code[code_index] = (VALUE)ic;
13081
13082 if (operand_type == TS_IVC) {
13083 IVC cache = (IVC)ic;
13084
13085 if (insn == BIN(setinstancevariable)) {
13086 ID iv_name = (ID)code[code_index - 1];
13087 cache->iv_set_name = iv_name;
13088 }
13089 else {
13090 cache->iv_set_name = 0;
13091 }
13092
13093 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13094 }
13095
13096 }
13097 break;
13098 case TS_CALLDATA:
13099 {
13100 code[code_index] = (VALUE)cd_entries++;
13101 }
13102 break;
13103 case TS_ID:
13104 {
13105 VALUE op = ibf_load_small_value(load, &reading_pos);
13106 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13107 }
13108 break;
13109 case TS_FUNCPTR:
13110 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13111 break;
13112 case TS_BUILTIN:
13113 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13114 break;
13115 default:
13116 code[code_index] = ibf_load_small_value(load, &reading_pos);
13117 continue;
13118 }
13119 }
13120 if (insn_len(insn) != op_index+1) {
13121 rb_raise(rb_eRuntimeError, "operand size mismatch");
13122 }
13123 }
13124
13125 load_body->iseq_size = code_index;
13126
13127 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13128 load_body->mark_bits.single = mark_offset_bits[0];
13129 }
13130 else {
13131 if (needs_bitmap) {
13132 load_body->mark_bits.list = mark_offset_bits;
13133 }
13134 else {
13135 load_body->mark_bits.list = 0;
13136 ruby_xfree(mark_offset_bits);
13137 }
13138 }
13139
13140 RUBY_ASSERT(code_index == iseq_size);
13141 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13142 return code;
13143}
13144
13145static ibf_offset_t
13146ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13147{
13148 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13149
13150 if (opt_num > 0) {
13151 IBF_W_ALIGN(VALUE);
13152 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13153 }
13154 else {
13155 return ibf_dump_pos(dump);
13156 }
13157}
13158
13159static VALUE *
13160ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13161{
13162 if (opt_num > 0) {
13163 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13164 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13165 return table;
13166 }
13167 else {
13168 return NULL;
13169 }
13170}
13171
13172static ibf_offset_t
13173ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13174{
13175 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13176
13177 if (kw) {
13178 struct rb_iseq_param_keyword dump_kw = *kw;
13179 int dv_num = kw->num - kw->required_num;
13180 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13181 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13182 int i;
13183
13184 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13185 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13186
13187 dump_kw.table = IBF_W(ids, ID, kw->num);
13188 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13189 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13190 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13191 }
13192 else {
13193 return 0;
13194 }
13195}
13196
13197static const struct rb_iseq_param_keyword *
13198ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13199{
13200 if (param_keyword_offset) {
13201 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13202 int dv_num = kw->num - kw->required_num;
13203 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13204
13205 int i;
13206 for (i=0; i<dv_num; i++) {
13207 dvs[i] = ibf_load_object(load, dvs[i]);
13208 }
13209
13210 // Will be set once the local table is loaded.
13211 kw->table = NULL;
13212
13213 kw->default_values = dvs;
13214 return kw;
13215 }
13216 else {
13217 return NULL;
13218 }
13219}
13220
13221static ibf_offset_t
13222ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13223{
13224 ibf_offset_t offset = ibf_dump_pos(dump);
13225 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13226
13227 unsigned int i;
13228 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13229 ibf_dump_write_small_value(dump, entries[i].line_no);
13230#ifdef USE_ISEQ_NODE_ID
13231 ibf_dump_write_small_value(dump, entries[i].node_id);
13232#endif
13233 ibf_dump_write_small_value(dump, entries[i].events);
13234 }
13235
13236 return offset;
13237}
13238
13239static struct iseq_insn_info_entry *
13240ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13241{
13242 ibf_offset_t reading_pos = body_offset;
13243 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13244
13245 unsigned int i;
13246 for (i = 0; i < size; i++) {
13247 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13248#ifdef USE_ISEQ_NODE_ID
13249 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13250#endif
13251 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13252 }
13253
13254 return entries;
13255}
13256
13257static ibf_offset_t
13258ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13259{
13260 ibf_offset_t offset = ibf_dump_pos(dump);
13261
13262 unsigned int last = 0;
13263 unsigned int i;
13264 for (i = 0; i < size; i++) {
13265 ibf_dump_write_small_value(dump, positions[i] - last);
13266 last = positions[i];
13267 }
13268
13269 return offset;
13270}
13271
13272static unsigned int *
13273ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13274{
13275 ibf_offset_t reading_pos = positions_offset;
13276 unsigned int *positions = ALLOC_N(unsigned int, size);
13277
13278 unsigned int last = 0;
13279 unsigned int i;
13280 for (i = 0; i < size; i++) {
13281 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13282 last = positions[i];
13283 }
13284
13285 return positions;
13286}
13287
13288static ibf_offset_t
13289ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13290{
13291 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13292 const int size = body->local_table_size;
13293 ID *table = ALLOCA_N(ID, size);
13294 int i;
13295
13296 for (i=0; i<size; i++) {
13297 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13298 if (v == 0) {
13299 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13300 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13301 }
13302 table[i] = v;
13303 }
13304
13305 IBF_W_ALIGN(ID);
13306 return ibf_dump_write(dump, table, sizeof(ID) * size);
13307}
13308
13309static const ID *
13310ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13311{
13312 if (size > 0) {
13313 ID *table = IBF_R(local_table_offset, ID, size);
13314 int i;
13315
13316 for (i=0; i<size; i++) {
13317 table[i] = ibf_load_id(load, table[i]);
13318 }
13319
13320 if (size == 1 && table[0] == idERROR_INFO) {
13321 xfree(table);
13322 return rb_iseq_shared_exc_local_tbl;
13323 }
13324 else {
13325 return table;
13326 }
13327 }
13328 else {
13329 return NULL;
13330 }
13331}
13332
13333static ibf_offset_t
13334ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13335{
13336 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13337 const int size = body->local_table_size;
13338 IBF_W_ALIGN(enum lvar_state);
13339 return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
13340}
13341
13342static enum lvar_state *
13343ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13344{
13345 if (local_table == rb_iseq_shared_exc_local_tbl ||
13346 size <= 0) {
13347 return NULL;
13348 }
13349 else {
13350 enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
13351 return states;
13352 }
13353}
13354
13355static ibf_offset_t
13356ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13357{
13358 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13359
13360 if (table) {
13361 int *iseq_indices = ALLOCA_N(int, table->size);
13362 unsigned int i;
13363
13364 for (i=0; i<table->size; i++) {
13365 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13366 }
13367
13368 const ibf_offset_t offset = ibf_dump_pos(dump);
13369
13370 for (i=0; i<table->size; i++) {
13371 ibf_dump_write_small_value(dump, iseq_indices[i]);
13372 ibf_dump_write_small_value(dump, table->entries[i].type);
13373 ibf_dump_write_small_value(dump, table->entries[i].start);
13374 ibf_dump_write_small_value(dump, table->entries[i].end);
13375 ibf_dump_write_small_value(dump, table->entries[i].cont);
13376 ibf_dump_write_small_value(dump, table->entries[i].sp);
13377 }
13378 return offset;
13379 }
13380 else {
13381 return ibf_dump_pos(dump);
13382 }
13383}
13384
13385static void
13386ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13387{
13388 if (size) {
13389 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13390 table->size = size;
13391 ISEQ_BODY(parent_iseq)->catch_table = table;
13392
13393 ibf_offset_t reading_pos = catch_table_offset;
13394
13395 unsigned int i;
13396 for (i=0; i<table->size; i++) {
13397 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13398 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13399 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13400 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13401 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13402 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13403
13404 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13405 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13406 }
13407 }
13408 else {
13409 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13410 }
13411}
13412
13413static ibf_offset_t
13414ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13415{
13416 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13417 const unsigned int ci_size = body->ci_size;
13418 const struct rb_call_data *cds = body->call_data;
13419
13420 ibf_offset_t offset = ibf_dump_pos(dump);
13421
13422 unsigned int i;
13423
13424 for (i = 0; i < ci_size; i++) {
13425 const struct rb_callinfo *ci = cds[i].ci;
13426 if (ci != NULL) {
13427 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13428 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13429 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13430
13431 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13432 if (kwarg) {
13433 int len = kwarg->keyword_len;
13434 ibf_dump_write_small_value(dump, len);
13435 for (int j=0; j<len; j++) {
13436 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13437 ibf_dump_write_small_value(dump, keyword);
13438 }
13439 }
13440 else {
13441 ibf_dump_write_small_value(dump, 0);
13442 }
13443 }
13444 else {
13445 // TODO: truncate NULL ci from call_data.
13446 ibf_dump_write_small_value(dump, (VALUE)-1);
13447 }
13448 }
13449
13450 return offset;
13451}
13452
13454 ID id;
13455 VALUE name;
13456 VALUE val;
13457};
13458
13460 size_t num;
13461 struct outer_variable_pair pairs[1];
13462};
13463
13464static enum rb_id_table_iterator_result
13465store_outer_variable(ID id, VALUE val, void *dump)
13466{
13467 struct outer_variable_list *ovlist = dump;
13468 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13469 pair->id = id;
13470 pair->name = rb_id2str(id);
13471 pair->val = val;
13472 return ID_TABLE_CONTINUE;
13473}
13474
13475static int
13476outer_variable_cmp(const void *a, const void *b, void *arg)
13477{
13478 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13479 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13480
13481 if (!ap->name) {
13482 return -1;
13483 }
13484 else if (!bp->name) {
13485 return 1;
13486 }
13487
13488 return rb_str_cmp(ap->name, bp->name);
13489}
13490
13491static ibf_offset_t
13492ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13493{
13494 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13495
13496 ibf_offset_t offset = ibf_dump_pos(dump);
13497
13498 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13499 ibf_dump_write_small_value(dump, (VALUE)size);
13500 if (size > 0) {
13501 VALUE buff;
13502 size_t buffsize =
13503 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13504 offsetof(struct outer_variable_list, pairs),
13505 rb_eArgError);
13506 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13507 ovlist->num = 0;
13508 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13509 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13510 for (size_t i = 0; i < size; ++i) {
13511 ID id = ovlist->pairs[i].id;
13512 ID val = ovlist->pairs[i].val;
13513 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13514 ibf_dump_write_small_value(dump, val);
13515 }
13516 }
13517
13518 return offset;
13519}
13520
13521/* note that we dump out rb_call_info but load back rb_call_data */
13522static void
13523ibf_load_ci_entries(const struct ibf_load *load,
13524 ibf_offset_t ci_entries_offset,
13525 unsigned int ci_size,
13526 struct rb_call_data **cd_ptr)
13527{
13528 if (!ci_size) {
13529 *cd_ptr = NULL;
13530 return;
13531 }
13532
13533 ibf_offset_t reading_pos = ci_entries_offset;
13534
13535 unsigned int i;
13536
13537 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13538 *cd_ptr = cds;
13539
13540 for (i = 0; i < ci_size; i++) {
13541 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13542 if (mid_index != (VALUE)-1) {
13543 ID mid = ibf_load_id(load, mid_index);
13544 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13545 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13546
13547 struct rb_callinfo_kwarg *kwarg = NULL;
13548 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13549 if (kwlen > 0) {
13550 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13551 kwarg->references = 0;
13552 kwarg->keyword_len = kwlen;
13553 for (int j=0; j<kwlen; j++) {
13554 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13555 kwarg->keywords[j] = ibf_load_object(load, keyword);
13556 }
13557 }
13558
13559 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13560 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13561 cds[i].cc = vm_cc_empty();
13562 }
13563 else {
13564 // NULL ci
13565 cds[i].ci = NULL;
13566 cds[i].cc = NULL;
13567 }
13568 }
13569}
13570
13571static struct rb_id_table *
13572ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13573{
13574 ibf_offset_t reading_pos = outer_variables_offset;
13575
13576 struct rb_id_table *tbl = NULL;
13577
13578 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13579
13580 if (table_size > 0) {
13581 tbl = rb_id_table_create(table_size);
13582 }
13583
13584 for (size_t i = 0; i < table_size; i++) {
13585 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13586 VALUE value = ibf_load_small_value(load, &reading_pos);
13587 if (!key) key = rb_make_temporary_id(i);
13588 rb_id_table_insert(tbl, key, value);
13589 }
13590
13591 return tbl;
13592}
13593
13594static ibf_offset_t
13595ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13596{
13597 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13598
13599 unsigned int *positions;
13600
13601 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13602
13603 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13604 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13605 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13606
13607#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13608 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13609
13610 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13611 struct ibf_dump_buffer buffer;
13612 buffer.str = rb_str_new(0, 0);
13613 buffer.obj_table = ibf_dump_object_table_new();
13614 dump->current_buffer = &buffer;
13615#endif
13616
13617 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13618 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13619 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13620 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13621 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13622
13623 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13624 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13625 ruby_xfree(positions);
13626
13627 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13628 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13629 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13630 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13631 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13632 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13633 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13634 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13635 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13636
13637#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13638 ibf_offset_t local_obj_list_offset;
13639 unsigned int local_obj_list_size;
13640
13641 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13642#endif
13643
13644 ibf_offset_t body_offset = ibf_dump_pos(dump);
13645
13646 /* dump the constant body */
13647 unsigned int param_flags =
13648 (body->param.flags.has_lead << 0) |
13649 (body->param.flags.has_opt << 1) |
13650 (body->param.flags.has_rest << 2) |
13651 (body->param.flags.has_post << 3) |
13652 (body->param.flags.has_kw << 4) |
13653 (body->param.flags.has_kwrest << 5) |
13654 (body->param.flags.has_block << 6) |
13655 (body->param.flags.ambiguous_param0 << 7) |
13656 (body->param.flags.accepts_no_kwarg << 8) |
13657 (body->param.flags.ruby2_keywords << 9) |
13658 (body->param.flags.anon_rest << 10) |
13659 (body->param.flags.anon_kwrest << 11) |
13660 (body->param.flags.use_block << 12) |
13661 (body->param.flags.forwardable << 13) ;
13662
13663#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13664# define IBF_BODY_OFFSET(x) (x)
13665#else
13666# define IBF_BODY_OFFSET(x) (body_offset - (x))
13667#endif
13668
13669 ibf_dump_write_small_value(dump, body->type);
13670 ibf_dump_write_small_value(dump, body->iseq_size);
13671 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13672 ibf_dump_write_small_value(dump, bytecode_size);
13673 ibf_dump_write_small_value(dump, param_flags);
13674 ibf_dump_write_small_value(dump, body->param.size);
13675 ibf_dump_write_small_value(dump, body->param.lead_num);
13676 ibf_dump_write_small_value(dump, body->param.opt_num);
13677 ibf_dump_write_small_value(dump, body->param.rest_start);
13678 ibf_dump_write_small_value(dump, body->param.post_start);
13679 ibf_dump_write_small_value(dump, body->param.post_num);
13680 ibf_dump_write_small_value(dump, body->param.block_start);
13681 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13682 ibf_dump_write_small_value(dump, param_keyword_offset);
13683 ibf_dump_write_small_value(dump, location_pathobj_index);
13684 ibf_dump_write_small_value(dump, location_base_label_index);
13685 ibf_dump_write_small_value(dump, location_label_index);
13686 ibf_dump_write_small_value(dump, body->location.first_lineno);
13687 ibf_dump_write_small_value(dump, body->location.node_id);
13688 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13689 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13690 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13691 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13692 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13693 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13694 ibf_dump_write_small_value(dump, body->insns_info.size);
13695 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13696 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13697 ibf_dump_write_small_value(dump, catch_table_size);
13698 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13699 ibf_dump_write_small_value(dump, parent_iseq_index);
13700 ibf_dump_write_small_value(dump, local_iseq_index);
13701 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13702 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13703 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13704 ibf_dump_write_small_value(dump, body->variable.flip_count);
13705 ibf_dump_write_small_value(dump, body->local_table_size);
13706 ibf_dump_write_small_value(dump, body->ivc_size);
13707 ibf_dump_write_small_value(dump, body->icvarc_size);
13708 ibf_dump_write_small_value(dump, body->ise_size);
13709 ibf_dump_write_small_value(dump, body->ic_size);
13710 ibf_dump_write_small_value(dump, body->ci_size);
13711 ibf_dump_write_small_value(dump, body->stack_max);
13712 ibf_dump_write_small_value(dump, body->builtin_attrs);
13713 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13714
13715#undef IBF_BODY_OFFSET
13716
13717#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13718 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13719
13720 dump->current_buffer = saved_buffer;
13721 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13722
13723 ibf_offset_t offset = ibf_dump_pos(dump);
13724 ibf_dump_write_small_value(dump, iseq_start);
13725 ibf_dump_write_small_value(dump, iseq_length_bytes);
13726 ibf_dump_write_small_value(dump, body_offset);
13727
13728 ibf_dump_write_small_value(dump, local_obj_list_offset);
13729 ibf_dump_write_small_value(dump, local_obj_list_size);
13730
13731 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13732
13733 return offset;
13734#else
13735 return body_offset;
13736#endif
13737}
13738
13739static VALUE
13740ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13741{
13742 VALUE str = ibf_load_object(load, str_index);
13743 if (str != Qnil) {
13744 str = rb_fstring(str);
13745 }
13746 return str;
13747}
13748
13749static void
13750ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13751{
13752 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13753
13754 ibf_offset_t reading_pos = offset;
13755
13756#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13757 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13758 load->current_buffer = &load->global_buffer;
13759
13760 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13761 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13762 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13763
13764 struct ibf_load_buffer buffer;
13765 buffer.buff = load->global_buffer.buff + iseq_start;
13766 buffer.size = iseq_length_bytes;
13767 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13768 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13769 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13770
13771 load->current_buffer = &buffer;
13772 reading_pos = body_offset;
13773#endif
13774
13775#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13776# define IBF_BODY_OFFSET(x) (x)
13777#else
13778# define IBF_BODY_OFFSET(x) (offset - (x))
13779#endif
13780
13781 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13782 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13783 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13784 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13785 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13786 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13787 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13788 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13789 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13790 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13791 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13792 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13793 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13794 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13795 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13796 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13797 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13798 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13799 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13800 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13801 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13802 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13803 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13804 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13805 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13806 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13807 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13808 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13809 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13810 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13811 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13812 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13813 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13814 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13815 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13816 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13817 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13818
13819 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13820 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13821 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13822 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13823
13824 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13825 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13826 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13827 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13828
13829 // setup fname and dummy frame
13830 VALUE path = ibf_load_object(load, location_pathobj_index);
13831 {
13832 VALUE realpath = Qnil;
13833
13834 if (RB_TYPE_P(path, T_STRING)) {
13835 realpath = path = rb_fstring(path);
13836 }
13837 else if (RB_TYPE_P(path, T_ARRAY)) {
13838 VALUE pathobj = path;
13839 if (RARRAY_LEN(pathobj) != 2) {
13840 rb_raise(rb_eRuntimeError, "path object size mismatch");
13841 }
13842 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13843 realpath = RARRAY_AREF(pathobj, 1);
13844 if (!NIL_P(realpath)) {
13845 if (!RB_TYPE_P(realpath, T_STRING)) {
13846 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13847 "(%x), path=%+"PRIsVALUE,
13848 realpath, TYPE(realpath), path);
13849 }
13850 realpath = rb_fstring(realpath);
13851 }
13852 }
13853 else {
13854 rb_raise(rb_eRuntimeError, "unexpected path object");
13855 }
13856 rb_iseq_pathobj_set(iseq, path, realpath);
13857 }
13858
13859 // push dummy frame
13860 rb_execution_context_t *ec = GET_EC();
13861 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13862
13863#undef IBF_BODY_OFFSET
13864
13865 load_body->type = type;
13866 load_body->stack_max = stack_max;
13867 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13868 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13869 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13870 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13871 load_body->param.flags.has_kw = FALSE;
13872 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13873 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13874 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13875 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13876 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13877 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13878 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13879 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13880 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13881 load_body->param.size = param_size;
13882 load_body->param.lead_num = param_lead_num;
13883 load_body->param.opt_num = param_opt_num;
13884 load_body->param.rest_start = param_rest_start;
13885 load_body->param.post_start = param_post_start;
13886 load_body->param.post_num = param_post_num;
13887 load_body->param.block_start = param_block_start;
13888 load_body->local_table_size = local_table_size;
13889 load_body->ci_size = ci_size;
13890 load_body->insns_info.size = insns_info_size;
13891
13892 ISEQ_COVERAGE_SET(iseq, Qnil);
13893 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13894 load_body->variable.flip_count = variable_flip_count;
13895 load_body->variable.script_lines = Qnil;
13896
13897 load_body->location.first_lineno = location_first_lineno;
13898 load_body->location.node_id = location_node_id;
13899 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13900 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13901 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13902 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13903 load_body->builtin_attrs = builtin_attrs;
13904 load_body->prism = prism;
13905
13906 load_body->ivc_size = ivc_size;
13907 load_body->icvarc_size = icvarc_size;
13908 load_body->ise_size = ise_size;
13909 load_body->ic_size = ic_size;
13910
13911 if (ISEQ_IS_SIZE(load_body)) {
13912 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13913 }
13914 else {
13915 load_body->is_entries = NULL;
13916 }
13917 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13918 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13919 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13920 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13921 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13922 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13923 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13924 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13925 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13926 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13927
13928 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13929 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13930 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13931
13932 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13933 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13934 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13935
13936 // This must be done after the local table is loaded.
13937 if (load_body->param.keyword != NULL) {
13938 RUBY_ASSERT(load_body->local_table);
13939 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13940 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13941 }
13942
13943 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13944#if VM_INSN_INFO_TABLE_IMPL == 2
13945 rb_iseq_insns_info_encode_positions(iseq);
13946#endif
13947
13948 rb_iseq_translate_threaded_code(iseq);
13949
13950#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13951 load->current_buffer = &load->global_buffer;
13952#endif
13953
13954 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13955 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13956
13957#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13958 load->current_buffer = saved_buffer;
13959#endif
13960 verify_call_cache(iseq);
13961
13962 RB_GC_GUARD(dummy_frame);
13963 rb_vm_pop_frame_no_int(ec);
13964}
13965
13967{
13968 struct ibf_dump *dump;
13969 VALUE offset_list;
13970};
13971
13972static int
13973ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13974{
13975 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13976 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13977
13978 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13979 rb_ary_push(args->offset_list, UINT2NUM(offset));
13980
13981 return ST_CONTINUE;
13982}
13983
13984static void
13985ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13986{
13987 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13988
13989 struct ibf_dump_iseq_list_arg args;
13990 args.dump = dump;
13991 args.offset_list = offset_list;
13992
13993 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13994
13995 st_index_t i;
13996 st_index_t size = dump->iseq_table->num_entries;
13997 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13998
13999 for (i = 0; i < size; i++) {
14000 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14001 }
14002
14003 ibf_dump_align(dump, sizeof(ibf_offset_t));
14004 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14005 header->iseq_list_size = (unsigned int)size;
14006}
14007
14008#define IBF_OBJECT_INTERNAL FL_PROMOTED0
14009
14010/*
14011 * Binary format
14012 * - ibf_object_header
14013 * - ibf_object_xxx (xxx is type)
14014 */
14015
14017 unsigned int type: 5;
14018 unsigned int special_const: 1;
14019 unsigned int frozen: 1;
14020 unsigned int internal: 1;
14021};
14022
14023enum ibf_object_class_index {
14024 IBF_OBJECT_CLASS_OBJECT,
14025 IBF_OBJECT_CLASS_ARRAY,
14026 IBF_OBJECT_CLASS_STANDARD_ERROR,
14027 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14028 IBF_OBJECT_CLASS_TYPE_ERROR,
14029 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14030};
14031
14033 long srcstr;
14034 char option;
14035};
14036
14038 long len;
14039 long keyval[FLEX_ARY_LEN];
14040};
14041
14043 long class_index;
14044 long len;
14045 long beg;
14046 long end;
14047 int excl;
14048};
14049
14051 ssize_t slen;
14052 BDIGIT digits[FLEX_ARY_LEN];
14053};
14054
14055enum ibf_object_data_type {
14056 IBF_OBJECT_DATA_ENCODING,
14057};
14058
14060 long a, b;
14061};
14062
14064 long str;
14065};
14066
14067#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14068 ((((offset) - 1) / (align) + 1) * (align))
14069/* No cast, since it's UB to create an unaligned pointer.
14070 * Leave as void* for use with memcpy in those cases.
14071 * We align the offset, but the buffer pointer is only VALUE aligned,
14072 * so the returned pointer may be unaligned for `type` .*/
14073#define IBF_OBJBODY(type, offset) \
14074 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14075
14076static const void *
14077ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14078{
14079 if (offset >= load->current_buffer->size) {
14080 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14081 }
14082 return load->current_buffer->buff + offset;
14083}
14084
14085NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14086
14087static void
14088ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14089{
14090 char buff[0x100];
14091 rb_raw_obj_info(buff, sizeof(buff), obj);
14092 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14093}
14094
14095NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14096
14097static VALUE
14098ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14099{
14100 rb_raise(rb_eArgError, "unsupported");
14102}
14103
14104static void
14105ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14106{
14107 enum ibf_object_class_index cindex;
14108 if (obj == rb_cObject) {
14109 cindex = IBF_OBJECT_CLASS_OBJECT;
14110 }
14111 else if (obj == rb_cArray) {
14112 cindex = IBF_OBJECT_CLASS_ARRAY;
14113 }
14114 else if (obj == rb_eStandardError) {
14115 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14116 }
14117 else if (obj == rb_eNoMatchingPatternError) {
14118 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14119 }
14120 else if (obj == rb_eTypeError) {
14121 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14122 }
14123 else if (obj == rb_eNoMatchingPatternKeyError) {
14124 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14125 }
14126 else {
14127 rb_obj_info_dump(obj);
14128 rb_p(obj);
14129 rb_bug("unsupported class");
14130 }
14131 ibf_dump_write_small_value(dump, (VALUE)cindex);
14132}
14133
14134static VALUE
14135ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14136{
14137 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14138
14139 switch (cindex) {
14140 case IBF_OBJECT_CLASS_OBJECT:
14141 return rb_cObject;
14142 case IBF_OBJECT_CLASS_ARRAY:
14143 return rb_cArray;
14144 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14145 return rb_eStandardError;
14146 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14148 case IBF_OBJECT_CLASS_TYPE_ERROR:
14149 return rb_eTypeError;
14150 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14152 }
14153
14154 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14155}
14156
14157
14158static void
14159ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14160{
14161 double dbl = RFLOAT_VALUE(obj);
14162 (void)IBF_W(&dbl, double, 1);
14163}
14164
14165static VALUE
14166ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14167{
14168 double d;
14169 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14170 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14171 VALUE f = DBL2NUM(d);
14172 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14173 return f;
14174}
14175
14176static void
14177ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14178{
14179 long encindex = (long)rb_enc_get_index(obj);
14180 long len = RSTRING_LEN(obj);
14181 const char *ptr = RSTRING_PTR(obj);
14182
14183 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14184 rb_encoding *enc = rb_enc_from_index((int)encindex);
14185 const char *enc_name = rb_enc_name(enc);
14186 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14187 }
14188
14189 ibf_dump_write_small_value(dump, encindex);
14190 ibf_dump_write_small_value(dump, len);
14191 IBF_WP(ptr, char, len);
14192}
14193
14194static VALUE
14195ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14196{
14197 ibf_offset_t reading_pos = offset;
14198
14199 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14200 const long len = (long)ibf_load_small_value(load, &reading_pos);
14201 const char *ptr = load->current_buffer->buff + reading_pos;
14202
14203 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14204 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14205 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14206 }
14207
14208 VALUE str;
14209 if (header->frozen && !header->internal) {
14210 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14211 }
14212 else {
14213 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14214
14215 if (header->internal) rb_obj_hide(str);
14216 if (header->frozen) str = rb_fstring(str);
14217 }
14218 return str;
14219}
14220
14221static void
14222ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14223{
14224 VALUE srcstr = RREGEXP_SRC(obj);
14225 struct ibf_object_regexp regexp;
14226 regexp.option = (char)rb_reg_options(obj);
14227 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14228
14229 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14230 ibf_dump_write_small_value(dump, regexp.srcstr);
14231}
14232
14233static VALUE
14234ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14235{
14236 struct ibf_object_regexp regexp;
14237 regexp.option = ibf_load_byte(load, &offset);
14238 regexp.srcstr = ibf_load_small_value(load, &offset);
14239
14240 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14241 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14242
14243 if (header->internal) rb_obj_hide(reg);
14244 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14245
14246 return reg;
14247}
14248
14249static void
14250ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14251{
14252 long i, len = RARRAY_LEN(obj);
14253 ibf_dump_write_small_value(dump, len);
14254 for (i=0; i<len; i++) {
14255 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14256 ibf_dump_write_small_value(dump, index);
14257 }
14258}
14259
14260static VALUE
14261ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14262{
14263 ibf_offset_t reading_pos = offset;
14264
14265 const long len = (long)ibf_load_small_value(load, &reading_pos);
14266
14267 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14268 int i;
14269
14270 for (i=0; i<len; i++) {
14271 const VALUE index = ibf_load_small_value(load, &reading_pos);
14272 rb_ary_push(ary, ibf_load_object(load, index));
14273 }
14274
14275 if (header->frozen) {
14276 rb_ary_freeze(ary);
14277 rb_ractor_make_shareable(ary); // TODO: check elements
14278 }
14279
14280 return ary;
14281}
14282
14283static int
14284ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14285{
14286 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14287
14288 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14289 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14290
14291 ibf_dump_write_small_value(dump, key_index);
14292 ibf_dump_write_small_value(dump, val_index);
14293 return ST_CONTINUE;
14294}
14295
14296static void
14297ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14298{
14299 long len = RHASH_SIZE(obj);
14300 ibf_dump_write_small_value(dump, (VALUE)len);
14301
14302 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14303}
14304
14305static VALUE
14306ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14307{
14308 long len = (long)ibf_load_small_value(load, &offset);
14309 VALUE obj = rb_hash_new_with_size(len);
14310 int i;
14311
14312 for (i = 0; i < len; i++) {
14313 VALUE key_index = ibf_load_small_value(load, &offset);
14314 VALUE val_index = ibf_load_small_value(load, &offset);
14315
14316 VALUE key = ibf_load_object(load, key_index);
14317 VALUE val = ibf_load_object(load, val_index);
14318 rb_hash_aset(obj, key, val);
14319 }
14320 rb_hash_rehash(obj);
14321
14322 if (header->internal) rb_obj_hide(obj);
14323 if (header->frozen) {
14324 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14325 }
14326
14327 return obj;
14328}
14329
14330static void
14331ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14332{
14333 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14334 struct ibf_object_struct_range range;
14335 VALUE beg, end;
14336 IBF_ZERO(range);
14337 range.len = 3;
14338 range.class_index = 0;
14339
14340 rb_range_values(obj, &beg, &end, &range.excl);
14341 range.beg = (long)ibf_dump_object(dump, beg);
14342 range.end = (long)ibf_dump_object(dump, end);
14343
14344 IBF_W_ALIGN(struct ibf_object_struct_range);
14345 IBF_WV(range);
14346 }
14347 else {
14348 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14349 rb_class_name(CLASS_OF(obj)));
14350 }
14351}
14352
14353static VALUE
14354ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14355{
14356 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14357 VALUE beg = ibf_load_object(load, range->beg);
14358 VALUE end = ibf_load_object(load, range->end);
14359 VALUE obj = rb_range_new(beg, end, range->excl);
14360 if (header->internal) rb_obj_hide(obj);
14361 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14362 return obj;
14363}
14364
14365static void
14366ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14367{
14368 ssize_t len = BIGNUM_LEN(obj);
14369 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14370 BDIGIT *d = BIGNUM_DIGITS(obj);
14371
14372 (void)IBF_W(&slen, ssize_t, 1);
14373 IBF_WP(d, BDIGIT, len);
14374}
14375
14376static VALUE
14377ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14378{
14379 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14380 int sign = bignum->slen > 0;
14381 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14382 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14385 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14386 big_unpack_flags |
14387 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14388 if (header->internal) rb_obj_hide(obj);
14389 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14390 return obj;
14391}
14392
14393static void
14394ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14395{
14396 if (rb_data_is_encoding(obj)) {
14397 rb_encoding *enc = rb_to_encoding(obj);
14398 const char *name = rb_enc_name(enc);
14399 long len = strlen(name) + 1;
14400 long data[2];
14401 data[0] = IBF_OBJECT_DATA_ENCODING;
14402 data[1] = len;
14403 (void)IBF_W(data, long, 2);
14404 IBF_WP(name, char, len);
14405 }
14406 else {
14407 ibf_dump_object_unsupported(dump, obj);
14408 }
14409}
14410
14411static VALUE
14412ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14413{
14414 const long *body = IBF_OBJBODY(long, offset);
14415 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14416 /* const long len = body[1]; */
14417 const char *data = (const char *)&body[2];
14418
14419 switch (type) {
14420 case IBF_OBJECT_DATA_ENCODING:
14421 {
14422 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14423 return encobj;
14424 }
14425 }
14426
14427 return ibf_load_object_unsupported(load, header, offset);
14428}
14429
14430static void
14431ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14432{
14433 long data[2];
14434 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14435 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14436
14437 (void)IBF_W(data, long, 2);
14438}
14439
14440static VALUE
14441ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14442{
14443 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14444 VALUE a = ibf_load_object(load, nums->a);
14445 VALUE b = ibf_load_object(load, nums->b);
14446 VALUE obj = header->type == T_COMPLEX ?
14447 rb_complex_new(a, b) : rb_rational_new(a, b);
14448
14449 if (header->internal) rb_obj_hide(obj);
14450 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14451 return obj;
14452}
14453
14454static void
14455ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14456{
14457 ibf_dump_object_string(dump, rb_sym2str(obj));
14458}
14459
14460static VALUE
14461ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14462{
14463 ibf_offset_t reading_pos = offset;
14464
14465 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14466 const long len = (long)ibf_load_small_value(load, &reading_pos);
14467 const char *ptr = load->current_buffer->buff + reading_pos;
14468
14469 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14470 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14471 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14472 }
14473
14474 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14475 return ID2SYM(id);
14476}
14477
14478typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14479static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14480 ibf_dump_object_unsupported, /* T_NONE */
14481 ibf_dump_object_unsupported, /* T_OBJECT */
14482 ibf_dump_object_class, /* T_CLASS */
14483 ibf_dump_object_unsupported, /* T_MODULE */
14484 ibf_dump_object_float, /* T_FLOAT */
14485 ibf_dump_object_string, /* T_STRING */
14486 ibf_dump_object_regexp, /* T_REGEXP */
14487 ibf_dump_object_array, /* T_ARRAY */
14488 ibf_dump_object_hash, /* T_HASH */
14489 ibf_dump_object_struct, /* T_STRUCT */
14490 ibf_dump_object_bignum, /* T_BIGNUM */
14491 ibf_dump_object_unsupported, /* T_FILE */
14492 ibf_dump_object_data, /* T_DATA */
14493 ibf_dump_object_unsupported, /* T_MATCH */
14494 ibf_dump_object_complex_rational, /* T_COMPLEX */
14495 ibf_dump_object_complex_rational, /* T_RATIONAL */
14496 ibf_dump_object_unsupported, /* 0x10 */
14497 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14498 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14499 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14500 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14501 ibf_dump_object_unsupported, /* T_FIXNUM */
14502 ibf_dump_object_unsupported, /* T_UNDEF */
14503 ibf_dump_object_unsupported, /* 0x17 */
14504 ibf_dump_object_unsupported, /* 0x18 */
14505 ibf_dump_object_unsupported, /* 0x19 */
14506 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14507 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14508 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14509 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14510 ibf_dump_object_unsupported, /* 0x1e */
14511 ibf_dump_object_unsupported, /* 0x1f */
14512};
14513
14514static void
14515ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14516{
14517 unsigned char byte =
14518 (header.type << 0) |
14519 (header.special_const << 5) |
14520 (header.frozen << 6) |
14521 (header.internal << 7);
14522
14523 IBF_WV(byte);
14524}
14525
14526static struct ibf_object_header
14527ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14528{
14529 unsigned char byte = ibf_load_byte(load, offset);
14530
14531 struct ibf_object_header header;
14532 header.type = (byte >> 0) & 0x1f;
14533 header.special_const = (byte >> 5) & 0x01;
14534 header.frozen = (byte >> 6) & 0x01;
14535 header.internal = (byte >> 7) & 0x01;
14536
14537 return header;
14538}
14539
14540static ibf_offset_t
14541ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14542{
14543 struct ibf_object_header obj_header;
14544 ibf_offset_t current_offset;
14545 IBF_ZERO(obj_header);
14546 obj_header.type = TYPE(obj);
14547
14548 IBF_W_ALIGN(ibf_offset_t);
14549 current_offset = ibf_dump_pos(dump);
14550
14551 if (SPECIAL_CONST_P(obj) &&
14552 ! (SYMBOL_P(obj) ||
14553 RB_FLOAT_TYPE_P(obj))) {
14554 obj_header.special_const = TRUE;
14555 obj_header.frozen = TRUE;
14556 obj_header.internal = TRUE;
14557 ibf_dump_object_object_header(dump, obj_header);
14558 ibf_dump_write_small_value(dump, obj);
14559 }
14560 else {
14561 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14562 obj_header.special_const = FALSE;
14563 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14564 ibf_dump_object_object_header(dump, obj_header);
14565 (*dump_object_functions[obj_header.type])(dump, obj);
14566 }
14567
14568 return current_offset;
14569}
14570
14571typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14572static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14573 ibf_load_object_unsupported, /* T_NONE */
14574 ibf_load_object_unsupported, /* T_OBJECT */
14575 ibf_load_object_class, /* T_CLASS */
14576 ibf_load_object_unsupported, /* T_MODULE */
14577 ibf_load_object_float, /* T_FLOAT */
14578 ibf_load_object_string, /* T_STRING */
14579 ibf_load_object_regexp, /* T_REGEXP */
14580 ibf_load_object_array, /* T_ARRAY */
14581 ibf_load_object_hash, /* T_HASH */
14582 ibf_load_object_struct, /* T_STRUCT */
14583 ibf_load_object_bignum, /* T_BIGNUM */
14584 ibf_load_object_unsupported, /* T_FILE */
14585 ibf_load_object_data, /* T_DATA */
14586 ibf_load_object_unsupported, /* T_MATCH */
14587 ibf_load_object_complex_rational, /* T_COMPLEX */
14588 ibf_load_object_complex_rational, /* T_RATIONAL */
14589 ibf_load_object_unsupported, /* 0x10 */
14590 ibf_load_object_unsupported, /* T_NIL */
14591 ibf_load_object_unsupported, /* T_TRUE */
14592 ibf_load_object_unsupported, /* T_FALSE */
14593 ibf_load_object_symbol,
14594 ibf_load_object_unsupported, /* T_FIXNUM */
14595 ibf_load_object_unsupported, /* T_UNDEF */
14596 ibf_load_object_unsupported, /* 0x17 */
14597 ibf_load_object_unsupported, /* 0x18 */
14598 ibf_load_object_unsupported, /* 0x19 */
14599 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14600 ibf_load_object_unsupported, /* T_NODE 0x1b */
14601 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14602 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14603 ibf_load_object_unsupported, /* 0x1e */
14604 ibf_load_object_unsupported, /* 0x1f */
14605};
14606
14607static VALUE
14608ibf_load_object(const struct ibf_load *load, VALUE object_index)
14609{
14610 if (object_index == 0) {
14611 return Qnil;
14612 }
14613 else {
14614 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14615 if (!obj) {
14616 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14617 ibf_offset_t offset = offsets[object_index];
14618 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14619
14620#if IBF_ISEQ_DEBUG
14621 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14622 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14623 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14624 header.type, header.special_const, header.frozen, header.internal);
14625#endif
14626 if (offset >= load->current_buffer->size) {
14627 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14628 }
14629
14630 if (header.special_const) {
14631 ibf_offset_t reading_pos = offset;
14632
14633 obj = ibf_load_small_value(load, &reading_pos);
14634 }
14635 else {
14636 obj = (*load_object_functions[header.type])(load, &header, offset);
14637 }
14638
14639 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14640 }
14641#if IBF_ISEQ_DEBUG
14642 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14643 object_index, obj);
14644#endif
14645 return obj;
14646 }
14647}
14648
14650{
14651 struct ibf_dump *dump;
14652 VALUE offset_list;
14653};
14654
14655static int
14656ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14657{
14658 VALUE obj = (VALUE)key;
14659 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14660
14661 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14662 rb_ary_push(args->offset_list, UINT2NUM(offset));
14663
14664 return ST_CONTINUE;
14665}
14666
14667static void
14668ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14669{
14670 st_table *obj_table = dump->current_buffer->obj_table;
14671 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14672
14673 struct ibf_dump_object_list_arg args;
14674 args.dump = dump;
14675 args.offset_list = offset_list;
14676
14677 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14678
14679 IBF_W_ALIGN(ibf_offset_t);
14680 *obj_list_offset = ibf_dump_pos(dump);
14681
14682 st_index_t size = obj_table->num_entries;
14683 st_index_t i;
14684
14685 for (i=0; i<size; i++) {
14686 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14687 IBF_WV(offset);
14688 }
14689
14690 *obj_list_size = (unsigned int)size;
14691}
14692
14693static void
14694ibf_dump_mark(void *ptr)
14695{
14696 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14697 rb_gc_mark(dump->global_buffer.str);
14698
14699 rb_mark_set(dump->global_buffer.obj_table);
14700 rb_mark_set(dump->iseq_table);
14701}
14702
14703static void
14704ibf_dump_free(void *ptr)
14705{
14706 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14707 if (dump->global_buffer.obj_table) {
14708 st_free_table(dump->global_buffer.obj_table);
14709 dump->global_buffer.obj_table = 0;
14710 }
14711 if (dump->iseq_table) {
14712 st_free_table(dump->iseq_table);
14713 dump->iseq_table = 0;
14714 }
14715}
14716
14717static size_t
14718ibf_dump_memsize(const void *ptr)
14719{
14720 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14721 size_t size = 0;
14722 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14723 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14724 return size;
14725}
14726
14727static const rb_data_type_t ibf_dump_type = {
14728 "ibf_dump",
14729 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14730 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14731};
14732
14733static void
14734ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14735{
14736 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14737 dump->iseq_table = NULL;
14738
14739 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14740 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14741 dump->iseq_table = st_init_numtable(); /* need free */
14742
14743 dump->current_buffer = &dump->global_buffer;
14744}
14745
14746VALUE
14747rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14748{
14749 struct ibf_dump *dump;
14750 struct ibf_header header = {{0}};
14751 VALUE dump_obj;
14752 VALUE str;
14753
14754 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14755 ISEQ_BODY(iseq)->local_iseq != iseq) {
14756 rb_raise(rb_eRuntimeError, "should be top of iseq");
14757 }
14758 if (RTEST(ISEQ_COVERAGE(iseq))) {
14759 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14760 }
14761
14762 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14763 ibf_dump_setup(dump, dump_obj);
14764
14765 ibf_dump_write(dump, &header, sizeof(header));
14766 ibf_dump_iseq(dump, iseq);
14767
14768 header.magic[0] = 'Y'; /* YARB */
14769 header.magic[1] = 'A';
14770 header.magic[2] = 'R';
14771 header.magic[3] = 'B';
14772 header.major_version = IBF_MAJOR_VERSION;
14773 header.minor_version = IBF_MINOR_VERSION;
14774 header.endian = IBF_ENDIAN_MARK;
14775 header.wordsize = (uint8_t)SIZEOF_VALUE;
14776 ibf_dump_iseq_list(dump, &header);
14777 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14778 header.size = ibf_dump_pos(dump);
14779
14780 if (RTEST(opt)) {
14781 VALUE opt_str = opt;
14782 const char *ptr = StringValuePtr(opt_str);
14783 header.extra_size = RSTRING_LENINT(opt_str);
14784 ibf_dump_write(dump, ptr, header.extra_size);
14785 }
14786 else {
14787 header.extra_size = 0;
14788 }
14789
14790 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14791
14792 str = dump->global_buffer.str;
14793 RB_GC_GUARD(dump_obj);
14794 return str;
14795}
14796
14797static const ibf_offset_t *
14798ibf_iseq_list(const struct ibf_load *load)
14799{
14800 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14801}
14802
14803void
14804rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14805{
14806 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14807 rb_iseq_t *prev_src_iseq = load->iseq;
14808 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14809 load->iseq = iseq;
14810#if IBF_ISEQ_DEBUG
14811 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14812 iseq->aux.loader.index, offset,
14813 load->header->size);
14814#endif
14815 ibf_load_iseq_each(load, iseq, offset);
14816 ISEQ_COMPILE_DATA_CLEAR(iseq);
14817 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14818 rb_iseq_init_trace(iseq);
14819 load->iseq = prev_src_iseq;
14820}
14821
14822#if USE_LAZY_LOAD
14823const rb_iseq_t *
14824rb_iseq_complete(const rb_iseq_t *iseq)
14825{
14826 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14827 return iseq;
14828}
14829#endif
14830
14831static rb_iseq_t *
14832ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14833{
14834 int iseq_index = (int)(VALUE)index_iseq;
14835
14836#if IBF_ISEQ_DEBUG
14837 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14838 (void *)index_iseq, (void *)load->iseq_list);
14839#endif
14840 if (iseq_index == -1) {
14841 return NULL;
14842 }
14843 else {
14844 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14845
14846#if IBF_ISEQ_DEBUG
14847 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14848#endif
14849 if (iseqv) {
14850 return (rb_iseq_t *)iseqv;
14851 }
14852 else {
14853 rb_iseq_t *iseq = iseq_imemo_alloc();
14854#if IBF_ISEQ_DEBUG
14855 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14856#endif
14857 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14858 iseq->aux.loader.obj = load->loader_obj;
14859 iseq->aux.loader.index = iseq_index;
14860#if IBF_ISEQ_DEBUG
14861 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14862 (void *)iseq, (void *)load->loader_obj, iseq_index);
14863#endif
14864 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14865
14866 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14867#if IBF_ISEQ_DEBUG
14868 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14869#endif
14870 rb_ibf_load_iseq_complete(iseq);
14871 }
14872
14873#if IBF_ISEQ_DEBUG
14874 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14875 (void *)iseq, (void *)load->iseq);
14876#endif
14877 return iseq;
14878 }
14879 }
14880}
14881
14882static void
14883ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14884{
14885 struct ibf_header *header = (struct ibf_header *)bytes;
14886 load->loader_obj = loader_obj;
14887 load->global_buffer.buff = bytes;
14888 load->header = header;
14889 load->global_buffer.size = header->size;
14890 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14891 load->global_buffer.obj_list_size = header->global_object_list_size;
14892 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14893 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14894 load->iseq = NULL;
14895
14896 load->current_buffer = &load->global_buffer;
14897
14898 if (size < header->size) {
14899 rb_raise(rb_eRuntimeError, "broken binary format");
14900 }
14901 if (strncmp(header->magic, "YARB", 4) != 0) {
14902 rb_raise(rb_eRuntimeError, "unknown binary format");
14903 }
14904 if (header->major_version != IBF_MAJOR_VERSION ||
14905 header->minor_version != IBF_MINOR_VERSION) {
14906 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14907 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14908 }
14909 if (header->endian != IBF_ENDIAN_MARK) {
14910 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14911 }
14912 if (header->wordsize != SIZEOF_VALUE) {
14913 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14914 }
14915 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14916 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14917 header->iseq_list_offset);
14918 }
14919 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14920 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14921 load->global_buffer.obj_list_offset);
14922 }
14923}
14924
14925static void
14926ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14927{
14928 StringValue(str);
14929
14930 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14931 rb_raise(rb_eRuntimeError, "broken binary format");
14932 }
14933
14934 if (USE_LAZY_LOAD) {
14935 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14936 }
14937
14938 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14939 RB_OBJ_WRITE(loader_obj, &load->str, str);
14940}
14941
14942static void
14943ibf_loader_mark(void *ptr)
14944{
14945 struct ibf_load *load = (struct ibf_load *)ptr;
14946 rb_gc_mark(load->str);
14947 rb_gc_mark(load->iseq_list);
14948 rb_gc_mark(load->global_buffer.obj_list);
14949}
14950
14951static void
14952ibf_loader_free(void *ptr)
14953{
14954 struct ibf_load *load = (struct ibf_load *)ptr;
14955 ruby_xfree(load);
14956}
14957
14958static size_t
14959ibf_loader_memsize(const void *ptr)
14960{
14961 return sizeof(struct ibf_load);
14962}
14963
14964static const rb_data_type_t ibf_load_type = {
14965 "ibf_loader",
14966 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14967 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14968};
14969
14970const rb_iseq_t *
14971rb_iseq_ibf_load(VALUE str)
14972{
14973 struct ibf_load *load;
14974 rb_iseq_t *iseq;
14975 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14976
14977 ibf_load_setup(load, loader_obj, str);
14978 iseq = ibf_load_iseq(load, 0);
14979
14980 RB_GC_GUARD(loader_obj);
14981 return iseq;
14982}
14983
14984const rb_iseq_t *
14985rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14986{
14987 struct ibf_load *load;
14988 rb_iseq_t *iseq;
14989 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14990
14991 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14992 iseq = ibf_load_iseq(load, 0);
14993
14994 RB_GC_GUARD(loader_obj);
14995 return iseq;
14996}
14997
14998VALUE
14999rb_iseq_ibf_load_extra_data(VALUE str)
15000{
15001 struct ibf_load *load;
15002 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15003 VALUE extra_str;
15004
15005 ibf_load_setup(load, loader_obj, str);
15006 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15007 RB_GC_GUARD(loader_obj);
15008 return extra_str;
15009}
15010
15011#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:696
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_cHash
Hash class.
Definition hash.c:109
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:687
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:910
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1329
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1839
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:69
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4223
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3791
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1740
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4154
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4140
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3559
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:3757
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4208
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:4028
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3272
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1513
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:974
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:993
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:943
int len
Length of the buffer.
Definition io.h:8
#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:1485
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:520
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:455
#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:502
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9074
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:286
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:257
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:209
struct rb_iseq_constant_body::@156 param
parameter information
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145