Ruby 4.0.0dev (2025-12-25 revision 6a66129d6c289b0da99cd89592f5ee948da6f381)
compile.c (6a66129d6c289b0da99cd89592f5ee948da6f381)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
498
499static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
500static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
501
502/*
503 * To make Array to LinkedList, use link_anchor
504 */
505
506static void
507verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
508{
509#if CPDEBUG
510 int flag = 0;
511 LINK_ELEMENT *list, *plist;
512
513 if (!compile_debug) return;
514
515 list = anchor->anchor.next;
516 plist = &anchor->anchor;
517 while (list) {
518 if (plist != list->prev) {
519 flag += 1;
520 }
521 plist = list;
522 list = list->next;
523 }
524
525 if (anchor->last != plist && anchor->last != 0) {
526 flag |= 0x70000;
527 }
528
529 if (flag != 0) {
530 rb_bug("list verify error: %08x (%s)", flag, info);
531 }
532#endif
533}
534#if CPDEBUG < 0
535#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
536#endif
537
538static void
539verify_call_cache(rb_iseq_t *iseq)
540{
541#if CPDEBUG
542 VALUE *original = rb_iseq_original_iseq(iseq);
543 size_t i = 0;
544 while (i < ISEQ_BODY(iseq)->iseq_size) {
545 VALUE insn = original[i];
546 const char *types = insn_op_types(insn);
547
548 for (int j=0; types[j]; j++) {
549 if (types[j] == TS_CALLDATA) {
550 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
551 const struct rb_callinfo *ci = cd->ci;
552 const struct rb_callcache *cc = cd->cc;
553 if (cc != vm_cc_empty()) {
554 vm_ci_dump(ci);
555 rb_bug("call cache is not initialized by vm_cc_empty()");
556 }
557 }
558 }
559 i += insn_len(insn);
560 }
561
562 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
563 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
564 const struct rb_callinfo *ci = cd->ci;
565 const struct rb_callcache *cc = cd->cc;
566 if (cc != NULL && cc != vm_cc_empty()) {
567 vm_ci_dump(ci);
568 rb_bug("call cache is not initialized by vm_cc_empty()");
569 }
570 }
571#endif
572}
573
574/*
575 * elem1, elem2 => elem1, elem2, elem
576 */
577static void
578ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
579{
580 elem->prev = anchor->last;
581 anchor->last->next = elem;
582 anchor->last = elem;
583 verify_list("add", anchor);
584}
585
586/*
587 * elem1, before, elem2 => elem1, before, elem, elem2
588 */
589static void
590APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
591{
592 elem->prev = before;
593 elem->next = before->next;
594 elem->next->prev = elem;
595 before->next = elem;
596 if (before == anchor->last) anchor->last = elem;
597 verify_list("add", anchor);
598}
599#if CPDEBUG < 0
600#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
601#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
602#endif
603
604static int
605branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
606{
607 if (!ISEQ_COVERAGE(iseq)) return 0;
608 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
609 if (first_line <= 0) return 0;
610 return 1;
611}
612
613static VALUE
614setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
615{
616 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
617 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
618 VALUE branch = rb_ary_hidden_new(6);
619
620 rb_hash_aset(structure, key, branch);
621 rb_ary_push(branch, ID2SYM(rb_intern(type)));
622 rb_ary_push(branch, INT2FIX(first_lineno));
623 rb_ary_push(branch, INT2FIX(first_column));
624 rb_ary_push(branch, INT2FIX(last_lineno));
625 rb_ary_push(branch, INT2FIX(last_column));
626 return branch;
627}
628
629static VALUE
630decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
631{
632 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
633
634 /*
635 * if !structure[node]
636 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
637 * else
638 * branches = structure[node][5]
639 * end
640 */
641
642 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
643 VALUE branch_base = rb_hash_aref(structure, key);
644 VALUE branches;
645
646 if (NIL_P(branch_base)) {
647 branch_base = setup_branch(loc, type, structure, key);
648 branches = rb_hash_new();
649 rb_obj_hide(branches);
650 rb_ary_push(branch_base, branches);
651 }
652 else {
653 branches = RARRAY_AREF(branch_base, 5);
654 }
655
656 return branches;
657}
658
659static NODE
660generate_dummy_line_node(int lineno, int node_id)
661{
662 NODE dummy = { 0 };
663 nd_set_line(&dummy, lineno);
664 nd_set_node_id(&dummy, node_id);
665 return dummy;
666}
667
668static void
669add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
670{
671 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
672
673 /*
674 * if !branches[branch_id]
675 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
676 * else
677 * counter_idx= branches[branch_id][5]
678 * end
679 */
680
681 VALUE key = INT2FIX(branch_id);
682 VALUE branch = rb_hash_aref(branches, key);
683 long counter_idx;
684
685 if (NIL_P(branch)) {
686 branch = setup_branch(loc, type, branches, key);
687 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
688 counter_idx = RARRAY_LEN(counters);
689 rb_ary_push(branch, LONG2FIX(counter_idx));
690 rb_ary_push(counters, INT2FIX(0));
691 }
692 else {
693 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
694 }
695
696 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
697 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724static NODE *
725get_nd_recv(const NODE *node)
726{
727 switch (nd_type(node)) {
728 case NODE_CALL:
729 return RNODE_CALL(node)->nd_recv;
730 case NODE_OPCALL:
731 return RNODE_OPCALL(node)->nd_recv;
732 case NODE_FCALL:
733 return 0;
734 case NODE_QCALL:
735 return RNODE_QCALL(node)->nd_recv;
736 case NODE_VCALL:
737 return 0;
738 case NODE_ATTRASGN:
739 return RNODE_ATTRASGN(node)->nd_recv;
740 case NODE_OP_ASGN1:
741 return RNODE_OP_ASGN1(node)->nd_recv;
742 case NODE_OP_ASGN2:
743 return RNODE_OP_ASGN2(node)->nd_recv;
744 default:
745 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
746 }
747}
748
749static ID
750get_node_call_nd_mid(const NODE *node)
751{
752 switch (nd_type(node)) {
753 case NODE_CALL:
754 return RNODE_CALL(node)->nd_mid;
755 case NODE_OPCALL:
756 return RNODE_OPCALL(node)->nd_mid;
757 case NODE_FCALL:
758 return RNODE_FCALL(node)->nd_mid;
759 case NODE_QCALL:
760 return RNODE_QCALL(node)->nd_mid;
761 case NODE_VCALL:
762 return RNODE_VCALL(node)->nd_mid;
763 case NODE_ATTRASGN:
764 return RNODE_ATTRASGN(node)->nd_mid;
765 default:
766 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
767 }
768}
769
770static NODE *
771get_nd_args(const NODE *node)
772{
773 switch (nd_type(node)) {
774 case NODE_CALL:
775 return RNODE_CALL(node)->nd_args;
776 case NODE_OPCALL:
777 return RNODE_OPCALL(node)->nd_args;
778 case NODE_FCALL:
779 return RNODE_FCALL(node)->nd_args;
780 case NODE_QCALL:
781 return RNODE_QCALL(node)->nd_args;
782 case NODE_VCALL:
783 return 0;
784 case NODE_ATTRASGN:
785 return RNODE_ATTRASGN(node)->nd_args;
786 default:
787 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
788 }
789}
790
791static ID
792get_node_colon_nd_mid(const NODE *node)
793{
794 switch (nd_type(node)) {
795 case NODE_COLON2:
796 return RNODE_COLON2(node)->nd_mid;
797 case NODE_COLON3:
798 return RNODE_COLON3(node)->nd_mid;
799 default:
800 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
801 }
802}
803
804static ID
805get_nd_vid(const NODE *node)
806{
807 switch (nd_type(node)) {
808 case NODE_LASGN:
809 return RNODE_LASGN(node)->nd_vid;
810 case NODE_DASGN:
811 return RNODE_DASGN(node)->nd_vid;
812 case NODE_IASGN:
813 return RNODE_IASGN(node)->nd_vid;
814 case NODE_CVASGN:
815 return RNODE_CVASGN(node)->nd_vid;
816 default:
817 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
818 }
819}
820
821static NODE *
822get_nd_value(const NODE *node)
823{
824 switch (nd_type(node)) {
825 case NODE_LASGN:
826 return RNODE_LASGN(node)->nd_value;
827 case NODE_DASGN:
828 return RNODE_DASGN(node)->nd_value;
829 default:
830 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
831 }
832}
833
834static VALUE
835get_string_value(const NODE *node)
836{
837 switch (nd_type(node)) {
838 case NODE_STR:
839 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
840 case NODE_FILE:
841 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
842 default:
843 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
844 }
845}
846
847VALUE
848rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
849{
850 DECL_ANCHOR(ret);
851 INIT_ANCHOR(ret);
852
853 (*ifunc->func)(iseq, ret, ifunc->data);
854
855 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
856
857 CHECK(iseq_setup_insn(iseq, ret));
858 return iseq_setup(iseq, ret);
859}
860
861static bool drop_unreachable_return(LINK_ANCHOR *ret);
862
863VALUE
864rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
865{
866 DECL_ANCHOR(ret);
867 INIT_ANCHOR(ret);
868
869 if (node == 0) {
870 NO_CHECK(COMPILE(ret, "nil", node));
871 iseq_set_local_table(iseq, 0, 0);
872 }
873 /* assume node is T_NODE */
874 else if (nd_type_p(node, NODE_SCOPE)) {
875 /* iseq type of top, method, class, block */
876 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
877 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_parameters_lvar_state(iseq);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(&OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1402 RBASIC_CLASS(*obj) == 0 || // hidden
1403 RB_OBJ_SHAREABLE_P(*obj));
1404}
1405
1406static INSN *
1407new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1408{
1409 INSN *iobj = compile_data_alloc_insn(iseq);
1410
1411 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1412
1413 iobj->link.type = ISEQ_ELEMENT_INSN;
1414 iobj->link.next = 0;
1415 iobj->insn_id = insn_id;
1416 iobj->insn_info.line_no = line_no;
1417 iobj->insn_info.node_id = node_id;
1418 iobj->insn_info.events = 0;
1419 iobj->operands = argv;
1420 iobj->operand_size = argc;
1421 iobj->sc_state = 0;
1422
1423 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1424
1425 return iobj;
1426}
1427
1428static INSN *
1429new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1430{
1431 VALUE *operands = 0;
1432 va_list argv;
1433 if (argc > 0) {
1434 int i;
1435 va_start(argv, argc);
1436 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1437 for (i = 0; i < argc; i++) {
1438 VALUE v = va_arg(argv, VALUE);
1439 operands[i] = v;
1440 }
1441 va_end(argv);
1442 }
1443 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1444}
1445
1446static INSN *
1447insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1448{
1449 VALUE *operands = 0;
1450 va_list argv;
1451 if (argc > 0) {
1452 int i;
1453 va_start(argv, argc);
1454 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1455 for (i = 0; i < argc; i++) {
1456 VALUE v = va_arg(argv, VALUE);
1457 operands[i] = v;
1458 }
1459 va_end(argv);
1460 }
1461
1462 iobj->insn_id = insn_id;
1463 iobj->operand_size = argc;
1464 iobj->operands = operands;
1465 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1466
1467 return iobj;
1468}
1469
1470static const struct rb_callinfo *
1471new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1472{
1473 VM_ASSERT(argc >= 0);
1474
1475 if (kw_arg) {
1476 flag |= VM_CALL_KWARG;
1477 argc += kw_arg->keyword_len;
1478 }
1479
1480 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1481 && !has_blockiseq) {
1482 flag |= VM_CALL_ARGS_SIMPLE;
1483 }
1484
1485 ISEQ_BODY(iseq)->ci_size++;
1486 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1487 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1488 return ci;
1489}
1490
1491static INSN *
1492new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1493{
1494 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1495 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1496 operands[0] = ci;
1497 operands[1] = (VALUE)blockiseq;
1498 if (blockiseq) {
1499 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1500 }
1501
1502 INSN *insn;
1503
1504 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1506 }
1507 else {
1508 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1509 }
1510
1511 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1512 RB_GC_GUARD(ci);
1513 return insn;
1514}
1515
1516static rb_iseq_t *
1517new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1518 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1519{
1520 rb_iseq_t *ret_iseq;
1521 VALUE ast_value = rb_ruby_ast_new(node);
1522
1523 debugs("[new_child_iseq]> ---------------------------------------\n");
1524 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1525 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1526 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1527 line_no, parent,
1528 isolated_depth ? isolated_depth + 1 : 0,
1529 type, ISEQ_COMPILE_DATA(iseq)->option,
1530 ISEQ_BODY(iseq)->variable.script_lines);
1531 debugs("[new_child_iseq]< ---------------------------------------\n");
1532 return ret_iseq;
1533}
1534
1535static rb_iseq_t *
1536new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1537 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1538{
1539 rb_iseq_t *ret_iseq;
1540
1541 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1542 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1543 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1544 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1545 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1546 return ret_iseq;
1547}
1548
1549static void
1550set_catch_except_p(rb_iseq_t *iseq)
1551{
1552 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1553 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1554 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1555 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1556 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1557 }
1558 }
1559}
1560
1561/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1562 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1563 if catch table exists. But we want to optimize while loop, which always has catch
1564 table entries for break/next/redo.
1565
1566 So this function sets true for limited ISeqs with break/next/redo catch table entries
1567 whose child ISeq would really raise an exception. */
1568static void
1569update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1570{
1571 unsigned int pos;
1572 size_t i;
1573 int insn;
1574 const struct iseq_catch_table *ct = body->catch_table;
1575
1576 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1577 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1578 pos = 0;
1579 while (pos < body->iseq_size) {
1580 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1581 if (insn == BIN(throw)) {
1582 set_catch_except_p(iseq);
1583 break;
1584 }
1585 pos += insn_len(insn);
1586 }
1587
1588 if (ct == NULL)
1589 return;
1590
1591 for (i = 0; i < ct->size; i++) {
1592 const struct iseq_catch_table_entry *entry =
1593 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1594 if (entry->type != CATCH_TYPE_BREAK
1595 && entry->type != CATCH_TYPE_NEXT
1596 && entry->type != CATCH_TYPE_REDO) {
1597 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1598 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1599 break;
1600 }
1601 }
1602}
1603
1604static void
1605iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1606{
1607 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1608 if (NIL_P(catch_table_ary)) return;
1609 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1610 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1611 for (i = 0; i < tlen; i++) {
1612 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1613 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1614 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1615 LINK_ELEMENT *e;
1616
1617 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1618
1619 if (ct != CATCH_TYPE_BREAK
1620 && ct != CATCH_TYPE_NEXT
1621 && ct != CATCH_TYPE_REDO) {
1622
1623 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1624 if (e == cont) {
1625 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1626 ELEM_INSERT_NEXT(end, &nop->link);
1627 break;
1628 }
1629 }
1630 }
1631 }
1632
1633 RB_GC_GUARD(catch_table_ary);
1634}
1635
1636static int
1637iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1638{
1639 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1640 return COMPILE_NG;
1641
1642 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1643
1644 if (compile_debug > 5)
1645 dump_disasm_list(FIRST_ELEMENT(anchor));
1646
1647 debugs("[compile step 3.1 (iseq_optimize)]\n");
1648 iseq_optimize(iseq, anchor);
1649
1650 if (compile_debug > 5)
1651 dump_disasm_list(FIRST_ELEMENT(anchor));
1652
1653 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1654 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1655 iseq_insns_unification(iseq, anchor);
1656 if (compile_debug > 5)
1657 dump_disasm_list(FIRST_ELEMENT(anchor));
1658 }
1659
1660 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1661 iseq_insert_nop_between_end_and_cont(iseq);
1662 if (compile_debug > 5)
1663 dump_disasm_list(FIRST_ELEMENT(anchor));
1664
1665 return COMPILE_OK;
1666}
1667
1668static int
1669iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1670{
1671 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1672 return COMPILE_NG;
1673
1674 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1675 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1676 if (compile_debug > 5)
1677 dump_disasm_list(FIRST_ELEMENT(anchor));
1678
1679 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1680 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1681
1682 debugs("[compile step 4.3 (set_optargs_table)] \n");
1683 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1684
1685 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1686 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1687
1688 debugs("[compile step 6 (update_catch_except_flags)] \n");
1689 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1690 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1691
1692 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1693 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1694 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1695 xfree(ISEQ_BODY(iseq)->catch_table);
1696 ISEQ_BODY(iseq)->catch_table = NULL;
1697 }
1698
1699#if VM_INSN_INFO_TABLE_IMPL == 2
1700 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1701 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1702 rb_iseq_insns_info_encode_positions(iseq);
1703 }
1704#endif
1705
1706 if (compile_debug > 1) {
1707 VALUE str = rb_iseq_disasm(iseq);
1708 printf("%s\n", StringValueCStr(str));
1709 }
1710 verify_call_cache(iseq);
1711 debugs("[compile step: finish]\n");
1712
1713 return COMPILE_OK;
1714}
1715
1716static int
1717iseq_set_exception_local_table(rb_iseq_t *iseq)
1718{
1719 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1720 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1721 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1722 return COMPILE_OK;
1723}
1724
1725static int
1726get_lvar_level(const rb_iseq_t *iseq)
1727{
1728 int lev = 0;
1729 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1730 lev++;
1731 iseq = ISEQ_BODY(iseq)->parent_iseq;
1732 }
1733 return lev;
1734}
1735
1736static int
1737get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1738{
1739 unsigned int i;
1740
1741 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1742 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1743 return (int)i;
1744 }
1745 }
1746 return -1;
1747}
1748
1749static int
1750get_local_var_idx(const rb_iseq_t *iseq, ID id)
1751{
1752 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1753
1754 if (idx < 0) {
1755 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1756 "get_local_var_idx: %d", idx);
1757 }
1758
1759 return idx;
1760}
1761
1762static int
1763get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1764{
1765 int lv = 0, idx = -1;
1766 const rb_iseq_t *const topmost_iseq = iseq;
1767
1768 while (iseq) {
1769 idx = get_dyna_var_idx_at_raw(iseq, id);
1770 if (idx >= 0) {
1771 break;
1772 }
1773 iseq = ISEQ_BODY(iseq)->parent_iseq;
1774 lv++;
1775 }
1776
1777 if (idx < 0) {
1778 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1779 "get_dyna_var_idx: -1");
1780 }
1781
1782 *level = lv;
1783 *ls = ISEQ_BODY(iseq)->local_table_size;
1784 return idx;
1785}
1786
1787static int
1788iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1789{
1790 const struct rb_iseq_constant_body *body;
1791 while (level > 0) {
1792 iseq = ISEQ_BODY(iseq)->parent_iseq;
1793 level--;
1794 }
1795 body = ISEQ_BODY(iseq);
1796 if (body->local_iseq == iseq && /* local variables */
1797 body->param.flags.has_block &&
1798 body->local_table_size - body->param.block_start == idx) {
1799 return TRUE;
1800 }
1801 else {
1802 return FALSE;
1803 }
1804}
1805
1806static int
1807iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1808{
1809 int level, ls;
1810 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1811 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1812 *pidx = ls - idx;
1813 *plevel = level;
1814 return TRUE;
1815 }
1816 else {
1817 return FALSE;
1818 }
1819}
1820
1821static void
1822access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1823{
1824 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1825
1826 if (isolated_depth && level >= isolated_depth) {
1827 if (id == rb_intern("yield")) {
1828 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1829 }
1830 else {
1831 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1832 }
1833 }
1834
1835 for (int i=0; i<level; i++) {
1836 VALUE val;
1837 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1838
1839 if (!ovs) {
1840 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1841 }
1842
1843 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1844 if (write && !val) {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1846 }
1847 }
1848 else {
1849 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1850 }
1851
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1853 }
1854}
1855
1856static ID
1857iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1858{
1859 for (int i=0; i<level; i++) {
1860 iseq = ISEQ_BODY(iseq)->parent_iseq;
1861 }
1862
1863 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1864 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1865 return id;
1866}
1867
1868static void
1869update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1870{
1871 for (int i=0; i<level; i++) {
1872 iseq = ISEQ_BODY(iseq)->parent_iseq;
1873 }
1874
1875 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1876 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1877 switch (states[table_idx]) {
1878 case lvar_uninitialized:
1879 states[table_idx] = lvar_initialized;
1880 break;
1881 case lvar_initialized:
1882 states[table_idx] = lvar_reassigned;
1883 break;
1884 case lvar_reassigned:
1885 /* nothing */
1886 break;
1887 default:
1888 rb_bug("unreachable");
1889 }
1890}
1891
1892static int
1893iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1894{
1895 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1896 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1897 }
1898
1899 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1900 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1901 for (int i=0; i<opt_num; i++) {
1902 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1903 }
1904
1905 return COMPILE_OK;
1906}
1907
1908static void
1909iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1910{
1911 if (iseq_local_block_param_p(iseq, idx, level)) {
1912 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1913 }
1914 else {
1915 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1916 }
1917 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1918}
1919
1920static void
1921iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1922{
1923 if (iseq_local_block_param_p(iseq, idx, level)) {
1924 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1925 }
1926 else {
1927 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1928 }
1929 update_lvar_state(iseq, level, idx);
1930 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1931}
1932
1933
1934
1935static void
1936iseq_calc_param_size(rb_iseq_t *iseq)
1937{
1938 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1939 if (body->param.flags.has_opt ||
1940 body->param.flags.has_post ||
1941 body->param.flags.has_rest ||
1942 body->param.flags.has_block ||
1943 body->param.flags.has_kw ||
1944 body->param.flags.has_kwrest) {
1945
1946 if (body->param.flags.has_block) {
1947 body->param.size = body->param.block_start + 1;
1948 }
1949 else if (body->param.flags.has_kwrest) {
1950 body->param.size = body->param.keyword->rest_start + 1;
1951 }
1952 else if (body->param.flags.has_kw) {
1953 body->param.size = body->param.keyword->bits_start + 1;
1954 }
1955 else if (body->param.flags.has_post) {
1956 body->param.size = body->param.post_start + body->param.post_num;
1957 }
1958 else if (body->param.flags.has_rest) {
1959 body->param.size = body->param.rest_start + 1;
1960 }
1961 else if (body->param.flags.has_opt) {
1962 body->param.size = body->param.lead_num + body->param.opt_num;
1963 }
1964 else {
1966 }
1967 }
1968 else {
1969 body->param.size = body->param.lead_num;
1970 }
1971}
1972
1973static int
1974iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1975 const struct rb_args_info *args, int arg_size)
1976{
1977 const rb_node_kw_arg_t *node = args->kw_args;
1978 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1979 struct rb_iseq_param_keyword *keyword;
1980 const VALUE default_values = rb_ary_hidden_new(1);
1981 const VALUE complex_mark = rb_str_tmp_new(0);
1982 int kw = 0, rkw = 0, di = 0, i;
1983
1984 body->param.flags.has_kw = TRUE;
1985 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1986
1987 while (node) {
1988 kw++;
1989 node = node->nd_next;
1990 }
1991 arg_size += kw;
1992 keyword->bits_start = arg_size++;
1993
1994 node = args->kw_args;
1995 while (node) {
1996 const NODE *val_node = get_nd_value(node->nd_body);
1997 VALUE dv;
1998
1999 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2000 ++rkw;
2001 }
2002 else {
2003 switch (nd_type(val_node)) {
2004 case NODE_SYM:
2005 dv = rb_node_sym_string_val(val_node);
2006 break;
2007 case NODE_REGX:
2008 dv = rb_node_regx_string_val(val_node);
2009 break;
2010 case NODE_LINE:
2011 dv = rb_node_line_lineno_val(val_node);
2012 break;
2013 case NODE_INTEGER:
2014 dv = rb_node_integer_literal_val(val_node);
2015 break;
2016 case NODE_FLOAT:
2017 dv = rb_node_float_literal_val(val_node);
2018 break;
2019 case NODE_RATIONAL:
2020 dv = rb_node_rational_literal_val(val_node);
2021 break;
2022 case NODE_IMAGINARY:
2023 dv = rb_node_imaginary_literal_val(val_node);
2024 break;
2025 case NODE_ENCODING:
2026 dv = rb_node_encoding_val(val_node);
2027 break;
2028 case NODE_NIL:
2029 dv = Qnil;
2030 break;
2031 case NODE_TRUE:
2032 dv = Qtrue;
2033 break;
2034 case NODE_FALSE:
2035 dv = Qfalse;
2036 break;
2037 default:
2038 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2039 dv = complex_mark;
2040 }
2041
2042 keyword->num = ++di;
2043 rb_ary_push(default_values, dv);
2044 }
2045
2046 node = node->nd_next;
2047 }
2048
2049 keyword->num = kw;
2050
2051 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2052 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2053 keyword->rest_start = arg_size++;
2054 body->param.flags.has_kwrest = TRUE;
2055
2056 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2057 }
2058 keyword->required_num = rkw;
2059 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2060
2061 if (RARRAY_LEN(default_values)) {
2062 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2063
2064 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2065 VALUE dv = RARRAY_AREF(default_values, i);
2066 if (dv == complex_mark) dv = Qundef;
2068 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2069 }
2070
2071 keyword->default_values = dvs;
2072 }
2073 return arg_size;
2074}
2075
2076static void
2077iseq_set_use_block(rb_iseq_t *iseq)
2078{
2079 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2080 if (!body->param.flags.use_block) {
2081 body->param.flags.use_block = 1;
2082
2083 rb_vm_t *vm = GET_VM();
2084
2085 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2086 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2087 set_insert(vm->unused_block_warning_table, key);
2088 }
2089 }
2090}
2091
2092static int
2093iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2094{
2095 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2096
2097 if (node_args) {
2098 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2099 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2100 ID rest_id = 0;
2101 int last_comma = 0;
2102 ID block_id = 0;
2103 int arg_size;
2104
2105 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2106
2107 body->param.lead_num = arg_size = (int)args->pre_args_num;
2108 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2109 debugs(" - argc: %d\n", body->param.lead_num);
2110
2111 rest_id = args->rest_arg;
2112 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2113 last_comma = 1;
2114 rest_id = 0;
2115 }
2116 block_id = args->block_arg;
2117
2118 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2119
2120 if (optimized_forward) {
2121 rest_id = 0;
2122 block_id = 0;
2123 }
2124
2125 if (args->opt_args) {
2126 const rb_node_opt_arg_t *node = args->opt_args;
2127 LABEL *label;
2128 VALUE labels = rb_ary_hidden_new(1);
2129 VALUE *opt_table;
2130 int i = 0, j;
2131
2132 while (node) {
2133 label = NEW_LABEL(nd_line(RNODE(node)));
2134 rb_ary_push(labels, (VALUE)label | 1);
2135 ADD_LABEL(optargs, label);
2136 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2137 node = node->nd_next;
2138 i += 1;
2139 }
2140
2141 /* last label */
2142 label = NEW_LABEL(nd_line(node_args));
2143 rb_ary_push(labels, (VALUE)label | 1);
2144 ADD_LABEL(optargs, label);
2145
2146 opt_table = ALLOC_N(VALUE, i+1);
2147
2148 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2149 for (j = 0; j < i+1; j++) {
2150 opt_table[j] &= ~1;
2151 }
2152 rb_ary_clear(labels);
2153
2154 body->param.flags.has_opt = TRUE;
2155 body->param.opt_num = i;
2156 body->param.opt_table = opt_table;
2157 arg_size += i;
2158 }
2159
2160 if (rest_id) {
2161 body->param.rest_start = arg_size++;
2162 body->param.flags.has_rest = TRUE;
2163 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2164 RUBY_ASSERT(body->param.rest_start != -1);
2165 }
2166
2167 if (args->first_post_arg) {
2168 body->param.post_start = arg_size;
2169 body->param.post_num = args->post_args_num;
2170 body->param.flags.has_post = TRUE;
2171 arg_size += args->post_args_num;
2172
2173 if (body->param.flags.has_rest) { /* TODO: why that? */
2174 body->param.post_start = body->param.rest_start + 1;
2175 }
2176 }
2177
2178 if (args->kw_args) {
2179 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2180 }
2181 else if (args->kw_rest_arg && !optimized_forward) {
2182 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2183 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2184 keyword->rest_start = arg_size++;
2185 body->param.keyword = keyword;
2186 body->param.flags.has_kwrest = TRUE;
2187
2188 static ID anon_kwrest = 0;
2189 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2190 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2191 }
2192 else if (args->no_kwarg) {
2193 body->param.flags.accepts_no_kwarg = TRUE;
2194 }
2195
2196 if (block_id) {
2197 body->param.block_start = arg_size++;
2198 body->param.flags.has_block = TRUE;
2199 iseq_set_use_block(iseq);
2200 }
2201
2202 // Only optimize specifically methods like this: `foo(...)`
2203 if (optimized_forward) {
2204 body->param.flags.use_block = 1;
2205 body->param.flags.forwardable = TRUE;
2206 arg_size = 1;
2207 }
2208
2209 iseq_calc_param_size(iseq);
2210 body->param.size = arg_size;
2211
2212 if (args->pre_init) { /* m_init */
2213 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2214 }
2215 if (args->post_init) { /* p_init */
2216 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2217 }
2218
2219 if (body->type == ISEQ_TYPE_BLOCK) {
2220 if (body->param.flags.has_opt == FALSE &&
2221 body->param.flags.has_post == FALSE &&
2222 body->param.flags.has_rest == FALSE &&
2223 body->param.flags.has_kw == FALSE &&
2224 body->param.flags.has_kwrest == FALSE) {
2225
2226 if (body->param.lead_num == 1 && last_comma == 0) {
2227 /* {|a|} */
2228 body->param.flags.ambiguous_param0 = TRUE;
2229 }
2230 }
2231 }
2232 }
2233
2234 return COMPILE_OK;
2235}
2236
2237static int
2238iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2239{
2240 unsigned int size = tbl ? tbl->size : 0;
2241 unsigned int offset = 0;
2242
2243 if (node_args) {
2244 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2245
2246 // If we have a function that only has `...` as the parameter,
2247 // then its local table should only be `...`
2248 // FIXME: I think this should be fixed in the AST rather than special case here.
2249 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2250 CHECK(size >= 3);
2251 size -= 3;
2252 offset += 3;
2253 }
2254 }
2255
2256 if (size > 0) {
2257 ID *ids = ALLOC_N(ID, size);
2258 MEMCPY(ids, tbl->ids + offset, ID, size);
2259 ISEQ_BODY(iseq)->local_table = ids;
2260
2261 enum lvar_state *states = ALLOC_N(enum lvar_state, size);
2262 // fprintf(stderr, "iseq:%p states:%p size:%d\n", iseq, states, (int)size);
2263 for (unsigned int i=0; i<size; i++) {
2264 states[i] = lvar_uninitialized;
2265 // fprintf(stderr, "id:%s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]));
2266 }
2267 ISEQ_BODY(iseq)->lvar_states = states;
2268 }
2269 ISEQ_BODY(iseq)->local_table_size = size;
2270
2271 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2272 return COMPILE_OK;
2273}
2274
2275int
2276rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2277{
2278 int tval, tlit;
2279
2280 if (val == lit) {
2281 return 0;
2282 }
2283 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2284 return val != lit;
2285 }
2286 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2287 return -1;
2288 }
2289 else if (tlit != tval) {
2290 return -1;
2291 }
2292 else if (tlit == T_SYMBOL) {
2293 return val != lit;
2294 }
2295 else if (tlit == T_STRING) {
2296 return rb_str_hash_cmp(lit, val);
2297 }
2298 else if (tlit == T_BIGNUM) {
2299 long x = FIX2LONG(rb_big_cmp(lit, val));
2300
2301 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2302 * There is no need to call rb_fix2int here. */
2303 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2304 return (int)x;
2305 }
2306 else if (tlit == T_FLOAT) {
2307 return rb_float_cmp(lit, val);
2308 }
2309 else if (tlit == T_RATIONAL) {
2310 const struct RRational *rat1 = RRATIONAL(val);
2311 const struct RRational *rat2 = RRATIONAL(lit);
2312 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2313 }
2314 else if (tlit == T_COMPLEX) {
2315 const struct RComplex *comp1 = RCOMPLEX(val);
2316 const struct RComplex *comp2 = RCOMPLEX(lit);
2317 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2318 }
2319 else if (tlit == T_REGEXP) {
2320 return rb_reg_equal(val, lit) ? 0 : -1;
2321 }
2322 else {
2324 }
2325}
2326
2327st_index_t
2328rb_iseq_cdhash_hash(VALUE a)
2329{
2330 switch (OBJ_BUILTIN_TYPE(a)) {
2331 case -1:
2332 case T_SYMBOL:
2333 return (st_index_t)a;
2334 case T_STRING:
2335 return rb_str_hash(a);
2336 case T_BIGNUM:
2337 return FIX2LONG(rb_big_hash(a));
2338 case T_FLOAT:
2339 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2340 case T_RATIONAL:
2341 return rb_rational_hash(a);
2342 case T_COMPLEX:
2343 return rb_complex_hash(a);
2344 case T_REGEXP:
2345 return NUM2LONG(rb_reg_hash(a));
2346 default:
2348 }
2349}
2350
2351static const struct st_hash_type cdhash_type = {
2352 rb_iseq_cdhash_cmp,
2353 rb_iseq_cdhash_hash,
2354};
2355
2357 VALUE hash;
2358 int pos;
2359 int len;
2360};
2361
2362static int
2363cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2364{
2365 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2366 LABEL *lobj = (LABEL *)(val & ~1);
2367 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2368 return ST_CONTINUE;
2369}
2370
2371
2372static inline VALUE
2373get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2374{
2375 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2376}
2377
2378static inline VALUE
2379get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2380{
2381 VALUE val;
2382 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2383 if (tbl) {
2384 if (rb_id_table_lookup(tbl,id,&val)) {
2385 return val;
2386 }
2387 }
2388 else {
2389 tbl = rb_id_table_create(1);
2390 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2391 }
2392 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2393 rb_id_table_insert(tbl,id,val);
2394 return val;
2395}
2396
2397#define BADINSN_DUMP(anchor, list, dest) \
2398 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2399
2400#define BADINSN_ERROR \
2401 (xfree(generated_iseq), \
2402 xfree(insns_info), \
2403 BADINSN_DUMP(anchor, list, NULL), \
2404 COMPILE_ERROR)
2405
2406static int
2407fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2408{
2409 int stack_max = 0, sp = 0, line = 0;
2410 LINK_ELEMENT *list;
2411
2412 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2413 if (IS_LABEL(list)) {
2414 LABEL *lobj = (LABEL *)list;
2415 lobj->set = TRUE;
2416 }
2417 }
2418
2419 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2420 switch (list->type) {
2421 case ISEQ_ELEMENT_INSN:
2422 {
2423 int j, len, insn;
2424 const char *types;
2425 VALUE *operands;
2426 INSN *iobj = (INSN *)list;
2427
2428 /* update sp */
2429 sp = calc_sp_depth(sp, iobj);
2430 if (sp < 0) {
2431 BADINSN_DUMP(anchor, list, NULL);
2432 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2433 "argument stack underflow (%d)", sp);
2434 return -1;
2435 }
2436 if (sp > stack_max) {
2437 stack_max = sp;
2438 }
2439
2440 line = iobj->insn_info.line_no;
2441 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2442 operands = iobj->operands;
2443 insn = iobj->insn_id;
2444 types = insn_op_types(insn);
2445 len = insn_len(insn);
2446
2447 /* operand check */
2448 if (iobj->operand_size != len - 1) {
2449 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2450 BADINSN_DUMP(anchor, list, NULL);
2451 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2452 "operand size miss! (%d for %d)",
2453 iobj->operand_size, len - 1);
2454 return -1;
2455 }
2456
2457 for (j = 0; types[j]; j++) {
2458 if (types[j] == TS_OFFSET) {
2459 /* label(destination position) */
2460 LABEL *lobj = (LABEL *)operands[j];
2461 if (!lobj->set) {
2462 BADINSN_DUMP(anchor, list, NULL);
2463 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2464 "unknown label: "LABEL_FORMAT, lobj->label_no);
2465 return -1;
2466 }
2467 if (lobj->sp == -1) {
2468 lobj->sp = sp;
2469 }
2470 else if (lobj->sp != sp) {
2471 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2472 RSTRING_PTR(rb_iseq_path(iseq)), line,
2473 lobj->label_no, lobj->sp, sp);
2474 }
2475 }
2476 }
2477 break;
2478 }
2479 case ISEQ_ELEMENT_LABEL:
2480 {
2481 LABEL *lobj = (LABEL *)list;
2482 if (lobj->sp == -1) {
2483 lobj->sp = sp;
2484 }
2485 else {
2486 if (lobj->sp != sp) {
2487 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2488 RSTRING_PTR(rb_iseq_path(iseq)), line,
2489 lobj->label_no, lobj->sp, sp);
2490 }
2491 sp = lobj->sp;
2492 }
2493 break;
2494 }
2495 case ISEQ_ELEMENT_TRACE:
2496 {
2497 /* ignore */
2498 break;
2499 }
2500 case ISEQ_ELEMENT_ADJUST:
2501 {
2502 ADJUST *adjust = (ADJUST *)list;
2503 int orig_sp = sp;
2504
2505 sp = adjust->label ? adjust->label->sp : 0;
2506 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2507 BADINSN_DUMP(anchor, list, NULL);
2508 COMPILE_ERROR(iseq, adjust->line_no,
2509 "iseq_set_sequence: adjust bug %d < %d",
2510 orig_sp, sp);
2511 return -1;
2512 }
2513 break;
2514 }
2515 default:
2516 BADINSN_DUMP(anchor, list, NULL);
2517 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2518 return -1;
2519 }
2520 }
2521 return stack_max;
2522}
2523
2524static int
2525add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2526 int insns_info_index, int code_index, const INSN *iobj)
2527{
2528 if (insns_info_index == 0 ||
2529 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2530#ifdef USE_ISEQ_NODE_ID
2531 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2532#endif
2533 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2534 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2535#ifdef USE_ISEQ_NODE_ID
2536 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2537#endif
2538 insns_info[insns_info_index].events = iobj->insn_info.events;
2539 positions[insns_info_index] = code_index;
2540 return TRUE;
2541 }
2542 return FALSE;
2543}
2544
2545static int
2546add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2547 int insns_info_index, int code_index, const ADJUST *adjust)
2548{
2549 insns_info[insns_info_index].line_no = adjust->line_no;
2550 insns_info[insns_info_index].node_id = -1;
2551 insns_info[insns_info_index].events = 0;
2552 positions[insns_info_index] = code_index;
2553 return TRUE;
2554}
2555
2556static ID *
2557array_to_idlist(VALUE arr)
2558{
2560 long size = RARRAY_LEN(arr);
2561 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2562 for (long i = 0; i < size; i++) {
2563 VALUE sym = RARRAY_AREF(arr, i);
2564 ids[i] = SYM2ID(sym);
2565 }
2566 ids[size] = 0;
2567 return ids;
2568}
2569
2570static VALUE
2571idlist_to_array(const ID *ids)
2572{
2573 VALUE arr = rb_ary_new();
2574 while (*ids) {
2575 rb_ary_push(arr, ID2SYM(*ids++));
2576 }
2577 return arr;
2578}
2579
2583static int
2584iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2585{
2586 struct iseq_insn_info_entry *insns_info;
2587 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2588 unsigned int *positions;
2589 LINK_ELEMENT *list;
2590 VALUE *generated_iseq;
2591 rb_event_flag_t events = 0;
2592 long data = 0;
2593
2594 int insn_num, code_index, insns_info_index, sp = 0;
2595 int stack_max = fix_sp_depth(iseq, anchor);
2596
2597 if (stack_max < 0) return COMPILE_NG;
2598
2599 /* fix label position */
2600 insn_num = code_index = 0;
2601 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2602 switch (list->type) {
2603 case ISEQ_ELEMENT_INSN:
2604 {
2605 INSN *iobj = (INSN *)list;
2606 /* update sp */
2607 sp = calc_sp_depth(sp, iobj);
2608 insn_num++;
2609 events = iobj->insn_info.events |= events;
2610 if (ISEQ_COVERAGE(iseq)) {
2611 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2612 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2613 int line = iobj->insn_info.line_no - 1;
2614 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2615 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2616 }
2617 }
2618 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2619 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2620 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2621 }
2622 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2623 }
2624 }
2625 code_index += insn_data_length(iobj);
2626 events = 0;
2627 data = 0;
2628 break;
2629 }
2630 case ISEQ_ELEMENT_LABEL:
2631 {
2632 LABEL *lobj = (LABEL *)list;
2633 lobj->position = code_index;
2634 if (lobj->sp != sp) {
2635 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2636 RSTRING_PTR(rb_iseq_path(iseq)),
2637 lobj->label_no, lobj->sp, sp);
2638 }
2639 sp = lobj->sp;
2640 break;
2641 }
2642 case ISEQ_ELEMENT_TRACE:
2643 {
2644 TRACE *trace = (TRACE *)list;
2645 events |= trace->event;
2646 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2647 break;
2648 }
2649 case ISEQ_ELEMENT_ADJUST:
2650 {
2651 ADJUST *adjust = (ADJUST *)list;
2652 if (adjust->line_no != -1) {
2653 int orig_sp = sp;
2654 sp = adjust->label ? adjust->label->sp : 0;
2655 if (orig_sp - sp > 0) {
2656 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2657 code_index++; /* insn */
2658 insn_num++;
2659 }
2660 }
2661 break;
2662 }
2663 default: break;
2664 }
2665 }
2666
2667 /* make instruction sequence */
2668 generated_iseq = ALLOC_N(VALUE, code_index);
2669 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2670 positions = ALLOC_N(unsigned int, insn_num);
2671 if (ISEQ_IS_SIZE(body)) {
2672 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2673 }
2674 else {
2675 body->is_entries = NULL;
2676 }
2677
2678 if (body->ci_size) {
2679 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2680 }
2681 else {
2682 body->call_data = NULL;
2683 }
2684 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2685
2686 // Calculate the bitmask buffer size.
2687 // Round the generated_iseq size up to the nearest multiple
2688 // of the number of bits in an unsigned long.
2689
2690 // Allocate enough room for the bitmask list
2691 iseq_bits_t * mark_offset_bits;
2692 int code_size = code_index;
2693
2694 bool needs_bitmap = false;
2695
2696 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2697 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2698 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2699 }
2700 else {
2701 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2702 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2703 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2704 }
2705
2706 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2707 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2708
2709 list = FIRST_ELEMENT(anchor);
2710 insns_info_index = code_index = sp = 0;
2711
2712 while (list) {
2713 switch (list->type) {
2714 case ISEQ_ELEMENT_INSN:
2715 {
2716 int j, len, insn;
2717 const char *types;
2718 VALUE *operands;
2719 INSN *iobj = (INSN *)list;
2720
2721 /* update sp */
2722 sp = calc_sp_depth(sp, iobj);
2723 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2724 operands = iobj->operands;
2725 insn = iobj->insn_id;
2726 generated_iseq[code_index] = insn;
2727 types = insn_op_types(insn);
2728 len = insn_len(insn);
2729
2730 for (j = 0; types[j]; j++) {
2731 char type = types[j];
2732
2733 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2734 switch (type) {
2735 case TS_OFFSET:
2736 {
2737 /* label(destination position) */
2738 LABEL *lobj = (LABEL *)operands[j];
2739 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2740 break;
2741 }
2742 case TS_CDHASH:
2743 {
2744 VALUE map = operands[j];
2745 struct cdhash_set_label_struct data;
2746 data.hash = map;
2747 data.pos = code_index;
2748 data.len = len;
2749 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2750
2751 rb_hash_rehash(map);
2752 freeze_hide_obj(map);
2754 generated_iseq[code_index + 1 + j] = map;
2755 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2756 RB_OBJ_WRITTEN(iseq, Qundef, map);
2757 needs_bitmap = true;
2758 break;
2759 }
2760 case TS_LINDEX:
2761 case TS_NUM: /* ulong */
2762 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2763 break;
2764 case TS_ISEQ: /* iseq */
2765 case TS_VALUE: /* VALUE */
2766 {
2767 VALUE v = operands[j];
2768 generated_iseq[code_index + 1 + j] = v;
2769 /* to mark ruby object */
2770 if (!SPECIAL_CONST_P(v)) {
2771 RB_OBJ_WRITTEN(iseq, Qundef, v);
2772 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2773 needs_bitmap = true;
2774 }
2775 break;
2776 }
2777 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2778 case TS_IC: /* inline cache: constants */
2779 {
2780 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2781 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2782 if (UNLIKELY(ic_index >= body->ic_size)) {
2783 BADINSN_DUMP(anchor, &iobj->link, 0);
2784 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2785 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2786 ic_index, ISEQ_IS_SIZE(body));
2787 }
2788
2789 ic->segments = array_to_idlist(operands[j]);
2790
2791 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2792 }
2793 break;
2794 case TS_IVC: /* inline ivar cache */
2795 {
2796 unsigned int ic_index = FIX2UINT(operands[j]);
2797
2798 IVC cache = ((IVC)&body->is_entries[ic_index]);
2799
2800 if (insn == BIN(setinstancevariable)) {
2801 cache->iv_set_name = SYM2ID(operands[j - 1]);
2802 }
2803 else {
2804 cache->iv_set_name = 0;
2805 }
2806
2807 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2808 }
2809 case TS_ISE: /* inline storage entry: `once` insn */
2810 case TS_ICVARC: /* inline cvar cache */
2811 {
2812 unsigned int ic_index = FIX2UINT(operands[j]);
2813 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2814 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2815 BADINSN_DUMP(anchor, &iobj->link, 0);
2816 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2817 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2818 ic_index, ISEQ_IS_SIZE(body));
2819 }
2820 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2821
2822 break;
2823 }
2824 case TS_CALLDATA:
2825 {
2826 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2827 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2828 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2829 cd->ci = source_ci;
2830 cd->cc = vm_cc_empty();
2831 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2832 break;
2833 }
2834 case TS_ID: /* ID */
2835 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2836 break;
2837 case TS_FUNCPTR:
2838 generated_iseq[code_index + 1 + j] = operands[j];
2839 break;
2840 case TS_BUILTIN:
2841 generated_iseq[code_index + 1 + j] = operands[j];
2842 break;
2843 default:
2844 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2845 "unknown operand type: %c", type);
2846 return COMPILE_NG;
2847 }
2848 }
2849 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2850 code_index += len;
2851 break;
2852 }
2853 case ISEQ_ELEMENT_LABEL:
2854 {
2855 LABEL *lobj = (LABEL *)list;
2856 if (lobj->sp != sp) {
2857 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2858 RSTRING_PTR(rb_iseq_path(iseq)),
2859 lobj->label_no, lobj->sp, sp);
2860 }
2861 sp = lobj->sp;
2862 break;
2863 }
2864 case ISEQ_ELEMENT_ADJUST:
2865 {
2866 ADJUST *adjust = (ADJUST *)list;
2867 int orig_sp = sp;
2868
2869 if (adjust->label) {
2870 sp = adjust->label->sp;
2871 }
2872 else {
2873 sp = 0;
2874 }
2875
2876 if (adjust->line_no != -1) {
2877 const int diff = orig_sp - sp;
2878 if (diff > 0) {
2879 if (insns_info_index == 0) {
2880 COMPILE_ERROR(iseq, adjust->line_no,
2881 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2882 }
2883 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2884 }
2885 if (diff > 1) {
2886 generated_iseq[code_index++] = BIN(adjuststack);
2887 generated_iseq[code_index++] = orig_sp - sp;
2888 }
2889 else if (diff == 1) {
2890 generated_iseq[code_index++] = BIN(pop);
2891 }
2892 else if (diff < 0) {
2893 int label_no = adjust->label ? adjust->label->label_no : -1;
2894 xfree(generated_iseq);
2895 xfree(insns_info);
2896 xfree(positions);
2897 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2898 xfree(mark_offset_bits);
2899 }
2900 debug_list(anchor, list);
2901 COMPILE_ERROR(iseq, adjust->line_no,
2902 "iseq_set_sequence: adjust bug to %d %d < %d",
2903 label_no, orig_sp, sp);
2904 return COMPILE_NG;
2905 }
2906 }
2907 break;
2908 }
2909 default:
2910 /* ignore */
2911 break;
2912 }
2913 list = list->next;
2914 }
2915
2916 body->iseq_encoded = (void *)generated_iseq;
2917 body->iseq_size = code_index;
2918 body->stack_max = stack_max;
2919
2920 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2921 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2922 }
2923 else {
2924 if (needs_bitmap) {
2925 body->mark_bits.list = mark_offset_bits;
2926 }
2927 else {
2928 body->mark_bits.list = NULL;
2929 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2930 ruby_xfree(mark_offset_bits);
2931 }
2932 }
2933
2934 /* get rid of memory leak when REALLOC failed */
2935 body->insns_info.body = insns_info;
2936 body->insns_info.positions = positions;
2937
2938 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2939 body->insns_info.body = insns_info;
2940 REALLOC_N(positions, unsigned int, insns_info_index);
2941 body->insns_info.positions = positions;
2942 body->insns_info.size = insns_info_index;
2943
2944 return COMPILE_OK;
2945}
2946
2947static int
2948label_get_position(LABEL *lobj)
2949{
2950 return lobj->position;
2951}
2952
2953static int
2954label_get_sp(LABEL *lobj)
2955{
2956 return lobj->sp;
2957}
2958
2959static int
2960iseq_set_exception_table(rb_iseq_t *iseq)
2961{
2962 const VALUE *tptr, *ptr;
2963 unsigned int tlen, i;
2964 struct iseq_catch_table_entry *entry;
2965
2966 ISEQ_BODY(iseq)->catch_table = NULL;
2967
2968 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2969 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2970 tlen = (int)RARRAY_LEN(catch_table_ary);
2971 tptr = RARRAY_CONST_PTR(catch_table_ary);
2972
2973 if (tlen > 0) {
2974 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2975 table->size = tlen;
2976
2977 for (i = 0; i < table->size; i++) {
2978 int pos;
2979 ptr = RARRAY_CONST_PTR(tptr[i]);
2980 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2981 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2982 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2983 RUBY_ASSERT(pos >= 0);
2984 entry->start = (unsigned int)pos;
2985 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2986 RUBY_ASSERT(pos >= 0);
2987 entry->end = (unsigned int)pos;
2988 entry->iseq = (rb_iseq_t *)ptr[3];
2989 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2990
2991 /* stack depth */
2992 if (ptr[4]) {
2993 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2994 entry->cont = label_get_position(lobj);
2995 entry->sp = label_get_sp(lobj);
2996
2997 /* TODO: Dirty Hack! Fix me */
2998 if (entry->type == CATCH_TYPE_RESCUE ||
2999 entry->type == CATCH_TYPE_BREAK ||
3000 entry->type == CATCH_TYPE_NEXT) {
3001 RUBY_ASSERT(entry->sp > 0);
3002 entry->sp--;
3003 }
3004 }
3005 else {
3006 entry->cont = 0;
3007 }
3008 }
3009 ISEQ_BODY(iseq)->catch_table = table;
3010 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3011 }
3012
3013 RB_GC_GUARD(catch_table_ary);
3014
3015 return COMPILE_OK;
3016}
3017
3018/*
3019 * set optional argument table
3020 * def foo(a, b=expr1, c=expr2)
3021 * =>
3022 * b:
3023 * expr1
3024 * c:
3025 * expr2
3026 */
3027static int
3028iseq_set_optargs_table(rb_iseq_t *iseq)
3029{
3030 int i;
3031 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3032
3033 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3034 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3035 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3036 }
3037 }
3038 return COMPILE_OK;
3039}
3040
3041static LINK_ELEMENT *
3042get_destination_insn(INSN *iobj)
3043{
3044 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3045 LINK_ELEMENT *list;
3046 rb_event_flag_t events = 0;
3047
3048 list = lobj->link.next;
3049 while (list) {
3050 switch (list->type) {
3051 case ISEQ_ELEMENT_INSN:
3052 case ISEQ_ELEMENT_ADJUST:
3053 goto found;
3054 case ISEQ_ELEMENT_LABEL:
3055 /* ignore */
3056 break;
3057 case ISEQ_ELEMENT_TRACE:
3058 {
3059 TRACE *trace = (TRACE *)list;
3060 events |= trace->event;
3061 }
3062 break;
3063 default: break;
3064 }
3065 list = list->next;
3066 }
3067 found:
3068 if (list && IS_INSN(list)) {
3069 INSN *iobj = (INSN *)list;
3070 iobj->insn_info.events |= events;
3071 }
3072 return list;
3073}
3074
3075static LINK_ELEMENT *
3076get_next_insn(INSN *iobj)
3077{
3078 LINK_ELEMENT *list = iobj->link.next;
3079
3080 while (list) {
3081 if (IS_INSN(list) || IS_ADJUST(list)) {
3082 return list;
3083 }
3084 list = list->next;
3085 }
3086 return 0;
3087}
3088
3089static LINK_ELEMENT *
3090get_prev_insn(INSN *iobj)
3091{
3092 LINK_ELEMENT *list = iobj->link.prev;
3093
3094 while (list) {
3095 if (IS_INSN(list) || IS_ADJUST(list)) {
3096 return list;
3097 }
3098 list = list->prev;
3099 }
3100 return 0;
3101}
3102
3103static void
3104unref_destination(INSN *iobj, int pos)
3105{
3106 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3107 --lobj->refcnt;
3108 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3109}
3110
3111static bool
3112replace_destination(INSN *dobj, INSN *nobj)
3113{
3114 VALUE n = OPERAND_AT(nobj, 0);
3115 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3116 LABEL *nl = (LABEL *)n;
3117 if (dl == nl) return false;
3118 --dl->refcnt;
3119 ++nl->refcnt;
3120 OPERAND_AT(dobj, 0) = n;
3121 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3122 return true;
3123}
3124
3125static LABEL*
3126find_destination(INSN *i)
3127{
3128 int pos, len = insn_len(i->insn_id);
3129 for (pos = 0; pos < len; ++pos) {
3130 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3131 return (LABEL *)OPERAND_AT(i, pos);
3132 }
3133 }
3134 return 0;
3135}
3136
3137static int
3138remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3139{
3140 LINK_ELEMENT *first = i, *end;
3141 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3142
3143 if (!i) return 0;
3144 unref_counts = ALLOCA_N(int, nlabels);
3145 MEMZERO(unref_counts, int, nlabels);
3146 end = i;
3147 do {
3148 LABEL *lab;
3149 if (IS_INSN(i)) {
3150 if (IS_INSN_ID(i, leave)) {
3151 end = i;
3152 break;
3153 }
3154 else if ((lab = find_destination((INSN *)i)) != 0) {
3155 unref_counts[lab->label_no]++;
3156 }
3157 }
3158 else if (IS_LABEL(i)) {
3159 lab = (LABEL *)i;
3160 if (lab->unremovable) return 0;
3161 if (lab->refcnt > unref_counts[lab->label_no]) {
3162 if (i == first) return 0;
3163 break;
3164 }
3165 continue;
3166 }
3167 else if (IS_TRACE(i)) {
3168 /* do nothing */
3169 }
3170 else if (IS_ADJUST(i)) {
3171 return 0;
3172 }
3173 end = i;
3174 } while ((i = i->next) != 0);
3175 i = first;
3176 do {
3177 if (IS_INSN(i)) {
3178 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3179 VALUE insn = INSN_OF(i);
3180 int pos, len = insn_len(insn);
3181 for (pos = 0; pos < len; ++pos) {
3182 switch (insn_op_types(insn)[pos]) {
3183 case TS_OFFSET:
3184 unref_destination((INSN *)i, pos);
3185 break;
3186 case TS_CALLDATA:
3187 --(body->ci_size);
3188 break;
3189 }
3190 }
3191 }
3192 ELEM_REMOVE(i);
3193 } while ((i != end) && (i = i->next) != 0);
3194 return 1;
3195}
3196
3197static int
3198iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3199{
3200 switch (OPERAND_AT(iobj, 0)) {
3201 case INT2FIX(0): /* empty array */
3202 ELEM_REMOVE(&iobj->link);
3203 return TRUE;
3204 case INT2FIX(1): /* single element array */
3205 ELEM_REMOVE(&iobj->link);
3206 return FALSE;
3207 default:
3208 iobj->insn_id = BIN(adjuststack);
3209 return TRUE;
3210 }
3211}
3212
3213static int
3214is_frozen_putstring(INSN *insn, VALUE *op)
3215{
3216 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3217 *op = OPERAND_AT(insn, 0);
3218 return 1;
3219 }
3220 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3221 *op = OPERAND_AT(insn, 0);
3222 return RB_TYPE_P(*op, T_STRING);
3223 }
3224 return 0;
3225}
3226
3227static int
3228insn_has_label_before(LINK_ELEMENT *elem)
3229{
3230 LINK_ELEMENT *prev = elem->prev;
3231 while (prev) {
3232 if (prev->type == ISEQ_ELEMENT_LABEL) {
3233 LABEL *label = (LABEL *)prev;
3234 if (label->refcnt > 0) {
3235 return 1;
3236 }
3237 }
3238 else if (prev->type == ISEQ_ELEMENT_INSN) {
3239 break;
3240 }
3241 prev = prev->prev;
3242 }
3243 return 0;
3244}
3245
3246static int
3247optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3248{
3249 /*
3250 * putobject obj
3251 * dup
3252 * checktype T_XXX
3253 * branchif l1
3254 * l2:
3255 * ...
3256 * l1:
3257 *
3258 * => obj is a T_XXX
3259 *
3260 * putobject obj (T_XXX)
3261 * jump L1
3262 * L1:
3263 *
3264 * => obj is not a T_XXX
3265 *
3266 * putobject obj (T_XXX)
3267 * jump L2
3268 * L2:
3269 */
3270 int line, node_id;
3271 INSN *niobj, *ciobj, *dup = 0;
3272 LABEL *dest = 0;
3273 VALUE type;
3274
3275 switch (INSN_OF(iobj)) {
3276 case BIN(putstring):
3277 case BIN(putchilledstring):
3279 break;
3280 case BIN(putnil):
3281 type = INT2FIX(T_NIL);
3282 break;
3283 case BIN(putobject):
3284 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3285 break;
3286 default: return FALSE;
3287 }
3288
3289 ciobj = (INSN *)get_next_insn(iobj);
3290 if (IS_INSN_ID(ciobj, jump)) {
3291 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3292 }
3293 if (IS_INSN_ID(ciobj, dup)) {
3294 ciobj = (INSN *)get_next_insn(dup = ciobj);
3295 }
3296 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3297 niobj = (INSN *)get_next_insn(ciobj);
3298 if (!niobj) {
3299 /* TODO: putobject true/false */
3300 return FALSE;
3301 }
3302 switch (INSN_OF(niobj)) {
3303 case BIN(branchif):
3304 if (OPERAND_AT(ciobj, 0) == type) {
3305 dest = (LABEL *)OPERAND_AT(niobj, 0);
3306 }
3307 break;
3308 case BIN(branchunless):
3309 if (OPERAND_AT(ciobj, 0) != type) {
3310 dest = (LABEL *)OPERAND_AT(niobj, 0);
3311 }
3312 break;
3313 default:
3314 return FALSE;
3315 }
3316 line = ciobj->insn_info.line_no;
3317 node_id = ciobj->insn_info.node_id;
3318 if (!dest) {
3319 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3320 dest = (LABEL *)niobj->link.next; /* reuse label */
3321 }
3322 else {
3323 dest = NEW_LABEL(line);
3324 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3325 }
3326 }
3327 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3328 LABEL_REF(dest);
3329 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3330 return TRUE;
3331}
3332
3333static const struct rb_callinfo *
3334ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3335{
3336 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3337 vm_ci_flag(ci) | add,
3338 vm_ci_argc(ci),
3339 vm_ci_kwarg(ci));
3340 RB_OBJ_WRITTEN(iseq, ci, nci);
3341 return nci;
3342}
3343
3344static const struct rb_callinfo *
3345ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3346{
3347 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3348 vm_ci_flag(ci),
3349 argc,
3350 vm_ci_kwarg(ci));
3351 RB_OBJ_WRITTEN(iseq, ci, nci);
3352 return nci;
3353}
3354
3355#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3356
3357static int
3358iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3359{
3360 INSN *const iobj = (INSN *)list;
3361
3362 again:
3363 optimize_checktype(iseq, iobj);
3364
3365 if (IS_INSN_ID(iobj, jump)) {
3366 INSN *niobj, *diobj, *piobj;
3367 diobj = (INSN *)get_destination_insn(iobj);
3368 niobj = (INSN *)get_next_insn(iobj);
3369
3370 if (diobj == niobj) {
3371 /*
3372 * jump LABEL
3373 * LABEL:
3374 * =>
3375 * LABEL:
3376 */
3377 unref_destination(iobj, 0);
3378 ELEM_REMOVE(&iobj->link);
3379 return COMPILE_OK;
3380 }
3381 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3382 IS_INSN_ID(diobj, jump) &&
3383 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3384 diobj->insn_info.events == 0) {
3385 /*
3386 * useless jump elimination:
3387 * jump LABEL1
3388 * ...
3389 * LABEL1:
3390 * jump LABEL2
3391 *
3392 * => in this case, first jump instruction should jump to
3393 * LABEL2 directly
3394 */
3395 if (replace_destination(iobj, diobj)) {
3396 remove_unreachable_chunk(iseq, iobj->link.next);
3397 goto again;
3398 }
3399 }
3400 else if (IS_INSN_ID(diobj, leave)) {
3401 /*
3402 * jump LABEL
3403 * ...
3404 * LABEL:
3405 * leave
3406 * =>
3407 * leave
3408 * ...
3409 * LABEL:
3410 * leave
3411 */
3412 /* replace */
3413 unref_destination(iobj, 0);
3414 iobj->insn_id = BIN(leave);
3415 iobj->operand_size = 0;
3416 iobj->insn_info = diobj->insn_info;
3417 goto again;
3418 }
3419 else if (IS_INSN(iobj->link.prev) &&
3420 (piobj = (INSN *)iobj->link.prev) &&
3421 (IS_INSN_ID(piobj, branchif) ||
3422 IS_INSN_ID(piobj, branchunless))) {
3423 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3424 if (niobj == pdiobj) {
3425 int refcnt = IS_LABEL(piobj->link.next) ?
3426 ((LABEL *)piobj->link.next)->refcnt : 0;
3427 /*
3428 * useless jump elimination (if/unless destination):
3429 * if L1
3430 * jump L2
3431 * L1:
3432 * ...
3433 * L2:
3434 *
3435 * ==>
3436 * unless L2
3437 * L1:
3438 * ...
3439 * L2:
3440 */
3441 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3442 ? BIN(branchunless) : BIN(branchif);
3443 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3444 ELEM_REMOVE(&iobj->link);
3445 }
3446 else {
3447 /* TODO: replace other branch destinations too */
3448 }
3449 return COMPILE_OK;
3450 }
3451 else if (diobj == pdiobj) {
3452 /*
3453 * useless jump elimination (if/unless before jump):
3454 * L1:
3455 * ...
3456 * if L1
3457 * jump L1
3458 *
3459 * ==>
3460 * L1:
3461 * ...
3462 * pop
3463 * jump L1
3464 */
3465 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3466 ELEM_REPLACE(&piobj->link, &popiobj->link);
3467 }
3468 }
3469 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3470 goto again;
3471 }
3472 }
3473
3474 /*
3475 * putstring "beg"
3476 * putstring "end"
3477 * newrange excl
3478 *
3479 * ==>
3480 *
3481 * putobject "beg".."end"
3482 */
3483 if (IS_INSN_ID(iobj, newrange)) {
3484 INSN *const range = iobj;
3485 INSN *beg, *end;
3486 VALUE str_beg, str_end;
3487
3488 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3489 is_frozen_putstring(end, &str_end) &&
3490 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3491 is_frozen_putstring(beg, &str_beg) &&
3492 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3493 int excl = FIX2INT(OPERAND_AT(range, 0));
3494 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3495
3496 ELEM_REMOVE(&beg->link);
3497 ELEM_REMOVE(&end->link);
3498 range->insn_id = BIN(putobject);
3499 OPERAND_AT(range, 0) = lit_range;
3500 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3501 }
3502 }
3503
3504 if (IS_INSN_ID(iobj, leave)) {
3505 remove_unreachable_chunk(iseq, iobj->link.next);
3506 }
3507
3508 /*
3509 * ...
3510 * duparray [...]
3511 * concatarray | concattoarray
3512 * =>
3513 * ...
3514 * putobject [...]
3515 * concatarray | concattoarray
3516 */
3517 if (IS_INSN_ID(iobj, duparray)) {
3518 LINK_ELEMENT *next = iobj->link.next;
3519 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3520 iobj->insn_id = BIN(putobject);
3521 }
3522 }
3523
3524 /*
3525 * duparray [...]
3526 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3527 * =>
3528 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3529 */
3530 if (IS_INSN_ID(iobj, duparray)) {
3531 LINK_ELEMENT *next = iobj->link.next;
3532 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3533 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3534 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3535
3536 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3537 VALUE ary = iobj->operands[0];
3539
3540 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3541 ELEM_REMOVE(next);
3542 }
3543 }
3544 }
3545
3546 /*
3547 * duphash {...}
3548 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3549 * =>
3550 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3551 */
3552 if (IS_INSN_ID(iobj, duphash)) {
3553 LINK_ELEMENT *next = iobj->link.next;
3554 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3555 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3556 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3557
3558 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3559 VALUE hash = iobj->operands[0];
3560 rb_obj_reveal(hash, rb_cHash);
3561 RB_OBJ_SET_SHAREABLE(hash);
3562
3563 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3564 ELEM_REMOVE(next);
3565 }
3566 }
3567 }
3568
3569 /*
3570 * newarray 0
3571 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3572 * =>
3573 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3574 */
3575 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3576 LINK_ELEMENT *next = iobj->link.next;
3577 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3578 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3579 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3580
3581 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3582 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3583 ELEM_REMOVE(next);
3584 }
3585 }
3586 }
3587
3588 /*
3589 * newhash 0
3590 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3591 * =>
3592 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3593 */
3594 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3595 LINK_ELEMENT *next = iobj->link.next;
3596 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3597 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3598 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3599
3600 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3601 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3602 ELEM_REMOVE(next);
3603 }
3604 }
3605 }
3606
3607 if (IS_INSN_ID(iobj, branchif) ||
3608 IS_INSN_ID(iobj, branchnil) ||
3609 IS_INSN_ID(iobj, branchunless)) {
3610 /*
3611 * if L1
3612 * ...
3613 * L1:
3614 * jump L2
3615 * =>
3616 * if L2
3617 */
3618 INSN *nobj = (INSN *)get_destination_insn(iobj);
3619
3620 /* This is super nasty hack!!!
3621 *
3622 * This jump-jump optimization may ignore event flags of the jump
3623 * instruction being skipped. Actually, Line 2 TracePoint event
3624 * is never fired in the following code:
3625 *
3626 * 1: raise if 1 == 2
3627 * 2: while true
3628 * 3: break
3629 * 4: end
3630 *
3631 * This is critical for coverage measurement. [Bug #15980]
3632 *
3633 * This is a stopgap measure: stop the jump-jump optimization if
3634 * coverage measurement is enabled and if the skipped instruction
3635 * has any event flag.
3636 *
3637 * Note that, still, TracePoint Line event does not occur on Line 2.
3638 * This should be fixed in future.
3639 */
3640 int stop_optimization =
3641 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3642 nobj->link.type == ISEQ_ELEMENT_INSN &&
3643 nobj->insn_info.events;
3644 if (!stop_optimization) {
3645 INSN *pobj = (INSN *)iobj->link.prev;
3646 int prev_dup = 0;
3647 if (pobj) {
3648 if (!IS_INSN(&pobj->link))
3649 pobj = 0;
3650 else if (IS_INSN_ID(pobj, dup))
3651 prev_dup = 1;
3652 }
3653
3654 for (;;) {
3655 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3656 if (!replace_destination(iobj, nobj)) break;
3657 }
3658 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3659 !!(nobj = (INSN *)nobj->link.next) &&
3660 /* basic blocks, with no labels in the middle */
3661 nobj->insn_id == iobj->insn_id) {
3662 /*
3663 * dup
3664 * if L1
3665 * ...
3666 * L1:
3667 * dup
3668 * if L2
3669 * =>
3670 * dup
3671 * if L2
3672 * ...
3673 * L1:
3674 * dup
3675 * if L2
3676 */
3677 if (!replace_destination(iobj, nobj)) break;
3678 }
3679 else if (pobj) {
3680 /*
3681 * putnil
3682 * if L1
3683 * =>
3684 * # nothing
3685 *
3686 * putobject true
3687 * if L1
3688 * =>
3689 * jump L1
3690 *
3691 * putstring ".."
3692 * if L1
3693 * =>
3694 * jump L1
3695 *
3696 * putstring ".."
3697 * dup
3698 * if L1
3699 * =>
3700 * putstring ".."
3701 * jump L1
3702 *
3703 */
3704 int cond;
3705 if (prev_dup && IS_INSN(pobj->link.prev)) {
3706 pobj = (INSN *)pobj->link.prev;
3707 }
3708 if (IS_INSN_ID(pobj, putobject)) {
3709 cond = (IS_INSN_ID(iobj, branchif) ?
3710 OPERAND_AT(pobj, 0) != Qfalse :
3711 IS_INSN_ID(iobj, branchunless) ?
3712 OPERAND_AT(pobj, 0) == Qfalse :
3713 FALSE);
3714 }
3715 else if (IS_INSN_ID(pobj, putstring) ||
3716 IS_INSN_ID(pobj, duparray) ||
3717 IS_INSN_ID(pobj, newarray)) {
3718 cond = IS_INSN_ID(iobj, branchif);
3719 }
3720 else if (IS_INSN_ID(pobj, putnil)) {
3721 cond = !IS_INSN_ID(iobj, branchif);
3722 }
3723 else break;
3724 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3725 ELEM_REMOVE(iobj->link.prev);
3726 }
3727 else if (!iseq_pop_newarray(iseq, pobj)) {
3728 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3729 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3730 }
3731 if (cond) {
3732 if (prev_dup) {
3733 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3734 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3735 }
3736 iobj->insn_id = BIN(jump);
3737 goto again;
3738 }
3739 else {
3740 unref_destination(iobj, 0);
3741 ELEM_REMOVE(&iobj->link);
3742 }
3743 break;
3744 }
3745 else break;
3746 nobj = (INSN *)get_destination_insn(nobj);
3747 }
3748 }
3749 }
3750
3751 if (IS_INSN_ID(iobj, pop)) {
3752 /*
3753 * putself / putnil / putobject obj / putstring "..."
3754 * pop
3755 * =>
3756 * # do nothing
3757 */
3758 LINK_ELEMENT *prev = iobj->link.prev;
3759 if (IS_INSN(prev)) {
3760 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3761 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3762 previ == BIN(putself) || previ == BIN(putstring) ||
3763 previ == BIN(putchilledstring) ||
3764 previ == BIN(dup) ||
3765 previ == BIN(getlocal) ||
3766 previ == BIN(getblockparam) ||
3767 previ == BIN(getblockparamproxy) ||
3768 previ == BIN(getinstancevariable) ||
3769 previ == BIN(duparray)) {
3770 /* just push operand or static value and pop soon, no
3771 * side effects */
3772 ELEM_REMOVE(prev);
3773 ELEM_REMOVE(&iobj->link);
3774 }
3775 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3776 ELEM_REMOVE(&iobj->link);
3777 }
3778 else if (previ == BIN(concatarray)) {
3779 INSN *piobj = (INSN *)prev;
3780 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3781 INSN_OF(piobj) = BIN(pop);
3782 }
3783 else if (previ == BIN(concatstrings)) {
3784 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3785 ELEM_REMOVE(prev);
3786 }
3787 else {
3788 ELEM_REMOVE(&iobj->link);
3789 INSN_OF(prev) = BIN(adjuststack);
3790 }
3791 }
3792 }
3793 }
3794
3795 if (IS_INSN_ID(iobj, newarray) ||
3796 IS_INSN_ID(iobj, duparray) ||
3797 IS_INSN_ID(iobj, concatarray) ||
3798 IS_INSN_ID(iobj, splatarray) ||
3799 0) {
3800 /*
3801 * newarray N
3802 * splatarray
3803 * =>
3804 * newarray N
3805 * newarray always puts an array
3806 */
3807 LINK_ELEMENT *next = iobj->link.next;
3808 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3809 /* remove splatarray following always-array insn */
3810 ELEM_REMOVE(next);
3811 }
3812 }
3813
3814 if (IS_INSN_ID(iobj, newarray)) {
3815 LINK_ELEMENT *next = iobj->link.next;
3816 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3817 OPERAND_AT(next, 1) == INT2FIX(0)) {
3818 VALUE op1, op2;
3819 op1 = OPERAND_AT(iobj, 0);
3820 op2 = OPERAND_AT(next, 0);
3821 ELEM_REMOVE(next);
3822
3823 if (op1 == op2) {
3824 /*
3825 * newarray 2
3826 * expandarray 2, 0
3827 * =>
3828 * swap
3829 */
3830 if (op1 == INT2FIX(2)) {
3831 INSN_OF(iobj) = BIN(swap);
3832 iobj->operand_size = 0;
3833 }
3834 /*
3835 * newarray X
3836 * expandarray X, 0
3837 * =>
3838 * opt_reverse X
3839 */
3840 else {
3841 INSN_OF(iobj) = BIN(opt_reverse);
3842 }
3843 }
3844 else {
3845 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3846 INSN_OF(iobj) = BIN(opt_reverse);
3847 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3848
3849 if (op1 > op2) {
3850 /* X > Y
3851 * newarray X
3852 * expandarray Y, 0
3853 * =>
3854 * pop * (Y-X)
3855 * opt_reverse Y
3856 */
3857 for (; diff > 0; diff--) {
3858 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3859 }
3860 }
3861 else { /* (op1 < op2) */
3862 /* X < Y
3863 * newarray X
3864 * expandarray Y, 0
3865 * =>
3866 * putnil * (Y-X)
3867 * opt_reverse Y
3868 */
3869 for (; diff < 0; diff++) {
3870 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3871 }
3872 }
3873 }
3874 }
3875 }
3876
3877 if (IS_INSN_ID(iobj, duparray)) {
3878 LINK_ELEMENT *next = iobj->link.next;
3879 /*
3880 * duparray obj
3881 * expandarray X, 0
3882 * =>
3883 * putobject obj
3884 * expandarray X, 0
3885 */
3886 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3887 INSN_OF(iobj) = BIN(putobject);
3888 }
3889 }
3890
3891 if (IS_INSN_ID(iobj, anytostring)) {
3892 LINK_ELEMENT *next = iobj->link.next;
3893 /*
3894 * anytostring
3895 * concatstrings 1
3896 * =>
3897 * anytostring
3898 */
3899 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3900 OPERAND_AT(next, 0) == INT2FIX(1)) {
3901 ELEM_REMOVE(next);
3902 }
3903 }
3904
3905 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3906 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3907 /*
3908 * putstring ""
3909 * concatstrings N
3910 * =>
3911 * concatstrings N-1
3912 */
3913 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3914 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3915 INSN *next = (INSN *)iobj->link.next;
3916 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3917 ELEM_REMOVE(&next->link);
3918 }
3919 ELEM_REMOVE(&iobj->link);
3920 }
3921 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3922 INSN *next = (INSN *)iobj->link.next;
3923 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3924 VALUE src = OPERAND_AT(iobj, 0);
3925 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3926 VALUE path = rb_iseq_path(iseq);
3927 int line = iobj->insn_info.line_no;
3928 VALUE errinfo = rb_errinfo();
3929 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3930 if (NIL_P(re)) {
3931 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3932 rb_set_errinfo(errinfo);
3933 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3934 }
3935 else {
3936 RB_OBJ_SET_SHAREABLE(re);
3937 }
3938 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3939 ELEM_REMOVE(iobj->link.next);
3940 }
3941 }
3942 }
3943
3944 if (IS_INSN_ID(iobj, concatstrings)) {
3945 /*
3946 * concatstrings N
3947 * concatstrings M
3948 * =>
3949 * concatstrings N+M-1
3950 */
3951 LINK_ELEMENT *next = iobj->link.next;
3952 INSN *jump = 0;
3953 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3954 next = get_destination_insn(jump = (INSN *)next);
3955 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3956 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3957 OPERAND_AT(iobj, 0) = INT2FIX(n);
3958 if (jump) {
3959 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3960 if (!--label->refcnt) {
3961 ELEM_REMOVE(&label->link);
3962 }
3963 else {
3964 label = NEW_LABEL(0);
3965 OPERAND_AT(jump, 0) = (VALUE)label;
3966 }
3967 label->refcnt++;
3968 ELEM_INSERT_NEXT(next, &label->link);
3969 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3970 }
3971 else {
3972 ELEM_REMOVE(next);
3973 }
3974 }
3975 }
3976
3977 if (do_tailcallopt &&
3978 (IS_INSN_ID(iobj, send) ||
3979 IS_INSN_ID(iobj, invokesuper))) {
3980 /*
3981 * send ...
3982 * leave
3983 * =>
3984 * send ..., ... | VM_CALL_TAILCALL, ...
3985 * leave # unreachable
3986 */
3987 INSN *piobj = NULL;
3988 if (iobj->link.next) {
3989 LINK_ELEMENT *next = iobj->link.next;
3990 do {
3991 if (!IS_INSN(next)) {
3992 next = next->next;
3993 continue;
3994 }
3995 switch (INSN_OF(next)) {
3996 case BIN(nop):
3997 next = next->next;
3998 break;
3999 case BIN(jump):
4000 /* if cond
4001 * return tailcall
4002 * end
4003 */
4004 next = get_destination_insn((INSN *)next);
4005 break;
4006 case BIN(leave):
4007 piobj = iobj;
4008 /* fall through */
4009 default:
4010 next = NULL;
4011 break;
4012 }
4013 } while (next);
4014 }
4015
4016 if (piobj) {
4017 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4018 if (IS_INSN_ID(piobj, send) ||
4019 IS_INSN_ID(piobj, invokesuper)) {
4020 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4021 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4022 OPERAND_AT(piobj, 0) = (VALUE)ci;
4023 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4024 }
4025 }
4026 else {
4027 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4028 OPERAND_AT(piobj, 0) = (VALUE)ci;
4029 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4030 }
4031 }
4032 }
4033
4034 if (IS_INSN_ID(iobj, dup)) {
4035 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4036 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4037
4038 /*
4039 * dup
4040 * setlocal x, y
4041 * setlocal x, y
4042 * =>
4043 * dup
4044 * setlocal x, y
4045 */
4046 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4047 set2 = set1->next;
4048 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4049 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4050 ELEM_REMOVE(set1);
4051 ELEM_REMOVE(&iobj->link);
4052 }
4053 }
4054
4055 /*
4056 * dup
4057 * setlocal x, y
4058 * dup
4059 * setlocal x, y
4060 * =>
4061 * dup
4062 * setlocal x, y
4063 */
4064 else if (IS_NEXT_INSN_ID(set1, dup) &&
4065 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4066 set2 = set1->next->next;
4067 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4068 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4069 ELEM_REMOVE(set1->next);
4070 ELEM_REMOVE(set2);
4071 }
4072 }
4073 }
4074 }
4075
4076 /*
4077 * getlocal x, y
4078 * dup
4079 * setlocal x, y
4080 * =>
4081 * dup
4082 */
4083 if (IS_INSN_ID(iobj, getlocal)) {
4084 LINK_ELEMENT *niobj = &iobj->link;
4085 if (IS_NEXT_INSN_ID(niobj, dup)) {
4086 niobj = niobj->next;
4087 }
4088 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4089 LINK_ELEMENT *set1 = niobj->next;
4090 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4091 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4092 ELEM_REMOVE(set1);
4093 ELEM_REMOVE(niobj);
4094 }
4095 }
4096 }
4097
4098 /*
4099 * opt_invokebuiltin_delegate
4100 * trace
4101 * leave
4102 * =>
4103 * opt_invokebuiltin_delegate_leave
4104 * trace
4105 * leave
4106 */
4107 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4108 if (IS_TRACE(iobj->link.next)) {
4109 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4110 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4111 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4112 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4113 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4114 }
4115 }
4116 }
4117 }
4118
4119 /*
4120 * getblockparam
4121 * branchif / branchunless
4122 * =>
4123 * getblockparamproxy
4124 * branchif / branchunless
4125 */
4126 if (IS_INSN_ID(iobj, getblockparam)) {
4127 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4128 iobj->insn_id = BIN(getblockparamproxy);
4129 }
4130 }
4131
4132 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4133 LINK_ELEMENT *niobj = &iobj->link;
4134 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4135 niobj = niobj->next;
4136 LINK_ELEMENT *siobj;
4137 unsigned int set_flags = 0, unset_flags = 0;
4138
4139 /*
4140 * Eliminate hash allocation for f(*a, kw: 1)
4141 *
4142 * splatarray false
4143 * duphash
4144 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4145 * =>
4146 * splatarray false
4147 * putobject
4148 * send ARGS_SPLAT|KW_SPLAT
4149 */
4150 if (IS_NEXT_INSN_ID(niobj, send)) {
4151 siobj = niobj->next;
4152 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4153 unset_flags = VM_CALL_ARGS_BLOCKARG;
4154 }
4155 /*
4156 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4157 *
4158 * splatarray false
4159 * duphash
4160 * getlocal / getinstancevariable / getblockparamproxy
4161 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4162 * =>
4163 * splatarray false
4164 * putobject
4165 * getlocal / getinstancevariable / getblockparamproxy
4166 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4167 */
4168 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4169 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4170 siobj = niobj->next->next;
4171 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4172 }
4173
4174 if (set_flags) {
4175 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4176 unsigned int flags = vm_ci_flag(ci);
4177 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4178 ((INSN*)niobj)->insn_id = BIN(putobject);
4179 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4180
4181 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4182 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4183 RB_OBJ_WRITTEN(iseq, ci, nci);
4184 OPERAND_AT(siobj, 0) = (VALUE)nci;
4185 }
4186 }
4187 }
4188 }
4189
4190 return COMPILE_OK;
4191}
4192
4193static int
4194insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4195{
4196 if (insn_id == BIN(opt_neq)) {
4197 VALUE original_ci = iobj->operands[0];
4198 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4199 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4200 }
4201 else {
4202 iobj->insn_id = insn_id;
4203 iobj->operand_size = insn_len(insn_id) - 1;
4204 }
4205 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4206
4207 return COMPILE_OK;
4208}
4209
4210static int
4211iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4212{
4213 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4214 IS_INSN(iobj->link.next)) {
4215 /*
4216 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4217 */
4218 INSN *niobj = (INSN *)iobj->link.next;
4219 if (IS_INSN_ID(niobj, send)) {
4220 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4221 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4222 VALUE method = INT2FIX(0);
4223 switch (vm_ci_mid(ci)) {
4224 case idMax:
4225 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4226 break;
4227 case idMin:
4228 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4229 break;
4230 case idHash:
4231 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4232 break;
4233 }
4234
4235 if (method != INT2FIX(0)) {
4236 VALUE num = iobj->operands[0];
4237 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4238 ELEM_REMOVE(&niobj->link);
4239 return COMPILE_OK;
4240 }
4241 }
4242 }
4243 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4244 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4245 IS_NEXT_INSN_ID(&niobj->link, send)) {
4246 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4247 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4248 VALUE num = iobj->operands[0];
4249 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4250 ELEM_REMOVE(&iobj->link);
4251 ELEM_REMOVE(niobj->link.next);
4252 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4253 return COMPILE_OK;
4254 }
4255 }
4256 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4257 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4258 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4259 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4260 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4261 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4262 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4263 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4264 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4265 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4266 VALUE num = iobj->operands[0];
4267 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4268 // Remove the "send" insn.
4269 ELEM_REMOVE((niobj->link.next)->next);
4270 // Remove the modified insn from its original "newarray" position...
4271 ELEM_REMOVE(&iobj->link);
4272 // and insert it after the buffer insn.
4273 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4274 return COMPILE_OK;
4275 }
4276 }
4277
4278 // Break the "else if" chain since some prior checks abort after sub-ifs.
4279 // We already found "newarray". To match `[...].include?(arg)` we look for
4280 // the instruction(s) representing the argument followed by a "send".
4281 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4282 IS_INSN_ID(niobj, putobject) ||
4283 IS_INSN_ID(niobj, putself) ||
4284 IS_INSN_ID(niobj, getlocal) ||
4285 IS_INSN_ID(niobj, getinstancevariable)) &&
4286 IS_NEXT_INSN_ID(&niobj->link, send)) {
4287
4288 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4289 const struct rb_callinfo *ci;
4290 // Allow any number (0 or more) of simple method calls on the argument
4291 // (as in `[...].include?(arg.method1.method2)`.
4292 do {
4293 sendobj = sendobj->next;
4294 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4295 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4296
4297 // If this send is for .include? with one arg we can do our opt.
4298 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4299 VALUE num = iobj->operands[0];
4300 INSN *sendins = (INSN *)sendobj;
4301 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4302 // Remove the original "newarray" insn.
4303 ELEM_REMOVE(&iobj->link);
4304 return COMPILE_OK;
4305 }
4306 }
4307 }
4308
4309 /*
4310 * duparray [...]
4311 * some insn for the arg...
4312 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4313 * =>
4314 * arg insn...
4315 * opt_duparray_send [...], :include?, 1
4316 */
4317 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4318 INSN *niobj = (INSN *)iobj->link.next;
4319 if ((IS_INSN_ID(niobj, getlocal) ||
4320 IS_INSN_ID(niobj, getinstancevariable) ||
4321 IS_INSN_ID(niobj, putself)) &&
4322 IS_NEXT_INSN_ID(&niobj->link, send)) {
4323
4324 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4325 const struct rb_callinfo *ci;
4326 // Allow any number (0 or more) of simple method calls on the argument
4327 // (as in `[...].include?(arg.method1.method2)`.
4328 do {
4329 sendobj = sendobj->next;
4330 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4331 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4332
4333 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4334 // Move the array arg from duparray to opt_duparray_send.
4335 VALUE ary = iobj->operands[0];
4337
4338 INSN *sendins = (INSN *)sendobj;
4339 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4340
4341 // Remove the duparray insn.
4342 ELEM_REMOVE(&iobj->link);
4343 return COMPILE_OK;
4344 }
4345 }
4346 }
4347
4348
4349 if (IS_INSN_ID(iobj, send)) {
4350 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4351 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4352
4353#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4354 if (vm_ci_simple(ci)) {
4355 switch (vm_ci_argc(ci)) {
4356 case 0:
4357 switch (vm_ci_mid(ci)) {
4358 case idLength: SP_INSN(length); return COMPILE_OK;
4359 case idSize: SP_INSN(size); return COMPILE_OK;
4360 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4361 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4362 case idSucc: SP_INSN(succ); return COMPILE_OK;
4363 case idNot: SP_INSN(not); return COMPILE_OK;
4364 }
4365 break;
4366 case 1:
4367 switch (vm_ci_mid(ci)) {
4368 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4369 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4370 case idMULT: SP_INSN(mult); return COMPILE_OK;
4371 case idDIV: SP_INSN(div); return COMPILE_OK;
4372 case idMOD: SP_INSN(mod); return COMPILE_OK;
4373 case idEq: SP_INSN(eq); return COMPILE_OK;
4374 case idNeq: SP_INSN(neq); return COMPILE_OK;
4375 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4376 case idLT: SP_INSN(lt); return COMPILE_OK;
4377 case idLE: SP_INSN(le); return COMPILE_OK;
4378 case idGT: SP_INSN(gt); return COMPILE_OK;
4379 case idGE: SP_INSN(ge); return COMPILE_OK;
4380 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4381 case idAREF: SP_INSN(aref); return COMPILE_OK;
4382 case idAnd: SP_INSN(and); return COMPILE_OK;
4383 case idOr: SP_INSN(or); return COMPILE_OK;
4384 }
4385 break;
4386 case 2:
4387 switch (vm_ci_mid(ci)) {
4388 case idASET: SP_INSN(aset); return COMPILE_OK;
4389 }
4390 break;
4391 }
4392 }
4393
4394 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4395 iobj->insn_id = BIN(opt_send_without_block);
4396 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4397 }
4398 }
4399#undef SP_INSN
4400
4401 return COMPILE_OK;
4402}
4403
4404static inline int
4405tailcallable_p(rb_iseq_t *iseq)
4406{
4407 switch (ISEQ_BODY(iseq)->type) {
4408 case ISEQ_TYPE_TOP:
4409 case ISEQ_TYPE_EVAL:
4410 case ISEQ_TYPE_MAIN:
4411 /* not tail callable because cfp will be over popped */
4412 case ISEQ_TYPE_RESCUE:
4413 case ISEQ_TYPE_ENSURE:
4414 /* rescue block can't tail call because of errinfo */
4415 return FALSE;
4416 default:
4417 return TRUE;
4418 }
4419}
4420
4421static int
4422iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4423{
4424 LINK_ELEMENT *list;
4425 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4426 const int do_tailcallopt = tailcallable_p(iseq) &&
4427 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4428 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4429 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4430 int rescue_level = 0;
4431 int tailcallopt = do_tailcallopt;
4432
4433 list = FIRST_ELEMENT(anchor);
4434
4435 int do_block_optimization = 0;
4436 LABEL * block_loop_label = NULL;
4437
4438 // If we're optimizing a block
4439 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4440 do_block_optimization = 1;
4441
4442 // If the block starts with a nop and a label,
4443 // record the label so we can detect if it's a jump target
4444 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4445 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4446 block_loop_label = (LABEL *)le->next;
4447 }
4448 }
4449
4450 while (list) {
4451 if (IS_INSN(list)) {
4452 if (do_peepholeopt) {
4453 iseq_peephole_optimize(iseq, list, tailcallopt);
4454 }
4455 if (do_si) {
4456 iseq_specialized_instruction(iseq, (INSN *)list);
4457 }
4458 if (do_ou) {
4459 insn_operands_unification((INSN *)list);
4460 }
4461
4462 if (do_block_optimization) {
4463 INSN * item = (INSN *)list;
4464 // Give up if there is a throw
4465 if (IS_INSN_ID(item, throw)) {
4466 do_block_optimization = 0;
4467 }
4468 else {
4469 // If the instruction has a jump target, check if the
4470 // jump target is the block loop label
4471 const char *types = insn_op_types(item->insn_id);
4472 for (int j = 0; types[j]; j++) {
4473 if (types[j] == TS_OFFSET) {
4474 // If the jump target is equal to the block loop
4475 // label, then we can't do the optimization because
4476 // the leading `nop` instruction fires the block
4477 // entry tracepoint
4478 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4479 if (target == block_loop_label) {
4480 do_block_optimization = 0;
4481 }
4482 }
4483 }
4484 }
4485 }
4486 }
4487 if (IS_LABEL(list)) {
4488 switch (((LABEL *)list)->rescued) {
4489 case LABEL_RESCUE_BEG:
4490 rescue_level++;
4491 tailcallopt = FALSE;
4492 break;
4493 case LABEL_RESCUE_END:
4494 if (!--rescue_level) tailcallopt = do_tailcallopt;
4495 break;
4496 }
4497 }
4498 list = list->next;
4499 }
4500
4501 if (do_block_optimization) {
4502 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4503 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4504 ELEM_REMOVE(le);
4505 }
4506 }
4507 return COMPILE_OK;
4508}
4509
4510#if OPT_INSTRUCTIONS_UNIFICATION
4511static INSN *
4512new_unified_insn(rb_iseq_t *iseq,
4513 int insn_id, int size, LINK_ELEMENT *seq_list)
4514{
4515 INSN *iobj = 0;
4516 LINK_ELEMENT *list = seq_list;
4517 int i, argc = 0;
4518 VALUE *operands = 0, *ptr = 0;
4519
4520
4521 /* count argc */
4522 for (i = 0; i < size; i++) {
4523 iobj = (INSN *)list;
4524 argc += iobj->operand_size;
4525 list = list->next;
4526 }
4527
4528 if (argc > 0) {
4529 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4530 }
4531
4532 /* copy operands */
4533 list = seq_list;
4534 for (i = 0; i < size; i++) {
4535 iobj = (INSN *)list;
4536 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4537 ptr += iobj->operand_size;
4538 list = list->next;
4539 }
4540
4541 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4542}
4543#endif
4544
4545/*
4546 * This scheme can get more performance if do this optimize with
4547 * label address resolving.
4548 * It's future work (if compile time was bottle neck).
4549 */
4550static int
4551iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4552{
4553#if OPT_INSTRUCTIONS_UNIFICATION
4554 LINK_ELEMENT *list;
4555 INSN *iobj, *niobj;
4556 int id, k;
4557 intptr_t j;
4558
4559 list = FIRST_ELEMENT(anchor);
4560 while (list) {
4561 if (IS_INSN(list)) {
4562 iobj = (INSN *)list;
4563 id = iobj->insn_id;
4564 if (unified_insns_data[id] != 0) {
4565 const int *const *entry = unified_insns_data[id];
4566 for (j = 1; j < (intptr_t)entry[0]; j++) {
4567 const int *unified = entry[j];
4568 LINK_ELEMENT *li = list->next;
4569 for (k = 2; k < unified[1]; k++) {
4570 if (!IS_INSN(li) ||
4571 ((INSN *)li)->insn_id != unified[k]) {
4572 goto miss;
4573 }
4574 li = li->next;
4575 }
4576 /* matched */
4577 niobj =
4578 new_unified_insn(iseq, unified[0], unified[1] - 1,
4579 list);
4580
4581 /* insert to list */
4582 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4583 niobj->link.next = li;
4584 if (li) {
4585 li->prev = (LINK_ELEMENT *)niobj;
4586 }
4587
4588 list->prev->next = (LINK_ELEMENT *)niobj;
4589 list = (LINK_ELEMENT *)niobj;
4590 break;
4591 miss:;
4592 }
4593 }
4594 }
4595 list = list->next;
4596 }
4597#endif
4598 return COMPILE_OK;
4599}
4600
4601static int
4602all_string_result_p(const NODE *node)
4603{
4604 if (!node) return FALSE;
4605 switch (nd_type(node)) {
4606 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4607 return TRUE;
4608 case NODE_IF: case NODE_UNLESS:
4609 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4610 if (all_string_result_p(RNODE_IF(node)->nd_body))
4611 return all_string_result_p(RNODE_IF(node)->nd_else);
4612 return FALSE;
4613 case NODE_AND: case NODE_OR:
4614 if (!RNODE_AND(node)->nd_2nd)
4615 return all_string_result_p(RNODE_AND(node)->nd_1st);
4616 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4617 return FALSE;
4618 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4619 default:
4620 return FALSE;
4621 }
4622}
4623
4625 rb_iseq_t *const iseq;
4626 LINK_ANCHOR *const ret;
4627 VALUE lit;
4628 const NODE *lit_node;
4629 int cnt;
4630 int dregx;
4631};
4632
4633static int
4634append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4635{
4636 VALUE s = rb_str_new_mutable_parser_string(str);
4637 if (args->dregx) {
4638 VALUE error = rb_reg_check_preprocess(s);
4639 if (!NIL_P(error)) {
4640 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4641 return COMPILE_NG;
4642 }
4643 }
4644 if (NIL_P(args->lit)) {
4645 args->lit = s;
4646 args->lit_node = node;
4647 }
4648 else {
4649 rb_str_buf_append(args->lit, s);
4650 }
4651 return COMPILE_OK;
4652}
4653
4654static void
4655flush_dstr_fragment(struct dstr_ctxt *args)
4656{
4657 if (!NIL_P(args->lit)) {
4658 rb_iseq_t *iseq = args->iseq;
4659 VALUE lit = args->lit;
4660 args->lit = Qnil;
4661 lit = rb_fstring(lit);
4662 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4663 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4664 args->cnt++;
4665 }
4666}
4667
4668static int
4669compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4670{
4671 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4672 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4673
4674 if (str) {
4675 CHECK(append_dstr_fragment(args, node, str));
4676 }
4677
4678 while (list) {
4679 const NODE *const head = list->nd_head;
4680 if (nd_type_p(head, NODE_STR)) {
4681 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4682 }
4683 else if (nd_type_p(head, NODE_DSTR)) {
4684 CHECK(compile_dstr_fragments_0(args, head));
4685 }
4686 else {
4687 flush_dstr_fragment(args);
4688 rb_iseq_t *iseq = args->iseq;
4689 CHECK(COMPILE(args->ret, "each string", head));
4690 args->cnt++;
4691 }
4692 list = (struct RNode_LIST *)list->nd_next;
4693 }
4694 return COMPILE_OK;
4695}
4696
4697static int
4698compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4699{
4700 struct dstr_ctxt args = {
4701 .iseq = iseq, .ret = ret,
4702 .lit = Qnil, .lit_node = NULL,
4703 .cnt = 0, .dregx = dregx,
4704 };
4705 CHECK(compile_dstr_fragments_0(&args, node));
4706 flush_dstr_fragment(&args);
4707
4708 *cntp = args.cnt;
4709
4710 return COMPILE_OK;
4711}
4712
4713static int
4714compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4715{
4716 while (node && nd_type_p(node, NODE_BLOCK)) {
4717 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4718 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4719 node = RNODE_BLOCK(node)->nd_next;
4720 }
4721 if (node) {
4722 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4723 }
4724 return COMPILE_OK;
4725}
4726
4727static int
4728compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4729{
4730 int cnt;
4731 if (!RNODE_DSTR(node)->nd_next) {
4732 VALUE lit = rb_node_dstr_string_val(node);
4733 ADD_INSN1(ret, node, putstring, lit);
4734 RB_OBJ_SET_SHAREABLE(lit);
4735 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4736 }
4737 else {
4738 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4739 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4740 }
4741 return COMPILE_OK;
4742}
4743
4744static int
4745compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4746{
4747 int cnt;
4748 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4749
4750 if (!RNODE_DREGX(node)->nd_next) {
4751 if (!popped) {
4752 VALUE src = rb_node_dregx_string_val(node);
4753 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4754 RB_OBJ_SET_SHAREABLE(match);
4755 ADD_INSN1(ret, node, putobject, match);
4756 RB_OBJ_WRITTEN(iseq, Qundef, match);
4757 }
4758 return COMPILE_OK;
4759 }
4760
4761 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4762 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4763
4764 if (popped) {
4765 ADD_INSN(ret, node, pop);
4766 }
4767
4768 return COMPILE_OK;
4769}
4770
4771static int
4772compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4773 LABEL *then_label, LABEL *else_label)
4774{
4775 const int line = nd_line(node);
4776 LABEL *lend = NEW_LABEL(line);
4777 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4778 + VM_SVAR_FLIPFLOP_START;
4779 VALUE key = INT2FIX(cnt);
4780
4781 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4782 ADD_INSNL(ret, node, branchif, lend);
4783
4784 /* *flip == 0 */
4785 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4786 ADD_INSNL(ret, node, branchunless, else_label);
4787 ADD_INSN1(ret, node, putobject, Qtrue);
4788 ADD_INSN1(ret, node, setspecial, key);
4789 if (!again) {
4790 ADD_INSNL(ret, node, jump, then_label);
4791 }
4792
4793 /* *flip == 1 */
4794 ADD_LABEL(ret, lend);
4795 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4796 ADD_INSNL(ret, node, branchunless, then_label);
4797 ADD_INSN1(ret, node, putobject, Qfalse);
4798 ADD_INSN1(ret, node, setspecial, key);
4799 ADD_INSNL(ret, node, jump, then_label);
4800
4801 return COMPILE_OK;
4802}
4803
4804static int
4805compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4806 LABEL *then_label, LABEL *else_label);
4807
4808#define COMPILE_SINGLE 2
4809static int
4810compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4811 LABEL *then_label, LABEL *else_label)
4812{
4813 DECL_ANCHOR(seq);
4814 INIT_ANCHOR(seq);
4815 LABEL *label = NEW_LABEL(nd_line(cond));
4816 if (!then_label) then_label = label;
4817 else if (!else_label) else_label = label;
4818
4819 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4820
4821 if (LIST_INSN_SIZE_ONE(seq)) {
4822 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4823 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4824 return COMPILE_OK;
4825 }
4826 if (!label->refcnt) {
4827 return COMPILE_SINGLE;
4828 }
4829 ADD_LABEL(seq, label);
4830 ADD_SEQ(ret, seq);
4831 return COMPILE_OK;
4832}
4833
4834static int
4835compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4836 LABEL *then_label, LABEL *else_label)
4837{
4838 int ok;
4839 DECL_ANCHOR(ignore);
4840
4841 again:
4842 switch (nd_type(cond)) {
4843 case NODE_AND:
4844 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4845 cond = RNODE_AND(cond)->nd_2nd;
4846 if (ok == COMPILE_SINGLE) {
4847 INIT_ANCHOR(ignore);
4848 ret = ignore;
4849 then_label = NEW_LABEL(nd_line(cond));
4850 }
4851 goto again;
4852 case NODE_OR:
4853 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4854 cond = RNODE_OR(cond)->nd_2nd;
4855 if (ok == COMPILE_SINGLE) {
4856 INIT_ANCHOR(ignore);
4857 ret = ignore;
4858 else_label = NEW_LABEL(nd_line(cond));
4859 }
4860 goto again;
4861 case NODE_SYM:
4862 case NODE_LINE:
4863 case NODE_FILE:
4864 case NODE_ENCODING:
4865 case NODE_INTEGER: /* NODE_INTEGER is always true */
4866 case NODE_FLOAT: /* NODE_FLOAT is always true */
4867 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4868 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4869 case NODE_TRUE:
4870 case NODE_STR:
4871 case NODE_REGX:
4872 case NODE_ZLIST:
4873 case NODE_LAMBDA:
4874 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4875 ADD_INSNL(ret, cond, jump, then_label);
4876 return COMPILE_OK;
4877 case NODE_FALSE:
4878 case NODE_NIL:
4879 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4880 ADD_INSNL(ret, cond, jump, else_label);
4881 return COMPILE_OK;
4882 case NODE_LIST:
4883 case NODE_ARGSCAT:
4884 case NODE_DREGX:
4885 case NODE_DSTR:
4886 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4887 ADD_INSNL(ret, cond, jump, then_label);
4888 return COMPILE_OK;
4889 case NODE_FLIP2:
4890 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4891 return COMPILE_OK;
4892 case NODE_FLIP3:
4893 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4894 return COMPILE_OK;
4895 case NODE_DEFINED:
4896 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4897 break;
4898 default:
4899 {
4900 DECL_ANCHOR(cond_seq);
4901 INIT_ANCHOR(cond_seq);
4902
4903 CHECK(COMPILE(cond_seq, "branch condition", cond));
4904
4905 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4906 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4907 if (insn->insn_id == BIN(putobject)) {
4908 if (RTEST(insn->operands[0])) {
4909 ADD_INSNL(ret, cond, jump, then_label);
4910 // maybe unreachable
4911 return COMPILE_OK;
4912 }
4913 else {
4914 ADD_INSNL(ret, cond, jump, else_label);
4915 return COMPILE_OK;
4916 }
4917 }
4918 }
4919 ADD_SEQ(ret, cond_seq);
4920 }
4921 break;
4922 }
4923
4924 ADD_INSNL(ret, cond, branchunless, else_label);
4925 ADD_INSNL(ret, cond, jump, then_label);
4926 return COMPILE_OK;
4927}
4928
4929#define HASH_BRACE 1
4930
4931static int
4932keyword_node_p(const NODE *const node)
4933{
4934 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4935}
4936
4937static VALUE
4938get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4939{
4940 switch (nd_type(node)) {
4941 case NODE_SYM:
4942 return rb_node_sym_string_val(node);
4943 default:
4944 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4945 }
4946}
4947
4948static VALUE
4949node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4950{
4951 NODE *node = node_hash->nd_head;
4952 VALUE hash = rb_hash_new();
4953 VALUE ary = rb_ary_new();
4954
4955 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4956 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4957 VALUE idx = rb_hash_aref(hash, key);
4958 if (!NIL_P(idx)) {
4959 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4960 (*count_ptr)--;
4961 }
4962 rb_hash_aset(hash, key, INT2FIX(i));
4963 rb_ary_store(ary, i, Qtrue);
4964 (*count_ptr)++;
4965 }
4966
4967 return ary;
4968}
4969
4970static int
4971compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4972 const NODE *const root_node,
4973 struct rb_callinfo_kwarg **const kw_arg_ptr,
4974 unsigned int *flag)
4975{
4976 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4977 RUBY_ASSERT(kw_arg_ptr != NULL);
4978 RUBY_ASSERT(flag != NULL);
4979
4980 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4981 const NODE *node = RNODE_HASH(root_node)->nd_head;
4982 int seen_nodes = 0;
4983
4984 while (node) {
4985 const NODE *key_node = RNODE_LIST(node)->nd_head;
4986 seen_nodes++;
4987
4988 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4989 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4990 /* can be keywords */
4991 }
4992 else {
4993 if (flag) {
4994 *flag |= VM_CALL_KW_SPLAT;
4995 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4996 /* A new hash will be created for the keyword arguments
4997 * in this case, so mark the method as passing mutable
4998 * keyword splat.
4999 */
5000 *flag |= VM_CALL_KW_SPLAT_MUT;
5001 }
5002 }
5003 return FALSE;
5004 }
5005 node = RNODE_LIST(node)->nd_next; /* skip value node */
5006 node = RNODE_LIST(node)->nd_next;
5007 }
5008
5009 /* may be keywords */
5010 node = RNODE_HASH(root_node)->nd_head;
5011 {
5012 int len = 0;
5013 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5014 struct rb_callinfo_kwarg *kw_arg =
5015 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5016 VALUE *keywords = kw_arg->keywords;
5017 int i = 0;
5018 int j = 0;
5019 kw_arg->references = 0;
5020 kw_arg->keyword_len = len;
5021
5022 *kw_arg_ptr = kw_arg;
5023
5024 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5025 const NODE *key_node = RNODE_LIST(node)->nd_head;
5026 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5027 int popped = TRUE;
5028 if (rb_ary_entry(key_index, i)) {
5029 keywords[j] = get_symbol_value(iseq, key_node);
5030 j++;
5031 popped = FALSE;
5032 }
5033 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5034 }
5035 RUBY_ASSERT(j == len);
5036 return TRUE;
5037 }
5038 }
5039 return FALSE;
5040}
5041
5042static int
5043compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5044{
5045 int len = 0;
5046
5047 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5048 if (CPDEBUG > 0) {
5049 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5050 }
5051
5052 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5053 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5054 }
5055 else {
5056 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5057 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5058 }
5059 }
5060
5061 return len;
5062}
5063
5064static inline bool
5065frozen_string_literal_p(const rb_iseq_t *iseq)
5066{
5067 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5068}
5069
5070static inline bool
5071static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5072{
5073 switch (nd_type(node)) {
5074 case NODE_SYM:
5075 case NODE_REGX:
5076 case NODE_LINE:
5077 case NODE_ENCODING:
5078 case NODE_INTEGER:
5079 case NODE_FLOAT:
5080 case NODE_RATIONAL:
5081 case NODE_IMAGINARY:
5082 case NODE_NIL:
5083 case NODE_TRUE:
5084 case NODE_FALSE:
5085 return TRUE;
5086 case NODE_STR:
5087 case NODE_FILE:
5088 return hash_key || frozen_string_literal_p(iseq);
5089 default:
5090 return FALSE;
5091 }
5092}
5093
5094static inline VALUE
5095static_literal_value(const NODE *node, rb_iseq_t *iseq)
5096{
5097 switch (nd_type(node)) {
5098 case NODE_INTEGER:
5099 {
5100 VALUE lit = rb_node_integer_literal_val(node);
5101 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5102 return lit;
5103 }
5104 case NODE_FLOAT:
5105 {
5106 VALUE lit = rb_node_float_literal_val(node);
5107 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5108 return lit;
5109 }
5110 case NODE_RATIONAL:
5111 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5112 case NODE_IMAGINARY:
5113 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5114 case NODE_NIL:
5115 return Qnil;
5116 case NODE_TRUE:
5117 return Qtrue;
5118 case NODE_FALSE:
5119 return Qfalse;
5120 case NODE_SYM:
5121 return rb_node_sym_string_val(node);
5122 case NODE_REGX:
5123 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5124 case NODE_LINE:
5125 return rb_node_line_lineno_val(node);
5126 case NODE_ENCODING:
5127 return rb_node_encoding_val(node);
5128 case NODE_FILE:
5129 case NODE_STR:
5130 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5131 VALUE lit = get_string_value(node);
5132 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5133 RB_OBJ_SET_SHAREABLE(str);
5134 return str;
5135 }
5136 else {
5137 return get_string_value(node);
5138 }
5139 default:
5140 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5141 }
5142}
5143
5144static int
5145compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5146{
5147 const NODE *line_node = node;
5148
5149 if (nd_type_p(node, NODE_ZLIST)) {
5150 if (!popped) {
5151 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5152 }
5153 return 0;
5154 }
5155
5156 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5157
5158 if (popped) {
5159 for (; node; node = RNODE_LIST(node)->nd_next) {
5160 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5161 }
5162 return 1;
5163 }
5164
5165 /* Compilation of an array literal.
5166 * The following code is essentially the same as:
5167 *
5168 * for (int count = 0; node; count++; node->nd_next) {
5169 * compile(node->nd_head);
5170 * }
5171 * ADD_INSN(newarray, count);
5172 *
5173 * However, there are three points.
5174 *
5175 * - The code above causes stack overflow for a big string literal.
5176 * The following limits the stack length up to max_stack_len.
5177 *
5178 * [x1,x2,...,x10000] =>
5179 * push x1 ; push x2 ; ...; push x256; newarray 256;
5180 * push x257; push x258; ...; push x512; pushtoarray 256;
5181 * push x513; push x514; ...; push x768; pushtoarray 256;
5182 * ...
5183 *
5184 * - Long subarray can be optimized by pre-allocating a hidden array.
5185 *
5186 * [1,2,3,...,100] =>
5187 * duparray [1,2,3,...,100]
5188 *
5189 * [x, 1,2,3,...,100, z] =>
5190 * push x; newarray 1;
5191 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5192 * push z; pushtoarray 1;
5193 *
5194 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5195 * to only push it onto the array if it is not empty
5196 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5197 *
5198 * [1,2,3,**kw] =>
5199 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5200 */
5201
5202 const int max_stack_len = 0x100;
5203 const int min_tmp_ary_len = 0x40;
5204 int stack_len = 0;
5205
5206 /* Either create a new array, or push to the existing array */
5207#define FLUSH_CHUNK \
5208 if (stack_len) { \
5209 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5210 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5211 first_chunk = FALSE; \
5212 stack_len = 0; \
5213 }
5214
5215 while (node) {
5216 int count = 1;
5217
5218 /* pre-allocation check (this branch can be omittable) */
5219 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5220 /* count the elements that are optimizable */
5221 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5222 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5223 count++;
5224
5225 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5226 /* The literal contains only optimizable elements, or the subarray is long enough */
5227 VALUE ary = rb_ary_hidden_new(count);
5228
5229 /* Create a hidden array */
5230 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5231 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5232 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5233
5234 /* Emit optimized code */
5235 FLUSH_CHUNK;
5236 if (first_chunk) {
5237 ADD_INSN1(ret, line_node, duparray, ary);
5238 first_chunk = FALSE;
5239 }
5240 else {
5241 ADD_INSN1(ret, line_node, putobject, ary);
5242 ADD_INSN(ret, line_node, concattoarray);
5243 }
5244 RB_OBJ_SET_SHAREABLE(ary);
5245 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5246 }
5247 }
5248
5249 /* Base case: Compile "count" elements */
5250 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5251 if (CPDEBUG > 0) {
5252 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5253 }
5254
5255 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5256 /* Create array or push existing non-keyword elements onto array */
5257 if (stack_len == 0 && first_chunk) {
5258 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5259 }
5260 else {
5261 FLUSH_CHUNK;
5262 }
5263 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5264 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5265 return 1;
5266 }
5267 else {
5268 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5269 stack_len++;
5270 }
5271
5272 /* If there are many pushed elements, flush them to avoid stack overflow */
5273 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5274 }
5275 }
5276
5277 FLUSH_CHUNK;
5278#undef FLUSH_CHUNK
5279 return 1;
5280}
5281
5282static inline int
5283static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5284{
5285 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);
5286}
5287
5288static int
5289compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5290{
5291 const NODE *line_node = node;
5292
5293 node = RNODE_HASH(node)->nd_head;
5294
5295 if (!node || nd_type_p(node, NODE_ZLIST)) {
5296 if (!popped) {
5297 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5298 }
5299 return 0;
5300 }
5301
5302 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5303
5304 if (popped) {
5305 for (; node; node = RNODE_LIST(node)->nd_next) {
5306 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5307 }
5308 return 1;
5309 }
5310
5311 /* Compilation of a hash literal (or keyword arguments).
5312 * This is very similar to compile_array, but there are some differences:
5313 *
5314 * - It contains key-value pairs. So we need to take every two elements.
5315 * We can assume that the length is always even.
5316 *
5317 * - Merging is done by a method call (id_core_hash_merge_ptr).
5318 * Sometimes we need to insert the receiver, so "anchor" is needed.
5319 * In addition, a method call is much slower than concatarray.
5320 * So it pays only when the subsequence is really long.
5321 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5322 *
5323 * - We need to handle keyword splat: **kw.
5324 * For **kw, the key part (node->nd_head) is NULL, and the value part
5325 * (node->nd_next->nd_head) is "kw".
5326 * The code is a bit difficult to avoid hash allocation for **{}.
5327 */
5328
5329 const int max_stack_len = 0x100;
5330 const int min_tmp_hash_len = 0x800;
5331 int stack_len = 0;
5332 int first_chunk = 1;
5333 DECL_ANCHOR(anchor);
5334 INIT_ANCHOR(anchor);
5335
5336 /* Convert pushed elements to a hash, and merge if needed */
5337#define FLUSH_CHUNK() \
5338 if (stack_len) { \
5339 if (first_chunk) { \
5340 APPEND_LIST(ret, anchor); \
5341 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5342 } \
5343 else { \
5344 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5345 ADD_INSN(ret, line_node, swap); \
5346 APPEND_LIST(ret, anchor); \
5347 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5348 } \
5349 INIT_ANCHOR(anchor); \
5350 first_chunk = stack_len = 0; \
5351 }
5352
5353 while (node) {
5354 int count = 1;
5355
5356 /* pre-allocation check (this branch can be omittable) */
5357 if (static_literal_node_pair_p(node, iseq)) {
5358 /* count the elements that are optimizable */
5359 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5360 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5361 count++;
5362
5363 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5364 /* The literal contains only optimizable elements, or the subsequence is long enough */
5365 VALUE ary = rb_ary_hidden_new(count);
5366
5367 /* Create a hidden hash */
5368 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5369 VALUE elem[2];
5370 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5371 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5372 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5373 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5374 rb_ary_cat(ary, elem, 2);
5375 }
5376 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5377 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5378 hash = RB_OBJ_SET_FROZEN_SHAREABLE(rb_obj_hide(hash));
5379
5380 /* Emit optimized code */
5381 FLUSH_CHUNK();
5382 if (first_chunk) {
5383 ADD_INSN1(ret, line_node, duphash, hash);
5384 first_chunk = 0;
5385 }
5386 else {
5387 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5388 ADD_INSN(ret, line_node, swap);
5389
5390 ADD_INSN1(ret, line_node, putobject, hash);
5391
5392 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5393 }
5394 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5395 }
5396 }
5397
5398 /* Base case: Compile "count" elements */
5399 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5400
5401 if (CPDEBUG > 0) {
5402 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5403 }
5404
5405 if (RNODE_LIST(node)->nd_head) {
5406 /* Normal key-value pair */
5407 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5408 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5409 stack_len += 2;
5410
5411 /* If there are many pushed elements, flush them to avoid stack overflow */
5412 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5413 }
5414 else {
5415 /* kwsplat case: foo(..., **kw, ...) */
5416 FLUSH_CHUNK();
5417
5418 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5419 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5420 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5421 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5422 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5423
5424 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5425 if (empty_kw) {
5426 if (only_kw && method_call_keywords) {
5427 /* **{} appears at the only keyword argument in method call,
5428 * so it won't be modified.
5429 * kw is a special NODE_LIT that contains a special empty hash,
5430 * so this emits: putobject {}.
5431 * This is only done for method calls and not for literal hashes,
5432 * because literal hashes should always result in a new hash.
5433 */
5434 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5435 }
5436 else if (first_kw) {
5437 /* **{} appears as the first keyword argument, so it may be modified.
5438 * We need to create a fresh hash object.
5439 */
5440 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5441 }
5442 /* Any empty keyword splats that are not the first can be ignored.
5443 * since merging an empty hash into the existing hash is the same
5444 * as not merging it. */
5445 }
5446 else {
5447 if (only_kw && method_call_keywords) {
5448 /* **kw is only keyword argument in method call.
5449 * Use directly. This will be not be flagged as mutable.
5450 * This is only done for method calls and not for literal hashes,
5451 * because literal hashes should always result in a new hash.
5452 */
5453 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5454 }
5455 else {
5456 /* There is more than one keyword argument, or this is not a method
5457 * call. In that case, we need to add an empty hash (if first keyword),
5458 * or merge the hash to the accumulated hash (if not the first keyword).
5459 */
5460 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5461 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5462 else ADD_INSN(ret, line_node, swap);
5463
5464 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5465
5466 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5467 }
5468 }
5469
5470 first_chunk = 0;
5471 }
5472 }
5473 }
5474
5475 FLUSH_CHUNK();
5476#undef FLUSH_CHUNK
5477 return 1;
5478}
5479
5480VALUE
5481rb_node_case_when_optimizable_literal(const NODE *const node)
5482{
5483 switch (nd_type(node)) {
5484 case NODE_INTEGER:
5485 return rb_node_integer_literal_val(node);
5486 case NODE_FLOAT: {
5487 VALUE v = rb_node_float_literal_val(node);
5488 double ival;
5489
5490 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5491 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5492 }
5493 return v;
5494 }
5495 case NODE_RATIONAL:
5496 case NODE_IMAGINARY:
5497 return Qundef;
5498 case NODE_NIL:
5499 return Qnil;
5500 case NODE_TRUE:
5501 return Qtrue;
5502 case NODE_FALSE:
5503 return Qfalse;
5504 case NODE_SYM:
5505 return rb_node_sym_string_val(node);
5506 case NODE_LINE:
5507 return rb_node_line_lineno_val(node);
5508 case NODE_STR:
5509 return rb_node_str_string_val(node);
5510 case NODE_FILE:
5511 return rb_node_file_path_val(node);
5512 }
5513 return Qundef;
5514}
5515
5516static int
5517when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5518 LABEL *l1, int only_special_literals, VALUE literals)
5519{
5520 while (vals) {
5521 const NODE *val = RNODE_LIST(vals)->nd_head;
5522 VALUE lit = rb_node_case_when_optimizable_literal(val);
5523
5524 if (UNDEF_P(lit)) {
5525 only_special_literals = 0;
5526 }
5527 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5528 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5529 }
5530
5531 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5532 debugp_param("nd_lit", get_string_value(val));
5533 lit = get_string_value(val);
5534 ADD_INSN1(cond_seq, val, putobject, lit);
5535 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5536 }
5537 else {
5538 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5539 }
5540
5541 // Emit pattern === target
5542 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5543 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5544 ADD_INSNL(cond_seq, val, branchif, l1);
5545 vals = RNODE_LIST(vals)->nd_next;
5546 }
5547 return only_special_literals;
5548}
5549
5550static int
5551when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5552 LABEL *l1, int only_special_literals, VALUE literals)
5553{
5554 const NODE *line_node = vals;
5555
5556 switch (nd_type(vals)) {
5557 case NODE_LIST:
5558 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5559 return COMPILE_NG;
5560 break;
5561 case NODE_SPLAT:
5562 ADD_INSN (cond_seq, line_node, dup);
5563 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5564 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5565 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5566 ADD_INSNL(cond_seq, line_node, branchif, l1);
5567 break;
5568 case NODE_ARGSCAT:
5569 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5570 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5571 break;
5572 case NODE_ARGSPUSH:
5573 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5574 ADD_INSN (cond_seq, line_node, dup);
5575 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5576 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5577 ADD_INSNL(cond_seq, line_node, branchif, l1);
5578 break;
5579 default:
5580 ADD_INSN (cond_seq, line_node, dup);
5581 CHECK(COMPILE(cond_seq, "when val", vals));
5582 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5583 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5584 ADD_INSNL(cond_seq, line_node, branchif, l1);
5585 break;
5586 }
5587 return COMPILE_OK;
5588}
5589
5590/* Multiple Assignment Handling
5591 *
5592 * In order to handle evaluation of multiple assignment such that the left hand side
5593 * is evaluated before the right hand side, we need to process the left hand side
5594 * and see if there are any attributes that need to be assigned, or constants set
5595 * on explicit objects. If so, we add instructions to evaluate the receiver of
5596 * any assigned attributes or constants before we process the right hand side.
5597 *
5598 * For a multiple assignment such as:
5599 *
5600 * l1.m1, l2[0] = r3, r4
5601 *
5602 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5603 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5604 * On the VM stack, this looks like:
5605 *
5606 * self # putself
5607 * l1 # send
5608 * l1, self # putself
5609 * l1, l2 # send
5610 * l1, l2, 0 # putobject 0
5611 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5612 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5613 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5614 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5615 * l1, l2, 0, [r3, r4], r4, m1= # send
5616 * l1, l2, 0, [r3, r4], r4 # pop
5617 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5618 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5619 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5620 * l1, l2, 0, [r3, r4], r4, []= # send
5621 * l1, l2, 0, [r3, r4], r4 # pop
5622 * l1, l2, 0, [r3, r4] # pop
5623 * [r3, r4], l2, 0, [r3, r4] # setn 3
5624 * [r3, r4], l2, 0 # pop
5625 * [r3, r4], l2 # pop
5626 * [r3, r4] # pop
5627 *
5628 * This is made more complex when you have to handle splats, post args,
5629 * and arbitrary levels of nesting. You need to keep track of the total
5630 * number of attributes to set, and for each attribute, how many entries
5631 * are on the stack before the final attribute, in order to correctly
5632 * calculate the topn value to use to get the receiver of the attribute
5633 * setter method.
5634 *
5635 * A brief description of the VM stack for simple multiple assignment
5636 * with no splat (rhs_array will not be present if the return value of
5637 * the multiple assignment is not needed):
5638 *
5639 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5640 *
5641 * For multiple assignment with splats, while processing the part before
5642 * the splat (splat+post here is an array of the splat and the post arguments):
5643 *
5644 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5645 *
5646 * When processing the splat and post arguments:
5647 *
5648 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5649 *
5650 * When processing nested multiple assignment, existing values on the stack
5651 * are kept. So for:
5652 *
5653 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5654 *
5655 * The stack layout would be the following before processing the nested
5656 * multiple assignment:
5657 *
5658 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5659 *
5660 * In order to handle this correctly, we need to keep track of the nesting
5661 * level for each attribute assignment, as well as the attribute number
5662 * (left hand side attributes are processed left to right) and number of
5663 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5664 * this information.
5665 *
5666 * We also need to track information for the entire multiple assignment, such
5667 * as the total number of arguments, and the current nesting level, to
5668 * handle both nested multiple assignment as well as cases where the
5669 * rhs is not needed. We also need to keep track of all attribute
5670 * assignments in this, which we do using a linked listed. struct masgn_state
5671 * tracks this information.
5672 */
5673
5675 INSN *before_insn;
5676 struct masgn_lhs_node *next;
5677 const NODE *line_node;
5678 int argn;
5679 int num_args;
5680 int lhs_pos;
5681};
5682
5684 struct masgn_lhs_node *first_memo;
5685 struct masgn_lhs_node *last_memo;
5686 int lhs_level;
5687 int num_args;
5688 bool nested;
5689};
5690
5691static int
5692add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5693{
5694 if (!state) {
5695 rb_bug("no masgn_state");
5696 }
5697
5698 struct masgn_lhs_node *memo;
5699 memo = malloc(sizeof(struct masgn_lhs_node));
5700 if (!memo) {
5701 return COMPILE_NG;
5702 }
5703
5704 memo->before_insn = before_insn;
5705 memo->line_node = line_node;
5706 memo->argn = state->num_args + 1;
5707 memo->num_args = argc;
5708 state->num_args += argc;
5709 memo->lhs_pos = lhs_pos;
5710 memo->next = NULL;
5711 if (!state->first_memo) {
5712 state->first_memo = memo;
5713 }
5714 else {
5715 state->last_memo->next = memo;
5716 }
5717 state->last_memo = memo;
5718
5719 return COMPILE_OK;
5720}
5721
5722static 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);
5723
5724static int
5725compile_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)
5726{
5727 switch (nd_type(node)) {
5728 case NODE_ATTRASGN: {
5729 INSN *iobj;
5730 const NODE *line_node = node;
5731
5732 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5733
5734 bool safenav_call = false;
5735 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5736 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5737 ASSUME(iobj);
5738 ELEM_REMOVE(insn_element);
5739 if (!IS_INSN_ID(iobj, send)) {
5740 safenav_call = true;
5741 iobj = (INSN *)get_prev_insn(iobj);
5742 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5743 }
5744 (pre->last = iobj->link.prev)->next = 0;
5745
5746 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5747 int argc = vm_ci_argc(ci) + 1;
5748 ci = ci_argc_set(iseq, ci, argc);
5749 OPERAND_AT(iobj, 0) = (VALUE)ci;
5750 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5751
5752 if (argc == 1) {
5753 ADD_INSN(lhs, line_node, swap);
5754 }
5755 else {
5756 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5757 }
5758
5759 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5760 return COMPILE_NG;
5761 }
5762
5763 iobj->link.prev = lhs->last;
5764 lhs->last->next = &iobj->link;
5765 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5766 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5767 int argc = vm_ci_argc(ci);
5768 bool dupsplat = false;
5769 ci = ci_argc_set(iseq, ci, argc - 1);
5770 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5771 /* Given h[*a], _ = ary
5772 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5773 * `a` must be dupped, because it will be appended with ary[0]
5774 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5775 */
5776 dupsplat = true;
5777 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5778 }
5779 OPERAND_AT(iobj, 0) = (VALUE)ci;
5780 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5781
5782 /* Given: h[*a], h[*b, 1] = ary
5783 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5784 * so this uses splatarray true on a to dup it before using pushtoarray
5785 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5786 * so you can use pushtoarray directly
5787 */
5788 int line_no = nd_line(line_node);
5789 int node_id = nd_node_id(line_node);
5790
5791 if (dupsplat) {
5792 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5793 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5794 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5795 }
5796 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5797 }
5798 if (!safenav_call) {
5799 ADD_INSN(lhs, line_node, pop);
5800 if (argc != 1) {
5801 ADD_INSN(lhs, line_node, pop);
5802 }
5803 }
5804 for (int i=0; i < argc; i++) {
5805 ADD_INSN(post, line_node, pop);
5806 }
5807 break;
5808 }
5809 case NODE_MASGN: {
5810 DECL_ANCHOR(nest_rhs);
5811 INIT_ANCHOR(nest_rhs);
5812 DECL_ANCHOR(nest_lhs);
5813 INIT_ANCHOR(nest_lhs);
5814
5815 int prev_level = state->lhs_level;
5816 bool prev_nested = state->nested;
5817 state->nested = 1;
5818 state->lhs_level = lhs_pos - 1;
5819 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5820 state->lhs_level = prev_level;
5821 state->nested = prev_nested;
5822
5823 ADD_SEQ(lhs, nest_rhs);
5824 ADD_SEQ(lhs, nest_lhs);
5825 break;
5826 }
5827 case NODE_CDECL:
5828 if (!RNODE_CDECL(node)->nd_vid) {
5829 /* Special handling only needed for expr::C, not for C */
5830 INSN *iobj;
5831
5832 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5833
5834 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5835 iobj = (INSN *)insn_element; /* setconstant insn */
5836 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5837 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5838 ELEM_REMOVE(insn_element);
5839 pre->last = iobj->link.prev;
5840 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5841
5842 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5843 return COMPILE_NG;
5844 }
5845
5846 ADD_INSN(post, node, pop);
5847 break;
5848 }
5849 /* Fallthrough */
5850 default: {
5851 DECL_ANCHOR(anchor);
5852 INIT_ANCHOR(anchor);
5853 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5854 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5855 ADD_SEQ(lhs, anchor);
5856 }
5857 }
5858
5859 return COMPILE_OK;
5860}
5861
5862static int
5863compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5864{
5865 if (lhsn) {
5866 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5867 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5868 }
5869 return COMPILE_OK;
5870}
5871
5872static int
5873compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5874 const NODE *rhsn, const NODE *orig_lhsn)
5875{
5876 VALUE mem[64];
5877 const int memsize = numberof(mem);
5878 int memindex = 0;
5879 int llen = 0, rlen = 0;
5880 int i;
5881 const NODE *lhsn = orig_lhsn;
5882
5883#define MEMORY(v) { \
5884 int i; \
5885 if (memindex == memsize) return 0; \
5886 for (i=0; i<memindex; i++) { \
5887 if (mem[i] == (v)) return 0; \
5888 } \
5889 mem[memindex++] = (v); \
5890}
5891
5892 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5893 return 0;
5894 }
5895
5896 while (lhsn) {
5897 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5898 switch (nd_type(ln)) {
5899 case NODE_LASGN:
5900 case NODE_DASGN:
5901 case NODE_IASGN:
5902 case NODE_CVASGN:
5903 MEMORY(get_nd_vid(ln));
5904 break;
5905 default:
5906 return 0;
5907 }
5908 lhsn = RNODE_LIST(lhsn)->nd_next;
5909 llen++;
5910 }
5911
5912 while (rhsn) {
5913 if (llen <= rlen) {
5914 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5915 }
5916 else {
5917 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5918 }
5919 rhsn = RNODE_LIST(rhsn)->nd_next;
5920 rlen++;
5921 }
5922
5923 if (llen > rlen) {
5924 for (i=0; i<llen-rlen; i++) {
5925 ADD_INSN(ret, orig_lhsn, putnil);
5926 }
5927 }
5928
5929 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5930 return 1;
5931}
5932
5933static int
5934compile_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)
5935{
5936 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5937 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5938 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5939 const NODE *lhsn_count = lhsn;
5940 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5941
5942 int llen = 0;
5943 int lpos = 0;
5944
5945 while (lhsn_count) {
5946 llen++;
5947 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5948 }
5949 while (lhsn) {
5950 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5951 lpos++;
5952 lhsn = RNODE_LIST(lhsn)->nd_next;
5953 }
5954
5955 if (lhs_splat) {
5956 if (nd_type_p(splatn, NODE_POSTARG)) {
5957 /*a, b, *r, p1, p2 */
5958 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5959 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5960 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5961 int ppos = 0;
5962 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5963
5964 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5965
5966 if (NODE_NAMED_REST_P(restn)) {
5967 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5968 }
5969 while (postn) {
5970 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5971 ppos++;
5972 postn = RNODE_LIST(postn)->nd_next;
5973 }
5974 }
5975 else {
5976 /* a, b, *r */
5977 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5978 }
5979 }
5980
5981 if (!state->nested) {
5982 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5983 }
5984
5985 if (!popped) {
5986 ADD_INSN(rhs, node, dup);
5987 }
5988 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5989 return COMPILE_OK;
5990}
5991
5992static int
5993compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5994{
5995 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5996 struct masgn_state state;
5997 state.lhs_level = popped ? 0 : 1;
5998 state.nested = 0;
5999 state.num_args = 0;
6000 state.first_memo = NULL;
6001 state.last_memo = NULL;
6002
6003 DECL_ANCHOR(pre);
6004 INIT_ANCHOR(pre);
6005 DECL_ANCHOR(rhs);
6006 INIT_ANCHOR(rhs);
6007 DECL_ANCHOR(lhs);
6008 INIT_ANCHOR(lhs);
6009 DECL_ANCHOR(post);
6010 INIT_ANCHOR(post);
6011 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6012
6013 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6014 while (memo) {
6015 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6016 for (int i = 0; i < memo->num_args; i++) {
6017 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6018 }
6019 tmp_memo = memo->next;
6020 free(memo);
6021 memo = tmp_memo;
6022 }
6023 CHECK(ok);
6024
6025 ADD_SEQ(ret, pre);
6026 ADD_SEQ(ret, rhs);
6027 ADD_SEQ(ret, lhs);
6028 if (!popped && state.num_args >= 1) {
6029 /* make sure rhs array is returned before popping */
6030 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6031 }
6032 ADD_SEQ(ret, post);
6033 }
6034 return COMPILE_OK;
6035}
6036
6037static VALUE
6038collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6039{
6040 VALUE arr = rb_ary_new();
6041 for (;;) {
6042 switch (nd_type(node)) {
6043 case NODE_CONST:
6044 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6045 RB_OBJ_SET_SHAREABLE(arr);
6046 return arr;
6047 case NODE_COLON3:
6048 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6049 rb_ary_unshift(arr, ID2SYM(idNULL));
6050 RB_OBJ_SET_SHAREABLE(arr);
6051 return arr;
6052 case NODE_COLON2:
6053 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6054 node = RNODE_COLON2(node)->nd_head;
6055 break;
6056 default:
6057 return Qfalse;
6058 }
6059 }
6060}
6061
6062static int
6063compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6064 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6065{
6066 switch (nd_type(node)) {
6067 case NODE_CONST:
6068 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6069 ADD_INSN1(body, node, putobject, Qtrue);
6070 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6071 break;
6072 case NODE_COLON3:
6073 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6074 ADD_INSN(body, node, pop);
6075 ADD_INSN1(body, node, putobject, rb_cObject);
6076 ADD_INSN1(body, node, putobject, Qtrue);
6077 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6078 break;
6079 case NODE_COLON2:
6080 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6081 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6082 ADD_INSN1(body, node, putobject, Qfalse);
6083 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6084 break;
6085 default:
6086 CHECK(COMPILE(pref, "const colon2 prefix", node));
6087 break;
6088 }
6089 return COMPILE_OK;
6090}
6091
6092static int
6093compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6094{
6095 if (nd_type_p(cpath, NODE_COLON3)) {
6096 /* toplevel class ::Foo */
6097 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6098 return VM_DEFINECLASS_FLAG_SCOPED;
6099 }
6100 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6101 /* Bar::Foo */
6102 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6103 return VM_DEFINECLASS_FLAG_SCOPED;
6104 }
6105 else {
6106 /* class at cbase Foo */
6107 ADD_INSN1(ret, cpath, putspecialobject,
6108 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6109 return 0;
6110 }
6111}
6112
6113static inline int
6114private_recv_p(const NODE *node)
6115{
6116 NODE *recv = get_nd_recv(node);
6117 if (recv && nd_type_p(recv, NODE_SELF)) {
6118 return RNODE_SELF(recv)->nd_state != 0;
6119 }
6120 return 0;
6121}
6122
6123static void
6124defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6125 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6126
6127static int
6128compile_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);
6129
6130static void
6131defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6132 const NODE *const node, LABEL **lfinish, VALUE needstr,
6133 bool keep_result)
6134{
6135 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6136 enum node_type type;
6137 const int line = nd_line(node);
6138 const NODE *line_node = node;
6139
6140 switch (type = nd_type(node)) {
6141
6142 /* easy literals */
6143 case NODE_NIL:
6144 expr_type = DEFINED_NIL;
6145 break;
6146 case NODE_SELF:
6147 expr_type = DEFINED_SELF;
6148 break;
6149 case NODE_TRUE:
6150 expr_type = DEFINED_TRUE;
6151 break;
6152 case NODE_FALSE:
6153 expr_type = DEFINED_FALSE;
6154 break;
6155
6156 case NODE_HASH:
6157 case NODE_LIST:{
6158 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6159
6160 if (vals) {
6161 do {
6162 if (RNODE_LIST(vals)->nd_head) {
6163 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6164
6165 if (!lfinish[1]) {
6166 lfinish[1] = NEW_LABEL(line);
6167 }
6168 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6169 }
6170 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6171 }
6172 }
6173 /* fall through */
6174 case NODE_STR:
6175 case NODE_SYM:
6176 case NODE_REGX:
6177 case NODE_LINE:
6178 case NODE_FILE:
6179 case NODE_ENCODING:
6180 case NODE_INTEGER:
6181 case NODE_FLOAT:
6182 case NODE_RATIONAL:
6183 case NODE_IMAGINARY:
6184 case NODE_ZLIST:
6185 case NODE_AND:
6186 case NODE_OR:
6187 default:
6188 expr_type = DEFINED_EXPR;
6189 break;
6190
6191 case NODE_SPLAT:
6192 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6193 if (!lfinish[1]) {
6194 lfinish[1] = NEW_LABEL(line);
6195 }
6196 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6197 expr_type = DEFINED_EXPR;
6198 break;
6199
6200 /* variables */
6201 case NODE_LVAR:
6202 case NODE_DVAR:
6203 expr_type = DEFINED_LVAR;
6204 break;
6205
6206#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6207 case NODE_IVAR:
6208 ADD_INSN3(ret, line_node, definedivar,
6209 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6210 return;
6211
6212 case NODE_GVAR:
6213 ADD_INSN(ret, line_node, putnil);
6214 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6215 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6216 return;
6217
6218 case NODE_CVAR:
6219 ADD_INSN(ret, line_node, putnil);
6220 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6221 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6222 return;
6223
6224 case NODE_CONST:
6225 ADD_INSN(ret, line_node, putnil);
6226 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6227 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6228 return;
6229 case NODE_COLON2:
6230 if (!lfinish[1]) {
6231 lfinish[1] = NEW_LABEL(line);
6232 }
6233 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6234 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6235 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6236
6237 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6238 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6239 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6240 }
6241 else {
6242 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6243 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6244 }
6245 return;
6246 case NODE_COLON3:
6247 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6248 ADD_INSN3(ret, line_node, defined,
6249 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6250 return;
6251
6252 /* method dispatch */
6253 case NODE_CALL:
6254 case NODE_OPCALL:
6255 case NODE_VCALL:
6256 case NODE_FCALL:
6257 case NODE_ATTRASGN:{
6258 const int explicit_receiver =
6259 (type == NODE_CALL || type == NODE_OPCALL ||
6260 (type == NODE_ATTRASGN && !private_recv_p(node)));
6261
6262 if (get_nd_args(node) || explicit_receiver) {
6263 if (!lfinish[1]) {
6264 lfinish[1] = NEW_LABEL(line);
6265 }
6266 if (!lfinish[2]) {
6267 lfinish[2] = NEW_LABEL(line);
6268 }
6269 }
6270 if (get_nd_args(node)) {
6271 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6272 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6273 }
6274 if (explicit_receiver) {
6275 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6276 switch (nd_type(get_nd_recv(node))) {
6277 case NODE_CALL:
6278 case NODE_OPCALL:
6279 case NODE_VCALL:
6280 case NODE_FCALL:
6281 case NODE_ATTRASGN:
6282 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6283 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6284 break;
6285 default:
6286 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6287 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6288 break;
6289 }
6290 if (keep_result) {
6291 ADD_INSN(ret, line_node, dup);
6292 }
6293 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6294 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6295 }
6296 else {
6297 ADD_INSN(ret, line_node, putself);
6298 if (keep_result) {
6299 ADD_INSN(ret, line_node, dup);
6300 }
6301 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6302 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6303 }
6304 return;
6305 }
6306
6307 case NODE_YIELD:
6308 ADD_INSN(ret, line_node, putnil);
6309 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6310 PUSH_VAL(DEFINED_YIELD));
6311 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6312 return;
6313
6314 case NODE_BACK_REF:
6315 case NODE_NTH_REF:
6316 ADD_INSN(ret, line_node, putnil);
6317 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6318 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6319 PUSH_VAL(DEFINED_GVAR));
6320 return;
6321
6322 case NODE_SUPER:
6323 case NODE_ZSUPER:
6324 ADD_INSN(ret, line_node, putnil);
6325 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6326 PUSH_VAL(DEFINED_ZSUPER));
6327 return;
6328
6329#undef PUSH_VAL
6330 case NODE_OP_ASGN1:
6331 case NODE_OP_ASGN2:
6332 case NODE_OP_ASGN_OR:
6333 case NODE_OP_ASGN_AND:
6334 case NODE_MASGN:
6335 case NODE_LASGN:
6336 case NODE_DASGN:
6337 case NODE_GASGN:
6338 case NODE_IASGN:
6339 case NODE_CDECL:
6340 case NODE_CVASGN:
6341 case NODE_OP_CDECL:
6342 expr_type = DEFINED_ASGN;
6343 break;
6344 }
6345
6346 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6347
6348 if (needstr != Qfalse) {
6349 VALUE str = rb_iseq_defined_string(expr_type);
6350 ADD_INSN1(ret, line_node, putobject, str);
6351 }
6352 else {
6353 ADD_INSN1(ret, line_node, putobject, Qtrue);
6354 }
6355}
6356
6357static void
6358build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6359{
6360 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6361 iseq_set_exception_local_table(iseq);
6362}
6363
6364static void
6365defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6366 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6367{
6368 LINK_ELEMENT *lcur = ret->last;
6369 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6370 if (lfinish[1]) {
6371 int line = nd_line(node);
6372 LABEL *lstart = NEW_LABEL(line);
6373 LABEL *lend = NEW_LABEL(line);
6374 const rb_iseq_t *rescue;
6376 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6377 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6378 rb_str_concat(rb_str_new2("defined guard in "),
6379 ISEQ_BODY(iseq)->location.label),
6380 ISEQ_TYPE_RESCUE, 0);
6381 lstart->rescued = LABEL_RESCUE_BEG;
6382 lend->rescued = LABEL_RESCUE_END;
6383 APPEND_LABEL(ret, lcur, lstart);
6384 ADD_LABEL(ret, lend);
6385 if (!ignore) {
6386 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6387 }
6388 }
6389}
6390
6391static int
6392compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6393{
6394 const int line = nd_line(node);
6395 const NODE *line_node = node;
6396 if (!RNODE_DEFINED(node)->nd_head) {
6397 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6398 ADD_INSN1(ret, line_node, putobject, str);
6399 }
6400 else {
6401 LABEL *lfinish[3];
6402 LINK_ELEMENT *last = ret->last;
6403 lfinish[0] = NEW_LABEL(line);
6404 lfinish[1] = 0;
6405 lfinish[2] = 0;
6406 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6407 if (lfinish[1]) {
6408 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6409 ADD_INSN(ret, line_node, swap);
6410 if (lfinish[2]) {
6411 ADD_LABEL(ret, lfinish[2]);
6412 }
6413 ADD_INSN(ret, line_node, pop);
6414 ADD_LABEL(ret, lfinish[1]);
6415 }
6416 ADD_LABEL(ret, lfinish[0]);
6417 }
6418 return COMPILE_OK;
6419}
6420
6421static VALUE
6422make_name_for_block(const rb_iseq_t *orig_iseq)
6423{
6424 int level = 1;
6425 const rb_iseq_t *iseq = orig_iseq;
6426
6427 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6428 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6429 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6430 level++;
6431 }
6432 iseq = ISEQ_BODY(iseq)->parent_iseq;
6433 }
6434 }
6435
6436 if (level == 1) {
6437 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6438 }
6439 else {
6440 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6441 }
6442}
6443
6444static void
6445push_ensure_entry(rb_iseq_t *iseq,
6447 struct ensure_range *er, const void *const node)
6448{
6449 enl->ensure_node = node;
6450 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6451 enl->erange = er;
6452 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6453}
6454
6455static void
6456add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6457 LABEL *lstart, LABEL *lend)
6458{
6459 struct ensure_range *ne =
6460 compile_data_alloc(iseq, sizeof(struct ensure_range));
6461
6462 while (erange->next != 0) {
6463 erange = erange->next;
6464 }
6465 ne->next = 0;
6466 ne->begin = lend;
6467 ne->end = erange->end;
6468 erange->end = lstart;
6469
6470 erange->next = ne;
6471}
6472
6473static bool
6474can_add_ensure_iseq(const rb_iseq_t *iseq)
6475{
6477 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6478 while (e) {
6479 if (e->ensure_node) return false;
6480 e = e->prev;
6481 }
6482 }
6483 return true;
6484}
6485
6486static void
6487add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6488{
6489 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6490
6492 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6493 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6494 DECL_ANCHOR(ensure);
6495
6496 INIT_ANCHOR(ensure);
6497 while (enlp) {
6498 if (enlp->erange != NULL) {
6499 DECL_ANCHOR(ensure_part);
6500 LABEL *lstart = NEW_LABEL(0);
6501 LABEL *lend = NEW_LABEL(0);
6502 INIT_ANCHOR(ensure_part);
6503
6504 add_ensure_range(iseq, enlp->erange, lstart, lend);
6505
6506 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6507 ADD_LABEL(ensure_part, lstart);
6508 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6509 ADD_LABEL(ensure_part, lend);
6510 ADD_SEQ(ensure, ensure_part);
6511 }
6512 else {
6513 if (!is_return) {
6514 break;
6515 }
6516 }
6517 enlp = enlp->prev;
6518 }
6519 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6520 ADD_SEQ(ret, ensure);
6521}
6522
6523#if RUBY_DEBUG
6524static int
6525check_keyword(const NODE *node)
6526{
6527 /* This check is essentially a code clone of compile_keyword_arg. */
6528
6529 if (nd_type_p(node, NODE_LIST)) {
6530 while (RNODE_LIST(node)->nd_next) {
6531 node = RNODE_LIST(node)->nd_next;
6532 }
6533 node = RNODE_LIST(node)->nd_head;
6534 }
6535
6536 return keyword_node_p(node);
6537}
6538#endif
6539
6540static bool
6541keyword_node_single_splat_p(NODE *kwnode)
6542{
6543 RUBY_ASSERT(keyword_node_p(kwnode));
6544
6545 NODE *node = RNODE_HASH(kwnode)->nd_head;
6546 return RNODE_LIST(node)->nd_head == NULL &&
6547 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6548}
6549
6550static void
6551compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6552 NODE *kwnode, unsigned int *flag_ptr)
6553{
6554 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6555 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6556 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6557 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6558 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6559}
6560
6561#define SPLATARRAY_FALSE 0
6562#define SPLATARRAY_TRUE 1
6563#define DUP_SINGLE_KW_SPLAT 2
6564
6565static int
6566setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6567 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6568{
6569 if (!argn) return 0;
6570
6571 NODE *kwnode = NULL;
6572
6573 switch (nd_type(argn)) {
6574 case NODE_LIST: {
6575 // f(x, y, z)
6576 int len = compile_args(iseq, args, argn, &kwnode);
6577 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6578
6579 if (kwnode) {
6580 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6581 len -= 1;
6582 }
6583 else {
6584 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6585 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6586 }
6587 else {
6588 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6589 }
6590 }
6591 }
6592
6593 return len;
6594 }
6595 case NODE_SPLAT: {
6596 // f(*a)
6597 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6598 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6599 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6600 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6601 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6602 return 1;
6603 }
6604 case NODE_ARGSCAT: {
6605 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6606 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6607 bool args_pushed = false;
6608
6609 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6610 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6611 if (kwnode) rest_len--;
6612 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6613 args_pushed = true;
6614 }
6615 else {
6616 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6617 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6618 }
6619
6620 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6621 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6622 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6623 argc += 1;
6624 }
6625 else if (!args_pushed) {
6626 ADD_INSN(args, argn, concattoarray);
6627 }
6628
6629 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6630 if (kwnode) {
6631 // kwsplat
6632 *flag_ptr |= VM_CALL_KW_SPLAT;
6633 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6634 argc += 1;
6635 }
6636
6637 return argc;
6638 }
6639 case NODE_ARGSPUSH: {
6640 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6641 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6642
6643 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6644 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6645 if (kwnode) rest_len--;
6646 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6647 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6648 }
6649 else {
6650 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6651 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6652 }
6653 else {
6654 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6655 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6656 }
6657 }
6658
6659 if (kwnode) {
6660 // f(*a, k:1)
6661 *flag_ptr |= VM_CALL_KW_SPLAT;
6662 if (!keyword_node_single_splat_p(kwnode)) {
6663 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6664 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6665 }
6666 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6667 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6668 }
6669 else {
6670 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6671 }
6672 argc += 1;
6673 }
6674
6675 return argc;
6676 }
6677 default: {
6678 UNKNOWN_NODE("setup_arg", argn, Qnil);
6679 }
6680 }
6681}
6682
6683static void
6684setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6685{
6686 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6687 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6688 }
6689}
6690
6691static bool
6692setup_args_dup_rest_p(const NODE *argn)
6693{
6694 switch(nd_type(argn)) {
6695 case NODE_LVAR:
6696 case NODE_DVAR:
6697 case NODE_GVAR:
6698 case NODE_IVAR:
6699 case NODE_CVAR:
6700 case NODE_CONST:
6701 case NODE_COLON3:
6702 case NODE_INTEGER:
6703 case NODE_FLOAT:
6704 case NODE_RATIONAL:
6705 case NODE_IMAGINARY:
6706 case NODE_STR:
6707 case NODE_SYM:
6708 case NODE_REGX:
6709 case NODE_SELF:
6710 case NODE_NIL:
6711 case NODE_TRUE:
6712 case NODE_FALSE:
6713 case NODE_LAMBDA:
6714 case NODE_NTH_REF:
6715 case NODE_BACK_REF:
6716 return false;
6717 case NODE_COLON2:
6718 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6719 case NODE_LIST:
6720 while (argn) {
6721 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6722 return true;
6723 }
6724 argn = RNODE_LIST(argn)->nd_next;
6725 }
6726 return false;
6727 default:
6728 return true;
6729 }
6730}
6731
6732static VALUE
6733setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6734 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6735{
6736 VALUE ret;
6737 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6738
6739 if (argn) {
6740 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6741 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6742
6743 if (check_arg) {
6744 switch(nd_type(check_arg)) {
6745 case(NODE_SPLAT):
6746 // avoid caller side array allocation for f(*arg)
6747 dup_rest = SPLATARRAY_FALSE;
6748 break;
6749 case(NODE_ARGSCAT):
6750 // avoid caller side array allocation for f(1, *arg)
6751 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6752 break;
6753 case(NODE_ARGSPUSH):
6754 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6755 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6756 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6757 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6758 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6759 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6760
6761 if (dup_rest == SPLATARRAY_FALSE) {
6762 // require allocation for keyword key/value/splat that may modify splatted argument
6763 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6764 while (node) {
6765 NODE *key_node = RNODE_LIST(node)->nd_head;
6766 if (key_node && setup_args_dup_rest_p(key_node)) {
6767 dup_rest = SPLATARRAY_TRUE;
6768 break;
6769 }
6770
6771 node = RNODE_LIST(node)->nd_next;
6772 NODE *value_node = RNODE_LIST(node)->nd_head;
6773 if (setup_args_dup_rest_p(value_node)) {
6774 dup_rest = SPLATARRAY_TRUE;
6775 break;
6776 }
6777
6778 node = RNODE_LIST(node)->nd_next;
6779 }
6780 }
6781 break;
6782 default:
6783 break;
6784 }
6785 }
6786
6787 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6788 // for block pass that may modify splatted argument, dup rest and kwrest if given
6789 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6790 }
6791 }
6792 initial_dup_rest = dup_rest;
6793
6794 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6795 DECL_ANCHOR(arg_block);
6796 INIT_ANCHOR(arg_block);
6797
6798 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6799 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6800
6801 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6802 const NODE * arg_node =
6803 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6804
6805 int argc = 0;
6806
6807 // Only compile leading args:
6808 // foo(x, y, ...)
6809 // ^^^^
6810 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6811 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6812 }
6813
6814 *flag |= VM_CALL_FORWARDING;
6815
6816 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6817 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6818 return INT2FIX(argc);
6819 }
6820 else {
6821 *flag |= VM_CALL_ARGS_BLOCKARG;
6822
6823 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6824 }
6825
6826 if (LIST_INSN_SIZE_ONE(arg_block)) {
6827 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6828 if (IS_INSN(elem)) {
6829 INSN *iobj = (INSN *)elem;
6830 if (iobj->insn_id == BIN(getblockparam)) {
6831 iobj->insn_id = BIN(getblockparamproxy);
6832 }
6833 }
6834 }
6835 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6836 ADD_SEQ(args, arg_block);
6837 }
6838 else {
6839 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6840 }
6841 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6842 return ret;
6843}
6844
6845static void
6846build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6847{
6848 const NODE *body = ptr;
6849 int line = nd_line(body);
6850 VALUE argc = INT2FIX(0);
6851 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6852
6853 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6854 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6855 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6856 iseq_set_local_table(iseq, 0, 0);
6857}
6858
6859static void
6860compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6861{
6862 const NODE *vars;
6863 LINK_ELEMENT *last;
6864 int line = nd_line(node);
6865 const NODE *line_node = node;
6866 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6867
6868#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6869 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6870#else
6871 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6872#endif
6873 ADD_INSN(ret, line_node, dup);
6874 ADD_INSNL(ret, line_node, branchunless, fail_label);
6875
6876 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6877 INSN *cap;
6878 if (RNODE_BLOCK(vars)->nd_next) {
6879 ADD_INSN(ret, line_node, dup);
6880 }
6881 last = ret->last;
6882 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6883 last = last->next; /* putobject :var */
6884 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6885 NULL, INT2FIX(0), NULL);
6886 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6887#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6888 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6889 /* only one name */
6890 DECL_ANCHOR(nom);
6891
6892 INIT_ANCHOR(nom);
6893 ADD_INSNL(nom, line_node, jump, end_label);
6894 ADD_LABEL(nom, fail_label);
6895# if 0 /* $~ must be MatchData or nil */
6896 ADD_INSN(nom, line_node, pop);
6897 ADD_INSN(nom, line_node, putnil);
6898# endif
6899 ADD_LABEL(nom, end_label);
6900 (nom->last->next = cap->link.next)->prev = nom->last;
6901 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6902 return;
6903 }
6904#endif
6905 }
6906 ADD_INSNL(ret, line_node, jump, end_label);
6907 ADD_LABEL(ret, fail_label);
6908 ADD_INSN(ret, line_node, pop);
6909 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6910 last = ret->last;
6911 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6912 last = last->next; /* putobject :var */
6913 ((INSN*)last)->insn_id = BIN(putnil);
6914 ((INSN*)last)->operand_size = 0;
6915 }
6916 ADD_LABEL(ret, end_label);
6917}
6918
6919static int
6920optimizable_range_item_p(const NODE *n)
6921{
6922 if (!n) return FALSE;
6923 switch (nd_type(n)) {
6924 case NODE_LINE:
6925 return TRUE;
6926 case NODE_INTEGER:
6927 return TRUE;
6928 case NODE_NIL:
6929 return TRUE;
6930 default:
6931 return FALSE;
6932 }
6933}
6934
6935static VALUE
6936optimized_range_item(const NODE *n)
6937{
6938 switch (nd_type(n)) {
6939 case NODE_LINE:
6940 return rb_node_line_lineno_val(n);
6941 case NODE_INTEGER:
6942 return rb_node_integer_literal_val(n);
6943 case NODE_FLOAT:
6944 return rb_node_float_literal_val(n);
6945 case NODE_RATIONAL:
6946 return rb_node_rational_literal_val(n);
6947 case NODE_IMAGINARY:
6948 return rb_node_imaginary_literal_val(n);
6949 case NODE_NIL:
6950 return Qnil;
6951 default:
6952 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6953 }
6954}
6955
6956static int
6957compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6958{
6959 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6960 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6961
6962 const int line = nd_line(node);
6963 const NODE *line_node = node;
6964 DECL_ANCHOR(cond_seq);
6965 LABEL *then_label, *else_label, *end_label;
6966 VALUE branches = Qfalse;
6967
6968 INIT_ANCHOR(cond_seq);
6969 then_label = NEW_LABEL(line);
6970 else_label = NEW_LABEL(line);
6971 end_label = 0;
6972
6973 NODE *cond = RNODE_IF(node)->nd_cond;
6974 if (nd_type(cond) == NODE_BLOCK) {
6975 cond = RNODE_BLOCK(cond)->nd_head;
6976 }
6977
6978 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6979 ADD_SEQ(ret, cond_seq);
6980
6981 if (then_label->refcnt && else_label->refcnt) {
6982 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6983 }
6984
6985 if (then_label->refcnt) {
6986 ADD_LABEL(ret, then_label);
6987
6988 DECL_ANCHOR(then_seq);
6989 INIT_ANCHOR(then_seq);
6990 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6991
6992 if (else_label->refcnt) {
6993 const NODE *const coverage_node = node_body ? node_body : node;
6994 add_trace_branch_coverage(
6995 iseq,
6996 ret,
6997 nd_code_loc(coverage_node),
6998 nd_node_id(coverage_node),
6999 0,
7000 type == NODE_IF ? "then" : "else",
7001 branches);
7002 end_label = NEW_LABEL(line);
7003 ADD_INSNL(then_seq, line_node, jump, end_label);
7004 if (!popped) {
7005 ADD_INSN(then_seq, line_node, pop);
7006 }
7007 }
7008 ADD_SEQ(ret, then_seq);
7009 }
7010
7011 if (else_label->refcnt) {
7012 ADD_LABEL(ret, else_label);
7013
7014 DECL_ANCHOR(else_seq);
7015 INIT_ANCHOR(else_seq);
7016 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7017
7018 if (then_label->refcnt) {
7019 const NODE *const coverage_node = node_else ? node_else : node;
7020 add_trace_branch_coverage(
7021 iseq,
7022 ret,
7023 nd_code_loc(coverage_node),
7024 nd_node_id(coverage_node),
7025 1,
7026 type == NODE_IF ? "else" : "then",
7027 branches);
7028 }
7029 ADD_SEQ(ret, else_seq);
7030 }
7031
7032 if (end_label) {
7033 ADD_LABEL(ret, end_label);
7034 }
7035
7036 return COMPILE_OK;
7037}
7038
7039static int
7040compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7041{
7042 const NODE *vals;
7043 const NODE *node = orig_node;
7044 LABEL *endlabel, *elselabel;
7045 DECL_ANCHOR(head);
7046 DECL_ANCHOR(body_seq);
7047 DECL_ANCHOR(cond_seq);
7048 int only_special_literals = 1;
7049 VALUE literals = rb_hash_new();
7050 int line;
7051 enum node_type type;
7052 const NODE *line_node;
7053 VALUE branches = Qfalse;
7054 int branch_id = 0;
7055
7056 INIT_ANCHOR(head);
7057 INIT_ANCHOR(body_seq);
7058 INIT_ANCHOR(cond_seq);
7059
7060 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7061
7062 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7063
7064 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
7065
7066 node = RNODE_CASE(node)->nd_body;
7067 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7068 type = nd_type(node);
7069 line = nd_line(node);
7070 line_node = node;
7071
7072 endlabel = NEW_LABEL(line);
7073 elselabel = NEW_LABEL(line);
7074
7075 ADD_SEQ(ret, head); /* case VAL */
7076
7077 while (type == NODE_WHEN) {
7078 LABEL *l1;
7079
7080 l1 = NEW_LABEL(line);
7081 ADD_LABEL(body_seq, l1);
7082 ADD_INSN(body_seq, line_node, pop);
7083
7084 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7085 add_trace_branch_coverage(
7086 iseq,
7087 body_seq,
7088 nd_code_loc(coverage_node),
7089 nd_node_id(coverage_node),
7090 branch_id++,
7091 "when",
7092 branches);
7093
7094 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7095 ADD_INSNL(body_seq, line_node, jump, endlabel);
7096
7097 vals = RNODE_WHEN(node)->nd_head;
7098 if (vals) {
7099 switch (nd_type(vals)) {
7100 case NODE_LIST:
7101 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7102 if (only_special_literals < 0) return COMPILE_NG;
7103 break;
7104 case NODE_SPLAT:
7105 case NODE_ARGSCAT:
7106 case NODE_ARGSPUSH:
7107 only_special_literals = 0;
7108 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7109 break;
7110 default:
7111 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7112 }
7113 }
7114 else {
7115 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7116 }
7117
7118 node = RNODE_WHEN(node)->nd_next;
7119 if (!node) {
7120 break;
7121 }
7122 type = nd_type(node);
7123 line = nd_line(node);
7124 line_node = node;
7125 }
7126 /* else */
7127 if (node) {
7128 ADD_LABEL(cond_seq, elselabel);
7129 ADD_INSN(cond_seq, line_node, pop);
7130 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7131 CHECK(COMPILE_(cond_seq, "else", node, popped));
7132 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7133 }
7134 else {
7135 debugs("== else (implicit)\n");
7136 ADD_LABEL(cond_seq, elselabel);
7137 ADD_INSN(cond_seq, orig_node, pop);
7138 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7139 if (!popped) {
7140 ADD_INSN(cond_seq, orig_node, putnil);
7141 }
7142 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7143 }
7144
7145 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7146 ADD_INSN(ret, orig_node, dup);
7147 rb_obj_hide(literals);
7148 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7149 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7150 LABEL_REF(elselabel);
7151 }
7152
7153 ADD_SEQ(ret, cond_seq);
7154 ADD_SEQ(ret, body_seq);
7155 ADD_LABEL(ret, endlabel);
7156 return COMPILE_OK;
7157}
7158
7159static int
7160compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7161{
7162 const NODE *vals;
7163 const NODE *val;
7164 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7165 LABEL *endlabel;
7166 DECL_ANCHOR(body_seq);
7167 VALUE branches = Qfalse;
7168 int branch_id = 0;
7169
7170 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7171
7172 INIT_ANCHOR(body_seq);
7173 endlabel = NEW_LABEL(nd_line(node));
7174
7175 while (node && nd_type_p(node, NODE_WHEN)) {
7176 const int line = nd_line(node);
7177 LABEL *l1 = NEW_LABEL(line);
7178 ADD_LABEL(body_seq, l1);
7179
7180 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7181 add_trace_branch_coverage(
7182 iseq,
7183 body_seq,
7184 nd_code_loc(coverage_node),
7185 nd_node_id(coverage_node),
7186 branch_id++,
7187 "when",
7188 branches);
7189
7190 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7191 ADD_INSNL(body_seq, node, jump, endlabel);
7192
7193 vals = RNODE_WHEN(node)->nd_head;
7194 if (!vals) {
7195 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7196 }
7197 switch (nd_type(vals)) {
7198 case NODE_LIST:
7199 while (vals) {
7200 LABEL *lnext;
7201 val = RNODE_LIST(vals)->nd_head;
7202 lnext = NEW_LABEL(nd_line(val));
7203 debug_compile("== when2\n", (void)0);
7204 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7205 ADD_LABEL(ret, lnext);
7206 vals = RNODE_LIST(vals)->nd_next;
7207 }
7208 break;
7209 case NODE_SPLAT:
7210 case NODE_ARGSCAT:
7211 case NODE_ARGSPUSH:
7212 ADD_INSN(ret, vals, putnil);
7213 CHECK(COMPILE(ret, "when2/cond splat", vals));
7214 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7215 ADD_INSNL(ret, vals, branchif, l1);
7216 break;
7217 default:
7218 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7219 }
7220 node = RNODE_WHEN(node)->nd_next;
7221 }
7222 /* else */
7223 const NODE *const coverage_node = node ? node : orig_node;
7224 add_trace_branch_coverage(
7225 iseq,
7226 ret,
7227 nd_code_loc(coverage_node),
7228 nd_node_id(coverage_node),
7229 branch_id,
7230 "else",
7231 branches);
7232 CHECK(COMPILE_(ret, "else", node, popped));
7233 ADD_INSNL(ret, orig_node, jump, endlabel);
7234
7235 ADD_SEQ(ret, body_seq);
7236 ADD_LABEL(ret, endlabel);
7237 return COMPILE_OK;
7238}
7239
7240static 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);
7241
7242static 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);
7243static 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);
7244static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7245static 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);
7246static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7247
7248#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7249#define CASE3_BI_OFFSET_ERROR_STRING 1
7250#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7251#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7252#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7253
7254static int
7255iseq_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)
7256{
7257 const int line = nd_line(node);
7258 const NODE *line_node = node;
7259
7260 switch (nd_type(node)) {
7261 case NODE_ARYPTN: {
7262 /*
7263 * if pattern.use_rest_num?
7264 * rest_num = 0
7265 * end
7266 * if pattern.has_constant_node?
7267 * unless pattern.constant === obj
7268 * goto match_failed
7269 * end
7270 * end
7271 * unless obj.respond_to?(:deconstruct)
7272 * goto match_failed
7273 * end
7274 * d = obj.deconstruct
7275 * unless Array === d
7276 * goto type_error
7277 * end
7278 * min_argc = pattern.pre_args_num + pattern.post_args_num
7279 * if pattern.has_rest_arg?
7280 * unless d.length >= min_argc
7281 * goto match_failed
7282 * end
7283 * else
7284 * unless d.length == min_argc
7285 * goto match_failed
7286 * end
7287 * end
7288 * pattern.pre_args_num.each do |i|
7289 * unless pattern.pre_args[i].match?(d[i])
7290 * goto match_failed
7291 * end
7292 * end
7293 * if pattern.use_rest_num?
7294 * rest_num = d.length - min_argc
7295 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7296 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7297 * goto match_failed
7298 * end
7299 * end
7300 * end
7301 * pattern.post_args_num.each do |i|
7302 * j = pattern.pre_args_num + i
7303 * j += rest_num
7304 * unless pattern.post_args[i].match?(d[j])
7305 * goto match_failed
7306 * end
7307 * end
7308 * goto matched
7309 * type_error:
7310 * FrozenCore.raise TypeError
7311 * match_failed:
7312 * goto unmatched
7313 */
7314 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7315 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7316 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7317
7318 const int min_argc = pre_args_num + post_args_num;
7319 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7320 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7321
7322 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7323 int i;
7324 match_failed = NEW_LABEL(line);
7325 type_error = NEW_LABEL(line);
7326 deconstruct = NEW_LABEL(line);
7327 deconstructed = NEW_LABEL(line);
7328
7329 if (use_rest_num) {
7330 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7331 ADD_INSN(ret, line_node, swap);
7332 if (base_index) {
7333 base_index++;
7334 }
7335 }
7336
7337 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7338
7339 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7340
7341 ADD_INSN(ret, line_node, dup);
7342 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7343 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7344 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7345 if (in_single_pattern) {
7346 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7347 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7348 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7349 INT2FIX(min_argc), base_index + 1 /* (1) */));
7350 }
7351 ADD_INSNL(ret, line_node, branchunless, match_failed);
7352
7353 for (i = 0; i < pre_args_num; i++) {
7354 ADD_INSN(ret, line_node, dup);
7355 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7356 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7357 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));
7358 args = RNODE_LIST(args)->nd_next;
7359 }
7360
7361 if (RNODE_ARYPTN(node)->rest_arg) {
7362 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7363 ADD_INSN(ret, line_node, dup);
7364 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7365 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7366 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7367 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7368 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7369 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7370 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7371
7372 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));
7373 }
7374 else {
7375 if (post_args_num > 0) {
7376 ADD_INSN(ret, line_node, dup);
7377 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7378 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7379 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7380 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7381 ADD_INSN(ret, line_node, pop);
7382 }
7383 }
7384 }
7385
7386 args = RNODE_ARYPTN(node)->post_args;
7387 for (i = 0; i < post_args_num; i++) {
7388 ADD_INSN(ret, line_node, dup);
7389
7390 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7391 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7392 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7393
7394 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7395 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));
7396 args = RNODE_LIST(args)->nd_next;
7397 }
7398
7399 ADD_INSN(ret, line_node, pop);
7400 if (use_rest_num) {
7401 ADD_INSN(ret, line_node, pop);
7402 }
7403 ADD_INSNL(ret, line_node, jump, matched);
7404 ADD_INSN(ret, line_node, putnil);
7405 if (use_rest_num) {
7406 ADD_INSN(ret, line_node, putnil);
7407 }
7408
7409 ADD_LABEL(ret, type_error);
7410 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7411 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7412 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7413 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7414 ADD_INSN(ret, line_node, pop);
7415
7416 ADD_LABEL(ret, match_failed);
7417 ADD_INSN(ret, line_node, pop);
7418 if (use_rest_num) {
7419 ADD_INSN(ret, line_node, pop);
7420 }
7421 ADD_INSNL(ret, line_node, jump, unmatched);
7422
7423 break;
7424 }
7425 case NODE_FNDPTN: {
7426 /*
7427 * if pattern.has_constant_node?
7428 * unless pattern.constant === obj
7429 * goto match_failed
7430 * end
7431 * end
7432 * unless obj.respond_to?(:deconstruct)
7433 * goto match_failed
7434 * end
7435 * d = obj.deconstruct
7436 * unless Array === d
7437 * goto type_error
7438 * end
7439 * unless d.length >= pattern.args_num
7440 * goto match_failed
7441 * end
7442 *
7443 * begin
7444 * len = d.length
7445 * limit = d.length - pattern.args_num
7446 * i = 0
7447 * while i <= limit
7448 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7449 * if pattern.has_pre_rest_arg_id
7450 * unless pattern.pre_rest_arg.match?(d[0, i])
7451 * goto find_failed
7452 * end
7453 * end
7454 * if pattern.has_post_rest_arg_id
7455 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7456 * goto find_failed
7457 * end
7458 * end
7459 * goto find_succeeded
7460 * end
7461 * i+=1
7462 * end
7463 * find_failed:
7464 * goto match_failed
7465 * find_succeeded:
7466 * end
7467 *
7468 * goto matched
7469 * type_error:
7470 * FrozenCore.raise TypeError
7471 * match_failed:
7472 * goto unmatched
7473 */
7474 const NODE *args = RNODE_FNDPTN(node)->args;
7475 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7476
7477 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7478 match_failed = NEW_LABEL(line);
7479 type_error = NEW_LABEL(line);
7480 deconstruct = NEW_LABEL(line);
7481 deconstructed = NEW_LABEL(line);
7482
7483 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7484
7485 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7486
7487 ADD_INSN(ret, line_node, dup);
7488 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7489 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7490 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7491 if (in_single_pattern) {
7492 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) */));
7493 }
7494 ADD_INSNL(ret, line_node, branchunless, match_failed);
7495
7496 {
7497 LABEL *while_begin = NEW_LABEL(nd_line(node));
7498 LABEL *next_loop = NEW_LABEL(nd_line(node));
7499 LABEL *find_succeeded = NEW_LABEL(line);
7500 LABEL *find_failed = NEW_LABEL(nd_line(node));
7501 int j;
7502
7503 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7504 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7505
7506 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7507 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7508 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7509
7510 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7511
7512 ADD_LABEL(ret, while_begin);
7513
7514 ADD_INSN(ret, line_node, dup);
7515 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7516 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7517 ADD_INSNL(ret, line_node, branchunless, find_failed);
7518
7519 for (j = 0; j < args_num; j++) {
7520 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7521 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7522 if (j != 0) {
7523 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7524 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7525 }
7526 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7527
7528 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));
7529 args = RNODE_LIST(args)->nd_next;
7530 }
7531
7532 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7533 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7534 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7535 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7536 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7537 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));
7538 }
7539 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7540 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7541 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7542 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7543 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7544 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7545 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7546 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));
7547 }
7548 ADD_INSNL(ret, line_node, jump, find_succeeded);
7549
7550 ADD_LABEL(ret, next_loop);
7551 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7552 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7553 ADD_INSNL(ret, line_node, jump, while_begin);
7554
7555 ADD_LABEL(ret, find_failed);
7556 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7557 if (in_single_pattern) {
7558 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7559 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7560 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7561 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7562 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7563
7564 ADD_INSN1(ret, line_node, putobject, Qfalse);
7565 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7566
7567 ADD_INSN(ret, line_node, pop);
7568 ADD_INSN(ret, line_node, pop);
7569 }
7570 ADD_INSNL(ret, line_node, jump, match_failed);
7571 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7572
7573 ADD_LABEL(ret, find_succeeded);
7574 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7575 }
7576
7577 ADD_INSN(ret, line_node, pop);
7578 ADD_INSNL(ret, line_node, jump, matched);
7579 ADD_INSN(ret, line_node, putnil);
7580
7581 ADD_LABEL(ret, type_error);
7582 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7583 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7584 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7585 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7586 ADD_INSN(ret, line_node, pop);
7587
7588 ADD_LABEL(ret, match_failed);
7589 ADD_INSN(ret, line_node, pop);
7590 ADD_INSNL(ret, line_node, jump, unmatched);
7591
7592 break;
7593 }
7594 case NODE_HSHPTN: {
7595 /*
7596 * keys = nil
7597 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7598 * keys = pattern.kw_args_node.keys
7599 * end
7600 * if pattern.has_constant_node?
7601 * unless pattern.constant === obj
7602 * goto match_failed
7603 * end
7604 * end
7605 * unless obj.respond_to?(:deconstruct_keys)
7606 * goto match_failed
7607 * end
7608 * d = obj.deconstruct_keys(keys)
7609 * unless Hash === d
7610 * goto type_error
7611 * end
7612 * if pattern.has_kw_rest_arg_node?
7613 * d = d.dup
7614 * end
7615 * if pattern.has_kw_args_node?
7616 * pattern.kw_args_node.each |k,|
7617 * unless d.key?(k)
7618 * goto match_failed
7619 * end
7620 * end
7621 * pattern.kw_args_node.each |k, pat|
7622 * if pattern.has_kw_rest_arg_node?
7623 * unless pat.match?(d.delete(k))
7624 * goto match_failed
7625 * end
7626 * else
7627 * unless pat.match?(d[k])
7628 * goto match_failed
7629 * end
7630 * end
7631 * end
7632 * else
7633 * unless d.empty?
7634 * goto match_failed
7635 * end
7636 * end
7637 * if pattern.has_kw_rest_arg_node?
7638 * if pattern.no_rest_keyword?
7639 * unless d.empty?
7640 * goto match_failed
7641 * end
7642 * else
7643 * unless pattern.kw_rest_arg_node.match?(d)
7644 * goto match_failed
7645 * end
7646 * end
7647 * end
7648 * goto matched
7649 * type_error:
7650 * FrozenCore.raise TypeError
7651 * match_failed:
7652 * goto unmatched
7653 */
7654 LABEL *match_failed, *type_error;
7655 VALUE keys = Qnil;
7656
7657 match_failed = NEW_LABEL(line);
7658 type_error = NEW_LABEL(line);
7659
7660 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7661 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7662 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7663 while (kw_args) {
7664 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7665 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7666 }
7667 }
7668
7669 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7670
7671 ADD_INSN(ret, line_node, dup);
7672 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7673 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7674 if (in_single_pattern) {
7675 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7676 }
7677 ADD_INSNL(ret, line_node, branchunless, match_failed);
7678
7679 if (NIL_P(keys)) {
7680 ADD_INSN(ret, line_node, putnil);
7681 }
7682 else {
7683 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7684 ADD_INSN1(ret, line_node, duparray, keys);
7685 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7686 }
7687 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7688
7689 ADD_INSN(ret, line_node, dup);
7690 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7691 ADD_INSNL(ret, line_node, branchunless, type_error);
7692
7693 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7694 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7695 }
7696
7697 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7698 int i;
7699 int keys_num;
7700 const NODE *args;
7701 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7702 if (args) {
7703 DECL_ANCHOR(match_values);
7704 INIT_ANCHOR(match_values);
7705 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7706 for (i = 0; i < keys_num; i++) {
7707 NODE *key_node = RNODE_LIST(args)->nd_head;
7708 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7709 VALUE key = get_symbol_value(iseq, key_node);
7710
7711 ADD_INSN(ret, line_node, dup);
7712 ADD_INSN1(ret, line_node, putobject, key);
7713 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7714 if (in_single_pattern) {
7715 LABEL *match_succeeded;
7716 match_succeeded = NEW_LABEL(line);
7717
7718 ADD_INSN(ret, line_node, dup);
7719 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7720
7721 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7722 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7723 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7724 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7725 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7726 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7727 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7728 ADD_INSN1(ret, line_node, putobject, key); // (7)
7729 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7730
7731 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7732
7733 ADD_LABEL(ret, match_succeeded);
7734 }
7735 ADD_INSNL(ret, line_node, branchunless, match_failed);
7736
7737 ADD_INSN(match_values, line_node, dup);
7738 ADD_INSN1(match_values, line_node, putobject, key);
7739 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7740 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7741 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7742 }
7743 ADD_SEQ(ret, match_values);
7744 }
7745 }
7746 else {
7747 ADD_INSN(ret, line_node, dup);
7748 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7749 if (in_single_pattern) {
7750 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7751 }
7752 ADD_INSNL(ret, line_node, branchunless, match_failed);
7753 }
7754
7755 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7756 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7757 ADD_INSN(ret, line_node, dup);
7758 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7759 if (in_single_pattern) {
7760 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7761 }
7762 ADD_INSNL(ret, line_node, branchunless, match_failed);
7763 }
7764 else {
7765 ADD_INSN(ret, line_node, dup); // (11)
7766 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));
7767 }
7768 }
7769
7770 ADD_INSN(ret, line_node, pop);
7771 ADD_INSNL(ret, line_node, jump, matched);
7772 ADD_INSN(ret, line_node, putnil);
7773
7774 ADD_LABEL(ret, type_error);
7775 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7776 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7777 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7778 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7779 ADD_INSN(ret, line_node, pop);
7780
7781 ADD_LABEL(ret, match_failed);
7782 ADD_INSN(ret, line_node, pop);
7783 ADD_INSNL(ret, line_node, jump, unmatched);
7784 break;
7785 }
7786 case NODE_SYM:
7787 case NODE_REGX:
7788 case NODE_LINE:
7789 case NODE_INTEGER:
7790 case NODE_FLOAT:
7791 case NODE_RATIONAL:
7792 case NODE_IMAGINARY:
7793 case NODE_FILE:
7794 case NODE_ENCODING:
7795 case NODE_STR:
7796 case NODE_XSTR:
7797 case NODE_DSTR:
7798 case NODE_DSYM:
7799 case NODE_DREGX:
7800 case NODE_LIST:
7801 case NODE_ZLIST:
7802 case NODE_LAMBDA:
7803 case NODE_DOT2:
7804 case NODE_DOT3:
7805 case NODE_CONST:
7806 case NODE_LVAR:
7807 case NODE_DVAR:
7808 case NODE_IVAR:
7809 case NODE_CVAR:
7810 case NODE_GVAR:
7811 case NODE_TRUE:
7812 case NODE_FALSE:
7813 case NODE_SELF:
7814 case NODE_NIL:
7815 case NODE_COLON2:
7816 case NODE_COLON3:
7817 case NODE_BEGIN:
7818 case NODE_BLOCK:
7819 case NODE_ONCE:
7820 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7821 if (in_single_pattern) {
7822 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7823 }
7824 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7825 if (in_single_pattern) {
7826 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7827 }
7828 ADD_INSNL(ret, line_node, branchif, matched);
7829 ADD_INSNL(ret, line_node, jump, unmatched);
7830 break;
7831 case NODE_LASGN: {
7832 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7833 ID id = RNODE_LASGN(node)->nd_vid;
7834 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7835
7836 if (in_alt_pattern) {
7837 const char *name = rb_id2name(id);
7838 if (name && strlen(name) > 0 && name[0] != '_') {
7839 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7840 rb_id2str(id));
7841 return COMPILE_NG;
7842 }
7843 }
7844
7845 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7846 ADD_INSNL(ret, line_node, jump, matched);
7847 break;
7848 }
7849 case NODE_DASGN: {
7850 int idx, lv, ls;
7851 ID id = RNODE_DASGN(node)->nd_vid;
7852
7853 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7854
7855 if (in_alt_pattern) {
7856 const char *name = rb_id2name(id);
7857 if (name && strlen(name) > 0 && name[0] != '_') {
7858 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7859 rb_id2str(id));
7860 return COMPILE_NG;
7861 }
7862 }
7863
7864 if (idx < 0) {
7865 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7866 rb_id2str(id));
7867 return COMPILE_NG;
7868 }
7869 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7870 ADD_INSNL(ret, line_node, jump, matched);
7871 break;
7872 }
7873 case NODE_IF:
7874 case NODE_UNLESS: {
7875 LABEL *match_failed;
7876 match_failed = unmatched;
7877 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7878 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7879 if (in_single_pattern) {
7880 LABEL *match_succeeded;
7881 match_succeeded = NEW_LABEL(line);
7882
7883 ADD_INSN(ret, line_node, dup);
7884 if (nd_type_p(node, NODE_IF)) {
7885 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7886 }
7887 else {
7888 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7889 }
7890
7891 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7892 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7893 ADD_INSN1(ret, line_node, putobject, Qfalse);
7894 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7895
7896 ADD_INSN(ret, line_node, pop);
7897 ADD_INSN(ret, line_node, pop);
7898
7899 ADD_LABEL(ret, match_succeeded);
7900 }
7901 if (nd_type_p(node, NODE_IF)) {
7902 ADD_INSNL(ret, line_node, branchunless, match_failed);
7903 }
7904 else {
7905 ADD_INSNL(ret, line_node, branchif, match_failed);
7906 }
7907 ADD_INSNL(ret, line_node, jump, matched);
7908 break;
7909 }
7910 case NODE_HASH: {
7911 NODE *n;
7912 LABEL *match_failed;
7913 match_failed = NEW_LABEL(line);
7914
7915 n = RNODE_HASH(node)->nd_head;
7916 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7917 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7918 return COMPILE_NG;
7919 }
7920
7921 ADD_INSN(ret, line_node, dup); // (1)
7922 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));
7923 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));
7924 ADD_INSN(ret, line_node, putnil);
7925
7926 ADD_LABEL(ret, match_failed);
7927 ADD_INSN(ret, line_node, pop);
7928 ADD_INSNL(ret, line_node, jump, unmatched);
7929 break;
7930 }
7931 case NODE_OR: {
7932 LABEL *match_succeeded, *fin;
7933 match_succeeded = NEW_LABEL(line);
7934 fin = NEW_LABEL(line);
7935
7936 ADD_INSN(ret, line_node, dup); // (1)
7937 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));
7938 ADD_LABEL(ret, match_succeeded);
7939 ADD_INSN(ret, line_node, pop);
7940 ADD_INSNL(ret, line_node, jump, matched);
7941 ADD_INSN(ret, line_node, putnil);
7942 ADD_LABEL(ret, fin);
7943 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7944 break;
7945 }
7946 default:
7947 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7948 }
7949 return COMPILE_OK;
7950}
7951
7952static int
7953iseq_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)
7954{
7955 LABEL *fin = NEW_LABEL(nd_line(node));
7956 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7957 ADD_LABEL(ret, fin);
7958 return COMPILE_OK;
7959}
7960
7961static int
7962iseq_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)
7963{
7964 const NODE *line_node = node;
7965
7966 if (RNODE_ARYPTN(node)->nd_pconst) {
7967 ADD_INSN(ret, line_node, dup); // (1)
7968 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7969 if (in_single_pattern) {
7970 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7971 }
7972 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7973 if (in_single_pattern) {
7974 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7975 }
7976 ADD_INSNL(ret, line_node, branchunless, match_failed);
7977 }
7978 return COMPILE_OK;
7979}
7980
7981
7982static int
7983iseq_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)
7984{
7985 const NODE *line_node = node;
7986
7987 // NOTE: this optimization allows us to re-use the #deconstruct value
7988 // (or its absence).
7989 if (use_deconstructed_cache) {
7990 // If value is nil then we haven't tried to deconstruct
7991 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7992 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7993
7994 // If false then the value is not deconstructable
7995 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7996 ADD_INSNL(ret, line_node, branchunless, match_failed);
7997
7998 // Drop value, add deconstructed to the stack and jump
7999 ADD_INSN(ret, line_node, pop); // (1)
8000 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8001 ADD_INSNL(ret, line_node, jump, deconstructed);
8002 }
8003 else {
8004 ADD_INSNL(ret, line_node, jump, deconstruct);
8005 }
8006
8007 ADD_LABEL(ret, deconstruct);
8008 ADD_INSN(ret, line_node, dup);
8009 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8010 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8011
8012 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8013 if (use_deconstructed_cache) {
8014 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8015 }
8016
8017 if (in_single_pattern) {
8018 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8019 }
8020
8021 ADD_INSNL(ret, line_node, branchunless, match_failed);
8022
8023 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8024
8025 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8026 if (use_deconstructed_cache) {
8027 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8028 }
8029
8030 ADD_INSN(ret, line_node, dup);
8031 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8032 ADD_INSNL(ret, line_node, branchunless, type_error);
8033
8034 ADD_LABEL(ret, deconstructed);
8035
8036 return COMPILE_OK;
8037}
8038
8039static int
8040iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8041{
8042 /*
8043 * if match_succeeded?
8044 * goto match_succeeded
8045 * end
8046 * error_string = FrozenCore.sprintf(errmsg, matchee)
8047 * key_error_p = false
8048 * match_succeeded:
8049 */
8050 const int line = nd_line(node);
8051 const NODE *line_node = node;
8052 LABEL *match_succeeded = NEW_LABEL(line);
8053
8054 ADD_INSN(ret, line_node, dup);
8055 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8056
8057 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8058 ADD_INSN1(ret, line_node, putobject, errmsg);
8059 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8060 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8061 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8062
8063 ADD_INSN1(ret, line_node, putobject, Qfalse);
8064 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8065
8066 ADD_INSN(ret, line_node, pop);
8067 ADD_INSN(ret, line_node, pop);
8068 ADD_LABEL(ret, match_succeeded);
8069
8070 return COMPILE_OK;
8071}
8072
8073static int
8074iseq_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)
8075{
8076 /*
8077 * if match_succeeded?
8078 * goto match_succeeded
8079 * end
8080 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8081 * key_error_p = false
8082 * match_succeeded:
8083 */
8084 const int line = nd_line(node);
8085 const NODE *line_node = node;
8086 LABEL *match_succeeded = NEW_LABEL(line);
8087
8088 ADD_INSN(ret, line_node, dup);
8089 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8090
8091 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8092 ADD_INSN1(ret, line_node, putobject, errmsg);
8093 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8094 ADD_INSN(ret, line_node, dup);
8095 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8096 ADD_INSN1(ret, line_node, putobject, pattern_length);
8097 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8098 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8099
8100 ADD_INSN1(ret, line_node, putobject, Qfalse);
8101 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8102
8103 ADD_INSN(ret, line_node, pop);
8104 ADD_INSN(ret, line_node, pop);
8105 ADD_LABEL(ret, match_succeeded);
8106
8107 return COMPILE_OK;
8108}
8109
8110static int
8111iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8112{
8113 /*
8114 * if match_succeeded?
8115 * goto match_succeeded
8116 * end
8117 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8118 * key_error_p = false
8119 * match_succeeded:
8120 */
8121 const int line = nd_line(node);
8122 const NODE *line_node = node;
8123 LABEL *match_succeeded = NEW_LABEL(line);
8124
8125 ADD_INSN(ret, line_node, dup);
8126 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8127
8128 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8129 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8130 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8131 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8132 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8133 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8134
8135 ADD_INSN1(ret, line_node, putobject, Qfalse);
8136 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8137
8138 ADD_INSN(ret, line_node, pop);
8139 ADD_INSN(ret, line_node, pop);
8140
8141 ADD_LABEL(ret, match_succeeded);
8142 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8143 ADD_INSN(ret, line_node, pop);
8144 ADD_INSN(ret, line_node, pop);
8145
8146 return COMPILE_OK;
8147}
8148
8149static int
8150compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8151{
8152 const NODE *pattern;
8153 const NODE *node = orig_node;
8154 LABEL *endlabel, *elselabel;
8155 DECL_ANCHOR(head);
8156 DECL_ANCHOR(body_seq);
8157 DECL_ANCHOR(cond_seq);
8158 int line;
8159 enum node_type type;
8160 const NODE *line_node;
8161 VALUE branches = 0;
8162 int branch_id = 0;
8163 bool single_pattern;
8164
8165 INIT_ANCHOR(head);
8166 INIT_ANCHOR(body_seq);
8167 INIT_ANCHOR(cond_seq);
8168
8169 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8170
8171 node = RNODE_CASE3(node)->nd_body;
8172 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8173 type = nd_type(node);
8174 line = nd_line(node);
8175 line_node = node;
8176 single_pattern = !RNODE_IN(node)->nd_next;
8177
8178 endlabel = NEW_LABEL(line);
8179 elselabel = NEW_LABEL(line);
8180
8181 if (single_pattern) {
8182 /* allocate stack for ... */
8183 ADD_INSN(head, line_node, putnil); /* key_error_key */
8184 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8185 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8186 ADD_INSN(head, line_node, putnil); /* error_string */
8187 }
8188 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8189
8190 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8191
8192 ADD_SEQ(ret, head); /* case VAL */
8193
8194 while (type == NODE_IN) {
8195 LABEL *l1;
8196
8197 if (branch_id) {
8198 ADD_INSN(body_seq, line_node, putnil);
8199 }
8200 l1 = NEW_LABEL(line);
8201 ADD_LABEL(body_seq, l1);
8202 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8203
8204 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8205 add_trace_branch_coverage(
8206 iseq,
8207 body_seq,
8208 nd_code_loc(coverage_node),
8209 nd_node_id(coverage_node),
8210 branch_id++,
8211 "in",
8212 branches);
8213
8214 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8215 ADD_INSNL(body_seq, line_node, jump, endlabel);
8216
8217 pattern = RNODE_IN(node)->nd_head;
8218 if (pattern) {
8219 int pat_line = nd_line(pattern);
8220 LABEL *next_pat = NEW_LABEL(pat_line);
8221 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8222 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8223 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8224 ADD_LABEL(cond_seq, next_pat);
8225 LABEL_UNREMOVABLE(next_pat);
8226 }
8227 else {
8228 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8229 return COMPILE_NG;
8230 }
8231
8232 node = RNODE_IN(node)->nd_next;
8233 if (!node) {
8234 break;
8235 }
8236 type = nd_type(node);
8237 line = nd_line(node);
8238 line_node = node;
8239 }
8240 /* else */
8241 if (node) {
8242 ADD_LABEL(cond_seq, elselabel);
8243 ADD_INSN(cond_seq, line_node, pop);
8244 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8245 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8246 CHECK(COMPILE_(cond_seq, "else", node, popped));
8247 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8248 ADD_INSN(cond_seq, line_node, putnil);
8249 if (popped) {
8250 ADD_INSN(cond_seq, line_node, putnil);
8251 }
8252 }
8253 else {
8254 debugs("== else (implicit)\n");
8255 ADD_LABEL(cond_seq, elselabel);
8256 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8257 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8258
8259 if (single_pattern) {
8260 /*
8261 * if key_error_p
8262 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8263 * else
8264 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8265 * end
8266 */
8267 LABEL *key_error, *fin;
8268 struct rb_callinfo_kwarg *kw_arg;
8269
8270 key_error = NEW_LABEL(line);
8271 fin = NEW_LABEL(line);
8272
8273 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8274 kw_arg->references = 0;
8275 kw_arg->keyword_len = 2;
8276 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8277 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8278
8279 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8280 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8281 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8282 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8283 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8284 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8285 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8286 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8287 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8288 ADD_INSNL(cond_seq, orig_node, jump, fin);
8289
8290 ADD_LABEL(cond_seq, key_error);
8291 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8292 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8293 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8294 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8295 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8296 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8297 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8298 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8299 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8300 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8301
8302 ADD_LABEL(cond_seq, fin);
8303 }
8304 else {
8305 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8306 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8307 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8308 }
8309 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8310 if (!popped) {
8311 ADD_INSN(cond_seq, orig_node, putnil);
8312 }
8313 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8314 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8315 if (popped) {
8316 ADD_INSN(cond_seq, line_node, putnil);
8317 }
8318 }
8319
8320 ADD_SEQ(ret, cond_seq);
8321 ADD_SEQ(ret, body_seq);
8322 ADD_LABEL(ret, endlabel);
8323 return COMPILE_OK;
8324}
8325
8326#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8327#undef CASE3_BI_OFFSET_ERROR_STRING
8328#undef CASE3_BI_OFFSET_KEY_ERROR_P
8329#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8330#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8331
8332static int
8333compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8334{
8335 const int line = (int)nd_line(node);
8336 const NODE *line_node = node;
8337
8338 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8339 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8340 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8341 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8342 VALUE branches = Qfalse;
8343
8345
8346 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8347 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8348 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8349 LABEL *end_label = NEW_LABEL(line);
8350 LABEL *adjust_label = NEW_LABEL(line);
8351
8352 LABEL *next_catch_label = NEW_LABEL(line);
8353 LABEL *tmp_label = NULL;
8354
8355 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8356 push_ensure_entry(iseq, &enl, NULL, NULL);
8357
8358 if (RNODE_WHILE(node)->nd_state == 1) {
8359 ADD_INSNL(ret, line_node, jump, next_label);
8360 }
8361 else {
8362 tmp_label = NEW_LABEL(line);
8363 ADD_INSNL(ret, line_node, jump, tmp_label);
8364 }
8365 ADD_LABEL(ret, adjust_label);
8366 ADD_INSN(ret, line_node, putnil);
8367 ADD_LABEL(ret, next_catch_label);
8368 ADD_INSN(ret, line_node, pop);
8369 ADD_INSNL(ret, line_node, jump, next_label);
8370 if (tmp_label) ADD_LABEL(ret, tmp_label);
8371
8372 ADD_LABEL(ret, redo_label);
8373 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8374
8375 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8376 add_trace_branch_coverage(
8377 iseq,
8378 ret,
8379 nd_code_loc(coverage_node),
8380 nd_node_id(coverage_node),
8381 0,
8382 "body",
8383 branches);
8384
8385 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8386 ADD_LABEL(ret, next_label); /* next */
8387
8388 if (type == NODE_WHILE) {
8389 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8390 redo_label, end_label));
8391 }
8392 else {
8393 /* until */
8394 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8395 end_label, redo_label));
8396 }
8397
8398 ADD_LABEL(ret, end_label);
8399 ADD_ADJUST_RESTORE(ret, adjust_label);
8400
8401 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8402 /* ADD_INSN(ret, line_node, putundef); */
8403 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8404 return COMPILE_NG;
8405 }
8406 else {
8407 ADD_INSN(ret, line_node, putnil);
8408 }
8409
8410 ADD_LABEL(ret, break_label); /* break */
8411
8412 if (popped) {
8413 ADD_INSN(ret, line_node, pop);
8414 }
8415
8416 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8417 break_label);
8418 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8419 next_catch_label);
8420 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8421 ISEQ_COMPILE_DATA(iseq)->redo_label);
8422
8423 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8424 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8425 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8426 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8427 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8428 return COMPILE_OK;
8429}
8430
8431static int
8432compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8433{
8434 const int line = nd_line(node);
8435 const NODE *line_node = node;
8436 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8437 LABEL *retry_label = NEW_LABEL(line);
8438 LABEL *retry_end_l = NEW_LABEL(line);
8439 const rb_iseq_t *child_iseq;
8440
8441 ADD_LABEL(ret, retry_label);
8442 if (nd_type_p(node, NODE_FOR)) {
8443 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8444
8445 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8446 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8447 ISEQ_TYPE_BLOCK, line);
8448 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8449 }
8450 else {
8451 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8452 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8453 ISEQ_TYPE_BLOCK, line);
8454 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8455 }
8456
8457 {
8458 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8459 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8460 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8461 //
8462 // Normally, "send" instruction is at the last.
8463 // However, qcall under branch coverage measurement adds some instructions after the "send".
8464 //
8465 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8466 INSN *iobj;
8467 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8468 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8469 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8470 iobj = (INSN*) get_prev_insn(iobj);
8471 }
8472 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8473
8474 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8475 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8476 if (&iobj->link == LAST_ELEMENT(ret)) {
8477 ret->last = (LINK_ELEMENT*) retry_end_l;
8478 }
8479 }
8480
8481 if (popped) {
8482 ADD_INSN(ret, line_node, pop);
8483 }
8484
8485 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8486
8487 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8488 return COMPILE_OK;
8489}
8490
8491static int
8492compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8493{
8494 /* massign to var in "for"
8495 * (args.length == 1 && Array.try_convert(args[0])) || args
8496 */
8497 const NODE *line_node = node;
8498 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8499 LABEL *not_single = NEW_LABEL(nd_line(var));
8500 LABEL *not_ary = NEW_LABEL(nd_line(var));
8501 CHECK(COMPILE(ret, "for var", var));
8502 ADD_INSN(ret, line_node, dup);
8503 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8504 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8505 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8506 ADD_INSNL(ret, line_node, branchunless, not_single);
8507 ADD_INSN(ret, line_node, dup);
8508 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8509 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8510 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8511 ADD_INSN(ret, line_node, swap);
8512 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8513 ADD_INSN(ret, line_node, dup);
8514 ADD_INSNL(ret, line_node, branchunless, not_ary);
8515 ADD_INSN(ret, line_node, swap);
8516 ADD_LABEL(ret, not_ary);
8517 ADD_INSN(ret, line_node, pop);
8518 ADD_LABEL(ret, not_single);
8519 return COMPILE_OK;
8520}
8521
8522static int
8523compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8524{
8525 const NODE *line_node = node;
8526 unsigned long throw_flag = 0;
8527
8528 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8529 /* while/until */
8530 LABEL *splabel = NEW_LABEL(0);
8531 ADD_LABEL(ret, splabel);
8532 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8533 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8534 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8535 add_ensure_iseq(ret, iseq, 0);
8536 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8537 ADD_ADJUST_RESTORE(ret, splabel);
8538
8539 if (!popped) {
8540 ADD_INSN(ret, line_node, putnil);
8541 }
8542 }
8543 else {
8544 const rb_iseq_t *ip = iseq;
8545
8546 while (ip) {
8547 if (!ISEQ_COMPILE_DATA(ip)) {
8548 ip = 0;
8549 break;
8550 }
8551
8552 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8553 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8554 }
8555 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8556 throw_flag = 0;
8557 }
8558 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8559 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8560 return COMPILE_NG;
8561 }
8562 else {
8563 ip = ISEQ_BODY(ip)->parent_iseq;
8564 continue;
8565 }
8566
8567 /* escape from block */
8568 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8569 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8570 if (popped) {
8571 ADD_INSN(ret, line_node, pop);
8572 }
8573 return COMPILE_OK;
8574 }
8575 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8576 return COMPILE_NG;
8577 }
8578 return COMPILE_OK;
8579}
8580
8581static int
8582compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8583{
8584 const NODE *line_node = node;
8585 unsigned long throw_flag = 0;
8586
8587 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8588 LABEL *splabel = NEW_LABEL(0);
8589 debugs("next in while loop\n");
8590 ADD_LABEL(ret, splabel);
8591 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8592 add_ensure_iseq(ret, iseq, 0);
8593 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8594 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8595 ADD_ADJUST_RESTORE(ret, splabel);
8596 if (!popped) {
8597 ADD_INSN(ret, line_node, putnil);
8598 }
8599 }
8600 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8601 LABEL *splabel = NEW_LABEL(0);
8602 debugs("next in block\n");
8603 ADD_LABEL(ret, splabel);
8604 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8605 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8606 add_ensure_iseq(ret, iseq, 0);
8607 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8608 ADD_ADJUST_RESTORE(ret, splabel);
8609
8610 if (!popped) {
8611 ADD_INSN(ret, line_node, putnil);
8612 }
8613 }
8614 else {
8615 const rb_iseq_t *ip = iseq;
8616
8617 while (ip) {
8618 if (!ISEQ_COMPILE_DATA(ip)) {
8619 ip = 0;
8620 break;
8621 }
8622
8623 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8624 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8625 /* while loop */
8626 break;
8627 }
8628 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8629 break;
8630 }
8631 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8632 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8633 return COMPILE_NG;
8634 }
8635
8636 ip = ISEQ_BODY(ip)->parent_iseq;
8637 }
8638 if (ip != 0) {
8639 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8640 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8641
8642 if (popped) {
8643 ADD_INSN(ret, line_node, pop);
8644 }
8645 }
8646 else {
8647 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8648 return COMPILE_NG;
8649 }
8650 }
8651 return COMPILE_OK;
8652}
8653
8654static int
8655compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8656{
8657 const NODE *line_node = node;
8658
8659 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8660 LABEL *splabel = NEW_LABEL(0);
8661 debugs("redo in while");
8662 ADD_LABEL(ret, splabel);
8663 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8664 add_ensure_iseq(ret, iseq, 0);
8665 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8666 ADD_ADJUST_RESTORE(ret, splabel);
8667 if (!popped) {
8668 ADD_INSN(ret, line_node, putnil);
8669 }
8670 }
8671 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8672 LABEL *splabel = NEW_LABEL(0);
8673
8674 debugs("redo in block");
8675 ADD_LABEL(ret, splabel);
8676 add_ensure_iseq(ret, iseq, 0);
8677 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8678 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8679 ADD_ADJUST_RESTORE(ret, splabel);
8680
8681 if (!popped) {
8682 ADD_INSN(ret, line_node, putnil);
8683 }
8684 }
8685 else {
8686 const rb_iseq_t *ip = iseq;
8687
8688 while (ip) {
8689 if (!ISEQ_COMPILE_DATA(ip)) {
8690 ip = 0;
8691 break;
8692 }
8693
8694 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8695 break;
8696 }
8697 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8698 break;
8699 }
8700 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8701 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8702 return COMPILE_NG;
8703 }
8704
8705 ip = ISEQ_BODY(ip)->parent_iseq;
8706 }
8707 if (ip != 0) {
8708 ADD_INSN(ret, line_node, putnil);
8709 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8710
8711 if (popped) {
8712 ADD_INSN(ret, line_node, pop);
8713 }
8714 }
8715 else {
8716 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8717 return COMPILE_NG;
8718 }
8719 }
8720 return COMPILE_OK;
8721}
8722
8723static int
8724compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8725{
8726 const NODE *line_node = node;
8727
8728 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8729 ADD_INSN(ret, line_node, putnil);
8730 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8731
8732 if (popped) {
8733 ADD_INSN(ret, line_node, pop);
8734 }
8735 }
8736 else {
8737 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8738 return COMPILE_NG;
8739 }
8740 return COMPILE_OK;
8741}
8742
8743static int
8744compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8745{
8746 const int line = nd_line(node);
8747 const NODE *line_node = node;
8748 LABEL *lstart = NEW_LABEL(line);
8749 LABEL *lend = NEW_LABEL(line);
8750 LABEL *lcont = NEW_LABEL(line);
8751 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8752 rb_str_concat(rb_str_new2("rescue in "),
8753 ISEQ_BODY(iseq)->location.label),
8754 ISEQ_TYPE_RESCUE, line);
8755
8756 lstart->rescued = LABEL_RESCUE_BEG;
8757 lend->rescued = LABEL_RESCUE_END;
8758 ADD_LABEL(ret, lstart);
8759
8760 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8761 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8762 {
8763 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8764 }
8765 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8766
8767 ADD_LABEL(ret, lend);
8768 if (RNODE_RESCUE(node)->nd_else) {
8769 ADD_INSN(ret, line_node, pop);
8770 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8771 }
8772 ADD_INSN(ret, line_node, nop);
8773 ADD_LABEL(ret, lcont);
8774
8775 if (popped) {
8776 ADD_INSN(ret, line_node, pop);
8777 }
8778
8779 /* register catch entry */
8780 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8781 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8782 return COMPILE_OK;
8783}
8784
8785static int
8786compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8787{
8788 const int line = nd_line(node);
8789 const NODE *line_node = node;
8790 const NODE *resq = node;
8791 const NODE *narg;
8792 LABEL *label_miss, *label_hit;
8793
8794 while (resq) {
8795 label_miss = NEW_LABEL(line);
8796 label_hit = NEW_LABEL(line);
8797
8798 narg = RNODE_RESBODY(resq)->nd_args;
8799 if (narg) {
8800 switch (nd_type(narg)) {
8801 case NODE_LIST:
8802 while (narg) {
8803 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8804 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8805 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8806 ADD_INSNL(ret, line_node, branchif, label_hit);
8807 narg = RNODE_LIST(narg)->nd_next;
8808 }
8809 break;
8810 case NODE_SPLAT:
8811 case NODE_ARGSCAT:
8812 case NODE_ARGSPUSH:
8813 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8814 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8815 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8816 ADD_INSNL(ret, line_node, branchif, label_hit);
8817 break;
8818 default:
8819 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8820 }
8821 }
8822 else {
8823 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8824 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8825 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8826 ADD_INSNL(ret, line_node, branchif, label_hit);
8827 }
8828 ADD_INSNL(ret, line_node, jump, label_miss);
8829 ADD_LABEL(ret, label_hit);
8830 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8831
8832 if (RNODE_RESBODY(resq)->nd_exc_var) {
8833 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8834 }
8835
8836 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) {
8837 // empty body
8838 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8839 }
8840 else {
8841 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8842 }
8843
8844 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8845 ADD_INSN(ret, line_node, nop);
8846 }
8847 ADD_INSN(ret, line_node, leave);
8848 ADD_LABEL(ret, label_miss);
8849 resq = RNODE_RESBODY(resq)->nd_next;
8850 }
8851 return COMPILE_OK;
8852}
8853
8854static int
8855compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8856{
8857 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8858 const NODE *line_node = node;
8859 DECL_ANCHOR(ensr);
8860 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8861 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8862 ISEQ_TYPE_ENSURE, line);
8863 LABEL *lstart = NEW_LABEL(line);
8864 LABEL *lend = NEW_LABEL(line);
8865 LABEL *lcont = NEW_LABEL(line);
8866 LINK_ELEMENT *last;
8867 int last_leave = 0;
8868 struct ensure_range er;
8870 struct ensure_range *erange;
8871
8872 INIT_ANCHOR(ensr);
8873 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8874 last = ensr->last;
8875 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8876
8877 er.begin = lstart;
8878 er.end = lend;
8879 er.next = 0;
8880 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8881
8882 ADD_LABEL(ret, lstart);
8883 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8884 ADD_LABEL(ret, lend);
8885 ADD_SEQ(ret, ensr);
8886 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8887 ADD_LABEL(ret, lcont);
8888 if (last_leave) ADD_INSN(ret, line_node, pop);
8889
8890 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8891 if (lstart->link.next != &lend->link) {
8892 while (erange) {
8893 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8894 ensure, lcont);
8895 erange = erange->next;
8896 }
8897 }
8898
8899 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8900 return COMPILE_OK;
8901}
8902
8903static int
8904compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8905{
8906 const NODE *line_node = node;
8907
8908 if (iseq) {
8909 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8910 const rb_iseq_t *is = iseq;
8911 enum rb_iseq_type t = type;
8912 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8913 LABEL *splabel = 0;
8914
8915 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8916 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8917 t = ISEQ_BODY(is)->type;
8918 }
8919 switch (t) {
8920 case ISEQ_TYPE_TOP:
8921 case ISEQ_TYPE_MAIN:
8922 if (retval) {
8923 rb_warn("argument of top-level return is ignored");
8924 }
8925 if (is == iseq) {
8926 /* plain top-level, leave directly */
8927 type = ISEQ_TYPE_METHOD;
8928 }
8929 break;
8930 default:
8931 break;
8932 }
8933
8934 if (type == ISEQ_TYPE_METHOD) {
8935 splabel = NEW_LABEL(0);
8936 ADD_LABEL(ret, splabel);
8937 ADD_ADJUST(ret, line_node, 0);
8938 }
8939
8940 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8941
8942 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8943 add_ensure_iseq(ret, iseq, 1);
8944 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8945 ADD_INSN(ret, line_node, leave);
8946 ADD_ADJUST_RESTORE(ret, splabel);
8947
8948 if (!popped) {
8949 ADD_INSN(ret, line_node, putnil);
8950 }
8951 }
8952 else {
8953 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8954 if (popped) {
8955 ADD_INSN(ret, line_node, pop);
8956 }
8957 }
8958 }
8959 return COMPILE_OK;
8960}
8961
8962static bool
8963drop_unreachable_return(LINK_ANCHOR *ret)
8964{
8965 LINK_ELEMENT *i = ret->last, *last;
8966 if (!i) return false;
8967 if (IS_TRACE(i)) i = i->prev;
8968 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8969 last = i = i->prev;
8970 if (IS_ADJUST(i)) i = i->prev;
8971 if (!IS_INSN(i)) return false;
8972 switch (INSN_OF(i)) {
8973 case BIN(leave):
8974 case BIN(jump):
8975 break;
8976 default:
8977 return false;
8978 }
8979 (ret->last = last->prev)->next = NULL;
8980 return true;
8981}
8982
8983static int
8984compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8985{
8986 CHECK(COMPILE_(ret, "nd_body", node, popped));
8987
8988 if (!popped && !all_string_result_p(node)) {
8989 const NODE *line_node = node;
8990 const unsigned int flag = VM_CALL_FCALL;
8991
8992 // Note, this dup could be removed if we are willing to change anytostring. It pops
8993 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8994 ADD_INSN(ret, line_node, dup);
8995 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8996 ADD_INSN(ret, line_node, anytostring);
8997 }
8998 return COMPILE_OK;
8999}
9000
9001static void
9002compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9003{
9004 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9005
9006 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9007 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9008}
9009
9010static LABEL *
9011qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9012{
9013 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9014 VALUE br = 0;
9015
9016 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
9017 *branches = br;
9018 ADD_INSN(recv, line_node, dup);
9019 ADD_INSNL(recv, line_node, branchnil, else_label);
9020 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9021 return else_label;
9022}
9023
9024static void
9025qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9026{
9027 LABEL *end_label;
9028 if (!else_label) return;
9029 end_label = NEW_LABEL(nd_line(line_node));
9030 ADD_INSNL(ret, line_node, jump, end_label);
9031 ADD_LABEL(ret, else_label);
9032 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9033 ADD_LABEL(ret, end_label);
9034}
9035
9036static int
9037compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9038{
9039 /* optimization shortcut
9040 * "literal".freeze -> opt_str_freeze("literal")
9041 */
9042 if (get_nd_recv(node) &&
9043 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9044 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9045 get_nd_args(node) == NULL &&
9046 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9047 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9048 VALUE str = get_string_value(get_nd_recv(node));
9049 if (get_node_call_nd_mid(node) == idUMinus) {
9050 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9051 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9052 }
9053 else {
9054 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9055 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9056 }
9057 RB_OBJ_WRITTEN(iseq, Qundef, str);
9058 if (popped) {
9059 ADD_INSN(ret, line_node, pop);
9060 }
9061 return TRUE;
9062 }
9063 return FALSE;
9064}
9065
9066static int
9067iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9068{
9069 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9070}
9071
9072static const struct rb_builtin_function *
9073iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9074{
9075 int i;
9076 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9077 for (i=0; table[i].index != -1; i++) {
9078 if (strcmp(table[i].name, name) == 0) {
9079 return &table[i];
9080 }
9081 }
9082 return NULL;
9083}
9084
9085static const char *
9086iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9087{
9088 const char *name = rb_id2name(mid);
9089 static const char prefix[] = "__builtin_";
9090 const size_t prefix_len = sizeof(prefix) - 1;
9091
9092 switch (type) {
9093 case NODE_CALL:
9094 if (recv) {
9095 switch (nd_type(recv)) {
9096 case NODE_VCALL:
9097 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9098 return name;
9099 }
9100 break;
9101 case NODE_CONST:
9102 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9103 return name;
9104 }
9105 break;
9106 default: break;
9107 }
9108 }
9109 break;
9110 case NODE_VCALL:
9111 case NODE_FCALL:
9112 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9113 return &name[prefix_len];
9114 }
9115 break;
9116 default: break;
9117 }
9118 return NULL;
9119}
9120
9121static int
9122delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9123{
9124
9125 if (argc == 0) {
9126 *pstart_index = 0;
9127 return TRUE;
9128 }
9129 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9130 unsigned int start=0;
9131
9132 // local_table: [p1, p2, p3, l1, l2, l3]
9133 // arguments: [p3, l1, l2] -> 2
9134 for (start = 0;
9135 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9136 start++) {
9137 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9138
9139 for (unsigned int i=start; i-start<argc; i++) {
9140 if (IS_INSN(elem) &&
9141 INSN_OF(elem) == BIN(getlocal)) {
9142 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9143 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9144
9145 if (local_level == 0) {
9146 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9147 if (0) { // for debug
9148 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9149 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9150 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9151 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9152 }
9153 if (i == index) {
9154 elem = elem->next;
9155 continue; /* for */
9156 }
9157 else {
9158 goto next;
9159 }
9160 }
9161 else {
9162 goto fail; // level != 0 is unsupported
9163 }
9164 }
9165 else {
9166 goto fail; // insn is not a getlocal
9167 }
9168 }
9169 goto success;
9170 next:;
9171 }
9172 fail:
9173 return FALSE;
9174 success:
9175 *pstart_index = start;
9176 return TRUE;
9177 }
9178 else {
9179 return FALSE;
9180 }
9181}
9182
9183// Compile Primitive.attr! :leaf, ...
9184static int
9185compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9186{
9187 VALUE symbol;
9188 VALUE string;
9189 if (!node) goto no_arg;
9190 while (node) {
9191 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9192 const NODE *next = RNODE_LIST(node)->nd_next;
9193
9194 node = RNODE_LIST(node)->nd_head;
9195 if (!node) goto no_arg;
9196 switch (nd_type(node)) {
9197 case NODE_SYM:
9198 symbol = rb_node_sym_string_val(node);
9199 break;
9200 default:
9201 goto bad_arg;
9202 }
9203
9204 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9205
9206 string = rb_sym2str(symbol);
9207 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9208 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9209 }
9210 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9211 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9212 }
9213 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9214 iseq_set_use_block(iseq);
9215 }
9216 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9217 // Let the iseq act like a C method in backtraces
9218 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9219 }
9220 else {
9221 goto unknown_arg;
9222 }
9223 node = next;
9224 }
9225 return COMPILE_OK;
9226 no_arg:
9227 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9228 return COMPILE_NG;
9229 non_symbol_arg:
9230 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9231 return COMPILE_NG;
9232 unknown_arg:
9233 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9234 return COMPILE_NG;
9235 bad_arg:
9236 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9237}
9238
9239static int
9240compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9241{
9242 VALUE name;
9243
9244 if (!node) goto no_arg;
9245 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9246 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9247 node = RNODE_LIST(node)->nd_head;
9248 if (!node) goto no_arg;
9249 switch (nd_type(node)) {
9250 case NODE_SYM:
9251 name = rb_node_sym_string_val(node);
9252 break;
9253 default:
9254 goto bad_arg;
9255 }
9256 if (!SYMBOL_P(name)) goto non_symbol_arg;
9257 if (!popped) {
9258 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9259 }
9260 return COMPILE_OK;
9261 no_arg:
9262 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9263 return COMPILE_NG;
9264 too_many_arg:
9265 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9266 return COMPILE_NG;
9267 non_symbol_arg:
9268 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9269 rb_builtin_class_name(name));
9270 return COMPILE_NG;
9271 bad_arg:
9272 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9273}
9274
9275static NODE *
9276mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9277{
9278 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9279 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9280 return RNODE_IF(node)->nd_body;
9281 }
9282 else {
9283 rb_bug("mandatory_node: can't find mandatory node");
9284 }
9285}
9286
9287static int
9288compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9289{
9290 // arguments
9291 struct rb_args_info args = {
9292 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9293 };
9294 rb_node_args_t args_node;
9295 rb_node_init(RNODE(&args_node), NODE_ARGS);
9296 args_node.nd_ainfo = args;
9297
9298 // local table without non-mandatory parameters
9299 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9300 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9301
9302 VALUE idtmp = 0;
9303 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9304 tbl->size = table_size;
9305
9306 int i;
9307
9308 // lead parameters
9309 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9310 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9311 }
9312 // local variables
9313 for (; i<table_size; i++) {
9314 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9315 }
9316
9317 rb_node_scope_t scope_node;
9318 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9319 scope_node.nd_tbl = tbl;
9320 scope_node.nd_body = mandatory_node(iseq, node);
9321 scope_node.nd_parent = NULL;
9322 scope_node.nd_args = &args_node;
9323
9324 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9325
9326 const rb_iseq_t *mandatory_only_iseq =
9327 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9328 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9329 nd_line(line_node), NULL, 0,
9330 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9331 ISEQ_BODY(iseq)->variable.script_lines);
9332 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9333
9334 ALLOCV_END(idtmp);
9335 return COMPILE_OK;
9336}
9337
9338static int
9339compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9340 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9341{
9342 NODE *args_node = get_nd_args(node);
9343
9344 if (parent_block != NULL) {
9345 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9346 return COMPILE_NG;
9347 }
9348 else {
9349# define BUILTIN_INLINE_PREFIX "_bi"
9350 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9351 bool cconst = false;
9352 retry:;
9353 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9354
9355 if (bf == NULL) {
9356 if (strcmp("cstmt!", builtin_func) == 0 ||
9357 strcmp("cexpr!", builtin_func) == 0) {
9358 // ok
9359 }
9360 else if (strcmp("cconst!", builtin_func) == 0) {
9361 cconst = true;
9362 }
9363 else if (strcmp("cinit!", builtin_func) == 0) {
9364 // ignore
9365 return COMPILE_OK;
9366 }
9367 else if (strcmp("attr!", builtin_func) == 0) {
9368 return compile_builtin_attr(iseq, args_node);
9369 }
9370 else if (strcmp("arg!", builtin_func) == 0) {
9371 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9372 }
9373 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9374 if (popped) {
9375 rb_bug("mandatory_only? should be in if condition");
9376 }
9377 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9378 rb_bug("mandatory_only? should be put on top");
9379 }
9380
9381 ADD_INSN1(ret, line_node, putobject, Qfalse);
9382 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9383 }
9384 else if (1) {
9385 rb_bug("can't find builtin function:%s", builtin_func);
9386 }
9387 else {
9388 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9389 return COMPILE_NG;
9390 }
9391
9392 int inline_index = nd_line(node);
9393 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9394 builtin_func = inline_func;
9395 args_node = NULL;
9396 goto retry;
9397 }
9398
9399 if (cconst) {
9400 typedef VALUE(*builtin_func0)(void *, VALUE);
9401 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9402 ADD_INSN1(ret, line_node, putobject, const_val);
9403 return COMPILE_OK;
9404 }
9405
9406 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9407
9408 unsigned int flag = 0;
9409 struct rb_callinfo_kwarg *keywords = NULL;
9410 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9411
9412 if (FIX2INT(argc) != bf->argc) {
9413 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9414 builtin_func, bf->argc, FIX2INT(argc));
9415 return COMPILE_NG;
9416 }
9417
9418 unsigned int start_index;
9419 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9420 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9421 }
9422 else {
9423 ADD_SEQ(ret, args);
9424 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9425 }
9426
9427 if (popped) ADD_INSN(ret, line_node, pop);
9428 return COMPILE_OK;
9429 }
9430}
9431
9432static int
9433compile_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)
9434{
9435 /* call: obj.method(...)
9436 * fcall: func(...)
9437 * vcall: func
9438 */
9439 DECL_ANCHOR(recv);
9440 DECL_ANCHOR(args);
9441 ID mid = get_node_call_nd_mid(node);
9442 VALUE argc;
9443 unsigned int flag = 0;
9444 struct rb_callinfo_kwarg *keywords = NULL;
9445 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9446 LABEL *else_label = NULL;
9447 VALUE branches = Qfalse;
9448
9449 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9450
9451 INIT_ANCHOR(recv);
9452 INIT_ANCHOR(args);
9453
9454#if OPT_SUPPORT_JOKE
9455 if (nd_type_p(node, NODE_VCALL)) {
9456 ID id_bitblt;
9457 ID id_answer;
9458
9459 CONST_ID(id_bitblt, "bitblt");
9460 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9461
9462 if (mid == id_bitblt) {
9463 ADD_INSN(ret, line_node, bitblt);
9464 return COMPILE_OK;
9465 }
9466 else if (mid == id_answer) {
9467 ADD_INSN(ret, line_node, answer);
9468 return COMPILE_OK;
9469 }
9470 }
9471 /* only joke */
9472 {
9473 ID goto_id;
9474 ID label_id;
9475
9476 CONST_ID(goto_id, "__goto__");
9477 CONST_ID(label_id, "__label__");
9478
9479 if (nd_type_p(node, NODE_FCALL) &&
9480 (mid == goto_id || mid == label_id)) {
9481 LABEL *label;
9482 st_data_t data;
9483 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9484 VALUE label_name;
9485
9486 if (!labels_table) {
9487 labels_table = st_init_numtable();
9488 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9489 }
9490 {
9491 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9492 return COMPILE_NG;
9493 }
9494
9495 if (mid == goto_id) {
9496 ADD_INSNL(ret, line_node, jump, label);
9497 }
9498 else {
9499 ADD_LABEL(ret, label);
9500 }
9501 return COMPILE_OK;
9502 }
9503 }
9504#endif
9505
9506 const char *builtin_func;
9507 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9508 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9509 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9510 }
9511
9512 /* receiver */
9513 if (!assume_receiver) {
9514 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9515 int idx, level;
9516
9517 if (mid == idCall &&
9518 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9519 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9520 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9521 }
9522 else if (private_recv_p(node)) {
9523 ADD_INSN(recv, node, putself);
9524 flag |= VM_CALL_FCALL;
9525 }
9526 else {
9527 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9528 }
9529
9530 if (type == NODE_QCALL) {
9531 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9532 }
9533 }
9534 else if (type == NODE_FCALL || type == NODE_VCALL) {
9535 ADD_CALL_RECEIVER(recv, line_node);
9536 }
9537 }
9538
9539 /* args */
9540 if (type != NODE_VCALL) {
9541 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9542 CHECK(!NIL_P(argc));
9543 }
9544 else {
9545 argc = INT2FIX(0);
9546 }
9547
9548 ADD_SEQ(ret, recv);
9549
9550 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9551 mid == rb_intern("new") &&
9552 parent_block == NULL &&
9553 !(flag & VM_CALL_ARGS_BLOCKARG);
9554
9555 if (inline_new) {
9556 ADD_INSN(ret, node, putnil);
9557 ADD_INSN(ret, node, swap);
9558 }
9559
9560 ADD_SEQ(ret, args);
9561
9562 debugp_param("call args argc", argc);
9563 debugp_param("call method", ID2SYM(mid));
9564
9565 switch ((int)type) {
9566 case NODE_VCALL:
9567 flag |= VM_CALL_VCALL;
9568 /* VCALL is funcall, so fall through */
9569 case NODE_FCALL:
9570 flag |= VM_CALL_FCALL;
9571 }
9572
9573 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9574 ADD_INSN(ret, line_node, splatkw);
9575 }
9576
9577 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9578 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9579
9580 if (inline_new) {
9581 // Jump unless the receiver uses the "basic" implementation of "new"
9582 VALUE ci;
9583 if (flag & VM_CALL_FORWARDING) {
9584 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9585 }
9586 else {
9587 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9588 }
9589 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9590 LABEL_REF(not_basic_new);
9591
9592 // optimized path
9593 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9594 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9595
9596 ADD_LABEL(ret, not_basic_new);
9597 // Fall back to normal send
9598 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9599 ADD_INSN(ret, line_node, swap);
9600
9601 ADD_LABEL(ret, not_basic_new_finish);
9602 ADD_INSN(ret, line_node, pop);
9603 }
9604 else {
9605 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9606 }
9607
9608 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9609 if (popped) {
9610 ADD_INSN(ret, line_node, pop);
9611 }
9612 return COMPILE_OK;
9613}
9614
9615static int
9616compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9617{
9618 const int line = nd_line(node);
9619 VALUE argc;
9620 unsigned int flag = 0;
9621 int asgnflag = 0;
9622 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9623
9624 /*
9625 * a[x] (op)= y
9626 *
9627 * nil # nil
9628 * eval a # nil a
9629 * eval x # nil a x
9630 * dupn 2 # nil a x a x
9631 * send :[] # nil a x a[x]
9632 * eval y # nil a x a[x] y
9633 * send op # nil a x ret
9634 * setn 3 # ret a x ret
9635 * send []= # ret ?
9636 * pop # ret
9637 */
9638
9639 /*
9640 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9641 * NODE_OP_ASGN nd_recv
9642 * nd_args->nd_head
9643 * nd_args->nd_body
9644 * nd_mid
9645 */
9646
9647 if (!popped) {
9648 ADD_INSN(ret, node, putnil);
9649 }
9650 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9651 CHECK(asgnflag != -1);
9652 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9653 case NODE_ZLIST:
9654 argc = INT2FIX(0);
9655 break;
9656 default:
9657 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9658 CHECK(!NIL_P(argc));
9659 }
9660 int dup_argn = FIX2INT(argc) + 1;
9661 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9662 flag |= asgnflag;
9663 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9664
9665 if (id == idOROP || id == idANDOP) {
9666 /* a[x] ||= y or a[x] &&= y
9667
9668 unless/if a[x]
9669 a[x]= y
9670 else
9671 nil
9672 end
9673 */
9674 LABEL *label = NEW_LABEL(line);
9675 LABEL *lfin = NEW_LABEL(line);
9676
9677 ADD_INSN(ret, node, dup);
9678 if (id == idOROP) {
9679 ADD_INSNL(ret, node, branchif, label);
9680 }
9681 else { /* idANDOP */
9682 ADD_INSNL(ret, node, branchunless, label);
9683 }
9684 ADD_INSN(ret, node, pop);
9685
9686 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9687 if (!popped) {
9688 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9689 }
9690 if (flag & VM_CALL_ARGS_SPLAT) {
9691 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9692 ADD_INSN(ret, node, swap);
9693 ADD_INSN1(ret, node, splatarray, Qtrue);
9694 ADD_INSN(ret, node, swap);
9695 flag |= VM_CALL_ARGS_SPLAT_MUT;
9696 }
9697 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9698 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9699 }
9700 else {
9701 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9702 }
9703 ADD_INSN(ret, node, pop);
9704 ADD_INSNL(ret, node, jump, lfin);
9705 ADD_LABEL(ret, label);
9706 if (!popped) {
9707 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9708 }
9709 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9710 ADD_LABEL(ret, lfin);
9711 }
9712 else {
9713 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9714 ADD_SEND(ret, node, id, INT2FIX(1));
9715 if (!popped) {
9716 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9717 }
9718 if (flag & VM_CALL_ARGS_SPLAT) {
9719 if (flag & VM_CALL_KW_SPLAT) {
9720 ADD_INSN1(ret, node, topn, INT2FIX(2));
9721 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9722 ADD_INSN1(ret, node, splatarray, Qtrue);
9723 flag |= VM_CALL_ARGS_SPLAT_MUT;
9724 }
9725 ADD_INSN(ret, node, swap);
9726 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9727 ADD_INSN1(ret, node, setn, INT2FIX(2));
9728 ADD_INSN(ret, node, pop);
9729 }
9730 else {
9731 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9732 ADD_INSN(ret, node, swap);
9733 ADD_INSN1(ret, node, splatarray, Qtrue);
9734 ADD_INSN(ret, node, swap);
9735 flag |= VM_CALL_ARGS_SPLAT_MUT;
9736 }
9737 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9738 }
9739 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9740 }
9741 else {
9742 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9743 }
9744 ADD_INSN(ret, node, pop);
9745 }
9746 return COMPILE_OK;
9747}
9748
9749static int
9750compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9751{
9752 const int line = nd_line(node);
9753 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9754 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9755 int asgnflag;
9756 LABEL *lfin = NEW_LABEL(line);
9757 LABEL *lcfin = NEW_LABEL(line);
9758 LABEL *lskip = 0;
9759 /*
9760 class C; attr_accessor :c; end
9761 r = C.new
9762 r.a &&= v # asgn2
9763
9764 eval r # r
9765 dup # r r
9766 eval r.a # r o
9767
9768 # or
9769 dup # r o o
9770 if lcfin # r o
9771 pop # r
9772 eval v # r v
9773 swap # v r
9774 topn 1 # v r v
9775 send a= # v ?
9776 jump lfin # v ?
9777
9778 lcfin: # r o
9779 swap # o r
9780
9781 lfin: # o ?
9782 pop # o
9783
9784 # or (popped)
9785 if lcfin # r
9786 eval v # r v
9787 send a= # ?
9788 jump lfin # ?
9789
9790 lcfin: # r
9791
9792 lfin: # ?
9793 pop #
9794
9795 # and
9796 dup # r o o
9797 unless lcfin
9798 pop # r
9799 eval v # r v
9800 swap # v r
9801 topn 1 # v r v
9802 send a= # v ?
9803 jump lfin # v ?
9804
9805 # others
9806 eval v # r o v
9807 send ?? # r w
9808 send a= # w
9809
9810 */
9811
9812 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9813 CHECK(asgnflag != -1);
9814 if (RNODE_OP_ASGN2(node)->nd_aid) {
9815 lskip = NEW_LABEL(line);
9816 ADD_INSN(ret, node, dup);
9817 ADD_INSNL(ret, node, branchnil, lskip);
9818 }
9819 ADD_INSN(ret, node, dup);
9820 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9821
9822 if (atype == idOROP || atype == idANDOP) {
9823 if (!popped) {
9824 ADD_INSN(ret, node, dup);
9825 }
9826 if (atype == idOROP) {
9827 ADD_INSNL(ret, node, branchif, lcfin);
9828 }
9829 else { /* idANDOP */
9830 ADD_INSNL(ret, node, branchunless, lcfin);
9831 }
9832 if (!popped) {
9833 ADD_INSN(ret, node, pop);
9834 }
9835 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9836 if (!popped) {
9837 ADD_INSN(ret, node, swap);
9838 ADD_INSN1(ret, node, topn, INT2FIX(1));
9839 }
9840 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9841 ADD_INSNL(ret, node, jump, lfin);
9842
9843 ADD_LABEL(ret, lcfin);
9844 if (!popped) {
9845 ADD_INSN(ret, node, swap);
9846 }
9847
9848 ADD_LABEL(ret, lfin);
9849 }
9850 else {
9851 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9852 ADD_SEND(ret, node, atype, INT2FIX(1));
9853 if (!popped) {
9854 ADD_INSN(ret, node, swap);
9855 ADD_INSN1(ret, node, topn, INT2FIX(1));
9856 }
9857 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9858 }
9859 if (lskip && popped) {
9860 ADD_LABEL(ret, lskip);
9861 }
9862 ADD_INSN(ret, node, pop);
9863 if (lskip && !popped) {
9864 ADD_LABEL(ret, lskip);
9865 }
9866 return COMPILE_OK;
9867}
9868
9869static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9870
9871static int
9872compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9873{
9874 const int line = nd_line(node);
9875 LABEL *lfin = 0;
9876 LABEL *lassign = 0;
9877 ID mid;
9878
9879 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9880 case NODE_COLON3:
9881 ADD_INSN1(ret, node, putobject, rb_cObject);
9882 break;
9883 case NODE_COLON2:
9884 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9885 break;
9886 default:
9887 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9888 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9889 return COMPILE_NG;
9890 }
9891 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9892 /* cref */
9893 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9894 lassign = NEW_LABEL(line);
9895 ADD_INSN(ret, node, dup); /* cref cref */
9896 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9897 ID2SYM(mid), Qtrue); /* cref bool */
9898 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9899 }
9900 ADD_INSN(ret, node, dup); /* cref cref */
9901 ADD_INSN1(ret, node, putobject, Qtrue);
9902 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9903
9904 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9905 lfin = NEW_LABEL(line);
9906 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9907 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9908 ADD_INSNL(ret, node, branchif, lfin);
9909 else /* idANDOP */
9910 ADD_INSNL(ret, node, branchunless, lfin);
9911 /* cref [obj] */
9912 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9913 if (lassign) ADD_LABEL(ret, lassign);
9914 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9915 /* cref value */
9916 if (popped)
9917 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9918 else {
9919 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9920 ADD_INSN(ret, node, swap); /* cref value value cref */
9921 }
9922 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9923 ADD_LABEL(ret, lfin); /* cref [value] */
9924 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9925 ADD_INSN(ret, node, pop); /* [value] */
9926 }
9927 else {
9928 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9929 /* cref obj value */
9930 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9931 /* cref value */
9932 ADD_INSN(ret, node, swap); /* value cref */
9933 if (!popped) {
9934 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9935 ADD_INSN(ret, node, swap); /* value value cref */
9936 }
9937 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9938 }
9939 return COMPILE_OK;
9940}
9941
9942static int
9943compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9944{
9945 const int line = nd_line(node);
9946 LABEL *lfin = NEW_LABEL(line);
9947 LABEL *lassign;
9948
9949 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9950 LABEL *lfinish[2];
9951 lfinish[0] = lfin;
9952 lfinish[1] = 0;
9953 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9954 lassign = lfinish[1];
9955 if (!lassign) {
9956 lassign = NEW_LABEL(line);
9957 }
9958 ADD_INSNL(ret, node, branchunless, lassign);
9959 }
9960 else {
9961 lassign = NEW_LABEL(line);
9962 }
9963
9964 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9965
9966 if (!popped) {
9967 ADD_INSN(ret, node, dup);
9968 }
9969
9970 if (type == NODE_OP_ASGN_AND) {
9971 ADD_INSNL(ret, node, branchunless, lfin);
9972 }
9973 else {
9974 ADD_INSNL(ret, node, branchif, lfin);
9975 }
9976
9977 if (!popped) {
9978 ADD_INSN(ret, node, pop);
9979 }
9980
9981 ADD_LABEL(ret, lassign);
9982 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9983 ADD_LABEL(ret, lfin);
9984 return COMPILE_OK;
9985}
9986
9987static int
9988compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9989{
9990 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9991 DECL_ANCHOR(args);
9992 int argc;
9993 unsigned int flag = 0;
9994 struct rb_callinfo_kwarg *keywords = NULL;
9995 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9996 int use_block = 1;
9997
9998 INIT_ANCHOR(args);
9999 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10000
10001 if (type == NODE_SUPER) {
10002 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10003 CHECK(!NIL_P(vargc));
10004 argc = FIX2INT(vargc);
10005 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10006 ADD_INSN(args, node, splatkw);
10007 }
10008
10009 if (flag & VM_CALL_ARGS_BLOCKARG) {
10010 use_block = 0;
10011 }
10012 }
10013 else {
10014 /* NODE_ZSUPER */
10015 int i;
10016 const rb_iseq_t *liseq = body->local_iseq;
10017 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10018 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10019 int lvar_level = get_lvar_level(iseq);
10020
10021 argc = local_body->param.lead_num;
10022
10023 /* normal arguments */
10024 for (i = 0; i < local_body->param.lead_num; i++) {
10025 int idx = local_body->local_table_size - i;
10026 ADD_GETLOCAL(args, node, idx, lvar_level);
10027 }
10028
10029 /* forward ... */
10030 if (local_body->param.flags.forwardable) {
10031 flag |= VM_CALL_FORWARDING;
10032 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10033 ADD_GETLOCAL(args, node, idx, lvar_level);
10034 }
10035
10036 if (local_body->param.flags.has_opt) {
10037 /* optional arguments */
10038 int j;
10039 for (j = 0; j < local_body->param.opt_num; j++) {
10040 int idx = local_body->local_table_size - (i + j);
10041 ADD_GETLOCAL(args, node, idx, lvar_level);
10042 }
10043 i += j;
10044 argc = i;
10045 }
10046 if (local_body->param.flags.has_rest) {
10047 /* rest argument */
10048 int idx = local_body->local_table_size - local_body->param.rest_start;
10049 ADD_GETLOCAL(args, node, idx, lvar_level);
10050 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10051
10052 argc = local_body->param.rest_start + 1;
10053 flag |= VM_CALL_ARGS_SPLAT;
10054 }
10055 if (local_body->param.flags.has_post) {
10056 /* post arguments */
10057 int post_len = local_body->param.post_num;
10058 int post_start = local_body->param.post_start;
10059
10060 if (local_body->param.flags.has_rest) {
10061 int j;
10062 for (j=0; j<post_len; j++) {
10063 int idx = local_body->local_table_size - (post_start + j);
10064 ADD_GETLOCAL(args, node, idx, lvar_level);
10065 }
10066 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10067 flag |= VM_CALL_ARGS_SPLAT_MUT;
10068 /* argc is settled at above */
10069 }
10070 else {
10071 int j;
10072 for (j=0; j<post_len; j++) {
10073 int idx = local_body->local_table_size - (post_start + j);
10074 ADD_GETLOCAL(args, node, idx, lvar_level);
10075 }
10076 argc = post_len + post_start;
10077 }
10078 }
10079
10080 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10081 int local_size = local_body->local_table_size;
10082 argc++;
10083
10084 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10085
10086 if (local_body->param.flags.has_kwrest) {
10087 int idx = local_body->local_table_size - local_kwd->rest_start;
10088 ADD_GETLOCAL(args, node, idx, lvar_level);
10089 RUBY_ASSERT(local_kwd->num > 0);
10090 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10091 }
10092 else {
10093 ADD_INSN1(args, node, newhash, INT2FIX(0));
10094 }
10095 for (i = 0; i < local_kwd->num; ++i) {
10096 ID id = local_kwd->table[i];
10097 int idx = local_size - get_local_var_idx(liseq, id);
10098 ADD_INSN1(args, node, putobject, ID2SYM(id));
10099 ADD_GETLOCAL(args, node, idx, lvar_level);
10100 }
10101 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10102 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10103 }
10104 else if (local_body->param.flags.has_kwrest) {
10105 int idx = local_body->local_table_size - local_kwd->rest_start;
10106 ADD_GETLOCAL(args, node, idx, lvar_level);
10107 argc++;
10108 flag |= VM_CALL_KW_SPLAT;
10109 }
10110 }
10111
10112 if (use_block && parent_block == NULL) {
10113 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10114 }
10115
10116 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10117 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10118 ADD_INSN(ret, node, putself);
10119 ADD_SEQ(ret, args);
10120
10121 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10122
10123 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10124 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10125 }
10126 else {
10127 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10128 }
10129
10130 if (popped) {
10131 ADD_INSN(ret, node, pop);
10132 }
10133 return COMPILE_OK;
10134}
10135
10136static int
10137compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10138{
10139 DECL_ANCHOR(args);
10140 VALUE argc;
10141 unsigned int flag = 0;
10142 struct rb_callinfo_kwarg *keywords = NULL;
10143
10144 INIT_ANCHOR(args);
10145
10146 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10147 case ISEQ_TYPE_TOP:
10148 case ISEQ_TYPE_MAIN:
10149 case ISEQ_TYPE_CLASS:
10150 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10151 return COMPILE_NG;
10152 default: /* valid */;
10153 }
10154
10155 if (RNODE_YIELD(node)->nd_head) {
10156 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10157 CHECK(!NIL_P(argc));
10158 }
10159 else {
10160 argc = INT2FIX(0);
10161 }
10162
10163 ADD_SEQ(ret, args);
10164 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10165 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10166
10167 if (popped) {
10168 ADD_INSN(ret, node, pop);
10169 }
10170
10171 int level = 0;
10172 const rb_iseq_t *tmp_iseq = iseq;
10173 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10174 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10175 }
10176 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10177
10178 return COMPILE_OK;
10179}
10180
10181static int
10182compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10183{
10184 DECL_ANCHOR(recv);
10185 DECL_ANCHOR(val);
10186
10187 INIT_ANCHOR(recv);
10188 INIT_ANCHOR(val);
10189 switch ((int)type) {
10190 case NODE_MATCH:
10191 {
10192 VALUE re = rb_node_regx_string_val(node);
10193 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10194 ADD_INSN1(recv, node, putobject, re);
10195 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10196 INT2FIX(0));
10197 }
10198 break;
10199 case NODE_MATCH2:
10200 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10201 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10202 break;
10203 case NODE_MATCH3:
10204 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10205 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10206 break;
10207 }
10208
10209 ADD_SEQ(ret, recv);
10210 ADD_SEQ(ret, val);
10211 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10212
10213 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10214 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10215 }
10216
10217 if (popped) {
10218 ADD_INSN(ret, node, pop);
10219 }
10220 return COMPILE_OK;
10221}
10222
10223static int
10224compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10225{
10226 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10227 /* constant */
10228 VALUE segments;
10229 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10230 (segments = collect_const_segments(iseq, node))) {
10231 ISEQ_BODY(iseq)->ic_size++;
10232 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10233 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10234 }
10235 else {
10236 /* constant */
10237 DECL_ANCHOR(pref);
10238 DECL_ANCHOR(body);
10239
10240 INIT_ANCHOR(pref);
10241 INIT_ANCHOR(body);
10242 CHECK(compile_const_prefix(iseq, node, pref, body));
10243 if (LIST_INSN_SIZE_ZERO(pref)) {
10244 ADD_INSN(ret, node, putnil);
10245 ADD_SEQ(ret, body);
10246 }
10247 else {
10248 ADD_SEQ(ret, pref);
10249 ADD_SEQ(ret, body);
10250 }
10251 }
10252 }
10253 else {
10254 /* function call */
10255 ADD_CALL_RECEIVER(ret, node);
10256 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10257 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10258 }
10259 if (popped) {
10260 ADD_INSN(ret, node, pop);
10261 }
10262 return COMPILE_OK;
10263}
10264
10265static int
10266compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10267{
10268 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10269
10270 /* add cache insn */
10271 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10272 ISEQ_BODY(iseq)->ic_size++;
10273 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10274 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10275 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10276 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10277 }
10278 else {
10279 ADD_INSN1(ret, node, putobject, rb_cObject);
10280 ADD_INSN1(ret, node, putobject, Qtrue);
10281 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10282 }
10283
10284 if (popped) {
10285 ADD_INSN(ret, node, pop);
10286 }
10287 return COMPILE_OK;
10288}
10289
10290static int
10291compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10292{
10293 VALUE flag = INT2FIX(excl);
10294 const NODE *b = RNODE_DOT2(node)->nd_beg;
10295 const NODE *e = RNODE_DOT2(node)->nd_end;
10296
10297 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10298 if (!popped) {
10299 VALUE bv = optimized_range_item(b);
10300 VALUE ev = optimized_range_item(e);
10301 VALUE val = rb_range_new(bv, ev, excl);
10303 ADD_INSN1(ret, node, putobject, val);
10304 RB_OBJ_WRITTEN(iseq, Qundef, val);
10305 }
10306 }
10307 else {
10308 CHECK(COMPILE_(ret, "min", b, popped));
10309 CHECK(COMPILE_(ret, "max", e, popped));
10310 if (!popped) {
10311 ADD_INSN1(ret, node, newrange, flag);
10312 }
10313 }
10314 return COMPILE_OK;
10315}
10316
10317static int
10318compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10319{
10320 if (!popped) {
10321 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10322 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10323 }
10324 else {
10325 const rb_iseq_t *ip = iseq;
10326 int level = 0;
10327 while (ip) {
10328 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10329 break;
10330 }
10331 ip = ISEQ_BODY(ip)->parent_iseq;
10332 level++;
10333 }
10334 if (ip) {
10335 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10336 }
10337 else {
10338 ADD_INSN(ret, node, putnil);
10339 }
10340 }
10341 }
10342 return COMPILE_OK;
10343}
10344
10345static int
10346compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10347{
10348 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10349 LABEL *end_label = NEW_LABEL(nd_line(node));
10350 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10351
10352 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10353 /* required argument. do nothing */
10354 COMPILE_ERROR(ERROR_ARGS "unreachable");
10355 return COMPILE_NG;
10356 }
10357 else if (nd_type_p(default_value, NODE_SYM) ||
10358 nd_type_p(default_value, NODE_REGX) ||
10359 nd_type_p(default_value, NODE_LINE) ||
10360 nd_type_p(default_value, NODE_INTEGER) ||
10361 nd_type_p(default_value, NODE_FLOAT) ||
10362 nd_type_p(default_value, NODE_RATIONAL) ||
10363 nd_type_p(default_value, NODE_IMAGINARY) ||
10364 nd_type_p(default_value, NODE_NIL) ||
10365 nd_type_p(default_value, NODE_TRUE) ||
10366 nd_type_p(default_value, NODE_FALSE)) {
10367 COMPILE_ERROR(ERROR_ARGS "unreachable");
10368 return COMPILE_NG;
10369 }
10370 else {
10371 /* if keywordcheck(_kw_bits, nth_keyword)
10372 * kw = default_value
10373 * end
10374 */
10375 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10376 int keyword_idx = body->param.keyword->num;
10377
10378 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10379 ADD_INSNL(ret, node, branchif, end_label);
10380 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10381 ADD_LABEL(ret, end_label);
10382 }
10383 return COMPILE_OK;
10384}
10385
10386static int
10387compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10388{
10389 DECL_ANCHOR(recv);
10390 DECL_ANCHOR(args);
10391 unsigned int flag = 0;
10392 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10393 VALUE argc;
10394 LABEL *else_label = NULL;
10395 VALUE branches = Qfalse;
10396
10397 INIT_ANCHOR(recv);
10398 INIT_ANCHOR(args);
10399 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10400 CHECK(!NIL_P(argc));
10401
10402 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10403 CHECK(asgnflag != -1);
10404 flag |= (unsigned int)asgnflag;
10405
10406 debugp_param("argc", argc);
10407 debugp_param("nd_mid", ID2SYM(mid));
10408
10409 if (!rb_is_attrset_id(mid)) {
10410 /* safe nav attr */
10411 mid = rb_id_attrset(mid);
10412 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10413 }
10414 if (!popped) {
10415 ADD_INSN(ret, node, putnil);
10416 ADD_SEQ(ret, recv);
10417 ADD_SEQ(ret, args);
10418
10419 if (flag & VM_CALL_ARGS_SPLAT) {
10420 ADD_INSN(ret, node, dup);
10421 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10422 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10423 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10424 ADD_INSN (ret, node, pop);
10425 }
10426 else {
10427 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10428 }
10429 }
10430 else {
10431 ADD_SEQ(ret, recv);
10432 ADD_SEQ(ret, args);
10433 }
10434 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10435 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10436 ADD_INSN(ret, node, pop);
10437 return COMPILE_OK;
10438}
10439
10440static int
10441compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10442{
10443 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10444 ADD_SEQ(ret, sub);
10445
10446 if (copy) {
10447 /*
10448 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10449 * NEW_LIST(value, loc), loc);
10450 */
10451 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10452 }
10453 else {
10454 /*
10455 * NEW_CALL(fcore, rb_intern("make_shareable"),
10456 * NEW_LIST(value, loc), loc);
10457 */
10458 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10459 }
10460
10461 return COMPILE_OK;
10462}
10463
10464static VALUE
10465node_const_decl_val(const NODE *node)
10466{
10467 VALUE path;
10468 switch (nd_type(node)) {
10469 case NODE_CDECL:
10470 if (RNODE_CDECL(node)->nd_vid) {
10471 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10472 goto end;
10473 }
10474 else {
10475 node = RNODE_CDECL(node)->nd_else;
10476 }
10477 break;
10478 case NODE_COLON2:
10479 break;
10480 case NODE_COLON3:
10481 // ::Const
10482 path = rb_str_new_cstr("::");
10483 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10484 goto end;
10485 default:
10486 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10488 }
10489
10490 path = rb_ary_new();
10491 if (node) {
10492 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10493 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10494 }
10495 if (node && nd_type_p(node, NODE_CONST)) {
10496 // Const::Name
10497 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10498 }
10499 else if (node && nd_type_p(node, NODE_COLON3)) {
10500 // ::Const::Name
10501 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10502 rb_ary_push(path, rb_str_new(0, 0));
10503 }
10504 else {
10505 // expression::Name
10506 rb_ary_push(path, rb_str_new_cstr("..."));
10507 }
10508 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10509 }
10510 end:
10511 path = rb_fstring(path);
10512 return path;
10513}
10514
10515static VALUE
10516const_decl_path(NODE *dest)
10517{
10518 VALUE path = Qnil;
10519 if (!nd_type_p(dest, NODE_CALL)) {
10520 path = node_const_decl_val(dest);
10521 }
10522 return path;
10523}
10524
10525static int
10526compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10527{
10528 /*
10529 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10530 */
10531 VALUE path = const_decl_path(dest);
10532 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10533 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10534 ADD_INSN1(ret, value, putobject, path);
10535 RB_OBJ_WRITTEN(iseq, Qundef, path);
10536 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10537
10538 return COMPILE_OK;
10539}
10540
10541#ifndef SHAREABLE_BARE_EXPRESSION
10542#define SHAREABLE_BARE_EXPRESSION 1
10543#endif
10544
10545static int
10546compile_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)
10547{
10548# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10549 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10550 VALUE lit = Qnil;
10551 DECL_ANCHOR(anchor);
10552
10553 enum node_type type = node ? nd_type(node) : NODE_NIL;
10554 switch (type) {
10555 case NODE_TRUE:
10556 *value_p = Qtrue;
10557 goto compile;
10558 case NODE_FALSE:
10559 *value_p = Qfalse;
10560 goto compile;
10561 case NODE_NIL:
10562 *value_p = Qnil;
10563 goto compile;
10564 case NODE_SYM:
10565 *value_p = rb_node_sym_string_val(node);
10566 goto compile;
10567 case NODE_REGX:
10568 *value_p = rb_node_regx_string_val(node);
10569 goto compile;
10570 case NODE_LINE:
10571 *value_p = rb_node_line_lineno_val(node);
10572 goto compile;
10573 case NODE_INTEGER:
10574 *value_p = rb_node_integer_literal_val(node);
10575 goto compile;
10576 case NODE_FLOAT:
10577 *value_p = rb_node_float_literal_val(node);
10578 goto compile;
10579 case NODE_RATIONAL:
10580 *value_p = rb_node_rational_literal_val(node);
10581 goto compile;
10582 case NODE_IMAGINARY:
10583 *value_p = rb_node_imaginary_literal_val(node);
10584 goto compile;
10585 case NODE_ENCODING:
10586 *value_p = rb_node_encoding_val(node);
10587
10588 compile:
10589 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10590 *shareable_literal_p = 1;
10591 return COMPILE_OK;
10592
10593 case NODE_DSTR:
10594 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10595 if (shareable == rb_parser_shareable_literal) {
10596 /*
10597 * NEW_CALL(node, idUMinus, 0, loc);
10598 *
10599 * -"#{var}"
10600 */
10601 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10602 }
10603 *value_p = Qundef;
10604 *shareable_literal_p = 1;
10605 return COMPILE_OK;
10606
10607 case NODE_STR:{
10608 VALUE lit = rb_node_str_string_val(node);
10609 ADD_INSN1(ret, node, putobject, lit);
10610 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10611 *value_p = lit;
10612 *shareable_literal_p = 1;
10613
10614 return COMPILE_OK;
10615 }
10616
10617 case NODE_FILE:{
10618 VALUE lit = rb_node_file_path_val(node);
10619 ADD_INSN1(ret, node, putobject, lit);
10620 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10621 *value_p = lit;
10622 *shareable_literal_p = 1;
10623
10624 return COMPILE_OK;
10625 }
10626
10627 case NODE_ZLIST:{
10628 VALUE lit = rb_ary_new();
10629 OBJ_FREEZE(lit);
10630 ADD_INSN1(ret, node, putobject, lit);
10631 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10632 *value_p = lit;
10633 *shareable_literal_p = 1;
10634
10635 return COMPILE_OK;
10636 }
10637
10638 case NODE_LIST:{
10639 INIT_ANCHOR(anchor);
10640 lit = rb_ary_new();
10641 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10642 VALUE val;
10643 int shareable_literal_p2;
10644 NODE *elt = RNODE_LIST(n)->nd_head;
10645 if (elt) {
10646 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10647 if (shareable_literal_p2) {
10648 /* noop */
10649 }
10650 else if (RTEST(lit)) {
10651 rb_ary_clear(lit);
10652 lit = Qfalse;
10653 }
10654 }
10655 if (RTEST(lit)) {
10656 if (!UNDEF_P(val)) {
10657 rb_ary_push(lit, val);
10658 }
10659 else {
10660 rb_ary_clear(lit);
10661 lit = Qnil; /* make shareable at runtime */
10662 }
10663 }
10664 }
10665 break;
10666 }
10667 case NODE_HASH:{
10668 if (!RNODE_HASH(node)->nd_brace) {
10669 *value_p = Qundef;
10670 *shareable_literal_p = 0;
10671 return COMPILE_OK;
10672 }
10673 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10674 if (!RNODE_LIST(n)->nd_head) {
10675 // If the hash node have a keyword splat, fall back to the default case.
10676 goto compile_shareable;
10677 }
10678 }
10679
10680 INIT_ANCHOR(anchor);
10681 lit = rb_hash_new();
10682 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10683 VALUE key_val = 0;
10684 VALUE value_val = 0;
10685 int shareable_literal_p2;
10686 NODE *key = RNODE_LIST(n)->nd_head;
10687 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10688 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10689 if (shareable_literal_p2) {
10690 /* noop */
10691 }
10692 else if (RTEST(lit)) {
10693 rb_hash_clear(lit);
10694 lit = Qfalse;
10695 }
10696 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10697 if (shareable_literal_p2) {
10698 /* noop */
10699 }
10700 else if (RTEST(lit)) {
10701 rb_hash_clear(lit);
10702 lit = Qfalse;
10703 }
10704 if (RTEST(lit)) {
10705 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10706 rb_hash_aset(lit, key_val, value_val);
10707 }
10708 else {
10709 rb_hash_clear(lit);
10710 lit = Qnil; /* make shareable at runtime */
10711 }
10712 }
10713 }
10714 break;
10715 }
10716
10717 default:
10718
10719 compile_shareable:
10720 if (shareable == rb_parser_shareable_literal &&
10721 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10722 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10723 *value_p = Qundef;
10724 *shareable_literal_p = 1;
10725 return COMPILE_OK;
10726 }
10727 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10728 *value_p = Qundef;
10729 *shareable_literal_p = 0;
10730 return COMPILE_OK;
10731 }
10732
10733 /* Array or Hash that does not have keyword splat */
10734 if (!lit) {
10735 if (nd_type(node) == NODE_LIST) {
10736 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10737 }
10738 else if (nd_type(node) == NODE_HASH) {
10739 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10740 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10741 }
10742 *value_p = Qundef;
10743 *shareable_literal_p = 0;
10744 ADD_SEQ(ret, anchor);
10745 return COMPILE_OK;
10746 }
10747 if (NIL_P(lit)) {
10748 // if shareable_literal, all elements should have been ensured
10749 // as shareable
10750 if (nd_type(node) == NODE_LIST) {
10751 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10752 }
10753 else if (nd_type(node) == NODE_HASH) {
10754 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10755 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10756 }
10757 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10758 *value_p = Qundef;
10759 *shareable_literal_p = 1;
10760 }
10761 else {
10763 ADD_INSN1(ret, node, putobject, val);
10764 RB_OBJ_WRITTEN(iseq, Qundef, val);
10765 *value_p = val;
10766 *shareable_literal_p = 1;
10767 }
10768
10769 return COMPILE_OK;
10770}
10771
10772static int
10773compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10774{
10775 int literal_p = 0;
10776 VALUE val;
10777 DECL_ANCHOR(anchor);
10778 INIT_ANCHOR(anchor);
10779
10780 switch (shareable) {
10781 case rb_parser_shareable_none:
10782 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10783 return COMPILE_OK;
10784
10785 case rb_parser_shareable_literal:
10786 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10787 ADD_SEQ(ret, anchor);
10788 return COMPILE_OK;
10789
10790 case rb_parser_shareable_copy:
10791 case rb_parser_shareable_everything:
10792 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10793 if (!literal_p) {
10794 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10795 }
10796 else {
10797 ADD_SEQ(ret, anchor);
10798 }
10799 return COMPILE_OK;
10800 default:
10801 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10802 }
10803}
10804
10805static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10813static int
10814iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10815{
10816 if (node == 0) {
10817 if (!popped) {
10818 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10819 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10820 debugs("node: NODE_NIL(implicit)\n");
10821 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10822 }
10823 return COMPILE_OK;
10824 }
10825 return iseq_compile_each0(iseq, ret, node, popped);
10826}
10827
10828static int
10829iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10830{
10831 const int line = (int)nd_line(node);
10832 const enum node_type type = nd_type(node);
10833 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10834
10835 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10836 /* ignore */
10837 }
10838 else {
10839 if (nd_fl_newline(node)) {
10840 int event = RUBY_EVENT_LINE;
10841 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10842 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10843 event |= RUBY_EVENT_COVERAGE_LINE;
10844 }
10845 ADD_TRACE(ret, event);
10846 }
10847 }
10848
10849 debug_node_start(node);
10850#undef BEFORE_RETURN
10851#define BEFORE_RETURN debug_node_end()
10852
10853 switch (type) {
10854 case NODE_BLOCK:
10855 CHECK(compile_block(iseq, ret, node, popped));
10856 break;
10857 case NODE_IF:
10858 case NODE_UNLESS:
10859 CHECK(compile_if(iseq, ret, node, popped, type));
10860 break;
10861 case NODE_CASE:
10862 CHECK(compile_case(iseq, ret, node, popped));
10863 break;
10864 case NODE_CASE2:
10865 CHECK(compile_case2(iseq, ret, node, popped));
10866 break;
10867 case NODE_CASE3:
10868 CHECK(compile_case3(iseq, ret, node, popped));
10869 break;
10870 case NODE_WHILE:
10871 case NODE_UNTIL:
10872 CHECK(compile_loop(iseq, ret, node, popped, type));
10873 break;
10874 case NODE_FOR:
10875 case NODE_ITER:
10876 CHECK(compile_iter(iseq, ret, node, popped));
10877 break;
10878 case NODE_FOR_MASGN:
10879 CHECK(compile_for_masgn(iseq, ret, node, popped));
10880 break;
10881 case NODE_BREAK:
10882 CHECK(compile_break(iseq, ret, node, popped));
10883 break;
10884 case NODE_NEXT:
10885 CHECK(compile_next(iseq, ret, node, popped));
10886 break;
10887 case NODE_REDO:
10888 CHECK(compile_redo(iseq, ret, node, popped));
10889 break;
10890 case NODE_RETRY:
10891 CHECK(compile_retry(iseq, ret, node, popped));
10892 break;
10893 case NODE_BEGIN:{
10894 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10895 break;
10896 }
10897 case NODE_RESCUE:
10898 CHECK(compile_rescue(iseq, ret, node, popped));
10899 break;
10900 case NODE_RESBODY:
10901 CHECK(compile_resbody(iseq, ret, node, popped));
10902 break;
10903 case NODE_ENSURE:
10904 CHECK(compile_ensure(iseq, ret, node, popped));
10905 break;
10906
10907 case NODE_AND:
10908 case NODE_OR:{
10909 LABEL *end_label = NEW_LABEL(line);
10910 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10911 if (!popped) {
10912 ADD_INSN(ret, node, dup);
10913 }
10914 if (type == NODE_AND) {
10915 ADD_INSNL(ret, node, branchunless, end_label);
10916 }
10917 else {
10918 ADD_INSNL(ret, node, branchif, end_label);
10919 }
10920 if (!popped) {
10921 ADD_INSN(ret, node, pop);
10922 }
10923 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10924 ADD_LABEL(ret, end_label);
10925 break;
10926 }
10927
10928 case NODE_MASGN:{
10929 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10930 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10931 compile_massign(iseq, ret, node, popped);
10932 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10933 break;
10934 }
10935
10936 case NODE_LASGN:{
10937 ID id = RNODE_LASGN(node)->nd_vid;
10938 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10939
10940 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10941 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10942
10943 if (!popped) {
10944 ADD_INSN(ret, node, dup);
10945 }
10946 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10947 break;
10948 }
10949 case NODE_DASGN: {
10950 int idx, lv, ls;
10951 ID id = RNODE_DASGN(node)->nd_vid;
10952 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10953 debugi("dassn id", rb_id2str(id) ? id : '*');
10954
10955 if (!popped) {
10956 ADD_INSN(ret, node, dup);
10957 }
10958
10959 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10960
10961 if (idx < 0) {
10962 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10963 rb_id2str(id));
10964 goto ng;
10965 }
10966 ADD_SETLOCAL(ret, node, ls - idx, lv);
10967 break;
10968 }
10969 case NODE_GASGN:{
10970 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10971
10972 if (!popped) {
10973 ADD_INSN(ret, node, dup);
10974 }
10975 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10976 break;
10977 }
10978 case NODE_IASGN:{
10979 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10980 if (!popped) {
10981 ADD_INSN(ret, node, dup);
10982 }
10983 ADD_INSN2(ret, node, setinstancevariable,
10984 ID2SYM(RNODE_IASGN(node)->nd_vid),
10985 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10986 break;
10987 }
10988 case NODE_CDECL:{
10989 if (RNODE_CDECL(node)->nd_vid) {
10990 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10991
10992 if (!popped) {
10993 ADD_INSN(ret, node, dup);
10994 }
10995
10996 ADD_INSN1(ret, node, putspecialobject,
10997 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10998 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10999 }
11000 else {
11001 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11002 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11003 ADD_INSN(ret, node, swap);
11004
11005 if (!popped) {
11006 ADD_INSN1(ret, node, topn, INT2FIX(1));
11007 ADD_INSN(ret, node, swap);
11008 }
11009
11010 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11011 }
11012 break;
11013 }
11014 case NODE_CVASGN:{
11015 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11016 if (!popped) {
11017 ADD_INSN(ret, node, dup);
11018 }
11019 ADD_INSN2(ret, node, setclassvariable,
11020 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11021 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11022 break;
11023 }
11024 case NODE_OP_ASGN1:
11025 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11026 break;
11027 case NODE_OP_ASGN2:
11028 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11029 break;
11030 case NODE_OP_CDECL:
11031 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11032 break;
11033 case NODE_OP_ASGN_AND:
11034 case NODE_OP_ASGN_OR:
11035 CHECK(compile_op_log(iseq, ret, node, popped, type));
11036 break;
11037 case NODE_CALL: /* obj.foo */
11038 case NODE_OPCALL: /* foo[] */
11039 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11040 break;
11041 }
11042 case NODE_QCALL: /* obj&.foo */
11043 case NODE_FCALL: /* foo() */
11044 case NODE_VCALL: /* foo (variable or call) */
11045 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11046 goto ng;
11047 }
11048 break;
11049 case NODE_SUPER:
11050 case NODE_ZSUPER:
11051 CHECK(compile_super(iseq, ret, node, popped, type));
11052 break;
11053 case NODE_LIST:{
11054 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11055 break;
11056 }
11057 case NODE_ZLIST:{
11058 if (!popped) {
11059 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11060 }
11061 break;
11062 }
11063 case NODE_HASH:
11064 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11065 break;
11066 case NODE_RETURN:
11067 CHECK(compile_return(iseq, ret, node, popped));
11068 break;
11069 case NODE_YIELD:
11070 CHECK(compile_yield(iseq, ret, node, popped));
11071 break;
11072 case NODE_LVAR:{
11073 if (!popped) {
11074 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11075 }
11076 break;
11077 }
11078 case NODE_DVAR:{
11079 int lv, idx, ls;
11080 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11081 if (!popped) {
11082 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11083 if (idx < 0) {
11084 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11085 rb_id2str(RNODE_DVAR(node)->nd_vid));
11086 goto ng;
11087 }
11088 ADD_GETLOCAL(ret, node, ls - idx, lv);
11089 }
11090 break;
11091 }
11092 case NODE_GVAR:{
11093 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11094 if (popped) {
11095 ADD_INSN(ret, node, pop);
11096 }
11097 break;
11098 }
11099 case NODE_IVAR:{
11100 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11101 if (!popped) {
11102 ADD_INSN2(ret, node, getinstancevariable,
11103 ID2SYM(RNODE_IVAR(node)->nd_vid),
11104 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11105 }
11106 break;
11107 }
11108 case NODE_CONST:{
11109 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11110
11111 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11112 body->ic_size++;
11113 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11114 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11115 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11116 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11117 }
11118 else {
11119 ADD_INSN(ret, node, putnil);
11120 ADD_INSN1(ret, node, putobject, Qtrue);
11121 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11122 }
11123
11124 if (popped) {
11125 ADD_INSN(ret, node, pop);
11126 }
11127 break;
11128 }
11129 case NODE_CVAR:{
11130 if (!popped) {
11131 ADD_INSN2(ret, node, getclassvariable,
11132 ID2SYM(RNODE_CVAR(node)->nd_vid),
11133 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11134 }
11135 break;
11136 }
11137 case NODE_NTH_REF:{
11138 if (!popped) {
11139 if (!RNODE_NTH_REF(node)->nd_nth) {
11140 ADD_INSN(ret, node, putnil);
11141 break;
11142 }
11143 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11144 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11145 }
11146 break;
11147 }
11148 case NODE_BACK_REF:{
11149 if (!popped) {
11150 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11151 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11152 }
11153 break;
11154 }
11155 case NODE_MATCH:
11156 case NODE_MATCH2:
11157 case NODE_MATCH3:
11158 CHECK(compile_match(iseq, ret, node, popped, type));
11159 break;
11160 case NODE_SYM:{
11161 if (!popped) {
11162 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11163 }
11164 break;
11165 }
11166 case NODE_LINE:{
11167 if (!popped) {
11168 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11169 }
11170 break;
11171 }
11172 case NODE_ENCODING:{
11173 if (!popped) {
11174 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11175 }
11176 break;
11177 }
11178 case NODE_INTEGER:{
11179 VALUE lit = rb_node_integer_literal_val(node);
11180 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11181 debugp_param("integer", lit);
11182 if (!popped) {
11183 ADD_INSN1(ret, node, putobject, lit);
11184 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11185 }
11186 break;
11187 }
11188 case NODE_FLOAT:{
11189 VALUE lit = rb_node_float_literal_val(node);
11190 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11191 debugp_param("float", lit);
11192 if (!popped) {
11193 ADD_INSN1(ret, node, putobject, lit);
11194 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11195 }
11196 break;
11197 }
11198 case NODE_RATIONAL:{
11199 VALUE lit = rb_node_rational_literal_val(node);
11201 debugp_param("rational", lit);
11202 if (!popped) {
11203 ADD_INSN1(ret, node, putobject, lit);
11204 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11205 }
11206 break;
11207 }
11208 case NODE_IMAGINARY:{
11209 VALUE lit = rb_node_imaginary_literal_val(node);
11211 debugp_param("imaginary", lit);
11212 if (!popped) {
11213 ADD_INSN1(ret, node, putobject, lit);
11214 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11215 }
11216 break;
11217 }
11218 case NODE_FILE:
11219 case NODE_STR:{
11220 debugp_param("nd_lit", get_string_value(node));
11221 if (!popped) {
11222 VALUE lit = get_string_value(node);
11223 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11224 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11225 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11226 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11227 RB_OBJ_SET_SHAREABLE(lit);
11228 }
11229 switch (option->frozen_string_literal) {
11230 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11231 ADD_INSN1(ret, node, putchilledstring, lit);
11232 break;
11233 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11234 ADD_INSN1(ret, node, putstring, lit);
11235 break;
11236 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11237 ADD_INSN1(ret, node, putobject, lit);
11238 break;
11239 default:
11240 rb_bug("invalid frozen_string_literal");
11241 }
11242 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11243 }
11244 break;
11245 }
11246 case NODE_DSTR:{
11247 compile_dstr(iseq, ret, node);
11248
11249 if (popped) {
11250 ADD_INSN(ret, node, pop);
11251 }
11252 break;
11253 }
11254 case NODE_XSTR:{
11255 ADD_CALL_RECEIVER(ret, node);
11256 VALUE str = rb_node_str_string_val(node);
11257 ADD_INSN1(ret, node, putobject, str);
11258 RB_OBJ_WRITTEN(iseq, Qundef, str);
11259 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11260
11261 if (popped) {
11262 ADD_INSN(ret, node, pop);
11263 }
11264 break;
11265 }
11266 case NODE_DXSTR:{
11267 ADD_CALL_RECEIVER(ret, node);
11268 compile_dstr(iseq, ret, node);
11269 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11270
11271 if (popped) {
11272 ADD_INSN(ret, node, pop);
11273 }
11274 break;
11275 }
11276 case NODE_EVSTR:
11277 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11278 break;
11279 case NODE_REGX:{
11280 if (!popped) {
11281 VALUE lit = rb_node_regx_string_val(node);
11282 RB_OBJ_SET_SHAREABLE(lit);
11283 ADD_INSN1(ret, node, putobject, lit);
11284 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11285 }
11286 break;
11287 }
11288 case NODE_DREGX:
11289 compile_dregx(iseq, ret, node, popped);
11290 break;
11291 case NODE_ONCE:{
11292 int ic_index = body->ise_size++;
11293 const rb_iseq_t *block_iseq;
11294 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11295
11296 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11297 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11298
11299 if (popped) {
11300 ADD_INSN(ret, node, pop);
11301 }
11302 break;
11303 }
11304 case NODE_ARGSCAT:{
11305 if (popped) {
11306 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11307 ADD_INSN1(ret, node, splatarray, Qfalse);
11308 ADD_INSN(ret, node, pop);
11309 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11310 ADD_INSN1(ret, node, splatarray, Qfalse);
11311 ADD_INSN(ret, node, pop);
11312 }
11313 else {
11314 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11315 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11316 if (nd_type_p(body_node, NODE_LIST)) {
11317 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11318 }
11319 else {
11320 CHECK(COMPILE(ret, "argscat body", body_node));
11321 ADD_INSN(ret, node, concattoarray);
11322 }
11323 }
11324 break;
11325 }
11326 case NODE_ARGSPUSH:{
11327 if (popped) {
11328 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11329 ADD_INSN1(ret, node, splatarray, Qfalse);
11330 ADD_INSN(ret, node, pop);
11331 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11332 }
11333 else {
11334 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11335 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11336 if (keyword_node_p(body_node)) {
11337 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11338 ADD_INSN(ret, node, pushtoarraykwsplat);
11339 }
11340 else if (static_literal_node_p(body_node, iseq, false)) {
11341 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11342 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11343 }
11344 else {
11345 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11346 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11347 }
11348 }
11349 break;
11350 }
11351 case NODE_SPLAT:{
11352 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11353 ADD_INSN1(ret, node, splatarray, Qtrue);
11354
11355 if (popped) {
11356 ADD_INSN(ret, node, pop);
11357 }
11358 break;
11359 }
11360 case NODE_DEFN:{
11361 ID mid = RNODE_DEFN(node)->nd_mid;
11362 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11363 rb_id2str(mid),
11364 ISEQ_TYPE_METHOD, line);
11365
11366 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11367 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11368 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11369
11370 if (!popped) {
11371 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11372 }
11373
11374 break;
11375 }
11376 case NODE_DEFS:{
11377 ID mid = RNODE_DEFS(node)->nd_mid;
11378 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11379 rb_id2str(mid),
11380 ISEQ_TYPE_METHOD, line);
11381
11382 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11383 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11384 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11385 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11386
11387 if (!popped) {
11388 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11389 }
11390 break;
11391 }
11392 case NODE_ALIAS:{
11393 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11394 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11395 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11396 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11397 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11398
11399 if (popped) {
11400 ADD_INSN(ret, node, pop);
11401 }
11402 break;
11403 }
11404 case NODE_VALIAS:{
11405 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11406 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11407 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11408 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11409
11410 if (popped) {
11411 ADD_INSN(ret, node, pop);
11412 }
11413 break;
11414 }
11415 case NODE_UNDEF:{
11416 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11417
11418 for (long i = 0; i < ary->len; i++) {
11419 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11420 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11421 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11422 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11423
11424 if (i < ary->len - 1) {
11425 ADD_INSN(ret, node, pop);
11426 }
11427 }
11428
11429 if (popped) {
11430 ADD_INSN(ret, node, pop);
11431 }
11432 break;
11433 }
11434 case NODE_CLASS:{
11435 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11436 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11437 ISEQ_TYPE_CLASS, line);
11438 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11439 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11440 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11441
11442 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11443 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11444 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11445
11446 if (popped) {
11447 ADD_INSN(ret, node, pop);
11448 }
11449 break;
11450 }
11451 case NODE_MODULE:{
11452 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11453 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11454 ISEQ_TYPE_CLASS, line);
11455 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11456 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11457
11458 ADD_INSN (ret, node, putnil); /* dummy */
11459 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11460 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11461
11462 if (popped) {
11463 ADD_INSN(ret, node, pop);
11464 }
11465 break;
11466 }
11467 case NODE_SCLASS:{
11468 ID singletonclass;
11469 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11470 ISEQ_TYPE_CLASS, line);
11471
11472 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11473 ADD_INSN (ret, node, putnil);
11474 CONST_ID(singletonclass, "singletonclass");
11475 ADD_INSN3(ret, node, defineclass,
11476 ID2SYM(singletonclass), singleton_class,
11477 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11478 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11479
11480 if (popped) {
11481 ADD_INSN(ret, node, pop);
11482 }
11483 break;
11484 }
11485 case NODE_COLON2:
11486 CHECK(compile_colon2(iseq, ret, node, popped));
11487 break;
11488 case NODE_COLON3:
11489 CHECK(compile_colon3(iseq, ret, node, popped));
11490 break;
11491 case NODE_DOT2:
11492 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11493 break;
11494 case NODE_DOT3:
11495 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11496 break;
11497 case NODE_FLIP2:
11498 case NODE_FLIP3:{
11499 LABEL *lend = NEW_LABEL(line);
11500 LABEL *ltrue = NEW_LABEL(line);
11501 LABEL *lfalse = NEW_LABEL(line);
11502 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11503 ltrue, lfalse));
11504 ADD_LABEL(ret, ltrue);
11505 ADD_INSN1(ret, node, putobject, Qtrue);
11506 ADD_INSNL(ret, node, jump, lend);
11507 ADD_LABEL(ret, lfalse);
11508 ADD_INSN1(ret, node, putobject, Qfalse);
11509 ADD_LABEL(ret, lend);
11510 break;
11511 }
11512 case NODE_SELF:{
11513 if (!popped) {
11514 ADD_INSN(ret, node, putself);
11515 }
11516 break;
11517 }
11518 case NODE_NIL:{
11519 if (!popped) {
11520 ADD_INSN(ret, node, putnil);
11521 }
11522 break;
11523 }
11524 case NODE_TRUE:{
11525 if (!popped) {
11526 ADD_INSN1(ret, node, putobject, Qtrue);
11527 }
11528 break;
11529 }
11530 case NODE_FALSE:{
11531 if (!popped) {
11532 ADD_INSN1(ret, node, putobject, Qfalse);
11533 }
11534 break;
11535 }
11536 case NODE_ERRINFO:
11537 CHECK(compile_errinfo(iseq, ret, node, popped));
11538 break;
11539 case NODE_DEFINED:
11540 if (!popped) {
11541 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11542 }
11543 break;
11544 case NODE_POSTEXE:{
11545 /* compiled to:
11546 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11547 */
11548 int is_index = body->ise_size++;
11550 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11551 const rb_iseq_t *once_iseq =
11552 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11553
11554 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11555 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11556
11557 if (popped) {
11558 ADD_INSN(ret, node, pop);
11559 }
11560 break;
11561 }
11562 case NODE_KW_ARG:
11563 CHECK(compile_kw_arg(iseq, ret, node, popped));
11564 break;
11565 case NODE_DSYM:{
11566 compile_dstr(iseq, ret, node);
11567 if (!popped) {
11568 ADD_INSN(ret, node, intern);
11569 }
11570 else {
11571 ADD_INSN(ret, node, pop);
11572 }
11573 break;
11574 }
11575 case NODE_ATTRASGN:
11576 CHECK(compile_attrasgn(iseq, ret, node, popped));
11577 break;
11578 case NODE_LAMBDA:{
11579 /* compile same as lambda{...} */
11580 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11581 VALUE argc = INT2FIX(0);
11582
11583 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11584 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11585 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11586
11587 if (popped) {
11588 ADD_INSN(ret, node, pop);
11589 }
11590 break;
11591 }
11592 default:
11593 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11594 ng:
11595 debug_node_end();
11596 return COMPILE_NG;
11597 }
11598
11599 debug_node_end();
11600 return COMPILE_OK;
11601}
11602
11603/***************************/
11604/* instruction information */
11605/***************************/
11606
11607static int
11608insn_data_length(INSN *iobj)
11609{
11610 return insn_len(iobj->insn_id);
11611}
11612
11613static int
11614calc_sp_depth(int depth, INSN *insn)
11615{
11616 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11617}
11618
11619static VALUE
11620opobj_inspect(VALUE obj)
11621{
11622 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11623 switch (BUILTIN_TYPE(obj)) {
11624 case T_STRING:
11625 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11626 break;
11627 case T_ARRAY:
11628 obj = rb_ary_dup(obj);
11629 break;
11630 default:
11631 break;
11632 }
11633 }
11634 return rb_inspect(obj);
11635}
11636
11637
11638
11639static VALUE
11640insn_data_to_s_detail(INSN *iobj)
11641{
11642 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11643
11644 if (iobj->operands) {
11645 const char *types = insn_op_types(iobj->insn_id);
11646 int j;
11647
11648 for (j = 0; types[j]; j++) {
11649 char type = types[j];
11650
11651 switch (type) {
11652 case TS_OFFSET: /* label(destination position) */
11653 {
11654 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11655 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11656 break;
11657 }
11658 break;
11659 case TS_ISEQ: /* iseq */
11660 {
11661 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11662 VALUE val = Qnil;
11663 if (0 && iseq) { /* TODO: invalidate now */
11664 val = (VALUE)iseq;
11665 }
11666 rb_str_concat(str, opobj_inspect(val));
11667 }
11668 break;
11669 case TS_LINDEX:
11670 case TS_NUM: /* ulong */
11671 case TS_VALUE: /* VALUE */
11672 {
11673 VALUE v = OPERAND_AT(iobj, j);
11674 if (!CLASS_OF(v))
11675 rb_str_cat2(str, "<hidden>");
11676 else {
11677 rb_str_concat(str, opobj_inspect(v));
11678 }
11679 break;
11680 }
11681 case TS_ID: /* ID */
11682 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11683 break;
11684 case TS_IC: /* inline cache */
11685 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11686 break;
11687 case TS_IVC: /* inline ivar cache */
11688 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11689 break;
11690 case TS_ICVARC: /* inline cvar cache */
11691 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11692 break;
11693 case TS_ISE: /* inline storage entry */
11694 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11695 break;
11696 case TS_CALLDATA: /* we store these as call infos at compile time */
11697 {
11698 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11699 rb_str_cat2(str, "<calldata:");
11700 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11701 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11702 break;
11703 }
11704 case TS_CDHASH: /* case/when condition cache */
11705 rb_str_cat2(str, "<ch>");
11706 break;
11707 case TS_FUNCPTR:
11708 {
11709 void *func = (void *)OPERAND_AT(iobj, j);
11710#ifdef HAVE_DLADDR
11711 Dl_info info;
11712 if (dladdr(func, &info) && info.dli_sname) {
11713 rb_str_cat2(str, info.dli_sname);
11714 break;
11715 }
11716#endif
11717 rb_str_catf(str, "<%p>", func);
11718 }
11719 break;
11720 case TS_BUILTIN:
11721 rb_str_cat2(str, "<TS_BUILTIN>");
11722 break;
11723 default:{
11724 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11725 }
11726 }
11727 if (types[j + 1]) {
11728 rb_str_cat2(str, ", ");
11729 }
11730 }
11731 }
11732 return str;
11733}
11734
11735static void
11736dump_disasm_list(const LINK_ELEMENT *link)
11737{
11738 dump_disasm_list_with_cursor(link, NULL, NULL);
11739}
11740
11741static void
11742dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11743{
11744 int pos = 0;
11745 INSN *iobj;
11746 LABEL *lobj;
11747 VALUE str;
11748
11749 printf("-- raw disasm--------\n");
11750
11751 while (link) {
11752 if (curr) printf(curr == link ? "*" : " ");
11753 switch (link->type) {
11754 case ISEQ_ELEMENT_INSN:
11755 {
11756 iobj = (INSN *)link;
11757 str = insn_data_to_s_detail(iobj);
11758 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11759 pos += insn_data_length(iobj);
11760 break;
11761 }
11762 case ISEQ_ELEMENT_LABEL:
11763 {
11764 lobj = (LABEL *)link;
11765 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11766 dest == lobj ? " <---" : "");
11767 break;
11768 }
11769 case ISEQ_ELEMENT_TRACE:
11770 {
11771 TRACE *trace = (TRACE *)link;
11772 printf(" trace: %0x\n", trace->event);
11773 break;
11774 }
11775 case ISEQ_ELEMENT_ADJUST:
11776 {
11777 ADJUST *adjust = (ADJUST *)link;
11778 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11779 break;
11780 }
11781 default:
11782 /* ignore */
11783 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11784 }
11785 link = link->next;
11786 }
11787 printf("---------------------\n");
11788 fflush(stdout);
11789}
11790
11791int
11792rb_insn_len(VALUE insn)
11793{
11794 return insn_len(insn);
11795}
11796
11797const char *
11798rb_insns_name(int i)
11799{
11800 return insn_name(i);
11801}
11802
11803VALUE
11804rb_insns_name_array(void)
11805{
11806 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11807 int i;
11808 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11809 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11810 }
11811 return rb_ary_freeze(ary);
11812}
11813
11814static LABEL *
11815register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11816{
11817 LABEL *label = 0;
11818 st_data_t tmp;
11819 obj = rb_to_symbol_type(obj);
11820
11821 if (st_lookup(labels_table, obj, &tmp) == 0) {
11822 label = NEW_LABEL(0);
11823 st_insert(labels_table, obj, (st_data_t)label);
11824 }
11825 else {
11826 label = (LABEL *)tmp;
11827 }
11828 LABEL_REF(label);
11829 return label;
11830}
11831
11832static VALUE
11833get_exception_sym2type(VALUE sym)
11834{
11835 static VALUE symRescue, symEnsure, symRetry;
11836 static VALUE symBreak, symRedo, symNext;
11837
11838 if (symRescue == 0) {
11839 symRescue = ID2SYM(rb_intern_const("rescue"));
11840 symEnsure = ID2SYM(rb_intern_const("ensure"));
11841 symRetry = ID2SYM(rb_intern_const("retry"));
11842 symBreak = ID2SYM(rb_intern_const("break"));
11843 symRedo = ID2SYM(rb_intern_const("redo"));
11844 symNext = ID2SYM(rb_intern_const("next"));
11845 }
11846
11847 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11848 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11849 if (sym == symRetry) return CATCH_TYPE_RETRY;
11850 if (sym == symBreak) return CATCH_TYPE_BREAK;
11851 if (sym == symRedo) return CATCH_TYPE_REDO;
11852 if (sym == symNext) return CATCH_TYPE_NEXT;
11853 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11854 return 0;
11855}
11856
11857static int
11858iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11859 VALUE exception)
11860{
11861 int i;
11862
11863 for (i=0; i<RARRAY_LEN(exception); i++) {
11864 const rb_iseq_t *eiseq;
11865 VALUE v, type;
11866 LABEL *lstart, *lend, *lcont;
11867 unsigned int sp;
11868
11869 v = rb_to_array_type(RARRAY_AREF(exception, i));
11870 if (RARRAY_LEN(v) != 6) {
11871 rb_raise(rb_eSyntaxError, "wrong exception entry");
11872 }
11873 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11874 if (NIL_P(RARRAY_AREF(v, 1))) {
11875 eiseq = NULL;
11876 }
11877 else {
11878 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11879 }
11880
11881 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11882 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11883 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11884 sp = NUM2UINT(RARRAY_AREF(v, 5));
11885
11886 /* TODO: Dirty Hack! Fix me */
11887 if (type == CATCH_TYPE_RESCUE ||
11888 type == CATCH_TYPE_BREAK ||
11889 type == CATCH_TYPE_NEXT) {
11890 ++sp;
11891 }
11892
11893 lcont->sp = sp;
11894
11895 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11896
11897 RB_GC_GUARD(v);
11898 }
11899 return COMPILE_OK;
11900}
11901
11902static struct st_table *
11903insn_make_insn_table(void)
11904{
11905 struct st_table *table;
11906 int i;
11907 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11908
11909 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11910 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11911 }
11912
11913 return table;
11914}
11915
11916static const rb_iseq_t *
11917iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11918{
11919 VALUE iseqw;
11920 const rb_iseq_t *loaded_iseq;
11921
11922 if (RB_TYPE_P(op, T_ARRAY)) {
11923 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11924 }
11925 else if (CLASS_OF(op) == rb_cISeq) {
11926 iseqw = op;
11927 }
11928 else {
11929 rb_raise(rb_eSyntaxError, "ISEQ is required");
11930 }
11931
11932 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11933 return loaded_iseq;
11934}
11935
11936static VALUE
11937iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11938{
11939 ID mid = 0;
11940 int orig_argc = 0;
11941 unsigned int flag = 0;
11942 struct rb_callinfo_kwarg *kw_arg = 0;
11943
11944 if (!NIL_P(op)) {
11945 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11946 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11947 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11948 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11949
11950 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11951 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11952 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11953
11954 if (!NIL_P(vkw_arg)) {
11955 int i;
11956 int len = RARRAY_LENINT(vkw_arg);
11957 size_t n = rb_callinfo_kwarg_bytes(len);
11958
11959 kw_arg = xmalloc(n);
11960 kw_arg->references = 0;
11961 kw_arg->keyword_len = len;
11962 for (i = 0; i < len; i++) {
11963 VALUE kw = RARRAY_AREF(vkw_arg, i);
11964 SYM2ID(kw); /* make immortal */
11965 kw_arg->keywords[i] = kw;
11966 }
11967 }
11968 }
11969
11970 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11971 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11972 return (VALUE)ci;
11973}
11974
11975static rb_event_flag_t
11976event_name_to_flag(VALUE sym)
11977{
11978#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11979 CHECK_EVENT(RUBY_EVENT_LINE);
11980 CHECK_EVENT(RUBY_EVENT_CLASS);
11981 CHECK_EVENT(RUBY_EVENT_END);
11982 CHECK_EVENT(RUBY_EVENT_CALL);
11983 CHECK_EVENT(RUBY_EVENT_RETURN);
11984 CHECK_EVENT(RUBY_EVENT_B_CALL);
11985 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11986 CHECK_EVENT(RUBY_EVENT_RESCUE);
11987#undef CHECK_EVENT
11988 return RUBY_EVENT_NONE;
11989}
11990
11991static int
11992iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11993 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11994{
11995 /* TODO: body should be frozen */
11996 long i, len = RARRAY_LEN(body);
11997 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11998 int j;
11999 int line_no = 0, node_id = -1, insn_idx = 0;
12000 int ret = COMPILE_OK;
12001
12002 /*
12003 * index -> LABEL *label
12004 */
12005 static struct st_table *insn_table;
12006
12007 if (insn_table == 0) {
12008 insn_table = insn_make_insn_table();
12009 }
12010
12011 for (i=0; i<len; i++) {
12012 VALUE obj = RARRAY_AREF(body, i);
12013
12014 if (SYMBOL_P(obj)) {
12015 rb_event_flag_t event;
12016 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12017 ADD_TRACE(anchor, event);
12018 }
12019 else {
12020 LABEL *label = register_label(iseq, labels_table, obj);
12021 ADD_LABEL(anchor, label);
12022 }
12023 }
12024 else if (FIXNUM_P(obj)) {
12025 line_no = NUM2INT(obj);
12026 }
12027 else if (RB_TYPE_P(obj, T_ARRAY)) {
12028 VALUE *argv = 0;
12029 int argc = RARRAY_LENINT(obj) - 1;
12030 st_data_t insn_id;
12031 VALUE insn;
12032
12033 if (node_ids) {
12034 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12035 }
12036
12037 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12038 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12039 /* TODO: exception */
12040 COMPILE_ERROR(iseq, line_no,
12041 "unknown instruction: %+"PRIsVALUE, insn);
12042 ret = COMPILE_NG;
12043 break;
12044 }
12045
12046 if (argc != insn_len((VALUE)insn_id)-1) {
12047 COMPILE_ERROR(iseq, line_no,
12048 "operand size mismatch");
12049 ret = COMPILE_NG;
12050 break;
12051 }
12052
12053 if (argc > 0) {
12054 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12055
12056 // add element before operand setup to make GC root
12057 ADD_ELEM(anchor,
12058 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12059 (enum ruby_vminsn_type)insn_id, argc, argv));
12060
12061 for (j=0; j<argc; j++) {
12062 VALUE op = rb_ary_entry(obj, j+1);
12063 switch (insn_op_type((VALUE)insn_id, j)) {
12064 case TS_OFFSET: {
12065 LABEL *label = register_label(iseq, labels_table, op);
12066 argv[j] = (VALUE)label;
12067 break;
12068 }
12069 case TS_LINDEX:
12070 case TS_NUM:
12071 (void)NUM2INT(op);
12072 argv[j] = op;
12073 break;
12074 case TS_VALUE:
12075 argv[j] = op;
12076 RB_OBJ_WRITTEN(iseq, Qundef, op);
12077 break;
12078 case TS_ISEQ:
12079 {
12080 if (op != Qnil) {
12081 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12082 argv[j] = v;
12083 RB_OBJ_WRITTEN(iseq, Qundef, v);
12084 }
12085 else {
12086 argv[j] = 0;
12087 }
12088 }
12089 break;
12090 case TS_ISE:
12091 argv[j] = op;
12092 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12093 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12094 }
12095 break;
12096 case TS_IC:
12097 {
12098 VALUE segments = rb_ary_new();
12099 op = rb_to_array_type(op);
12100
12101 for (int i = 0; i < RARRAY_LEN(op); i++) {
12102 VALUE sym = RARRAY_AREF(op, i);
12103 sym = rb_to_symbol_type(sym);
12104 rb_ary_push(segments, sym);
12105 }
12106
12107 RB_GC_GUARD(op);
12108 argv[j] = segments;
12109 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12110 ISEQ_BODY(iseq)->ic_size++;
12111 }
12112 break;
12113 case TS_IVC: /* inline ivar cache */
12114 argv[j] = op;
12115 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12116 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12117 }
12118 break;
12119 case TS_ICVARC: /* inline cvar cache */
12120 argv[j] = op;
12121 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12122 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12123 }
12124 break;
12125 case TS_CALLDATA:
12126 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12127 break;
12128 case TS_ID:
12129 argv[j] = rb_to_symbol_type(op);
12130 break;
12131 case TS_CDHASH:
12132 {
12133 int i;
12134 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12135
12136 RHASH_TBL_RAW(map)->type = &cdhash_type;
12137 op = rb_to_array_type(op);
12138 for (i=0; i<RARRAY_LEN(op); i+=2) {
12139 VALUE key = RARRAY_AREF(op, i);
12140 VALUE sym = RARRAY_AREF(op, i+1);
12141 LABEL *label =
12142 register_label(iseq, labels_table, sym);
12143 rb_hash_aset(map, key, (VALUE)label | 1);
12144 }
12145 RB_GC_GUARD(op);
12146 RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
12147 argv[j] = map;
12148 RB_OBJ_WRITTEN(iseq, Qundef, map);
12149 }
12150 break;
12151 case TS_FUNCPTR:
12152 {
12153#if SIZEOF_VALUE <= SIZEOF_LONG
12154 long funcptr = NUM2LONG(op);
12155#else
12156 LONG_LONG funcptr = NUM2LL(op);
12157#endif
12158 argv[j] = (VALUE)funcptr;
12159 }
12160 break;
12161 default:
12162 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12163 }
12164 }
12165 }
12166 else {
12167 ADD_ELEM(anchor,
12168 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12169 (enum ruby_vminsn_type)insn_id, argc, NULL));
12170 }
12171 }
12172 else {
12173 rb_raise(rb_eTypeError, "unexpected object for instruction");
12174 }
12175 }
12176 RTYPEDDATA_DATA(labels_wrapper) = 0;
12177 RB_GC_GUARD(labels_wrapper);
12178 validate_labels(iseq, labels_table);
12179 if (!ret) return ret;
12180 return iseq_setup(iseq, anchor);
12181}
12182
12183#define CHECK_ARRAY(v) rb_to_array_type(v)
12184#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12185
12186static int
12187int_param(int *dst, VALUE param, VALUE sym)
12188{
12189 VALUE val = rb_hash_aref(param, sym);
12190 if (FIXNUM_P(val)) {
12191 *dst = FIX2INT(val);
12192 return TRUE;
12193 }
12194 else if (!NIL_P(val)) {
12195 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12196 sym, val);
12197 }
12198 return FALSE;
12199}
12200
12201static const struct rb_iseq_param_keyword *
12202iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12203{
12204 int i, j;
12205 int len = RARRAY_LENINT(keywords);
12206 int default_len;
12207 VALUE key, sym, default_val;
12208 VALUE *dvs;
12209 ID *ids;
12210 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12211
12212 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12213
12214 keyword->num = len;
12215#define SYM(s) ID2SYM(rb_intern_const(#s))
12216 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12217 i = keyword->bits_start - keyword->num;
12218 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12219#undef SYM
12220
12221 /* required args */
12222 for (i = 0; i < len; i++) {
12223 VALUE val = RARRAY_AREF(keywords, i);
12224
12225 if (!SYMBOL_P(val)) {
12226 goto default_values;
12227 }
12228 ids[i] = SYM2ID(val);
12229 keyword->required_num++;
12230 }
12231
12232 default_values: /* note: we intentionally preserve `i' from previous loop */
12233 default_len = len - i;
12234 if (default_len == 0) {
12235 keyword->table = ids;
12236 return keyword;
12237 }
12238 else if (default_len < 0) {
12240 }
12241
12242 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12243
12244 for (j = 0; i < len; i++, j++) {
12245 key = RARRAY_AREF(keywords, i);
12246 CHECK_ARRAY(key);
12247
12248 switch (RARRAY_LEN(key)) {
12249 case 1:
12250 sym = RARRAY_AREF(key, 0);
12251 default_val = Qundef;
12252 break;
12253 case 2:
12254 sym = RARRAY_AREF(key, 0);
12255 default_val = RARRAY_AREF(key, 1);
12256 break;
12257 default:
12258 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12259 }
12260 ids[i] = SYM2ID(sym);
12261 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12262 }
12263
12264 keyword->table = ids;
12265 keyword->default_values = dvs;
12266
12267 return keyword;
12268}
12269
12270static void
12271iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12272{
12273 rb_gc_mark_and_move(obj);
12274}
12275
12276void
12277rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12278{
12279 INSN *iobj = 0;
12280 size_t size = sizeof(INSN);
12281 unsigned int pos = 0;
12282
12283 while (storage) {
12284#ifdef STRICT_ALIGNMENT
12285 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12286#else
12287 const size_t padding = 0; /* expected to be optimized by compiler */
12288#endif /* STRICT_ALIGNMENT */
12289 size_t offset = pos + size + padding;
12290 if (offset > storage->size || offset > storage->pos) {
12291 pos = 0;
12292 storage = storage->next;
12293 }
12294 else {
12295#ifdef STRICT_ALIGNMENT
12296 pos += (int)padding;
12297#endif /* STRICT_ALIGNMENT */
12298
12299 iobj = (INSN *)&storage->buff[pos];
12300
12301 if (iobj->operands) {
12302 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12303 }
12304 pos += (int)size;
12305 }
12306 }
12307}
12308
12309static const rb_data_type_t labels_wrapper_type = {
12310 .wrap_struct_name = "compiler/labels_wrapper",
12311 .function = {
12312 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12313 .dfree = (RUBY_DATA_FUNC)st_free_table,
12314 },
12315 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12316};
12317
12318void
12319rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12320 VALUE exception, VALUE body)
12321{
12322#define SYM(s) ID2SYM(rb_intern_const(#s))
12323 int i, len;
12324 unsigned int arg_size, local_size, stack_max;
12325 ID *tbl;
12326 struct st_table *labels_table = st_init_numtable();
12327 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12328 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12329 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12330 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12331 DECL_ANCHOR(anchor);
12332 INIT_ANCHOR(anchor);
12333
12334 len = RARRAY_LENINT(locals);
12335 ISEQ_BODY(iseq)->local_table_size = len;
12336 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12337
12338 for (i = 0; i < len; i++) {
12339 VALUE lv = RARRAY_AREF(locals, i);
12340
12341 if (sym_arg_rest == lv) {
12342 tbl[i] = 0;
12343 }
12344 else {
12345 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12346 }
12347 }
12348
12349#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12350 if (INT_PARAM(lead_num)) {
12351 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12352 }
12353 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12354 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12355 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12356 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12357#undef INT_PARAM
12358 {
12359#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12360 int x;
12361 INT_PARAM(arg_size);
12362 INT_PARAM(local_size);
12363 INT_PARAM(stack_max);
12364#undef INT_PARAM
12365 }
12366
12367 VALUE node_ids = Qfalse;
12368#ifdef USE_ISEQ_NODE_ID
12369 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12370 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12371 rb_raise(rb_eTypeError, "node_ids is not an array");
12372 }
12373#endif
12374
12375 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12376 len = RARRAY_LENINT(arg_opt_labels);
12377 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12378
12379 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12380 VALUE *opt_table = ALLOC_N(VALUE, len);
12381
12382 for (i = 0; i < len; i++) {
12383 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12384 LABEL *label = register_label(iseq, labels_table, ent);
12385 opt_table[i] = (VALUE)label;
12386 }
12387
12388 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12389 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12390 }
12391 }
12392 else if (!NIL_P(arg_opt_labels)) {
12393 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12394 arg_opt_labels);
12395 }
12396
12397 if (RB_TYPE_P(keywords, T_ARRAY)) {
12398 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12399 }
12400 else if (!NIL_P(keywords)) {
12401 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12402 keywords);
12403 }
12404
12405 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12406 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12407 }
12408
12409 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12410 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12411 }
12412
12413 if (int_param(&i, params, SYM(kwrest))) {
12414 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12415 if (keyword == NULL) {
12416 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12417 }
12418 keyword->rest_start = i;
12419 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12420 }
12421#undef SYM
12422 iseq_calc_param_size(iseq);
12423
12424 /* exception */
12425 iseq_build_from_ary_exception(iseq, labels_table, exception);
12426
12427 /* body */
12428 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12429
12430 ISEQ_BODY(iseq)->param.size = arg_size;
12431 ISEQ_BODY(iseq)->local_table_size = local_size;
12432 ISEQ_BODY(iseq)->stack_max = stack_max;
12433}
12434
12435/* for parser */
12436
12437int
12438rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12439{
12440 if (iseq) {
12441 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12442 while (body->type == ISEQ_TYPE_BLOCK ||
12443 body->type == ISEQ_TYPE_RESCUE ||
12444 body->type == ISEQ_TYPE_ENSURE ||
12445 body->type == ISEQ_TYPE_EVAL ||
12446 body->type == ISEQ_TYPE_MAIN
12447 ) {
12448 unsigned int i;
12449
12450 for (i = 0; i < body->local_table_size; i++) {
12451 if (body->local_table[i] == id) {
12452 return 1;
12453 }
12454 }
12455 iseq = body->parent_iseq;
12456 body = ISEQ_BODY(iseq);
12457 }
12458 }
12459 return 0;
12460}
12461
12462int
12463rb_local_defined(ID id, const rb_iseq_t *iseq)
12464{
12465 if (iseq) {
12466 unsigned int i;
12467 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12468
12469 for (i=0; i<body->local_table_size; i++) {
12470 if (body->local_table[i] == id) {
12471 return 1;
12472 }
12473 }
12474 }
12475 return 0;
12476}
12477
12478/* ISeq binary format */
12479
12480#ifndef IBF_ISEQ_DEBUG
12481#define IBF_ISEQ_DEBUG 0
12482#endif
12483
12484#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12485#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12486#endif
12487
12488typedef uint32_t ibf_offset_t;
12489#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12490
12491#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12492#ifdef RUBY_DEVEL
12493#define IBF_DEVEL_VERSION 5
12494#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12495#else
12496#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12497#endif
12498
12499static const char IBF_ENDIAN_MARK =
12500#ifdef WORDS_BIGENDIAN
12501 'b'
12502#else
12503 'l'
12504#endif
12505 ;
12506
12508 char magic[4]; /* YARB */
12509 uint32_t major_version;
12510 uint32_t minor_version;
12511 uint32_t size;
12512 uint32_t extra_size;
12513
12514 uint32_t iseq_list_size;
12515 uint32_t global_object_list_size;
12516 ibf_offset_t iseq_list_offset;
12517 ibf_offset_t global_object_list_offset;
12518 uint8_t endian;
12519 uint8_t wordsize; /* assume no 2048-bit CPU */
12520};
12521
12523 VALUE str;
12524 st_table *obj_table; /* obj -> obj number */
12525};
12526
12527struct ibf_dump {
12528 st_table *iseq_table; /* iseq -> iseq number */
12529 struct ibf_dump_buffer global_buffer;
12530 struct ibf_dump_buffer *current_buffer;
12531};
12532
12534 const char *buff;
12535 ibf_offset_t size;
12536
12537 VALUE obj_list; /* [obj0, ...] */
12538 unsigned int obj_list_size;
12539 ibf_offset_t obj_list_offset;
12540};
12541
12542struct ibf_load {
12543 const struct ibf_header *header;
12544 VALUE iseq_list; /* [iseq0, ...] */
12545 struct ibf_load_buffer global_buffer;
12546 VALUE loader_obj;
12547 rb_iseq_t *iseq;
12548 VALUE str;
12549 struct ibf_load_buffer *current_buffer;
12550};
12551
12553 long size;
12554 VALUE buffer[1];
12555};
12556
12557static void
12558pinned_list_mark(void *ptr)
12559{
12560 long i;
12561 struct pinned_list *list = (struct pinned_list *)ptr;
12562 for (i = 0; i < list->size; i++) {
12563 if (list->buffer[i]) {
12564 rb_gc_mark(list->buffer[i]);
12565 }
12566 }
12567}
12568
12569static const rb_data_type_t pinned_list_type = {
12570 "pinned_list",
12571 {
12572 pinned_list_mark,
12574 NULL, // No external memory to report,
12575 },
12576 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12577};
12578
12579static VALUE
12580pinned_list_fetch(VALUE list, long offset)
12581{
12582 struct pinned_list * ptr;
12583
12584 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12585
12586 if (offset >= ptr->size) {
12587 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12588 }
12589
12590 return ptr->buffer[offset];
12591}
12592
12593static void
12594pinned_list_store(VALUE list, long offset, VALUE object)
12595{
12596 struct pinned_list * ptr;
12597
12598 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12599
12600 if (offset >= ptr->size) {
12601 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12602 }
12603
12604 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12605}
12606
12607static VALUE
12608pinned_list_new(long size)
12609{
12610 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12611 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12612 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12613 ptr->size = size;
12614 return obj_list;
12615}
12616
12617static ibf_offset_t
12618ibf_dump_pos(struct ibf_dump *dump)
12619{
12620 long pos = RSTRING_LEN(dump->current_buffer->str);
12621#if SIZEOF_LONG > SIZEOF_INT
12622 if (pos >= UINT_MAX) {
12623 rb_raise(rb_eRuntimeError, "dump size exceeds");
12624 }
12625#endif
12626 return (unsigned int)pos;
12627}
12628
12629static void
12630ibf_dump_align(struct ibf_dump *dump, size_t align)
12631{
12632 ibf_offset_t pos = ibf_dump_pos(dump);
12633 if (pos % align) {
12634 static const char padding[sizeof(VALUE)];
12635 size_t size = align - ((size_t)pos % align);
12636#if SIZEOF_LONG > SIZEOF_INT
12637 if (pos + size >= UINT_MAX) {
12638 rb_raise(rb_eRuntimeError, "dump size exceeds");
12639 }
12640#endif
12641 for (; size > sizeof(padding); size -= sizeof(padding)) {
12642 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12643 }
12644 rb_str_cat(dump->current_buffer->str, padding, size);
12645 }
12646}
12647
12648static ibf_offset_t
12649ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12650{
12651 ibf_offset_t pos = ibf_dump_pos(dump);
12652#if SIZEOF_LONG > SIZEOF_INT
12653 /* ensure the resulting dump does not exceed UINT_MAX */
12654 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12655 rb_raise(rb_eRuntimeError, "dump size exceeds");
12656 }
12657#endif
12658 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12659 return pos;
12660}
12661
12662static ibf_offset_t
12663ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12664{
12665 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12666}
12667
12668static void
12669ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12670{
12671 VALUE str = dump->current_buffer->str;
12672 char *ptr = RSTRING_PTR(str);
12673 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12674 rb_bug("ibf_dump_overwrite: overflow");
12675 memcpy(ptr + offset, buff, size);
12676}
12677
12678static const void *
12679ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12680{
12681 ibf_offset_t beg = *offset;
12682 *offset += size;
12683 return load->current_buffer->buff + beg;
12684}
12685
12686static void *
12687ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12688{
12689 void *buff = ruby_xmalloc2(x, y);
12690 size_t size = x * y;
12691 memcpy(buff, load->current_buffer->buff + offset, size);
12692 return buff;
12693}
12694
12695#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12696
12697#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12698#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12699#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12700#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12701#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12702
12703static int
12704ibf_table_lookup(struct st_table *table, st_data_t key)
12705{
12706 st_data_t val;
12707
12708 if (st_lookup(table, key, &val)) {
12709 return (int)val;
12710 }
12711 else {
12712 return -1;
12713 }
12714}
12715
12716static int
12717ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12718{
12719 int index = ibf_table_lookup(table, key);
12720
12721 if (index < 0) { /* not found */
12722 index = (int)table->num_entries;
12723 st_insert(table, key, (st_data_t)index);
12724 }
12725
12726 return index;
12727}
12728
12729/* dump/load generic */
12730
12731static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12732
12733static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12734static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12735
12736static st_table *
12737ibf_dump_object_table_new(void)
12738{
12739 st_table *obj_table = st_init_numtable(); /* need free */
12740 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12741
12742 return obj_table;
12743}
12744
12745static VALUE
12746ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12747{
12748 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12749}
12750
12751static VALUE
12752ibf_dump_id(struct ibf_dump *dump, ID id)
12753{
12754 if (id == 0 || rb_id2name(id) == NULL) {
12755 return 0;
12756 }
12757 return ibf_dump_object(dump, rb_id2sym(id));
12758}
12759
12760static ID
12761ibf_load_id(const struct ibf_load *load, const ID id_index)
12762{
12763 if (id_index == 0) {
12764 return 0;
12765 }
12766 VALUE sym = ibf_load_object(load, id_index);
12767 if (rb_integer_type_p(sym)) {
12768 /* Load hidden local variables as indexes */
12769 return NUM2ULONG(sym);
12770 }
12771 return rb_sym2id(sym);
12772}
12773
12774/* dump/load: code */
12775
12776static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12777
12778static int
12779ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12780{
12781 if (iseq == NULL) {
12782 return -1;
12783 }
12784 else {
12785 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12786 }
12787}
12788
12789static unsigned char
12790ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12791{
12792 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12793 return (unsigned char)load->current_buffer->buff[(*offset)++];
12794}
12795
12796/*
12797 * Small uint serialization
12798 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12799 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12800 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12801 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12802 * ...
12803 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12804 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12805 */
12806static void
12807ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12808{
12809 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12810 ibf_dump_write(dump, &x, sizeof(VALUE));
12811 return;
12812 }
12813
12814 enum { max_byte_length = sizeof(VALUE) + 1 };
12815
12816 unsigned char bytes[max_byte_length];
12817 ibf_offset_t n;
12818
12819 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12820 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12821 }
12822
12823 x <<= 1;
12824 x |= 1;
12825 x <<= n;
12826 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12827 n++;
12828
12829 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12830}
12831
12832static VALUE
12833ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12834{
12835 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12836 union { char s[sizeof(VALUE)]; VALUE v; } x;
12837
12838 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12839 *offset += sizeof(VALUE);
12840
12841 return x.v;
12842 }
12843
12844 enum { max_byte_length = sizeof(VALUE) + 1 };
12845
12846 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12847 const unsigned char c = buffer[*offset];
12848
12849 ibf_offset_t n =
12850 c & 1 ? 1 :
12851 c == 0 ? 9 : ntz_int32(c) + 1;
12852 VALUE x = (VALUE)c >> n;
12853
12854 if (*offset + n > load->current_buffer->size) {
12855 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12856 }
12857
12858 ibf_offset_t i;
12859 for (i = 1; i < n; i++) {
12860 x <<= 8;
12861 x |= (VALUE)buffer[*offset + i];
12862 }
12863
12864 *offset += n;
12865 return x;
12866}
12867
12868static void
12869ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12870{
12871 // short: index
12872 // short: name.length
12873 // bytes: name
12874 // // omit argc (only verify with name)
12875 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12876
12877 size_t len = strlen(bf->name);
12878 ibf_dump_write_small_value(dump, (VALUE)len);
12879 ibf_dump_write(dump, bf->name, len);
12880}
12881
12882static const struct rb_builtin_function *
12883ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12884{
12885 int i = (int)ibf_load_small_value(load, offset);
12886 int len = (int)ibf_load_small_value(load, offset);
12887 const char *name = (char *)ibf_load_ptr(load, offset, len);
12888
12889 if (0) {
12890 fprintf(stderr, "%.*s!!\n", len, name);
12891 }
12892
12893 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12894 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12895 if (strncmp(table[i].name, name, len) != 0) {
12896 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12897 }
12898 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12899
12900 return &table[i];
12901}
12902
12903static ibf_offset_t
12904ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12905{
12906 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12907 const int iseq_size = body->iseq_size;
12908 int code_index;
12909 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12910
12911 ibf_offset_t offset = ibf_dump_pos(dump);
12912
12913 for (code_index=0; code_index<iseq_size;) {
12914 const VALUE insn = orig_code[code_index++];
12915 const char *types = insn_op_types(insn);
12916 int op_index;
12917
12918 /* opcode */
12919 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12920 ibf_dump_write_small_value(dump, insn);
12921
12922 /* operands */
12923 for (op_index=0; types[op_index]; op_index++, code_index++) {
12924 VALUE op = orig_code[code_index];
12925 VALUE wv;
12926
12927 switch (types[op_index]) {
12928 case TS_CDHASH:
12929 case TS_VALUE:
12930 wv = ibf_dump_object(dump, op);
12931 break;
12932 case TS_ISEQ:
12933 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12934 break;
12935 case TS_IC:
12936 {
12937 IC ic = (IC)op;
12938 VALUE arr = idlist_to_array(ic->segments);
12939 wv = ibf_dump_object(dump, arr);
12940 }
12941 break;
12942 case TS_ISE:
12943 case TS_IVC:
12944 case TS_ICVARC:
12945 {
12947 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12948 }
12949 break;
12950 case TS_CALLDATA:
12951 {
12952 goto skip_wv;
12953 }
12954 case TS_ID:
12955 wv = ibf_dump_id(dump, (ID)op);
12956 break;
12957 case TS_FUNCPTR:
12958 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12959 goto skip_wv;
12960 case TS_BUILTIN:
12961 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12962 goto skip_wv;
12963 default:
12964 wv = op;
12965 break;
12966 }
12967 ibf_dump_write_small_value(dump, wv);
12968 skip_wv:;
12969 }
12970 RUBY_ASSERT(insn_len(insn) == op_index+1);
12971 }
12972
12973 return offset;
12974}
12975
12976static VALUE *
12977ibf_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)
12978{
12979 VALUE iseqv = (VALUE)iseq;
12980 unsigned int code_index;
12981 ibf_offset_t reading_pos = bytecode_offset;
12982 VALUE *code = ALLOC_N(VALUE, iseq_size);
12983
12984 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12985 struct rb_call_data *cd_entries = load_body->call_data;
12986 int ic_index = 0;
12987
12988 load_body->iseq_encoded = code;
12989 load_body->iseq_size = 0;
12990
12991 iseq_bits_t * mark_offset_bits;
12992
12993 iseq_bits_t tmp[1] = {0};
12994
12995 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12996 mark_offset_bits = tmp;
12997 }
12998 else {
12999 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13000 }
13001 bool needs_bitmap = false;
13002
13003 for (code_index=0; code_index<iseq_size;) {
13004 /* opcode */
13005 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13006 const char *types = insn_op_types(insn);
13007 int op_index;
13008
13009 code_index++;
13010
13011 /* operands */
13012 for (op_index=0; types[op_index]; op_index++, code_index++) {
13013 const char operand_type = types[op_index];
13014 switch (operand_type) {
13015 case TS_VALUE:
13016 {
13017 VALUE op = ibf_load_small_value(load, &reading_pos);
13018 VALUE v = ibf_load_object(load, op);
13019 code[code_index] = v;
13020 if (!SPECIAL_CONST_P(v)) {
13021 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13022 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13023 needs_bitmap = true;
13024 }
13025 break;
13026 }
13027 case TS_CDHASH:
13028 {
13029 VALUE op = ibf_load_small_value(load, &reading_pos);
13030 VALUE v = ibf_load_object(load, op);
13031 v = rb_hash_dup(v); // hash dumped as frozen
13032 RHASH_TBL_RAW(v)->type = &cdhash_type;
13033 rb_hash_rehash(v); // hash function changed
13034 RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13035
13036 // Overwrite the existing hash in the object list. This
13037 // is to keep the object alive during load time.
13038 // [Bug #17984] [ruby-core:104259]
13039 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13040
13041 code[code_index] = v;
13042 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13043 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13044 needs_bitmap = true;
13045 break;
13046 }
13047 case TS_ISEQ:
13048 {
13049 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13050 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13051 code[code_index] = v;
13052 if (!SPECIAL_CONST_P(v)) {
13053 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13054 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13055 needs_bitmap = true;
13056 }
13057 break;
13058 }
13059 case TS_IC:
13060 {
13061 VALUE op = ibf_load_small_value(load, &reading_pos);
13062 VALUE arr = ibf_load_object(load, op);
13063
13064 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13065 ic->segments = array_to_idlist(arr);
13066
13067 code[code_index] = (VALUE)ic;
13068 }
13069 break;
13070 case TS_ISE:
13071 case TS_ICVARC:
13072 case TS_IVC:
13073 {
13074 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13075
13076 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13077 code[code_index] = (VALUE)ic;
13078
13079 if (operand_type == TS_IVC) {
13080 IVC cache = (IVC)ic;
13081
13082 if (insn == BIN(setinstancevariable)) {
13083 ID iv_name = (ID)code[code_index - 1];
13084 cache->iv_set_name = iv_name;
13085 }
13086 else {
13087 cache->iv_set_name = 0;
13088 }
13089
13090 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13091 }
13092
13093 }
13094 break;
13095 case TS_CALLDATA:
13096 {
13097 code[code_index] = (VALUE)cd_entries++;
13098 }
13099 break;
13100 case TS_ID:
13101 {
13102 VALUE op = ibf_load_small_value(load, &reading_pos);
13103 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13104 }
13105 break;
13106 case TS_FUNCPTR:
13107 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13108 break;
13109 case TS_BUILTIN:
13110 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13111 break;
13112 default:
13113 code[code_index] = ibf_load_small_value(load, &reading_pos);
13114 continue;
13115 }
13116 }
13117 if (insn_len(insn) != op_index+1) {
13118 rb_raise(rb_eRuntimeError, "operand size mismatch");
13119 }
13120 }
13121
13122 load_body->iseq_size = code_index;
13123
13124 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13125 load_body->mark_bits.single = mark_offset_bits[0];
13126 }
13127 else {
13128 if (needs_bitmap) {
13129 load_body->mark_bits.list = mark_offset_bits;
13130 }
13131 else {
13132 load_body->mark_bits.list = 0;
13133 ruby_xfree(mark_offset_bits);
13134 }
13135 }
13136
13137 RUBY_ASSERT(code_index == iseq_size);
13138 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13139 return code;
13140}
13141
13142static ibf_offset_t
13143ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13144{
13145 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13146
13147 if (opt_num > 0) {
13148 IBF_W_ALIGN(VALUE);
13149 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13150 }
13151 else {
13152 return ibf_dump_pos(dump);
13153 }
13154}
13155
13156static VALUE *
13157ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13158{
13159 if (opt_num > 0) {
13160 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13161 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13162 return table;
13163 }
13164 else {
13165 return NULL;
13166 }
13167}
13168
13169static ibf_offset_t
13170ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13171{
13172 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13173
13174 if (kw) {
13175 struct rb_iseq_param_keyword dump_kw = *kw;
13176 int dv_num = kw->num - kw->required_num;
13177 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13178 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13179 int i;
13180
13181 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13182 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13183
13184 dump_kw.table = IBF_W(ids, ID, kw->num);
13185 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13186 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13187 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13188 }
13189 else {
13190 return 0;
13191 }
13192}
13193
13194static const struct rb_iseq_param_keyword *
13195ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13196{
13197 if (param_keyword_offset) {
13198 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13199 int dv_num = kw->num - kw->required_num;
13200 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13201
13202 int i;
13203 for (i=0; i<dv_num; i++) {
13204 dvs[i] = ibf_load_object(load, dvs[i]);
13205 }
13206
13207 // Will be set once the local table is loaded.
13208 kw->table = NULL;
13209
13210 kw->default_values = dvs;
13211 return kw;
13212 }
13213 else {
13214 return NULL;
13215 }
13216}
13217
13218static ibf_offset_t
13219ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13220{
13221 ibf_offset_t offset = ibf_dump_pos(dump);
13222 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13223
13224 unsigned int i;
13225 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13226 ibf_dump_write_small_value(dump, entries[i].line_no);
13227#ifdef USE_ISEQ_NODE_ID
13228 ibf_dump_write_small_value(dump, entries[i].node_id);
13229#endif
13230 ibf_dump_write_small_value(dump, entries[i].events);
13231 }
13232
13233 return offset;
13234}
13235
13236static struct iseq_insn_info_entry *
13237ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13238{
13239 ibf_offset_t reading_pos = body_offset;
13240 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13241
13242 unsigned int i;
13243 for (i = 0; i < size; i++) {
13244 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13245#ifdef USE_ISEQ_NODE_ID
13246 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13247#endif
13248 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13249 }
13250
13251 return entries;
13252}
13253
13254static ibf_offset_t
13255ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13256{
13257 ibf_offset_t offset = ibf_dump_pos(dump);
13258
13259 unsigned int last = 0;
13260 unsigned int i;
13261 for (i = 0; i < size; i++) {
13262 ibf_dump_write_small_value(dump, positions[i] - last);
13263 last = positions[i];
13264 }
13265
13266 return offset;
13267}
13268
13269static unsigned int *
13270ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13271{
13272 ibf_offset_t reading_pos = positions_offset;
13273 unsigned int *positions = ALLOC_N(unsigned int, size);
13274
13275 unsigned int last = 0;
13276 unsigned int i;
13277 for (i = 0; i < size; i++) {
13278 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13279 last = positions[i];
13280 }
13281
13282 return positions;
13283}
13284
13285static ibf_offset_t
13286ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13287{
13288 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13289 const int size = body->local_table_size;
13290 ID *table = ALLOCA_N(ID, size);
13291 int i;
13292
13293 for (i=0; i<size; i++) {
13294 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13295 if (v == 0) {
13296 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13297 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13298 }
13299 table[i] = v;
13300 }
13301
13302 IBF_W_ALIGN(ID);
13303 return ibf_dump_write(dump, table, sizeof(ID) * size);
13304}
13305
13306static const ID *
13307ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13308{
13309 if (size > 0) {
13310 ID *table = IBF_R(local_table_offset, ID, size);
13311 int i;
13312
13313 for (i=0; i<size; i++) {
13314 table[i] = ibf_load_id(load, table[i]);
13315 }
13316
13317 if (size == 1 && table[0] == idERROR_INFO) {
13318 xfree(table);
13319 return rb_iseq_shared_exc_local_tbl;
13320 }
13321 else {
13322 return table;
13323 }
13324 }
13325 else {
13326 return NULL;
13327 }
13328}
13329
13330static ibf_offset_t
13331ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13332{
13333 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13334 const int size = body->local_table_size;
13335 IBF_W_ALIGN(enum lvar_state);
13336 return ibf_dump_write(dump, body->lvar_states, sizeof(enum lvar_state) * (body->lvar_states ? size : 0));
13337}
13338
13339static enum lvar_state *
13340ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13341{
13342 if (local_table == rb_iseq_shared_exc_local_tbl ||
13343 size <= 0) {
13344 return NULL;
13345 }
13346 else {
13347 enum lvar_state *states = IBF_R(lvar_states_offset, enum lvar_state, size);
13348 return states;
13349 }
13350}
13351
13352static ibf_offset_t
13353ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13354{
13355 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13356
13357 if (table) {
13358 int *iseq_indices = ALLOCA_N(int, table->size);
13359 unsigned int i;
13360
13361 for (i=0; i<table->size; i++) {
13362 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13363 }
13364
13365 const ibf_offset_t offset = ibf_dump_pos(dump);
13366
13367 for (i=0; i<table->size; i++) {
13368 ibf_dump_write_small_value(dump, iseq_indices[i]);
13369 ibf_dump_write_small_value(dump, table->entries[i].type);
13370 ibf_dump_write_small_value(dump, table->entries[i].start);
13371 ibf_dump_write_small_value(dump, table->entries[i].end);
13372 ibf_dump_write_small_value(dump, table->entries[i].cont);
13373 ibf_dump_write_small_value(dump, table->entries[i].sp);
13374 }
13375 return offset;
13376 }
13377 else {
13378 return ibf_dump_pos(dump);
13379 }
13380}
13381
13382static void
13383ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13384{
13385 if (size) {
13386 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13387 table->size = size;
13388 ISEQ_BODY(parent_iseq)->catch_table = table;
13389
13390 ibf_offset_t reading_pos = catch_table_offset;
13391
13392 unsigned int i;
13393 for (i=0; i<table->size; i++) {
13394 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13395 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13396 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13397 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13398 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13399 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13400
13401 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13402 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13403 }
13404 }
13405 else {
13406 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13407 }
13408}
13409
13410static ibf_offset_t
13411ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13412{
13413 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13414 const unsigned int ci_size = body->ci_size;
13415 const struct rb_call_data *cds = body->call_data;
13416
13417 ibf_offset_t offset = ibf_dump_pos(dump);
13418
13419 unsigned int i;
13420
13421 for (i = 0; i < ci_size; i++) {
13422 const struct rb_callinfo *ci = cds[i].ci;
13423 if (ci != NULL) {
13424 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13425 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13426 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13427
13428 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13429 if (kwarg) {
13430 int len = kwarg->keyword_len;
13431 ibf_dump_write_small_value(dump, len);
13432 for (int j=0; j<len; j++) {
13433 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13434 ibf_dump_write_small_value(dump, keyword);
13435 }
13436 }
13437 else {
13438 ibf_dump_write_small_value(dump, 0);
13439 }
13440 }
13441 else {
13442 // TODO: truncate NULL ci from call_data.
13443 ibf_dump_write_small_value(dump, (VALUE)-1);
13444 }
13445 }
13446
13447 return offset;
13448}
13449
13451 ID id;
13452 VALUE name;
13453 VALUE val;
13454};
13455
13457 size_t num;
13458 struct outer_variable_pair pairs[1];
13459};
13460
13461static enum rb_id_table_iterator_result
13462store_outer_variable(ID id, VALUE val, void *dump)
13463{
13464 struct outer_variable_list *ovlist = dump;
13465 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13466 pair->id = id;
13467 pair->name = rb_id2str(id);
13468 pair->val = val;
13469 return ID_TABLE_CONTINUE;
13470}
13471
13472static int
13473outer_variable_cmp(const void *a, const void *b, void *arg)
13474{
13475 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13476 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13477
13478 if (!ap->name) {
13479 return -1;
13480 }
13481 else if (!bp->name) {
13482 return 1;
13483 }
13484
13485 return rb_str_cmp(ap->name, bp->name);
13486}
13487
13488static ibf_offset_t
13489ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13490{
13491 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13492
13493 ibf_offset_t offset = ibf_dump_pos(dump);
13494
13495 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13496 ibf_dump_write_small_value(dump, (VALUE)size);
13497 if (size > 0) {
13498 VALUE buff;
13499 size_t buffsize =
13500 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13501 offsetof(struct outer_variable_list, pairs),
13502 rb_eArgError);
13503 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13504 ovlist->num = 0;
13505 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13506 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13507 for (size_t i = 0; i < size; ++i) {
13508 ID id = ovlist->pairs[i].id;
13509 ID val = ovlist->pairs[i].val;
13510 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13511 ibf_dump_write_small_value(dump, val);
13512 }
13513 }
13514
13515 return offset;
13516}
13517
13518/* note that we dump out rb_call_info but load back rb_call_data */
13519static void
13520ibf_load_ci_entries(const struct ibf_load *load,
13521 ibf_offset_t ci_entries_offset,
13522 unsigned int ci_size,
13523 struct rb_call_data **cd_ptr)
13524{
13525 if (!ci_size) {
13526 *cd_ptr = NULL;
13527 return;
13528 }
13529
13530 ibf_offset_t reading_pos = ci_entries_offset;
13531
13532 unsigned int i;
13533
13534 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13535 *cd_ptr = cds;
13536
13537 for (i = 0; i < ci_size; i++) {
13538 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13539 if (mid_index != (VALUE)-1) {
13540 ID mid = ibf_load_id(load, mid_index);
13541 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13542 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13543
13544 struct rb_callinfo_kwarg *kwarg = NULL;
13545 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13546 if (kwlen > 0) {
13547 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13548 kwarg->references = 0;
13549 kwarg->keyword_len = kwlen;
13550 for (int j=0; j<kwlen; j++) {
13551 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13552 kwarg->keywords[j] = ibf_load_object(load, keyword);
13553 }
13554 }
13555
13556 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13557 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13558 cds[i].cc = vm_cc_empty();
13559 }
13560 else {
13561 // NULL ci
13562 cds[i].ci = NULL;
13563 cds[i].cc = NULL;
13564 }
13565 }
13566}
13567
13568static struct rb_id_table *
13569ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13570{
13571 ibf_offset_t reading_pos = outer_variables_offset;
13572
13573 struct rb_id_table *tbl = NULL;
13574
13575 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13576
13577 if (table_size > 0) {
13578 tbl = rb_id_table_create(table_size);
13579 }
13580
13581 for (size_t i = 0; i < table_size; i++) {
13582 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13583 VALUE value = ibf_load_small_value(load, &reading_pos);
13584 if (!key) key = rb_make_temporary_id(i);
13585 rb_id_table_insert(tbl, key, value);
13586 }
13587
13588 return tbl;
13589}
13590
13591static ibf_offset_t
13592ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13593{
13594 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13595
13596 unsigned int *positions;
13597
13598 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13599
13600 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13601 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13602 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13603
13604#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13605 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13606
13607 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13608 struct ibf_dump_buffer buffer;
13609 buffer.str = rb_str_new(0, 0);
13610 buffer.obj_table = ibf_dump_object_table_new();
13611 dump->current_buffer = &buffer;
13612#endif
13613
13614 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13615 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13616 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13617 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13618 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13619
13620 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13621 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13622 ruby_xfree(positions);
13623
13624 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13625 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13626 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13627 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13628 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13629 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13630 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13631 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13632 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13633
13634#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13635 ibf_offset_t local_obj_list_offset;
13636 unsigned int local_obj_list_size;
13637
13638 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13639#endif
13640
13641 ibf_offset_t body_offset = ibf_dump_pos(dump);
13642
13643 /* dump the constant body */
13644 unsigned int param_flags =
13645 (body->param.flags.has_lead << 0) |
13646 (body->param.flags.has_opt << 1) |
13647 (body->param.flags.has_rest << 2) |
13648 (body->param.flags.has_post << 3) |
13649 (body->param.flags.has_kw << 4) |
13650 (body->param.flags.has_kwrest << 5) |
13651 (body->param.flags.has_block << 6) |
13652 (body->param.flags.ambiguous_param0 << 7) |
13653 (body->param.flags.accepts_no_kwarg << 8) |
13654 (body->param.flags.ruby2_keywords << 9) |
13655 (body->param.flags.anon_rest << 10) |
13656 (body->param.flags.anon_kwrest << 11) |
13657 (body->param.flags.use_block << 12) |
13658 (body->param.flags.forwardable << 13) ;
13659
13660#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13661# define IBF_BODY_OFFSET(x) (x)
13662#else
13663# define IBF_BODY_OFFSET(x) (body_offset - (x))
13664#endif
13665
13666 ibf_dump_write_small_value(dump, body->type);
13667 ibf_dump_write_small_value(dump, body->iseq_size);
13668 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13669 ibf_dump_write_small_value(dump, bytecode_size);
13670 ibf_dump_write_small_value(dump, param_flags);
13671 ibf_dump_write_small_value(dump, body->param.size);
13672 ibf_dump_write_small_value(dump, body->param.lead_num);
13673 ibf_dump_write_small_value(dump, body->param.opt_num);
13674 ibf_dump_write_small_value(dump, body->param.rest_start);
13675 ibf_dump_write_small_value(dump, body->param.post_start);
13676 ibf_dump_write_small_value(dump, body->param.post_num);
13677 ibf_dump_write_small_value(dump, body->param.block_start);
13678 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13679 ibf_dump_write_small_value(dump, param_keyword_offset);
13680 ibf_dump_write_small_value(dump, location_pathobj_index);
13681 ibf_dump_write_small_value(dump, location_base_label_index);
13682 ibf_dump_write_small_value(dump, location_label_index);
13683 ibf_dump_write_small_value(dump, body->location.first_lineno);
13684 ibf_dump_write_small_value(dump, body->location.node_id);
13685 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13686 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13687 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13688 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13689 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13690 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13691 ibf_dump_write_small_value(dump, body->insns_info.size);
13692 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13693 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13694 ibf_dump_write_small_value(dump, catch_table_size);
13695 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13696 ibf_dump_write_small_value(dump, parent_iseq_index);
13697 ibf_dump_write_small_value(dump, local_iseq_index);
13698 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13699 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13700 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13701 ibf_dump_write_small_value(dump, body->variable.flip_count);
13702 ibf_dump_write_small_value(dump, body->local_table_size);
13703 ibf_dump_write_small_value(dump, body->ivc_size);
13704 ibf_dump_write_small_value(dump, body->icvarc_size);
13705 ibf_dump_write_small_value(dump, body->ise_size);
13706 ibf_dump_write_small_value(dump, body->ic_size);
13707 ibf_dump_write_small_value(dump, body->ci_size);
13708 ibf_dump_write_small_value(dump, body->stack_max);
13709 ibf_dump_write_small_value(dump, body->builtin_attrs);
13710 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13711
13712#undef IBF_BODY_OFFSET
13713
13714#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13715 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13716
13717 dump->current_buffer = saved_buffer;
13718 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13719
13720 ibf_offset_t offset = ibf_dump_pos(dump);
13721 ibf_dump_write_small_value(dump, iseq_start);
13722 ibf_dump_write_small_value(dump, iseq_length_bytes);
13723 ibf_dump_write_small_value(dump, body_offset);
13724
13725 ibf_dump_write_small_value(dump, local_obj_list_offset);
13726 ibf_dump_write_small_value(dump, local_obj_list_size);
13727
13728 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13729
13730 return offset;
13731#else
13732 return body_offset;
13733#endif
13734}
13735
13736static VALUE
13737ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13738{
13739 VALUE str = ibf_load_object(load, str_index);
13740 if (str != Qnil) {
13741 str = rb_fstring(str);
13742 }
13743 return str;
13744}
13745
13746static void
13747ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13748{
13749 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13750
13751 ibf_offset_t reading_pos = offset;
13752
13753#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13754 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13755 load->current_buffer = &load->global_buffer;
13756
13757 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13758 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13759 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13760
13761 struct ibf_load_buffer buffer;
13762 buffer.buff = load->global_buffer.buff + iseq_start;
13763 buffer.size = iseq_length_bytes;
13764 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13765 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13766 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13767
13768 load->current_buffer = &buffer;
13769 reading_pos = body_offset;
13770#endif
13771
13772#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13773# define IBF_BODY_OFFSET(x) (x)
13774#else
13775# define IBF_BODY_OFFSET(x) (offset - (x))
13776#endif
13777
13778 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13779 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13780 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13781 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13782 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13783 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13784 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13785 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13786 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13787 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13788 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13789 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13790 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13791 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13792 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13793 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13794 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13795 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13796 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13797 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13798 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13799 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13800 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13801 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13802 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13803 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13804 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13805 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13806 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13807 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13808 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13809 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13810 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13811 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13812 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13813 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13814 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13815
13816 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13817 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13818 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13819 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13820
13821 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13822 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13823 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13824 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13825
13826 // setup fname and dummy frame
13827 VALUE path = ibf_load_object(load, location_pathobj_index);
13828 {
13829 VALUE realpath = Qnil;
13830
13831 if (RB_TYPE_P(path, T_STRING)) {
13832 realpath = path = rb_fstring(path);
13833 }
13834 else if (RB_TYPE_P(path, T_ARRAY)) {
13835 VALUE pathobj = path;
13836 if (RARRAY_LEN(pathobj) != 2) {
13837 rb_raise(rb_eRuntimeError, "path object size mismatch");
13838 }
13839 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13840 realpath = RARRAY_AREF(pathobj, 1);
13841 if (!NIL_P(realpath)) {
13842 if (!RB_TYPE_P(realpath, T_STRING)) {
13843 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13844 "(%x), path=%+"PRIsVALUE,
13845 realpath, TYPE(realpath), path);
13846 }
13847 realpath = rb_fstring(realpath);
13848 }
13849 }
13850 else {
13851 rb_raise(rb_eRuntimeError, "unexpected path object");
13852 }
13853 rb_iseq_pathobj_set(iseq, path, realpath);
13854 }
13855
13856 // push dummy frame
13857 rb_execution_context_t *ec = GET_EC();
13858 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13859
13860#undef IBF_BODY_OFFSET
13861
13862 load_body->type = type;
13863 load_body->stack_max = stack_max;
13864 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13865 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13866 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13867 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13868 load_body->param.flags.has_kw = FALSE;
13869 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13870 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13871 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13872 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13873 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13874 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13875 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13876 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13877 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13878 load_body->param.size = param_size;
13879 load_body->param.lead_num = param_lead_num;
13880 load_body->param.opt_num = param_opt_num;
13881 load_body->param.rest_start = param_rest_start;
13882 load_body->param.post_start = param_post_start;
13883 load_body->param.post_num = param_post_num;
13884 load_body->param.block_start = param_block_start;
13885 load_body->local_table_size = local_table_size;
13886 load_body->ci_size = ci_size;
13887 load_body->insns_info.size = insns_info_size;
13888
13889 ISEQ_COVERAGE_SET(iseq, Qnil);
13890 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13891 load_body->variable.flip_count = variable_flip_count;
13892 load_body->variable.script_lines = Qnil;
13893
13894 load_body->location.first_lineno = location_first_lineno;
13895 load_body->location.node_id = location_node_id;
13896 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13897 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13898 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13899 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13900 load_body->builtin_attrs = builtin_attrs;
13901 load_body->prism = prism;
13902
13903 load_body->ivc_size = ivc_size;
13904 load_body->icvarc_size = icvarc_size;
13905 load_body->ise_size = ise_size;
13906 load_body->ic_size = ic_size;
13907
13908 if (ISEQ_IS_SIZE(load_body)) {
13909 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13910 }
13911 else {
13912 load_body->is_entries = NULL;
13913 }
13914 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13915 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13916 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13917 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13918 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13919 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13920 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13921 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13922 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13923 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13924
13925 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13926 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13927 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13928
13929 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13930 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13931 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13932
13933 // This must be done after the local table is loaded.
13934 if (load_body->param.keyword != NULL) {
13935 RUBY_ASSERT(load_body->local_table);
13936 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13937 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13938 }
13939
13940 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13941#if VM_INSN_INFO_TABLE_IMPL == 2
13942 rb_iseq_insns_info_encode_positions(iseq);
13943#endif
13944
13945 rb_iseq_translate_threaded_code(iseq);
13946
13947#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13948 load->current_buffer = &load->global_buffer;
13949#endif
13950
13951 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13952 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13953
13954#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13955 load->current_buffer = saved_buffer;
13956#endif
13957 verify_call_cache(iseq);
13958
13959 RB_GC_GUARD(dummy_frame);
13960 rb_vm_pop_frame_no_int(ec);
13961}
13962
13964{
13965 struct ibf_dump *dump;
13966 VALUE offset_list;
13967};
13968
13969static int
13970ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13971{
13972 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13973 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13974
13975 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13976 rb_ary_push(args->offset_list, UINT2NUM(offset));
13977
13978 return ST_CONTINUE;
13979}
13980
13981static void
13982ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13983{
13984 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13985
13986 struct ibf_dump_iseq_list_arg args;
13987 args.dump = dump;
13988 args.offset_list = offset_list;
13989
13990 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13991
13992 st_index_t i;
13993 st_index_t size = dump->iseq_table->num_entries;
13994 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13995
13996 for (i = 0; i < size; i++) {
13997 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13998 }
13999
14000 ibf_dump_align(dump, sizeof(ibf_offset_t));
14001 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14002 header->iseq_list_size = (unsigned int)size;
14003}
14004
14005/*
14006 * Binary format
14007 * - ibf_object_header
14008 * - ibf_object_xxx (xxx is type)
14009 */
14010
14012 unsigned int type: 5;
14013 unsigned int special_const: 1;
14014 unsigned int frozen: 1;
14015 unsigned int internal: 1;
14016};
14017
14018enum ibf_object_class_index {
14019 IBF_OBJECT_CLASS_OBJECT,
14020 IBF_OBJECT_CLASS_ARRAY,
14021 IBF_OBJECT_CLASS_STANDARD_ERROR,
14022 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14023 IBF_OBJECT_CLASS_TYPE_ERROR,
14024 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14025};
14026
14028 long srcstr;
14029 char option;
14030};
14031
14033 long len;
14034 long keyval[FLEX_ARY_LEN];
14035};
14036
14038 long class_index;
14039 long len;
14040 long beg;
14041 long end;
14042 int excl;
14043};
14044
14046 ssize_t slen;
14047 BDIGIT digits[FLEX_ARY_LEN];
14048};
14049
14050enum ibf_object_data_type {
14051 IBF_OBJECT_DATA_ENCODING,
14052};
14053
14055 long a, b;
14056};
14057
14059 long str;
14060};
14061
14062#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14063 ((((offset) - 1) / (align) + 1) * (align))
14064/* No cast, since it's UB to create an unaligned pointer.
14065 * Leave as void* for use with memcpy in those cases.
14066 * We align the offset, but the buffer pointer is only VALUE aligned,
14067 * so the returned pointer may be unaligned for `type` .*/
14068#define IBF_OBJBODY(type, offset) \
14069 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14070
14071static const void *
14072ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14073{
14074 if (offset >= load->current_buffer->size) {
14075 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14076 }
14077 return load->current_buffer->buff + offset;
14078}
14079
14080NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14081
14082static void
14083ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14084{
14085 char buff[0x100];
14086 rb_raw_obj_info(buff, sizeof(buff), obj);
14087 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14088}
14089
14090NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14091
14092static VALUE
14093ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14094{
14095 rb_raise(rb_eArgError, "unsupported");
14097}
14098
14099static void
14100ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14101{
14102 enum ibf_object_class_index cindex;
14103 if (obj == rb_cObject) {
14104 cindex = IBF_OBJECT_CLASS_OBJECT;
14105 }
14106 else if (obj == rb_cArray) {
14107 cindex = IBF_OBJECT_CLASS_ARRAY;
14108 }
14109 else if (obj == rb_eStandardError) {
14110 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14111 }
14112 else if (obj == rb_eNoMatchingPatternError) {
14113 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14114 }
14115 else if (obj == rb_eTypeError) {
14116 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14117 }
14118 else if (obj == rb_eNoMatchingPatternKeyError) {
14119 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14120 }
14121 else {
14122 rb_obj_info_dump(obj);
14123 rb_p(obj);
14124 rb_bug("unsupported class");
14125 }
14126 ibf_dump_write_small_value(dump, (VALUE)cindex);
14127}
14128
14129static VALUE
14130ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14131{
14132 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14133
14134 switch (cindex) {
14135 case IBF_OBJECT_CLASS_OBJECT:
14136 return rb_cObject;
14137 case IBF_OBJECT_CLASS_ARRAY:
14138 return rb_cArray;
14139 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14140 return rb_eStandardError;
14141 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14143 case IBF_OBJECT_CLASS_TYPE_ERROR:
14144 return rb_eTypeError;
14145 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14147 }
14148
14149 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14150}
14151
14152
14153static void
14154ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14155{
14156 double dbl = RFLOAT_VALUE(obj);
14157 (void)IBF_W(&dbl, double, 1);
14158}
14159
14160static VALUE
14161ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14162{
14163 double d;
14164 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14165 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14166 VALUE f = DBL2NUM(d);
14167 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14168 return f;
14169}
14170
14171static void
14172ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14173{
14174 long encindex = (long)rb_enc_get_index(obj);
14175 long len = RSTRING_LEN(obj);
14176 const char *ptr = RSTRING_PTR(obj);
14177
14178 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14179 rb_encoding *enc = rb_enc_from_index((int)encindex);
14180 const char *enc_name = rb_enc_name(enc);
14181 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14182 }
14183
14184 ibf_dump_write_small_value(dump, encindex);
14185 ibf_dump_write_small_value(dump, len);
14186 IBF_WP(ptr, char, len);
14187}
14188
14189static VALUE
14190ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14191{
14192 ibf_offset_t reading_pos = offset;
14193
14194 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14195 const long len = (long)ibf_load_small_value(load, &reading_pos);
14196 const char *ptr = load->current_buffer->buff + reading_pos;
14197
14198 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14199 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14200 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14201 }
14202
14203 VALUE str;
14204 if (header->frozen && !header->internal) {
14205 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14206 }
14207 else {
14208 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14209
14210 if (header->internal) rb_obj_hide(str);
14211 if (header->frozen) str = rb_fstring(str);
14212 }
14213 return str;
14214}
14215
14216static void
14217ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14218{
14219 VALUE srcstr = RREGEXP_SRC(obj);
14220 struct ibf_object_regexp regexp;
14221 regexp.option = (char)rb_reg_options(obj);
14222 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14223
14224 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14225 ibf_dump_write_small_value(dump, regexp.srcstr);
14226}
14227
14228static VALUE
14229ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14230{
14231 struct ibf_object_regexp regexp;
14232 regexp.option = ibf_load_byte(load, &offset);
14233 regexp.srcstr = ibf_load_small_value(load, &offset);
14234
14235 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14236 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14237
14238 if (header->internal) rb_obj_hide(reg);
14239 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14240
14241 return reg;
14242}
14243
14244static void
14245ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14246{
14247 long i, len = RARRAY_LEN(obj);
14248 ibf_dump_write_small_value(dump, len);
14249 for (i=0; i<len; i++) {
14250 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14251 ibf_dump_write_small_value(dump, index);
14252 }
14253}
14254
14255static VALUE
14256ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14257{
14258 ibf_offset_t reading_pos = offset;
14259
14260 const long len = (long)ibf_load_small_value(load, &reading_pos);
14261
14262 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14263 int i;
14264
14265 for (i=0; i<len; i++) {
14266 const VALUE index = ibf_load_small_value(load, &reading_pos);
14267 rb_ary_push(ary, ibf_load_object(load, index));
14268 }
14269
14270 if (header->frozen) {
14271 rb_ary_freeze(ary);
14272 rb_ractor_make_shareable(ary); // TODO: check elements
14273 }
14274
14275 return ary;
14276}
14277
14278static int
14279ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14280{
14281 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14282
14283 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14284 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14285
14286 ibf_dump_write_small_value(dump, key_index);
14287 ibf_dump_write_small_value(dump, val_index);
14288 return ST_CONTINUE;
14289}
14290
14291static void
14292ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14293{
14294 long len = RHASH_SIZE(obj);
14295 ibf_dump_write_small_value(dump, (VALUE)len);
14296
14297 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14298}
14299
14300static VALUE
14301ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14302{
14303 long len = (long)ibf_load_small_value(load, &offset);
14304 VALUE obj = rb_hash_new_with_size(len);
14305 int i;
14306
14307 for (i = 0; i < len; i++) {
14308 VALUE key_index = ibf_load_small_value(load, &offset);
14309 VALUE val_index = ibf_load_small_value(load, &offset);
14310
14311 VALUE key = ibf_load_object(load, key_index);
14312 VALUE val = ibf_load_object(load, val_index);
14313 rb_hash_aset(obj, key, val);
14314 }
14315 rb_hash_rehash(obj);
14316
14317 if (header->internal) rb_obj_hide(obj);
14318 if (header->frozen) {
14319 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14320 }
14321
14322 return obj;
14323}
14324
14325static void
14326ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14327{
14328 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14329 struct ibf_object_struct_range range;
14330 VALUE beg, end;
14331 IBF_ZERO(range);
14332 range.len = 3;
14333 range.class_index = 0;
14334
14335 rb_range_values(obj, &beg, &end, &range.excl);
14336 range.beg = (long)ibf_dump_object(dump, beg);
14337 range.end = (long)ibf_dump_object(dump, end);
14338
14339 IBF_W_ALIGN(struct ibf_object_struct_range);
14340 IBF_WV(range);
14341 }
14342 else {
14343 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14344 rb_class_name(CLASS_OF(obj)));
14345 }
14346}
14347
14348static VALUE
14349ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14350{
14351 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14352 VALUE beg = ibf_load_object(load, range->beg);
14353 VALUE end = ibf_load_object(load, range->end);
14354 VALUE obj = rb_range_new(beg, end, range->excl);
14355 if (header->internal) rb_obj_hide(obj);
14356 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14357 return obj;
14358}
14359
14360static void
14361ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14362{
14363 ssize_t len = BIGNUM_LEN(obj);
14364 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14365 BDIGIT *d = BIGNUM_DIGITS(obj);
14366
14367 (void)IBF_W(&slen, ssize_t, 1);
14368 IBF_WP(d, BDIGIT, len);
14369}
14370
14371static VALUE
14372ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14373{
14374 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14375 int sign = bignum->slen > 0;
14376 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14377 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14380 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14381 big_unpack_flags |
14382 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14383 if (header->internal) rb_obj_hide(obj);
14384 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14385 return obj;
14386}
14387
14388static void
14389ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14390{
14391 if (rb_data_is_encoding(obj)) {
14392 rb_encoding *enc = rb_to_encoding(obj);
14393 const char *name = rb_enc_name(enc);
14394 long len = strlen(name) + 1;
14395 long data[2];
14396 data[0] = IBF_OBJECT_DATA_ENCODING;
14397 data[1] = len;
14398 (void)IBF_W(data, long, 2);
14399 IBF_WP(name, char, len);
14400 }
14401 else {
14402 ibf_dump_object_unsupported(dump, obj);
14403 }
14404}
14405
14406static VALUE
14407ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14408{
14409 const long *body = IBF_OBJBODY(long, offset);
14410 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14411 /* const long len = body[1]; */
14412 const char *data = (const char *)&body[2];
14413
14414 switch (type) {
14415 case IBF_OBJECT_DATA_ENCODING:
14416 {
14417 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14418 return encobj;
14419 }
14420 }
14421
14422 return ibf_load_object_unsupported(load, header, offset);
14423}
14424
14425static void
14426ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14427{
14428 long data[2];
14429 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14430 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14431
14432 (void)IBF_W(data, long, 2);
14433}
14434
14435static VALUE
14436ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14437{
14438 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14439 VALUE a = ibf_load_object(load, nums->a);
14440 VALUE b = ibf_load_object(load, nums->b);
14441 VALUE obj = header->type == T_COMPLEX ?
14442 rb_complex_new(a, b) : rb_rational_new(a, b);
14443
14444 if (header->internal) rb_obj_hide(obj);
14445 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14446 return obj;
14447}
14448
14449static void
14450ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14451{
14452 ibf_dump_object_string(dump, rb_sym2str(obj));
14453}
14454
14455static VALUE
14456ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14457{
14458 ibf_offset_t reading_pos = offset;
14459
14460 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14461 const long len = (long)ibf_load_small_value(load, &reading_pos);
14462 const char *ptr = load->current_buffer->buff + reading_pos;
14463
14464 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14465 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14466 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14467 }
14468
14469 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14470 return ID2SYM(id);
14471}
14472
14473typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14474static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14475 ibf_dump_object_unsupported, /* T_NONE */
14476 ibf_dump_object_unsupported, /* T_OBJECT */
14477 ibf_dump_object_class, /* T_CLASS */
14478 ibf_dump_object_unsupported, /* T_MODULE */
14479 ibf_dump_object_float, /* T_FLOAT */
14480 ibf_dump_object_string, /* T_STRING */
14481 ibf_dump_object_regexp, /* T_REGEXP */
14482 ibf_dump_object_array, /* T_ARRAY */
14483 ibf_dump_object_hash, /* T_HASH */
14484 ibf_dump_object_struct, /* T_STRUCT */
14485 ibf_dump_object_bignum, /* T_BIGNUM */
14486 ibf_dump_object_unsupported, /* T_FILE */
14487 ibf_dump_object_data, /* T_DATA */
14488 ibf_dump_object_unsupported, /* T_MATCH */
14489 ibf_dump_object_complex_rational, /* T_COMPLEX */
14490 ibf_dump_object_complex_rational, /* T_RATIONAL */
14491 ibf_dump_object_unsupported, /* 0x10 */
14492 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14493 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14494 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14495 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14496 ibf_dump_object_unsupported, /* T_FIXNUM */
14497 ibf_dump_object_unsupported, /* T_UNDEF */
14498 ibf_dump_object_unsupported, /* 0x17 */
14499 ibf_dump_object_unsupported, /* 0x18 */
14500 ibf_dump_object_unsupported, /* 0x19 */
14501 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14502 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14503 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14504 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14505 ibf_dump_object_unsupported, /* 0x1e */
14506 ibf_dump_object_unsupported, /* 0x1f */
14507};
14508
14509static void
14510ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14511{
14512 unsigned char byte =
14513 (header.type << 0) |
14514 (header.special_const << 5) |
14515 (header.frozen << 6) |
14516 (header.internal << 7);
14517
14518 IBF_WV(byte);
14519}
14520
14521static struct ibf_object_header
14522ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14523{
14524 unsigned char byte = ibf_load_byte(load, offset);
14525
14526 struct ibf_object_header header;
14527 header.type = (byte >> 0) & 0x1f;
14528 header.special_const = (byte >> 5) & 0x01;
14529 header.frozen = (byte >> 6) & 0x01;
14530 header.internal = (byte >> 7) & 0x01;
14531
14532 return header;
14533}
14534
14535static ibf_offset_t
14536ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14537{
14538 struct ibf_object_header obj_header;
14539 ibf_offset_t current_offset;
14540 IBF_ZERO(obj_header);
14541 obj_header.type = TYPE(obj);
14542
14543 IBF_W_ALIGN(ibf_offset_t);
14544 current_offset = ibf_dump_pos(dump);
14545
14546 if (SPECIAL_CONST_P(obj) &&
14547 ! (SYMBOL_P(obj) ||
14548 RB_FLOAT_TYPE_P(obj))) {
14549 obj_header.special_const = TRUE;
14550 obj_header.frozen = TRUE;
14551 obj_header.internal = TRUE;
14552 ibf_dump_object_object_header(dump, obj_header);
14553 ibf_dump_write_small_value(dump, obj);
14554 }
14555 else {
14556 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14557 obj_header.special_const = FALSE;
14558 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14559 ibf_dump_object_object_header(dump, obj_header);
14560 (*dump_object_functions[obj_header.type])(dump, obj);
14561 }
14562
14563 return current_offset;
14564}
14565
14566typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14567static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14568 ibf_load_object_unsupported, /* T_NONE */
14569 ibf_load_object_unsupported, /* T_OBJECT */
14570 ibf_load_object_class, /* T_CLASS */
14571 ibf_load_object_unsupported, /* T_MODULE */
14572 ibf_load_object_float, /* T_FLOAT */
14573 ibf_load_object_string, /* T_STRING */
14574 ibf_load_object_regexp, /* T_REGEXP */
14575 ibf_load_object_array, /* T_ARRAY */
14576 ibf_load_object_hash, /* T_HASH */
14577 ibf_load_object_struct, /* T_STRUCT */
14578 ibf_load_object_bignum, /* T_BIGNUM */
14579 ibf_load_object_unsupported, /* T_FILE */
14580 ibf_load_object_data, /* T_DATA */
14581 ibf_load_object_unsupported, /* T_MATCH */
14582 ibf_load_object_complex_rational, /* T_COMPLEX */
14583 ibf_load_object_complex_rational, /* T_RATIONAL */
14584 ibf_load_object_unsupported, /* 0x10 */
14585 ibf_load_object_unsupported, /* T_NIL */
14586 ibf_load_object_unsupported, /* T_TRUE */
14587 ibf_load_object_unsupported, /* T_FALSE */
14588 ibf_load_object_symbol,
14589 ibf_load_object_unsupported, /* T_FIXNUM */
14590 ibf_load_object_unsupported, /* T_UNDEF */
14591 ibf_load_object_unsupported, /* 0x17 */
14592 ibf_load_object_unsupported, /* 0x18 */
14593 ibf_load_object_unsupported, /* 0x19 */
14594 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14595 ibf_load_object_unsupported, /* T_NODE 0x1b */
14596 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14597 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14598 ibf_load_object_unsupported, /* 0x1e */
14599 ibf_load_object_unsupported, /* 0x1f */
14600};
14601
14602static VALUE
14603ibf_load_object(const struct ibf_load *load, VALUE object_index)
14604{
14605 if (object_index == 0) {
14606 return Qnil;
14607 }
14608 else {
14609 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14610 if (!obj) {
14611 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14612 ibf_offset_t offset = offsets[object_index];
14613 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14614
14615#if IBF_ISEQ_DEBUG
14616 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14617 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14618 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14619 header.type, header.special_const, header.frozen, header.internal);
14620#endif
14621 if (offset >= load->current_buffer->size) {
14622 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14623 }
14624
14625 if (header.special_const) {
14626 ibf_offset_t reading_pos = offset;
14627
14628 obj = ibf_load_small_value(load, &reading_pos);
14629 }
14630 else {
14631 obj = (*load_object_functions[header.type])(load, &header, offset);
14632 }
14633
14634 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14635 }
14636#if IBF_ISEQ_DEBUG
14637 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14638 object_index, obj);
14639#endif
14640 return obj;
14641 }
14642}
14643
14645{
14646 struct ibf_dump *dump;
14647 VALUE offset_list;
14648};
14649
14650static int
14651ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14652{
14653 VALUE obj = (VALUE)key;
14654 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14655
14656 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14657 rb_ary_push(args->offset_list, UINT2NUM(offset));
14658
14659 return ST_CONTINUE;
14660}
14661
14662static void
14663ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14664{
14665 st_table *obj_table = dump->current_buffer->obj_table;
14666 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14667
14668 struct ibf_dump_object_list_arg args;
14669 args.dump = dump;
14670 args.offset_list = offset_list;
14671
14672 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14673
14674 IBF_W_ALIGN(ibf_offset_t);
14675 *obj_list_offset = ibf_dump_pos(dump);
14676
14677 st_index_t size = obj_table->num_entries;
14678 st_index_t i;
14679
14680 for (i=0; i<size; i++) {
14681 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14682 IBF_WV(offset);
14683 }
14684
14685 *obj_list_size = (unsigned int)size;
14686}
14687
14688static void
14689ibf_dump_mark(void *ptr)
14690{
14691 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14692 rb_gc_mark(dump->global_buffer.str);
14693
14694 rb_mark_set(dump->global_buffer.obj_table);
14695 rb_mark_set(dump->iseq_table);
14696}
14697
14698static void
14699ibf_dump_free(void *ptr)
14700{
14701 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14702 if (dump->global_buffer.obj_table) {
14703 st_free_table(dump->global_buffer.obj_table);
14704 dump->global_buffer.obj_table = 0;
14705 }
14706 if (dump->iseq_table) {
14707 st_free_table(dump->iseq_table);
14708 dump->iseq_table = 0;
14709 }
14710}
14711
14712static size_t
14713ibf_dump_memsize(const void *ptr)
14714{
14715 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14716 size_t size = 0;
14717 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14718 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14719 return size;
14720}
14721
14722static const rb_data_type_t ibf_dump_type = {
14723 "ibf_dump",
14724 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14725 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14726};
14727
14728static void
14729ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14730{
14731 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14732 dump->iseq_table = NULL;
14733
14734 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14735 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14736 dump->iseq_table = st_init_numtable(); /* need free */
14737
14738 dump->current_buffer = &dump->global_buffer;
14739}
14740
14741VALUE
14742rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14743{
14744 struct ibf_dump *dump;
14745 struct ibf_header header = {{0}};
14746 VALUE dump_obj;
14747 VALUE str;
14748
14749 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14750 ISEQ_BODY(iseq)->local_iseq != iseq) {
14751 rb_raise(rb_eRuntimeError, "should be top of iseq");
14752 }
14753 if (RTEST(ISEQ_COVERAGE(iseq))) {
14754 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14755 }
14756
14757 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14758 ibf_dump_setup(dump, dump_obj);
14759
14760 ibf_dump_write(dump, &header, sizeof(header));
14761 ibf_dump_iseq(dump, iseq);
14762
14763 header.magic[0] = 'Y'; /* YARB */
14764 header.magic[1] = 'A';
14765 header.magic[2] = 'R';
14766 header.magic[3] = 'B';
14767 header.major_version = IBF_MAJOR_VERSION;
14768 header.minor_version = IBF_MINOR_VERSION;
14769 header.endian = IBF_ENDIAN_MARK;
14770 header.wordsize = (uint8_t)SIZEOF_VALUE;
14771 ibf_dump_iseq_list(dump, &header);
14772 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14773 header.size = ibf_dump_pos(dump);
14774
14775 if (RTEST(opt)) {
14776 VALUE opt_str = opt;
14777 const char *ptr = StringValuePtr(opt_str);
14778 header.extra_size = RSTRING_LENINT(opt_str);
14779 ibf_dump_write(dump, ptr, header.extra_size);
14780 }
14781 else {
14782 header.extra_size = 0;
14783 }
14784
14785 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14786
14787 str = dump->global_buffer.str;
14788 RB_GC_GUARD(dump_obj);
14789 return str;
14790}
14791
14792static const ibf_offset_t *
14793ibf_iseq_list(const struct ibf_load *load)
14794{
14795 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14796}
14797
14798void
14799rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14800{
14801 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14802 rb_iseq_t *prev_src_iseq = load->iseq;
14803 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14804 load->iseq = iseq;
14805#if IBF_ISEQ_DEBUG
14806 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14807 iseq->aux.loader.index, offset,
14808 load->header->size);
14809#endif
14810 ibf_load_iseq_each(load, iseq, offset);
14811 ISEQ_COMPILE_DATA_CLEAR(iseq);
14812 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14813 rb_iseq_init_trace(iseq);
14814 load->iseq = prev_src_iseq;
14815}
14816
14817#if USE_LAZY_LOAD
14818const rb_iseq_t *
14819rb_iseq_complete(const rb_iseq_t *iseq)
14820{
14821 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14822 return iseq;
14823}
14824#endif
14825
14826static rb_iseq_t *
14827ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14828{
14829 int iseq_index = (int)(VALUE)index_iseq;
14830
14831#if IBF_ISEQ_DEBUG
14832 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14833 (void *)index_iseq, (void *)load->iseq_list);
14834#endif
14835 if (iseq_index == -1) {
14836 return NULL;
14837 }
14838 else {
14839 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14840
14841#if IBF_ISEQ_DEBUG
14842 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14843#endif
14844 if (iseqv) {
14845 return (rb_iseq_t *)iseqv;
14846 }
14847 else {
14848 rb_iseq_t *iseq = iseq_imemo_alloc();
14849#if IBF_ISEQ_DEBUG
14850 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14851#endif
14852 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14853 iseq->aux.loader.obj = load->loader_obj;
14854 iseq->aux.loader.index = iseq_index;
14855#if IBF_ISEQ_DEBUG
14856 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14857 (void *)iseq, (void *)load->loader_obj, iseq_index);
14858#endif
14859 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14860
14861 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14862#if IBF_ISEQ_DEBUG
14863 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14864#endif
14865 rb_ibf_load_iseq_complete(iseq);
14866 }
14867
14868#if IBF_ISEQ_DEBUG
14869 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14870 (void *)iseq, (void *)load->iseq);
14871#endif
14872 return iseq;
14873 }
14874 }
14875}
14876
14877static void
14878ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14879{
14880 struct ibf_header *header = (struct ibf_header *)bytes;
14881 load->loader_obj = loader_obj;
14882 load->global_buffer.buff = bytes;
14883 load->header = header;
14884 load->global_buffer.size = header->size;
14885 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14886 load->global_buffer.obj_list_size = header->global_object_list_size;
14887 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14888 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14889 load->iseq = NULL;
14890
14891 load->current_buffer = &load->global_buffer;
14892
14893 if (size < header->size) {
14894 rb_raise(rb_eRuntimeError, "broken binary format");
14895 }
14896 if (strncmp(header->magic, "YARB", 4) != 0) {
14897 rb_raise(rb_eRuntimeError, "unknown binary format");
14898 }
14899 if (header->major_version != IBF_MAJOR_VERSION ||
14900 header->minor_version != IBF_MINOR_VERSION) {
14901 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14902 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14903 }
14904 if (header->endian != IBF_ENDIAN_MARK) {
14905 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14906 }
14907 if (header->wordsize != SIZEOF_VALUE) {
14908 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14909 }
14910 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14911 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14912 header->iseq_list_offset);
14913 }
14914 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14915 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14916 load->global_buffer.obj_list_offset);
14917 }
14918}
14919
14920static void
14921ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14922{
14923 StringValue(str);
14924
14925 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14926 rb_raise(rb_eRuntimeError, "broken binary format");
14927 }
14928
14929 if (USE_LAZY_LOAD) {
14930 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14931 }
14932
14933 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14934 RB_OBJ_WRITE(loader_obj, &load->str, str);
14935}
14936
14937static void
14938ibf_loader_mark(void *ptr)
14939{
14940 struct ibf_load *load = (struct ibf_load *)ptr;
14941 rb_gc_mark(load->str);
14942 rb_gc_mark(load->iseq_list);
14943 rb_gc_mark(load->global_buffer.obj_list);
14944}
14945
14946static void
14947ibf_loader_free(void *ptr)
14948{
14949 struct ibf_load *load = (struct ibf_load *)ptr;
14950 ruby_xfree(load);
14951}
14952
14953static size_t
14954ibf_loader_memsize(const void *ptr)
14955{
14956 return sizeof(struct ibf_load);
14957}
14958
14959static const rb_data_type_t ibf_load_type = {
14960 "ibf_loader",
14961 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14962 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14963};
14964
14965const rb_iseq_t *
14966rb_iseq_ibf_load(VALUE str)
14967{
14968 struct ibf_load *load;
14969 rb_iseq_t *iseq;
14970 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14971
14972 ibf_load_setup(load, loader_obj, str);
14973 iseq = ibf_load_iseq(load, 0);
14974
14975 RB_GC_GUARD(loader_obj);
14976 return iseq;
14977}
14978
14979const rb_iseq_t *
14980rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14981{
14982 struct ibf_load *load;
14983 rb_iseq_t *iseq;
14984 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14985
14986 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14987 iseq = ibf_load_iseq(load, 0);
14988
14989 RB_GC_GUARD(loader_obj);
14990 return iseq;
14991}
14992
14993VALUE
14994rb_iseq_ibf_load_extra_data(VALUE str)
14995{
14996 struct ibf_load *load;
14997 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14998 VALUE extra_str;
14999
15000 ibf_load_setup(load, loader_obj, str);
15001 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15002 RB_GC_GUARD(loader_obj);
15003 return extra_str;
15004}
15005
15006#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:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1444
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:666
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1445
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1448
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_cHash
Hash class.
Definition hash.c:109
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:923
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1342
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1862
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:69
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:2000
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:3797
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1746
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4160
#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:4146
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3565
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:3763
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4214
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:4034
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3278
#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:285
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:1547
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:649
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:461
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:508
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9059
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:288
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:259
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:208
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:215
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