Ruby 3.5.0dev (2025-07-16 revision 37d088ad24d700db4b59f2c44dee2d202faf122b)
compile.c (37d088ad24d700db4b59f2c44dee2d202faf122b)
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);
497
498static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
499static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
500
501/*
502 * To make Array to LinkedList, use link_anchor
503 */
504
505static void
506verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
507{
508#if CPDEBUG
509 int flag = 0;
510 LINK_ELEMENT *list, *plist;
511
512 if (!compile_debug) return;
513
514 list = anchor->anchor.next;
515 plist = &anchor->anchor;
516 while (list) {
517 if (plist != list->prev) {
518 flag += 1;
519 }
520 plist = list;
521 list = list->next;
522 }
523
524 if (anchor->last != plist && anchor->last != 0) {
525 flag |= 0x70000;
526 }
527
528 if (flag != 0) {
529 rb_bug("list verify error: %08x (%s)", flag, info);
530 }
531#endif
532}
533#if CPDEBUG < 0
534#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
535#endif
536
537static void
538verify_call_cache(rb_iseq_t *iseq)
539{
540#if CPDEBUG
541 VALUE *original = rb_iseq_original_iseq(iseq);
542 size_t i = 0;
543 while (i < ISEQ_BODY(iseq)->iseq_size) {
544 VALUE insn = original[i];
545 const char *types = insn_op_types(insn);
546
547 for (int j=0; types[j]; j++) {
548 if (types[j] == TS_CALLDATA) {
549 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
550 const struct rb_callinfo *ci = cd->ci;
551 const struct rb_callcache *cc = cd->cc;
552 if (cc != vm_cc_empty()) {
553 vm_ci_dump(ci);
554 rb_bug("call cache is not initialized by vm_cc_empty()");
555 }
556 }
557 }
558 i += insn_len(insn);
559 }
560
561 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
562 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
563 const struct rb_callinfo *ci = cd->ci;
564 const struct rb_callcache *cc = cd->cc;
565 if (cc != NULL && cc != vm_cc_empty()) {
566 vm_ci_dump(ci);
567 rb_bug("call cache is not initialized by vm_cc_empty()");
568 }
569 }
570#endif
571}
572
573/*
574 * elem1, elem2 => elem1, elem2, elem
575 */
576static void
577ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
578{
579 elem->prev = anchor->last;
580 anchor->last->next = elem;
581 anchor->last = elem;
582 verify_list("add", anchor);
583}
584
585/*
586 * elem1, before, elem2 => elem1, before, elem, elem2
587 */
588static void
589APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
590{
591 elem->prev = before;
592 elem->next = before->next;
593 elem->next->prev = elem;
594 before->next = elem;
595 if (before == anchor->last) anchor->last = elem;
596 verify_list("add", anchor);
597}
598#if CPDEBUG < 0
599#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
600#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
601#endif
602
603static int
604branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
605{
606 if (!ISEQ_COVERAGE(iseq)) return 0;
607 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
608 if (first_line <= 0) return 0;
609 return 1;
610}
611
612#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
613
614static VALUE
615setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
616{
617 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
618 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
619 VALUE branch = rb_ary_hidden_new(6);
620
621 rb_hash_aset(structure, key, branch);
622 rb_ary_push(branch, ID2SYM(rb_intern(type)));
623 rb_ary_push(branch, INT2FIX(first_lineno));
624 rb_ary_push(branch, INT2FIX(first_column));
625 rb_ary_push(branch, INT2FIX(last_lineno));
626 rb_ary_push(branch, INT2FIX(last_column));
627 return branch;
628}
629
630static VALUE
631decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
632{
633 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
634
635 /*
636 * if !structure[node]
637 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
638 * else
639 * branches = structure[node][5]
640 * end
641 */
642
643 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
644 VALUE branch_base = rb_hash_aref(structure, key);
645 VALUE branches;
646
647 if (NIL_P(branch_base)) {
648 branch_base = setup_branch(loc, type, structure, key);
649 branches = rb_hash_new();
650 rb_obj_hide(branches);
651 rb_ary_push(branch_base, branches);
652 }
653 else {
654 branches = RARRAY_AREF(branch_base, 5);
655 }
656
657 return branches;
658}
659
660static NODE
661generate_dummy_line_node(int lineno, int node_id)
662{
663 NODE dummy = { 0 };
664 nd_set_line(&dummy, lineno);
665 nd_set_node_id(&dummy, node_id);
666 return dummy;
667}
668
669static void
670add_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)
671{
672 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
673
674 /*
675 * if !branches[branch_id]
676 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
677 * else
678 * counter_idx= branches[branch_id][5]
679 * end
680 */
681
682 VALUE key = INT2FIX(branch_id);
683 VALUE branch = rb_hash_aref(branches, key);
684 long counter_idx;
685
686 if (NIL_P(branch)) {
687 branch = setup_branch(loc, type, branches, key);
688 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
689 counter_idx = RARRAY_LEN(counters);
690 rb_ary_push(branch, LONG2FIX(counter_idx));
691 rb_ary_push(counters, INT2FIX(0));
692 }
693 else {
694 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
695 }
696
697 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
698 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
699}
700
701#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
702
703static int
704validate_label(st_data_t name, st_data_t label, st_data_t arg)
705{
706 rb_iseq_t *iseq = (rb_iseq_t *)arg;
707 LABEL *lobj = (LABEL *)label;
708 if (!lobj->link.next) {
709 do {
710 COMPILE_ERROR(iseq, lobj->position,
711 "%"PRIsVALUE": undefined label",
712 rb_sym2str((VALUE)name));
713 } while (0);
714 }
715 return ST_CONTINUE;
716}
717
718static void
719validate_labels(rb_iseq_t *iseq, st_table *labels_table)
720{
721 st_foreach(labels_table, validate_label, (st_data_t)iseq);
722 st_free_table(labels_table);
723}
724
725static NODE *
726get_nd_recv(const NODE *node)
727{
728 switch (nd_type(node)) {
729 case NODE_CALL:
730 return RNODE_CALL(node)->nd_recv;
731 case NODE_OPCALL:
732 return RNODE_OPCALL(node)->nd_recv;
733 case NODE_FCALL:
734 return 0;
735 case NODE_QCALL:
736 return RNODE_QCALL(node)->nd_recv;
737 case NODE_VCALL:
738 return 0;
739 case NODE_ATTRASGN:
740 return RNODE_ATTRASGN(node)->nd_recv;
741 case NODE_OP_ASGN1:
742 return RNODE_OP_ASGN1(node)->nd_recv;
743 case NODE_OP_ASGN2:
744 return RNODE_OP_ASGN2(node)->nd_recv;
745 default:
746 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
747 }
748}
749
750static ID
751get_node_call_nd_mid(const NODE *node)
752{
753 switch (nd_type(node)) {
754 case NODE_CALL:
755 return RNODE_CALL(node)->nd_mid;
756 case NODE_OPCALL:
757 return RNODE_OPCALL(node)->nd_mid;
758 case NODE_FCALL:
759 return RNODE_FCALL(node)->nd_mid;
760 case NODE_QCALL:
761 return RNODE_QCALL(node)->nd_mid;
762 case NODE_VCALL:
763 return RNODE_VCALL(node)->nd_mid;
764 case NODE_ATTRASGN:
765 return RNODE_ATTRASGN(node)->nd_mid;
766 default:
767 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
768 }
769}
770
771static NODE *
772get_nd_args(const NODE *node)
773{
774 switch (nd_type(node)) {
775 case NODE_CALL:
776 return RNODE_CALL(node)->nd_args;
777 case NODE_OPCALL:
778 return RNODE_OPCALL(node)->nd_args;
779 case NODE_FCALL:
780 return RNODE_FCALL(node)->nd_args;
781 case NODE_QCALL:
782 return RNODE_QCALL(node)->nd_args;
783 case NODE_VCALL:
784 return 0;
785 case NODE_ATTRASGN:
786 return RNODE_ATTRASGN(node)->nd_args;
787 default:
788 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
789 }
790}
791
792static ID
793get_node_colon_nd_mid(const NODE *node)
794{
795 switch (nd_type(node)) {
796 case NODE_COLON2:
797 return RNODE_COLON2(node)->nd_mid;
798 case NODE_COLON3:
799 return RNODE_COLON3(node)->nd_mid;
800 default:
801 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
802 }
803}
804
805static ID
806get_nd_vid(const NODE *node)
807{
808 switch (nd_type(node)) {
809 case NODE_LASGN:
810 return RNODE_LASGN(node)->nd_vid;
811 case NODE_DASGN:
812 return RNODE_DASGN(node)->nd_vid;
813 case NODE_IASGN:
814 return RNODE_IASGN(node)->nd_vid;
815 case NODE_CVASGN:
816 return RNODE_CVASGN(node)->nd_vid;
817 default:
818 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
819 }
820}
821
822static NODE *
823get_nd_value(const NODE *node)
824{
825 switch (nd_type(node)) {
826 case NODE_LASGN:
827 return RNODE_LASGN(node)->nd_value;
828 case NODE_DASGN:
829 return RNODE_DASGN(node)->nd_value;
830 default:
831 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
832 }
833}
834
835static VALUE
836get_string_value(const NODE *node)
837{
838 switch (nd_type(node)) {
839 case NODE_STR:
840 return rb_node_str_string_val(node);
841 case NODE_FILE:
842 return rb_node_file_path_val(node);
843 default:
844 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
845 }
846}
847
848VALUE
849rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
850{
851 DECL_ANCHOR(ret);
852 INIT_ANCHOR(ret);
853
854 (*ifunc->func)(iseq, ret, ifunc->data);
855
856 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
857
858 CHECK(iseq_setup_insn(iseq, ret));
859 return iseq_setup(iseq, ret);
860}
861
862static bool drop_unreachable_return(LINK_ANCHOR *ret);
863
864VALUE
865rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
866{
867 DECL_ANCHOR(ret);
868 INIT_ANCHOR(ret);
869
870 if (node == 0) {
871 NO_CHECK(COMPILE(ret, "nil", node));
872 iseq_set_local_table(iseq, 0, 0);
873 }
874 /* assume node is T_NODE */
875 else if (nd_type_p(node, NODE_SCOPE)) {
876 /* iseq type of top, method, class, block */
877 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
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);
1401}
1402
1403static INSN *
1404new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1405{
1406 INSN *iobj = compile_data_alloc_insn(iseq);
1407
1408 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1409
1410 iobj->link.type = ISEQ_ELEMENT_INSN;
1411 iobj->link.next = 0;
1412 iobj->insn_id = insn_id;
1413 iobj->insn_info.line_no = line_no;
1414 iobj->insn_info.node_id = node_id;
1415 iobj->insn_info.events = 0;
1416 iobj->operands = argv;
1417 iobj->operand_size = argc;
1418 iobj->sc_state = 0;
1419
1420 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1421
1422 return iobj;
1423}
1424
1425static INSN *
1426new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1427{
1428 VALUE *operands = 0;
1429 va_list argv;
1430 if (argc > 0) {
1431 int i;
1432 va_start(argv, argc);
1433 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1434 for (i = 0; i < argc; i++) {
1435 VALUE v = va_arg(argv, VALUE);
1436 operands[i] = v;
1437 }
1438 va_end(argv);
1439 }
1440 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1441}
1442
1443static const struct rb_callinfo *
1444new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1445{
1446 VM_ASSERT(argc >= 0);
1447
1448 if (kw_arg) {
1449 flag |= VM_CALL_KWARG;
1450 argc += kw_arg->keyword_len;
1451 }
1452
1453 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1454 && !has_blockiseq) {
1455 flag |= VM_CALL_ARGS_SIMPLE;
1456 }
1457
1458 ISEQ_BODY(iseq)->ci_size++;
1459 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1460 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1461 return ci;
1462}
1463
1464static INSN *
1465new_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)
1466{
1467 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1468 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1469 operands[0] = ci;
1470 operands[1] = (VALUE)blockiseq;
1471 if (blockiseq) {
1472 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1473 }
1474
1475 INSN *insn;
1476
1477 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1478 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1479 }
1480 else {
1481 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1482 }
1483
1484 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1485 RB_GC_GUARD(ci);
1486 return insn;
1487}
1488
1489static rb_iseq_t *
1490new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1491 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1492{
1493 rb_iseq_t *ret_iseq;
1494 VALUE ast_value = rb_ruby_ast_new(node);
1495
1496 debugs("[new_child_iseq]> ---------------------------------------\n");
1497 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1498 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1499 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1500 line_no, parent,
1501 isolated_depth ? isolated_depth + 1 : 0,
1502 type, ISEQ_COMPILE_DATA(iseq)->option,
1503 ISEQ_BODY(iseq)->variable.script_lines);
1504 debugs("[new_child_iseq]< ---------------------------------------\n");
1505 return ret_iseq;
1506}
1507
1508static rb_iseq_t *
1509new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1510 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1511{
1512 rb_iseq_t *ret_iseq;
1513
1514 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1515 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1516 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1517 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1518 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1519 return ret_iseq;
1520}
1521
1522static void
1523set_catch_except_p(rb_iseq_t *iseq)
1524{
1525 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1526 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1527 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1528 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1529 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1530 }
1531 }
1532}
1533
1534/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1535 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1536 if catch table exists. But we want to optimize while loop, which always has catch
1537 table entries for break/next/redo.
1538
1539 So this function sets true for limited ISeqs with break/next/redo catch table entries
1540 whose child ISeq would really raise an exception. */
1541static void
1542update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1543{
1544 unsigned int pos;
1545 size_t i;
1546 int insn;
1547 const struct iseq_catch_table *ct = body->catch_table;
1548
1549 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1550 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1551 pos = 0;
1552 while (pos < body->iseq_size) {
1553 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1554 if (insn == BIN(throw)) {
1555 set_catch_except_p(iseq);
1556 break;
1557 }
1558 pos += insn_len(insn);
1559 }
1560
1561 if (ct == NULL)
1562 return;
1563
1564 for (i = 0; i < ct->size; i++) {
1565 const struct iseq_catch_table_entry *entry =
1566 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1567 if (entry->type != CATCH_TYPE_BREAK
1568 && entry->type != CATCH_TYPE_NEXT
1569 && entry->type != CATCH_TYPE_REDO) {
1570 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1571 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1572 break;
1573 }
1574 }
1575}
1576
1577static void
1578iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1579{
1580 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1581 if (NIL_P(catch_table_ary)) return;
1582 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1583 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1584 for (i = 0; i < tlen; i++) {
1585 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1586 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1587 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1588 LINK_ELEMENT *e;
1589
1590 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1591
1592 if (ct != CATCH_TYPE_BREAK
1593 && ct != CATCH_TYPE_NEXT
1594 && ct != CATCH_TYPE_REDO) {
1595
1596 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1597 if (e == cont) {
1598 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1599 ELEM_INSERT_NEXT(end, &nop->link);
1600 break;
1601 }
1602 }
1603 }
1604 }
1605
1606 RB_GC_GUARD(catch_table_ary);
1607}
1608
1609static int
1610iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1611{
1612 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1613 return COMPILE_NG;
1614
1615 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1616
1617 if (compile_debug > 5)
1618 dump_disasm_list(FIRST_ELEMENT(anchor));
1619
1620 debugs("[compile step 3.1 (iseq_optimize)]\n");
1621 iseq_optimize(iseq, anchor);
1622
1623 if (compile_debug > 5)
1624 dump_disasm_list(FIRST_ELEMENT(anchor));
1625
1626 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1627 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1628 iseq_insns_unification(iseq, anchor);
1629 if (compile_debug > 5)
1630 dump_disasm_list(FIRST_ELEMENT(anchor));
1631 }
1632
1633 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1634 iseq_insert_nop_between_end_and_cont(iseq);
1635 if (compile_debug > 5)
1636 dump_disasm_list(FIRST_ELEMENT(anchor));
1637
1638 return COMPILE_OK;
1639}
1640
1641static int
1642iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1643{
1644 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1645 return COMPILE_NG;
1646
1647 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1648 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1649 if (compile_debug > 5)
1650 dump_disasm_list(FIRST_ELEMENT(anchor));
1651
1652 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1653 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1654
1655 debugs("[compile step 4.3 (set_optargs_table)] \n");
1656 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1657
1658 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1659 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1660
1661 debugs("[compile step 6 (update_catch_except_flags)] \n");
1662 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1663 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1664
1665 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1666 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1667 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1668 xfree(ISEQ_BODY(iseq)->catch_table);
1669 ISEQ_BODY(iseq)->catch_table = NULL;
1670 }
1671
1672#if VM_INSN_INFO_TABLE_IMPL == 2
1673 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1674 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1675 rb_iseq_insns_info_encode_positions(iseq);
1676 }
1677#endif
1678
1679 if (compile_debug > 1) {
1680 VALUE str = rb_iseq_disasm(iseq);
1681 printf("%s\n", StringValueCStr(str));
1682 }
1683 verify_call_cache(iseq);
1684 debugs("[compile step: finish]\n");
1685
1686 return COMPILE_OK;
1687}
1688
1689static int
1690iseq_set_exception_local_table(rb_iseq_t *iseq)
1691{
1692 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1693 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1694 return COMPILE_OK;
1695}
1696
1697static int
1698get_lvar_level(const rb_iseq_t *iseq)
1699{
1700 int lev = 0;
1701 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1702 lev++;
1703 iseq = ISEQ_BODY(iseq)->parent_iseq;
1704 }
1705 return lev;
1706}
1707
1708static int
1709get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1710{
1711 unsigned int i;
1712
1713 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1714 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1715 return (int)i;
1716 }
1717 }
1718 return -1;
1719}
1720
1721static int
1722get_local_var_idx(const rb_iseq_t *iseq, ID id)
1723{
1724 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1725
1726 if (idx < 0) {
1727 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1728 "get_local_var_idx: %d", idx);
1729 }
1730
1731 return idx;
1732}
1733
1734static int
1735get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1736{
1737 int lv = 0, idx = -1;
1738 const rb_iseq_t *const topmost_iseq = iseq;
1739
1740 while (iseq) {
1741 idx = get_dyna_var_idx_at_raw(iseq, id);
1742 if (idx >= 0) {
1743 break;
1744 }
1745 iseq = ISEQ_BODY(iseq)->parent_iseq;
1746 lv++;
1747 }
1748
1749 if (idx < 0) {
1750 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1751 "get_dyna_var_idx: -1");
1752 }
1753
1754 *level = lv;
1755 *ls = ISEQ_BODY(iseq)->local_table_size;
1756 return idx;
1757}
1758
1759static int
1760iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1761{
1762 const struct rb_iseq_constant_body *body;
1763 while (level > 0) {
1764 iseq = ISEQ_BODY(iseq)->parent_iseq;
1765 level--;
1766 }
1767 body = ISEQ_BODY(iseq);
1768 if (body->local_iseq == iseq && /* local variables */
1769 body->param.flags.has_block &&
1770 body->local_table_size - body->param.block_start == idx) {
1771 return TRUE;
1772 }
1773 else {
1774 return FALSE;
1775 }
1776}
1777
1778static int
1779iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1780{
1781 int level, ls;
1782 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1783 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1784 *pidx = ls - idx;
1785 *plevel = level;
1786 return TRUE;
1787 }
1788 else {
1789 return FALSE;
1790 }
1791}
1792
1793static void
1794access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1795{
1796 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1797
1798 if (isolated_depth && level >= isolated_depth) {
1799 if (id == rb_intern("yield")) {
1800 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1801 }
1802 else {
1803 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1804 }
1805 }
1806
1807 for (int i=0; i<level; i++) {
1808 VALUE val;
1809 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1810
1811 if (!ovs) {
1812 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1813 }
1814
1815 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1816 if (write && !val) {
1817 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1818 }
1819 }
1820 else {
1821 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1822 }
1823
1824 iseq = ISEQ_BODY(iseq)->parent_iseq;
1825 }
1826}
1827
1828static ID
1829iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1830{
1831 for (int i=0; i<level; i++) {
1832 iseq = ISEQ_BODY(iseq)->parent_iseq;
1833 }
1834
1835 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1836 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1837 return id;
1838}
1839
1840static void
1841iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1842{
1843 if (iseq_local_block_param_p(iseq, idx, level)) {
1844 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1845 }
1846 else {
1847 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1848 }
1849 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1850}
1851
1852static void
1853iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1854{
1855 if (iseq_local_block_param_p(iseq, idx, level)) {
1856 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1857 }
1858 else {
1859 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1860 }
1861 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1862}
1863
1864
1865
1866static void
1867iseq_calc_param_size(rb_iseq_t *iseq)
1868{
1869 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1870 if (body->param.flags.has_opt ||
1871 body->param.flags.has_post ||
1872 body->param.flags.has_rest ||
1873 body->param.flags.has_block ||
1874 body->param.flags.has_kw ||
1875 body->param.flags.has_kwrest) {
1876
1877 if (body->param.flags.has_block) {
1878 body->param.size = body->param.block_start + 1;
1879 }
1880 else if (body->param.flags.has_kwrest) {
1881 body->param.size = body->param.keyword->rest_start + 1;
1882 }
1883 else if (body->param.flags.has_kw) {
1884 body->param.size = body->param.keyword->bits_start + 1;
1885 }
1886 else if (body->param.flags.has_post) {
1887 body->param.size = body->param.post_start + body->param.post_num;
1888 }
1889 else if (body->param.flags.has_rest) {
1890 body->param.size = body->param.rest_start + 1;
1891 }
1892 else if (body->param.flags.has_opt) {
1893 body->param.size = body->param.lead_num + body->param.opt_num;
1894 }
1895 else {
1897 }
1898 }
1899 else {
1900 body->param.size = body->param.lead_num;
1901 }
1902}
1903
1904static int
1905iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1906 const struct rb_args_info *args, int arg_size)
1907{
1908 const rb_node_kw_arg_t *node = args->kw_args;
1909 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1910 struct rb_iseq_param_keyword *keyword;
1911 const VALUE default_values = rb_ary_hidden_new(1);
1912 const VALUE complex_mark = rb_str_tmp_new(0);
1913 int kw = 0, rkw = 0, di = 0, i;
1914
1915 body->param.flags.has_kw = TRUE;
1916 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1917
1918 while (node) {
1919 kw++;
1920 node = node->nd_next;
1921 }
1922 arg_size += kw;
1923 keyword->bits_start = arg_size++;
1924
1925 node = args->kw_args;
1926 while (node) {
1927 const NODE *val_node = get_nd_value(node->nd_body);
1928 VALUE dv;
1929
1930 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1931 ++rkw;
1932 }
1933 else {
1934 switch (nd_type(val_node)) {
1935 case NODE_SYM:
1936 dv = rb_node_sym_string_val(val_node);
1937 break;
1938 case NODE_REGX:
1939 dv = rb_node_regx_string_val(val_node);
1940 break;
1941 case NODE_LINE:
1942 dv = rb_node_line_lineno_val(val_node);
1943 break;
1944 case NODE_INTEGER:
1945 dv = rb_node_integer_literal_val(val_node);
1946 break;
1947 case NODE_FLOAT:
1948 dv = rb_node_float_literal_val(val_node);
1949 break;
1950 case NODE_RATIONAL:
1951 dv = rb_node_rational_literal_val(val_node);
1952 break;
1953 case NODE_IMAGINARY:
1954 dv = rb_node_imaginary_literal_val(val_node);
1955 break;
1956 case NODE_ENCODING:
1957 dv = rb_node_encoding_val(val_node);
1958 break;
1959 case NODE_NIL:
1960 dv = Qnil;
1961 break;
1962 case NODE_TRUE:
1963 dv = Qtrue;
1964 break;
1965 case NODE_FALSE:
1966 dv = Qfalse;
1967 break;
1968 default:
1969 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1970 dv = complex_mark;
1971 }
1972
1973 keyword->num = ++di;
1974 rb_ary_push(default_values, dv);
1975 }
1976
1977 node = node->nd_next;
1978 }
1979
1980 keyword->num = kw;
1981
1982 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1983 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
1984 keyword->rest_start = arg_size++;
1985 body->param.flags.has_kwrest = TRUE;
1986
1987 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
1988 }
1989 keyword->required_num = rkw;
1990 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1991
1992 if (RARRAY_LEN(default_values)) {
1993 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1994
1995 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1996 VALUE dv = RARRAY_AREF(default_values, i);
1997 if (dv == complex_mark) dv = Qundef;
1998 RB_OBJ_WRITE(iseq, &dvs[i], dv);
1999 }
2000
2001 keyword->default_values = dvs;
2002 }
2003 return arg_size;
2004}
2005
2006static void
2007iseq_set_use_block(rb_iseq_t *iseq)
2008{
2009 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2010 if (!body->param.flags.use_block) {
2011 body->param.flags.use_block = 1;
2012
2013 rb_vm_t *vm = GET_VM();
2014
2015 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2016 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2017 set_insert(vm->unused_block_warning_table, key);
2018 }
2019 }
2020}
2021
2022static int
2023iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2024{
2025 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2026
2027 if (node_args) {
2028 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2029 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2030 ID rest_id = 0;
2031 int last_comma = 0;
2032 ID block_id = 0;
2033 int arg_size;
2034
2035 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2036
2037 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2038 body->param.lead_num = arg_size = (int)args->pre_args_num;
2039 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2040 debugs(" - argc: %d\n", body->param.lead_num);
2041
2042 rest_id = args->rest_arg;
2043 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2044 last_comma = 1;
2045 rest_id = 0;
2046 }
2047 block_id = args->block_arg;
2048
2049 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2050
2051 if (optimized_forward) {
2052 rest_id = 0;
2053 block_id = 0;
2054 }
2055
2056 if (args->opt_args) {
2057 const rb_node_opt_arg_t *node = args->opt_args;
2058 LABEL *label;
2059 VALUE labels = rb_ary_hidden_new(1);
2060 VALUE *opt_table;
2061 int i = 0, j;
2062
2063 while (node) {
2064 label = NEW_LABEL(nd_line(RNODE(node)));
2065 rb_ary_push(labels, (VALUE)label | 1);
2066 ADD_LABEL(optargs, label);
2067 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2068 node = node->nd_next;
2069 i += 1;
2070 }
2071
2072 /* last label */
2073 label = NEW_LABEL(nd_line(node_args));
2074 rb_ary_push(labels, (VALUE)label | 1);
2075 ADD_LABEL(optargs, label);
2076
2077 opt_table = ALLOC_N(VALUE, i+1);
2078
2079 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2080 for (j = 0; j < i+1; j++) {
2081 opt_table[j] &= ~1;
2082 }
2083 rb_ary_clear(labels);
2084
2085 body->param.flags.has_opt = TRUE;
2086 body->param.opt_num = i;
2087 body->param.opt_table = opt_table;
2088 arg_size += i;
2089 }
2090
2091 if (rest_id) {
2092 body->param.rest_start = arg_size++;
2093 body->param.flags.has_rest = TRUE;
2094 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2095 RUBY_ASSERT(body->param.rest_start != -1);
2096 }
2097
2098 if (args->first_post_arg) {
2099 body->param.post_start = arg_size;
2100 body->param.post_num = args->post_args_num;
2101 body->param.flags.has_post = TRUE;
2102 arg_size += args->post_args_num;
2103
2104 if (body->param.flags.has_rest) { /* TODO: why that? */
2105 body->param.post_start = body->param.rest_start + 1;
2106 }
2107 }
2108
2109 if (args->kw_args) {
2110 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2111 }
2112 else if (args->kw_rest_arg && !optimized_forward) {
2113 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2114 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2115 keyword->rest_start = arg_size++;
2116 body->param.keyword = keyword;
2117 body->param.flags.has_kwrest = TRUE;
2118
2119 static ID anon_kwrest = 0;
2120 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2121 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2122 }
2123 else if (args->no_kwarg) {
2124 body->param.flags.accepts_no_kwarg = TRUE;
2125 }
2126
2127 if (block_id) {
2128 body->param.block_start = arg_size++;
2129 body->param.flags.has_block = TRUE;
2130 iseq_set_use_block(iseq);
2131 }
2132
2133 // Only optimize specifically methods like this: `foo(...)`
2134 if (optimized_forward) {
2135 body->param.flags.use_block = 1;
2136 body->param.flags.forwardable = TRUE;
2137 arg_size = 1;
2138 }
2139
2140 iseq_calc_param_size(iseq);
2141 body->param.size = arg_size;
2142
2143 if (args->pre_init) { /* m_init */
2144 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2145 }
2146 if (args->post_init) { /* p_init */
2147 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2148 }
2149
2150 if (body->type == ISEQ_TYPE_BLOCK) {
2151 if (body->param.flags.has_opt == FALSE &&
2152 body->param.flags.has_post == FALSE &&
2153 body->param.flags.has_rest == FALSE &&
2154 body->param.flags.has_kw == FALSE &&
2155 body->param.flags.has_kwrest == FALSE) {
2156
2157 if (body->param.lead_num == 1 && last_comma == 0) {
2158 /* {|a|} */
2159 body->param.flags.ambiguous_param0 = TRUE;
2160 }
2161 }
2162 }
2163 }
2164
2165 return COMPILE_OK;
2166}
2167
2168static int
2169iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2170{
2171 unsigned int size = tbl ? tbl->size : 0;
2172 unsigned int offset = 0;
2173
2174 if (node_args) {
2175 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2176
2177 // If we have a function that only has `...` as the parameter,
2178 // then its local table should only be `...`
2179 // FIXME: I think this should be fixed in the AST rather than special case here.
2180 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2181 CHECK(size >= 3);
2182 size -= 3;
2183 offset += 3;
2184 }
2185 }
2186
2187 if (size > 0) {
2188 ID *ids = ALLOC_N(ID, size);
2189 MEMCPY(ids, tbl->ids + offset, ID, size);
2190 ISEQ_BODY(iseq)->local_table = ids;
2191 }
2192 ISEQ_BODY(iseq)->local_table_size = size;
2193
2194 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2195 return COMPILE_OK;
2196}
2197
2198int
2199rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2200{
2201 int tval, tlit;
2202
2203 if (val == lit) {
2204 return 0;
2205 }
2206 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2207 return val != lit;
2208 }
2209 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2210 return -1;
2211 }
2212 else if (tlit != tval) {
2213 return -1;
2214 }
2215 else if (tlit == T_SYMBOL) {
2216 return val != lit;
2217 }
2218 else if (tlit == T_STRING) {
2219 return rb_str_hash_cmp(lit, val);
2220 }
2221 else if (tlit == T_BIGNUM) {
2222 long x = FIX2LONG(rb_big_cmp(lit, val));
2223
2224 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2225 * There is no need to call rb_fix2int here. */
2226 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2227 return (int)x;
2228 }
2229 else if (tlit == T_FLOAT) {
2230 return rb_float_cmp(lit, val);
2231 }
2232 else if (tlit == T_RATIONAL) {
2233 const struct RRational *rat1 = RRATIONAL(val);
2234 const struct RRational *rat2 = RRATIONAL(lit);
2235 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2236 }
2237 else if (tlit == T_COMPLEX) {
2238 const struct RComplex *comp1 = RCOMPLEX(val);
2239 const struct RComplex *comp2 = RCOMPLEX(lit);
2240 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2241 }
2242 else if (tlit == T_REGEXP) {
2243 return rb_reg_equal(val, lit) ? 0 : -1;
2244 }
2245 else {
2247 }
2248}
2249
2250st_index_t
2251rb_iseq_cdhash_hash(VALUE a)
2252{
2253 switch (OBJ_BUILTIN_TYPE(a)) {
2254 case -1:
2255 case T_SYMBOL:
2256 return (st_index_t)a;
2257 case T_STRING:
2258 return rb_str_hash(a);
2259 case T_BIGNUM:
2260 return FIX2LONG(rb_big_hash(a));
2261 case T_FLOAT:
2262 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2263 case T_RATIONAL:
2264 return rb_rational_hash(a);
2265 case T_COMPLEX:
2266 return rb_complex_hash(a);
2267 case T_REGEXP:
2268 return NUM2LONG(rb_reg_hash(a));
2269 default:
2271 }
2272}
2273
2274static const struct st_hash_type cdhash_type = {
2275 rb_iseq_cdhash_cmp,
2276 rb_iseq_cdhash_hash,
2277};
2278
2280 VALUE hash;
2281 int pos;
2282 int len;
2283};
2284
2285static int
2286cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2287{
2288 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2289 LABEL *lobj = (LABEL *)(val & ~1);
2290 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2291 return ST_CONTINUE;
2292}
2293
2294
2295static inline VALUE
2296get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2297{
2298 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2299}
2300
2301static inline VALUE
2302get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2303{
2304 VALUE val;
2305 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2306 if (tbl) {
2307 if (rb_id_table_lookup(tbl,id,&val)) {
2308 return val;
2309 }
2310 }
2311 else {
2312 tbl = rb_id_table_create(1);
2313 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2314 }
2315 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2316 rb_id_table_insert(tbl,id,val);
2317 return val;
2318}
2319
2320#define BADINSN_DUMP(anchor, list, dest) \
2321 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2322
2323#define BADINSN_ERROR \
2324 (xfree(generated_iseq), \
2325 xfree(insns_info), \
2326 BADINSN_DUMP(anchor, list, NULL), \
2327 COMPILE_ERROR)
2328
2329static int
2330fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2331{
2332 int stack_max = 0, sp = 0, line = 0;
2333 LINK_ELEMENT *list;
2334
2335 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2336 if (IS_LABEL(list)) {
2337 LABEL *lobj = (LABEL *)list;
2338 lobj->set = TRUE;
2339 }
2340 }
2341
2342 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2343 switch (list->type) {
2344 case ISEQ_ELEMENT_INSN:
2345 {
2346 int j, len, insn;
2347 const char *types;
2348 VALUE *operands;
2349 INSN *iobj = (INSN *)list;
2350
2351 /* update sp */
2352 sp = calc_sp_depth(sp, iobj);
2353 if (sp < 0) {
2354 BADINSN_DUMP(anchor, list, NULL);
2355 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2356 "argument stack underflow (%d)", sp);
2357 return -1;
2358 }
2359 if (sp > stack_max) {
2360 stack_max = sp;
2361 }
2362
2363 line = iobj->insn_info.line_no;
2364 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2365 operands = iobj->operands;
2366 insn = iobj->insn_id;
2367 types = insn_op_types(insn);
2368 len = insn_len(insn);
2369
2370 /* operand check */
2371 if (iobj->operand_size != len - 1) {
2372 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2373 BADINSN_DUMP(anchor, list, NULL);
2374 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2375 "operand size miss! (%d for %d)",
2376 iobj->operand_size, len - 1);
2377 return -1;
2378 }
2379
2380 for (j = 0; types[j]; j++) {
2381 if (types[j] == TS_OFFSET) {
2382 /* label(destination position) */
2383 LABEL *lobj = (LABEL *)operands[j];
2384 if (!lobj->set) {
2385 BADINSN_DUMP(anchor, list, NULL);
2386 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2387 "unknown label: "LABEL_FORMAT, lobj->label_no);
2388 return -1;
2389 }
2390 if (lobj->sp == -1) {
2391 lobj->sp = sp;
2392 }
2393 else if (lobj->sp != sp) {
2394 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2395 RSTRING_PTR(rb_iseq_path(iseq)), line,
2396 lobj->label_no, lobj->sp, sp);
2397 }
2398 }
2399 }
2400 break;
2401 }
2402 case ISEQ_ELEMENT_LABEL:
2403 {
2404 LABEL *lobj = (LABEL *)list;
2405 if (lobj->sp == -1) {
2406 lobj->sp = sp;
2407 }
2408 else {
2409 if (lobj->sp != sp) {
2410 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2411 RSTRING_PTR(rb_iseq_path(iseq)), line,
2412 lobj->label_no, lobj->sp, sp);
2413 }
2414 sp = lobj->sp;
2415 }
2416 break;
2417 }
2418 case ISEQ_ELEMENT_TRACE:
2419 {
2420 /* ignore */
2421 break;
2422 }
2423 case ISEQ_ELEMENT_ADJUST:
2424 {
2425 ADJUST *adjust = (ADJUST *)list;
2426 int orig_sp = sp;
2427
2428 sp = adjust->label ? adjust->label->sp : 0;
2429 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2430 BADINSN_DUMP(anchor, list, NULL);
2431 COMPILE_ERROR(iseq, adjust->line_no,
2432 "iseq_set_sequence: adjust bug %d < %d",
2433 orig_sp, sp);
2434 return -1;
2435 }
2436 break;
2437 }
2438 default:
2439 BADINSN_DUMP(anchor, list, NULL);
2440 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2441 return -1;
2442 }
2443 }
2444 return stack_max;
2445}
2446
2447static int
2448add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2449 int insns_info_index, int code_index, const INSN *iobj)
2450{
2451 if (insns_info_index == 0 ||
2452 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2453#ifdef USE_ISEQ_NODE_ID
2454 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2455#endif
2456 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2457 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2458#ifdef USE_ISEQ_NODE_ID
2459 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2460#endif
2461 insns_info[insns_info_index].events = iobj->insn_info.events;
2462 positions[insns_info_index] = code_index;
2463 return TRUE;
2464 }
2465 return FALSE;
2466}
2467
2468static int
2469add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2470 int insns_info_index, int code_index, const ADJUST *adjust)
2471{
2472 insns_info[insns_info_index].line_no = adjust->line_no;
2473 insns_info[insns_info_index].node_id = -1;
2474 insns_info[insns_info_index].events = 0;
2475 positions[insns_info_index] = code_index;
2476 return TRUE;
2477}
2478
2479static ID *
2480array_to_idlist(VALUE arr)
2481{
2483 long size = RARRAY_LEN(arr);
2484 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2485 for (long i = 0; i < size; i++) {
2486 VALUE sym = RARRAY_AREF(arr, i);
2487 ids[i] = SYM2ID(sym);
2488 }
2489 ids[size] = 0;
2490 return ids;
2491}
2492
2493static VALUE
2494idlist_to_array(const ID *ids)
2495{
2496 VALUE arr = rb_ary_new();
2497 while (*ids) {
2498 rb_ary_push(arr, ID2SYM(*ids++));
2499 }
2500 return arr;
2501}
2502
2506static int
2507iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2508{
2509 struct iseq_insn_info_entry *insns_info;
2510 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2511 unsigned int *positions;
2512 LINK_ELEMENT *list;
2513 VALUE *generated_iseq;
2514 rb_event_flag_t events = 0;
2515 long data = 0;
2516
2517 int insn_num, code_index, insns_info_index, sp = 0;
2518 int stack_max = fix_sp_depth(iseq, anchor);
2519
2520 if (stack_max < 0) return COMPILE_NG;
2521
2522 /* fix label position */
2523 insn_num = code_index = 0;
2524 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2525 switch (list->type) {
2526 case ISEQ_ELEMENT_INSN:
2527 {
2528 INSN *iobj = (INSN *)list;
2529 /* update sp */
2530 sp = calc_sp_depth(sp, iobj);
2531 insn_num++;
2532 events = iobj->insn_info.events |= events;
2533 if (ISEQ_COVERAGE(iseq)) {
2534 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2535 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2536 int line = iobj->insn_info.line_no - 1;
2537 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2538 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2539 }
2540 }
2541 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2542 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2543 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2544 }
2545 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2546 }
2547 }
2548 code_index += insn_data_length(iobj);
2549 events = 0;
2550 data = 0;
2551 break;
2552 }
2553 case ISEQ_ELEMENT_LABEL:
2554 {
2555 LABEL *lobj = (LABEL *)list;
2556 lobj->position = code_index;
2557 if (lobj->sp != sp) {
2558 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2559 RSTRING_PTR(rb_iseq_path(iseq)),
2560 lobj->label_no, lobj->sp, sp);
2561 }
2562 sp = lobj->sp;
2563 break;
2564 }
2565 case ISEQ_ELEMENT_TRACE:
2566 {
2567 TRACE *trace = (TRACE *)list;
2568 events |= trace->event;
2569 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2570 break;
2571 }
2572 case ISEQ_ELEMENT_ADJUST:
2573 {
2574 ADJUST *adjust = (ADJUST *)list;
2575 if (adjust->line_no != -1) {
2576 int orig_sp = sp;
2577 sp = adjust->label ? adjust->label->sp : 0;
2578 if (orig_sp - sp > 0) {
2579 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2580 code_index++; /* insn */
2581 insn_num++;
2582 }
2583 }
2584 break;
2585 }
2586 default: break;
2587 }
2588 }
2589
2590 /* make instruction sequence */
2591 generated_iseq = ALLOC_N(VALUE, code_index);
2592 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2593 positions = ALLOC_N(unsigned int, insn_num);
2594 if (ISEQ_IS_SIZE(body)) {
2595 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2596 }
2597 else {
2598 body->is_entries = NULL;
2599 }
2600
2601 if (body->ci_size) {
2602 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2603 }
2604 else {
2605 body->call_data = NULL;
2606 }
2607 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2608
2609 // Calculate the bitmask buffer size.
2610 // Round the generated_iseq size up to the nearest multiple
2611 // of the number of bits in an unsigned long.
2612
2613 // Allocate enough room for the bitmask list
2614 iseq_bits_t * mark_offset_bits;
2615 int code_size = code_index;
2616
2617 bool needs_bitmap = false;
2618
2619 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2620 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2621 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2622 }
2623 else {
2624 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2625 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2626 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2627 }
2628
2629 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2630 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2631
2632 list = FIRST_ELEMENT(anchor);
2633 insns_info_index = code_index = sp = 0;
2634
2635 while (list) {
2636 switch (list->type) {
2637 case ISEQ_ELEMENT_INSN:
2638 {
2639 int j, len, insn;
2640 const char *types;
2641 VALUE *operands;
2642 INSN *iobj = (INSN *)list;
2643
2644 /* update sp */
2645 sp = calc_sp_depth(sp, iobj);
2646 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2647 operands = iobj->operands;
2648 insn = iobj->insn_id;
2649 generated_iseq[code_index] = insn;
2650 types = insn_op_types(insn);
2651 len = insn_len(insn);
2652
2653 for (j = 0; types[j]; j++) {
2654 char type = types[j];
2655
2656 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2657 switch (type) {
2658 case TS_OFFSET:
2659 {
2660 /* label(destination position) */
2661 LABEL *lobj = (LABEL *)operands[j];
2662 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2663 break;
2664 }
2665 case TS_CDHASH:
2666 {
2667 VALUE map = operands[j];
2668 struct cdhash_set_label_struct data;
2669 data.hash = map;
2670 data.pos = code_index;
2671 data.len = len;
2672 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2673
2674 rb_hash_rehash(map);
2675 freeze_hide_obj(map);
2676 generated_iseq[code_index + 1 + j] = map;
2677 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2678 RB_OBJ_WRITTEN(iseq, Qundef, map);
2679 needs_bitmap = true;
2680 break;
2681 }
2682 case TS_LINDEX:
2683 case TS_NUM: /* ulong */
2684 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2685 break;
2686 case TS_ISEQ: /* iseq */
2687 case TS_VALUE: /* VALUE */
2688 {
2689 VALUE v = operands[j];
2690 generated_iseq[code_index + 1 + j] = v;
2691 /* to mark ruby object */
2692 if (!SPECIAL_CONST_P(v)) {
2693 RB_OBJ_WRITTEN(iseq, Qundef, v);
2694 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2695 needs_bitmap = true;
2696 }
2697 break;
2698 }
2699 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2700 case TS_IC: /* inline cache: constants */
2701 {
2702 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2703 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2704 if (UNLIKELY(ic_index >= body->ic_size)) {
2705 BADINSN_DUMP(anchor, &iobj->link, 0);
2706 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2707 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2708 ic_index, ISEQ_IS_SIZE(body));
2709 }
2710
2711 ic->segments = array_to_idlist(operands[j]);
2712
2713 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2714 }
2715 break;
2716 case TS_IVC: /* inline ivar cache */
2717 {
2718 unsigned int ic_index = FIX2UINT(operands[j]);
2719
2720 IVC cache = ((IVC)&body->is_entries[ic_index]);
2721
2722 if (insn == BIN(setinstancevariable)) {
2723 cache->iv_set_name = SYM2ID(operands[j - 1]);
2724 }
2725 else {
2726 cache->iv_set_name = 0;
2727 }
2728
2729 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2730 }
2731 case TS_ISE: /* inline storage entry: `once` insn */
2732 case TS_ICVARC: /* inline cvar cache */
2733 {
2734 unsigned int ic_index = FIX2UINT(operands[j]);
2735 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2736 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2737 BADINSN_DUMP(anchor, &iobj->link, 0);
2738 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2739 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2740 ic_index, ISEQ_IS_SIZE(body));
2741 }
2742 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2743
2744 break;
2745 }
2746 case TS_CALLDATA:
2747 {
2748 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2749 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2750 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2751 cd->ci = source_ci;
2752 cd->cc = vm_cc_empty();
2753 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2754 break;
2755 }
2756 case TS_ID: /* ID */
2757 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2758 break;
2759 case TS_FUNCPTR:
2760 generated_iseq[code_index + 1 + j] = operands[j];
2761 break;
2762 case TS_BUILTIN:
2763 generated_iseq[code_index + 1 + j] = operands[j];
2764 break;
2765 default:
2766 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2767 "unknown operand type: %c", type);
2768 return COMPILE_NG;
2769 }
2770 }
2771 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2772 code_index += len;
2773 break;
2774 }
2775 case ISEQ_ELEMENT_LABEL:
2776 {
2777 LABEL *lobj = (LABEL *)list;
2778 if (lobj->sp != sp) {
2779 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2780 RSTRING_PTR(rb_iseq_path(iseq)),
2781 lobj->label_no, lobj->sp, sp);
2782 }
2783 sp = lobj->sp;
2784 break;
2785 }
2786 case ISEQ_ELEMENT_ADJUST:
2787 {
2788 ADJUST *adjust = (ADJUST *)list;
2789 int orig_sp = sp;
2790
2791 if (adjust->label) {
2792 sp = adjust->label->sp;
2793 }
2794 else {
2795 sp = 0;
2796 }
2797
2798 if (adjust->line_no != -1) {
2799 const int diff = orig_sp - sp;
2800 if (diff > 0) {
2801 if (insns_info_index == 0) {
2802 COMPILE_ERROR(iseq, adjust->line_no,
2803 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2804 }
2805 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2806 }
2807 if (diff > 1) {
2808 generated_iseq[code_index++] = BIN(adjuststack);
2809 generated_iseq[code_index++] = orig_sp - sp;
2810 }
2811 else if (diff == 1) {
2812 generated_iseq[code_index++] = BIN(pop);
2813 }
2814 else if (diff < 0) {
2815 int label_no = adjust->label ? adjust->label->label_no : -1;
2816 xfree(generated_iseq);
2817 xfree(insns_info);
2818 xfree(positions);
2819 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2820 xfree(mark_offset_bits);
2821 }
2822 debug_list(anchor, list);
2823 COMPILE_ERROR(iseq, adjust->line_no,
2824 "iseq_set_sequence: adjust bug to %d %d < %d",
2825 label_no, orig_sp, sp);
2826 return COMPILE_NG;
2827 }
2828 }
2829 break;
2830 }
2831 default:
2832 /* ignore */
2833 break;
2834 }
2835 list = list->next;
2836 }
2837
2838 body->iseq_encoded = (void *)generated_iseq;
2839 body->iseq_size = code_index;
2840 body->stack_max = stack_max;
2841
2842 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2843 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2844 }
2845 else {
2846 if (needs_bitmap) {
2847 body->mark_bits.list = mark_offset_bits;
2848 }
2849 else {
2850 body->mark_bits.list = NULL;
2851 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2852 ruby_xfree(mark_offset_bits);
2853 }
2854 }
2855
2856 /* get rid of memory leak when REALLOC failed */
2857 body->insns_info.body = insns_info;
2858 body->insns_info.positions = positions;
2859
2860 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2861 body->insns_info.body = insns_info;
2862 REALLOC_N(positions, unsigned int, insns_info_index);
2863 body->insns_info.positions = positions;
2864 body->insns_info.size = insns_info_index;
2865
2866 return COMPILE_OK;
2867}
2868
2869static int
2870label_get_position(LABEL *lobj)
2871{
2872 return lobj->position;
2873}
2874
2875static int
2876label_get_sp(LABEL *lobj)
2877{
2878 return lobj->sp;
2879}
2880
2881static int
2882iseq_set_exception_table(rb_iseq_t *iseq)
2883{
2884 const VALUE *tptr, *ptr;
2885 unsigned int tlen, i;
2886 struct iseq_catch_table_entry *entry;
2887
2888 ISEQ_BODY(iseq)->catch_table = NULL;
2889
2890 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2891 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2892 tlen = (int)RARRAY_LEN(catch_table_ary);
2893 tptr = RARRAY_CONST_PTR(catch_table_ary);
2894
2895 if (tlen > 0) {
2896 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2897 table->size = tlen;
2898
2899 for (i = 0; i < table->size; i++) {
2900 int pos;
2901 ptr = RARRAY_CONST_PTR(tptr[i]);
2902 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2903 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2904 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2905 RUBY_ASSERT(pos >= 0);
2906 entry->start = (unsigned int)pos;
2907 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2908 RUBY_ASSERT(pos >= 0);
2909 entry->end = (unsigned int)pos;
2910 entry->iseq = (rb_iseq_t *)ptr[3];
2911 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2912
2913 /* stack depth */
2914 if (ptr[4]) {
2915 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2916 entry->cont = label_get_position(lobj);
2917 entry->sp = label_get_sp(lobj);
2918
2919 /* TODO: Dirty Hack! Fix me */
2920 if (entry->type == CATCH_TYPE_RESCUE ||
2921 entry->type == CATCH_TYPE_BREAK ||
2922 entry->type == CATCH_TYPE_NEXT) {
2923 RUBY_ASSERT(entry->sp > 0);
2924 entry->sp--;
2925 }
2926 }
2927 else {
2928 entry->cont = 0;
2929 }
2930 }
2931 ISEQ_BODY(iseq)->catch_table = table;
2932 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2933 }
2934
2935 RB_GC_GUARD(catch_table_ary);
2936
2937 return COMPILE_OK;
2938}
2939
2940/*
2941 * set optional argument table
2942 * def foo(a, b=expr1, c=expr2)
2943 * =>
2944 * b:
2945 * expr1
2946 * c:
2947 * expr2
2948 */
2949static int
2950iseq_set_optargs_table(rb_iseq_t *iseq)
2951{
2952 int i;
2953 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2954
2955 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2956 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2957 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2958 }
2959 }
2960 return COMPILE_OK;
2961}
2962
2963static LINK_ELEMENT *
2964get_destination_insn(INSN *iobj)
2965{
2966 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2967 LINK_ELEMENT *list;
2968 rb_event_flag_t events = 0;
2969
2970 list = lobj->link.next;
2971 while (list) {
2972 switch (list->type) {
2973 case ISEQ_ELEMENT_INSN:
2974 case ISEQ_ELEMENT_ADJUST:
2975 goto found;
2976 case ISEQ_ELEMENT_LABEL:
2977 /* ignore */
2978 break;
2979 case ISEQ_ELEMENT_TRACE:
2980 {
2981 TRACE *trace = (TRACE *)list;
2982 events |= trace->event;
2983 }
2984 break;
2985 default: break;
2986 }
2987 list = list->next;
2988 }
2989 found:
2990 if (list && IS_INSN(list)) {
2991 INSN *iobj = (INSN *)list;
2992 iobj->insn_info.events |= events;
2993 }
2994 return list;
2995}
2996
2997static LINK_ELEMENT *
2998get_next_insn(INSN *iobj)
2999{
3000 LINK_ELEMENT *list = iobj->link.next;
3001
3002 while (list) {
3003 if (IS_INSN(list) || IS_ADJUST(list)) {
3004 return list;
3005 }
3006 list = list->next;
3007 }
3008 return 0;
3009}
3010
3011static LINK_ELEMENT *
3012get_prev_insn(INSN *iobj)
3013{
3014 LINK_ELEMENT *list = iobj->link.prev;
3015
3016 while (list) {
3017 if (IS_INSN(list) || IS_ADJUST(list)) {
3018 return list;
3019 }
3020 list = list->prev;
3021 }
3022 return 0;
3023}
3024
3025static void
3026unref_destination(INSN *iobj, int pos)
3027{
3028 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3029 --lobj->refcnt;
3030 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3031}
3032
3033static bool
3034replace_destination(INSN *dobj, INSN *nobj)
3035{
3036 VALUE n = OPERAND_AT(nobj, 0);
3037 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3038 LABEL *nl = (LABEL *)n;
3039 if (dl == nl) return false;
3040 --dl->refcnt;
3041 ++nl->refcnt;
3042 OPERAND_AT(dobj, 0) = n;
3043 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3044 return true;
3045}
3046
3047static LABEL*
3048find_destination(INSN *i)
3049{
3050 int pos, len = insn_len(i->insn_id);
3051 for (pos = 0; pos < len; ++pos) {
3052 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3053 return (LABEL *)OPERAND_AT(i, pos);
3054 }
3055 }
3056 return 0;
3057}
3058
3059static int
3060remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3061{
3062 LINK_ELEMENT *first = i, *end;
3063 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3064
3065 if (!i) return 0;
3066 unref_counts = ALLOCA_N(int, nlabels);
3067 MEMZERO(unref_counts, int, nlabels);
3068 end = i;
3069 do {
3070 LABEL *lab;
3071 if (IS_INSN(i)) {
3072 if (IS_INSN_ID(i, leave)) {
3073 end = i;
3074 break;
3075 }
3076 else if ((lab = find_destination((INSN *)i)) != 0) {
3077 unref_counts[lab->label_no]++;
3078 }
3079 }
3080 else if (IS_LABEL(i)) {
3081 lab = (LABEL *)i;
3082 if (lab->unremovable) return 0;
3083 if (lab->refcnt > unref_counts[lab->label_no]) {
3084 if (i == first) return 0;
3085 break;
3086 }
3087 continue;
3088 }
3089 else if (IS_TRACE(i)) {
3090 /* do nothing */
3091 }
3092 else if (IS_ADJUST(i)) {
3093 return 0;
3094 }
3095 end = i;
3096 } while ((i = i->next) != 0);
3097 i = first;
3098 do {
3099 if (IS_INSN(i)) {
3100 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3101 VALUE insn = INSN_OF(i);
3102 int pos, len = insn_len(insn);
3103 for (pos = 0; pos < len; ++pos) {
3104 switch (insn_op_types(insn)[pos]) {
3105 case TS_OFFSET:
3106 unref_destination((INSN *)i, pos);
3107 break;
3108 case TS_CALLDATA:
3109 --(body->ci_size);
3110 break;
3111 }
3112 }
3113 }
3114 ELEM_REMOVE(i);
3115 } while ((i != end) && (i = i->next) != 0);
3116 return 1;
3117}
3118
3119static int
3120iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3121{
3122 switch (OPERAND_AT(iobj, 0)) {
3123 case INT2FIX(0): /* empty array */
3124 ELEM_REMOVE(&iobj->link);
3125 return TRUE;
3126 case INT2FIX(1): /* single element array */
3127 ELEM_REMOVE(&iobj->link);
3128 return FALSE;
3129 default:
3130 iobj->insn_id = BIN(adjuststack);
3131 return TRUE;
3132 }
3133}
3134
3135static int
3136is_frozen_putstring(INSN *insn, VALUE *op)
3137{
3138 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3139 *op = OPERAND_AT(insn, 0);
3140 return 1;
3141 }
3142 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3143 *op = OPERAND_AT(insn, 0);
3144 return RB_TYPE_P(*op, T_STRING);
3145 }
3146 return 0;
3147}
3148
3149static int
3150optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3151{
3152 /*
3153 * putobject obj
3154 * dup
3155 * checktype T_XXX
3156 * branchif l1
3157 * l2:
3158 * ...
3159 * l1:
3160 *
3161 * => obj is a T_XXX
3162 *
3163 * putobject obj (T_XXX)
3164 * jump L1
3165 * L1:
3166 *
3167 * => obj is not a T_XXX
3168 *
3169 * putobject obj (T_XXX)
3170 * jump L2
3171 * L2:
3172 */
3173 int line, node_id;
3174 INSN *niobj, *ciobj, *dup = 0;
3175 LABEL *dest = 0;
3176 VALUE type;
3177
3178 switch (INSN_OF(iobj)) {
3179 case BIN(putstring):
3180 case BIN(putchilledstring):
3182 break;
3183 case BIN(putnil):
3184 type = INT2FIX(T_NIL);
3185 break;
3186 case BIN(putobject):
3187 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3188 break;
3189 default: return FALSE;
3190 }
3191
3192 ciobj = (INSN *)get_next_insn(iobj);
3193 if (IS_INSN_ID(ciobj, jump)) {
3194 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3195 }
3196 if (IS_INSN_ID(ciobj, dup)) {
3197 ciobj = (INSN *)get_next_insn(dup = ciobj);
3198 }
3199 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3200 niobj = (INSN *)get_next_insn(ciobj);
3201 if (!niobj) {
3202 /* TODO: putobject true/false */
3203 return FALSE;
3204 }
3205 switch (INSN_OF(niobj)) {
3206 case BIN(branchif):
3207 if (OPERAND_AT(ciobj, 0) == type) {
3208 dest = (LABEL *)OPERAND_AT(niobj, 0);
3209 }
3210 break;
3211 case BIN(branchunless):
3212 if (OPERAND_AT(ciobj, 0) != type) {
3213 dest = (LABEL *)OPERAND_AT(niobj, 0);
3214 }
3215 break;
3216 default:
3217 return FALSE;
3218 }
3219 line = ciobj->insn_info.line_no;
3220 node_id = ciobj->insn_info.node_id;
3221 if (!dest) {
3222 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3223 dest = (LABEL *)niobj->link.next; /* reuse label */
3224 }
3225 else {
3226 dest = NEW_LABEL(line);
3227 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3228 }
3229 }
3230 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3231 LABEL_REF(dest);
3232 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3233 return TRUE;
3234}
3235
3236static const struct rb_callinfo *
3237ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3238{
3239 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3240 vm_ci_flag(ci) | add,
3241 vm_ci_argc(ci),
3242 vm_ci_kwarg(ci));
3243 RB_OBJ_WRITTEN(iseq, ci, nci);
3244 return nci;
3245}
3246
3247static const struct rb_callinfo *
3248ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3249{
3250 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3251 vm_ci_flag(ci),
3252 argc,
3253 vm_ci_kwarg(ci));
3254 RB_OBJ_WRITTEN(iseq, ci, nci);
3255 return nci;
3256}
3257
3258#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3259
3260static int
3261iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3262{
3263 INSN *const iobj = (INSN *)list;
3264
3265 again:
3266 optimize_checktype(iseq, iobj);
3267
3268 if (IS_INSN_ID(iobj, jump)) {
3269 INSN *niobj, *diobj, *piobj;
3270 diobj = (INSN *)get_destination_insn(iobj);
3271 niobj = (INSN *)get_next_insn(iobj);
3272
3273 if (diobj == niobj) {
3274 /*
3275 * jump LABEL
3276 * LABEL:
3277 * =>
3278 * LABEL:
3279 */
3280 unref_destination(iobj, 0);
3281 ELEM_REMOVE(&iobj->link);
3282 return COMPILE_OK;
3283 }
3284 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3285 IS_INSN_ID(diobj, jump) &&
3286 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3287 diobj->insn_info.events == 0) {
3288 /*
3289 * useless jump elimination:
3290 * jump LABEL1
3291 * ...
3292 * LABEL1:
3293 * jump LABEL2
3294 *
3295 * => in this case, first jump instruction should jump to
3296 * LABEL2 directly
3297 */
3298 if (replace_destination(iobj, diobj)) {
3299 remove_unreachable_chunk(iseq, iobj->link.next);
3300 goto again;
3301 }
3302 }
3303 else if (IS_INSN_ID(diobj, leave)) {
3304 /*
3305 * jump LABEL
3306 * ...
3307 * LABEL:
3308 * leave
3309 * =>
3310 * leave
3311 * ...
3312 * LABEL:
3313 * leave
3314 */
3315 /* replace */
3316 unref_destination(iobj, 0);
3317 iobj->insn_id = BIN(leave);
3318 iobj->operand_size = 0;
3319 iobj->insn_info = diobj->insn_info;
3320 goto again;
3321 }
3322 else if (IS_INSN(iobj->link.prev) &&
3323 (piobj = (INSN *)iobj->link.prev) &&
3324 (IS_INSN_ID(piobj, branchif) ||
3325 IS_INSN_ID(piobj, branchunless))) {
3326 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3327 if (niobj == pdiobj) {
3328 int refcnt = IS_LABEL(piobj->link.next) ?
3329 ((LABEL *)piobj->link.next)->refcnt : 0;
3330 /*
3331 * useless jump elimination (if/unless destination):
3332 * if L1
3333 * jump L2
3334 * L1:
3335 * ...
3336 * L2:
3337 *
3338 * ==>
3339 * unless L2
3340 * L1:
3341 * ...
3342 * L2:
3343 */
3344 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3345 ? BIN(branchunless) : BIN(branchif);
3346 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3347 ELEM_REMOVE(&iobj->link);
3348 }
3349 else {
3350 /* TODO: replace other branch destinations too */
3351 }
3352 return COMPILE_OK;
3353 }
3354 else if (diobj == pdiobj) {
3355 /*
3356 * useless jump elimination (if/unless before jump):
3357 * L1:
3358 * ...
3359 * if L1
3360 * jump L1
3361 *
3362 * ==>
3363 * L1:
3364 * ...
3365 * pop
3366 * jump L1
3367 */
3368 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3369 ELEM_REPLACE(&piobj->link, &popiobj->link);
3370 }
3371 }
3372 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3373 goto again;
3374 }
3375 }
3376
3377 /*
3378 * putstring "beg"
3379 * putstring "end"
3380 * newrange excl
3381 *
3382 * ==>
3383 *
3384 * putobject "beg".."end"
3385 */
3386 if (IS_INSN_ID(iobj, newrange)) {
3387 INSN *const range = iobj;
3388 INSN *beg, *end;
3389 VALUE str_beg, str_end;
3390
3391 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3392 is_frozen_putstring(end, &str_end) &&
3393 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3394 is_frozen_putstring(beg, &str_beg)) {
3395 int excl = FIX2INT(OPERAND_AT(range, 0));
3396 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3397
3398 ELEM_REMOVE(&beg->link);
3399 ELEM_REMOVE(&end->link);
3400 range->insn_id = BIN(putobject);
3401 OPERAND_AT(range, 0) = lit_range;
3402 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3403 }
3404 }
3405
3406 if (IS_INSN_ID(iobj, leave)) {
3407 remove_unreachable_chunk(iseq, iobj->link.next);
3408 }
3409
3410 /*
3411 * ...
3412 * duparray [...]
3413 * concatarray | concattoarray
3414 * =>
3415 * ...
3416 * putobject [...]
3417 * concatarray | concattoarray
3418 */
3419 if (IS_INSN_ID(iobj, duparray)) {
3420 LINK_ELEMENT *next = iobj->link.next;
3421 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3422 iobj->insn_id = BIN(putobject);
3423 }
3424 }
3425
3426 /*
3427 * duparray [...]
3428 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3429 * =>
3430 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3431 */
3432 if (IS_INSN_ID(iobj, duparray)) {
3433 LINK_ELEMENT *next = iobj->link.next;
3434 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3435 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3436 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3437
3438 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3439 VALUE ary = iobj->operands[0];
3441
3442 iobj->insn_id = BIN(opt_ary_freeze);
3443 iobj->operand_size = 2;
3444 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3445 iobj->operands[0] = ary;
3446 iobj->operands[1] = (VALUE)ci;
3447 ELEM_REMOVE(next);
3448 }
3449 }
3450 }
3451
3452 /*
3453 * duphash {...}
3454 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3455 * =>
3456 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3457 */
3458 if (IS_INSN_ID(iobj, duphash)) {
3459 LINK_ELEMENT *next = iobj->link.next;
3460 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3461 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3462 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3463
3464 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3465 VALUE hash = iobj->operands[0];
3466 rb_obj_reveal(hash, rb_cHash);
3467
3468 iobj->insn_id = BIN(opt_hash_freeze);
3469 iobj->operand_size = 2;
3470 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3471 iobj->operands[0] = hash;
3472 iobj->operands[1] = (VALUE)ci;
3473 ELEM_REMOVE(next);
3474 }
3475 }
3476 }
3477
3478 /*
3479 * newarray 0
3480 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3481 * =>
3482 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3483 */
3484 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3485 LINK_ELEMENT *next = iobj->link.next;
3486 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3487 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3488 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3489
3490 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3491 iobj->insn_id = BIN(opt_ary_freeze);
3492 iobj->operand_size = 2;
3493 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3494 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cArray_empty_frozen);
3495 iobj->operands[1] = (VALUE)ci;
3496 ELEM_REMOVE(next);
3497 }
3498 }
3499 }
3500
3501 /*
3502 * newhash 0
3503 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3504 * =>
3505 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3506 */
3507 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3508 LINK_ELEMENT *next = iobj->link.next;
3509 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3510 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3511 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3512
3513 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3514 iobj->insn_id = BIN(opt_hash_freeze);
3515 iobj->operand_size = 2;
3516 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3517 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cHash_empty_frozen);
3518 iobj->operands[1] = (VALUE)ci;
3519 ELEM_REMOVE(next);
3520 }
3521 }
3522 }
3523
3524 if (IS_INSN_ID(iobj, branchif) ||
3525 IS_INSN_ID(iobj, branchnil) ||
3526 IS_INSN_ID(iobj, branchunless)) {
3527 /*
3528 * if L1
3529 * ...
3530 * L1:
3531 * jump L2
3532 * =>
3533 * if L2
3534 */
3535 INSN *nobj = (INSN *)get_destination_insn(iobj);
3536
3537 /* This is super nasty hack!!!
3538 *
3539 * This jump-jump optimization may ignore event flags of the jump
3540 * instruction being skipped. Actually, Line 2 TracePoint event
3541 * is never fired in the following code:
3542 *
3543 * 1: raise if 1 == 2
3544 * 2: while true
3545 * 3: break
3546 * 4: end
3547 *
3548 * This is critical for coverage measurement. [Bug #15980]
3549 *
3550 * This is a stopgap measure: stop the jump-jump optimization if
3551 * coverage measurement is enabled and if the skipped instruction
3552 * has any event flag.
3553 *
3554 * Note that, still, TracePoint Line event does not occur on Line 2.
3555 * This should be fixed in future.
3556 */
3557 int stop_optimization =
3558 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3559 nobj->link.type == ISEQ_ELEMENT_INSN &&
3560 nobj->insn_info.events;
3561 if (!stop_optimization) {
3562 INSN *pobj = (INSN *)iobj->link.prev;
3563 int prev_dup = 0;
3564 if (pobj) {
3565 if (!IS_INSN(&pobj->link))
3566 pobj = 0;
3567 else if (IS_INSN_ID(pobj, dup))
3568 prev_dup = 1;
3569 }
3570
3571 for (;;) {
3572 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3573 if (!replace_destination(iobj, nobj)) break;
3574 }
3575 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3576 !!(nobj = (INSN *)nobj->link.next) &&
3577 /* basic blocks, with no labels in the middle */
3578 nobj->insn_id == iobj->insn_id) {
3579 /*
3580 * dup
3581 * if L1
3582 * ...
3583 * L1:
3584 * dup
3585 * if L2
3586 * =>
3587 * dup
3588 * if L2
3589 * ...
3590 * L1:
3591 * dup
3592 * if L2
3593 */
3594 if (!replace_destination(iobj, nobj)) break;
3595 }
3596 else if (pobj) {
3597 /*
3598 * putnil
3599 * if L1
3600 * =>
3601 * # nothing
3602 *
3603 * putobject true
3604 * if L1
3605 * =>
3606 * jump L1
3607 *
3608 * putstring ".."
3609 * if L1
3610 * =>
3611 * jump L1
3612 *
3613 * putstring ".."
3614 * dup
3615 * if L1
3616 * =>
3617 * putstring ".."
3618 * jump L1
3619 *
3620 */
3621 int cond;
3622 if (prev_dup && IS_INSN(pobj->link.prev)) {
3623 pobj = (INSN *)pobj->link.prev;
3624 }
3625 if (IS_INSN_ID(pobj, putobject)) {
3626 cond = (IS_INSN_ID(iobj, branchif) ?
3627 OPERAND_AT(pobj, 0) != Qfalse :
3628 IS_INSN_ID(iobj, branchunless) ?
3629 OPERAND_AT(pobj, 0) == Qfalse :
3630 FALSE);
3631 }
3632 else if (IS_INSN_ID(pobj, putstring) ||
3633 IS_INSN_ID(pobj, duparray) ||
3634 IS_INSN_ID(pobj, newarray)) {
3635 cond = IS_INSN_ID(iobj, branchif);
3636 }
3637 else if (IS_INSN_ID(pobj, putnil)) {
3638 cond = !IS_INSN_ID(iobj, branchif);
3639 }
3640 else break;
3641 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3642 ELEM_REMOVE(iobj->link.prev);
3643 }
3644 else if (!iseq_pop_newarray(iseq, pobj)) {
3645 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3646 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3647 }
3648 if (cond) {
3649 if (prev_dup) {
3650 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3651 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3652 }
3653 iobj->insn_id = BIN(jump);
3654 goto again;
3655 }
3656 else {
3657 unref_destination(iobj, 0);
3658 ELEM_REMOVE(&iobj->link);
3659 }
3660 break;
3661 }
3662 else break;
3663 nobj = (INSN *)get_destination_insn(nobj);
3664 }
3665 }
3666 }
3667
3668 if (IS_INSN_ID(iobj, pop)) {
3669 /*
3670 * putself / putnil / putobject obj / putstring "..."
3671 * pop
3672 * =>
3673 * # do nothing
3674 */
3675 LINK_ELEMENT *prev = iobj->link.prev;
3676 if (IS_INSN(prev)) {
3677 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3678 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3679 previ == BIN(putself) || previ == BIN(putstring) ||
3680 previ == BIN(putchilledstring) ||
3681 previ == BIN(dup) ||
3682 previ == BIN(getlocal) ||
3683 previ == BIN(getblockparam) ||
3684 previ == BIN(getblockparamproxy) ||
3685 previ == BIN(getinstancevariable) ||
3686 previ == BIN(duparray)) {
3687 /* just push operand or static value and pop soon, no
3688 * side effects */
3689 ELEM_REMOVE(prev);
3690 ELEM_REMOVE(&iobj->link);
3691 }
3692 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3693 ELEM_REMOVE(&iobj->link);
3694 }
3695 else if (previ == BIN(concatarray)) {
3696 INSN *piobj = (INSN *)prev;
3697 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3698 INSN_OF(piobj) = BIN(pop);
3699 }
3700 else if (previ == BIN(concatstrings)) {
3701 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3702 ELEM_REMOVE(prev);
3703 }
3704 else {
3705 ELEM_REMOVE(&iobj->link);
3706 INSN_OF(prev) = BIN(adjuststack);
3707 }
3708 }
3709 }
3710 }
3711
3712 if (IS_INSN_ID(iobj, newarray) ||
3713 IS_INSN_ID(iobj, duparray) ||
3714 IS_INSN_ID(iobj, concatarray) ||
3715 IS_INSN_ID(iobj, splatarray) ||
3716 0) {
3717 /*
3718 * newarray N
3719 * splatarray
3720 * =>
3721 * newarray N
3722 * newarray always puts an array
3723 */
3724 LINK_ELEMENT *next = iobj->link.next;
3725 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3726 /* remove splatarray following always-array insn */
3727 ELEM_REMOVE(next);
3728 }
3729 }
3730
3731 if (IS_INSN_ID(iobj, newarray)) {
3732 LINK_ELEMENT *next = iobj->link.next;
3733 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3734 OPERAND_AT(next, 1) == INT2FIX(0)) {
3735 VALUE op1, op2;
3736 op1 = OPERAND_AT(iobj, 0);
3737 op2 = OPERAND_AT(next, 0);
3738 ELEM_REMOVE(next);
3739
3740 if (op1 == op2) {
3741 /*
3742 * newarray 2
3743 * expandarray 2, 0
3744 * =>
3745 * swap
3746 */
3747 if (op1 == INT2FIX(2)) {
3748 INSN_OF(iobj) = BIN(swap);
3749 iobj->operand_size = 0;
3750 }
3751 /*
3752 * newarray X
3753 * expandarray X, 0
3754 * =>
3755 * opt_reverse X
3756 */
3757 else {
3758 INSN_OF(iobj) = BIN(opt_reverse);
3759 }
3760 }
3761 else {
3762 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3763 INSN_OF(iobj) = BIN(opt_reverse);
3764 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3765
3766 if (op1 > op2) {
3767 /* X > Y
3768 * newarray X
3769 * expandarray Y, 0
3770 * =>
3771 * pop * (Y-X)
3772 * opt_reverse Y
3773 */
3774 for (; diff > 0; diff--) {
3775 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3776 }
3777 }
3778 else { /* (op1 < op2) */
3779 /* X < Y
3780 * newarray X
3781 * expandarray Y, 0
3782 * =>
3783 * putnil * (Y-X)
3784 * opt_reverse Y
3785 */
3786 for (; diff < 0; diff++) {
3787 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3788 }
3789 }
3790 }
3791 }
3792 }
3793
3794 if (IS_INSN_ID(iobj, duparray)) {
3795 LINK_ELEMENT *next = iobj->link.next;
3796 /*
3797 * duparray obj
3798 * expandarray X, 0
3799 * =>
3800 * putobject obj
3801 * expandarray X, 0
3802 */
3803 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3804 INSN_OF(iobj) = BIN(putobject);
3805 }
3806 }
3807
3808 if (IS_INSN_ID(iobj, anytostring)) {
3809 LINK_ELEMENT *next = iobj->link.next;
3810 /*
3811 * anytostring
3812 * concatstrings 1
3813 * =>
3814 * anytostring
3815 */
3816 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3817 OPERAND_AT(next, 0) == INT2FIX(1)) {
3818 ELEM_REMOVE(next);
3819 }
3820 }
3821
3822 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3823 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3824 /*
3825 * putstring ""
3826 * concatstrings N
3827 * =>
3828 * concatstrings N-1
3829 */
3830 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3831 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3832 INSN *next = (INSN *)iobj->link.next;
3833 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3834 ELEM_REMOVE(&next->link);
3835 }
3836 ELEM_REMOVE(&iobj->link);
3837 }
3838 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3839 INSN *next = (INSN *)iobj->link.next;
3840 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3841 VALUE src = OPERAND_AT(iobj, 0);
3842 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3843 VALUE path = rb_iseq_path(iseq);
3844 int line = iobj->insn_info.line_no;
3845 VALUE errinfo = rb_errinfo();
3846 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3847 if (NIL_P(re)) {
3848 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3849 rb_set_errinfo(errinfo);
3850 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3851 }
3852 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3853 ELEM_REMOVE(iobj->link.next);
3854 }
3855 }
3856 }
3857
3858 if (IS_INSN_ID(iobj, concatstrings)) {
3859 /*
3860 * concatstrings N
3861 * concatstrings M
3862 * =>
3863 * concatstrings N+M-1
3864 */
3865 LINK_ELEMENT *next = iobj->link.next;
3866 INSN *jump = 0;
3867 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3868 next = get_destination_insn(jump = (INSN *)next);
3869 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3870 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3871 OPERAND_AT(iobj, 0) = INT2FIX(n);
3872 if (jump) {
3873 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3874 if (!--label->refcnt) {
3875 ELEM_REMOVE(&label->link);
3876 }
3877 else {
3878 label = NEW_LABEL(0);
3879 OPERAND_AT(jump, 0) = (VALUE)label;
3880 }
3881 label->refcnt++;
3882 ELEM_INSERT_NEXT(next, &label->link);
3883 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3884 }
3885 else {
3886 ELEM_REMOVE(next);
3887 }
3888 }
3889 }
3890
3891 if (do_tailcallopt &&
3892 (IS_INSN_ID(iobj, send) ||
3893 IS_INSN_ID(iobj, opt_aref_with) ||
3894 IS_INSN_ID(iobj, opt_aset_with) ||
3895 IS_INSN_ID(iobj, invokesuper))) {
3896 /*
3897 * send ...
3898 * leave
3899 * =>
3900 * send ..., ... | VM_CALL_TAILCALL, ...
3901 * leave # unreachable
3902 */
3903 INSN *piobj = NULL;
3904 if (iobj->link.next) {
3905 LINK_ELEMENT *next = iobj->link.next;
3906 do {
3907 if (!IS_INSN(next)) {
3908 next = next->next;
3909 continue;
3910 }
3911 switch (INSN_OF(next)) {
3912 case BIN(nop):
3913 next = next->next;
3914 break;
3915 case BIN(jump):
3916 /* if cond
3917 * return tailcall
3918 * end
3919 */
3920 next = get_destination_insn((INSN *)next);
3921 break;
3922 case BIN(leave):
3923 piobj = iobj;
3924 /* fall through */
3925 default:
3926 next = NULL;
3927 break;
3928 }
3929 } while (next);
3930 }
3931
3932 if (piobj) {
3933 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3934 if (IS_INSN_ID(piobj, send) ||
3935 IS_INSN_ID(piobj, invokesuper)) {
3936 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3937 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3938 OPERAND_AT(piobj, 0) = (VALUE)ci;
3939 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3940 }
3941 }
3942 else {
3943 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3944 OPERAND_AT(piobj, 0) = (VALUE)ci;
3945 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3946 }
3947 }
3948 }
3949
3950 if (IS_INSN_ID(iobj, dup)) {
3951 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3952 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3953
3954 /*
3955 * dup
3956 * setlocal x, y
3957 * setlocal x, y
3958 * =>
3959 * dup
3960 * setlocal x, y
3961 */
3962 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3963 set2 = set1->next;
3964 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3965 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3966 ELEM_REMOVE(set1);
3967 ELEM_REMOVE(&iobj->link);
3968 }
3969 }
3970
3971 /*
3972 * dup
3973 * setlocal x, y
3974 * dup
3975 * setlocal x, y
3976 * =>
3977 * dup
3978 * setlocal x, y
3979 */
3980 else if (IS_NEXT_INSN_ID(set1, dup) &&
3981 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3982 set2 = set1->next->next;
3983 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3984 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3985 ELEM_REMOVE(set1->next);
3986 ELEM_REMOVE(set2);
3987 }
3988 }
3989 }
3990 }
3991
3992 /*
3993 * getlocal x, y
3994 * dup
3995 * setlocal x, y
3996 * =>
3997 * dup
3998 */
3999 if (IS_INSN_ID(iobj, getlocal)) {
4000 LINK_ELEMENT *niobj = &iobj->link;
4001 if (IS_NEXT_INSN_ID(niobj, dup)) {
4002 niobj = niobj->next;
4003 }
4004 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4005 LINK_ELEMENT *set1 = niobj->next;
4006 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4007 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4008 ELEM_REMOVE(set1);
4009 ELEM_REMOVE(niobj);
4010 }
4011 }
4012 }
4013
4014 /*
4015 * opt_invokebuiltin_delegate
4016 * trace
4017 * leave
4018 * =>
4019 * opt_invokebuiltin_delegate_leave
4020 * trace
4021 * leave
4022 */
4023 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4024 if (IS_TRACE(iobj->link.next)) {
4025 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4026 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4027 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4028 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4029 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4030 }
4031 }
4032 }
4033 }
4034
4035 /*
4036 * getblockparam
4037 * branchif / branchunless
4038 * =>
4039 * getblockparamproxy
4040 * branchif / branchunless
4041 */
4042 if (IS_INSN_ID(iobj, getblockparam)) {
4043 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4044 iobj->insn_id = BIN(getblockparamproxy);
4045 }
4046 }
4047
4048 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4049 LINK_ELEMENT *niobj = &iobj->link;
4050 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4051 niobj = niobj->next;
4052 LINK_ELEMENT *siobj;
4053 unsigned int set_flags = 0, unset_flags = 0;
4054
4055 /*
4056 * Eliminate hash allocation for f(*a, kw: 1)
4057 *
4058 * splatarray false
4059 * duphash
4060 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4061 * =>
4062 * splatarray false
4063 * putobject
4064 * send ARGS_SPLAT|KW_SPLAT
4065 */
4066 if (IS_NEXT_INSN_ID(niobj, send)) {
4067 siobj = niobj->next;
4068 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4069 unset_flags = VM_CALL_ARGS_BLOCKARG;
4070 }
4071 /*
4072 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4073 *
4074 * splatarray false
4075 * duphash
4076 * getlocal / getinstancevariable / getblockparamproxy
4077 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4078 * =>
4079 * splatarray false
4080 * putobject
4081 * getlocal / getinstancevariable / getblockparamproxy
4082 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4083 */
4084 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4085 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4086 siobj = niobj->next->next;
4087 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4088 }
4089
4090 if (set_flags) {
4091 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4092 unsigned int flags = vm_ci_flag(ci);
4093 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4094 ((INSN*)niobj)->insn_id = BIN(putobject);
4095 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4096
4097 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4098 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4099 RB_OBJ_WRITTEN(iseq, ci, nci);
4100 OPERAND_AT(siobj, 0) = (VALUE)nci;
4101 }
4102 }
4103 }
4104 }
4105
4106 return COMPILE_OK;
4107}
4108
4109static int
4110insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4111{
4112 iobj->insn_id = insn_id;
4113 iobj->operand_size = insn_len(insn_id) - 1;
4114 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4115
4116 if (insn_id == BIN(opt_neq)) {
4117 VALUE original_ci = iobj->operands[0];
4118 iobj->operand_size = 2;
4119 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4120 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4121 iobj->operands[1] = original_ci;
4122 }
4123
4124 return COMPILE_OK;
4125}
4126
4127static int
4128iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4129{
4130 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4131 IS_INSN(iobj->link.next)) {
4132 /*
4133 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4134 */
4135 INSN *niobj = (INSN *)iobj->link.next;
4136 if (IS_INSN_ID(niobj, send)) {
4137 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4138 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4139 VALUE method = INT2FIX(0);
4140 switch (vm_ci_mid(ci)) {
4141 case idMax:
4142 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4143 break;
4144 case idMin:
4145 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4146 break;
4147 case idHash:
4148 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4149 break;
4150 }
4151
4152 if (method != INT2FIX(0)) {
4153 VALUE num = iobj->operands[0];
4154 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4155 iobj->insn_id = BIN(opt_newarray_send);
4156 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4157 iobj->operands[0] = num;
4158 iobj->operands[1] = method;
4159 iobj->operand_size = operand_len;
4160 ELEM_REMOVE(&niobj->link);
4161 return COMPILE_OK;
4162 }
4163 }
4164 }
4165 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4166 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4167 IS_NEXT_INSN_ID(&niobj->link, send)) {
4168 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4169 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4170 VALUE num = iobj->operands[0];
4171 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4172 iobj->insn_id = BIN(opt_newarray_send);
4173 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4174 iobj->operands[0] = FIXNUM_INC(num, 1);
4175 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4176 iobj->operand_size = operand_len;
4177 ELEM_REMOVE(&iobj->link);
4178 ELEM_REMOVE(niobj->link.next);
4179 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4180 return COMPILE_OK;
4181 }
4182 }
4183 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4184 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4185 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4186 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4187 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4188 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4189 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4190 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4191 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4192 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4193 VALUE num = iobj->operands[0];
4194 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4195 iobj->insn_id = BIN(opt_newarray_send);
4196 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4197 iobj->operands[0] = FIXNUM_INC(num, 2);
4198 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4199 iobj->operand_size = operand_len;
4200 // Remove the "send" insn.
4201 ELEM_REMOVE((niobj->link.next)->next);
4202 // Remove the modified insn from its original "newarray" position...
4203 ELEM_REMOVE(&iobj->link);
4204 // and insert it after the buffer insn.
4205 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4206 return COMPILE_OK;
4207 }
4208 }
4209
4210 // Break the "else if" chain since some prior checks abort after sub-ifs.
4211 // We already found "newarray". To match `[...].include?(arg)` we look for
4212 // the instruction(s) representing the argument followed by a "send".
4213 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4214 IS_INSN_ID(niobj, putobject) ||
4215 IS_INSN_ID(niobj, putself) ||
4216 IS_INSN_ID(niobj, getlocal) ||
4217 IS_INSN_ID(niobj, getinstancevariable)) &&
4218 IS_NEXT_INSN_ID(&niobj->link, send)) {
4219
4220 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4221 const struct rb_callinfo *ci;
4222 // Allow any number (0 or more) of simple method calls on the argument
4223 // (as in `[...].include?(arg.method1.method2)`.
4224 do {
4225 sendobj = sendobj->next;
4226 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4227 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4228
4229 // If this send is for .include? with one arg we can do our opt.
4230 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4231 VALUE num = iobj->operands[0];
4232 INSN *sendins = (INSN *)sendobj;
4233 sendins->insn_id = BIN(opt_newarray_send);
4234 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4235 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4236 sendins->operands[0] = FIXNUM_INC(num, 1);
4237 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4238 // Remove the original "newarray" insn.
4239 ELEM_REMOVE(&iobj->link);
4240 return COMPILE_OK;
4241 }
4242 }
4243 }
4244
4245 /*
4246 * duparray [...]
4247 * some insn for the arg...
4248 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4249 * =>
4250 * arg insn...
4251 * opt_duparray_send [...], :include?, 1
4252 */
4253 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4254 INSN *niobj = (INSN *)iobj->link.next;
4255 if ((IS_INSN_ID(niobj, getlocal) ||
4256 IS_INSN_ID(niobj, getinstancevariable) ||
4257 IS_INSN_ID(niobj, putself)) &&
4258 IS_NEXT_INSN_ID(&niobj->link, send)) {
4259
4260 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4261 const struct rb_callinfo *ci;
4262 // Allow any number (0 or more) of simple method calls on the argument
4263 // (as in `[...].include?(arg.method1.method2)`.
4264 do {
4265 sendobj = sendobj->next;
4266 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4267 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4268
4269 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4270 // Move the array arg from duparray to opt_duparray_send.
4271 VALUE ary = iobj->operands[0];
4273
4274 INSN *sendins = (INSN *)sendobj;
4275 sendins->insn_id = BIN(opt_duparray_send);
4276 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4277 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4278 sendins->operands[0] = ary;
4279 sendins->operands[1] = rb_id2sym(idIncludeP);
4280 sendins->operands[2] = INT2FIX(1);
4281
4282 // Remove the duparray insn.
4283 ELEM_REMOVE(&iobj->link);
4284 return COMPILE_OK;
4285 }
4286 }
4287 }
4288
4289
4290 if (IS_INSN_ID(iobj, send)) {
4291 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4292 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4293
4294#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4295 if (vm_ci_simple(ci)) {
4296 switch (vm_ci_argc(ci)) {
4297 case 0:
4298 switch (vm_ci_mid(ci)) {
4299 case idLength: SP_INSN(length); return COMPILE_OK;
4300 case idSize: SP_INSN(size); return COMPILE_OK;
4301 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4302 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4303 case idSucc: SP_INSN(succ); return COMPILE_OK;
4304 case idNot: SP_INSN(not); return COMPILE_OK;
4305 }
4306 break;
4307 case 1:
4308 switch (vm_ci_mid(ci)) {
4309 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4310 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4311 case idMULT: SP_INSN(mult); return COMPILE_OK;
4312 case idDIV: SP_INSN(div); return COMPILE_OK;
4313 case idMOD: SP_INSN(mod); return COMPILE_OK;
4314 case idEq: SP_INSN(eq); return COMPILE_OK;
4315 case idNeq: SP_INSN(neq); return COMPILE_OK;
4316 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4317 case idLT: SP_INSN(lt); return COMPILE_OK;
4318 case idLE: SP_INSN(le); return COMPILE_OK;
4319 case idGT: SP_INSN(gt); return COMPILE_OK;
4320 case idGE: SP_INSN(ge); return COMPILE_OK;
4321 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4322 case idAREF: SP_INSN(aref); return COMPILE_OK;
4323 case idAnd: SP_INSN(and); return COMPILE_OK;
4324 case idOr: SP_INSN(or); return COMPILE_OK;
4325 }
4326 break;
4327 case 2:
4328 switch (vm_ci_mid(ci)) {
4329 case idASET: SP_INSN(aset); return COMPILE_OK;
4330 }
4331 break;
4332 }
4333 }
4334
4335 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4336 iobj->insn_id = BIN(opt_send_without_block);
4337 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4338 }
4339 }
4340#undef SP_INSN
4341
4342 return COMPILE_OK;
4343}
4344
4345static inline int
4346tailcallable_p(rb_iseq_t *iseq)
4347{
4348 switch (ISEQ_BODY(iseq)->type) {
4349 case ISEQ_TYPE_TOP:
4350 case ISEQ_TYPE_EVAL:
4351 case ISEQ_TYPE_MAIN:
4352 /* not tail callable because cfp will be over popped */
4353 case ISEQ_TYPE_RESCUE:
4354 case ISEQ_TYPE_ENSURE:
4355 /* rescue block can't tail call because of errinfo */
4356 return FALSE;
4357 default:
4358 return TRUE;
4359 }
4360}
4361
4362static int
4363iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4364{
4365 LINK_ELEMENT *list;
4366 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4367 const int do_tailcallopt = tailcallable_p(iseq) &&
4368 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4369 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4370 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4371 int rescue_level = 0;
4372 int tailcallopt = do_tailcallopt;
4373
4374 list = FIRST_ELEMENT(anchor);
4375
4376 int do_block_optimization = 0;
4377 LABEL * block_loop_label = NULL;
4378
4379 // If we're optimizing a block
4380 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4381 do_block_optimization = 1;
4382
4383 // If the block starts with a nop and a label,
4384 // record the label so we can detect if it's a jump target
4385 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4386 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4387 block_loop_label = (LABEL *)le->next;
4388 }
4389 }
4390
4391 while (list) {
4392 if (IS_INSN(list)) {
4393 if (do_peepholeopt) {
4394 iseq_peephole_optimize(iseq, list, tailcallopt);
4395 }
4396 if (do_si) {
4397 iseq_specialized_instruction(iseq, (INSN *)list);
4398 }
4399 if (do_ou) {
4400 insn_operands_unification((INSN *)list);
4401 }
4402
4403 if (do_block_optimization) {
4404 INSN * item = (INSN *)list;
4405 // Give up if there is a throw
4406 if (IS_INSN_ID(item, throw)) {
4407 do_block_optimization = 0;
4408 }
4409 else {
4410 // If the instruction has a jump target, check if the
4411 // jump target is the block loop label
4412 const char *types = insn_op_types(item->insn_id);
4413 for (int j = 0; types[j]; j++) {
4414 if (types[j] == TS_OFFSET) {
4415 // If the jump target is equal to the block loop
4416 // label, then we can't do the optimization because
4417 // the leading `nop` instruction fires the block
4418 // entry tracepoint
4419 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4420 if (target == block_loop_label) {
4421 do_block_optimization = 0;
4422 }
4423 }
4424 }
4425 }
4426 }
4427 }
4428 if (IS_LABEL(list)) {
4429 switch (((LABEL *)list)->rescued) {
4430 case LABEL_RESCUE_BEG:
4431 rescue_level++;
4432 tailcallopt = FALSE;
4433 break;
4434 case LABEL_RESCUE_END:
4435 if (!--rescue_level) tailcallopt = do_tailcallopt;
4436 break;
4437 }
4438 }
4439 list = list->next;
4440 }
4441
4442 if (do_block_optimization) {
4443 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4444 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4445 ELEM_REMOVE(le);
4446 }
4447 }
4448 return COMPILE_OK;
4449}
4450
4451#if OPT_INSTRUCTIONS_UNIFICATION
4452static INSN *
4453new_unified_insn(rb_iseq_t *iseq,
4454 int insn_id, int size, LINK_ELEMENT *seq_list)
4455{
4456 INSN *iobj = 0;
4457 LINK_ELEMENT *list = seq_list;
4458 int i, argc = 0;
4459 VALUE *operands = 0, *ptr = 0;
4460
4461
4462 /* count argc */
4463 for (i = 0; i < size; i++) {
4464 iobj = (INSN *)list;
4465 argc += iobj->operand_size;
4466 list = list->next;
4467 }
4468
4469 if (argc > 0) {
4470 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4471 }
4472
4473 /* copy operands */
4474 list = seq_list;
4475 for (i = 0; i < size; i++) {
4476 iobj = (INSN *)list;
4477 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4478 ptr += iobj->operand_size;
4479 list = list->next;
4480 }
4481
4482 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4483}
4484#endif
4485
4486/*
4487 * This scheme can get more performance if do this optimize with
4488 * label address resolving.
4489 * It's future work (if compile time was bottle neck).
4490 */
4491static int
4492iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4493{
4494#if OPT_INSTRUCTIONS_UNIFICATION
4495 LINK_ELEMENT *list;
4496 INSN *iobj, *niobj;
4497 int id, k;
4498 intptr_t j;
4499
4500 list = FIRST_ELEMENT(anchor);
4501 while (list) {
4502 if (IS_INSN(list)) {
4503 iobj = (INSN *)list;
4504 id = iobj->insn_id;
4505 if (unified_insns_data[id] != 0) {
4506 const int *const *entry = unified_insns_data[id];
4507 for (j = 1; j < (intptr_t)entry[0]; j++) {
4508 const int *unified = entry[j];
4509 LINK_ELEMENT *li = list->next;
4510 for (k = 2; k < unified[1]; k++) {
4511 if (!IS_INSN(li) ||
4512 ((INSN *)li)->insn_id != unified[k]) {
4513 goto miss;
4514 }
4515 li = li->next;
4516 }
4517 /* matched */
4518 niobj =
4519 new_unified_insn(iseq, unified[0], unified[1] - 1,
4520 list);
4521
4522 /* insert to list */
4523 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4524 niobj->link.next = li;
4525 if (li) {
4526 li->prev = (LINK_ELEMENT *)niobj;
4527 }
4528
4529 list->prev->next = (LINK_ELEMENT *)niobj;
4530 list = (LINK_ELEMENT *)niobj;
4531 break;
4532 miss:;
4533 }
4534 }
4535 }
4536 list = list->next;
4537 }
4538#endif
4539 return COMPILE_OK;
4540}
4541
4542static int
4543all_string_result_p(const NODE *node)
4544{
4545 if (!node) return FALSE;
4546 switch (nd_type(node)) {
4547 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4548 return TRUE;
4549 case NODE_IF: case NODE_UNLESS:
4550 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4551 if (all_string_result_p(RNODE_IF(node)->nd_body))
4552 return all_string_result_p(RNODE_IF(node)->nd_else);
4553 return FALSE;
4554 case NODE_AND: case NODE_OR:
4555 if (!RNODE_AND(node)->nd_2nd)
4556 return all_string_result_p(RNODE_AND(node)->nd_1st);
4557 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4558 return FALSE;
4559 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4560 default:
4561 return FALSE;
4562 }
4563}
4564
4566 rb_iseq_t *const iseq;
4567 LINK_ANCHOR *const ret;
4568 VALUE lit;
4569 const NODE *lit_node;
4570 int cnt;
4571 int dregx;
4572};
4573
4574static int
4575append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4576{
4577 VALUE s = rb_str_new_mutable_parser_string(str);
4578 if (args->dregx) {
4579 VALUE error = rb_reg_check_preprocess(s);
4580 if (!NIL_P(error)) {
4581 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4582 return COMPILE_NG;
4583 }
4584 }
4585 if (NIL_P(args->lit)) {
4586 args->lit = s;
4587 args->lit_node = node;
4588 }
4589 else {
4590 rb_str_buf_append(args->lit, s);
4591 }
4592 return COMPILE_OK;
4593}
4594
4595static void
4596flush_dstr_fragment(struct dstr_ctxt *args)
4597{
4598 if (!NIL_P(args->lit)) {
4599 rb_iseq_t *iseq = args->iseq;
4600 VALUE lit = args->lit;
4601 args->lit = Qnil;
4602 lit = rb_fstring(lit);
4603 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4604 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4605 args->cnt++;
4606 }
4607}
4608
4609static int
4610compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4611{
4612 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4613 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4614
4615 if (str) {
4616 CHECK(append_dstr_fragment(args, node, str));
4617 }
4618
4619 while (list) {
4620 const NODE *const head = list->nd_head;
4621 if (nd_type_p(head, NODE_STR)) {
4622 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4623 }
4624 else if (nd_type_p(head, NODE_DSTR)) {
4625 CHECK(compile_dstr_fragments_0(args, head));
4626 }
4627 else {
4628 flush_dstr_fragment(args);
4629 rb_iseq_t *iseq = args->iseq;
4630 CHECK(COMPILE(args->ret, "each string", head));
4631 args->cnt++;
4632 }
4633 list = (struct RNode_LIST *)list->nd_next;
4634 }
4635 return COMPILE_OK;
4636}
4637
4638static int
4639compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4640{
4641 struct dstr_ctxt args = {
4642 .iseq = iseq, .ret = ret,
4643 .lit = Qnil, .lit_node = NULL,
4644 .cnt = 0, .dregx = dregx,
4645 };
4646 CHECK(compile_dstr_fragments_0(&args, node));
4647 flush_dstr_fragment(&args);
4648
4649 *cntp = args.cnt;
4650
4651 return COMPILE_OK;
4652}
4653
4654static int
4655compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4656{
4657 while (node && nd_type_p(node, NODE_BLOCK)) {
4658 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4659 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4660 node = RNODE_BLOCK(node)->nd_next;
4661 }
4662 if (node) {
4663 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4664 }
4665 return COMPILE_OK;
4666}
4667
4668static int
4669compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4670{
4671 int cnt;
4672 if (!RNODE_DSTR(node)->nd_next) {
4673 VALUE lit = rb_node_dstr_string_val(node);
4674 ADD_INSN1(ret, node, putstring, lit);
4675 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4676 }
4677 else {
4678 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4679 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4680 }
4681 return COMPILE_OK;
4682}
4683
4684static int
4685compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4686{
4687 int cnt;
4688 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4689
4690 if (!RNODE_DREGX(node)->nd_next) {
4691 if (!popped) {
4692 VALUE src = rb_node_dregx_string_val(node);
4693 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4694 ADD_INSN1(ret, node, putobject, match);
4695 RB_OBJ_WRITTEN(iseq, Qundef, match);
4696 }
4697 return COMPILE_OK;
4698 }
4699
4700 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4701 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4702
4703 if (popped) {
4704 ADD_INSN(ret, node, pop);
4705 }
4706
4707 return COMPILE_OK;
4708}
4709
4710static int
4711compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4712 LABEL *then_label, LABEL *else_label)
4713{
4714 const int line = nd_line(node);
4715 LABEL *lend = NEW_LABEL(line);
4716 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4717 + VM_SVAR_FLIPFLOP_START;
4718 VALUE key = INT2FIX(cnt);
4719
4720 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4721 ADD_INSNL(ret, node, branchif, lend);
4722
4723 /* *flip == 0 */
4724 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4725 ADD_INSNL(ret, node, branchunless, else_label);
4726 ADD_INSN1(ret, node, putobject, Qtrue);
4727 ADD_INSN1(ret, node, setspecial, key);
4728 if (!again) {
4729 ADD_INSNL(ret, node, jump, then_label);
4730 }
4731
4732 /* *flip == 1 */
4733 ADD_LABEL(ret, lend);
4734 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4735 ADD_INSNL(ret, node, branchunless, then_label);
4736 ADD_INSN1(ret, node, putobject, Qfalse);
4737 ADD_INSN1(ret, node, setspecial, key);
4738 ADD_INSNL(ret, node, jump, then_label);
4739
4740 return COMPILE_OK;
4741}
4742
4743static int
4744compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4745 LABEL *then_label, LABEL *else_label);
4746
4747#define COMPILE_SINGLE 2
4748static int
4749compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4750 LABEL *then_label, LABEL *else_label)
4751{
4752 DECL_ANCHOR(seq);
4753 INIT_ANCHOR(seq);
4754 LABEL *label = NEW_LABEL(nd_line(cond));
4755 if (!then_label) then_label = label;
4756 else if (!else_label) else_label = label;
4757
4758 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4759
4760 if (LIST_INSN_SIZE_ONE(seq)) {
4761 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4762 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4763 return COMPILE_OK;
4764 }
4765 if (!label->refcnt) {
4766 return COMPILE_SINGLE;
4767 }
4768 ADD_LABEL(seq, label);
4769 ADD_SEQ(ret, seq);
4770 return COMPILE_OK;
4771}
4772
4773static int
4774compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4775 LABEL *then_label, LABEL *else_label)
4776{
4777 int ok;
4778 DECL_ANCHOR(ignore);
4779
4780 again:
4781 switch (nd_type(cond)) {
4782 case NODE_AND:
4783 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4784 cond = RNODE_AND(cond)->nd_2nd;
4785 if (ok == COMPILE_SINGLE) {
4786 INIT_ANCHOR(ignore);
4787 ret = ignore;
4788 then_label = NEW_LABEL(nd_line(cond));
4789 }
4790 goto again;
4791 case NODE_OR:
4792 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4793 cond = RNODE_OR(cond)->nd_2nd;
4794 if (ok == COMPILE_SINGLE) {
4795 INIT_ANCHOR(ignore);
4796 ret = ignore;
4797 else_label = NEW_LABEL(nd_line(cond));
4798 }
4799 goto again;
4800 case NODE_SYM:
4801 case NODE_LINE:
4802 case NODE_FILE:
4803 case NODE_ENCODING:
4804 case NODE_INTEGER: /* NODE_INTEGER is always true */
4805 case NODE_FLOAT: /* NODE_FLOAT is always true */
4806 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4807 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4808 case NODE_TRUE:
4809 case NODE_STR:
4810 case NODE_REGX:
4811 case NODE_ZLIST:
4812 case NODE_LAMBDA:
4813 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4814 ADD_INSNL(ret, cond, jump, then_label);
4815 return COMPILE_OK;
4816 case NODE_FALSE:
4817 case NODE_NIL:
4818 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4819 ADD_INSNL(ret, cond, jump, else_label);
4820 return COMPILE_OK;
4821 case NODE_LIST:
4822 case NODE_ARGSCAT:
4823 case NODE_DREGX:
4824 case NODE_DSTR:
4825 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4826 ADD_INSNL(ret, cond, jump, then_label);
4827 return COMPILE_OK;
4828 case NODE_FLIP2:
4829 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4830 return COMPILE_OK;
4831 case NODE_FLIP3:
4832 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4833 return COMPILE_OK;
4834 case NODE_DEFINED:
4835 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4836 break;
4837 default:
4838 {
4839 DECL_ANCHOR(cond_seq);
4840 INIT_ANCHOR(cond_seq);
4841
4842 CHECK(COMPILE(cond_seq, "branch condition", cond));
4843
4844 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4845 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4846 if (insn->insn_id == BIN(putobject)) {
4847 if (RTEST(insn->operands[0])) {
4848 ADD_INSNL(ret, cond, jump, then_label);
4849 // maybe unreachable
4850 return COMPILE_OK;
4851 }
4852 else {
4853 ADD_INSNL(ret, cond, jump, else_label);
4854 return COMPILE_OK;
4855 }
4856 }
4857 }
4858 ADD_SEQ(ret, cond_seq);
4859 }
4860 break;
4861 }
4862
4863 ADD_INSNL(ret, cond, branchunless, else_label);
4864 ADD_INSNL(ret, cond, jump, then_label);
4865 return COMPILE_OK;
4866}
4867
4868#define HASH_BRACE 1
4869
4870static int
4871keyword_node_p(const NODE *const node)
4872{
4873 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4874}
4875
4876static VALUE
4877get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4878{
4879 switch (nd_type(node)) {
4880 case NODE_SYM:
4881 return rb_node_sym_string_val(node);
4882 default:
4883 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4884 }
4885}
4886
4887static VALUE
4888node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4889{
4890 NODE *node = node_hash->nd_head;
4891 VALUE hash = rb_hash_new();
4892 VALUE ary = rb_ary_new();
4893
4894 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4895 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4896 VALUE idx = rb_hash_aref(hash, key);
4897 if (!NIL_P(idx)) {
4898 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4899 (*count_ptr)--;
4900 }
4901 rb_hash_aset(hash, key, INT2FIX(i));
4902 rb_ary_store(ary, i, Qtrue);
4903 (*count_ptr)++;
4904 }
4905
4906 return ary;
4907}
4908
4909static int
4910compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4911 const NODE *const root_node,
4912 struct rb_callinfo_kwarg **const kw_arg_ptr,
4913 unsigned int *flag)
4914{
4915 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4916 RUBY_ASSERT(kw_arg_ptr != NULL);
4917 RUBY_ASSERT(flag != NULL);
4918
4919 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4920 const NODE *node = RNODE_HASH(root_node)->nd_head;
4921 int seen_nodes = 0;
4922
4923 while (node) {
4924 const NODE *key_node = RNODE_LIST(node)->nd_head;
4925 seen_nodes++;
4926
4927 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4928 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4929 /* can be keywords */
4930 }
4931 else {
4932 if (flag) {
4933 *flag |= VM_CALL_KW_SPLAT;
4934 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4935 /* A new hash will be created for the keyword arguments
4936 * in this case, so mark the method as passing mutable
4937 * keyword splat.
4938 */
4939 *flag |= VM_CALL_KW_SPLAT_MUT;
4940 }
4941 }
4942 return FALSE;
4943 }
4944 node = RNODE_LIST(node)->nd_next; /* skip value node */
4945 node = RNODE_LIST(node)->nd_next;
4946 }
4947
4948 /* may be keywords */
4949 node = RNODE_HASH(root_node)->nd_head;
4950 {
4951 int len = 0;
4952 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4953 struct rb_callinfo_kwarg *kw_arg =
4954 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4955 VALUE *keywords = kw_arg->keywords;
4956 int i = 0;
4957 int j = 0;
4958 kw_arg->references = 0;
4959 kw_arg->keyword_len = len;
4960
4961 *kw_arg_ptr = kw_arg;
4962
4963 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4964 const NODE *key_node = RNODE_LIST(node)->nd_head;
4965 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4966 int popped = TRUE;
4967 if (rb_ary_entry(key_index, i)) {
4968 keywords[j] = get_symbol_value(iseq, key_node);
4969 j++;
4970 popped = FALSE;
4971 }
4972 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4973 }
4974 RUBY_ASSERT(j == len);
4975 return TRUE;
4976 }
4977 }
4978 return FALSE;
4979}
4980
4981static int
4982compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4983{
4984 int len = 0;
4985
4986 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4987 if (CPDEBUG > 0) {
4988 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4989 }
4990
4991 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4992 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4993 }
4994 else {
4995 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4996 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4997 }
4998 }
4999
5000 return len;
5001}
5002
5003static inline bool
5004frozen_string_literal_p(const rb_iseq_t *iseq)
5005{
5006 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5007}
5008
5009static inline bool
5010static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5011{
5012 switch (nd_type(node)) {
5013 case NODE_SYM:
5014 case NODE_REGX:
5015 case NODE_LINE:
5016 case NODE_ENCODING:
5017 case NODE_INTEGER:
5018 case NODE_FLOAT:
5019 case NODE_RATIONAL:
5020 case NODE_IMAGINARY:
5021 case NODE_NIL:
5022 case NODE_TRUE:
5023 case NODE_FALSE:
5024 return TRUE;
5025 case NODE_STR:
5026 case NODE_FILE:
5027 return hash_key || frozen_string_literal_p(iseq);
5028 default:
5029 return FALSE;
5030 }
5031}
5032
5033static inline VALUE
5034static_literal_value(const NODE *node, rb_iseq_t *iseq)
5035{
5036 switch (nd_type(node)) {
5037 case NODE_INTEGER:
5038 return rb_node_integer_literal_val(node);
5039 case NODE_FLOAT:
5040 return rb_node_float_literal_val(node);
5041 case NODE_RATIONAL:
5042 return rb_node_rational_literal_val(node);
5043 case NODE_IMAGINARY:
5044 return rb_node_imaginary_literal_val(node);
5045 case NODE_NIL:
5046 return Qnil;
5047 case NODE_TRUE:
5048 return Qtrue;
5049 case NODE_FALSE:
5050 return Qfalse;
5051 case NODE_SYM:
5052 return rb_node_sym_string_val(node);
5053 case NODE_REGX:
5054 return rb_node_regx_string_val(node);
5055 case NODE_LINE:
5056 return rb_node_line_lineno_val(node);
5057 case NODE_ENCODING:
5058 return rb_node_encoding_val(node);
5059 case NODE_FILE:
5060 case NODE_STR:
5061 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5062 VALUE lit = get_string_value(node);
5063 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5064 }
5065 else {
5066 return get_string_value(node);
5067 }
5068 default:
5069 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5070 }
5071}
5072
5073static int
5074compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5075{
5076 const NODE *line_node = node;
5077
5078 if (nd_type_p(node, NODE_ZLIST)) {
5079 if (!popped) {
5080 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5081 }
5082 return 0;
5083 }
5084
5085 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5086
5087 if (popped) {
5088 for (; node; node = RNODE_LIST(node)->nd_next) {
5089 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5090 }
5091 return 1;
5092 }
5093
5094 /* Compilation of an array literal.
5095 * The following code is essentially the same as:
5096 *
5097 * for (int count = 0; node; count++; node->nd_next) {
5098 * compile(node->nd_head);
5099 * }
5100 * ADD_INSN(newarray, count);
5101 *
5102 * However, there are three points.
5103 *
5104 * - The code above causes stack overflow for a big string literal.
5105 * The following limits the stack length up to max_stack_len.
5106 *
5107 * [x1,x2,...,x10000] =>
5108 * push x1 ; push x2 ; ...; push x256; newarray 256;
5109 * push x257; push x258; ...; push x512; pushtoarray 256;
5110 * push x513; push x514; ...; push x768; pushtoarray 256;
5111 * ...
5112 *
5113 * - Long subarray can be optimized by pre-allocating a hidden array.
5114 *
5115 * [1,2,3,...,100] =>
5116 * duparray [1,2,3,...,100]
5117 *
5118 * [x, 1,2,3,...,100, z] =>
5119 * push x; newarray 1;
5120 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5121 * push z; pushtoarray 1;
5122 *
5123 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5124 * to only push it onto the array if it is not empty
5125 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5126 *
5127 * [1,2,3,**kw] =>
5128 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5129 */
5130
5131 const int max_stack_len = 0x100;
5132 const int min_tmp_ary_len = 0x40;
5133 int stack_len = 0;
5134
5135 /* Either create a new array, or push to the existing array */
5136#define FLUSH_CHUNK \
5137 if (stack_len) { \
5138 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5139 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5140 first_chunk = FALSE; \
5141 stack_len = 0; \
5142 }
5143
5144 while (node) {
5145 int count = 1;
5146
5147 /* pre-allocation check (this branch can be omittable) */
5148 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5149 /* count the elements that are optimizable */
5150 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5151 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5152 count++;
5153
5154 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5155 /* The literal contains only optimizable elements, or the subarray is long enough */
5156 VALUE ary = rb_ary_hidden_new(count);
5157
5158 /* Create a hidden array */
5159 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5160 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5161 OBJ_FREEZE(ary);
5162
5163 /* Emit optimized code */
5164 FLUSH_CHUNK;
5165 if (first_chunk) {
5166 ADD_INSN1(ret, line_node, duparray, ary);
5167 first_chunk = FALSE;
5168 }
5169 else {
5170 ADD_INSN1(ret, line_node, putobject, ary);
5171 ADD_INSN(ret, line_node, concattoarray);
5172 }
5173 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5174 }
5175 }
5176
5177 /* Base case: Compile "count" elements */
5178 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5179 if (CPDEBUG > 0) {
5180 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5181 }
5182
5183 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5184 /* Create array or push existing non-keyword elements onto array */
5185 if (stack_len == 0 && first_chunk) {
5186 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5187 }
5188 else {
5189 FLUSH_CHUNK;
5190 }
5191 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5192 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5193 return 1;
5194 }
5195 else {
5196 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5197 stack_len++;
5198 }
5199
5200 /* If there are many pushed elements, flush them to avoid stack overflow */
5201 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5202 }
5203 }
5204
5205 FLUSH_CHUNK;
5206#undef FLUSH_CHUNK
5207 return 1;
5208}
5209
5210static inline int
5211static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5212{
5213 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);
5214}
5215
5216static int
5217compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5218{
5219 const NODE *line_node = node;
5220
5221 node = RNODE_HASH(node)->nd_head;
5222
5223 if (!node || nd_type_p(node, NODE_ZLIST)) {
5224 if (!popped) {
5225 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5226 }
5227 return 0;
5228 }
5229
5230 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5231
5232 if (popped) {
5233 for (; node; node = RNODE_LIST(node)->nd_next) {
5234 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5235 }
5236 return 1;
5237 }
5238
5239 /* Compilation of a hash literal (or keyword arguments).
5240 * This is very similar to compile_array, but there are some differences:
5241 *
5242 * - It contains key-value pairs. So we need to take every two elements.
5243 * We can assume that the length is always even.
5244 *
5245 * - Merging is done by a method call (id_core_hash_merge_ptr).
5246 * Sometimes we need to insert the receiver, so "anchor" is needed.
5247 * In addition, a method call is much slower than concatarray.
5248 * So it pays only when the subsequence is really long.
5249 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5250 *
5251 * - We need to handle keyword splat: **kw.
5252 * For **kw, the key part (node->nd_head) is NULL, and the value part
5253 * (node->nd_next->nd_head) is "kw".
5254 * The code is a bit difficult to avoid hash allocation for **{}.
5255 */
5256
5257 const int max_stack_len = 0x100;
5258 const int min_tmp_hash_len = 0x800;
5259 int stack_len = 0;
5260 int first_chunk = 1;
5261 DECL_ANCHOR(anchor);
5262 INIT_ANCHOR(anchor);
5263
5264 /* Convert pushed elements to a hash, and merge if needed */
5265#define FLUSH_CHUNK() \
5266 if (stack_len) { \
5267 if (first_chunk) { \
5268 APPEND_LIST(ret, anchor); \
5269 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5270 } \
5271 else { \
5272 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5273 ADD_INSN(ret, line_node, swap); \
5274 APPEND_LIST(ret, anchor); \
5275 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5276 } \
5277 INIT_ANCHOR(anchor); \
5278 first_chunk = stack_len = 0; \
5279 }
5280
5281 while (node) {
5282 int count = 1;
5283
5284 /* pre-allocation check (this branch can be omittable) */
5285 if (static_literal_node_pair_p(node, iseq)) {
5286 /* count the elements that are optimizable */
5287 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5288 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5289 count++;
5290
5291 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5292 /* The literal contains only optimizable elements, or the subsequence is long enough */
5293 VALUE ary = rb_ary_hidden_new(count);
5294
5295 /* Create a hidden hash */
5296 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5297 VALUE elem[2];
5298 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5299 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5300 rb_ary_cat(ary, elem, 2);
5301 }
5302 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5303 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5304 hash = rb_obj_hide(hash);
5305 OBJ_FREEZE(hash);
5306
5307 /* Emit optimized code */
5308 FLUSH_CHUNK();
5309 if (first_chunk) {
5310 ADD_INSN1(ret, line_node, duphash, hash);
5311 first_chunk = 0;
5312 }
5313 else {
5314 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5315 ADD_INSN(ret, line_node, swap);
5316
5317 ADD_INSN1(ret, line_node, putobject, hash);
5318
5319 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5320 }
5321 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5322 }
5323 }
5324
5325 /* Base case: Compile "count" elements */
5326 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5327
5328 if (CPDEBUG > 0) {
5329 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5330 }
5331
5332 if (RNODE_LIST(node)->nd_head) {
5333 /* Normal key-value pair */
5334 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5335 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5336 stack_len += 2;
5337
5338 /* If there are many pushed elements, flush them to avoid stack overflow */
5339 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5340 }
5341 else {
5342 /* kwsplat case: foo(..., **kw, ...) */
5343 FLUSH_CHUNK();
5344
5345 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5346 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5347 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5348 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5349 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5350
5351 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5352 if (empty_kw) {
5353 if (only_kw && method_call_keywords) {
5354 /* **{} appears at the only keyword argument in method call,
5355 * so it won't be modified.
5356 * kw is a special NODE_LIT that contains a special empty hash,
5357 * so this emits: putobject {}.
5358 * This is only done for method calls and not for literal hashes,
5359 * because literal hashes should always result in a new hash.
5360 */
5361 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5362 }
5363 else if (first_kw) {
5364 /* **{} appears as the first keyword argument, so it may be modified.
5365 * We need to create a fresh hash object.
5366 */
5367 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5368 }
5369 /* Any empty keyword splats that are not the first can be ignored.
5370 * since merging an empty hash into the existing hash is the same
5371 * as not merging it. */
5372 }
5373 else {
5374 if (only_kw && method_call_keywords) {
5375 /* **kw is only keyword argument in method call.
5376 * Use directly. This will be not be flagged as mutable.
5377 * This is only done for method calls and not for literal hashes,
5378 * because literal hashes should always result in a new hash.
5379 */
5380 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5381 }
5382 else {
5383 /* There is more than one keyword argument, or this is not a method
5384 * call. In that case, we need to add an empty hash (if first keyword),
5385 * or merge the hash to the accumulated hash (if not the first keyword).
5386 */
5387 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5388 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5389 else ADD_INSN(ret, line_node, swap);
5390
5391 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5392
5393 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5394 }
5395 }
5396
5397 first_chunk = 0;
5398 }
5399 }
5400 }
5401
5402 FLUSH_CHUNK();
5403#undef FLUSH_CHUNK
5404 return 1;
5405}
5406
5407VALUE
5408rb_node_case_when_optimizable_literal(const NODE *const node)
5409{
5410 switch (nd_type(node)) {
5411 case NODE_INTEGER:
5412 return rb_node_integer_literal_val(node);
5413 case NODE_FLOAT: {
5414 VALUE v = rb_node_float_literal_val(node);
5415 double ival;
5416
5417 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5418 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5419 }
5420 return v;
5421 }
5422 case NODE_RATIONAL:
5423 case NODE_IMAGINARY:
5424 return Qundef;
5425 case NODE_NIL:
5426 return Qnil;
5427 case NODE_TRUE:
5428 return Qtrue;
5429 case NODE_FALSE:
5430 return Qfalse;
5431 case NODE_SYM:
5432 return rb_node_sym_string_val(node);
5433 case NODE_LINE:
5434 return rb_node_line_lineno_val(node);
5435 case NODE_STR:
5436 return rb_node_str_string_val(node);
5437 case NODE_FILE:
5438 return rb_node_file_path_val(node);
5439 }
5440 return Qundef;
5441}
5442
5443static int
5444when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5445 LABEL *l1, int only_special_literals, VALUE literals)
5446{
5447 while (vals) {
5448 const NODE *val = RNODE_LIST(vals)->nd_head;
5449 VALUE lit = rb_node_case_when_optimizable_literal(val);
5450
5451 if (UNDEF_P(lit)) {
5452 only_special_literals = 0;
5453 }
5454 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5455 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5456 }
5457
5458 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5459 debugp_param("nd_lit", get_string_value(val));
5460 lit = get_string_value(val);
5461 ADD_INSN1(cond_seq, val, putobject, lit);
5462 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5463 }
5464 else {
5465 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5466 }
5467
5468 // Emit pattern === target
5469 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5470 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5471 ADD_INSNL(cond_seq, val, branchif, l1);
5472 vals = RNODE_LIST(vals)->nd_next;
5473 }
5474 return only_special_literals;
5475}
5476
5477static int
5478when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5479 LABEL *l1, int only_special_literals, VALUE literals)
5480{
5481 const NODE *line_node = vals;
5482
5483 switch (nd_type(vals)) {
5484 case NODE_LIST:
5485 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5486 return COMPILE_NG;
5487 break;
5488 case NODE_SPLAT:
5489 ADD_INSN (cond_seq, line_node, dup);
5490 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5491 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5492 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5493 ADD_INSNL(cond_seq, line_node, branchif, l1);
5494 break;
5495 case NODE_ARGSCAT:
5496 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5497 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5498 break;
5499 case NODE_ARGSPUSH:
5500 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5501 ADD_INSN (cond_seq, line_node, dup);
5502 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5503 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5504 ADD_INSNL(cond_seq, line_node, branchif, l1);
5505 break;
5506 default:
5507 ADD_INSN (cond_seq, line_node, dup);
5508 CHECK(COMPILE(cond_seq, "when val", vals));
5509 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5510 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5511 ADD_INSNL(cond_seq, line_node, branchif, l1);
5512 break;
5513 }
5514 return COMPILE_OK;
5515}
5516
5517/* Multiple Assignment Handling
5518 *
5519 * In order to handle evaluation of multiple assignment such that the left hand side
5520 * is evaluated before the right hand side, we need to process the left hand side
5521 * and see if there are any attributes that need to be assigned, or constants set
5522 * on explicit objects. If so, we add instructions to evaluate the receiver of
5523 * any assigned attributes or constants before we process the right hand side.
5524 *
5525 * For a multiple assignment such as:
5526 *
5527 * l1.m1, l2[0] = r3, r4
5528 *
5529 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5530 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5531 * On the VM stack, this looks like:
5532 *
5533 * self # putself
5534 * l1 # send
5535 * l1, self # putself
5536 * l1, l2 # send
5537 * l1, l2, 0 # putobject 0
5538 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5539 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5540 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5541 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5542 * l1, l2, 0, [r3, r4], r4, m1= # send
5543 * l1, l2, 0, [r3, r4], r4 # pop
5544 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5545 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5546 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5547 * l1, l2, 0, [r3, r4], r4, []= # send
5548 * l1, l2, 0, [r3, r4], r4 # pop
5549 * l1, l2, 0, [r3, r4] # pop
5550 * [r3, r4], l2, 0, [r3, r4] # setn 3
5551 * [r3, r4], l2, 0 # pop
5552 * [r3, r4], l2 # pop
5553 * [r3, r4] # pop
5554 *
5555 * This is made more complex when you have to handle splats, post args,
5556 * and arbitrary levels of nesting. You need to keep track of the total
5557 * number of attributes to set, and for each attribute, how many entries
5558 * are on the stack before the final attribute, in order to correctly
5559 * calculate the topn value to use to get the receiver of the attribute
5560 * setter method.
5561 *
5562 * A brief description of the VM stack for simple multiple assignment
5563 * with no splat (rhs_array will not be present if the return value of
5564 * the multiple assignment is not needed):
5565 *
5566 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5567 *
5568 * For multiple assignment with splats, while processing the part before
5569 * the splat (splat+post here is an array of the splat and the post arguments):
5570 *
5571 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5572 *
5573 * When processing the splat and post arguments:
5574 *
5575 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5576 *
5577 * When processing nested multiple assignment, existing values on the stack
5578 * are kept. So for:
5579 *
5580 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5581 *
5582 * The stack layout would be the following before processing the nested
5583 * multiple assignment:
5584 *
5585 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5586 *
5587 * In order to handle this correctly, we need to keep track of the nesting
5588 * level for each attribute assignment, as well as the attribute number
5589 * (left hand side attributes are processed left to right) and number of
5590 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5591 * this information.
5592 *
5593 * We also need to track information for the entire multiple assignment, such
5594 * as the total number of arguments, and the current nesting level, to
5595 * handle both nested multiple assignment as well as cases where the
5596 * rhs is not needed. We also need to keep track of all attribute
5597 * assignments in this, which we do using a linked listed. struct masgn_state
5598 * tracks this information.
5599 */
5600
5602 INSN *before_insn;
5603 struct masgn_lhs_node *next;
5604 const NODE *line_node;
5605 int argn;
5606 int num_args;
5607 int lhs_pos;
5608};
5609
5611 struct masgn_lhs_node *first_memo;
5612 struct masgn_lhs_node *last_memo;
5613 int lhs_level;
5614 int num_args;
5615 bool nested;
5616};
5617
5618static int
5619add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5620{
5621 if (!state) {
5622 rb_bug("no masgn_state");
5623 }
5624
5625 struct masgn_lhs_node *memo;
5626 memo = malloc(sizeof(struct masgn_lhs_node));
5627 if (!memo) {
5628 return COMPILE_NG;
5629 }
5630
5631 memo->before_insn = before_insn;
5632 memo->line_node = line_node;
5633 memo->argn = state->num_args + 1;
5634 memo->num_args = argc;
5635 state->num_args += argc;
5636 memo->lhs_pos = lhs_pos;
5637 memo->next = NULL;
5638 if (!state->first_memo) {
5639 state->first_memo = memo;
5640 }
5641 else {
5642 state->last_memo->next = memo;
5643 }
5644 state->last_memo = memo;
5645
5646 return COMPILE_OK;
5647}
5648
5649static 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);
5650
5651static int
5652compile_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)
5653{
5654 switch (nd_type(node)) {
5655 case NODE_ATTRASGN: {
5656 INSN *iobj;
5657 const NODE *line_node = node;
5658
5659 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5660
5661 bool safenav_call = false;
5662 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5663 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5664 ASSUME(iobj);
5665 ELEM_REMOVE(insn_element);
5666 if (!IS_INSN_ID(iobj, send)) {
5667 safenav_call = true;
5668 iobj = (INSN *)get_prev_insn(iobj);
5669 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5670 }
5671 (pre->last = iobj->link.prev)->next = 0;
5672
5673 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5674 int argc = vm_ci_argc(ci) + 1;
5675 ci = ci_argc_set(iseq, ci, argc);
5676 OPERAND_AT(iobj, 0) = (VALUE)ci;
5677 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5678
5679 if (argc == 1) {
5680 ADD_INSN(lhs, line_node, swap);
5681 }
5682 else {
5683 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5684 }
5685
5686 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5687 return COMPILE_NG;
5688 }
5689
5690 iobj->link.prev = lhs->last;
5691 lhs->last->next = &iobj->link;
5692 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5693 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5694 int argc = vm_ci_argc(ci);
5695 bool dupsplat = false;
5696 ci = ci_argc_set(iseq, ci, argc - 1);
5697 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5698 /* Given h[*a], _ = ary
5699 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5700 * `a` must be dupped, because it will be appended with ary[0]
5701 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5702 */
5703 dupsplat = true;
5704 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5705 }
5706 OPERAND_AT(iobj, 0) = (VALUE)ci;
5707 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5708
5709 /* Given: h[*a], h[*b, 1] = ary
5710 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5711 * so this uses splatarray true on a to dup it before using pushtoarray
5712 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5713 * so you can use pushtoarray directly
5714 */
5715 int line_no = nd_line(line_node);
5716 int node_id = nd_node_id(line_node);
5717
5718 if (dupsplat) {
5719 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5720 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5721 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5722 }
5723 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5724 }
5725 if (!safenav_call) {
5726 ADD_INSN(lhs, line_node, pop);
5727 if (argc != 1) {
5728 ADD_INSN(lhs, line_node, pop);
5729 }
5730 }
5731 for (int i=0; i < argc; i++) {
5732 ADD_INSN(post, line_node, pop);
5733 }
5734 break;
5735 }
5736 case NODE_MASGN: {
5737 DECL_ANCHOR(nest_rhs);
5738 INIT_ANCHOR(nest_rhs);
5739 DECL_ANCHOR(nest_lhs);
5740 INIT_ANCHOR(nest_lhs);
5741
5742 int prev_level = state->lhs_level;
5743 bool prev_nested = state->nested;
5744 state->nested = 1;
5745 state->lhs_level = lhs_pos - 1;
5746 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5747 state->lhs_level = prev_level;
5748 state->nested = prev_nested;
5749
5750 ADD_SEQ(lhs, nest_rhs);
5751 ADD_SEQ(lhs, nest_lhs);
5752 break;
5753 }
5754 case NODE_CDECL:
5755 if (!RNODE_CDECL(node)->nd_vid) {
5756 /* Special handling only needed for expr::C, not for C */
5757 INSN *iobj;
5758
5759 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5760
5761 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5762 iobj = (INSN *)insn_element; /* setconstant insn */
5763 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5764 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5765 ELEM_REMOVE(insn_element);
5766 pre->last = iobj->link.prev;
5767 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5768
5769 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5770 return COMPILE_NG;
5771 }
5772
5773 ADD_INSN(post, node, pop);
5774 break;
5775 }
5776 /* Fallthrough */
5777 default: {
5778 DECL_ANCHOR(anchor);
5779 INIT_ANCHOR(anchor);
5780 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5781 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5782 ADD_SEQ(lhs, anchor);
5783 }
5784 }
5785
5786 return COMPILE_OK;
5787}
5788
5789static int
5790compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5791{
5792 if (lhsn) {
5793 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5794 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5795 }
5796 return COMPILE_OK;
5797}
5798
5799static int
5800compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5801 const NODE *rhsn, const NODE *orig_lhsn)
5802{
5803 VALUE mem[64];
5804 const int memsize = numberof(mem);
5805 int memindex = 0;
5806 int llen = 0, rlen = 0;
5807 int i;
5808 const NODE *lhsn = orig_lhsn;
5809
5810#define MEMORY(v) { \
5811 int i; \
5812 if (memindex == memsize) return 0; \
5813 for (i=0; i<memindex; i++) { \
5814 if (mem[i] == (v)) return 0; \
5815 } \
5816 mem[memindex++] = (v); \
5817}
5818
5819 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5820 return 0;
5821 }
5822
5823 while (lhsn) {
5824 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5825 switch (nd_type(ln)) {
5826 case NODE_LASGN:
5827 case NODE_DASGN:
5828 case NODE_IASGN:
5829 case NODE_CVASGN:
5830 MEMORY(get_nd_vid(ln));
5831 break;
5832 default:
5833 return 0;
5834 }
5835 lhsn = RNODE_LIST(lhsn)->nd_next;
5836 llen++;
5837 }
5838
5839 while (rhsn) {
5840 if (llen <= rlen) {
5841 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5842 }
5843 else {
5844 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5845 }
5846 rhsn = RNODE_LIST(rhsn)->nd_next;
5847 rlen++;
5848 }
5849
5850 if (llen > rlen) {
5851 for (i=0; i<llen-rlen; i++) {
5852 ADD_INSN(ret, orig_lhsn, putnil);
5853 }
5854 }
5855
5856 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5857 return 1;
5858}
5859
5860static int
5861compile_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)
5862{
5863 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5864 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5865 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5866 const NODE *lhsn_count = lhsn;
5867 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5868
5869 int llen = 0;
5870 int lpos = 0;
5871
5872 while (lhsn_count) {
5873 llen++;
5874 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5875 }
5876 while (lhsn) {
5877 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5878 lpos++;
5879 lhsn = RNODE_LIST(lhsn)->nd_next;
5880 }
5881
5882 if (lhs_splat) {
5883 if (nd_type_p(splatn, NODE_POSTARG)) {
5884 /*a, b, *r, p1, p2 */
5885 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5886 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5887 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5888 int ppos = 0;
5889 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5890
5891 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5892
5893 if (NODE_NAMED_REST_P(restn)) {
5894 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5895 }
5896 while (postn) {
5897 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5898 ppos++;
5899 postn = RNODE_LIST(postn)->nd_next;
5900 }
5901 }
5902 else {
5903 /* a, b, *r */
5904 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5905 }
5906 }
5907
5908 if (!state->nested) {
5909 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5910 }
5911
5912 if (!popped) {
5913 ADD_INSN(rhs, node, dup);
5914 }
5915 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5916 return COMPILE_OK;
5917}
5918
5919static int
5920compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5921{
5922 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5923 struct masgn_state state;
5924 state.lhs_level = popped ? 0 : 1;
5925 state.nested = 0;
5926 state.num_args = 0;
5927 state.first_memo = NULL;
5928 state.last_memo = NULL;
5929
5930 DECL_ANCHOR(pre);
5931 INIT_ANCHOR(pre);
5932 DECL_ANCHOR(rhs);
5933 INIT_ANCHOR(rhs);
5934 DECL_ANCHOR(lhs);
5935 INIT_ANCHOR(lhs);
5936 DECL_ANCHOR(post);
5937 INIT_ANCHOR(post);
5938 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5939
5940 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5941 while (memo) {
5942 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5943 for (int i = 0; i < memo->num_args; i++) {
5944 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5945 }
5946 tmp_memo = memo->next;
5947 free(memo);
5948 memo = tmp_memo;
5949 }
5950 CHECK(ok);
5951
5952 ADD_SEQ(ret, pre);
5953 ADD_SEQ(ret, rhs);
5954 ADD_SEQ(ret, lhs);
5955 if (!popped && state.num_args >= 1) {
5956 /* make sure rhs array is returned before popping */
5957 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5958 }
5959 ADD_SEQ(ret, post);
5960 }
5961 return COMPILE_OK;
5962}
5963
5964static VALUE
5965collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5966{
5967 VALUE arr = rb_ary_new();
5968 for (;;) {
5969 switch (nd_type(node)) {
5970 case NODE_CONST:
5971 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5972 return arr;
5973 case NODE_COLON3:
5974 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5975 rb_ary_unshift(arr, ID2SYM(idNULL));
5976 return arr;
5977 case NODE_COLON2:
5978 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5979 node = RNODE_COLON2(node)->nd_head;
5980 break;
5981 default:
5982 return Qfalse;
5983 }
5984 }
5985}
5986
5987static int
5988compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5989 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5990{
5991 switch (nd_type(node)) {
5992 case NODE_CONST:
5993 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5994 ADD_INSN1(body, node, putobject, Qtrue);
5995 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5996 break;
5997 case NODE_COLON3:
5998 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5999 ADD_INSN(body, node, pop);
6000 ADD_INSN1(body, node, putobject, rb_cObject);
6001 ADD_INSN1(body, node, putobject, Qtrue);
6002 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6003 break;
6004 case NODE_COLON2:
6005 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6006 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6007 ADD_INSN1(body, node, putobject, Qfalse);
6008 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6009 break;
6010 default:
6011 CHECK(COMPILE(pref, "const colon2 prefix", node));
6012 break;
6013 }
6014 return COMPILE_OK;
6015}
6016
6017static int
6018compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6019{
6020 if (nd_type_p(cpath, NODE_COLON3)) {
6021 /* toplevel class ::Foo */
6022 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6023 return VM_DEFINECLASS_FLAG_SCOPED;
6024 }
6025 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6026 /* Bar::Foo */
6027 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6028 return VM_DEFINECLASS_FLAG_SCOPED;
6029 }
6030 else {
6031 /* class at cbase Foo */
6032 ADD_INSN1(ret, cpath, putspecialobject,
6033 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6034 return 0;
6035 }
6036}
6037
6038static inline int
6039private_recv_p(const NODE *node)
6040{
6041 NODE *recv = get_nd_recv(node);
6042 if (recv && nd_type_p(recv, NODE_SELF)) {
6043 return RNODE_SELF(recv)->nd_state != 0;
6044 }
6045 return 0;
6046}
6047
6048static void
6049defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6050 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6051
6052static int
6053compile_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);
6054
6055static void
6056defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6057 const NODE *const node, LABEL **lfinish, VALUE needstr,
6058 bool keep_result)
6059{
6060 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6061 enum node_type type;
6062 const int line = nd_line(node);
6063 const NODE *line_node = node;
6064
6065 switch (type = nd_type(node)) {
6066
6067 /* easy literals */
6068 case NODE_NIL:
6069 expr_type = DEFINED_NIL;
6070 break;
6071 case NODE_SELF:
6072 expr_type = DEFINED_SELF;
6073 break;
6074 case NODE_TRUE:
6075 expr_type = DEFINED_TRUE;
6076 break;
6077 case NODE_FALSE:
6078 expr_type = DEFINED_FALSE;
6079 break;
6080
6081 case NODE_HASH:
6082 case NODE_LIST:{
6083 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6084
6085 if (vals) {
6086 do {
6087 if (RNODE_LIST(vals)->nd_head) {
6088 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6089
6090 if (!lfinish[1]) {
6091 lfinish[1] = NEW_LABEL(line);
6092 }
6093 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6094 }
6095 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6096 }
6097 }
6098 /* fall through */
6099 case NODE_STR:
6100 case NODE_SYM:
6101 case NODE_REGX:
6102 case NODE_LINE:
6103 case NODE_FILE:
6104 case NODE_ENCODING:
6105 case NODE_INTEGER:
6106 case NODE_FLOAT:
6107 case NODE_RATIONAL:
6108 case NODE_IMAGINARY:
6109 case NODE_ZLIST:
6110 case NODE_AND:
6111 case NODE_OR:
6112 default:
6113 expr_type = DEFINED_EXPR;
6114 break;
6115
6116 case NODE_SPLAT:
6117 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6118 if (!lfinish[1]) {
6119 lfinish[1] = NEW_LABEL(line);
6120 }
6121 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6122 expr_type = DEFINED_EXPR;
6123 break;
6124
6125 /* variables */
6126 case NODE_LVAR:
6127 case NODE_DVAR:
6128 expr_type = DEFINED_LVAR;
6129 break;
6130
6131#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6132 case NODE_IVAR:
6133 ADD_INSN3(ret, line_node, definedivar,
6134 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6135 return;
6136
6137 case NODE_GVAR:
6138 ADD_INSN(ret, line_node, putnil);
6139 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6140 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6141 return;
6142
6143 case NODE_CVAR:
6144 ADD_INSN(ret, line_node, putnil);
6145 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6146 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6147 return;
6148
6149 case NODE_CONST:
6150 ADD_INSN(ret, line_node, putnil);
6151 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6152 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6153 return;
6154 case NODE_COLON2:
6155 if (!lfinish[1]) {
6156 lfinish[1] = NEW_LABEL(line);
6157 }
6158 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6159 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6160 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6161
6162 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6163 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6164 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6165 }
6166 else {
6167 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6168 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6169 }
6170 return;
6171 case NODE_COLON3:
6172 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6173 ADD_INSN3(ret, line_node, defined,
6174 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6175 return;
6176
6177 /* method dispatch */
6178 case NODE_CALL:
6179 case NODE_OPCALL:
6180 case NODE_VCALL:
6181 case NODE_FCALL:
6182 case NODE_ATTRASGN:{
6183 const int explicit_receiver =
6184 (type == NODE_CALL || type == NODE_OPCALL ||
6185 (type == NODE_ATTRASGN && !private_recv_p(node)));
6186
6187 if (get_nd_args(node) || explicit_receiver) {
6188 if (!lfinish[1]) {
6189 lfinish[1] = NEW_LABEL(line);
6190 }
6191 if (!lfinish[2]) {
6192 lfinish[2] = NEW_LABEL(line);
6193 }
6194 }
6195 if (get_nd_args(node)) {
6196 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6197 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6198 }
6199 if (explicit_receiver) {
6200 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6201 switch (nd_type(get_nd_recv(node))) {
6202 case NODE_CALL:
6203 case NODE_OPCALL:
6204 case NODE_VCALL:
6205 case NODE_FCALL:
6206 case NODE_ATTRASGN:
6207 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6208 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6209 break;
6210 default:
6211 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6212 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6213 break;
6214 }
6215 if (keep_result) {
6216 ADD_INSN(ret, line_node, dup);
6217 }
6218 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6219 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6220 }
6221 else {
6222 ADD_INSN(ret, line_node, putself);
6223 if (keep_result) {
6224 ADD_INSN(ret, line_node, dup);
6225 }
6226 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6227 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6228 }
6229 return;
6230 }
6231
6232 case NODE_YIELD:
6233 ADD_INSN(ret, line_node, putnil);
6234 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6235 PUSH_VAL(DEFINED_YIELD));
6236 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6237 return;
6238
6239 case NODE_BACK_REF:
6240 case NODE_NTH_REF:
6241 ADD_INSN(ret, line_node, putnil);
6242 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6243 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6244 PUSH_VAL(DEFINED_GVAR));
6245 return;
6246
6247 case NODE_SUPER:
6248 case NODE_ZSUPER:
6249 ADD_INSN(ret, line_node, putnil);
6250 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6251 PUSH_VAL(DEFINED_ZSUPER));
6252 return;
6253
6254#undef PUSH_VAL
6255 case NODE_OP_ASGN1:
6256 case NODE_OP_ASGN2:
6257 case NODE_OP_ASGN_OR:
6258 case NODE_OP_ASGN_AND:
6259 case NODE_MASGN:
6260 case NODE_LASGN:
6261 case NODE_DASGN:
6262 case NODE_GASGN:
6263 case NODE_IASGN:
6264 case NODE_CDECL:
6265 case NODE_CVASGN:
6266 case NODE_OP_CDECL:
6267 expr_type = DEFINED_ASGN;
6268 break;
6269 }
6270
6271 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6272
6273 if (needstr != Qfalse) {
6274 VALUE str = rb_iseq_defined_string(expr_type);
6275 ADD_INSN1(ret, line_node, putobject, str);
6276 }
6277 else {
6278 ADD_INSN1(ret, line_node, putobject, Qtrue);
6279 }
6280}
6281
6282static void
6283build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6284{
6285 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6286 iseq_set_exception_local_table(iseq);
6287}
6288
6289static void
6290defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6291 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6292{
6293 LINK_ELEMENT *lcur = ret->last;
6294 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6295 if (lfinish[1]) {
6296 int line = nd_line(node);
6297 LABEL *lstart = NEW_LABEL(line);
6298 LABEL *lend = NEW_LABEL(line);
6299 const rb_iseq_t *rescue;
6301 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6302 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6303 rb_str_concat(rb_str_new2("defined guard in "),
6304 ISEQ_BODY(iseq)->location.label),
6305 ISEQ_TYPE_RESCUE, 0);
6306 lstart->rescued = LABEL_RESCUE_BEG;
6307 lend->rescued = LABEL_RESCUE_END;
6308 APPEND_LABEL(ret, lcur, lstart);
6309 ADD_LABEL(ret, lend);
6310 if (!ignore) {
6311 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6312 }
6313 }
6314}
6315
6316static int
6317compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6318{
6319 const int line = nd_line(node);
6320 const NODE *line_node = node;
6321 if (!RNODE_DEFINED(node)->nd_head) {
6322 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6323 ADD_INSN1(ret, line_node, putobject, str);
6324 }
6325 else {
6326 LABEL *lfinish[3];
6327 LINK_ELEMENT *last = ret->last;
6328 lfinish[0] = NEW_LABEL(line);
6329 lfinish[1] = 0;
6330 lfinish[2] = 0;
6331 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6332 if (lfinish[1]) {
6333 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6334 ADD_INSN(ret, line_node, swap);
6335 if (lfinish[2]) {
6336 ADD_LABEL(ret, lfinish[2]);
6337 }
6338 ADD_INSN(ret, line_node, pop);
6339 ADD_LABEL(ret, lfinish[1]);
6340 }
6341 ADD_LABEL(ret, lfinish[0]);
6342 }
6343 return COMPILE_OK;
6344}
6345
6346static VALUE
6347make_name_for_block(const rb_iseq_t *orig_iseq)
6348{
6349 int level = 1;
6350 const rb_iseq_t *iseq = orig_iseq;
6351
6352 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6353 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6354 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6355 level++;
6356 }
6357 iseq = ISEQ_BODY(iseq)->parent_iseq;
6358 }
6359 }
6360
6361 if (level == 1) {
6362 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6363 }
6364 else {
6365 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6366 }
6367}
6368
6369static void
6370push_ensure_entry(rb_iseq_t *iseq,
6372 struct ensure_range *er, const void *const node)
6373{
6374 enl->ensure_node = node;
6375 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6376 enl->erange = er;
6377 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6378}
6379
6380static void
6381add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6382 LABEL *lstart, LABEL *lend)
6383{
6384 struct ensure_range *ne =
6385 compile_data_alloc(iseq, sizeof(struct ensure_range));
6386
6387 while (erange->next != 0) {
6388 erange = erange->next;
6389 }
6390 ne->next = 0;
6391 ne->begin = lend;
6392 ne->end = erange->end;
6393 erange->end = lstart;
6394
6395 erange->next = ne;
6396}
6397
6398static bool
6399can_add_ensure_iseq(const rb_iseq_t *iseq)
6400{
6402 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6403 while (e) {
6404 if (e->ensure_node) return false;
6405 e = e->prev;
6406 }
6407 }
6408 return true;
6409}
6410
6411static void
6412add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6413{
6414 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6415
6417 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6418 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6419 DECL_ANCHOR(ensure);
6420
6421 INIT_ANCHOR(ensure);
6422 while (enlp) {
6423 if (enlp->erange != NULL) {
6424 DECL_ANCHOR(ensure_part);
6425 LABEL *lstart = NEW_LABEL(0);
6426 LABEL *lend = NEW_LABEL(0);
6427 INIT_ANCHOR(ensure_part);
6428
6429 add_ensure_range(iseq, enlp->erange, lstart, lend);
6430
6431 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6432 ADD_LABEL(ensure_part, lstart);
6433 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6434 ADD_LABEL(ensure_part, lend);
6435 ADD_SEQ(ensure, ensure_part);
6436 }
6437 else {
6438 if (!is_return) {
6439 break;
6440 }
6441 }
6442 enlp = enlp->prev;
6443 }
6444 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6445 ADD_SEQ(ret, ensure);
6446}
6447
6448#if RUBY_DEBUG
6449static int
6450check_keyword(const NODE *node)
6451{
6452 /* This check is essentially a code clone of compile_keyword_arg. */
6453
6454 if (nd_type_p(node, NODE_LIST)) {
6455 while (RNODE_LIST(node)->nd_next) {
6456 node = RNODE_LIST(node)->nd_next;
6457 }
6458 node = RNODE_LIST(node)->nd_head;
6459 }
6460
6461 return keyword_node_p(node);
6462}
6463#endif
6464
6465static bool
6466keyword_node_single_splat_p(NODE *kwnode)
6467{
6468 RUBY_ASSERT(keyword_node_p(kwnode));
6469
6470 NODE *node = RNODE_HASH(kwnode)->nd_head;
6471 return RNODE_LIST(node)->nd_head == NULL &&
6472 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6473}
6474
6475static void
6476compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6477 NODE *kwnode, unsigned int *flag_ptr)
6478{
6479 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6480 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6481 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6482 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6483 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6484}
6485
6486#define SPLATARRAY_FALSE 0
6487#define SPLATARRAY_TRUE 1
6488#define DUP_SINGLE_KW_SPLAT 2
6489
6490static int
6491setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6492 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6493{
6494 if (!argn) return 0;
6495
6496 NODE *kwnode = NULL;
6497
6498 switch (nd_type(argn)) {
6499 case NODE_LIST: {
6500 // f(x, y, z)
6501 int len = compile_args(iseq, args, argn, &kwnode);
6502 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6503
6504 if (kwnode) {
6505 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6506 len -= 1;
6507 }
6508 else {
6509 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6510 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6511 }
6512 else {
6513 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6514 }
6515 }
6516 }
6517
6518 return len;
6519 }
6520 case NODE_SPLAT: {
6521 // f(*a)
6522 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6523 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6524 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6525 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6526 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6527 return 1;
6528 }
6529 case NODE_ARGSCAT: {
6530 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6531 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6532 bool args_pushed = false;
6533
6534 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6535 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6536 if (kwnode) rest_len--;
6537 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6538 args_pushed = true;
6539 }
6540 else {
6541 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6542 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6543 }
6544
6545 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6546 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6547 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6548 argc += 1;
6549 }
6550 else if (!args_pushed) {
6551 ADD_INSN(args, argn, concattoarray);
6552 }
6553
6554 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6555 if (kwnode) {
6556 // kwsplat
6557 *flag_ptr |= VM_CALL_KW_SPLAT;
6558 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6559 argc += 1;
6560 }
6561
6562 return argc;
6563 }
6564 case NODE_ARGSPUSH: {
6565 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6566 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6567
6568 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6569 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6570 if (kwnode) rest_len--;
6571 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6572 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6573 }
6574 else {
6575 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6576 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6577 }
6578 else {
6579 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6580 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6581 }
6582 }
6583
6584 if (kwnode) {
6585 // f(*a, k:1)
6586 *flag_ptr |= VM_CALL_KW_SPLAT;
6587 if (!keyword_node_single_splat_p(kwnode)) {
6588 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6589 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6590 }
6591 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6592 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6593 }
6594 else {
6595 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6596 }
6597 argc += 1;
6598 }
6599
6600 return argc;
6601 }
6602 default: {
6603 UNKNOWN_NODE("setup_arg", argn, Qnil);
6604 }
6605 }
6606}
6607
6608static void
6609setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6610{
6611 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6612 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6613 }
6614}
6615
6616static bool
6617setup_args_dup_rest_p(const NODE *argn)
6618{
6619 switch(nd_type(argn)) {
6620 case NODE_LVAR:
6621 case NODE_DVAR:
6622 case NODE_GVAR:
6623 case NODE_IVAR:
6624 case NODE_CVAR:
6625 case NODE_CONST:
6626 case NODE_COLON3:
6627 case NODE_INTEGER:
6628 case NODE_FLOAT:
6629 case NODE_RATIONAL:
6630 case NODE_IMAGINARY:
6631 case NODE_STR:
6632 case NODE_SYM:
6633 case NODE_REGX:
6634 case NODE_SELF:
6635 case NODE_NIL:
6636 case NODE_TRUE:
6637 case NODE_FALSE:
6638 case NODE_LAMBDA:
6639 case NODE_NTH_REF:
6640 case NODE_BACK_REF:
6641 return false;
6642 case NODE_COLON2:
6643 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6644 case NODE_LIST:
6645 while (argn) {
6646 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6647 return true;
6648 }
6649 argn = RNODE_LIST(argn)->nd_next;
6650 }
6651 return false;
6652 default:
6653 return true;
6654 }
6655}
6656
6657static VALUE
6658setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6659 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6660{
6661 VALUE ret;
6662 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6663
6664 if (argn) {
6665 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6666 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6667
6668 if (check_arg) {
6669 switch(nd_type(check_arg)) {
6670 case(NODE_SPLAT):
6671 // avoid caller side array allocation for f(*arg)
6672 dup_rest = SPLATARRAY_FALSE;
6673 break;
6674 case(NODE_ARGSCAT):
6675 // avoid caller side array allocation for f(1, *arg)
6676 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6677 break;
6678 case(NODE_ARGSPUSH):
6679 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6680 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6681 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6682 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6683 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6684 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6685
6686 if (dup_rest == SPLATARRAY_FALSE) {
6687 // require allocation for keyword key/value/splat that may modify splatted argument
6688 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6689 while (node) {
6690 NODE *key_node = RNODE_LIST(node)->nd_head;
6691 if (key_node && setup_args_dup_rest_p(key_node)) {
6692 dup_rest = SPLATARRAY_TRUE;
6693 break;
6694 }
6695
6696 node = RNODE_LIST(node)->nd_next;
6697 NODE *value_node = RNODE_LIST(node)->nd_head;
6698 if (setup_args_dup_rest_p(value_node)) {
6699 dup_rest = SPLATARRAY_TRUE;
6700 break;
6701 }
6702
6703 node = RNODE_LIST(node)->nd_next;
6704 }
6705 }
6706 break;
6707 default:
6708 break;
6709 }
6710 }
6711
6712 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6713 // for block pass that may modify splatted argument, dup rest and kwrest if given
6714 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6715 }
6716 }
6717 initial_dup_rest = dup_rest;
6718
6719 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6720 DECL_ANCHOR(arg_block);
6721 INIT_ANCHOR(arg_block);
6722
6723 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6724 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6725
6726 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6727 const NODE * arg_node =
6728 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6729
6730 int argc = 0;
6731
6732 // Only compile leading args:
6733 // foo(x, y, ...)
6734 // ^^^^
6735 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6736 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6737 }
6738
6739 *flag |= VM_CALL_FORWARDING;
6740
6741 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6742 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6743 return INT2FIX(argc);
6744 }
6745 else {
6746 *flag |= VM_CALL_ARGS_BLOCKARG;
6747
6748 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6749 }
6750
6751 if (LIST_INSN_SIZE_ONE(arg_block)) {
6752 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6753 if (IS_INSN(elem)) {
6754 INSN *iobj = (INSN *)elem;
6755 if (iobj->insn_id == BIN(getblockparam)) {
6756 iobj->insn_id = BIN(getblockparamproxy);
6757 }
6758 }
6759 }
6760 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6761 ADD_SEQ(args, arg_block);
6762 }
6763 else {
6764 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6765 }
6766 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6767 return ret;
6768}
6769
6770static void
6771build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6772{
6773 const NODE *body = ptr;
6774 int line = nd_line(body);
6775 VALUE argc = INT2FIX(0);
6776 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6777
6778 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6779 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6780 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6781 iseq_set_local_table(iseq, 0, 0);
6782}
6783
6784static void
6785compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6786{
6787 const NODE *vars;
6788 LINK_ELEMENT *last;
6789 int line = nd_line(node);
6790 const NODE *line_node = node;
6791 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6792
6793#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6794 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6795#else
6796 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6797#endif
6798 ADD_INSN(ret, line_node, dup);
6799 ADD_INSNL(ret, line_node, branchunless, fail_label);
6800
6801 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6802 INSN *cap;
6803 if (RNODE_BLOCK(vars)->nd_next) {
6804 ADD_INSN(ret, line_node, dup);
6805 }
6806 last = ret->last;
6807 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6808 last = last->next; /* putobject :var */
6809 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6810 NULL, INT2FIX(0), NULL);
6811 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6812#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6813 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6814 /* only one name */
6815 DECL_ANCHOR(nom);
6816
6817 INIT_ANCHOR(nom);
6818 ADD_INSNL(nom, line_node, jump, end_label);
6819 ADD_LABEL(nom, fail_label);
6820# if 0 /* $~ must be MatchData or nil */
6821 ADD_INSN(nom, line_node, pop);
6822 ADD_INSN(nom, line_node, putnil);
6823# endif
6824 ADD_LABEL(nom, end_label);
6825 (nom->last->next = cap->link.next)->prev = nom->last;
6826 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6827 return;
6828 }
6829#endif
6830 }
6831 ADD_INSNL(ret, line_node, jump, end_label);
6832 ADD_LABEL(ret, fail_label);
6833 ADD_INSN(ret, line_node, pop);
6834 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6835 last = ret->last;
6836 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6837 last = last->next; /* putobject :var */
6838 ((INSN*)last)->insn_id = BIN(putnil);
6839 ((INSN*)last)->operand_size = 0;
6840 }
6841 ADD_LABEL(ret, end_label);
6842}
6843
6844static int
6845optimizable_range_item_p(const NODE *n)
6846{
6847 if (!n) return FALSE;
6848 switch (nd_type(n)) {
6849 case NODE_LINE:
6850 return TRUE;
6851 case NODE_INTEGER:
6852 return TRUE;
6853 case NODE_NIL:
6854 return TRUE;
6855 default:
6856 return FALSE;
6857 }
6858}
6859
6860static VALUE
6861optimized_range_item(const NODE *n)
6862{
6863 switch (nd_type(n)) {
6864 case NODE_LINE:
6865 return rb_node_line_lineno_val(n);
6866 case NODE_INTEGER:
6867 return rb_node_integer_literal_val(n);
6868 case NODE_FLOAT:
6869 return rb_node_float_literal_val(n);
6870 case NODE_RATIONAL:
6871 return rb_node_rational_literal_val(n);
6872 case NODE_IMAGINARY:
6873 return rb_node_imaginary_literal_val(n);
6874 case NODE_NIL:
6875 return Qnil;
6876 default:
6877 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6878 }
6879}
6880
6881static int
6882compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6883{
6884 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6885 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6886
6887 const int line = nd_line(node);
6888 const NODE *line_node = node;
6889 DECL_ANCHOR(cond_seq);
6890 LABEL *then_label, *else_label, *end_label;
6891 VALUE branches = Qfalse;
6892
6893 INIT_ANCHOR(cond_seq);
6894 then_label = NEW_LABEL(line);
6895 else_label = NEW_LABEL(line);
6896 end_label = 0;
6897
6898 NODE *cond = RNODE_IF(node)->nd_cond;
6899 if (nd_type(cond) == NODE_BLOCK) {
6900 cond = RNODE_BLOCK(cond)->nd_head;
6901 }
6902
6903 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6904 ADD_SEQ(ret, cond_seq);
6905
6906 if (then_label->refcnt && else_label->refcnt) {
6907 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6908 }
6909
6910 if (then_label->refcnt) {
6911 ADD_LABEL(ret, then_label);
6912
6913 DECL_ANCHOR(then_seq);
6914 INIT_ANCHOR(then_seq);
6915 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6916
6917 if (else_label->refcnt) {
6918 const NODE *const coverage_node = node_body ? node_body : node;
6919 add_trace_branch_coverage(
6920 iseq,
6921 ret,
6922 nd_code_loc(coverage_node),
6923 nd_node_id(coverage_node),
6924 0,
6925 type == NODE_IF ? "then" : "else",
6926 branches);
6927 end_label = NEW_LABEL(line);
6928 ADD_INSNL(then_seq, line_node, jump, end_label);
6929 if (!popped) {
6930 ADD_INSN(then_seq, line_node, pop);
6931 }
6932 }
6933 ADD_SEQ(ret, then_seq);
6934 }
6935
6936 if (else_label->refcnt) {
6937 ADD_LABEL(ret, else_label);
6938
6939 DECL_ANCHOR(else_seq);
6940 INIT_ANCHOR(else_seq);
6941 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6942
6943 if (then_label->refcnt) {
6944 const NODE *const coverage_node = node_else ? node_else : node;
6945 add_trace_branch_coverage(
6946 iseq,
6947 ret,
6948 nd_code_loc(coverage_node),
6949 nd_node_id(coverage_node),
6950 1,
6951 type == NODE_IF ? "else" : "then",
6952 branches);
6953 }
6954 ADD_SEQ(ret, else_seq);
6955 }
6956
6957 if (end_label) {
6958 ADD_LABEL(ret, end_label);
6959 }
6960
6961 return COMPILE_OK;
6962}
6963
6964static int
6965compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6966{
6967 const NODE *vals;
6968 const NODE *node = orig_node;
6969 LABEL *endlabel, *elselabel;
6970 DECL_ANCHOR(head);
6971 DECL_ANCHOR(body_seq);
6972 DECL_ANCHOR(cond_seq);
6973 int only_special_literals = 1;
6974 VALUE literals = rb_hash_new();
6975 int line;
6976 enum node_type type;
6977 const NODE *line_node;
6978 VALUE branches = Qfalse;
6979 int branch_id = 0;
6980
6981 INIT_ANCHOR(head);
6982 INIT_ANCHOR(body_seq);
6983 INIT_ANCHOR(cond_seq);
6984
6985 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6986
6987 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6988
6989 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6990
6991 node = RNODE_CASE(node)->nd_body;
6992 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6993 type = nd_type(node);
6994 line = nd_line(node);
6995 line_node = node;
6996
6997 endlabel = NEW_LABEL(line);
6998 elselabel = NEW_LABEL(line);
6999
7000 ADD_SEQ(ret, head); /* case VAL */
7001
7002 while (type == NODE_WHEN) {
7003 LABEL *l1;
7004
7005 l1 = NEW_LABEL(line);
7006 ADD_LABEL(body_seq, l1);
7007 ADD_INSN(body_seq, line_node, pop);
7008
7009 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7010 add_trace_branch_coverage(
7011 iseq,
7012 body_seq,
7013 nd_code_loc(coverage_node),
7014 nd_node_id(coverage_node),
7015 branch_id++,
7016 "when",
7017 branches);
7018
7019 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7020 ADD_INSNL(body_seq, line_node, jump, endlabel);
7021
7022 vals = RNODE_WHEN(node)->nd_head;
7023 if (vals) {
7024 switch (nd_type(vals)) {
7025 case NODE_LIST:
7026 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7027 if (only_special_literals < 0) return COMPILE_NG;
7028 break;
7029 case NODE_SPLAT:
7030 case NODE_ARGSCAT:
7031 case NODE_ARGSPUSH:
7032 only_special_literals = 0;
7033 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7034 break;
7035 default:
7036 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7037 }
7038 }
7039 else {
7040 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7041 }
7042
7043 node = RNODE_WHEN(node)->nd_next;
7044 if (!node) {
7045 break;
7046 }
7047 type = nd_type(node);
7048 line = nd_line(node);
7049 line_node = node;
7050 }
7051 /* else */
7052 if (node) {
7053 ADD_LABEL(cond_seq, elselabel);
7054 ADD_INSN(cond_seq, line_node, pop);
7055 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7056 CHECK(COMPILE_(cond_seq, "else", node, popped));
7057 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7058 }
7059 else {
7060 debugs("== else (implicit)\n");
7061 ADD_LABEL(cond_seq, elselabel);
7062 ADD_INSN(cond_seq, orig_node, pop);
7063 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7064 if (!popped) {
7065 ADD_INSN(cond_seq, orig_node, putnil);
7066 }
7067 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7068 }
7069
7070 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7071 ADD_INSN(ret, orig_node, dup);
7072 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7073 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7074 LABEL_REF(elselabel);
7075 }
7076
7077 ADD_SEQ(ret, cond_seq);
7078 ADD_SEQ(ret, body_seq);
7079 ADD_LABEL(ret, endlabel);
7080 return COMPILE_OK;
7081}
7082
7083static int
7084compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7085{
7086 const NODE *vals;
7087 const NODE *val;
7088 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7089 LABEL *endlabel;
7090 DECL_ANCHOR(body_seq);
7091 VALUE branches = Qfalse;
7092 int branch_id = 0;
7093
7094 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7095
7096 INIT_ANCHOR(body_seq);
7097 endlabel = NEW_LABEL(nd_line(node));
7098
7099 while (node && nd_type_p(node, NODE_WHEN)) {
7100 const int line = nd_line(node);
7101 LABEL *l1 = NEW_LABEL(line);
7102 ADD_LABEL(body_seq, l1);
7103
7104 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7105 add_trace_branch_coverage(
7106 iseq,
7107 body_seq,
7108 nd_code_loc(coverage_node),
7109 nd_node_id(coverage_node),
7110 branch_id++,
7111 "when",
7112 branches);
7113
7114 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7115 ADD_INSNL(body_seq, node, jump, endlabel);
7116
7117 vals = RNODE_WHEN(node)->nd_head;
7118 if (!vals) {
7119 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7120 }
7121 switch (nd_type(vals)) {
7122 case NODE_LIST:
7123 while (vals) {
7124 LABEL *lnext;
7125 val = RNODE_LIST(vals)->nd_head;
7126 lnext = NEW_LABEL(nd_line(val));
7127 debug_compile("== when2\n", (void)0);
7128 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7129 ADD_LABEL(ret, lnext);
7130 vals = RNODE_LIST(vals)->nd_next;
7131 }
7132 break;
7133 case NODE_SPLAT:
7134 case NODE_ARGSCAT:
7135 case NODE_ARGSPUSH:
7136 ADD_INSN(ret, vals, putnil);
7137 CHECK(COMPILE(ret, "when2/cond splat", vals));
7138 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7139 ADD_INSNL(ret, vals, branchif, l1);
7140 break;
7141 default:
7142 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7143 }
7144 node = RNODE_WHEN(node)->nd_next;
7145 }
7146 /* else */
7147 const NODE *const coverage_node = node ? node : orig_node;
7148 add_trace_branch_coverage(
7149 iseq,
7150 ret,
7151 nd_code_loc(coverage_node),
7152 nd_node_id(coverage_node),
7153 branch_id,
7154 "else",
7155 branches);
7156 CHECK(COMPILE_(ret, "else", node, popped));
7157 ADD_INSNL(ret, orig_node, jump, endlabel);
7158
7159 ADD_SEQ(ret, body_seq);
7160 ADD_LABEL(ret, endlabel);
7161 return COMPILE_OK;
7162}
7163
7164static 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);
7165
7166static 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);
7167static 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);
7168static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7169static 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);
7170static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7171
7172#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7173#define CASE3_BI_OFFSET_ERROR_STRING 1
7174#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7175#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7176#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7177
7178static int
7179iseq_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)
7180{
7181 const int line = nd_line(node);
7182 const NODE *line_node = node;
7183
7184 switch (nd_type(node)) {
7185 case NODE_ARYPTN: {
7186 /*
7187 * if pattern.use_rest_num?
7188 * rest_num = 0
7189 * end
7190 * if pattern.has_constant_node?
7191 * unless pattern.constant === obj
7192 * goto match_failed
7193 * end
7194 * end
7195 * unless obj.respond_to?(:deconstruct)
7196 * goto match_failed
7197 * end
7198 * d = obj.deconstruct
7199 * unless Array === d
7200 * goto type_error
7201 * end
7202 * min_argc = pattern.pre_args_num + pattern.post_args_num
7203 * if pattern.has_rest_arg?
7204 * unless d.length >= min_argc
7205 * goto match_failed
7206 * end
7207 * else
7208 * unless d.length == min_argc
7209 * goto match_failed
7210 * end
7211 * end
7212 * pattern.pre_args_num.each do |i|
7213 * unless pattern.pre_args[i].match?(d[i])
7214 * goto match_failed
7215 * end
7216 * end
7217 * if pattern.use_rest_num?
7218 * rest_num = d.length - min_argc
7219 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7220 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7221 * goto match_failed
7222 * end
7223 * end
7224 * end
7225 * pattern.post_args_num.each do |i|
7226 * j = pattern.pre_args_num + i
7227 * j += rest_num
7228 * unless pattern.post_args[i].match?(d[j])
7229 * goto match_failed
7230 * end
7231 * end
7232 * goto matched
7233 * type_error:
7234 * FrozenCore.raise TypeError
7235 * match_failed:
7236 * goto unmatched
7237 */
7238 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7239 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7240 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7241
7242 const int min_argc = pre_args_num + post_args_num;
7243 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7244 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7245
7246 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7247 int i;
7248 match_failed = NEW_LABEL(line);
7249 type_error = NEW_LABEL(line);
7250 deconstruct = NEW_LABEL(line);
7251 deconstructed = NEW_LABEL(line);
7252
7253 if (use_rest_num) {
7254 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7255 ADD_INSN(ret, line_node, swap);
7256 if (base_index) {
7257 base_index++;
7258 }
7259 }
7260
7261 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7262
7263 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7264
7265 ADD_INSN(ret, line_node, dup);
7266 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7267 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7268 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7269 if (in_single_pattern) {
7270 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7271 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7272 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7273 INT2FIX(min_argc), base_index + 1 /* (1) */));
7274 }
7275 ADD_INSNL(ret, line_node, branchunless, match_failed);
7276
7277 for (i = 0; i < pre_args_num; i++) {
7278 ADD_INSN(ret, line_node, dup);
7279 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7280 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7281 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));
7282 args = RNODE_LIST(args)->nd_next;
7283 }
7284
7285 if (RNODE_ARYPTN(node)->rest_arg) {
7286 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7287 ADD_INSN(ret, line_node, dup);
7288 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7289 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7290 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7291 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7292 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7293 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7294 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7295
7296 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));
7297 }
7298 else {
7299 if (post_args_num > 0) {
7300 ADD_INSN(ret, line_node, dup);
7301 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7302 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7303 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7304 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7305 ADD_INSN(ret, line_node, pop);
7306 }
7307 }
7308 }
7309
7310 args = RNODE_ARYPTN(node)->post_args;
7311 for (i = 0; i < post_args_num; i++) {
7312 ADD_INSN(ret, line_node, dup);
7313
7314 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7315 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7316 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7317
7318 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7319 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));
7320 args = RNODE_LIST(args)->nd_next;
7321 }
7322
7323 ADD_INSN(ret, line_node, pop);
7324 if (use_rest_num) {
7325 ADD_INSN(ret, line_node, pop);
7326 }
7327 ADD_INSNL(ret, line_node, jump, matched);
7328 ADD_INSN(ret, line_node, putnil);
7329 if (use_rest_num) {
7330 ADD_INSN(ret, line_node, putnil);
7331 }
7332
7333 ADD_LABEL(ret, type_error);
7334 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7335 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7336 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7337 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7338 ADD_INSN(ret, line_node, pop);
7339
7340 ADD_LABEL(ret, match_failed);
7341 ADD_INSN(ret, line_node, pop);
7342 if (use_rest_num) {
7343 ADD_INSN(ret, line_node, pop);
7344 }
7345 ADD_INSNL(ret, line_node, jump, unmatched);
7346
7347 break;
7348 }
7349 case NODE_FNDPTN: {
7350 /*
7351 * if pattern.has_constant_node?
7352 * unless pattern.constant === obj
7353 * goto match_failed
7354 * end
7355 * end
7356 * unless obj.respond_to?(:deconstruct)
7357 * goto match_failed
7358 * end
7359 * d = obj.deconstruct
7360 * unless Array === d
7361 * goto type_error
7362 * end
7363 * unless d.length >= pattern.args_num
7364 * goto match_failed
7365 * end
7366 *
7367 * begin
7368 * len = d.length
7369 * limit = d.length - pattern.args_num
7370 * i = 0
7371 * while i <= limit
7372 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7373 * if pattern.has_pre_rest_arg_id
7374 * unless pattern.pre_rest_arg.match?(d[0, i])
7375 * goto find_failed
7376 * end
7377 * end
7378 * if pattern.has_post_rest_arg_id
7379 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7380 * goto find_failed
7381 * end
7382 * end
7383 * goto find_succeeded
7384 * end
7385 * i+=1
7386 * end
7387 * find_failed:
7388 * goto match_failed
7389 * find_succeeded:
7390 * end
7391 *
7392 * goto matched
7393 * type_error:
7394 * FrozenCore.raise TypeError
7395 * match_failed:
7396 * goto unmatched
7397 */
7398 const NODE *args = RNODE_FNDPTN(node)->args;
7399 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7400
7401 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7402 match_failed = NEW_LABEL(line);
7403 type_error = NEW_LABEL(line);
7404 deconstruct = NEW_LABEL(line);
7405 deconstructed = NEW_LABEL(line);
7406
7407 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7408
7409 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7410
7411 ADD_INSN(ret, line_node, dup);
7412 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7413 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7414 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7415 if (in_single_pattern) {
7416 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) */));
7417 }
7418 ADD_INSNL(ret, line_node, branchunless, match_failed);
7419
7420 {
7421 LABEL *while_begin = NEW_LABEL(nd_line(node));
7422 LABEL *next_loop = NEW_LABEL(nd_line(node));
7423 LABEL *find_succeeded = NEW_LABEL(line);
7424 LABEL *find_failed = NEW_LABEL(nd_line(node));
7425 int j;
7426
7427 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7428 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7429
7430 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7431 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7432 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7433
7434 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7435
7436 ADD_LABEL(ret, while_begin);
7437
7438 ADD_INSN(ret, line_node, dup);
7439 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7440 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7441 ADD_INSNL(ret, line_node, branchunless, find_failed);
7442
7443 for (j = 0; j < args_num; j++) {
7444 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7445 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7446 if (j != 0) {
7447 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7448 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7449 }
7450 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7451
7452 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));
7453 args = RNODE_LIST(args)->nd_next;
7454 }
7455
7456 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7457 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7458 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7459 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7460 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7461 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));
7462 }
7463 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7464 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7465 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7466 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7467 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7468 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7469 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7470 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));
7471 }
7472 ADD_INSNL(ret, line_node, jump, find_succeeded);
7473
7474 ADD_LABEL(ret, next_loop);
7475 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7476 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7477 ADD_INSNL(ret, line_node, jump, while_begin);
7478
7479 ADD_LABEL(ret, find_failed);
7480 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7481 if (in_single_pattern) {
7482 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7483 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7484 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7485 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7486 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7487
7488 ADD_INSN1(ret, line_node, putobject, Qfalse);
7489 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7490
7491 ADD_INSN(ret, line_node, pop);
7492 ADD_INSN(ret, line_node, pop);
7493 }
7494 ADD_INSNL(ret, line_node, jump, match_failed);
7495 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7496
7497 ADD_LABEL(ret, find_succeeded);
7498 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7499 }
7500
7501 ADD_INSN(ret, line_node, pop);
7502 ADD_INSNL(ret, line_node, jump, matched);
7503 ADD_INSN(ret, line_node, putnil);
7504
7505 ADD_LABEL(ret, type_error);
7506 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7507 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7508 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7509 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7510 ADD_INSN(ret, line_node, pop);
7511
7512 ADD_LABEL(ret, match_failed);
7513 ADD_INSN(ret, line_node, pop);
7514 ADD_INSNL(ret, line_node, jump, unmatched);
7515
7516 break;
7517 }
7518 case NODE_HSHPTN: {
7519 /*
7520 * keys = nil
7521 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7522 * keys = pattern.kw_args_node.keys
7523 * end
7524 * if pattern.has_constant_node?
7525 * unless pattern.constant === obj
7526 * goto match_failed
7527 * end
7528 * end
7529 * unless obj.respond_to?(:deconstruct_keys)
7530 * goto match_failed
7531 * end
7532 * d = obj.deconstruct_keys(keys)
7533 * unless Hash === d
7534 * goto type_error
7535 * end
7536 * if pattern.has_kw_rest_arg_node?
7537 * d = d.dup
7538 * end
7539 * if pattern.has_kw_args_node?
7540 * pattern.kw_args_node.each |k,|
7541 * unless d.key?(k)
7542 * goto match_failed
7543 * end
7544 * end
7545 * pattern.kw_args_node.each |k, pat|
7546 * if pattern.has_kw_rest_arg_node?
7547 * unless pat.match?(d.delete(k))
7548 * goto match_failed
7549 * end
7550 * else
7551 * unless pat.match?(d[k])
7552 * goto match_failed
7553 * end
7554 * end
7555 * end
7556 * else
7557 * unless d.empty?
7558 * goto match_failed
7559 * end
7560 * end
7561 * if pattern.has_kw_rest_arg_node?
7562 * if pattern.no_rest_keyword?
7563 * unless d.empty?
7564 * goto match_failed
7565 * end
7566 * else
7567 * unless pattern.kw_rest_arg_node.match?(d)
7568 * goto match_failed
7569 * end
7570 * end
7571 * end
7572 * goto matched
7573 * type_error:
7574 * FrozenCore.raise TypeError
7575 * match_failed:
7576 * goto unmatched
7577 */
7578 LABEL *match_failed, *type_error;
7579 VALUE keys = Qnil;
7580
7581 match_failed = NEW_LABEL(line);
7582 type_error = NEW_LABEL(line);
7583
7584 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7585 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7586 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7587 while (kw_args) {
7588 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7589 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7590 }
7591 }
7592
7593 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7594
7595 ADD_INSN(ret, line_node, dup);
7596 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7597 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7598 if (in_single_pattern) {
7599 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7600 }
7601 ADD_INSNL(ret, line_node, branchunless, match_failed);
7602
7603 if (NIL_P(keys)) {
7604 ADD_INSN(ret, line_node, putnil);
7605 }
7606 else {
7607 ADD_INSN1(ret, line_node, duparray, keys);
7608 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7609 }
7610 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7611
7612 ADD_INSN(ret, line_node, dup);
7613 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7614 ADD_INSNL(ret, line_node, branchunless, type_error);
7615
7616 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7617 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7618 }
7619
7620 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7621 int i;
7622 int keys_num;
7623 const NODE *args;
7624 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7625 if (args) {
7626 DECL_ANCHOR(match_values);
7627 INIT_ANCHOR(match_values);
7628 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7629 for (i = 0; i < keys_num; i++) {
7630 NODE *key_node = RNODE_LIST(args)->nd_head;
7631 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7632 VALUE key = get_symbol_value(iseq, key_node);
7633
7634 ADD_INSN(ret, line_node, dup);
7635 ADD_INSN1(ret, line_node, putobject, key);
7636 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7637 if (in_single_pattern) {
7638 LABEL *match_succeeded;
7639 match_succeeded = NEW_LABEL(line);
7640
7641 ADD_INSN(ret, line_node, dup);
7642 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7643
7644 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7645 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7646 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7647 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7648 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7649 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7650 ADD_INSN1(ret, line_node, putobject, key); // (7)
7651 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7652
7653 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7654
7655 ADD_LABEL(ret, match_succeeded);
7656 }
7657 ADD_INSNL(ret, line_node, branchunless, match_failed);
7658
7659 ADD_INSN(match_values, line_node, dup);
7660 ADD_INSN1(match_values, line_node, putobject, key);
7661 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7662 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7663 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7664 }
7665 ADD_SEQ(ret, match_values);
7666 }
7667 }
7668 else {
7669 ADD_INSN(ret, line_node, dup);
7670 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7671 if (in_single_pattern) {
7672 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7673 }
7674 ADD_INSNL(ret, line_node, branchunless, match_failed);
7675 }
7676
7677 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7678 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7679 ADD_INSN(ret, line_node, dup);
7680 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7681 if (in_single_pattern) {
7682 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7683 }
7684 ADD_INSNL(ret, line_node, branchunless, match_failed);
7685 }
7686 else {
7687 ADD_INSN(ret, line_node, dup); // (11)
7688 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));
7689 }
7690 }
7691
7692 ADD_INSN(ret, line_node, pop);
7693 ADD_INSNL(ret, line_node, jump, matched);
7694 ADD_INSN(ret, line_node, putnil);
7695
7696 ADD_LABEL(ret, type_error);
7697 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7698 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7699 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7700 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7701 ADD_INSN(ret, line_node, pop);
7702
7703 ADD_LABEL(ret, match_failed);
7704 ADD_INSN(ret, line_node, pop);
7705 ADD_INSNL(ret, line_node, jump, unmatched);
7706 break;
7707 }
7708 case NODE_SYM:
7709 case NODE_REGX:
7710 case NODE_LINE:
7711 case NODE_INTEGER:
7712 case NODE_FLOAT:
7713 case NODE_RATIONAL:
7714 case NODE_IMAGINARY:
7715 case NODE_FILE:
7716 case NODE_ENCODING:
7717 case NODE_STR:
7718 case NODE_XSTR:
7719 case NODE_DSTR:
7720 case NODE_DSYM:
7721 case NODE_DREGX:
7722 case NODE_LIST:
7723 case NODE_ZLIST:
7724 case NODE_LAMBDA:
7725 case NODE_DOT2:
7726 case NODE_DOT3:
7727 case NODE_CONST:
7728 case NODE_LVAR:
7729 case NODE_DVAR:
7730 case NODE_IVAR:
7731 case NODE_CVAR:
7732 case NODE_GVAR:
7733 case NODE_TRUE:
7734 case NODE_FALSE:
7735 case NODE_SELF:
7736 case NODE_NIL:
7737 case NODE_COLON2:
7738 case NODE_COLON3:
7739 case NODE_BEGIN:
7740 case NODE_BLOCK:
7741 case NODE_ONCE:
7742 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7743 if (in_single_pattern) {
7744 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7745 }
7746 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7747 if (in_single_pattern) {
7748 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7749 }
7750 ADD_INSNL(ret, line_node, branchif, matched);
7751 ADD_INSNL(ret, line_node, jump, unmatched);
7752 break;
7753 case NODE_LASGN: {
7754 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7755 ID id = RNODE_LASGN(node)->nd_vid;
7756 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7757
7758 if (in_alt_pattern) {
7759 const char *name = rb_id2name(id);
7760 if (name && strlen(name) > 0 && name[0] != '_') {
7761 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7762 rb_id2str(id));
7763 return COMPILE_NG;
7764 }
7765 }
7766
7767 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7768 ADD_INSNL(ret, line_node, jump, matched);
7769 break;
7770 }
7771 case NODE_DASGN: {
7772 int idx, lv, ls;
7773 ID id = RNODE_DASGN(node)->nd_vid;
7774
7775 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7776
7777 if (in_alt_pattern) {
7778 const char *name = rb_id2name(id);
7779 if (name && strlen(name) > 0 && name[0] != '_') {
7780 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7781 rb_id2str(id));
7782 return COMPILE_NG;
7783 }
7784 }
7785
7786 if (idx < 0) {
7787 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7788 rb_id2str(id));
7789 return COMPILE_NG;
7790 }
7791 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7792 ADD_INSNL(ret, line_node, jump, matched);
7793 break;
7794 }
7795 case NODE_IF:
7796 case NODE_UNLESS: {
7797 LABEL *match_failed;
7798 match_failed = unmatched;
7799 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7800 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7801 if (in_single_pattern) {
7802 LABEL *match_succeeded;
7803 match_succeeded = NEW_LABEL(line);
7804
7805 ADD_INSN(ret, line_node, dup);
7806 if (nd_type_p(node, NODE_IF)) {
7807 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7808 }
7809 else {
7810 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7811 }
7812
7813 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7814 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7815 ADD_INSN1(ret, line_node, putobject, Qfalse);
7816 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7817
7818 ADD_INSN(ret, line_node, pop);
7819 ADD_INSN(ret, line_node, pop);
7820
7821 ADD_LABEL(ret, match_succeeded);
7822 }
7823 if (nd_type_p(node, NODE_IF)) {
7824 ADD_INSNL(ret, line_node, branchunless, match_failed);
7825 }
7826 else {
7827 ADD_INSNL(ret, line_node, branchif, match_failed);
7828 }
7829 ADD_INSNL(ret, line_node, jump, matched);
7830 break;
7831 }
7832 case NODE_HASH: {
7833 NODE *n;
7834 LABEL *match_failed;
7835 match_failed = NEW_LABEL(line);
7836
7837 n = RNODE_HASH(node)->nd_head;
7838 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7839 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7840 return COMPILE_NG;
7841 }
7842
7843 ADD_INSN(ret, line_node, dup); // (1)
7844 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));
7845 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));
7846 ADD_INSN(ret, line_node, putnil);
7847
7848 ADD_LABEL(ret, match_failed);
7849 ADD_INSN(ret, line_node, pop);
7850 ADD_INSNL(ret, line_node, jump, unmatched);
7851 break;
7852 }
7853 case NODE_OR: {
7854 LABEL *match_succeeded, *fin;
7855 match_succeeded = NEW_LABEL(line);
7856 fin = NEW_LABEL(line);
7857
7858 ADD_INSN(ret, line_node, dup); // (1)
7859 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));
7860 ADD_LABEL(ret, match_succeeded);
7861 ADD_INSN(ret, line_node, pop);
7862 ADD_INSNL(ret, line_node, jump, matched);
7863 ADD_INSN(ret, line_node, putnil);
7864 ADD_LABEL(ret, fin);
7865 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7866 break;
7867 }
7868 default:
7869 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7870 }
7871 return COMPILE_OK;
7872}
7873
7874static int
7875iseq_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)
7876{
7877 LABEL *fin = NEW_LABEL(nd_line(node));
7878 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7879 ADD_LABEL(ret, fin);
7880 return COMPILE_OK;
7881}
7882
7883static int
7884iseq_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)
7885{
7886 const NODE *line_node = node;
7887
7888 if (RNODE_ARYPTN(node)->nd_pconst) {
7889 ADD_INSN(ret, line_node, dup); // (1)
7890 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7891 if (in_single_pattern) {
7892 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7893 }
7894 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7895 if (in_single_pattern) {
7896 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7897 }
7898 ADD_INSNL(ret, line_node, branchunless, match_failed);
7899 }
7900 return COMPILE_OK;
7901}
7902
7903
7904static int
7905iseq_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)
7906{
7907 const NODE *line_node = node;
7908
7909 // NOTE: this optimization allows us to re-use the #deconstruct value
7910 // (or its absence).
7911 if (use_deconstructed_cache) {
7912 // If value is nil then we haven't tried to deconstruct
7913 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7914 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7915
7916 // If false then the value is not deconstructable
7917 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7918 ADD_INSNL(ret, line_node, branchunless, match_failed);
7919
7920 // Drop value, add deconstructed to the stack and jump
7921 ADD_INSN(ret, line_node, pop); // (1)
7922 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7923 ADD_INSNL(ret, line_node, jump, deconstructed);
7924 }
7925 else {
7926 ADD_INSNL(ret, line_node, jump, deconstruct);
7927 }
7928
7929 ADD_LABEL(ret, deconstruct);
7930 ADD_INSN(ret, line_node, dup);
7931 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7932 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7933
7934 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7935 if (use_deconstructed_cache) {
7936 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7937 }
7938
7939 if (in_single_pattern) {
7940 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7941 }
7942
7943 ADD_INSNL(ret, line_node, branchunless, match_failed);
7944
7945 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7946
7947 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7948 if (use_deconstructed_cache) {
7949 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7950 }
7951
7952 ADD_INSN(ret, line_node, dup);
7953 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7954 ADD_INSNL(ret, line_node, branchunless, type_error);
7955
7956 ADD_LABEL(ret, deconstructed);
7957
7958 return COMPILE_OK;
7959}
7960
7961static int
7962iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7963{
7964 /*
7965 * if match_succeeded?
7966 * goto match_succeeded
7967 * end
7968 * error_string = FrozenCore.sprintf(errmsg, matchee)
7969 * key_error_p = false
7970 * match_succeeded:
7971 */
7972 const int line = nd_line(node);
7973 const NODE *line_node = node;
7974 LABEL *match_succeeded = NEW_LABEL(line);
7975
7976 ADD_INSN(ret, line_node, dup);
7977 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7978
7979 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7980 ADD_INSN1(ret, line_node, putobject, errmsg);
7981 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7982 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7983 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7984
7985 ADD_INSN1(ret, line_node, putobject, Qfalse);
7986 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7987
7988 ADD_INSN(ret, line_node, pop);
7989 ADD_INSN(ret, line_node, pop);
7990 ADD_LABEL(ret, match_succeeded);
7991
7992 return COMPILE_OK;
7993}
7994
7995static int
7996iseq_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)
7997{
7998 /*
7999 * if match_succeeded?
8000 * goto match_succeeded
8001 * end
8002 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8003 * key_error_p = false
8004 * match_succeeded:
8005 */
8006 const int line = nd_line(node);
8007 const NODE *line_node = node;
8008 LABEL *match_succeeded = NEW_LABEL(line);
8009
8010 ADD_INSN(ret, line_node, dup);
8011 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8012
8013 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8014 ADD_INSN1(ret, line_node, putobject, errmsg);
8015 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8016 ADD_INSN(ret, line_node, dup);
8017 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8018 ADD_INSN1(ret, line_node, putobject, pattern_length);
8019 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8020 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8021
8022 ADD_INSN1(ret, line_node, putobject, Qfalse);
8023 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8024
8025 ADD_INSN(ret, line_node, pop);
8026 ADD_INSN(ret, line_node, pop);
8027 ADD_LABEL(ret, match_succeeded);
8028
8029 return COMPILE_OK;
8030}
8031
8032static int
8033iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8034{
8035 /*
8036 * if match_succeeded?
8037 * goto match_succeeded
8038 * end
8039 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8040 * key_error_p = false
8041 * match_succeeded:
8042 */
8043 const int line = nd_line(node);
8044 const NODE *line_node = node;
8045 LABEL *match_succeeded = NEW_LABEL(line);
8046
8047 ADD_INSN(ret, line_node, dup);
8048 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8049
8050 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8051 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8052 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8053 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8054 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8055 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8056
8057 ADD_INSN1(ret, line_node, putobject, Qfalse);
8058 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8059
8060 ADD_INSN(ret, line_node, pop);
8061 ADD_INSN(ret, line_node, pop);
8062
8063 ADD_LABEL(ret, match_succeeded);
8064 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8065 ADD_INSN(ret, line_node, pop);
8066 ADD_INSN(ret, line_node, pop);
8067
8068 return COMPILE_OK;
8069}
8070
8071static int
8072compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8073{
8074 const NODE *pattern;
8075 const NODE *node = orig_node;
8076 LABEL *endlabel, *elselabel;
8077 DECL_ANCHOR(head);
8078 DECL_ANCHOR(body_seq);
8079 DECL_ANCHOR(cond_seq);
8080 int line;
8081 enum node_type type;
8082 const NODE *line_node;
8083 VALUE branches = 0;
8084 int branch_id = 0;
8085 bool single_pattern;
8086
8087 INIT_ANCHOR(head);
8088 INIT_ANCHOR(body_seq);
8089 INIT_ANCHOR(cond_seq);
8090
8091 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8092
8093 node = RNODE_CASE3(node)->nd_body;
8094 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8095 type = nd_type(node);
8096 line = nd_line(node);
8097 line_node = node;
8098 single_pattern = !RNODE_IN(node)->nd_next;
8099
8100 endlabel = NEW_LABEL(line);
8101 elselabel = NEW_LABEL(line);
8102
8103 if (single_pattern) {
8104 /* allocate stack for ... */
8105 ADD_INSN(head, line_node, putnil); /* key_error_key */
8106 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8107 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8108 ADD_INSN(head, line_node, putnil); /* error_string */
8109 }
8110 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8111
8112 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8113
8114 ADD_SEQ(ret, head); /* case VAL */
8115
8116 while (type == NODE_IN) {
8117 LABEL *l1;
8118
8119 if (branch_id) {
8120 ADD_INSN(body_seq, line_node, putnil);
8121 }
8122 l1 = NEW_LABEL(line);
8123 ADD_LABEL(body_seq, l1);
8124 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8125
8126 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8127 add_trace_branch_coverage(
8128 iseq,
8129 body_seq,
8130 nd_code_loc(coverage_node),
8131 nd_node_id(coverage_node),
8132 branch_id++,
8133 "in",
8134 branches);
8135
8136 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8137 ADD_INSNL(body_seq, line_node, jump, endlabel);
8138
8139 pattern = RNODE_IN(node)->nd_head;
8140 if (pattern) {
8141 int pat_line = nd_line(pattern);
8142 LABEL *next_pat = NEW_LABEL(pat_line);
8143 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8144 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8145 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8146 ADD_LABEL(cond_seq, next_pat);
8147 LABEL_UNREMOVABLE(next_pat);
8148 }
8149 else {
8150 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8151 return COMPILE_NG;
8152 }
8153
8154 node = RNODE_IN(node)->nd_next;
8155 if (!node) {
8156 break;
8157 }
8158 type = nd_type(node);
8159 line = nd_line(node);
8160 line_node = node;
8161 }
8162 /* else */
8163 if (node) {
8164 ADD_LABEL(cond_seq, elselabel);
8165 ADD_INSN(cond_seq, line_node, pop);
8166 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8167 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8168 CHECK(COMPILE_(cond_seq, "else", node, popped));
8169 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8170 ADD_INSN(cond_seq, line_node, putnil);
8171 if (popped) {
8172 ADD_INSN(cond_seq, line_node, putnil);
8173 }
8174 }
8175 else {
8176 debugs("== else (implicit)\n");
8177 ADD_LABEL(cond_seq, elselabel);
8178 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8179 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8180
8181 if (single_pattern) {
8182 /*
8183 * if key_error_p
8184 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8185 * else
8186 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8187 * end
8188 */
8189 LABEL *key_error, *fin;
8190 struct rb_callinfo_kwarg *kw_arg;
8191
8192 key_error = NEW_LABEL(line);
8193 fin = NEW_LABEL(line);
8194
8195 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8196 kw_arg->references = 0;
8197 kw_arg->keyword_len = 2;
8198 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8199 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8200
8201 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8202 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8203 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8204 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8205 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8206 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8207 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8208 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8209 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8210 ADD_INSNL(cond_seq, orig_node, jump, fin);
8211
8212 ADD_LABEL(cond_seq, key_error);
8213 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8214 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8215 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8216 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8217 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8218 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8219 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8220 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8221 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8222 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8223
8224 ADD_LABEL(cond_seq, fin);
8225 }
8226 else {
8227 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8228 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8229 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8230 }
8231 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8232 if (!popped) {
8233 ADD_INSN(cond_seq, orig_node, putnil);
8234 }
8235 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8236 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8237 if (popped) {
8238 ADD_INSN(cond_seq, line_node, putnil);
8239 }
8240 }
8241
8242 ADD_SEQ(ret, cond_seq);
8243 ADD_SEQ(ret, body_seq);
8244 ADD_LABEL(ret, endlabel);
8245 return COMPILE_OK;
8246}
8247
8248#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8249#undef CASE3_BI_OFFSET_ERROR_STRING
8250#undef CASE3_BI_OFFSET_KEY_ERROR_P
8251#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8252#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8253
8254static int
8255compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8256{
8257 const int line = (int)nd_line(node);
8258 const NODE *line_node = node;
8259
8260 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8261 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8262 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8263 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8264 VALUE branches = Qfalse;
8265
8267
8268 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8269 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8270 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8271 LABEL *end_label = NEW_LABEL(line);
8272 LABEL *adjust_label = NEW_LABEL(line);
8273
8274 LABEL *next_catch_label = NEW_LABEL(line);
8275 LABEL *tmp_label = NULL;
8276
8277 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8278 push_ensure_entry(iseq, &enl, NULL, NULL);
8279
8280 if (RNODE_WHILE(node)->nd_state == 1) {
8281 ADD_INSNL(ret, line_node, jump, next_label);
8282 }
8283 else {
8284 tmp_label = NEW_LABEL(line);
8285 ADD_INSNL(ret, line_node, jump, tmp_label);
8286 }
8287 ADD_LABEL(ret, adjust_label);
8288 ADD_INSN(ret, line_node, putnil);
8289 ADD_LABEL(ret, next_catch_label);
8290 ADD_INSN(ret, line_node, pop);
8291 ADD_INSNL(ret, line_node, jump, next_label);
8292 if (tmp_label) ADD_LABEL(ret, tmp_label);
8293
8294 ADD_LABEL(ret, redo_label);
8295 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8296
8297 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8298 add_trace_branch_coverage(
8299 iseq,
8300 ret,
8301 nd_code_loc(coverage_node),
8302 nd_node_id(coverage_node),
8303 0,
8304 "body",
8305 branches);
8306
8307 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8308 ADD_LABEL(ret, next_label); /* next */
8309
8310 if (type == NODE_WHILE) {
8311 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8312 redo_label, end_label));
8313 }
8314 else {
8315 /* until */
8316 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8317 end_label, redo_label));
8318 }
8319
8320 ADD_LABEL(ret, end_label);
8321 ADD_ADJUST_RESTORE(ret, adjust_label);
8322
8323 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8324 /* ADD_INSN(ret, line_node, putundef); */
8325 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8326 return COMPILE_NG;
8327 }
8328 else {
8329 ADD_INSN(ret, line_node, putnil);
8330 }
8331
8332 ADD_LABEL(ret, break_label); /* break */
8333
8334 if (popped) {
8335 ADD_INSN(ret, line_node, pop);
8336 }
8337
8338 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8339 break_label);
8340 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8341 next_catch_label);
8342 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8343 ISEQ_COMPILE_DATA(iseq)->redo_label);
8344
8345 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8346 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8347 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8348 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8349 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8350 return COMPILE_OK;
8351}
8352
8353static int
8354compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8355{
8356 const int line = nd_line(node);
8357 const NODE *line_node = node;
8358 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8359 LABEL *retry_label = NEW_LABEL(line);
8360 LABEL *retry_end_l = NEW_LABEL(line);
8361 const rb_iseq_t *child_iseq;
8362
8363 ADD_LABEL(ret, retry_label);
8364 if (nd_type_p(node, NODE_FOR)) {
8365 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8366
8367 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8368 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8369 ISEQ_TYPE_BLOCK, line);
8370 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8371 }
8372 else {
8373 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8374 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8375 ISEQ_TYPE_BLOCK, line);
8376 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8377 }
8378
8379 {
8380 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8381 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8382 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8383 //
8384 // Normally, "send" instruction is at the last.
8385 // However, qcall under branch coverage measurement adds some instructions after the "send".
8386 //
8387 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8388 INSN *iobj;
8389 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8390 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8391 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8392 iobj = (INSN*) get_prev_insn(iobj);
8393 }
8394 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8395
8396 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8397 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8398 if (&iobj->link == LAST_ELEMENT(ret)) {
8399 ret->last = (LINK_ELEMENT*) retry_end_l;
8400 }
8401 }
8402
8403 if (popped) {
8404 ADD_INSN(ret, line_node, pop);
8405 }
8406
8407 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8408
8409 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8410 return COMPILE_OK;
8411}
8412
8413static int
8414compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8415{
8416 /* massign to var in "for"
8417 * (args.length == 1 && Array.try_convert(args[0])) || args
8418 */
8419 const NODE *line_node = node;
8420 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8421 LABEL *not_single = NEW_LABEL(nd_line(var));
8422 LABEL *not_ary = NEW_LABEL(nd_line(var));
8423 CHECK(COMPILE(ret, "for var", var));
8424 ADD_INSN(ret, line_node, dup);
8425 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8426 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8427 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8428 ADD_INSNL(ret, line_node, branchunless, not_single);
8429 ADD_INSN(ret, line_node, dup);
8430 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8431 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8432 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8433 ADD_INSN(ret, line_node, swap);
8434 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8435 ADD_INSN(ret, line_node, dup);
8436 ADD_INSNL(ret, line_node, branchunless, not_ary);
8437 ADD_INSN(ret, line_node, swap);
8438 ADD_LABEL(ret, not_ary);
8439 ADD_INSN(ret, line_node, pop);
8440 ADD_LABEL(ret, not_single);
8441 return COMPILE_OK;
8442}
8443
8444static int
8445compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8446{
8447 const NODE *line_node = node;
8448 unsigned long throw_flag = 0;
8449
8450 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8451 /* while/until */
8452 LABEL *splabel = NEW_LABEL(0);
8453 ADD_LABEL(ret, splabel);
8454 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8455 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8456 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8457 add_ensure_iseq(ret, iseq, 0);
8458 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8459 ADD_ADJUST_RESTORE(ret, splabel);
8460
8461 if (!popped) {
8462 ADD_INSN(ret, line_node, putnil);
8463 }
8464 }
8465 else {
8466 const rb_iseq_t *ip = iseq;
8467
8468 while (ip) {
8469 if (!ISEQ_COMPILE_DATA(ip)) {
8470 ip = 0;
8471 break;
8472 }
8473
8474 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8475 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8476 }
8477 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8478 throw_flag = 0;
8479 }
8480 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8481 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8482 return COMPILE_NG;
8483 }
8484 else {
8485 ip = ISEQ_BODY(ip)->parent_iseq;
8486 continue;
8487 }
8488
8489 /* escape from block */
8490 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8491 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8492 if (popped) {
8493 ADD_INSN(ret, line_node, pop);
8494 }
8495 return COMPILE_OK;
8496 }
8497 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8498 return COMPILE_NG;
8499 }
8500 return COMPILE_OK;
8501}
8502
8503static int
8504compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8505{
8506 const NODE *line_node = node;
8507 unsigned long throw_flag = 0;
8508
8509 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8510 LABEL *splabel = NEW_LABEL(0);
8511 debugs("next in while loop\n");
8512 ADD_LABEL(ret, splabel);
8513 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8514 add_ensure_iseq(ret, iseq, 0);
8515 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8516 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8517 ADD_ADJUST_RESTORE(ret, splabel);
8518 if (!popped) {
8519 ADD_INSN(ret, line_node, putnil);
8520 }
8521 }
8522 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8523 LABEL *splabel = NEW_LABEL(0);
8524 debugs("next in block\n");
8525 ADD_LABEL(ret, splabel);
8526 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8527 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8528 add_ensure_iseq(ret, iseq, 0);
8529 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8530 ADD_ADJUST_RESTORE(ret, splabel);
8531
8532 if (!popped) {
8533 ADD_INSN(ret, line_node, putnil);
8534 }
8535 }
8536 else {
8537 const rb_iseq_t *ip = iseq;
8538
8539 while (ip) {
8540 if (!ISEQ_COMPILE_DATA(ip)) {
8541 ip = 0;
8542 break;
8543 }
8544
8545 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8546 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8547 /* while loop */
8548 break;
8549 }
8550 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8551 break;
8552 }
8553 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8554 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8555 return COMPILE_NG;
8556 }
8557
8558 ip = ISEQ_BODY(ip)->parent_iseq;
8559 }
8560 if (ip != 0) {
8561 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8562 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8563
8564 if (popped) {
8565 ADD_INSN(ret, line_node, pop);
8566 }
8567 }
8568 else {
8569 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8570 return COMPILE_NG;
8571 }
8572 }
8573 return COMPILE_OK;
8574}
8575
8576static int
8577compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8578{
8579 const NODE *line_node = node;
8580
8581 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8582 LABEL *splabel = NEW_LABEL(0);
8583 debugs("redo in while");
8584 ADD_LABEL(ret, splabel);
8585 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8586 add_ensure_iseq(ret, iseq, 0);
8587 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8588 ADD_ADJUST_RESTORE(ret, splabel);
8589 if (!popped) {
8590 ADD_INSN(ret, line_node, putnil);
8591 }
8592 }
8593 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8594 LABEL *splabel = NEW_LABEL(0);
8595
8596 debugs("redo in block");
8597 ADD_LABEL(ret, splabel);
8598 add_ensure_iseq(ret, iseq, 0);
8599 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8600 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8601 ADD_ADJUST_RESTORE(ret, splabel);
8602
8603 if (!popped) {
8604 ADD_INSN(ret, line_node, putnil);
8605 }
8606 }
8607 else {
8608 const rb_iseq_t *ip = iseq;
8609
8610 while (ip) {
8611 if (!ISEQ_COMPILE_DATA(ip)) {
8612 ip = 0;
8613 break;
8614 }
8615
8616 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8617 break;
8618 }
8619 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8620 break;
8621 }
8622 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8623 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8624 return COMPILE_NG;
8625 }
8626
8627 ip = ISEQ_BODY(ip)->parent_iseq;
8628 }
8629 if (ip != 0) {
8630 ADD_INSN(ret, line_node, putnil);
8631 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8632
8633 if (popped) {
8634 ADD_INSN(ret, line_node, pop);
8635 }
8636 }
8637 else {
8638 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8639 return COMPILE_NG;
8640 }
8641 }
8642 return COMPILE_OK;
8643}
8644
8645static int
8646compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8647{
8648 const NODE *line_node = node;
8649
8650 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8651 ADD_INSN(ret, line_node, putnil);
8652 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8653
8654 if (popped) {
8655 ADD_INSN(ret, line_node, pop);
8656 }
8657 }
8658 else {
8659 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8660 return COMPILE_NG;
8661 }
8662 return COMPILE_OK;
8663}
8664
8665static int
8666compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8667{
8668 const int line = nd_line(node);
8669 const NODE *line_node = node;
8670 LABEL *lstart = NEW_LABEL(line);
8671 LABEL *lend = NEW_LABEL(line);
8672 LABEL *lcont = NEW_LABEL(line);
8673 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8674 rb_str_concat(rb_str_new2("rescue in "),
8675 ISEQ_BODY(iseq)->location.label),
8676 ISEQ_TYPE_RESCUE, line);
8677
8678 lstart->rescued = LABEL_RESCUE_BEG;
8679 lend->rescued = LABEL_RESCUE_END;
8680 ADD_LABEL(ret, lstart);
8681
8682 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8683 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8684 {
8685 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8686 }
8687 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8688
8689 ADD_LABEL(ret, lend);
8690 if (RNODE_RESCUE(node)->nd_else) {
8691 ADD_INSN(ret, line_node, pop);
8692 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8693 }
8694 ADD_INSN(ret, line_node, nop);
8695 ADD_LABEL(ret, lcont);
8696
8697 if (popped) {
8698 ADD_INSN(ret, line_node, pop);
8699 }
8700
8701 /* register catch entry */
8702 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8703 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8704 return COMPILE_OK;
8705}
8706
8707static int
8708compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8709{
8710 const int line = nd_line(node);
8711 const NODE *line_node = node;
8712 const NODE *resq = node;
8713 const NODE *narg;
8714 LABEL *label_miss, *label_hit;
8715
8716 while (resq) {
8717 label_miss = NEW_LABEL(line);
8718 label_hit = NEW_LABEL(line);
8719
8720 narg = RNODE_RESBODY(resq)->nd_args;
8721 if (narg) {
8722 switch (nd_type(narg)) {
8723 case NODE_LIST:
8724 while (narg) {
8725 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8726 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8727 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8728 ADD_INSNL(ret, line_node, branchif, label_hit);
8729 narg = RNODE_LIST(narg)->nd_next;
8730 }
8731 break;
8732 case NODE_SPLAT:
8733 case NODE_ARGSCAT:
8734 case NODE_ARGSPUSH:
8735 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8736 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8737 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8738 ADD_INSNL(ret, line_node, branchif, label_hit);
8739 break;
8740 default:
8741 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8742 }
8743 }
8744 else {
8745 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8746 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8747 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8748 ADD_INSNL(ret, line_node, branchif, label_hit);
8749 }
8750 ADD_INSNL(ret, line_node, jump, label_miss);
8751 ADD_LABEL(ret, label_hit);
8752 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8753
8754 if (RNODE_RESBODY(resq)->nd_exc_var) {
8755 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8756 }
8757
8758 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) {
8759 // empty body
8760 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8761 }
8762 else {
8763 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8764 }
8765
8766 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8767 ADD_INSN(ret, line_node, nop);
8768 }
8769 ADD_INSN(ret, line_node, leave);
8770 ADD_LABEL(ret, label_miss);
8771 resq = RNODE_RESBODY(resq)->nd_next;
8772 }
8773 return COMPILE_OK;
8774}
8775
8776static int
8777compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8778{
8779 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8780 const NODE *line_node = node;
8781 DECL_ANCHOR(ensr);
8782 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8783 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8784 ISEQ_TYPE_ENSURE, line);
8785 LABEL *lstart = NEW_LABEL(line);
8786 LABEL *lend = NEW_LABEL(line);
8787 LABEL *lcont = NEW_LABEL(line);
8788 LINK_ELEMENT *last;
8789 int last_leave = 0;
8790 struct ensure_range er;
8792 struct ensure_range *erange;
8793
8794 INIT_ANCHOR(ensr);
8795 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8796 last = ensr->last;
8797 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8798
8799 er.begin = lstart;
8800 er.end = lend;
8801 er.next = 0;
8802 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8803
8804 ADD_LABEL(ret, lstart);
8805 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8806 ADD_LABEL(ret, lend);
8807 ADD_SEQ(ret, ensr);
8808 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8809 ADD_LABEL(ret, lcont);
8810 if (last_leave) ADD_INSN(ret, line_node, pop);
8811
8812 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8813 if (lstart->link.next != &lend->link) {
8814 while (erange) {
8815 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8816 ensure, lcont);
8817 erange = erange->next;
8818 }
8819 }
8820
8821 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8822 return COMPILE_OK;
8823}
8824
8825static int
8826compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8827{
8828 const NODE *line_node = node;
8829
8830 if (iseq) {
8831 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8832 const rb_iseq_t *is = iseq;
8833 enum rb_iseq_type t = type;
8834 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8835 LABEL *splabel = 0;
8836
8837 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8838 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8839 t = ISEQ_BODY(is)->type;
8840 }
8841 switch (t) {
8842 case ISEQ_TYPE_TOP:
8843 case ISEQ_TYPE_MAIN:
8844 if (retval) {
8845 rb_warn("argument of top-level return is ignored");
8846 }
8847 if (is == iseq) {
8848 /* plain top-level, leave directly */
8849 type = ISEQ_TYPE_METHOD;
8850 }
8851 break;
8852 default:
8853 break;
8854 }
8855
8856 if (type == ISEQ_TYPE_METHOD) {
8857 splabel = NEW_LABEL(0);
8858 ADD_LABEL(ret, splabel);
8859 ADD_ADJUST(ret, line_node, 0);
8860 }
8861
8862 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8863
8864 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8865 add_ensure_iseq(ret, iseq, 1);
8866 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8867 ADD_INSN(ret, line_node, leave);
8868 ADD_ADJUST_RESTORE(ret, splabel);
8869
8870 if (!popped) {
8871 ADD_INSN(ret, line_node, putnil);
8872 }
8873 }
8874 else {
8875 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8876 if (popped) {
8877 ADD_INSN(ret, line_node, pop);
8878 }
8879 }
8880 }
8881 return COMPILE_OK;
8882}
8883
8884static bool
8885drop_unreachable_return(LINK_ANCHOR *ret)
8886{
8887 LINK_ELEMENT *i = ret->last, *last;
8888 if (!i) return false;
8889 if (IS_TRACE(i)) i = i->prev;
8890 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8891 last = i = i->prev;
8892 if (IS_ADJUST(i)) i = i->prev;
8893 if (!IS_INSN(i)) return false;
8894 switch (INSN_OF(i)) {
8895 case BIN(leave):
8896 case BIN(jump):
8897 break;
8898 default:
8899 return false;
8900 }
8901 (ret->last = last->prev)->next = NULL;
8902 return true;
8903}
8904
8905static int
8906compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8907{
8908 CHECK(COMPILE_(ret, "nd_body", node, popped));
8909
8910 if (!popped && !all_string_result_p(node)) {
8911 const NODE *line_node = node;
8912 const unsigned int flag = VM_CALL_FCALL;
8913
8914 // Note, this dup could be removed if we are willing to change anytostring. It pops
8915 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8916 ADD_INSN(ret, line_node, dup);
8917 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8918 ADD_INSN(ret, line_node, anytostring);
8919 }
8920 return COMPILE_OK;
8921}
8922
8923static void
8924compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8925{
8926 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8927
8928 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8929 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8930}
8931
8932static LABEL *
8933qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8934{
8935 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8936 VALUE br = 0;
8937
8938 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8939 *branches = br;
8940 ADD_INSN(recv, line_node, dup);
8941 ADD_INSNL(recv, line_node, branchnil, else_label);
8942 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8943 return else_label;
8944}
8945
8946static void
8947qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8948{
8949 LABEL *end_label;
8950 if (!else_label) return;
8951 end_label = NEW_LABEL(nd_line(line_node));
8952 ADD_INSNL(ret, line_node, jump, end_label);
8953 ADD_LABEL(ret, else_label);
8954 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8955 ADD_LABEL(ret, end_label);
8956}
8957
8958static int
8959compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8960{
8961 /* optimization shortcut
8962 * "literal".freeze -> opt_str_freeze("literal")
8963 */
8964 if (get_nd_recv(node) &&
8965 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8966 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8967 get_nd_args(node) == NULL &&
8968 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8969 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8970 VALUE str = get_string_value(get_nd_recv(node));
8971 if (get_node_call_nd_mid(node) == idUMinus) {
8972 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8973 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8974 }
8975 else {
8976 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8977 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8978 }
8979 RB_OBJ_WRITTEN(iseq, Qundef, str);
8980 if (popped) {
8981 ADD_INSN(ret, line_node, pop);
8982 }
8983 return TRUE;
8984 }
8985 /* optimization shortcut
8986 * obj["literal"] -> opt_aref_with(obj, "literal")
8987 */
8988 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8989 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8990 (nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
8991 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8992 !frozen_string_literal_p(iseq) &&
8993 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8994 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8995 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8996 ADD_INSN2(ret, line_node, opt_aref_with, str,
8997 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8998 RB_OBJ_WRITTEN(iseq, Qundef, str);
8999 if (popped) {
9000 ADD_INSN(ret, line_node, pop);
9001 }
9002 return TRUE;
9003 }
9004 return FALSE;
9005}
9006
9007static int
9008iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9009{
9010 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9011}
9012
9013static const struct rb_builtin_function *
9014iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9015{
9016 int i;
9017 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9018 for (i=0; table[i].index != -1; i++) {
9019 if (strcmp(table[i].name, name) == 0) {
9020 return &table[i];
9021 }
9022 }
9023 return NULL;
9024}
9025
9026static const char *
9027iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9028{
9029 const char *name = rb_id2name(mid);
9030 static const char prefix[] = "__builtin_";
9031 const size_t prefix_len = sizeof(prefix) - 1;
9032
9033 switch (type) {
9034 case NODE_CALL:
9035 if (recv) {
9036 switch (nd_type(recv)) {
9037 case NODE_VCALL:
9038 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9039 return name;
9040 }
9041 break;
9042 case NODE_CONST:
9043 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9044 return name;
9045 }
9046 break;
9047 default: break;
9048 }
9049 }
9050 break;
9051 case NODE_VCALL:
9052 case NODE_FCALL:
9053 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9054 return &name[prefix_len];
9055 }
9056 break;
9057 default: break;
9058 }
9059 return NULL;
9060}
9061
9062static int
9063delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9064{
9065
9066 if (argc == 0) {
9067 *pstart_index = 0;
9068 return TRUE;
9069 }
9070 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9071 unsigned int start=0;
9072
9073 // local_table: [p1, p2, p3, l1, l2, l3]
9074 // arguments: [p3, l1, l2] -> 2
9075 for (start = 0;
9076 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9077 start++) {
9078 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9079
9080 for (unsigned int i=start; i-start<argc; i++) {
9081 if (IS_INSN(elem) &&
9082 INSN_OF(elem) == BIN(getlocal)) {
9083 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9084 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9085
9086 if (local_level == 0) {
9087 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9088 if (0) { // for debug
9089 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9090 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9091 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9092 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9093 }
9094 if (i == index) {
9095 elem = elem->next;
9096 continue; /* for */
9097 }
9098 else {
9099 goto next;
9100 }
9101 }
9102 else {
9103 goto fail; // level != 0 is unsupported
9104 }
9105 }
9106 else {
9107 goto fail; // insn is not a getlocal
9108 }
9109 }
9110 goto success;
9111 next:;
9112 }
9113 fail:
9114 return FALSE;
9115 success:
9116 *pstart_index = start;
9117 return TRUE;
9118 }
9119 else {
9120 return FALSE;
9121 }
9122}
9123
9124// Compile Primitive.attr! :leaf, ...
9125static int
9126compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9127{
9128 VALUE symbol;
9129 VALUE string;
9130 if (!node) goto no_arg;
9131 while (node) {
9132 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9133 const NODE *next = RNODE_LIST(node)->nd_next;
9134
9135 node = RNODE_LIST(node)->nd_head;
9136 if (!node) goto no_arg;
9137 switch (nd_type(node)) {
9138 case NODE_SYM:
9139 symbol = rb_node_sym_string_val(node);
9140 break;
9141 default:
9142 goto bad_arg;
9143 }
9144
9145 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9146
9147 string = rb_sym2str(symbol);
9148 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9149 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9150 }
9151 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9152 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9153 }
9154 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9155 iseq_set_use_block(iseq);
9156 }
9157 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9158 // Let the iseq act like a C method in backtraces
9159 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9160 }
9161 else {
9162 goto unknown_arg;
9163 }
9164 node = next;
9165 }
9166 return COMPILE_OK;
9167 no_arg:
9168 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9169 return COMPILE_NG;
9170 non_symbol_arg:
9171 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9172 return COMPILE_NG;
9173 unknown_arg:
9174 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9175 return COMPILE_NG;
9176 bad_arg:
9177 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9178}
9179
9180static int
9181compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9182{
9183 VALUE name;
9184
9185 if (!node) goto no_arg;
9186 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9187 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9188 node = RNODE_LIST(node)->nd_head;
9189 if (!node) goto no_arg;
9190 switch (nd_type(node)) {
9191 case NODE_SYM:
9192 name = rb_node_sym_string_val(node);
9193 break;
9194 default:
9195 goto bad_arg;
9196 }
9197 if (!SYMBOL_P(name)) goto non_symbol_arg;
9198 if (!popped) {
9199 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9200 }
9201 return COMPILE_OK;
9202 no_arg:
9203 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9204 return COMPILE_NG;
9205 too_many_arg:
9206 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9207 return COMPILE_NG;
9208 non_symbol_arg:
9209 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9210 rb_builtin_class_name(name));
9211 return COMPILE_NG;
9212 bad_arg:
9213 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9214}
9215
9216static NODE *
9217mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9218{
9219 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9220 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9221 return RNODE_IF(node)->nd_body;
9222 }
9223 else {
9224 rb_bug("mandatory_node: can't find mandatory node");
9225 }
9226}
9227
9228static int
9229compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9230{
9231 // arguments
9232 struct rb_args_info args = {
9233 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9234 };
9235 rb_node_args_t args_node;
9236 rb_node_init(RNODE(&args_node), NODE_ARGS);
9237 args_node.nd_ainfo = args;
9238
9239 // local table without non-mandatory parameters
9240 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9241 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9242
9243 VALUE idtmp = 0;
9244 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9245 tbl->size = table_size;
9246
9247 int i;
9248
9249 // lead parameters
9250 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9251 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9252 }
9253 // local variables
9254 for (; i<table_size; i++) {
9255 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9256 }
9257
9258 rb_node_scope_t scope_node;
9259 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9260 scope_node.nd_tbl = tbl;
9261 scope_node.nd_body = mandatory_node(iseq, node);
9262 scope_node.nd_args = &args_node;
9263
9264 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9265
9266 const rb_iseq_t *mandatory_only_iseq =
9267 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9268 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9269 nd_line(line_node), NULL, 0,
9270 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9271 ISEQ_BODY(iseq)->variable.script_lines);
9272 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9273
9274 ALLOCV_END(idtmp);
9275 return COMPILE_OK;
9276}
9277
9278static int
9279compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9280 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9281{
9282 NODE *args_node = get_nd_args(node);
9283
9284 if (parent_block != NULL) {
9285 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9286 return COMPILE_NG;
9287 }
9288 else {
9289# define BUILTIN_INLINE_PREFIX "_bi"
9290 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9291 bool cconst = false;
9292 retry:;
9293 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9294
9295 if (bf == NULL) {
9296 if (strcmp("cstmt!", builtin_func) == 0 ||
9297 strcmp("cexpr!", builtin_func) == 0) {
9298 // ok
9299 }
9300 else if (strcmp("cconst!", builtin_func) == 0) {
9301 cconst = true;
9302 }
9303 else if (strcmp("cinit!", builtin_func) == 0) {
9304 // ignore
9305 return COMPILE_OK;
9306 }
9307 else if (strcmp("attr!", builtin_func) == 0) {
9308 return compile_builtin_attr(iseq, args_node);
9309 }
9310 else if (strcmp("arg!", builtin_func) == 0) {
9311 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9312 }
9313 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9314 if (popped) {
9315 rb_bug("mandatory_only? should be in if condition");
9316 }
9317 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9318 rb_bug("mandatory_only? should be put on top");
9319 }
9320
9321 ADD_INSN1(ret, line_node, putobject, Qfalse);
9322 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9323 }
9324 else if (1) {
9325 rb_bug("can't find builtin function:%s", builtin_func);
9326 }
9327 else {
9328 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9329 return COMPILE_NG;
9330 }
9331
9332 int inline_index = nd_line(node);
9333 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9334 builtin_func = inline_func;
9335 args_node = NULL;
9336 goto retry;
9337 }
9338
9339 if (cconst) {
9340 typedef VALUE(*builtin_func0)(void *, VALUE);
9341 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9342 ADD_INSN1(ret, line_node, putobject, const_val);
9343 return COMPILE_OK;
9344 }
9345
9346 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9347
9348 unsigned int flag = 0;
9349 struct rb_callinfo_kwarg *keywords = NULL;
9350 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9351
9352 if (FIX2INT(argc) != bf->argc) {
9353 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9354 builtin_func, bf->argc, FIX2INT(argc));
9355 return COMPILE_NG;
9356 }
9357
9358 unsigned int start_index;
9359 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9360 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9361 }
9362 else {
9363 ADD_SEQ(ret, args);
9364 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9365 }
9366
9367 if (popped) ADD_INSN(ret, line_node, pop);
9368 return COMPILE_OK;
9369 }
9370}
9371
9372static int
9373compile_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)
9374{
9375 /* call: obj.method(...)
9376 * fcall: func(...)
9377 * vcall: func
9378 */
9379 DECL_ANCHOR(recv);
9380 DECL_ANCHOR(args);
9381 ID mid = get_node_call_nd_mid(node);
9382 VALUE argc;
9383 unsigned int flag = 0;
9384 struct rb_callinfo_kwarg *keywords = NULL;
9385 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9386 LABEL *else_label = NULL;
9387 VALUE branches = Qfalse;
9388
9389 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9390
9391 INIT_ANCHOR(recv);
9392 INIT_ANCHOR(args);
9393
9394#if OPT_SUPPORT_JOKE
9395 if (nd_type_p(node, NODE_VCALL)) {
9396 ID id_bitblt;
9397 ID id_answer;
9398
9399 CONST_ID(id_bitblt, "bitblt");
9400 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9401
9402 if (mid == id_bitblt) {
9403 ADD_INSN(ret, line_node, bitblt);
9404 return COMPILE_OK;
9405 }
9406 else if (mid == id_answer) {
9407 ADD_INSN(ret, line_node, answer);
9408 return COMPILE_OK;
9409 }
9410 }
9411 /* only joke */
9412 {
9413 ID goto_id;
9414 ID label_id;
9415
9416 CONST_ID(goto_id, "__goto__");
9417 CONST_ID(label_id, "__label__");
9418
9419 if (nd_type_p(node, NODE_FCALL) &&
9420 (mid == goto_id || mid == label_id)) {
9421 LABEL *label;
9422 st_data_t data;
9423 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9424 VALUE label_name;
9425
9426 if (!labels_table) {
9427 labels_table = st_init_numtable();
9428 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9429 }
9430 {
9431 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9432 return COMPILE_NG;
9433 }
9434
9435 if (mid == goto_id) {
9436 ADD_INSNL(ret, line_node, jump, label);
9437 }
9438 else {
9439 ADD_LABEL(ret, label);
9440 }
9441 return COMPILE_OK;
9442 }
9443 }
9444#endif
9445
9446 const char *builtin_func;
9447 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9448 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9449 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9450 }
9451
9452 /* receiver */
9453 if (!assume_receiver) {
9454 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9455 int idx, level;
9456
9457 if (mid == idCall &&
9458 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9459 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9460 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9461 }
9462 else if (private_recv_p(node)) {
9463 ADD_INSN(recv, node, putself);
9464 flag |= VM_CALL_FCALL;
9465 }
9466 else {
9467 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9468 }
9469
9470 if (type == NODE_QCALL) {
9471 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9472 }
9473 }
9474 else if (type == NODE_FCALL || type == NODE_VCALL) {
9475 ADD_CALL_RECEIVER(recv, line_node);
9476 }
9477 }
9478
9479 /* args */
9480 if (type != NODE_VCALL) {
9481 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9482 CHECK(!NIL_P(argc));
9483 }
9484 else {
9485 argc = INT2FIX(0);
9486 }
9487
9488 ADD_SEQ(ret, recv);
9489
9490 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9491 mid == rb_intern("new") &&
9492 parent_block == NULL &&
9493 !(flag & VM_CALL_ARGS_BLOCKARG);
9494
9495 if (inline_new) {
9496 ADD_INSN(ret, node, putnil);
9497 ADD_INSN(ret, node, swap);
9498 }
9499
9500 ADD_SEQ(ret, args);
9501
9502 debugp_param("call args argc", argc);
9503 debugp_param("call method", ID2SYM(mid));
9504
9505 switch ((int)type) {
9506 case NODE_VCALL:
9507 flag |= VM_CALL_VCALL;
9508 /* VCALL is funcall, so fall through */
9509 case NODE_FCALL:
9510 flag |= VM_CALL_FCALL;
9511 }
9512
9513 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9514 ADD_INSN(ret, line_node, splatkw);
9515 }
9516
9517 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9518 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9519
9520 if (inline_new) {
9521 // Jump unless the receiver uses the "basic" implementation of "new"
9522 VALUE ci;
9523 if (flag & VM_CALL_FORWARDING) {
9524 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9525 }
9526 else {
9527 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9528 }
9529 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9530 LABEL_REF(not_basic_new);
9531
9532 // optimized path
9533 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9534 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9535
9536 ADD_LABEL(ret, not_basic_new);
9537 // Fall back to normal send
9538 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9539 ADD_INSN(ret, line_node, swap);
9540
9541 ADD_LABEL(ret, not_basic_new_finish);
9542 ADD_INSN(ret, line_node, pop);
9543 }
9544 else {
9545 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9546 }
9547
9548 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9549 if (popped) {
9550 ADD_INSN(ret, line_node, pop);
9551 }
9552 return COMPILE_OK;
9553}
9554
9555static int
9556compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9557{
9558 const int line = nd_line(node);
9559 VALUE argc;
9560 unsigned int flag = 0;
9561 int asgnflag = 0;
9562 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9563
9564 /*
9565 * a[x] (op)= y
9566 *
9567 * nil # nil
9568 * eval a # nil a
9569 * eval x # nil a x
9570 * dupn 2 # nil a x a x
9571 * send :[] # nil a x a[x]
9572 * eval y # nil a x a[x] y
9573 * send op # nil a x ret
9574 * setn 3 # ret a x ret
9575 * send []= # ret ?
9576 * pop # ret
9577 */
9578
9579 /*
9580 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9581 * NODE_OP_ASGN nd_recv
9582 * nd_args->nd_head
9583 * nd_args->nd_body
9584 * nd_mid
9585 */
9586
9587 if (!popped) {
9588 ADD_INSN(ret, node, putnil);
9589 }
9590 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9591 CHECK(asgnflag != -1);
9592 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9593 case NODE_ZLIST:
9594 argc = INT2FIX(0);
9595 break;
9596 default:
9597 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9598 CHECK(!NIL_P(argc));
9599 }
9600 int dup_argn = FIX2INT(argc) + 1;
9601 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9602 flag |= asgnflag;
9603 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9604
9605 if (id == idOROP || id == idANDOP) {
9606 /* a[x] ||= y or a[x] &&= y
9607
9608 unless/if a[x]
9609 a[x]= y
9610 else
9611 nil
9612 end
9613 */
9614 LABEL *label = NEW_LABEL(line);
9615 LABEL *lfin = NEW_LABEL(line);
9616
9617 ADD_INSN(ret, node, dup);
9618 if (id == idOROP) {
9619 ADD_INSNL(ret, node, branchif, label);
9620 }
9621 else { /* idANDOP */
9622 ADD_INSNL(ret, node, branchunless, label);
9623 }
9624 ADD_INSN(ret, node, pop);
9625
9626 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9627 if (!popped) {
9628 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9629 }
9630 if (flag & VM_CALL_ARGS_SPLAT) {
9631 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9632 ADD_INSN(ret, node, swap);
9633 ADD_INSN1(ret, node, splatarray, Qtrue);
9634 ADD_INSN(ret, node, swap);
9635 flag |= VM_CALL_ARGS_SPLAT_MUT;
9636 }
9637 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9638 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9639 }
9640 else {
9641 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9642 }
9643 ADD_INSN(ret, node, pop);
9644 ADD_INSNL(ret, node, jump, lfin);
9645 ADD_LABEL(ret, label);
9646 if (!popped) {
9647 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9648 }
9649 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9650 ADD_LABEL(ret, lfin);
9651 }
9652 else {
9653 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9654 ADD_SEND(ret, node, id, INT2FIX(1));
9655 if (!popped) {
9656 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9657 }
9658 if (flag & VM_CALL_ARGS_SPLAT) {
9659 if (flag & VM_CALL_KW_SPLAT) {
9660 ADD_INSN1(ret, node, topn, INT2FIX(2));
9661 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9662 ADD_INSN1(ret, node, splatarray, Qtrue);
9663 flag |= VM_CALL_ARGS_SPLAT_MUT;
9664 }
9665 ADD_INSN(ret, node, swap);
9666 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9667 ADD_INSN1(ret, node, setn, INT2FIX(2));
9668 ADD_INSN(ret, node, pop);
9669 }
9670 else {
9671 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9672 ADD_INSN(ret, node, swap);
9673 ADD_INSN1(ret, node, splatarray, Qtrue);
9674 ADD_INSN(ret, node, swap);
9675 flag |= VM_CALL_ARGS_SPLAT_MUT;
9676 }
9677 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9678 }
9679 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9680 }
9681 else {
9682 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9683 }
9684 ADD_INSN(ret, node, pop);
9685 }
9686 return COMPILE_OK;
9687}
9688
9689static int
9690compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9691{
9692 const int line = nd_line(node);
9693 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9694 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9695 int asgnflag;
9696 LABEL *lfin = NEW_LABEL(line);
9697 LABEL *lcfin = NEW_LABEL(line);
9698 LABEL *lskip = 0;
9699 /*
9700 class C; attr_accessor :c; end
9701 r = C.new
9702 r.a &&= v # asgn2
9703
9704 eval r # r
9705 dup # r r
9706 eval r.a # r o
9707
9708 # or
9709 dup # r o o
9710 if lcfin # r o
9711 pop # r
9712 eval v # r v
9713 swap # v r
9714 topn 1 # v r v
9715 send a= # v ?
9716 jump lfin # v ?
9717
9718 lcfin: # r o
9719 swap # o r
9720
9721 lfin: # o ?
9722 pop # o
9723
9724 # or (popped)
9725 if lcfin # r
9726 eval v # r v
9727 send a= # ?
9728 jump lfin # ?
9729
9730 lcfin: # r
9731
9732 lfin: # ?
9733 pop #
9734
9735 # and
9736 dup # r o o
9737 unless lcfin
9738 pop # r
9739 eval v # r v
9740 swap # v r
9741 topn 1 # v r v
9742 send a= # v ?
9743 jump lfin # v ?
9744
9745 # others
9746 eval v # r o v
9747 send ?? # r w
9748 send a= # w
9749
9750 */
9751
9752 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9753 CHECK(asgnflag != -1);
9754 if (RNODE_OP_ASGN2(node)->nd_aid) {
9755 lskip = NEW_LABEL(line);
9756 ADD_INSN(ret, node, dup);
9757 ADD_INSNL(ret, node, branchnil, lskip);
9758 }
9759 ADD_INSN(ret, node, dup);
9760 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9761
9762 if (atype == idOROP || atype == idANDOP) {
9763 if (!popped) {
9764 ADD_INSN(ret, node, dup);
9765 }
9766 if (atype == idOROP) {
9767 ADD_INSNL(ret, node, branchif, lcfin);
9768 }
9769 else { /* idANDOP */
9770 ADD_INSNL(ret, node, branchunless, lcfin);
9771 }
9772 if (!popped) {
9773 ADD_INSN(ret, node, pop);
9774 }
9775 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9776 if (!popped) {
9777 ADD_INSN(ret, node, swap);
9778 ADD_INSN1(ret, node, topn, INT2FIX(1));
9779 }
9780 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9781 ADD_INSNL(ret, node, jump, lfin);
9782
9783 ADD_LABEL(ret, lcfin);
9784 if (!popped) {
9785 ADD_INSN(ret, node, swap);
9786 }
9787
9788 ADD_LABEL(ret, lfin);
9789 }
9790 else {
9791 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9792 ADD_SEND(ret, node, atype, INT2FIX(1));
9793 if (!popped) {
9794 ADD_INSN(ret, node, swap);
9795 ADD_INSN1(ret, node, topn, INT2FIX(1));
9796 }
9797 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9798 }
9799 if (lskip && popped) {
9800 ADD_LABEL(ret, lskip);
9801 }
9802 ADD_INSN(ret, node, pop);
9803 if (lskip && !popped) {
9804 ADD_LABEL(ret, lskip);
9805 }
9806 return COMPILE_OK;
9807}
9808
9809static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9810
9811static int
9812compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9813{
9814 const int line = nd_line(node);
9815 LABEL *lfin = 0;
9816 LABEL *lassign = 0;
9817 ID mid;
9818
9819 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9820 case NODE_COLON3:
9821 ADD_INSN1(ret, node, putobject, rb_cObject);
9822 break;
9823 case NODE_COLON2:
9824 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9825 break;
9826 default:
9827 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9828 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9829 return COMPILE_NG;
9830 }
9831 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9832 /* cref */
9833 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9834 lassign = NEW_LABEL(line);
9835 ADD_INSN(ret, node, dup); /* cref cref */
9836 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9837 ID2SYM(mid), Qtrue); /* cref bool */
9838 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9839 }
9840 ADD_INSN(ret, node, dup); /* cref cref */
9841 ADD_INSN1(ret, node, putobject, Qtrue);
9842 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9843
9844 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9845 lfin = NEW_LABEL(line);
9846 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9847 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9848 ADD_INSNL(ret, node, branchif, lfin);
9849 else /* idANDOP */
9850 ADD_INSNL(ret, node, branchunless, lfin);
9851 /* cref [obj] */
9852 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9853 if (lassign) ADD_LABEL(ret, lassign);
9854 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9855 /* cref value */
9856 if (popped)
9857 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9858 else {
9859 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9860 ADD_INSN(ret, node, swap); /* cref value value cref */
9861 }
9862 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9863 ADD_LABEL(ret, lfin); /* cref [value] */
9864 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9865 ADD_INSN(ret, node, pop); /* [value] */
9866 }
9867 else {
9868 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9869 /* cref obj value */
9870 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9871 /* cref value */
9872 ADD_INSN(ret, node, swap); /* value cref */
9873 if (!popped) {
9874 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9875 ADD_INSN(ret, node, swap); /* value value cref */
9876 }
9877 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9878 }
9879 return COMPILE_OK;
9880}
9881
9882static int
9883compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9884{
9885 const int line = nd_line(node);
9886 LABEL *lfin = NEW_LABEL(line);
9887 LABEL *lassign;
9888
9889 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9890 LABEL *lfinish[2];
9891 lfinish[0] = lfin;
9892 lfinish[1] = 0;
9893 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9894 lassign = lfinish[1];
9895 if (!lassign) {
9896 lassign = NEW_LABEL(line);
9897 }
9898 ADD_INSNL(ret, node, branchunless, lassign);
9899 }
9900 else {
9901 lassign = NEW_LABEL(line);
9902 }
9903
9904 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9905
9906 if (!popped) {
9907 ADD_INSN(ret, node, dup);
9908 }
9909
9910 if (type == NODE_OP_ASGN_AND) {
9911 ADD_INSNL(ret, node, branchunless, lfin);
9912 }
9913 else {
9914 ADD_INSNL(ret, node, branchif, lfin);
9915 }
9916
9917 if (!popped) {
9918 ADD_INSN(ret, node, pop);
9919 }
9920
9921 ADD_LABEL(ret, lassign);
9922 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9923 ADD_LABEL(ret, lfin);
9924 return COMPILE_OK;
9925}
9926
9927static int
9928compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9929{
9930 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9931 DECL_ANCHOR(args);
9932 int argc;
9933 unsigned int flag = 0;
9934 struct rb_callinfo_kwarg *keywords = NULL;
9935 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9936 int use_block = 1;
9937
9938 INIT_ANCHOR(args);
9939 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9940
9941 if (type == NODE_SUPER) {
9942 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9943 CHECK(!NIL_P(vargc));
9944 argc = FIX2INT(vargc);
9945 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9946 ADD_INSN(args, node, splatkw);
9947 }
9948
9949 if (flag & VM_CALL_ARGS_BLOCKARG) {
9950 use_block = 0;
9951 }
9952 }
9953 else {
9954 /* NODE_ZSUPER */
9955 int i;
9956 const rb_iseq_t *liseq = body->local_iseq;
9957 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9958 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9959 int lvar_level = get_lvar_level(iseq);
9960
9961 argc = local_body->param.lead_num;
9962
9963 /* normal arguments */
9964 for (i = 0; i < local_body->param.lead_num; i++) {
9965 int idx = local_body->local_table_size - i;
9966 ADD_GETLOCAL(args, node, idx, lvar_level);
9967 }
9968
9969 /* forward ... */
9970 if (local_body->param.flags.forwardable) {
9971 flag |= VM_CALL_FORWARDING;
9972 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9973 ADD_GETLOCAL(args, node, idx, lvar_level);
9974 }
9975
9976 if (local_body->param.flags.has_opt) {
9977 /* optional arguments */
9978 int j;
9979 for (j = 0; j < local_body->param.opt_num; j++) {
9980 int idx = local_body->local_table_size - (i + j);
9981 ADD_GETLOCAL(args, node, idx, lvar_level);
9982 }
9983 i += j;
9984 argc = i;
9985 }
9986 if (local_body->param.flags.has_rest) {
9987 /* rest argument */
9988 int idx = local_body->local_table_size - local_body->param.rest_start;
9989 ADD_GETLOCAL(args, node, idx, lvar_level);
9990 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9991
9992 argc = local_body->param.rest_start + 1;
9993 flag |= VM_CALL_ARGS_SPLAT;
9994 }
9995 if (local_body->param.flags.has_post) {
9996 /* post arguments */
9997 int post_len = local_body->param.post_num;
9998 int post_start = local_body->param.post_start;
9999
10000 if (local_body->param.flags.has_rest) {
10001 int j;
10002 for (j=0; j<post_len; j++) {
10003 int idx = local_body->local_table_size - (post_start + j);
10004 ADD_GETLOCAL(args, node, idx, lvar_level);
10005 }
10006 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10007 flag |= VM_CALL_ARGS_SPLAT_MUT;
10008 /* argc is settled at above */
10009 }
10010 else {
10011 int j;
10012 for (j=0; j<post_len; j++) {
10013 int idx = local_body->local_table_size - (post_start + j);
10014 ADD_GETLOCAL(args, node, idx, lvar_level);
10015 }
10016 argc = post_len + post_start;
10017 }
10018 }
10019
10020 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10021 int local_size = local_body->local_table_size;
10022 argc++;
10023
10024 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10025
10026 if (local_body->param.flags.has_kwrest) {
10027 int idx = local_body->local_table_size - local_kwd->rest_start;
10028 ADD_GETLOCAL(args, node, idx, lvar_level);
10029 RUBY_ASSERT(local_kwd->num > 0);
10030 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10031 }
10032 else {
10033 ADD_INSN1(args, node, newhash, INT2FIX(0));
10034 }
10035 for (i = 0; i < local_kwd->num; ++i) {
10036 ID id = local_kwd->table[i];
10037 int idx = local_size - get_local_var_idx(liseq, id);
10038 ADD_INSN1(args, node, putobject, ID2SYM(id));
10039 ADD_GETLOCAL(args, node, idx, lvar_level);
10040 }
10041 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10042 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10043 }
10044 else if (local_body->param.flags.has_kwrest) {
10045 int idx = local_body->local_table_size - local_kwd->rest_start;
10046 ADD_GETLOCAL(args, node, idx, lvar_level);
10047 argc++;
10048 flag |= VM_CALL_KW_SPLAT;
10049 }
10050 }
10051
10052 if (use_block && parent_block == NULL) {
10053 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10054 }
10055
10056 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10057 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10058 ADD_INSN(ret, node, putself);
10059 ADD_SEQ(ret, args);
10060
10061 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10062
10063 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10064 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10065 }
10066 else {
10067 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10068 }
10069
10070 if (popped) {
10071 ADD_INSN(ret, node, pop);
10072 }
10073 return COMPILE_OK;
10074}
10075
10076static int
10077compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10078{
10079 DECL_ANCHOR(args);
10080 VALUE argc;
10081 unsigned int flag = 0;
10082 struct rb_callinfo_kwarg *keywords = NULL;
10083
10084 INIT_ANCHOR(args);
10085
10086 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10087 case ISEQ_TYPE_TOP:
10088 case ISEQ_TYPE_MAIN:
10089 case ISEQ_TYPE_CLASS:
10090 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10091 return COMPILE_NG;
10092 default: /* valid */;
10093 }
10094
10095 if (RNODE_YIELD(node)->nd_head) {
10096 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10097 CHECK(!NIL_P(argc));
10098 }
10099 else {
10100 argc = INT2FIX(0);
10101 }
10102
10103 ADD_SEQ(ret, args);
10104 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10105 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10106
10107 if (popped) {
10108 ADD_INSN(ret, node, pop);
10109 }
10110
10111 int level = 0;
10112 const rb_iseq_t *tmp_iseq = iseq;
10113 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10114 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10115 }
10116 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10117
10118 return COMPILE_OK;
10119}
10120
10121static int
10122compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10123{
10124 DECL_ANCHOR(recv);
10125 DECL_ANCHOR(val);
10126
10127 INIT_ANCHOR(recv);
10128 INIT_ANCHOR(val);
10129 switch ((int)type) {
10130 case NODE_MATCH:
10131 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10132 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10133 INT2FIX(0));
10134 break;
10135 case NODE_MATCH2:
10136 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10137 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10138 break;
10139 case NODE_MATCH3:
10140 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10141 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10142 break;
10143 }
10144
10145 ADD_SEQ(ret, recv);
10146 ADD_SEQ(ret, val);
10147 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10148
10149 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10150 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10151 }
10152
10153 if (popped) {
10154 ADD_INSN(ret, node, pop);
10155 }
10156 return COMPILE_OK;
10157}
10158
10159static int
10160compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10161{
10162 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10163 /* constant */
10164 VALUE segments;
10165 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10166 (segments = collect_const_segments(iseq, node))) {
10167 ISEQ_BODY(iseq)->ic_size++;
10168 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10169 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10170 }
10171 else {
10172 /* constant */
10173 DECL_ANCHOR(pref);
10174 DECL_ANCHOR(body);
10175
10176 INIT_ANCHOR(pref);
10177 INIT_ANCHOR(body);
10178 CHECK(compile_const_prefix(iseq, node, pref, body));
10179 if (LIST_INSN_SIZE_ZERO(pref)) {
10180 ADD_INSN(ret, node, putnil);
10181 ADD_SEQ(ret, body);
10182 }
10183 else {
10184 ADD_SEQ(ret, pref);
10185 ADD_SEQ(ret, body);
10186 }
10187 }
10188 }
10189 else {
10190 /* function call */
10191 ADD_CALL_RECEIVER(ret, node);
10192 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10193 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10194 }
10195 if (popped) {
10196 ADD_INSN(ret, node, pop);
10197 }
10198 return COMPILE_OK;
10199}
10200
10201static int
10202compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10203{
10204 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10205
10206 /* add cache insn */
10207 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10208 ISEQ_BODY(iseq)->ic_size++;
10209 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10210 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10211 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10212 }
10213 else {
10214 ADD_INSN1(ret, node, putobject, rb_cObject);
10215 ADD_INSN1(ret, node, putobject, Qtrue);
10216 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10217 }
10218
10219 if (popped) {
10220 ADD_INSN(ret, node, pop);
10221 }
10222 return COMPILE_OK;
10223}
10224
10225static int
10226compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10227{
10228 VALUE flag = INT2FIX(excl);
10229 const NODE *b = RNODE_DOT2(node)->nd_beg;
10230 const NODE *e = RNODE_DOT2(node)->nd_end;
10231
10232 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10233 if (!popped) {
10234 VALUE bv = optimized_range_item(b);
10235 VALUE ev = optimized_range_item(e);
10236 VALUE val = rb_range_new(bv, ev, excl);
10237 ADD_INSN1(ret, node, putobject, val);
10238 RB_OBJ_WRITTEN(iseq, Qundef, val);
10239 }
10240 }
10241 else {
10242 CHECK(COMPILE_(ret, "min", b, popped));
10243 CHECK(COMPILE_(ret, "max", e, popped));
10244 if (!popped) {
10245 ADD_INSN1(ret, node, newrange, flag);
10246 }
10247 }
10248 return COMPILE_OK;
10249}
10250
10251static int
10252compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10253{
10254 if (!popped) {
10255 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10256 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10257 }
10258 else {
10259 const rb_iseq_t *ip = iseq;
10260 int level = 0;
10261 while (ip) {
10262 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10263 break;
10264 }
10265 ip = ISEQ_BODY(ip)->parent_iseq;
10266 level++;
10267 }
10268 if (ip) {
10269 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10270 }
10271 else {
10272 ADD_INSN(ret, node, putnil);
10273 }
10274 }
10275 }
10276 return COMPILE_OK;
10277}
10278
10279static int
10280compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10281{
10282 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10283 LABEL *end_label = NEW_LABEL(nd_line(node));
10284 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10285
10286 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10287 /* required argument. do nothing */
10288 COMPILE_ERROR(ERROR_ARGS "unreachable");
10289 return COMPILE_NG;
10290 }
10291 else if (nd_type_p(default_value, NODE_SYM) ||
10292 nd_type_p(default_value, NODE_REGX) ||
10293 nd_type_p(default_value, NODE_LINE) ||
10294 nd_type_p(default_value, NODE_INTEGER) ||
10295 nd_type_p(default_value, NODE_FLOAT) ||
10296 nd_type_p(default_value, NODE_RATIONAL) ||
10297 nd_type_p(default_value, NODE_IMAGINARY) ||
10298 nd_type_p(default_value, NODE_NIL) ||
10299 nd_type_p(default_value, NODE_TRUE) ||
10300 nd_type_p(default_value, NODE_FALSE)) {
10301 COMPILE_ERROR(ERROR_ARGS "unreachable");
10302 return COMPILE_NG;
10303 }
10304 else {
10305 /* if keywordcheck(_kw_bits, nth_keyword)
10306 * kw = default_value
10307 * end
10308 */
10309 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10310 int keyword_idx = body->param.keyword->num;
10311
10312 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10313 ADD_INSNL(ret, node, branchif, end_label);
10314 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10315 ADD_LABEL(ret, end_label);
10316 }
10317 return COMPILE_OK;
10318}
10319
10320static int
10321compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10322{
10323 DECL_ANCHOR(recv);
10324 DECL_ANCHOR(args);
10325 unsigned int flag = 0;
10326 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10327 VALUE argc;
10328 LABEL *else_label = NULL;
10329 VALUE branches = Qfalse;
10330
10331 /* optimization shortcut
10332 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10333 */
10334 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10335 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10336 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10337 (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
10338 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10339 !frozen_string_literal_p(iseq) &&
10340 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10341 {
10342 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10343 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10344 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10345 if (!popped) {
10346 ADD_INSN(ret, node, swap);
10347 ADD_INSN1(ret, node, topn, INT2FIX(1));
10348 }
10349 ADD_INSN2(ret, node, opt_aset_with, str,
10350 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10351 RB_OBJ_WRITTEN(iseq, Qundef, str);
10352 ADD_INSN(ret, node, pop);
10353 return COMPILE_OK;
10354 }
10355
10356 INIT_ANCHOR(recv);
10357 INIT_ANCHOR(args);
10358 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10359 CHECK(!NIL_P(argc));
10360
10361 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10362 CHECK(asgnflag != -1);
10363 flag |= (unsigned int)asgnflag;
10364
10365 debugp_param("argc", argc);
10366 debugp_param("nd_mid", ID2SYM(mid));
10367
10368 if (!rb_is_attrset_id(mid)) {
10369 /* safe nav attr */
10370 mid = rb_id_attrset(mid);
10371 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10372 }
10373 if (!popped) {
10374 ADD_INSN(ret, node, putnil);
10375 ADD_SEQ(ret, recv);
10376 ADD_SEQ(ret, args);
10377
10378 if (flag & VM_CALL_ARGS_SPLAT) {
10379 ADD_INSN(ret, node, dup);
10380 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10381 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10382 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10383 ADD_INSN (ret, node, pop);
10384 }
10385 else {
10386 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10387 }
10388 }
10389 else {
10390 ADD_SEQ(ret, recv);
10391 ADD_SEQ(ret, args);
10392 }
10393 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10394 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10395 ADD_INSN(ret, node, pop);
10396 return COMPILE_OK;
10397}
10398
10399static int
10400compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10401{
10402 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10403 ADD_SEQ(ret, sub);
10404
10405 if (copy) {
10406 /*
10407 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10408 * NEW_LIST(value, loc), loc);
10409 */
10410 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10411 }
10412 else {
10413 /*
10414 * NEW_CALL(fcore, rb_intern("make_shareable"),
10415 * NEW_LIST(value, loc), loc);
10416 */
10417 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10418 }
10419
10420 return COMPILE_OK;
10421}
10422
10423static VALUE
10424node_const_decl_val(const NODE *node)
10425{
10426 VALUE path;
10427 switch (nd_type(node)) {
10428 case NODE_CDECL:
10429 if (RNODE_CDECL(node)->nd_vid) {
10430 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10431 goto end;
10432 }
10433 else {
10434 node = RNODE_CDECL(node)->nd_else;
10435 }
10436 break;
10437 case NODE_COLON2:
10438 break;
10439 case NODE_COLON3:
10440 // ::Const
10441 path = rb_str_new_cstr("::");
10442 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10443 goto end;
10444 default:
10445 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10447 }
10448
10449 path = rb_ary_new();
10450 if (node) {
10451 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10452 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10453 }
10454 if (node && nd_type_p(node, NODE_CONST)) {
10455 // Const::Name
10456 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10457 }
10458 else if (node && nd_type_p(node, NODE_COLON3)) {
10459 // ::Const::Name
10460 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10461 rb_ary_push(path, rb_str_new(0, 0));
10462 }
10463 else {
10464 // expression::Name
10465 rb_ary_push(path, rb_str_new_cstr("..."));
10466 }
10467 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10468 }
10469 end:
10470 path = rb_fstring(path);
10471 return path;
10472}
10473
10474static VALUE
10475const_decl_path(NODE *dest)
10476{
10477 VALUE path = Qnil;
10478 if (!nd_type_p(dest, NODE_CALL)) {
10479 path = node_const_decl_val(dest);
10480 }
10481 return path;
10482}
10483
10484static int
10485compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10486{
10487 /*
10488 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10489 */
10490 VALUE path = const_decl_path(dest);
10491 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10492 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10493 ADD_INSN1(ret, value, putobject, path);
10494 RB_OBJ_WRITTEN(iseq, Qundef, path);
10495 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10496
10497 return COMPILE_OK;
10498}
10499
10500#ifndef SHAREABLE_BARE_EXPRESSION
10501#define SHAREABLE_BARE_EXPRESSION 1
10502#endif
10503
10504static int
10505compile_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)
10506{
10507# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10508 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10509 VALUE lit = Qnil;
10510 DECL_ANCHOR(anchor);
10511
10512 enum node_type type = node ? nd_type(node) : NODE_NIL;
10513 switch (type) {
10514 case NODE_TRUE:
10515 *value_p = Qtrue;
10516 goto compile;
10517 case NODE_FALSE:
10518 *value_p = Qfalse;
10519 goto compile;
10520 case NODE_NIL:
10521 *value_p = Qnil;
10522 goto compile;
10523 case NODE_SYM:
10524 *value_p = rb_node_sym_string_val(node);
10525 goto compile;
10526 case NODE_REGX:
10527 *value_p = rb_node_regx_string_val(node);
10528 goto compile;
10529 case NODE_LINE:
10530 *value_p = rb_node_line_lineno_val(node);
10531 goto compile;
10532 case NODE_INTEGER:
10533 *value_p = rb_node_integer_literal_val(node);
10534 goto compile;
10535 case NODE_FLOAT:
10536 *value_p = rb_node_float_literal_val(node);
10537 goto compile;
10538 case NODE_RATIONAL:
10539 *value_p = rb_node_rational_literal_val(node);
10540 goto compile;
10541 case NODE_IMAGINARY:
10542 *value_p = rb_node_imaginary_literal_val(node);
10543 goto compile;
10544 case NODE_ENCODING:
10545 *value_p = rb_node_encoding_val(node);
10546
10547 compile:
10548 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10549 *shareable_literal_p = 1;
10550 return COMPILE_OK;
10551
10552 case NODE_DSTR:
10553 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10554 if (shareable == rb_parser_shareable_literal) {
10555 /*
10556 * NEW_CALL(node, idUMinus, 0, loc);
10557 *
10558 * -"#{var}"
10559 */
10560 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10561 }
10562 *value_p = Qundef;
10563 *shareable_literal_p = 1;
10564 return COMPILE_OK;
10565
10566 case NODE_STR:{
10567 VALUE lit = rb_node_str_string_val(node);
10568 ADD_INSN1(ret, node, putobject, lit);
10569 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10570 *value_p = lit;
10571 *shareable_literal_p = 1;
10572
10573 return COMPILE_OK;
10574 }
10575
10576 case NODE_FILE:{
10577 VALUE lit = rb_node_file_path_val(node);
10578 ADD_INSN1(ret, node, putobject, lit);
10579 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10580 *value_p = lit;
10581 *shareable_literal_p = 1;
10582
10583 return COMPILE_OK;
10584 }
10585
10586 case NODE_ZLIST:{
10587 VALUE lit = rb_ary_new();
10588 OBJ_FREEZE(lit);
10589 ADD_INSN1(ret, node, putobject, lit);
10590 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10591 *value_p = lit;
10592 *shareable_literal_p = 1;
10593
10594 return COMPILE_OK;
10595 }
10596
10597 case NODE_LIST:{
10598 INIT_ANCHOR(anchor);
10599 lit = rb_ary_new();
10600 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10601 VALUE val;
10602 int shareable_literal_p2;
10603 NODE *elt = RNODE_LIST(n)->nd_head;
10604 if (elt) {
10605 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10606 if (shareable_literal_p2) {
10607 /* noop */
10608 }
10609 else if (RTEST(lit)) {
10610 rb_ary_clear(lit);
10611 lit = Qfalse;
10612 }
10613 }
10614 if (RTEST(lit)) {
10615 if (!UNDEF_P(val)) {
10616 rb_ary_push(lit, val);
10617 }
10618 else {
10619 rb_ary_clear(lit);
10620 lit = Qnil; /* make shareable at runtime */
10621 }
10622 }
10623 }
10624 break;
10625 }
10626 case NODE_HASH:{
10627 if (!RNODE_HASH(node)->nd_brace) {
10628 *value_p = Qundef;
10629 *shareable_literal_p = 0;
10630 return COMPILE_OK;
10631 }
10632 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10633 if (!RNODE_LIST(n)->nd_head) {
10634 // If the hash node have a keyword splat, fall back to the default case.
10635 goto compile_shareable;
10636 }
10637 }
10638
10639 INIT_ANCHOR(anchor);
10640 lit = rb_hash_new();
10641 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10642 VALUE key_val = 0;
10643 VALUE value_val = 0;
10644 int shareable_literal_p2;
10645 NODE *key = RNODE_LIST(n)->nd_head;
10646 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10647 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10648 if (shareable_literal_p2) {
10649 /* noop */
10650 }
10651 else if (RTEST(lit)) {
10652 rb_hash_clear(lit);
10653 lit = Qfalse;
10654 }
10655 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10656 if (shareable_literal_p2) {
10657 /* noop */
10658 }
10659 else if (RTEST(lit)) {
10660 rb_hash_clear(lit);
10661 lit = Qfalse;
10662 }
10663 if (RTEST(lit)) {
10664 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10665 rb_hash_aset(lit, key_val, value_val);
10666 }
10667 else {
10668 rb_hash_clear(lit);
10669 lit = Qnil; /* make shareable at runtime */
10670 }
10671 }
10672 }
10673 break;
10674 }
10675
10676 default:
10677
10678 compile_shareable:
10679 if (shareable == rb_parser_shareable_literal &&
10680 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10681 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10682 *value_p = Qundef;
10683 *shareable_literal_p = 1;
10684 return COMPILE_OK;
10685 }
10686 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10687 *value_p = Qundef;
10688 *shareable_literal_p = 0;
10689 return COMPILE_OK;
10690 }
10691
10692 /* Array or Hash that does not have keyword splat */
10693 if (!lit) {
10694 if (nd_type(node) == NODE_LIST) {
10695 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10696 }
10697 else if (nd_type(node) == NODE_HASH) {
10698 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10699 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10700 }
10701 *value_p = Qundef;
10702 *shareable_literal_p = 0;
10703 ADD_SEQ(ret, anchor);
10704 return COMPILE_OK;
10705 }
10706 if (NIL_P(lit)) {
10707 // if shareable_literal, all elements should have been ensured
10708 // as shareable
10709 if (nd_type(node) == NODE_LIST) {
10710 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10711 }
10712 else if (nd_type(node) == NODE_HASH) {
10713 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10714 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10715 }
10716 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10717 *value_p = Qundef;
10718 *shareable_literal_p = 1;
10719 }
10720 else {
10722 ADD_INSN1(ret, node, putobject, val);
10723 RB_OBJ_WRITTEN(iseq, Qundef, val);
10724 *value_p = val;
10725 *shareable_literal_p = 1;
10726 }
10727
10728 return COMPILE_OK;
10729}
10730
10731static int
10732compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10733{
10734 int literal_p = 0;
10735 VALUE val;
10736 DECL_ANCHOR(anchor);
10737 INIT_ANCHOR(anchor);
10738
10739 switch (shareable) {
10740 case rb_parser_shareable_none:
10741 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10742 return COMPILE_OK;
10743
10744 case rb_parser_shareable_literal:
10745 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10746 ADD_SEQ(ret, anchor);
10747 return COMPILE_OK;
10748
10749 case rb_parser_shareable_copy:
10750 case rb_parser_shareable_everything:
10751 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10752 if (!literal_p) {
10753 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10754 }
10755 else {
10756 ADD_SEQ(ret, anchor);
10757 }
10758 return COMPILE_OK;
10759 default:
10760 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10761 }
10762}
10763
10764static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10772static int
10773iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10774{
10775 if (node == 0) {
10776 if (!popped) {
10777 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10778 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10779 debugs("node: NODE_NIL(implicit)\n");
10780 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10781 }
10782 return COMPILE_OK;
10783 }
10784 return iseq_compile_each0(iseq, ret, node, popped);
10785}
10786
10787static int
10788iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10789{
10790 const int line = (int)nd_line(node);
10791 const enum node_type type = nd_type(node);
10792 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10793
10794 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10795 /* ignore */
10796 }
10797 else {
10798 if (nd_fl_newline(node)) {
10799 int event = RUBY_EVENT_LINE;
10800 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10801 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10802 event |= RUBY_EVENT_COVERAGE_LINE;
10803 }
10804 ADD_TRACE(ret, event);
10805 }
10806 }
10807
10808 debug_node_start(node);
10809#undef BEFORE_RETURN
10810#define BEFORE_RETURN debug_node_end()
10811
10812 switch (type) {
10813 case NODE_BLOCK:
10814 CHECK(compile_block(iseq, ret, node, popped));
10815 break;
10816 case NODE_IF:
10817 case NODE_UNLESS:
10818 CHECK(compile_if(iseq, ret, node, popped, type));
10819 break;
10820 case NODE_CASE:
10821 CHECK(compile_case(iseq, ret, node, popped));
10822 break;
10823 case NODE_CASE2:
10824 CHECK(compile_case2(iseq, ret, node, popped));
10825 break;
10826 case NODE_CASE3:
10827 CHECK(compile_case3(iseq, ret, node, popped));
10828 break;
10829 case NODE_WHILE:
10830 case NODE_UNTIL:
10831 CHECK(compile_loop(iseq, ret, node, popped, type));
10832 break;
10833 case NODE_FOR:
10834 case NODE_ITER:
10835 CHECK(compile_iter(iseq, ret, node, popped));
10836 break;
10837 case NODE_FOR_MASGN:
10838 CHECK(compile_for_masgn(iseq, ret, node, popped));
10839 break;
10840 case NODE_BREAK:
10841 CHECK(compile_break(iseq, ret, node, popped));
10842 break;
10843 case NODE_NEXT:
10844 CHECK(compile_next(iseq, ret, node, popped));
10845 break;
10846 case NODE_REDO:
10847 CHECK(compile_redo(iseq, ret, node, popped));
10848 break;
10849 case NODE_RETRY:
10850 CHECK(compile_retry(iseq, ret, node, popped));
10851 break;
10852 case NODE_BEGIN:{
10853 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10854 break;
10855 }
10856 case NODE_RESCUE:
10857 CHECK(compile_rescue(iseq, ret, node, popped));
10858 break;
10859 case NODE_RESBODY:
10860 CHECK(compile_resbody(iseq, ret, node, popped));
10861 break;
10862 case NODE_ENSURE:
10863 CHECK(compile_ensure(iseq, ret, node, popped));
10864 break;
10865
10866 case NODE_AND:
10867 case NODE_OR:{
10868 LABEL *end_label = NEW_LABEL(line);
10869 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10870 if (!popped) {
10871 ADD_INSN(ret, node, dup);
10872 }
10873 if (type == NODE_AND) {
10874 ADD_INSNL(ret, node, branchunless, end_label);
10875 }
10876 else {
10877 ADD_INSNL(ret, node, branchif, end_label);
10878 }
10879 if (!popped) {
10880 ADD_INSN(ret, node, pop);
10881 }
10882 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10883 ADD_LABEL(ret, end_label);
10884 break;
10885 }
10886
10887 case NODE_MASGN:{
10888 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10889 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10890 compile_massign(iseq, ret, node, popped);
10891 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10892 break;
10893 }
10894
10895 case NODE_LASGN:{
10896 ID id = RNODE_LASGN(node)->nd_vid;
10897 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10898
10899 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10900 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10901
10902 if (!popped) {
10903 ADD_INSN(ret, node, dup);
10904 }
10905 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10906 break;
10907 }
10908 case NODE_DASGN: {
10909 int idx, lv, ls;
10910 ID id = RNODE_DASGN(node)->nd_vid;
10911 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10912 debugi("dassn id", rb_id2str(id) ? id : '*');
10913
10914 if (!popped) {
10915 ADD_INSN(ret, node, dup);
10916 }
10917
10918 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10919
10920 if (idx < 0) {
10921 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10922 rb_id2str(id));
10923 goto ng;
10924 }
10925 ADD_SETLOCAL(ret, node, ls - idx, lv);
10926 break;
10927 }
10928 case NODE_GASGN:{
10929 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10930
10931 if (!popped) {
10932 ADD_INSN(ret, node, dup);
10933 }
10934 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10935 break;
10936 }
10937 case NODE_IASGN:{
10938 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10939 if (!popped) {
10940 ADD_INSN(ret, node, dup);
10941 }
10942 ADD_INSN2(ret, node, setinstancevariable,
10943 ID2SYM(RNODE_IASGN(node)->nd_vid),
10944 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10945 break;
10946 }
10947 case NODE_CDECL:{
10948 if (RNODE_CDECL(node)->nd_vid) {
10949 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10950
10951 if (!popped) {
10952 ADD_INSN(ret, node, dup);
10953 }
10954
10955 ADD_INSN1(ret, node, putspecialobject,
10956 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10957 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10958 }
10959 else {
10960 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10961 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10962 ADD_INSN(ret, node, swap);
10963
10964 if (!popped) {
10965 ADD_INSN1(ret, node, topn, INT2FIX(1));
10966 ADD_INSN(ret, node, swap);
10967 }
10968
10969 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10970 }
10971 break;
10972 }
10973 case NODE_CVASGN:{
10974 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10975 if (!popped) {
10976 ADD_INSN(ret, node, dup);
10977 }
10978 ADD_INSN2(ret, node, setclassvariable,
10979 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10980 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10981 break;
10982 }
10983 case NODE_OP_ASGN1:
10984 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10985 break;
10986 case NODE_OP_ASGN2:
10987 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10988 break;
10989 case NODE_OP_CDECL:
10990 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10991 break;
10992 case NODE_OP_ASGN_AND:
10993 case NODE_OP_ASGN_OR:
10994 CHECK(compile_op_log(iseq, ret, node, popped, type));
10995 break;
10996 case NODE_CALL: /* obj.foo */
10997 case NODE_OPCALL: /* foo[] */
10998 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10999 break;
11000 }
11001 case NODE_QCALL: /* obj&.foo */
11002 case NODE_FCALL: /* foo() */
11003 case NODE_VCALL: /* foo (variable or call) */
11004 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11005 goto ng;
11006 }
11007 break;
11008 case NODE_SUPER:
11009 case NODE_ZSUPER:
11010 CHECK(compile_super(iseq, ret, node, popped, type));
11011 break;
11012 case NODE_LIST:{
11013 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11014 break;
11015 }
11016 case NODE_ZLIST:{
11017 if (!popped) {
11018 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11019 }
11020 break;
11021 }
11022 case NODE_HASH:
11023 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11024 break;
11025 case NODE_RETURN:
11026 CHECK(compile_return(iseq, ret, node, popped));
11027 break;
11028 case NODE_YIELD:
11029 CHECK(compile_yield(iseq, ret, node, popped));
11030 break;
11031 case NODE_LVAR:{
11032 if (!popped) {
11033 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11034 }
11035 break;
11036 }
11037 case NODE_DVAR:{
11038 int lv, idx, ls;
11039 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11040 if (!popped) {
11041 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11042 if (idx < 0) {
11043 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11044 rb_id2str(RNODE_DVAR(node)->nd_vid));
11045 goto ng;
11046 }
11047 ADD_GETLOCAL(ret, node, ls - idx, lv);
11048 }
11049 break;
11050 }
11051 case NODE_GVAR:{
11052 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11053 if (popped) {
11054 ADD_INSN(ret, node, pop);
11055 }
11056 break;
11057 }
11058 case NODE_IVAR:{
11059 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11060 if (!popped) {
11061 ADD_INSN2(ret, node, getinstancevariable,
11062 ID2SYM(RNODE_IVAR(node)->nd_vid),
11063 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11064 }
11065 break;
11066 }
11067 case NODE_CONST:{
11068 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11069
11070 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11071 body->ic_size++;
11072 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11073 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11074 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11075 }
11076 else {
11077 ADD_INSN(ret, node, putnil);
11078 ADD_INSN1(ret, node, putobject, Qtrue);
11079 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11080 }
11081
11082 if (popped) {
11083 ADD_INSN(ret, node, pop);
11084 }
11085 break;
11086 }
11087 case NODE_CVAR:{
11088 if (!popped) {
11089 ADD_INSN2(ret, node, getclassvariable,
11090 ID2SYM(RNODE_CVAR(node)->nd_vid),
11091 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11092 }
11093 break;
11094 }
11095 case NODE_NTH_REF:{
11096 if (!popped) {
11097 if (!RNODE_NTH_REF(node)->nd_nth) {
11098 ADD_INSN(ret, node, putnil);
11099 break;
11100 }
11101 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11102 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11103 }
11104 break;
11105 }
11106 case NODE_BACK_REF:{
11107 if (!popped) {
11108 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11109 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11110 }
11111 break;
11112 }
11113 case NODE_MATCH:
11114 case NODE_MATCH2:
11115 case NODE_MATCH3:
11116 CHECK(compile_match(iseq, ret, node, popped, type));
11117 break;
11118 case NODE_SYM:{
11119 if (!popped) {
11120 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11121 }
11122 break;
11123 }
11124 case NODE_LINE:{
11125 if (!popped) {
11126 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11127 }
11128 break;
11129 }
11130 case NODE_ENCODING:{
11131 if (!popped) {
11132 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11133 }
11134 break;
11135 }
11136 case NODE_INTEGER:{
11137 VALUE lit = rb_node_integer_literal_val(node);
11138 debugp_param("integer", lit);
11139 if (!popped) {
11140 ADD_INSN1(ret, node, putobject, lit);
11141 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11142 }
11143 break;
11144 }
11145 case NODE_FLOAT:{
11146 VALUE lit = rb_node_float_literal_val(node);
11147 debugp_param("float", lit);
11148 if (!popped) {
11149 ADD_INSN1(ret, node, putobject, lit);
11150 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11151 }
11152 break;
11153 }
11154 case NODE_RATIONAL:{
11155 VALUE lit = rb_node_rational_literal_val(node);
11156 debugp_param("rational", lit);
11157 if (!popped) {
11158 ADD_INSN1(ret, node, putobject, lit);
11159 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11160 }
11161 break;
11162 }
11163 case NODE_IMAGINARY:{
11164 VALUE lit = rb_node_imaginary_literal_val(node);
11165 debugp_param("imaginary", lit);
11166 if (!popped) {
11167 ADD_INSN1(ret, node, putobject, lit);
11168 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11169 }
11170 break;
11171 }
11172 case NODE_FILE:
11173 case NODE_STR:{
11174 debugp_param("nd_lit", get_string_value(node));
11175 if (!popped) {
11176 VALUE lit = get_string_value(node);
11177 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11178 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11179 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11180 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11181 }
11182 switch (option->frozen_string_literal) {
11183 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11184 ADD_INSN1(ret, node, putchilledstring, lit);
11185 break;
11186 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11187 ADD_INSN1(ret, node, putstring, lit);
11188 break;
11189 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11190 ADD_INSN1(ret, node, putobject, lit);
11191 break;
11192 default:
11193 rb_bug("invalid frozen_string_literal");
11194 }
11195 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11196 }
11197 break;
11198 }
11199 case NODE_DSTR:{
11200 compile_dstr(iseq, ret, node);
11201
11202 if (popped) {
11203 ADD_INSN(ret, node, pop);
11204 }
11205 break;
11206 }
11207 case NODE_XSTR:{
11208 ADD_CALL_RECEIVER(ret, node);
11209 VALUE str = rb_node_str_string_val(node);
11210 ADD_INSN1(ret, node, putobject, str);
11211 RB_OBJ_WRITTEN(iseq, Qundef, str);
11212 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11213
11214 if (popped) {
11215 ADD_INSN(ret, node, pop);
11216 }
11217 break;
11218 }
11219 case NODE_DXSTR:{
11220 ADD_CALL_RECEIVER(ret, node);
11221 compile_dstr(iseq, ret, node);
11222 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11223
11224 if (popped) {
11225 ADD_INSN(ret, node, pop);
11226 }
11227 break;
11228 }
11229 case NODE_EVSTR:
11230 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11231 break;
11232 case NODE_REGX:{
11233 if (!popped) {
11234 VALUE lit = rb_node_regx_string_val(node);
11235 ADD_INSN1(ret, node, putobject, lit);
11236 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11237 }
11238 break;
11239 }
11240 case NODE_DREGX:
11241 compile_dregx(iseq, ret, node, popped);
11242 break;
11243 case NODE_ONCE:{
11244 int ic_index = body->ise_size++;
11245 const rb_iseq_t *block_iseq;
11246 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11247
11248 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11249 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11250
11251 if (popped) {
11252 ADD_INSN(ret, node, pop);
11253 }
11254 break;
11255 }
11256 case NODE_ARGSCAT:{
11257 if (popped) {
11258 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11259 ADD_INSN1(ret, node, splatarray, Qfalse);
11260 ADD_INSN(ret, node, pop);
11261 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11262 ADD_INSN1(ret, node, splatarray, Qfalse);
11263 ADD_INSN(ret, node, pop);
11264 }
11265 else {
11266 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11267 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11268 if (nd_type_p(body_node, NODE_LIST)) {
11269 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11270 }
11271 else {
11272 CHECK(COMPILE(ret, "argscat body", body_node));
11273 ADD_INSN(ret, node, concattoarray);
11274 }
11275 }
11276 break;
11277 }
11278 case NODE_ARGSPUSH:{
11279 if (popped) {
11280 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11281 ADD_INSN1(ret, node, splatarray, Qfalse);
11282 ADD_INSN(ret, node, pop);
11283 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11284 }
11285 else {
11286 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11287 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11288 if (keyword_node_p(body_node)) {
11289 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11290 ADD_INSN(ret, node, pushtoarraykwsplat);
11291 }
11292 else if (static_literal_node_p(body_node, iseq, false)) {
11293 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11294 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11295 }
11296 else {
11297 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11298 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11299 }
11300 }
11301 break;
11302 }
11303 case NODE_SPLAT:{
11304 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11305 ADD_INSN1(ret, node, splatarray, Qtrue);
11306
11307 if (popped) {
11308 ADD_INSN(ret, node, pop);
11309 }
11310 break;
11311 }
11312 case NODE_DEFN:{
11313 ID mid = RNODE_DEFN(node)->nd_mid;
11314 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11315 rb_id2str(mid),
11316 ISEQ_TYPE_METHOD, line);
11317
11318 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11319 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11320 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11321
11322 if (!popped) {
11323 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11324 }
11325
11326 break;
11327 }
11328 case NODE_DEFS:{
11329 ID mid = RNODE_DEFS(node)->nd_mid;
11330 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11331 rb_id2str(mid),
11332 ISEQ_TYPE_METHOD, line);
11333
11334 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11335 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11336 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11337 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11338
11339 if (!popped) {
11340 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11341 }
11342 break;
11343 }
11344 case NODE_ALIAS:{
11345 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11346 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11347 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11348 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11349 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11350
11351 if (popped) {
11352 ADD_INSN(ret, node, pop);
11353 }
11354 break;
11355 }
11356 case NODE_VALIAS:{
11357 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11358 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11359 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11360 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11361
11362 if (popped) {
11363 ADD_INSN(ret, node, pop);
11364 }
11365 break;
11366 }
11367 case NODE_UNDEF:{
11368 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11369
11370 for (long i = 0; i < ary->len; i++) {
11371 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11372 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11373 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11374 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11375
11376 if (i < ary->len - 1) {
11377 ADD_INSN(ret, node, pop);
11378 }
11379 }
11380
11381 if (popped) {
11382 ADD_INSN(ret, node, pop);
11383 }
11384 break;
11385 }
11386 case NODE_CLASS:{
11387 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11388 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11389 ISEQ_TYPE_CLASS, line);
11390 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11391 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11392 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11393
11394 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11395 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11396 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11397
11398 if (popped) {
11399 ADD_INSN(ret, node, pop);
11400 }
11401 break;
11402 }
11403 case NODE_MODULE:{
11404 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11405 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11406 ISEQ_TYPE_CLASS, line);
11407 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11408 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11409
11410 ADD_INSN (ret, node, putnil); /* dummy */
11411 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11412 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11413
11414 if (popped) {
11415 ADD_INSN(ret, node, pop);
11416 }
11417 break;
11418 }
11419 case NODE_SCLASS:{
11420 ID singletonclass;
11421 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11422 ISEQ_TYPE_CLASS, line);
11423
11424 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11425 ADD_INSN (ret, node, putnil);
11426 CONST_ID(singletonclass, "singletonclass");
11427 ADD_INSN3(ret, node, defineclass,
11428 ID2SYM(singletonclass), singleton_class,
11429 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11430 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11431
11432 if (popped) {
11433 ADD_INSN(ret, node, pop);
11434 }
11435 break;
11436 }
11437 case NODE_COLON2:
11438 CHECK(compile_colon2(iseq, ret, node, popped));
11439 break;
11440 case NODE_COLON3:
11441 CHECK(compile_colon3(iseq, ret, node, popped));
11442 break;
11443 case NODE_DOT2:
11444 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11445 break;
11446 case NODE_DOT3:
11447 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11448 break;
11449 case NODE_FLIP2:
11450 case NODE_FLIP3:{
11451 LABEL *lend = NEW_LABEL(line);
11452 LABEL *ltrue = NEW_LABEL(line);
11453 LABEL *lfalse = NEW_LABEL(line);
11454 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11455 ltrue, lfalse));
11456 ADD_LABEL(ret, ltrue);
11457 ADD_INSN1(ret, node, putobject, Qtrue);
11458 ADD_INSNL(ret, node, jump, lend);
11459 ADD_LABEL(ret, lfalse);
11460 ADD_INSN1(ret, node, putobject, Qfalse);
11461 ADD_LABEL(ret, lend);
11462 break;
11463 }
11464 case NODE_SELF:{
11465 if (!popped) {
11466 ADD_INSN(ret, node, putself);
11467 }
11468 break;
11469 }
11470 case NODE_NIL:{
11471 if (!popped) {
11472 ADD_INSN(ret, node, putnil);
11473 }
11474 break;
11475 }
11476 case NODE_TRUE:{
11477 if (!popped) {
11478 ADD_INSN1(ret, node, putobject, Qtrue);
11479 }
11480 break;
11481 }
11482 case NODE_FALSE:{
11483 if (!popped) {
11484 ADD_INSN1(ret, node, putobject, Qfalse);
11485 }
11486 break;
11487 }
11488 case NODE_ERRINFO:
11489 CHECK(compile_errinfo(iseq, ret, node, popped));
11490 break;
11491 case NODE_DEFINED:
11492 if (!popped) {
11493 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11494 }
11495 break;
11496 case NODE_POSTEXE:{
11497 /* compiled to:
11498 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11499 */
11500 int is_index = body->ise_size++;
11502 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11503 const rb_iseq_t *once_iseq =
11504 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11505
11506 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11507 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11508
11509 if (popped) {
11510 ADD_INSN(ret, node, pop);
11511 }
11512 break;
11513 }
11514 case NODE_KW_ARG:
11515 CHECK(compile_kw_arg(iseq, ret, node, popped));
11516 break;
11517 case NODE_DSYM:{
11518 compile_dstr(iseq, ret, node);
11519 if (!popped) {
11520 ADD_INSN(ret, node, intern);
11521 }
11522 else {
11523 ADD_INSN(ret, node, pop);
11524 }
11525 break;
11526 }
11527 case NODE_ATTRASGN:
11528 CHECK(compile_attrasgn(iseq, ret, node, popped));
11529 break;
11530 case NODE_LAMBDA:{
11531 /* compile same as lambda{...} */
11532 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11533 VALUE argc = INT2FIX(0);
11534
11535 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11536 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11537 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11538
11539 if (popped) {
11540 ADD_INSN(ret, node, pop);
11541 }
11542 break;
11543 }
11544 default:
11545 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11546 ng:
11547 debug_node_end();
11548 return COMPILE_NG;
11549 }
11550
11551 debug_node_end();
11552 return COMPILE_OK;
11553}
11554
11555/***************************/
11556/* instruction information */
11557/***************************/
11558
11559static int
11560insn_data_length(INSN *iobj)
11561{
11562 return insn_len(iobj->insn_id);
11563}
11564
11565static int
11566calc_sp_depth(int depth, INSN *insn)
11567{
11568 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11569}
11570
11571static VALUE
11572opobj_inspect(VALUE obj)
11573{
11574 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11575 switch (BUILTIN_TYPE(obj)) {
11576 case T_STRING:
11577 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11578 break;
11579 case T_ARRAY:
11580 obj = rb_ary_dup(obj);
11581 break;
11582 default:
11583 break;
11584 }
11585 }
11586 return rb_inspect(obj);
11587}
11588
11589
11590
11591static VALUE
11592insn_data_to_s_detail(INSN *iobj)
11593{
11594 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11595
11596 if (iobj->operands) {
11597 const char *types = insn_op_types(iobj->insn_id);
11598 int j;
11599
11600 for (j = 0; types[j]; j++) {
11601 char type = types[j];
11602
11603 switch (type) {
11604 case TS_OFFSET: /* label(destination position) */
11605 {
11606 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11607 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11608 break;
11609 }
11610 break;
11611 case TS_ISEQ: /* iseq */
11612 {
11613 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11614 VALUE val = Qnil;
11615 if (0 && iseq) { /* TODO: invalidate now */
11616 val = (VALUE)iseq;
11617 }
11618 rb_str_concat(str, opobj_inspect(val));
11619 }
11620 break;
11621 case TS_LINDEX:
11622 case TS_NUM: /* ulong */
11623 case TS_VALUE: /* VALUE */
11624 {
11625 VALUE v = OPERAND_AT(iobj, j);
11626 if (!CLASS_OF(v))
11627 rb_str_cat2(str, "<hidden>");
11628 else {
11629 rb_str_concat(str, opobj_inspect(v));
11630 }
11631 break;
11632 }
11633 case TS_ID: /* ID */
11634 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11635 break;
11636 case TS_IC: /* inline cache */
11637 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11638 break;
11639 case TS_IVC: /* inline ivar cache */
11640 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11641 break;
11642 case TS_ICVARC: /* inline cvar cache */
11643 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11644 break;
11645 case TS_ISE: /* inline storage entry */
11646 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11647 break;
11648 case TS_CALLDATA: /* we store these as call infos at compile time */
11649 {
11650 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11651 rb_str_cat2(str, "<calldata:");
11652 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11653 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11654 break;
11655 }
11656 case TS_CDHASH: /* case/when condition cache */
11657 rb_str_cat2(str, "<ch>");
11658 break;
11659 case TS_FUNCPTR:
11660 {
11661 void *func = (void *)OPERAND_AT(iobj, j);
11662#ifdef HAVE_DLADDR
11663 Dl_info info;
11664 if (dladdr(func, &info) && info.dli_sname) {
11665 rb_str_cat2(str, info.dli_sname);
11666 break;
11667 }
11668#endif
11669 rb_str_catf(str, "<%p>", func);
11670 }
11671 break;
11672 case TS_BUILTIN:
11673 rb_str_cat2(str, "<TS_BUILTIN>");
11674 break;
11675 default:{
11676 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11677 }
11678 }
11679 if (types[j + 1]) {
11680 rb_str_cat2(str, ", ");
11681 }
11682 }
11683 }
11684 return str;
11685}
11686
11687static void
11688dump_disasm_list(const LINK_ELEMENT *link)
11689{
11690 dump_disasm_list_with_cursor(link, NULL, NULL);
11691}
11692
11693static void
11694dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11695{
11696 int pos = 0;
11697 INSN *iobj;
11698 LABEL *lobj;
11699 VALUE str;
11700
11701 printf("-- raw disasm--------\n");
11702
11703 while (link) {
11704 if (curr) printf(curr == link ? "*" : " ");
11705 switch (link->type) {
11706 case ISEQ_ELEMENT_INSN:
11707 {
11708 iobj = (INSN *)link;
11709 str = insn_data_to_s_detail(iobj);
11710 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11711 pos += insn_data_length(iobj);
11712 break;
11713 }
11714 case ISEQ_ELEMENT_LABEL:
11715 {
11716 lobj = (LABEL *)link;
11717 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11718 dest == lobj ? " <---" : "");
11719 break;
11720 }
11721 case ISEQ_ELEMENT_TRACE:
11722 {
11723 TRACE *trace = (TRACE *)link;
11724 printf(" trace: %0x\n", trace->event);
11725 break;
11726 }
11727 case ISEQ_ELEMENT_ADJUST:
11728 {
11729 ADJUST *adjust = (ADJUST *)link;
11730 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11731 break;
11732 }
11733 default:
11734 /* ignore */
11735 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11736 }
11737 link = link->next;
11738 }
11739 printf("---------------------\n");
11740 fflush(stdout);
11741}
11742
11743int
11744rb_insn_len(VALUE insn)
11745{
11746 return insn_len(insn);
11747}
11748
11749const char *
11750rb_insns_name(int i)
11751{
11752 return insn_name(i);
11753}
11754
11755VALUE
11756rb_insns_name_array(void)
11757{
11758 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11759 int i;
11760 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11761 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11762 }
11763 return rb_ary_freeze(ary);
11764}
11765
11766static LABEL *
11767register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11768{
11769 LABEL *label = 0;
11770 st_data_t tmp;
11771 obj = rb_to_symbol_type(obj);
11772
11773 if (st_lookup(labels_table, obj, &tmp) == 0) {
11774 label = NEW_LABEL(0);
11775 st_insert(labels_table, obj, (st_data_t)label);
11776 }
11777 else {
11778 label = (LABEL *)tmp;
11779 }
11780 LABEL_REF(label);
11781 return label;
11782}
11783
11784static VALUE
11785get_exception_sym2type(VALUE sym)
11786{
11787 static VALUE symRescue, symEnsure, symRetry;
11788 static VALUE symBreak, symRedo, symNext;
11789
11790 if (symRescue == 0) {
11791 symRescue = ID2SYM(rb_intern_const("rescue"));
11792 symEnsure = ID2SYM(rb_intern_const("ensure"));
11793 symRetry = ID2SYM(rb_intern_const("retry"));
11794 symBreak = ID2SYM(rb_intern_const("break"));
11795 symRedo = ID2SYM(rb_intern_const("redo"));
11796 symNext = ID2SYM(rb_intern_const("next"));
11797 }
11798
11799 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11800 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11801 if (sym == symRetry) return CATCH_TYPE_RETRY;
11802 if (sym == symBreak) return CATCH_TYPE_BREAK;
11803 if (sym == symRedo) return CATCH_TYPE_REDO;
11804 if (sym == symNext) return CATCH_TYPE_NEXT;
11805 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11806 return 0;
11807}
11808
11809static int
11810iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11811 VALUE exception)
11812{
11813 int i;
11814
11815 for (i=0; i<RARRAY_LEN(exception); i++) {
11816 const rb_iseq_t *eiseq;
11817 VALUE v, type;
11818 LABEL *lstart, *lend, *lcont;
11819 unsigned int sp;
11820
11821 v = rb_to_array_type(RARRAY_AREF(exception, i));
11822 if (RARRAY_LEN(v) != 6) {
11823 rb_raise(rb_eSyntaxError, "wrong exception entry");
11824 }
11825 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11826 if (NIL_P(RARRAY_AREF(v, 1))) {
11827 eiseq = NULL;
11828 }
11829 else {
11830 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11831 }
11832
11833 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11834 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11835 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11836 sp = NUM2UINT(RARRAY_AREF(v, 5));
11837
11838 /* TODO: Dirty Hack! Fix me */
11839 if (type == CATCH_TYPE_RESCUE ||
11840 type == CATCH_TYPE_BREAK ||
11841 type == CATCH_TYPE_NEXT) {
11842 ++sp;
11843 }
11844
11845 lcont->sp = sp;
11846
11847 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11848
11849 RB_GC_GUARD(v);
11850 }
11851 return COMPILE_OK;
11852}
11853
11854static struct st_table *
11855insn_make_insn_table(void)
11856{
11857 struct st_table *table;
11858 int i;
11859 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11860
11861 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11862 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11863 }
11864
11865 return table;
11866}
11867
11868static const rb_iseq_t *
11869iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11870{
11871 VALUE iseqw;
11872 const rb_iseq_t *loaded_iseq;
11873
11874 if (RB_TYPE_P(op, T_ARRAY)) {
11875 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11876 }
11877 else if (CLASS_OF(op) == rb_cISeq) {
11878 iseqw = op;
11879 }
11880 else {
11881 rb_raise(rb_eSyntaxError, "ISEQ is required");
11882 }
11883
11884 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11885 return loaded_iseq;
11886}
11887
11888static VALUE
11889iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11890{
11891 ID mid = 0;
11892 int orig_argc = 0;
11893 unsigned int flag = 0;
11894 struct rb_callinfo_kwarg *kw_arg = 0;
11895
11896 if (!NIL_P(op)) {
11897 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11898 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11899 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11900 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11901
11902 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11903 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11904 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11905
11906 if (!NIL_P(vkw_arg)) {
11907 int i;
11908 int len = RARRAY_LENINT(vkw_arg);
11909 size_t n = rb_callinfo_kwarg_bytes(len);
11910
11911 kw_arg = xmalloc(n);
11912 kw_arg->references = 0;
11913 kw_arg->keyword_len = len;
11914 for (i = 0; i < len; i++) {
11915 VALUE kw = RARRAY_AREF(vkw_arg, i);
11916 SYM2ID(kw); /* make immortal */
11917 kw_arg->keywords[i] = kw;
11918 }
11919 }
11920 }
11921
11922 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11923 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11924 return (VALUE)ci;
11925}
11926
11927static rb_event_flag_t
11928event_name_to_flag(VALUE sym)
11929{
11930#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11931 CHECK_EVENT(RUBY_EVENT_LINE);
11932 CHECK_EVENT(RUBY_EVENT_CLASS);
11933 CHECK_EVENT(RUBY_EVENT_END);
11934 CHECK_EVENT(RUBY_EVENT_CALL);
11935 CHECK_EVENT(RUBY_EVENT_RETURN);
11936 CHECK_EVENT(RUBY_EVENT_B_CALL);
11937 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11938 CHECK_EVENT(RUBY_EVENT_RESCUE);
11939#undef CHECK_EVENT
11940 return RUBY_EVENT_NONE;
11941}
11942
11943static int
11944iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11945 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11946{
11947 /* TODO: body should be frozen */
11948 long i, len = RARRAY_LEN(body);
11949 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11950 int j;
11951 int line_no = 0, node_id = -1, insn_idx = 0;
11952 int ret = COMPILE_OK;
11953
11954 /*
11955 * index -> LABEL *label
11956 */
11957 static struct st_table *insn_table;
11958
11959 if (insn_table == 0) {
11960 insn_table = insn_make_insn_table();
11961 }
11962
11963 for (i=0; i<len; i++) {
11964 VALUE obj = RARRAY_AREF(body, i);
11965
11966 if (SYMBOL_P(obj)) {
11967 rb_event_flag_t event;
11968 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11969 ADD_TRACE(anchor, event);
11970 }
11971 else {
11972 LABEL *label = register_label(iseq, labels_table, obj);
11973 ADD_LABEL(anchor, label);
11974 }
11975 }
11976 else if (FIXNUM_P(obj)) {
11977 line_no = NUM2INT(obj);
11978 }
11979 else if (RB_TYPE_P(obj, T_ARRAY)) {
11980 VALUE *argv = 0;
11981 int argc = RARRAY_LENINT(obj) - 1;
11982 st_data_t insn_id;
11983 VALUE insn;
11984
11985 if (node_ids) {
11986 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11987 }
11988
11989 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11990 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11991 /* TODO: exception */
11992 COMPILE_ERROR(iseq, line_no,
11993 "unknown instruction: %+"PRIsVALUE, insn);
11994 ret = COMPILE_NG;
11995 break;
11996 }
11997
11998 if (argc != insn_len((VALUE)insn_id)-1) {
11999 COMPILE_ERROR(iseq, line_no,
12000 "operand size mismatch");
12001 ret = COMPILE_NG;
12002 break;
12003 }
12004
12005 if (argc > 0) {
12006 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12007
12008 // add element before operand setup to make GC root
12009 ADD_ELEM(anchor,
12010 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12011 (enum ruby_vminsn_type)insn_id, argc, argv));
12012
12013 for (j=0; j<argc; j++) {
12014 VALUE op = rb_ary_entry(obj, j+1);
12015 switch (insn_op_type((VALUE)insn_id, j)) {
12016 case TS_OFFSET: {
12017 LABEL *label = register_label(iseq, labels_table, op);
12018 argv[j] = (VALUE)label;
12019 break;
12020 }
12021 case TS_LINDEX:
12022 case TS_NUM:
12023 (void)NUM2INT(op);
12024 argv[j] = op;
12025 break;
12026 case TS_VALUE:
12027 argv[j] = op;
12028 RB_OBJ_WRITTEN(iseq, Qundef, op);
12029 break;
12030 case TS_ISEQ:
12031 {
12032 if (op != Qnil) {
12033 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12034 argv[j] = v;
12035 RB_OBJ_WRITTEN(iseq, Qundef, v);
12036 }
12037 else {
12038 argv[j] = 0;
12039 }
12040 }
12041 break;
12042 case TS_ISE:
12043 argv[j] = op;
12044 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12045 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12046 }
12047 break;
12048 case TS_IC:
12049 {
12050 VALUE segments = rb_ary_new();
12051 op = rb_to_array_type(op);
12052
12053 for (int i = 0; i < RARRAY_LEN(op); i++) {
12054 VALUE sym = RARRAY_AREF(op, i);
12055 sym = rb_to_symbol_type(sym);
12056 rb_ary_push(segments, sym);
12057 }
12058
12059 RB_GC_GUARD(op);
12060 argv[j] = segments;
12061 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12062 ISEQ_BODY(iseq)->ic_size++;
12063 }
12064 break;
12065 case TS_IVC: /* inline ivar cache */
12066 argv[j] = op;
12067 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12068 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12069 }
12070 break;
12071 case TS_ICVARC: /* inline cvar cache */
12072 argv[j] = op;
12073 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12074 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12075 }
12076 break;
12077 case TS_CALLDATA:
12078 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12079 break;
12080 case TS_ID:
12081 argv[j] = rb_to_symbol_type(op);
12082 break;
12083 case TS_CDHASH:
12084 {
12085 int i;
12086 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12087
12088 RHASH_TBL_RAW(map)->type = &cdhash_type;
12089 op = rb_to_array_type(op);
12090 for (i=0; i<RARRAY_LEN(op); i+=2) {
12091 VALUE key = RARRAY_AREF(op, i);
12092 VALUE sym = RARRAY_AREF(op, i+1);
12093 LABEL *label =
12094 register_label(iseq, labels_table, sym);
12095 rb_hash_aset(map, key, (VALUE)label | 1);
12096 }
12097 RB_GC_GUARD(op);
12098 argv[j] = map;
12099 RB_OBJ_WRITTEN(iseq, Qundef, map);
12100 }
12101 break;
12102 case TS_FUNCPTR:
12103 {
12104#if SIZEOF_VALUE <= SIZEOF_LONG
12105 long funcptr = NUM2LONG(op);
12106#else
12107 LONG_LONG funcptr = NUM2LL(op);
12108#endif
12109 argv[j] = (VALUE)funcptr;
12110 }
12111 break;
12112 default:
12113 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12114 }
12115 }
12116 }
12117 else {
12118 ADD_ELEM(anchor,
12119 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12120 (enum ruby_vminsn_type)insn_id, argc, NULL));
12121 }
12122 }
12123 else {
12124 rb_raise(rb_eTypeError, "unexpected object for instruction");
12125 }
12126 }
12127 RTYPEDDATA_DATA(labels_wrapper) = 0;
12128 RB_GC_GUARD(labels_wrapper);
12129 validate_labels(iseq, labels_table);
12130 if (!ret) return ret;
12131 return iseq_setup(iseq, anchor);
12132}
12133
12134#define CHECK_ARRAY(v) rb_to_array_type(v)
12135#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12136
12137static int
12138int_param(int *dst, VALUE param, VALUE sym)
12139{
12140 VALUE val = rb_hash_aref(param, sym);
12141 if (FIXNUM_P(val)) {
12142 *dst = FIX2INT(val);
12143 return TRUE;
12144 }
12145 else if (!NIL_P(val)) {
12146 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12147 sym, val);
12148 }
12149 return FALSE;
12150}
12151
12152static const struct rb_iseq_param_keyword *
12153iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12154{
12155 int i, j;
12156 int len = RARRAY_LENINT(keywords);
12157 int default_len;
12158 VALUE key, sym, default_val;
12159 VALUE *dvs;
12160 ID *ids;
12161 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12162
12163 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12164
12165 keyword->num = len;
12166#define SYM(s) ID2SYM(rb_intern_const(#s))
12167 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12168 i = keyword->bits_start - keyword->num;
12169 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12170#undef SYM
12171
12172 /* required args */
12173 for (i = 0; i < len; i++) {
12174 VALUE val = RARRAY_AREF(keywords, i);
12175
12176 if (!SYMBOL_P(val)) {
12177 goto default_values;
12178 }
12179 ids[i] = SYM2ID(val);
12180 keyword->required_num++;
12181 }
12182
12183 default_values: /* note: we intentionally preserve `i' from previous loop */
12184 default_len = len - i;
12185 if (default_len == 0) {
12186 keyword->table = ids;
12187 return keyword;
12188 }
12189 else if (default_len < 0) {
12191 }
12192
12193 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12194
12195 for (j = 0; i < len; i++, j++) {
12196 key = RARRAY_AREF(keywords, i);
12197 CHECK_ARRAY(key);
12198
12199 switch (RARRAY_LEN(key)) {
12200 case 1:
12201 sym = RARRAY_AREF(key, 0);
12202 default_val = Qundef;
12203 break;
12204 case 2:
12205 sym = RARRAY_AREF(key, 0);
12206 default_val = RARRAY_AREF(key, 1);
12207 break;
12208 default:
12209 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12210 }
12211 ids[i] = SYM2ID(sym);
12212 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12213 }
12214
12215 keyword->table = ids;
12216 keyword->default_values = dvs;
12217
12218 return keyword;
12219}
12220
12221static void
12222iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12223{
12224 rb_gc_mark_and_move(obj);
12225}
12226
12227void
12228rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12229{
12230 INSN *iobj = 0;
12231 size_t size = sizeof(INSN);
12232 unsigned int pos = 0;
12233
12234 while (storage) {
12235#ifdef STRICT_ALIGNMENT
12236 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12237#else
12238 const size_t padding = 0; /* expected to be optimized by compiler */
12239#endif /* STRICT_ALIGNMENT */
12240 size_t offset = pos + size + padding;
12241 if (offset > storage->size || offset > storage->pos) {
12242 pos = 0;
12243 storage = storage->next;
12244 }
12245 else {
12246#ifdef STRICT_ALIGNMENT
12247 pos += (int)padding;
12248#endif /* STRICT_ALIGNMENT */
12249
12250 iobj = (INSN *)&storage->buff[pos];
12251
12252 if (iobj->operands) {
12253 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12254 }
12255 pos += (int)size;
12256 }
12257 }
12258}
12259
12260static const rb_data_type_t labels_wrapper_type = {
12261 .wrap_struct_name = "compiler/labels_wrapper",
12262 .function = {
12263 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12264 .dfree = (RUBY_DATA_FUNC)st_free_table,
12265 },
12266 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12267};
12268
12269void
12270rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12271 VALUE exception, VALUE body)
12272{
12273#define SYM(s) ID2SYM(rb_intern_const(#s))
12274 int i, len;
12275 unsigned int arg_size, local_size, stack_max;
12276 ID *tbl;
12277 struct st_table *labels_table = st_init_numtable();
12278 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12279 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12280 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12281 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12282 DECL_ANCHOR(anchor);
12283 INIT_ANCHOR(anchor);
12284
12285 len = RARRAY_LENINT(locals);
12286 ISEQ_BODY(iseq)->local_table_size = len;
12287 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12288
12289 for (i = 0; i < len; i++) {
12290 VALUE lv = RARRAY_AREF(locals, i);
12291
12292 if (sym_arg_rest == lv) {
12293 tbl[i] = 0;
12294 }
12295 else {
12296 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12297 }
12298 }
12299
12300#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12301 if (INT_PARAM(lead_num)) {
12302 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12303 }
12304 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12305 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12306 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12307 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12308#undef INT_PARAM
12309 {
12310#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12311 int x;
12312 INT_PARAM(arg_size);
12313 INT_PARAM(local_size);
12314 INT_PARAM(stack_max);
12315#undef INT_PARAM
12316 }
12317
12318 VALUE node_ids = Qfalse;
12319#ifdef USE_ISEQ_NODE_ID
12320 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12321 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12322 rb_raise(rb_eTypeError, "node_ids is not an array");
12323 }
12324#endif
12325
12326 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12327 len = RARRAY_LENINT(arg_opt_labels);
12328 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12329
12330 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12331 VALUE *opt_table = ALLOC_N(VALUE, len);
12332
12333 for (i = 0; i < len; i++) {
12334 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12335 LABEL *label = register_label(iseq, labels_table, ent);
12336 opt_table[i] = (VALUE)label;
12337 }
12338
12339 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12340 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12341 }
12342 }
12343 else if (!NIL_P(arg_opt_labels)) {
12344 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12345 arg_opt_labels);
12346 }
12347
12348 if (RB_TYPE_P(keywords, T_ARRAY)) {
12349 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12350 }
12351 else if (!NIL_P(keywords)) {
12352 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12353 keywords);
12354 }
12355
12356 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12357 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12358 }
12359
12360 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12361 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12362 }
12363
12364 if (int_param(&i, params, SYM(kwrest))) {
12365 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12366 if (keyword == NULL) {
12367 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12368 }
12369 keyword->rest_start = i;
12370 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12371 }
12372#undef SYM
12373 iseq_calc_param_size(iseq);
12374
12375 /* exception */
12376 iseq_build_from_ary_exception(iseq, labels_table, exception);
12377
12378 /* body */
12379 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12380
12381 ISEQ_BODY(iseq)->param.size = arg_size;
12382 ISEQ_BODY(iseq)->local_table_size = local_size;
12383 ISEQ_BODY(iseq)->stack_max = stack_max;
12384}
12385
12386/* for parser */
12387
12388int
12389rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12390{
12391 if (iseq) {
12392 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12393 while (body->type == ISEQ_TYPE_BLOCK ||
12394 body->type == ISEQ_TYPE_RESCUE ||
12395 body->type == ISEQ_TYPE_ENSURE ||
12396 body->type == ISEQ_TYPE_EVAL ||
12397 body->type == ISEQ_TYPE_MAIN
12398 ) {
12399 unsigned int i;
12400
12401 for (i = 0; i < body->local_table_size; i++) {
12402 if (body->local_table[i] == id) {
12403 return 1;
12404 }
12405 }
12406 iseq = body->parent_iseq;
12407 body = ISEQ_BODY(iseq);
12408 }
12409 }
12410 return 0;
12411}
12412
12413int
12414rb_local_defined(ID id, const rb_iseq_t *iseq)
12415{
12416 if (iseq) {
12417 unsigned int i;
12418 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12419
12420 for (i=0; i<body->local_table_size; i++) {
12421 if (body->local_table[i] == id) {
12422 return 1;
12423 }
12424 }
12425 }
12426 return 0;
12427}
12428
12429/* ISeq binary format */
12430
12431#ifndef IBF_ISEQ_DEBUG
12432#define IBF_ISEQ_DEBUG 0
12433#endif
12434
12435#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12436#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12437#endif
12438
12439typedef uint32_t ibf_offset_t;
12440#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12441
12442#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12443#ifdef RUBY_DEVEL
12444#define IBF_DEVEL_VERSION 4
12445#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12446#else
12447#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12448#endif
12449
12450static const char IBF_ENDIAN_MARK =
12451#ifdef WORDS_BIGENDIAN
12452 'b'
12453#else
12454 'l'
12455#endif
12456 ;
12457
12459 char magic[4]; /* YARB */
12460 uint32_t major_version;
12461 uint32_t minor_version;
12462 uint32_t size;
12463 uint32_t extra_size;
12464
12465 uint32_t iseq_list_size;
12466 uint32_t global_object_list_size;
12467 ibf_offset_t iseq_list_offset;
12468 ibf_offset_t global_object_list_offset;
12469 uint8_t endian;
12470 uint8_t wordsize; /* assume no 2048-bit CPU */
12471};
12472
12474 VALUE str;
12475 st_table *obj_table; /* obj -> obj number */
12476};
12477
12478struct ibf_dump {
12479 st_table *iseq_table; /* iseq -> iseq number */
12480 struct ibf_dump_buffer global_buffer;
12481 struct ibf_dump_buffer *current_buffer;
12482};
12483
12485 const char *buff;
12486 ibf_offset_t size;
12487
12488 VALUE obj_list; /* [obj0, ...] */
12489 unsigned int obj_list_size;
12490 ibf_offset_t obj_list_offset;
12491};
12492
12493struct ibf_load {
12494 const struct ibf_header *header;
12495 VALUE iseq_list; /* [iseq0, ...] */
12496 struct ibf_load_buffer global_buffer;
12497 VALUE loader_obj;
12498 rb_iseq_t *iseq;
12499 VALUE str;
12500 struct ibf_load_buffer *current_buffer;
12501};
12502
12504 long size;
12505 VALUE buffer[1];
12506};
12507
12508static void
12509pinned_list_mark(void *ptr)
12510{
12511 long i;
12512 struct pinned_list *list = (struct pinned_list *)ptr;
12513 for (i = 0; i < list->size; i++) {
12514 if (list->buffer[i]) {
12515 rb_gc_mark(list->buffer[i]);
12516 }
12517 }
12518}
12519
12520static const rb_data_type_t pinned_list_type = {
12521 "pinned_list",
12522 {
12523 pinned_list_mark,
12525 NULL, // No external memory to report,
12526 },
12527 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12528};
12529
12530static VALUE
12531pinned_list_fetch(VALUE list, long offset)
12532{
12533 struct pinned_list * ptr;
12534
12535 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12536
12537 if (offset >= ptr->size) {
12538 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12539 }
12540
12541 return ptr->buffer[offset];
12542}
12543
12544static void
12545pinned_list_store(VALUE list, long offset, VALUE object)
12546{
12547 struct pinned_list * ptr;
12548
12549 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12550
12551 if (offset >= ptr->size) {
12552 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12553 }
12554
12555 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12556}
12557
12558static VALUE
12559pinned_list_new(long size)
12560{
12561 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12562 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12563 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12564 ptr->size = size;
12565 return obj_list;
12566}
12567
12568static ibf_offset_t
12569ibf_dump_pos(struct ibf_dump *dump)
12570{
12571 long pos = RSTRING_LEN(dump->current_buffer->str);
12572#if SIZEOF_LONG > SIZEOF_INT
12573 if (pos >= UINT_MAX) {
12574 rb_raise(rb_eRuntimeError, "dump size exceeds");
12575 }
12576#endif
12577 return (unsigned int)pos;
12578}
12579
12580static void
12581ibf_dump_align(struct ibf_dump *dump, size_t align)
12582{
12583 ibf_offset_t pos = ibf_dump_pos(dump);
12584 if (pos % align) {
12585 static const char padding[sizeof(VALUE)];
12586 size_t size = align - ((size_t)pos % align);
12587#if SIZEOF_LONG > SIZEOF_INT
12588 if (pos + size >= UINT_MAX) {
12589 rb_raise(rb_eRuntimeError, "dump size exceeds");
12590 }
12591#endif
12592 for (; size > sizeof(padding); size -= sizeof(padding)) {
12593 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12594 }
12595 rb_str_cat(dump->current_buffer->str, padding, size);
12596 }
12597}
12598
12599static ibf_offset_t
12600ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12601{
12602 ibf_offset_t pos = ibf_dump_pos(dump);
12603#if SIZEOF_LONG > SIZEOF_INT
12604 /* ensure the resulting dump does not exceed UINT_MAX */
12605 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12606 rb_raise(rb_eRuntimeError, "dump size exceeds");
12607 }
12608#endif
12609 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12610 return pos;
12611}
12612
12613static ibf_offset_t
12614ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12615{
12616 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12617}
12618
12619static void
12620ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12621{
12622 VALUE str = dump->current_buffer->str;
12623 char *ptr = RSTRING_PTR(str);
12624 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12625 rb_bug("ibf_dump_overwrite: overflow");
12626 memcpy(ptr + offset, buff, size);
12627}
12628
12629static const void *
12630ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12631{
12632 ibf_offset_t beg = *offset;
12633 *offset += size;
12634 return load->current_buffer->buff + beg;
12635}
12636
12637static void *
12638ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12639{
12640 void *buff = ruby_xmalloc2(x, y);
12641 size_t size = x * y;
12642 memcpy(buff, load->current_buffer->buff + offset, size);
12643 return buff;
12644}
12645
12646#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12647
12648#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12649#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12650#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12651#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12652#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12653
12654static int
12655ibf_table_lookup(struct st_table *table, st_data_t key)
12656{
12657 st_data_t val;
12658
12659 if (st_lookup(table, key, &val)) {
12660 return (int)val;
12661 }
12662 else {
12663 return -1;
12664 }
12665}
12666
12667static int
12668ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12669{
12670 int index = ibf_table_lookup(table, key);
12671
12672 if (index < 0) { /* not found */
12673 index = (int)table->num_entries;
12674 st_insert(table, key, (st_data_t)index);
12675 }
12676
12677 return index;
12678}
12679
12680/* dump/load generic */
12681
12682static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12683
12684static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12685static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12686
12687static st_table *
12688ibf_dump_object_table_new(void)
12689{
12690 st_table *obj_table = st_init_numtable(); /* need free */
12691 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12692
12693 return obj_table;
12694}
12695
12696static VALUE
12697ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12698{
12699 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12700}
12701
12702static VALUE
12703ibf_dump_id(struct ibf_dump *dump, ID id)
12704{
12705 if (id == 0 || rb_id2name(id) == NULL) {
12706 return 0;
12707 }
12708 return ibf_dump_object(dump, rb_id2sym(id));
12709}
12710
12711static ID
12712ibf_load_id(const struct ibf_load *load, const ID id_index)
12713{
12714 if (id_index == 0) {
12715 return 0;
12716 }
12717 VALUE sym = ibf_load_object(load, id_index);
12718 if (rb_integer_type_p(sym)) {
12719 /* Load hidden local variables as indexes */
12720 return NUM2ULONG(sym);
12721 }
12722 return rb_sym2id(sym);
12723}
12724
12725/* dump/load: code */
12726
12727static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12728
12729static int
12730ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12731{
12732 if (iseq == NULL) {
12733 return -1;
12734 }
12735 else {
12736 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12737 }
12738}
12739
12740static unsigned char
12741ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12742{
12743 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12744 return (unsigned char)load->current_buffer->buff[(*offset)++];
12745}
12746
12747/*
12748 * Small uint serialization
12749 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12750 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12751 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12752 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12753 * ...
12754 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12755 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12756 */
12757static void
12758ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12759{
12760 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12761 ibf_dump_write(dump, &x, sizeof(VALUE));
12762 return;
12763 }
12764
12765 enum { max_byte_length = sizeof(VALUE) + 1 };
12766
12767 unsigned char bytes[max_byte_length];
12768 ibf_offset_t n;
12769
12770 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12771 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12772 }
12773
12774 x <<= 1;
12775 x |= 1;
12776 x <<= n;
12777 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12778 n++;
12779
12780 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12781}
12782
12783static VALUE
12784ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12785{
12786 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12787 union { char s[sizeof(VALUE)]; VALUE v; } x;
12788
12789 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12790 *offset += sizeof(VALUE);
12791
12792 return x.v;
12793 }
12794
12795 enum { max_byte_length = sizeof(VALUE) + 1 };
12796
12797 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12798 const unsigned char c = buffer[*offset];
12799
12800 ibf_offset_t n =
12801 c & 1 ? 1 :
12802 c == 0 ? 9 : ntz_int32(c) + 1;
12803 VALUE x = (VALUE)c >> n;
12804
12805 if (*offset + n > load->current_buffer->size) {
12806 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12807 }
12808
12809 ibf_offset_t i;
12810 for (i = 1; i < n; i++) {
12811 x <<= 8;
12812 x |= (VALUE)buffer[*offset + i];
12813 }
12814
12815 *offset += n;
12816 return x;
12817}
12818
12819static void
12820ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12821{
12822 // short: index
12823 // short: name.length
12824 // bytes: name
12825 // // omit argc (only verify with name)
12826 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12827
12828 size_t len = strlen(bf->name);
12829 ibf_dump_write_small_value(dump, (VALUE)len);
12830 ibf_dump_write(dump, bf->name, len);
12831}
12832
12833static const struct rb_builtin_function *
12834ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12835{
12836 int i = (int)ibf_load_small_value(load, offset);
12837 int len = (int)ibf_load_small_value(load, offset);
12838 const char *name = (char *)ibf_load_ptr(load, offset, len);
12839
12840 if (0) {
12841 fprintf(stderr, "%.*s!!\n", len, name);
12842 }
12843
12844 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12845 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12846 if (strncmp(table[i].name, name, len) != 0) {
12847 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12848 }
12849 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12850
12851 return &table[i];
12852}
12853
12854static ibf_offset_t
12855ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12856{
12857 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12858 const int iseq_size = body->iseq_size;
12859 int code_index;
12860 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12861
12862 ibf_offset_t offset = ibf_dump_pos(dump);
12863
12864 for (code_index=0; code_index<iseq_size;) {
12865 const VALUE insn = orig_code[code_index++];
12866 const char *types = insn_op_types(insn);
12867 int op_index;
12868
12869 /* opcode */
12870 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12871 ibf_dump_write_small_value(dump, insn);
12872
12873 /* operands */
12874 for (op_index=0; types[op_index]; op_index++, code_index++) {
12875 VALUE op = orig_code[code_index];
12876 VALUE wv;
12877
12878 switch (types[op_index]) {
12879 case TS_CDHASH:
12880 case TS_VALUE:
12881 wv = ibf_dump_object(dump, op);
12882 break;
12883 case TS_ISEQ:
12884 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12885 break;
12886 case TS_IC:
12887 {
12888 IC ic = (IC)op;
12889 VALUE arr = idlist_to_array(ic->segments);
12890 wv = ibf_dump_object(dump, arr);
12891 }
12892 break;
12893 case TS_ISE:
12894 case TS_IVC:
12895 case TS_ICVARC:
12896 {
12898 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12899 }
12900 break;
12901 case TS_CALLDATA:
12902 {
12903 goto skip_wv;
12904 }
12905 case TS_ID:
12906 wv = ibf_dump_id(dump, (ID)op);
12907 break;
12908 case TS_FUNCPTR:
12909 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12910 goto skip_wv;
12911 case TS_BUILTIN:
12912 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12913 goto skip_wv;
12914 default:
12915 wv = op;
12916 break;
12917 }
12918 ibf_dump_write_small_value(dump, wv);
12919 skip_wv:;
12920 }
12921 RUBY_ASSERT(insn_len(insn) == op_index+1);
12922 }
12923
12924 return offset;
12925}
12926
12927static VALUE *
12928ibf_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)
12929{
12930 VALUE iseqv = (VALUE)iseq;
12931 unsigned int code_index;
12932 ibf_offset_t reading_pos = bytecode_offset;
12933 VALUE *code = ALLOC_N(VALUE, iseq_size);
12934
12935 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12936 struct rb_call_data *cd_entries = load_body->call_data;
12937 int ic_index = 0;
12938
12939 iseq_bits_t * mark_offset_bits;
12940
12941 iseq_bits_t tmp[1] = {0};
12942
12943 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12944 mark_offset_bits = tmp;
12945 }
12946 else {
12947 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12948 }
12949 bool needs_bitmap = false;
12950
12951 for (code_index=0; code_index<iseq_size;) {
12952 /* opcode */
12953 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12954 const char *types = insn_op_types(insn);
12955 int op_index;
12956
12957 code_index++;
12958
12959 /* operands */
12960 for (op_index=0; types[op_index]; op_index++, code_index++) {
12961 const char operand_type = types[op_index];
12962 switch (operand_type) {
12963 case TS_VALUE:
12964 {
12965 VALUE op = ibf_load_small_value(load, &reading_pos);
12966 VALUE v = ibf_load_object(load, op);
12967 code[code_index] = v;
12968 if (!SPECIAL_CONST_P(v)) {
12969 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12970 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12971 needs_bitmap = true;
12972 }
12973 break;
12974 }
12975 case TS_CDHASH:
12976 {
12977 VALUE op = ibf_load_small_value(load, &reading_pos);
12978 VALUE v = ibf_load_object(load, op);
12979 v = rb_hash_dup(v); // hash dumped as frozen
12980 RHASH_TBL_RAW(v)->type = &cdhash_type;
12981 rb_hash_rehash(v); // hash function changed
12982 freeze_hide_obj(v);
12983
12984 // Overwrite the existing hash in the object list. This
12985 // is to keep the object alive during load time.
12986 // [Bug #17984] [ruby-core:104259]
12987 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12988
12989 code[code_index] = v;
12990 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12991 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12992 needs_bitmap = true;
12993 break;
12994 }
12995 case TS_ISEQ:
12996 {
12997 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12998 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12999 code[code_index] = v;
13000 if (!SPECIAL_CONST_P(v)) {
13001 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13002 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13003 needs_bitmap = true;
13004 }
13005 break;
13006 }
13007 case TS_IC:
13008 {
13009 VALUE op = ibf_load_small_value(load, &reading_pos);
13010 VALUE arr = ibf_load_object(load, op);
13011
13012 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13013 ic->segments = array_to_idlist(arr);
13014
13015 code[code_index] = (VALUE)ic;
13016 }
13017 break;
13018 case TS_ISE:
13019 case TS_ICVARC:
13020 case TS_IVC:
13021 {
13022 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13023
13024 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13025 code[code_index] = (VALUE)ic;
13026
13027 if (operand_type == TS_IVC) {
13028 IVC cache = (IVC)ic;
13029
13030 if (insn == BIN(setinstancevariable)) {
13031 ID iv_name = (ID)code[code_index - 1];
13032 cache->iv_set_name = iv_name;
13033 }
13034 else {
13035 cache->iv_set_name = 0;
13036 }
13037
13038 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13039 }
13040
13041 }
13042 break;
13043 case TS_CALLDATA:
13044 {
13045 code[code_index] = (VALUE)cd_entries++;
13046 }
13047 break;
13048 case TS_ID:
13049 {
13050 VALUE op = ibf_load_small_value(load, &reading_pos);
13051 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13052 }
13053 break;
13054 case TS_FUNCPTR:
13055 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13056 break;
13057 case TS_BUILTIN:
13058 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13059 break;
13060 default:
13061 code[code_index] = ibf_load_small_value(load, &reading_pos);
13062 continue;
13063 }
13064 }
13065 if (insn_len(insn) != op_index+1) {
13066 rb_raise(rb_eRuntimeError, "operand size mismatch");
13067 }
13068 }
13069
13070 load_body->iseq_encoded = code;
13071 load_body->iseq_size = code_index;
13072
13073 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13074 load_body->mark_bits.single = mark_offset_bits[0];
13075 }
13076 else {
13077 if (needs_bitmap) {
13078 load_body->mark_bits.list = mark_offset_bits;
13079 }
13080 else {
13081 load_body->mark_bits.list = 0;
13082 ruby_xfree(mark_offset_bits);
13083 }
13084 }
13085
13086 RUBY_ASSERT(code_index == iseq_size);
13087 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13088 return code;
13089}
13090
13091static ibf_offset_t
13092ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13093{
13094 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13095
13096 if (opt_num > 0) {
13097 IBF_W_ALIGN(VALUE);
13098 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13099 }
13100 else {
13101 return ibf_dump_pos(dump);
13102 }
13103}
13104
13105static VALUE *
13106ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13107{
13108 if (opt_num > 0) {
13109 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13110 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13111 return table;
13112 }
13113 else {
13114 return NULL;
13115 }
13116}
13117
13118static ibf_offset_t
13119ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13120{
13121 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13122
13123 if (kw) {
13124 struct rb_iseq_param_keyword dump_kw = *kw;
13125 int dv_num = kw->num - kw->required_num;
13126 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13127 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13128 int i;
13129
13130 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13131 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13132
13133 dump_kw.table = IBF_W(ids, ID, kw->num);
13134 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13135 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13136 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13137 }
13138 else {
13139 return 0;
13140 }
13141}
13142
13143static const struct rb_iseq_param_keyword *
13144ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13145{
13146 if (param_keyword_offset) {
13147 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13148 int dv_num = kw->num - kw->required_num;
13149 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13150
13151 int i;
13152 for (i=0; i<dv_num; i++) {
13153 dvs[i] = ibf_load_object(load, dvs[i]);
13154 }
13155
13156 // Will be set once the local table is loaded.
13157 kw->table = NULL;
13158
13159 kw->default_values = dvs;
13160 return kw;
13161 }
13162 else {
13163 return NULL;
13164 }
13165}
13166
13167static ibf_offset_t
13168ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13169{
13170 ibf_offset_t offset = ibf_dump_pos(dump);
13171 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13172
13173 unsigned int i;
13174 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13175 ibf_dump_write_small_value(dump, entries[i].line_no);
13176#ifdef USE_ISEQ_NODE_ID
13177 ibf_dump_write_small_value(dump, entries[i].node_id);
13178#endif
13179 ibf_dump_write_small_value(dump, entries[i].events);
13180 }
13181
13182 return offset;
13183}
13184
13185static struct iseq_insn_info_entry *
13186ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13187{
13188 ibf_offset_t reading_pos = body_offset;
13189 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13190
13191 unsigned int i;
13192 for (i = 0; i < size; i++) {
13193 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13194#ifdef USE_ISEQ_NODE_ID
13195 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13196#endif
13197 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13198 }
13199
13200 return entries;
13201}
13202
13203static ibf_offset_t
13204ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13205{
13206 ibf_offset_t offset = ibf_dump_pos(dump);
13207
13208 unsigned int last = 0;
13209 unsigned int i;
13210 for (i = 0; i < size; i++) {
13211 ibf_dump_write_small_value(dump, positions[i] - last);
13212 last = positions[i];
13213 }
13214
13215 return offset;
13216}
13217
13218static unsigned int *
13219ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13220{
13221 ibf_offset_t reading_pos = positions_offset;
13222 unsigned int *positions = ALLOC_N(unsigned int, size);
13223
13224 unsigned int last = 0;
13225 unsigned int i;
13226 for (i = 0; i < size; i++) {
13227 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13228 last = positions[i];
13229 }
13230
13231 return positions;
13232}
13233
13234static ibf_offset_t
13235ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13236{
13237 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13238 const int size = body->local_table_size;
13239 ID *table = ALLOCA_N(ID, size);
13240 int i;
13241
13242 for (i=0; i<size; i++) {
13243 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13244 if (v == 0) {
13245 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13246 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13247 }
13248 table[i] = v;
13249 }
13250
13251 IBF_W_ALIGN(ID);
13252 return ibf_dump_write(dump, table, sizeof(ID) * size);
13253}
13254
13255static ID *
13256ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13257{
13258 if (size > 0) {
13259 ID *table = IBF_R(local_table_offset, ID, size);
13260 int i;
13261
13262 for (i=0; i<size; i++) {
13263 table[i] = ibf_load_id(load, table[i]);
13264 }
13265 return table;
13266 }
13267 else {
13268 return NULL;
13269 }
13270}
13271
13272static ibf_offset_t
13273ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13274{
13275 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13276
13277 if (table) {
13278 int *iseq_indices = ALLOCA_N(int, table->size);
13279 unsigned int i;
13280
13281 for (i=0; i<table->size; i++) {
13282 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13283 }
13284
13285 const ibf_offset_t offset = ibf_dump_pos(dump);
13286
13287 for (i=0; i<table->size; i++) {
13288 ibf_dump_write_small_value(dump, iseq_indices[i]);
13289 ibf_dump_write_small_value(dump, table->entries[i].type);
13290 ibf_dump_write_small_value(dump, table->entries[i].start);
13291 ibf_dump_write_small_value(dump, table->entries[i].end);
13292 ibf_dump_write_small_value(dump, table->entries[i].cont);
13293 ibf_dump_write_small_value(dump, table->entries[i].sp);
13294 }
13295 return offset;
13296 }
13297 else {
13298 return ibf_dump_pos(dump);
13299 }
13300}
13301
13302static void
13303ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13304{
13305 if (size) {
13306 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13307 table->size = size;
13308 ISEQ_BODY(parent_iseq)->catch_table = table;
13309
13310 ibf_offset_t reading_pos = catch_table_offset;
13311
13312 unsigned int i;
13313 for (i=0; i<table->size; i++) {
13314 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13315 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13316 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13317 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13318 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13319 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13320
13321 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13322 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13323 }
13324 }
13325 else {
13326 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13327 }
13328}
13329
13330static ibf_offset_t
13331ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13332{
13333 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13334 const unsigned int ci_size = body->ci_size;
13335 const struct rb_call_data *cds = body->call_data;
13336
13337 ibf_offset_t offset = ibf_dump_pos(dump);
13338
13339 unsigned int i;
13340
13341 for (i = 0; i < ci_size; i++) {
13342 const struct rb_callinfo *ci = cds[i].ci;
13343 if (ci != NULL) {
13344 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13345 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13346 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13347
13348 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13349 if (kwarg) {
13350 int len = kwarg->keyword_len;
13351 ibf_dump_write_small_value(dump, len);
13352 for (int j=0; j<len; j++) {
13353 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13354 ibf_dump_write_small_value(dump, keyword);
13355 }
13356 }
13357 else {
13358 ibf_dump_write_small_value(dump, 0);
13359 }
13360 }
13361 else {
13362 // TODO: truncate NULL ci from call_data.
13363 ibf_dump_write_small_value(dump, (VALUE)-1);
13364 }
13365 }
13366
13367 return offset;
13368}
13369
13371 ID id;
13372 VALUE name;
13373 VALUE val;
13374};
13375
13377 size_t num;
13378 struct outer_variable_pair pairs[1];
13379};
13380
13381static enum rb_id_table_iterator_result
13382store_outer_variable(ID id, VALUE val, void *dump)
13383{
13384 struct outer_variable_list *ovlist = dump;
13385 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13386 pair->id = id;
13387 pair->name = rb_id2str(id);
13388 pair->val = val;
13389 return ID_TABLE_CONTINUE;
13390}
13391
13392static int
13393outer_variable_cmp(const void *a, const void *b, void *arg)
13394{
13395 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13396 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13397
13398 if (!ap->name) {
13399 return -1;
13400 }
13401 else if (!bp->name) {
13402 return 1;
13403 }
13404
13405 return rb_str_cmp(ap->name, bp->name);
13406}
13407
13408static ibf_offset_t
13409ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13410{
13411 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13412
13413 ibf_offset_t offset = ibf_dump_pos(dump);
13414
13415 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13416 ibf_dump_write_small_value(dump, (VALUE)size);
13417 if (size > 0) {
13418 VALUE buff;
13419 size_t buffsize =
13420 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13421 offsetof(struct outer_variable_list, pairs),
13422 rb_eArgError);
13423 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13424 ovlist->num = 0;
13425 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13426 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13427 for (size_t i = 0; i < size; ++i) {
13428 ID id = ovlist->pairs[i].id;
13429 ID val = ovlist->pairs[i].val;
13430 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13431 ibf_dump_write_small_value(dump, val);
13432 }
13433 }
13434
13435 return offset;
13436}
13437
13438/* note that we dump out rb_call_info but load back rb_call_data */
13439static void
13440ibf_load_ci_entries(const struct ibf_load *load,
13441 ibf_offset_t ci_entries_offset,
13442 unsigned int ci_size,
13443 struct rb_call_data **cd_ptr)
13444{
13445 if (!ci_size) {
13446 *cd_ptr = NULL;
13447 return;
13448 }
13449
13450 ibf_offset_t reading_pos = ci_entries_offset;
13451
13452 unsigned int i;
13453
13454 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13455 *cd_ptr = cds;
13456
13457 for (i = 0; i < ci_size; i++) {
13458 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13459 if (mid_index != (VALUE)-1) {
13460 ID mid = ibf_load_id(load, mid_index);
13461 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13462 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13463
13464 struct rb_callinfo_kwarg *kwarg = NULL;
13465 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13466 if (kwlen > 0) {
13467 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13468 kwarg->references = 0;
13469 kwarg->keyword_len = kwlen;
13470 for (int j=0; j<kwlen; j++) {
13471 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13472 kwarg->keywords[j] = ibf_load_object(load, keyword);
13473 }
13474 }
13475
13476 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13477 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13478 cds[i].cc = vm_cc_empty();
13479 }
13480 else {
13481 // NULL ci
13482 cds[i].ci = NULL;
13483 cds[i].cc = NULL;
13484 }
13485 }
13486}
13487
13488static struct rb_id_table *
13489ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13490{
13491 ibf_offset_t reading_pos = outer_variables_offset;
13492
13493 struct rb_id_table *tbl = NULL;
13494
13495 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13496
13497 if (table_size > 0) {
13498 tbl = rb_id_table_create(table_size);
13499 }
13500
13501 for (size_t i = 0; i < table_size; i++) {
13502 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13503 VALUE value = ibf_load_small_value(load, &reading_pos);
13504 if (!key) key = rb_make_temporary_id(i);
13505 rb_id_table_insert(tbl, key, value);
13506 }
13507
13508 return tbl;
13509}
13510
13511static ibf_offset_t
13512ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13513{
13514 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13515
13516 unsigned int *positions;
13517
13518 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13519
13520 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13521 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13522 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13523
13524#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13525 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13526
13527 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13528 struct ibf_dump_buffer buffer;
13529 buffer.str = rb_str_new(0, 0);
13530 buffer.obj_table = ibf_dump_object_table_new();
13531 dump->current_buffer = &buffer;
13532#endif
13533
13534 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13535 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13536 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13537 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13538 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13539
13540 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13541 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13542 ruby_xfree(positions);
13543
13544 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13545 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13546 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13547 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13548 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13549 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13550 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13551 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13552
13553#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13554 ibf_offset_t local_obj_list_offset;
13555 unsigned int local_obj_list_size;
13556
13557 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13558#endif
13559
13560 ibf_offset_t body_offset = ibf_dump_pos(dump);
13561
13562 /* dump the constant body */
13563 unsigned int param_flags =
13564 (body->param.flags.has_lead << 0) |
13565 (body->param.flags.has_opt << 1) |
13566 (body->param.flags.has_rest << 2) |
13567 (body->param.flags.has_post << 3) |
13568 (body->param.flags.has_kw << 4) |
13569 (body->param.flags.has_kwrest << 5) |
13570 (body->param.flags.has_block << 6) |
13571 (body->param.flags.ambiguous_param0 << 7) |
13572 (body->param.flags.accepts_no_kwarg << 8) |
13573 (body->param.flags.ruby2_keywords << 9) |
13574 (body->param.flags.anon_rest << 10) |
13575 (body->param.flags.anon_kwrest << 11) |
13576 (body->param.flags.use_block << 12) |
13577 (body->param.flags.forwardable << 13) ;
13578
13579#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13580# define IBF_BODY_OFFSET(x) (x)
13581#else
13582# define IBF_BODY_OFFSET(x) (body_offset - (x))
13583#endif
13584
13585 ibf_dump_write_small_value(dump, body->type);
13586 ibf_dump_write_small_value(dump, body->iseq_size);
13587 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13588 ibf_dump_write_small_value(dump, bytecode_size);
13589 ibf_dump_write_small_value(dump, param_flags);
13590 ibf_dump_write_small_value(dump, body->param.size);
13591 ibf_dump_write_small_value(dump, body->param.lead_num);
13592 ibf_dump_write_small_value(dump, body->param.opt_num);
13593 ibf_dump_write_small_value(dump, body->param.rest_start);
13594 ibf_dump_write_small_value(dump, body->param.post_start);
13595 ibf_dump_write_small_value(dump, body->param.post_num);
13596 ibf_dump_write_small_value(dump, body->param.block_start);
13597 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13598 ibf_dump_write_small_value(dump, param_keyword_offset);
13599 ibf_dump_write_small_value(dump, location_pathobj_index);
13600 ibf_dump_write_small_value(dump, location_base_label_index);
13601 ibf_dump_write_small_value(dump, location_label_index);
13602 ibf_dump_write_small_value(dump, body->location.first_lineno);
13603 ibf_dump_write_small_value(dump, body->location.node_id);
13604 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13605 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13606 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13607 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13608 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13609 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13610 ibf_dump_write_small_value(dump, body->insns_info.size);
13611 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13612 ibf_dump_write_small_value(dump, catch_table_size);
13613 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13614 ibf_dump_write_small_value(dump, parent_iseq_index);
13615 ibf_dump_write_small_value(dump, local_iseq_index);
13616 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13617 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13618 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13619 ibf_dump_write_small_value(dump, body->variable.flip_count);
13620 ibf_dump_write_small_value(dump, body->local_table_size);
13621 ibf_dump_write_small_value(dump, body->ivc_size);
13622 ibf_dump_write_small_value(dump, body->icvarc_size);
13623 ibf_dump_write_small_value(dump, body->ise_size);
13624 ibf_dump_write_small_value(dump, body->ic_size);
13625 ibf_dump_write_small_value(dump, body->ci_size);
13626 ibf_dump_write_small_value(dump, body->stack_max);
13627 ibf_dump_write_small_value(dump, body->builtin_attrs);
13628 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13629
13630#undef IBF_BODY_OFFSET
13631
13632#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13633 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13634
13635 dump->current_buffer = saved_buffer;
13636 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13637
13638 ibf_offset_t offset = ibf_dump_pos(dump);
13639 ibf_dump_write_small_value(dump, iseq_start);
13640 ibf_dump_write_small_value(dump, iseq_length_bytes);
13641 ibf_dump_write_small_value(dump, body_offset);
13642
13643 ibf_dump_write_small_value(dump, local_obj_list_offset);
13644 ibf_dump_write_small_value(dump, local_obj_list_size);
13645
13646 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13647
13648 return offset;
13649#else
13650 return body_offset;
13651#endif
13652}
13653
13654static VALUE
13655ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13656{
13657 VALUE str = ibf_load_object(load, str_index);
13658 if (str != Qnil) {
13659 str = rb_fstring(str);
13660 }
13661 return str;
13662}
13663
13664static void
13665ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13666{
13667 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13668
13669 ibf_offset_t reading_pos = offset;
13670
13671#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13672 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13673 load->current_buffer = &load->global_buffer;
13674
13675 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13676 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13677 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13678
13679 struct ibf_load_buffer buffer;
13680 buffer.buff = load->global_buffer.buff + iseq_start;
13681 buffer.size = iseq_length_bytes;
13682 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13683 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13684 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13685
13686 load->current_buffer = &buffer;
13687 reading_pos = body_offset;
13688#endif
13689
13690#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13691# define IBF_BODY_OFFSET(x) (x)
13692#else
13693# define IBF_BODY_OFFSET(x) (offset - (x))
13694#endif
13695
13696 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13697 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13698 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13699 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13700 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13701 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13702 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13703 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13704 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13705 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13706 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13707 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13708 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13709 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13710 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13711 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13712 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13713 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13714 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13715 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13716 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13717 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13718 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13719 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13720 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13721 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13722 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13723 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13724 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13725 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13726 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13727 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13728 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13729 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13730 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13731 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13732
13733 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13734 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13735 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13736 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13737
13738 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13739 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13740 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13741 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13742
13743 // setup fname and dummy frame
13744 VALUE path = ibf_load_object(load, location_pathobj_index);
13745 {
13746 VALUE realpath = Qnil;
13747
13748 if (RB_TYPE_P(path, T_STRING)) {
13749 realpath = path = rb_fstring(path);
13750 }
13751 else if (RB_TYPE_P(path, T_ARRAY)) {
13752 VALUE pathobj = path;
13753 if (RARRAY_LEN(pathobj) != 2) {
13754 rb_raise(rb_eRuntimeError, "path object size mismatch");
13755 }
13756 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13757 realpath = RARRAY_AREF(pathobj, 1);
13758 if (!NIL_P(realpath)) {
13759 if (!RB_TYPE_P(realpath, T_STRING)) {
13760 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13761 "(%x), path=%+"PRIsVALUE,
13762 realpath, TYPE(realpath), path);
13763 }
13764 realpath = rb_fstring(realpath);
13765 }
13766 }
13767 else {
13768 rb_raise(rb_eRuntimeError, "unexpected path object");
13769 }
13770 rb_iseq_pathobj_set(iseq, path, realpath);
13771 }
13772
13773 // push dummy frame
13774 rb_execution_context_t *ec = GET_EC();
13775 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13776
13777#undef IBF_BODY_OFFSET
13778
13779 load_body->type = type;
13780 load_body->stack_max = stack_max;
13781 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13782 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13783 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13784 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13785 load_body->param.flags.has_kw = FALSE;
13786 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13787 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13788 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13789 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13790 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13791 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13792 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13793 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13794 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13795 load_body->param.size = param_size;
13796 load_body->param.lead_num = param_lead_num;
13797 load_body->param.opt_num = param_opt_num;
13798 load_body->param.rest_start = param_rest_start;
13799 load_body->param.post_start = param_post_start;
13800 load_body->param.post_num = param_post_num;
13801 load_body->param.block_start = param_block_start;
13802 load_body->local_table_size = local_table_size;
13803 load_body->ci_size = ci_size;
13804 load_body->insns_info.size = insns_info_size;
13805
13806 ISEQ_COVERAGE_SET(iseq, Qnil);
13807 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13808 load_body->variable.flip_count = variable_flip_count;
13809 load_body->variable.script_lines = Qnil;
13810
13811 load_body->location.first_lineno = location_first_lineno;
13812 load_body->location.node_id = location_node_id;
13813 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13814 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13815 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13816 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13817 load_body->builtin_attrs = builtin_attrs;
13818 load_body->prism = prism;
13819
13820 load_body->ivc_size = ivc_size;
13821 load_body->icvarc_size = icvarc_size;
13822 load_body->ise_size = ise_size;
13823 load_body->ic_size = ic_size;
13824
13825 if (ISEQ_IS_SIZE(load_body)) {
13826 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13827 }
13828 else {
13829 load_body->is_entries = NULL;
13830 }
13831 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13832 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13833 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13834 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13835 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13836 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13837 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13838 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13839 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13840
13841 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13842 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13843 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13844
13845 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13846 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13847 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13848
13849 // This must be done after the local table is loaded.
13850 if (load_body->param.keyword != NULL) {
13851 RUBY_ASSERT(load_body->local_table);
13852 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13853 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13854 }
13855
13856 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13857#if VM_INSN_INFO_TABLE_IMPL == 2
13858 rb_iseq_insns_info_encode_positions(iseq);
13859#endif
13860
13861 rb_iseq_translate_threaded_code(iseq);
13862
13863#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13864 load->current_buffer = &load->global_buffer;
13865#endif
13866
13867 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13868 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13869
13870#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13871 load->current_buffer = saved_buffer;
13872#endif
13873 verify_call_cache(iseq);
13874
13875 RB_GC_GUARD(dummy_frame);
13876 rb_vm_pop_frame_no_int(ec);
13877}
13878
13880{
13881 struct ibf_dump *dump;
13882 VALUE offset_list;
13883};
13884
13885static int
13886ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13887{
13888 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13889 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13890
13891 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13892 rb_ary_push(args->offset_list, UINT2NUM(offset));
13893
13894 return ST_CONTINUE;
13895}
13896
13897static void
13898ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13899{
13900 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13901
13902 struct ibf_dump_iseq_list_arg args;
13903 args.dump = dump;
13904 args.offset_list = offset_list;
13905
13906 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13907
13908 st_index_t i;
13909 st_index_t size = dump->iseq_table->num_entries;
13910 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13911
13912 for (i = 0; i < size; i++) {
13913 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13914 }
13915
13916 ibf_dump_align(dump, sizeof(ibf_offset_t));
13917 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13918 header->iseq_list_size = (unsigned int)size;
13919}
13920
13921#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13922
13923/*
13924 * Binary format
13925 * - ibf_object_header
13926 * - ibf_object_xxx (xxx is type)
13927 */
13928
13930 unsigned int type: 5;
13931 unsigned int special_const: 1;
13932 unsigned int frozen: 1;
13933 unsigned int internal: 1;
13934};
13935
13936enum ibf_object_class_index {
13937 IBF_OBJECT_CLASS_OBJECT,
13938 IBF_OBJECT_CLASS_ARRAY,
13939 IBF_OBJECT_CLASS_STANDARD_ERROR,
13940 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13941 IBF_OBJECT_CLASS_TYPE_ERROR,
13942 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13943};
13944
13946 long srcstr;
13947 char option;
13948};
13949
13951 long len;
13952 long keyval[FLEX_ARY_LEN];
13953};
13954
13956 long class_index;
13957 long len;
13958 long beg;
13959 long end;
13960 int excl;
13961};
13962
13964 ssize_t slen;
13965 BDIGIT digits[FLEX_ARY_LEN];
13966};
13967
13968enum ibf_object_data_type {
13969 IBF_OBJECT_DATA_ENCODING,
13970};
13971
13973 long a, b;
13974};
13975
13977 long str;
13978};
13979
13980#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13981 ((((offset) - 1) / (align) + 1) * (align))
13982#define IBF_OBJBODY(type, offset) (const type *)\
13983 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13984
13985static const void *
13986ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13987{
13988 if (offset >= load->current_buffer->size) {
13989 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13990 }
13991 return load->current_buffer->buff + offset;
13992}
13993
13994NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13995
13996static void
13997ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13998{
13999 char buff[0x100];
14000 rb_raw_obj_info(buff, sizeof(buff), obj);
14001 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14002}
14003
14004NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14005
14006static VALUE
14007ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14008{
14009 rb_raise(rb_eArgError, "unsupported");
14011}
14012
14013static void
14014ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14015{
14016 enum ibf_object_class_index cindex;
14017 if (obj == rb_cObject) {
14018 cindex = IBF_OBJECT_CLASS_OBJECT;
14019 }
14020 else if (obj == rb_cArray) {
14021 cindex = IBF_OBJECT_CLASS_ARRAY;
14022 }
14023 else if (obj == rb_eStandardError) {
14024 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14025 }
14026 else if (obj == rb_eNoMatchingPatternError) {
14027 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14028 }
14029 else if (obj == rb_eTypeError) {
14030 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14031 }
14032 else if (obj == rb_eNoMatchingPatternKeyError) {
14033 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14034 }
14035 else {
14036 rb_obj_info_dump(obj);
14037 rb_p(obj);
14038 rb_bug("unsupported class");
14039 }
14040 ibf_dump_write_small_value(dump, (VALUE)cindex);
14041}
14042
14043static VALUE
14044ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14045{
14046 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14047
14048 switch (cindex) {
14049 case IBF_OBJECT_CLASS_OBJECT:
14050 return rb_cObject;
14051 case IBF_OBJECT_CLASS_ARRAY:
14052 return rb_cArray;
14053 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14054 return rb_eStandardError;
14055 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14057 case IBF_OBJECT_CLASS_TYPE_ERROR:
14058 return rb_eTypeError;
14059 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14061 }
14062
14063 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14064}
14065
14066
14067static void
14068ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14069{
14070 double dbl = RFLOAT_VALUE(obj);
14071 (void)IBF_W(&dbl, double, 1);
14072}
14073
14074static VALUE
14075ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14076{
14077 const double *dblp = IBF_OBJBODY(double, offset);
14078 return DBL2NUM(*dblp);
14079}
14080
14081static void
14082ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14083{
14084 long encindex = (long)rb_enc_get_index(obj);
14085 long len = RSTRING_LEN(obj);
14086 const char *ptr = RSTRING_PTR(obj);
14087
14088 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14089 rb_encoding *enc = rb_enc_from_index((int)encindex);
14090 const char *enc_name = rb_enc_name(enc);
14091 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14092 }
14093
14094 ibf_dump_write_small_value(dump, encindex);
14095 ibf_dump_write_small_value(dump, len);
14096 IBF_WP(ptr, char, len);
14097}
14098
14099static VALUE
14100ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14101{
14102 ibf_offset_t reading_pos = offset;
14103
14104 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14105 const long len = (long)ibf_load_small_value(load, &reading_pos);
14106 const char *ptr = load->current_buffer->buff + reading_pos;
14107
14108 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14109 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14110 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14111 }
14112
14113 VALUE str;
14114 if (header->frozen && !header->internal) {
14115 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14116 }
14117 else {
14118 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14119
14120 if (header->internal) rb_obj_hide(str);
14121 if (header->frozen) str = rb_fstring(str);
14122 }
14123 return str;
14124}
14125
14126static void
14127ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14128{
14129 VALUE srcstr = RREGEXP_SRC(obj);
14130 struct ibf_object_regexp regexp;
14131 regexp.option = (char)rb_reg_options(obj);
14132 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14133
14134 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14135 ibf_dump_write_small_value(dump, regexp.srcstr);
14136}
14137
14138static VALUE
14139ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14140{
14141 struct ibf_object_regexp regexp;
14142 regexp.option = ibf_load_byte(load, &offset);
14143 regexp.srcstr = ibf_load_small_value(load, &offset);
14144
14145 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14146 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14147
14148 if (header->internal) rb_obj_hide(reg);
14149 if (header->frozen) rb_obj_freeze(reg);
14150
14151 return reg;
14152}
14153
14154static void
14155ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14156{
14157 long i, len = RARRAY_LEN(obj);
14158 ibf_dump_write_small_value(dump, len);
14159 for (i=0; i<len; i++) {
14160 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14161 ibf_dump_write_small_value(dump, index);
14162 }
14163}
14164
14165static VALUE
14166ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14167{
14168 ibf_offset_t reading_pos = offset;
14169
14170 const long len = (long)ibf_load_small_value(load, &reading_pos);
14171
14172 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14173 int i;
14174
14175 for (i=0; i<len; i++) {
14176 const VALUE index = ibf_load_small_value(load, &reading_pos);
14177 rb_ary_push(ary, ibf_load_object(load, index));
14178 }
14179
14180 if (header->frozen) rb_ary_freeze(ary);
14181
14182 return ary;
14183}
14184
14185static int
14186ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14187{
14188 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14189
14190 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14191 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14192
14193 ibf_dump_write_small_value(dump, key_index);
14194 ibf_dump_write_small_value(dump, val_index);
14195 return ST_CONTINUE;
14196}
14197
14198static void
14199ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14200{
14201 long len = RHASH_SIZE(obj);
14202 ibf_dump_write_small_value(dump, (VALUE)len);
14203
14204 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14205}
14206
14207static VALUE
14208ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14209{
14210 long len = (long)ibf_load_small_value(load, &offset);
14211 VALUE obj = rb_hash_new_with_size(len);
14212 int i;
14213
14214 for (i = 0; i < len; i++) {
14215 VALUE key_index = ibf_load_small_value(load, &offset);
14216 VALUE val_index = ibf_load_small_value(load, &offset);
14217
14218 VALUE key = ibf_load_object(load, key_index);
14219 VALUE val = ibf_load_object(load, val_index);
14220 rb_hash_aset(obj, key, val);
14221 }
14222 rb_hash_rehash(obj);
14223
14224 if (header->internal) rb_obj_hide(obj);
14225 if (header->frozen) rb_obj_freeze(obj);
14226
14227 return obj;
14228}
14229
14230static void
14231ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14232{
14233 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14234 struct ibf_object_struct_range range;
14235 VALUE beg, end;
14236 IBF_ZERO(range);
14237 range.len = 3;
14238 range.class_index = 0;
14239
14240 rb_range_values(obj, &beg, &end, &range.excl);
14241 range.beg = (long)ibf_dump_object(dump, beg);
14242 range.end = (long)ibf_dump_object(dump, end);
14243
14244 IBF_W_ALIGN(struct ibf_object_struct_range);
14245 IBF_WV(range);
14246 }
14247 else {
14248 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14249 rb_class_name(CLASS_OF(obj)));
14250 }
14251}
14252
14253static VALUE
14254ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14255{
14256 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14257 VALUE beg = ibf_load_object(load, range->beg);
14258 VALUE end = ibf_load_object(load, range->end);
14259 VALUE obj = rb_range_new(beg, end, range->excl);
14260 if (header->internal) rb_obj_hide(obj);
14261 if (header->frozen) rb_obj_freeze(obj);
14262 return obj;
14263}
14264
14265static void
14266ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14267{
14268 ssize_t len = BIGNUM_LEN(obj);
14269 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14270 BDIGIT *d = BIGNUM_DIGITS(obj);
14271
14272 (void)IBF_W(&slen, ssize_t, 1);
14273 IBF_WP(d, BDIGIT, len);
14274}
14275
14276static VALUE
14277ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14278{
14279 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14280 int sign = bignum->slen > 0;
14281 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14282 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14285 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14286 big_unpack_flags |
14287 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14288 if (header->internal) rb_obj_hide(obj);
14289 if (header->frozen) rb_obj_freeze(obj);
14290 return obj;
14291}
14292
14293static void
14294ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14295{
14296 if (rb_data_is_encoding(obj)) {
14297 rb_encoding *enc = rb_to_encoding(obj);
14298 const char *name = rb_enc_name(enc);
14299 long len = strlen(name) + 1;
14300 long data[2];
14301 data[0] = IBF_OBJECT_DATA_ENCODING;
14302 data[1] = len;
14303 (void)IBF_W(data, long, 2);
14304 IBF_WP(name, char, len);
14305 }
14306 else {
14307 ibf_dump_object_unsupported(dump, obj);
14308 }
14309}
14310
14311static VALUE
14312ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14313{
14314 const long *body = IBF_OBJBODY(long, offset);
14315 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14316 /* const long len = body[1]; */
14317 const char *data = (const char *)&body[2];
14318
14319 switch (type) {
14320 case IBF_OBJECT_DATA_ENCODING:
14321 {
14322 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14323 return encobj;
14324 }
14325 }
14326
14327 return ibf_load_object_unsupported(load, header, offset);
14328}
14329
14330static void
14331ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14332{
14333 long data[2];
14334 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14335 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14336
14337 (void)IBF_W(data, long, 2);
14338}
14339
14340static VALUE
14341ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14342{
14343 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14344 VALUE a = ibf_load_object(load, nums->a);
14345 VALUE b = ibf_load_object(load, nums->b);
14346 VALUE obj = header->type == T_COMPLEX ?
14347 rb_complex_new(a, b) : rb_rational_new(a, b);
14348
14349 if (header->internal) rb_obj_hide(obj);
14350 if (header->frozen) rb_obj_freeze(obj);
14351 return obj;
14352}
14353
14354static void
14355ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14356{
14357 ibf_dump_object_string(dump, rb_sym2str(obj));
14358}
14359
14360static VALUE
14361ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14362{
14363 ibf_offset_t reading_pos = offset;
14364
14365 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14366 const long len = (long)ibf_load_small_value(load, &reading_pos);
14367 const char *ptr = load->current_buffer->buff + reading_pos;
14368
14369 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14370 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14371 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14372 }
14373
14374 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14375 return ID2SYM(id);
14376}
14377
14378typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14379static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14380 ibf_dump_object_unsupported, /* T_NONE */
14381 ibf_dump_object_unsupported, /* T_OBJECT */
14382 ibf_dump_object_class, /* T_CLASS */
14383 ibf_dump_object_unsupported, /* T_MODULE */
14384 ibf_dump_object_float, /* T_FLOAT */
14385 ibf_dump_object_string, /* T_STRING */
14386 ibf_dump_object_regexp, /* T_REGEXP */
14387 ibf_dump_object_array, /* T_ARRAY */
14388 ibf_dump_object_hash, /* T_HASH */
14389 ibf_dump_object_struct, /* T_STRUCT */
14390 ibf_dump_object_bignum, /* T_BIGNUM */
14391 ibf_dump_object_unsupported, /* T_FILE */
14392 ibf_dump_object_data, /* T_DATA */
14393 ibf_dump_object_unsupported, /* T_MATCH */
14394 ibf_dump_object_complex_rational, /* T_COMPLEX */
14395 ibf_dump_object_complex_rational, /* T_RATIONAL */
14396 ibf_dump_object_unsupported, /* 0x10 */
14397 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14398 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14399 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14400 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14401 ibf_dump_object_unsupported, /* T_FIXNUM */
14402 ibf_dump_object_unsupported, /* T_UNDEF */
14403 ibf_dump_object_unsupported, /* 0x17 */
14404 ibf_dump_object_unsupported, /* 0x18 */
14405 ibf_dump_object_unsupported, /* 0x19 */
14406 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14407 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14408 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14409 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14410 ibf_dump_object_unsupported, /* 0x1e */
14411 ibf_dump_object_unsupported, /* 0x1f */
14412};
14413
14414static void
14415ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14416{
14417 unsigned char byte =
14418 (header.type << 0) |
14419 (header.special_const << 5) |
14420 (header.frozen << 6) |
14421 (header.internal << 7);
14422
14423 IBF_WV(byte);
14424}
14425
14426static struct ibf_object_header
14427ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14428{
14429 unsigned char byte = ibf_load_byte(load, offset);
14430
14431 struct ibf_object_header header;
14432 header.type = (byte >> 0) & 0x1f;
14433 header.special_const = (byte >> 5) & 0x01;
14434 header.frozen = (byte >> 6) & 0x01;
14435 header.internal = (byte >> 7) & 0x01;
14436
14437 return header;
14438}
14439
14440static ibf_offset_t
14441ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14442{
14443 struct ibf_object_header obj_header;
14444 ibf_offset_t current_offset;
14445 IBF_ZERO(obj_header);
14446 obj_header.type = TYPE(obj);
14447
14448 IBF_W_ALIGN(ibf_offset_t);
14449 current_offset = ibf_dump_pos(dump);
14450
14451 if (SPECIAL_CONST_P(obj) &&
14452 ! (SYMBOL_P(obj) ||
14453 RB_FLOAT_TYPE_P(obj))) {
14454 obj_header.special_const = TRUE;
14455 obj_header.frozen = TRUE;
14456 obj_header.internal = TRUE;
14457 ibf_dump_object_object_header(dump, obj_header);
14458 ibf_dump_write_small_value(dump, obj);
14459 }
14460 else {
14461 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14462 obj_header.special_const = FALSE;
14463 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14464 ibf_dump_object_object_header(dump, obj_header);
14465 (*dump_object_functions[obj_header.type])(dump, obj);
14466 }
14467
14468 return current_offset;
14469}
14470
14471typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14472static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14473 ibf_load_object_unsupported, /* T_NONE */
14474 ibf_load_object_unsupported, /* T_OBJECT */
14475 ibf_load_object_class, /* T_CLASS */
14476 ibf_load_object_unsupported, /* T_MODULE */
14477 ibf_load_object_float, /* T_FLOAT */
14478 ibf_load_object_string, /* T_STRING */
14479 ibf_load_object_regexp, /* T_REGEXP */
14480 ibf_load_object_array, /* T_ARRAY */
14481 ibf_load_object_hash, /* T_HASH */
14482 ibf_load_object_struct, /* T_STRUCT */
14483 ibf_load_object_bignum, /* T_BIGNUM */
14484 ibf_load_object_unsupported, /* T_FILE */
14485 ibf_load_object_data, /* T_DATA */
14486 ibf_load_object_unsupported, /* T_MATCH */
14487 ibf_load_object_complex_rational, /* T_COMPLEX */
14488 ibf_load_object_complex_rational, /* T_RATIONAL */
14489 ibf_load_object_unsupported, /* 0x10 */
14490 ibf_load_object_unsupported, /* T_NIL */
14491 ibf_load_object_unsupported, /* T_TRUE */
14492 ibf_load_object_unsupported, /* T_FALSE */
14493 ibf_load_object_symbol,
14494 ibf_load_object_unsupported, /* T_FIXNUM */
14495 ibf_load_object_unsupported, /* T_UNDEF */
14496 ibf_load_object_unsupported, /* 0x17 */
14497 ibf_load_object_unsupported, /* 0x18 */
14498 ibf_load_object_unsupported, /* 0x19 */
14499 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14500 ibf_load_object_unsupported, /* T_NODE 0x1b */
14501 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14502 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14503 ibf_load_object_unsupported, /* 0x1e */
14504 ibf_load_object_unsupported, /* 0x1f */
14505};
14506
14507static VALUE
14508ibf_load_object(const struct ibf_load *load, VALUE object_index)
14509{
14510 if (object_index == 0) {
14511 return Qnil;
14512 }
14513 else {
14514 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14515 if (!obj) {
14516 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14517 ibf_offset_t offset = offsets[object_index];
14518 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14519
14520#if IBF_ISEQ_DEBUG
14521 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14522 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14523 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14524 header.type, header.special_const, header.frozen, header.internal);
14525#endif
14526 if (offset >= load->current_buffer->size) {
14527 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14528 }
14529
14530 if (header.special_const) {
14531 ibf_offset_t reading_pos = offset;
14532
14533 obj = ibf_load_small_value(load, &reading_pos);
14534 }
14535 else {
14536 obj = (*load_object_functions[header.type])(load, &header, offset);
14537 }
14538
14539 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14540 }
14541#if IBF_ISEQ_DEBUG
14542 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14543 object_index, obj);
14544#endif
14545 return obj;
14546 }
14547}
14548
14550{
14551 struct ibf_dump *dump;
14552 VALUE offset_list;
14553};
14554
14555static int
14556ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14557{
14558 VALUE obj = (VALUE)key;
14559 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14560
14561 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14562 rb_ary_push(args->offset_list, UINT2NUM(offset));
14563
14564 return ST_CONTINUE;
14565}
14566
14567static void
14568ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14569{
14570 st_table *obj_table = dump->current_buffer->obj_table;
14571 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14572
14573 struct ibf_dump_object_list_arg args;
14574 args.dump = dump;
14575 args.offset_list = offset_list;
14576
14577 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14578
14579 IBF_W_ALIGN(ibf_offset_t);
14580 *obj_list_offset = ibf_dump_pos(dump);
14581
14582 st_index_t size = obj_table->num_entries;
14583 st_index_t i;
14584
14585 for (i=0; i<size; i++) {
14586 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14587 IBF_WV(offset);
14588 }
14589
14590 *obj_list_size = (unsigned int)size;
14591}
14592
14593static void
14594ibf_dump_mark(void *ptr)
14595{
14596 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14597 rb_gc_mark(dump->global_buffer.str);
14598
14599 rb_mark_set(dump->global_buffer.obj_table);
14600 rb_mark_set(dump->iseq_table);
14601}
14602
14603static void
14604ibf_dump_free(void *ptr)
14605{
14606 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14607 if (dump->global_buffer.obj_table) {
14608 st_free_table(dump->global_buffer.obj_table);
14609 dump->global_buffer.obj_table = 0;
14610 }
14611 if (dump->iseq_table) {
14612 st_free_table(dump->iseq_table);
14613 dump->iseq_table = 0;
14614 }
14615}
14616
14617static size_t
14618ibf_dump_memsize(const void *ptr)
14619{
14620 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14621 size_t size = 0;
14622 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14623 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14624 return size;
14625}
14626
14627static const rb_data_type_t ibf_dump_type = {
14628 "ibf_dump",
14629 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14630 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14631};
14632
14633static void
14634ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14635{
14636 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14637 dump->iseq_table = NULL;
14638
14639 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14640 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14641 dump->iseq_table = st_init_numtable(); /* need free */
14642
14643 dump->current_buffer = &dump->global_buffer;
14644}
14645
14646VALUE
14647rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14648{
14649 struct ibf_dump *dump;
14650 struct ibf_header header = {{0}};
14651 VALUE dump_obj;
14652 VALUE str;
14653
14654 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14655 ISEQ_BODY(iseq)->local_iseq != iseq) {
14656 rb_raise(rb_eRuntimeError, "should be top of iseq");
14657 }
14658 if (RTEST(ISEQ_COVERAGE(iseq))) {
14659 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14660 }
14661
14662 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14663 ibf_dump_setup(dump, dump_obj);
14664
14665 ibf_dump_write(dump, &header, sizeof(header));
14666 ibf_dump_iseq(dump, iseq);
14667
14668 header.magic[0] = 'Y'; /* YARB */
14669 header.magic[1] = 'A';
14670 header.magic[2] = 'R';
14671 header.magic[3] = 'B';
14672 header.major_version = IBF_MAJOR_VERSION;
14673 header.minor_version = IBF_MINOR_VERSION;
14674 header.endian = IBF_ENDIAN_MARK;
14675 header.wordsize = (uint8_t)SIZEOF_VALUE;
14676 ibf_dump_iseq_list(dump, &header);
14677 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14678 header.size = ibf_dump_pos(dump);
14679
14680 if (RTEST(opt)) {
14681 VALUE opt_str = opt;
14682 const char *ptr = StringValuePtr(opt_str);
14683 header.extra_size = RSTRING_LENINT(opt_str);
14684 ibf_dump_write(dump, ptr, header.extra_size);
14685 }
14686 else {
14687 header.extra_size = 0;
14688 }
14689
14690 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14691
14692 str = dump->global_buffer.str;
14693 RB_GC_GUARD(dump_obj);
14694 return str;
14695}
14696
14697static const ibf_offset_t *
14698ibf_iseq_list(const struct ibf_load *load)
14699{
14700 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14701}
14702
14703void
14704rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14705{
14706 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14707 rb_iseq_t *prev_src_iseq = load->iseq;
14708 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14709 load->iseq = iseq;
14710#if IBF_ISEQ_DEBUG
14711 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14712 iseq->aux.loader.index, offset,
14713 load->header->size);
14714#endif
14715 ibf_load_iseq_each(load, iseq, offset);
14716 ISEQ_COMPILE_DATA_CLEAR(iseq);
14717 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14718 rb_iseq_init_trace(iseq);
14719 load->iseq = prev_src_iseq;
14720}
14721
14722#if USE_LAZY_LOAD
14723const rb_iseq_t *
14724rb_iseq_complete(const rb_iseq_t *iseq)
14725{
14726 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14727 return iseq;
14728}
14729#endif
14730
14731static rb_iseq_t *
14732ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14733{
14734 int iseq_index = (int)(VALUE)index_iseq;
14735
14736#if IBF_ISEQ_DEBUG
14737 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14738 (void *)index_iseq, (void *)load->iseq_list);
14739#endif
14740 if (iseq_index == -1) {
14741 return NULL;
14742 }
14743 else {
14744 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14745
14746#if IBF_ISEQ_DEBUG
14747 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14748#endif
14749 if (iseqv) {
14750 return (rb_iseq_t *)iseqv;
14751 }
14752 else {
14753 rb_iseq_t *iseq = iseq_imemo_alloc();
14754#if IBF_ISEQ_DEBUG
14755 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14756#endif
14757 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14758 iseq->aux.loader.obj = load->loader_obj;
14759 iseq->aux.loader.index = iseq_index;
14760#if IBF_ISEQ_DEBUG
14761 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14762 (void *)iseq, (void *)load->loader_obj, iseq_index);
14763#endif
14764 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14765
14766 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14767#if IBF_ISEQ_DEBUG
14768 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14769#endif
14770 rb_ibf_load_iseq_complete(iseq);
14771 }
14772
14773#if IBF_ISEQ_DEBUG
14774 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14775 (void *)iseq, (void *)load->iseq);
14776#endif
14777 return iseq;
14778 }
14779 }
14780}
14781
14782static void
14783ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14784{
14785 struct ibf_header *header = (struct ibf_header *)bytes;
14786 load->loader_obj = loader_obj;
14787 load->global_buffer.buff = bytes;
14788 load->header = header;
14789 load->global_buffer.size = header->size;
14790 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14791 load->global_buffer.obj_list_size = header->global_object_list_size;
14792 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14793 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14794 load->iseq = NULL;
14795
14796 load->current_buffer = &load->global_buffer;
14797
14798 if (size < header->size) {
14799 rb_raise(rb_eRuntimeError, "broken binary format");
14800 }
14801 if (strncmp(header->magic, "YARB", 4) != 0) {
14802 rb_raise(rb_eRuntimeError, "unknown binary format");
14803 }
14804 if (header->major_version != IBF_MAJOR_VERSION ||
14805 header->minor_version != IBF_MINOR_VERSION) {
14806 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14807 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14808 }
14809 if (header->endian != IBF_ENDIAN_MARK) {
14810 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14811 }
14812 if (header->wordsize != SIZEOF_VALUE) {
14813 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14814 }
14815 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14816 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14817 header->iseq_list_offset);
14818 }
14819 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14820 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14821 load->global_buffer.obj_list_offset);
14822 }
14823}
14824
14825static void
14826ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14827{
14828 StringValue(str);
14829
14830 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14831 rb_raise(rb_eRuntimeError, "broken binary format");
14832 }
14833
14834 if (USE_LAZY_LOAD) {
14835 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14836 }
14837
14838 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14839 RB_OBJ_WRITE(loader_obj, &load->str, str);
14840}
14841
14842static void
14843ibf_loader_mark(void *ptr)
14844{
14845 struct ibf_load *load = (struct ibf_load *)ptr;
14846 rb_gc_mark(load->str);
14847 rb_gc_mark(load->iseq_list);
14848 rb_gc_mark(load->global_buffer.obj_list);
14849}
14850
14851static void
14852ibf_loader_free(void *ptr)
14853{
14854 struct ibf_load *load = (struct ibf_load *)ptr;
14855 ruby_xfree(load);
14856}
14857
14858static size_t
14859ibf_loader_memsize(const void *ptr)
14860{
14861 return sizeof(struct ibf_load);
14862}
14863
14864static const rb_data_type_t ibf_load_type = {
14865 "ibf_loader",
14866 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14867 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14868};
14869
14870const rb_iseq_t *
14871rb_iseq_ibf_load(VALUE str)
14872{
14873 struct ibf_load *load;
14874 rb_iseq_t *iseq;
14875 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14876
14877 ibf_load_setup(load, loader_obj, str);
14878 iseq = ibf_load_iseq(load, 0);
14879
14880 RB_GC_GUARD(loader_obj);
14881 return iseq;
14882}
14883
14884const rb_iseq_t *
14885rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14886{
14887 struct ibf_load *load;
14888 rb_iseq_t *iseq;
14889 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14890
14891 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14892 iseq = ibf_load_iseq(load, 0);
14893
14894 RB_GC_GUARD(loader_obj);
14895 return iseq;
14896}
14897
14898VALUE
14899rb_iseq_ibf_load_extra_data(VALUE str)
14900{
14901 struct ibf_load *load;
14902 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14903 VALUE extra_str;
14904
14905 ibf_load_setup(load, loader_obj, str);
14906 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14907 RB_GC_GUARD(loader_obj);
14908 return extra_str;
14909}
14910
14911#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:1675
#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:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:695
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:110
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:101
VALUE rb_cHash
Hash class.
Definition hash.c:113
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:657
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:880
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1299
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1090
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1114
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1838
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:68
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4225
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:3755
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1710
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4119
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4105
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3523
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:3721
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4175
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:3992
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3236
#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:1514
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:497
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:980
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:999
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:948
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1405
#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:163
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:450
#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:497
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9067
#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:280
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:287
Definition vm_core.h:290
Definition iseq.h:251
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:203
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:210
struct rb_iseq_constant_body::@154 param
parameter information
Definition st.h:79
Definition vm_core.h:299
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