Ruby 3.5.0dev (2025-06-06 revision dde9fca63bf4bf56050c734adca3eaae70506179)
compile.c (dde9fca63bf4bf56050c734adca3eaae70506179)
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 size -= 3;
2182 offset += 3;
2183 }
2184 }
2185
2186 if (size > 0) {
2187#if SIZEOF_INT >= SIZEOF_SIZE_T
2188 ASSUME(size < SIZE_MAX / sizeof(ID)); /* checked in xmalloc2_size */
2189#endif
2190 ID *ids = ALLOC_N(ID, size);
2191 MEMCPY(ids, tbl->ids + offset, ID, size);
2192 ISEQ_BODY(iseq)->local_table = ids;
2193 }
2194 ISEQ_BODY(iseq)->local_table_size = size;
2195
2196 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2197 return COMPILE_OK;
2198}
2199
2200int
2201rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2202{
2203 int tval, tlit;
2204
2205 if (val == lit) {
2206 return 0;
2207 }
2208 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2209 return val != lit;
2210 }
2211 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2212 return -1;
2213 }
2214 else if (tlit != tval) {
2215 return -1;
2216 }
2217 else if (tlit == T_SYMBOL) {
2218 return val != lit;
2219 }
2220 else if (tlit == T_STRING) {
2221 return rb_str_hash_cmp(lit, val);
2222 }
2223 else if (tlit == T_BIGNUM) {
2224 long x = FIX2LONG(rb_big_cmp(lit, val));
2225
2226 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2227 * There is no need to call rb_fix2int here. */
2228 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2229 return (int)x;
2230 }
2231 else if (tlit == T_FLOAT) {
2232 return rb_float_cmp(lit, val);
2233 }
2234 else if (tlit == T_RATIONAL) {
2235 const struct RRational *rat1 = RRATIONAL(val);
2236 const struct RRational *rat2 = RRATIONAL(lit);
2237 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2238 }
2239 else if (tlit == T_COMPLEX) {
2240 const struct RComplex *comp1 = RCOMPLEX(val);
2241 const struct RComplex *comp2 = RCOMPLEX(lit);
2242 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2243 }
2244 else if (tlit == T_REGEXP) {
2245 return rb_reg_equal(val, lit) ? 0 : -1;
2246 }
2247 else {
2249 }
2250}
2251
2252st_index_t
2253rb_iseq_cdhash_hash(VALUE a)
2254{
2255 switch (OBJ_BUILTIN_TYPE(a)) {
2256 case -1:
2257 case T_SYMBOL:
2258 return (st_index_t)a;
2259 case T_STRING:
2260 return rb_str_hash(a);
2261 case T_BIGNUM:
2262 return FIX2LONG(rb_big_hash(a));
2263 case T_FLOAT:
2264 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2265 case T_RATIONAL:
2266 return rb_rational_hash(a);
2267 case T_COMPLEX:
2268 return rb_complex_hash(a);
2269 case T_REGEXP:
2270 return NUM2LONG(rb_reg_hash(a));
2271 default:
2273 }
2274}
2275
2276static const struct st_hash_type cdhash_type = {
2277 rb_iseq_cdhash_cmp,
2278 rb_iseq_cdhash_hash,
2279};
2280
2282 VALUE hash;
2283 int pos;
2284 int len;
2285};
2286
2287static int
2288cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2289{
2290 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2291 LABEL *lobj = (LABEL *)(val & ~1);
2292 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2293 return ST_CONTINUE;
2294}
2295
2296
2297static inline VALUE
2298get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2299{
2300 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2301}
2302
2303static inline VALUE
2304get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2305{
2306 VALUE val;
2307 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2308 if (tbl) {
2309 if (rb_id_table_lookup(tbl,id,&val)) {
2310 return val;
2311 }
2312 }
2313 else {
2314 tbl = rb_id_table_create(1);
2315 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2316 }
2317 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2318 rb_id_table_insert(tbl,id,val);
2319 return val;
2320}
2321
2322#define BADINSN_DUMP(anchor, list, dest) \
2323 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2324
2325#define BADINSN_ERROR \
2326 (xfree(generated_iseq), \
2327 xfree(insns_info), \
2328 BADINSN_DUMP(anchor, list, NULL), \
2329 COMPILE_ERROR)
2330
2331static int
2332fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2333{
2334 int stack_max = 0, sp = 0, line = 0;
2335 LINK_ELEMENT *list;
2336
2337 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2338 if (IS_LABEL(list)) {
2339 LABEL *lobj = (LABEL *)list;
2340 lobj->set = TRUE;
2341 }
2342 }
2343
2344 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2345 switch (list->type) {
2346 case ISEQ_ELEMENT_INSN:
2347 {
2348 int j, len, insn;
2349 const char *types;
2350 VALUE *operands;
2351 INSN *iobj = (INSN *)list;
2352
2353 /* update sp */
2354 sp = calc_sp_depth(sp, iobj);
2355 if (sp < 0) {
2356 BADINSN_DUMP(anchor, list, NULL);
2357 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2358 "argument stack underflow (%d)", sp);
2359 return -1;
2360 }
2361 if (sp > stack_max) {
2362 stack_max = sp;
2363 }
2364
2365 line = iobj->insn_info.line_no;
2366 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2367 operands = iobj->operands;
2368 insn = iobj->insn_id;
2369 types = insn_op_types(insn);
2370 len = insn_len(insn);
2371
2372 /* operand check */
2373 if (iobj->operand_size != len - 1) {
2374 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2375 BADINSN_DUMP(anchor, list, NULL);
2376 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2377 "operand size miss! (%d for %d)",
2378 iobj->operand_size, len - 1);
2379 return -1;
2380 }
2381
2382 for (j = 0; types[j]; j++) {
2383 if (types[j] == TS_OFFSET) {
2384 /* label(destination position) */
2385 LABEL *lobj = (LABEL *)operands[j];
2386 if (!lobj->set) {
2387 BADINSN_DUMP(anchor, list, NULL);
2388 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2389 "unknown label: "LABEL_FORMAT, lobj->label_no);
2390 return -1;
2391 }
2392 if (lobj->sp == -1) {
2393 lobj->sp = sp;
2394 }
2395 else if (lobj->sp != sp) {
2396 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2397 RSTRING_PTR(rb_iseq_path(iseq)), line,
2398 lobj->label_no, lobj->sp, sp);
2399 }
2400 }
2401 }
2402 break;
2403 }
2404 case ISEQ_ELEMENT_LABEL:
2405 {
2406 LABEL *lobj = (LABEL *)list;
2407 if (lobj->sp == -1) {
2408 lobj->sp = sp;
2409 }
2410 else {
2411 if (lobj->sp != sp) {
2412 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2413 RSTRING_PTR(rb_iseq_path(iseq)), line,
2414 lobj->label_no, lobj->sp, sp);
2415 }
2416 sp = lobj->sp;
2417 }
2418 break;
2419 }
2420 case ISEQ_ELEMENT_TRACE:
2421 {
2422 /* ignore */
2423 break;
2424 }
2425 case ISEQ_ELEMENT_ADJUST:
2426 {
2427 ADJUST *adjust = (ADJUST *)list;
2428 int orig_sp = sp;
2429
2430 sp = adjust->label ? adjust->label->sp : 0;
2431 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2432 BADINSN_DUMP(anchor, list, NULL);
2433 COMPILE_ERROR(iseq, adjust->line_no,
2434 "iseq_set_sequence: adjust bug %d < %d",
2435 orig_sp, sp);
2436 return -1;
2437 }
2438 break;
2439 }
2440 default:
2441 BADINSN_DUMP(anchor, list, NULL);
2442 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2443 return -1;
2444 }
2445 }
2446 return stack_max;
2447}
2448
2449static int
2450add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2451 int insns_info_index, int code_index, const INSN *iobj)
2452{
2453 if (insns_info_index == 0 ||
2454 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2455#ifdef USE_ISEQ_NODE_ID
2456 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2457#endif
2458 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2459 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2460#ifdef USE_ISEQ_NODE_ID
2461 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2462#endif
2463 insns_info[insns_info_index].events = iobj->insn_info.events;
2464 positions[insns_info_index] = code_index;
2465 return TRUE;
2466 }
2467 return FALSE;
2468}
2469
2470static int
2471add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2472 int insns_info_index, int code_index, const ADJUST *adjust)
2473{
2474 insns_info[insns_info_index].line_no = adjust->line_no;
2475 insns_info[insns_info_index].node_id = -1;
2476 insns_info[insns_info_index].events = 0;
2477 positions[insns_info_index] = code_index;
2478 return TRUE;
2479}
2480
2481static ID *
2482array_to_idlist(VALUE arr)
2483{
2485 long size = RARRAY_LEN(arr);
2486 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2487 for (int i = 0; i < size; i++) {
2488 VALUE sym = RARRAY_AREF(arr, i);
2489 ids[i] = SYM2ID(sym);
2490 }
2491 ids[size] = 0;
2492 return ids;
2493}
2494
2495static VALUE
2496idlist_to_array(const ID *ids)
2497{
2498 VALUE arr = rb_ary_new();
2499 while (*ids) {
2500 rb_ary_push(arr, ID2SYM(*ids++));
2501 }
2502 return arr;
2503}
2504
2508static int
2509iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2510{
2511 struct iseq_insn_info_entry *insns_info;
2512 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2513 unsigned int *positions;
2514 LINK_ELEMENT *list;
2515 VALUE *generated_iseq;
2516 rb_event_flag_t events = 0;
2517 long data = 0;
2518
2519 int insn_num, code_index, insns_info_index, sp = 0;
2520 int stack_max = fix_sp_depth(iseq, anchor);
2521
2522 if (stack_max < 0) return COMPILE_NG;
2523
2524 /* fix label position */
2525 insn_num = code_index = 0;
2526 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2527 switch (list->type) {
2528 case ISEQ_ELEMENT_INSN:
2529 {
2530 INSN *iobj = (INSN *)list;
2531 /* update sp */
2532 sp = calc_sp_depth(sp, iobj);
2533 insn_num++;
2534 events = iobj->insn_info.events |= events;
2535 if (ISEQ_COVERAGE(iseq)) {
2536 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2537 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2538 int line = iobj->insn_info.line_no - 1;
2539 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2540 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2541 }
2542 }
2543 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2544 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2545 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2546 }
2547 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2548 }
2549 }
2550 code_index += insn_data_length(iobj);
2551 events = 0;
2552 data = 0;
2553 break;
2554 }
2555 case ISEQ_ELEMENT_LABEL:
2556 {
2557 LABEL *lobj = (LABEL *)list;
2558 lobj->position = code_index;
2559 if (lobj->sp != sp) {
2560 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2561 RSTRING_PTR(rb_iseq_path(iseq)),
2562 lobj->label_no, lobj->sp, sp);
2563 }
2564 sp = lobj->sp;
2565 break;
2566 }
2567 case ISEQ_ELEMENT_TRACE:
2568 {
2569 TRACE *trace = (TRACE *)list;
2570 events |= trace->event;
2571 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2572 break;
2573 }
2574 case ISEQ_ELEMENT_ADJUST:
2575 {
2576 ADJUST *adjust = (ADJUST *)list;
2577 if (adjust->line_no != -1) {
2578 int orig_sp = sp;
2579 sp = adjust->label ? adjust->label->sp : 0;
2580 if (orig_sp - sp > 0) {
2581 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2582 code_index++; /* insn */
2583 insn_num++;
2584 }
2585 }
2586 break;
2587 }
2588 default: break;
2589 }
2590 }
2591
2592 /* make instruction sequence */
2593 generated_iseq = ALLOC_N(VALUE, code_index);
2594 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2595 positions = ALLOC_N(unsigned int, insn_num);
2596 if (ISEQ_IS_SIZE(body)) {
2597 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2598 }
2599 else {
2600 body->is_entries = NULL;
2601 }
2602
2603 if (body->ci_size) {
2604 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2605 }
2606 else {
2607 body->call_data = NULL;
2608 }
2609 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2610
2611 // Calculate the bitmask buffer size.
2612 // Round the generated_iseq size up to the nearest multiple
2613 // of the number of bits in an unsigned long.
2614
2615 // Allocate enough room for the bitmask list
2616 iseq_bits_t * mark_offset_bits;
2617 int code_size = code_index;
2618
2619 bool needs_bitmap = false;
2620
2621 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2622 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2623 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2624 }
2625 else {
2626 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2627 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2628 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2629 }
2630
2631 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2632 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2633
2634 list = FIRST_ELEMENT(anchor);
2635 insns_info_index = code_index = sp = 0;
2636
2637 while (list) {
2638 switch (list->type) {
2639 case ISEQ_ELEMENT_INSN:
2640 {
2641 int j, len, insn;
2642 const char *types;
2643 VALUE *operands;
2644 INSN *iobj = (INSN *)list;
2645
2646 /* update sp */
2647 sp = calc_sp_depth(sp, iobj);
2648 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2649 operands = iobj->operands;
2650 insn = iobj->insn_id;
2651 generated_iseq[code_index] = insn;
2652 types = insn_op_types(insn);
2653 len = insn_len(insn);
2654
2655 for (j = 0; types[j]; j++) {
2656 char type = types[j];
2657
2658 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2659 switch (type) {
2660 case TS_OFFSET:
2661 {
2662 /* label(destination position) */
2663 LABEL *lobj = (LABEL *)operands[j];
2664 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2665 break;
2666 }
2667 case TS_CDHASH:
2668 {
2669 VALUE map = operands[j];
2670 struct cdhash_set_label_struct data;
2671 data.hash = map;
2672 data.pos = code_index;
2673 data.len = len;
2674 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2675
2676 rb_hash_rehash(map);
2677 freeze_hide_obj(map);
2678 generated_iseq[code_index + 1 + j] = map;
2679 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2680 RB_OBJ_WRITTEN(iseq, Qundef, map);
2681 needs_bitmap = true;
2682 break;
2683 }
2684 case TS_LINDEX:
2685 case TS_NUM: /* ulong */
2686 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2687 break;
2688 case TS_ISEQ: /* iseq */
2689 case TS_VALUE: /* VALUE */
2690 {
2691 VALUE v = operands[j];
2692 generated_iseq[code_index + 1 + j] = v;
2693 /* to mark ruby object */
2694 if (!SPECIAL_CONST_P(v)) {
2695 RB_OBJ_WRITTEN(iseq, Qundef, v);
2696 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2697 needs_bitmap = true;
2698 }
2699 break;
2700 }
2701 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2702 case TS_IC: /* inline cache: constants */
2703 {
2704 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2705 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2706 if (UNLIKELY(ic_index >= body->ic_size)) {
2707 BADINSN_DUMP(anchor, &iobj->link, 0);
2708 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2709 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2710 ic_index, ISEQ_IS_SIZE(body));
2711 }
2712
2713 ic->segments = array_to_idlist(operands[j]);
2714
2715 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2716 }
2717 break;
2718 case TS_IVC: /* inline ivar cache */
2719 {
2720 unsigned int ic_index = FIX2UINT(operands[j]);
2721
2722 IVC cache = ((IVC)&body->is_entries[ic_index]);
2723
2724 if (insn == BIN(setinstancevariable)) {
2725 cache->iv_set_name = SYM2ID(operands[j - 1]);
2726 }
2727 else {
2728 cache->iv_set_name = 0;
2729 }
2730
2731 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2732 }
2733 case TS_ISE: /* inline storage entry: `once` insn */
2734 case TS_ICVARC: /* inline cvar cache */
2735 {
2736 unsigned int ic_index = FIX2UINT(operands[j]);
2737 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2738 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2739 BADINSN_DUMP(anchor, &iobj->link, 0);
2740 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2741 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2742 ic_index, ISEQ_IS_SIZE(body));
2743 }
2744 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2745
2746 break;
2747 }
2748 case TS_CALLDATA:
2749 {
2750 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2751 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2752 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2753 cd->ci = source_ci;
2754 cd->cc = vm_cc_empty();
2755 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2756 break;
2757 }
2758 case TS_ID: /* ID */
2759 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2760 break;
2761 case TS_FUNCPTR:
2762 generated_iseq[code_index + 1 + j] = operands[j];
2763 break;
2764 case TS_BUILTIN:
2765 generated_iseq[code_index + 1 + j] = operands[j];
2766 break;
2767 default:
2768 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2769 "unknown operand type: %c", type);
2770 return COMPILE_NG;
2771 }
2772 }
2773 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2774 code_index += len;
2775 break;
2776 }
2777 case ISEQ_ELEMENT_LABEL:
2778 {
2779 LABEL *lobj = (LABEL *)list;
2780 if (lobj->sp != sp) {
2781 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2782 RSTRING_PTR(rb_iseq_path(iseq)),
2783 lobj->label_no, lobj->sp, sp);
2784 }
2785 sp = lobj->sp;
2786 break;
2787 }
2788 case ISEQ_ELEMENT_ADJUST:
2789 {
2790 ADJUST *adjust = (ADJUST *)list;
2791 int orig_sp = sp;
2792
2793 if (adjust->label) {
2794 sp = adjust->label->sp;
2795 }
2796 else {
2797 sp = 0;
2798 }
2799
2800 if (adjust->line_no != -1) {
2801 const int diff = orig_sp - sp;
2802 if (diff > 0) {
2803 if (insns_info_index == 0) {
2804 COMPILE_ERROR(iseq, adjust->line_no,
2805 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2806 }
2807 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2808 }
2809 if (diff > 1) {
2810 generated_iseq[code_index++] = BIN(adjuststack);
2811 generated_iseq[code_index++] = orig_sp - sp;
2812 }
2813 else if (diff == 1) {
2814 generated_iseq[code_index++] = BIN(pop);
2815 }
2816 else if (diff < 0) {
2817 int label_no = adjust->label ? adjust->label->label_no : -1;
2818 xfree(generated_iseq);
2819 xfree(insns_info);
2820 xfree(positions);
2821 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2822 xfree(mark_offset_bits);
2823 }
2824 debug_list(anchor, list);
2825 COMPILE_ERROR(iseq, adjust->line_no,
2826 "iseq_set_sequence: adjust bug to %d %d < %d",
2827 label_no, orig_sp, sp);
2828 return COMPILE_NG;
2829 }
2830 }
2831 break;
2832 }
2833 default:
2834 /* ignore */
2835 break;
2836 }
2837 list = list->next;
2838 }
2839
2840 body->iseq_encoded = (void *)generated_iseq;
2841 body->iseq_size = code_index;
2842 body->stack_max = stack_max;
2843
2844 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2845 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2846 }
2847 else {
2848 if (needs_bitmap) {
2849 body->mark_bits.list = mark_offset_bits;
2850 }
2851 else {
2852 body->mark_bits.list = NULL;
2853 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2854 ruby_xfree(mark_offset_bits);
2855 }
2856 }
2857
2858 /* get rid of memory leak when REALLOC failed */
2859 body->insns_info.body = insns_info;
2860 body->insns_info.positions = positions;
2861
2862 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2863 body->insns_info.body = insns_info;
2864 REALLOC_N(positions, unsigned int, insns_info_index);
2865 body->insns_info.positions = positions;
2866 body->insns_info.size = insns_info_index;
2867
2868 return COMPILE_OK;
2869}
2870
2871static int
2872label_get_position(LABEL *lobj)
2873{
2874 return lobj->position;
2875}
2876
2877static int
2878label_get_sp(LABEL *lobj)
2879{
2880 return lobj->sp;
2881}
2882
2883static int
2884iseq_set_exception_table(rb_iseq_t *iseq)
2885{
2886 const VALUE *tptr, *ptr;
2887 unsigned int tlen, i;
2888 struct iseq_catch_table_entry *entry;
2889
2890 ISEQ_BODY(iseq)->catch_table = NULL;
2891
2892 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2893 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2894 tlen = (int)RARRAY_LEN(catch_table_ary);
2895 tptr = RARRAY_CONST_PTR(catch_table_ary);
2896
2897 if (tlen > 0) {
2898 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2899 table->size = tlen;
2900
2901 for (i = 0; i < table->size; i++) {
2902 int pos;
2903 ptr = RARRAY_CONST_PTR(tptr[i]);
2904 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2905 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2906 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2907 RUBY_ASSERT(pos >= 0);
2908 entry->start = (unsigned int)pos;
2909 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2910 RUBY_ASSERT(pos >= 0);
2911 entry->end = (unsigned int)pos;
2912 entry->iseq = (rb_iseq_t *)ptr[3];
2913 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2914
2915 /* stack depth */
2916 if (ptr[4]) {
2917 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2918 entry->cont = label_get_position(lobj);
2919 entry->sp = label_get_sp(lobj);
2920
2921 /* TODO: Dirty Hack! Fix me */
2922 if (entry->type == CATCH_TYPE_RESCUE ||
2923 entry->type == CATCH_TYPE_BREAK ||
2924 entry->type == CATCH_TYPE_NEXT) {
2925 RUBY_ASSERT(entry->sp > 0);
2926 entry->sp--;
2927 }
2928 }
2929 else {
2930 entry->cont = 0;
2931 }
2932 }
2933 ISEQ_BODY(iseq)->catch_table = table;
2934 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2935 }
2936
2937 RB_GC_GUARD(catch_table_ary);
2938
2939 return COMPILE_OK;
2940}
2941
2942/*
2943 * set optional argument table
2944 * def foo(a, b=expr1, c=expr2)
2945 * =>
2946 * b:
2947 * expr1
2948 * c:
2949 * expr2
2950 */
2951static int
2952iseq_set_optargs_table(rb_iseq_t *iseq)
2953{
2954 int i;
2955 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2956
2957 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2958 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2959 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2960 }
2961 }
2962 return COMPILE_OK;
2963}
2964
2965static LINK_ELEMENT *
2966get_destination_insn(INSN *iobj)
2967{
2968 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2969 LINK_ELEMENT *list;
2970 rb_event_flag_t events = 0;
2971
2972 list = lobj->link.next;
2973 while (list) {
2974 switch (list->type) {
2975 case ISEQ_ELEMENT_INSN:
2976 case ISEQ_ELEMENT_ADJUST:
2977 goto found;
2978 case ISEQ_ELEMENT_LABEL:
2979 /* ignore */
2980 break;
2981 case ISEQ_ELEMENT_TRACE:
2982 {
2983 TRACE *trace = (TRACE *)list;
2984 events |= trace->event;
2985 }
2986 break;
2987 default: break;
2988 }
2989 list = list->next;
2990 }
2991 found:
2992 if (list && IS_INSN(list)) {
2993 INSN *iobj = (INSN *)list;
2994 iobj->insn_info.events |= events;
2995 }
2996 return list;
2997}
2998
2999static LINK_ELEMENT *
3000get_next_insn(INSN *iobj)
3001{
3002 LINK_ELEMENT *list = iobj->link.next;
3003
3004 while (list) {
3005 if (IS_INSN(list) || IS_ADJUST(list)) {
3006 return list;
3007 }
3008 list = list->next;
3009 }
3010 return 0;
3011}
3012
3013static LINK_ELEMENT *
3014get_prev_insn(INSN *iobj)
3015{
3016 LINK_ELEMENT *list = iobj->link.prev;
3017
3018 while (list) {
3019 if (IS_INSN(list) || IS_ADJUST(list)) {
3020 return list;
3021 }
3022 list = list->prev;
3023 }
3024 return 0;
3025}
3026
3027static void
3028unref_destination(INSN *iobj, int pos)
3029{
3030 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3031 --lobj->refcnt;
3032 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3033}
3034
3035static bool
3036replace_destination(INSN *dobj, INSN *nobj)
3037{
3038 VALUE n = OPERAND_AT(nobj, 0);
3039 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3040 LABEL *nl = (LABEL *)n;
3041 if (dl == nl) return false;
3042 --dl->refcnt;
3043 ++nl->refcnt;
3044 OPERAND_AT(dobj, 0) = n;
3045 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3046 return true;
3047}
3048
3049static LABEL*
3050find_destination(INSN *i)
3051{
3052 int pos, len = insn_len(i->insn_id);
3053 for (pos = 0; pos < len; ++pos) {
3054 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3055 return (LABEL *)OPERAND_AT(i, pos);
3056 }
3057 }
3058 return 0;
3059}
3060
3061static int
3062remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3063{
3064 LINK_ELEMENT *first = i, *end;
3065 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3066
3067 if (!i) return 0;
3068 unref_counts = ALLOCA_N(int, nlabels);
3069 MEMZERO(unref_counts, int, nlabels);
3070 end = i;
3071 do {
3072 LABEL *lab;
3073 if (IS_INSN(i)) {
3074 if (IS_INSN_ID(i, leave)) {
3075 end = i;
3076 break;
3077 }
3078 else if ((lab = find_destination((INSN *)i)) != 0) {
3079 unref_counts[lab->label_no]++;
3080 }
3081 }
3082 else if (IS_LABEL(i)) {
3083 lab = (LABEL *)i;
3084 if (lab->unremovable) return 0;
3085 if (lab->refcnt > unref_counts[lab->label_no]) {
3086 if (i == first) return 0;
3087 break;
3088 }
3089 continue;
3090 }
3091 else if (IS_TRACE(i)) {
3092 /* do nothing */
3093 }
3094 else if (IS_ADJUST(i)) {
3095 return 0;
3096 }
3097 end = i;
3098 } while ((i = i->next) != 0);
3099 i = first;
3100 do {
3101 if (IS_INSN(i)) {
3102 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3103 VALUE insn = INSN_OF(i);
3104 int pos, len = insn_len(insn);
3105 for (pos = 0; pos < len; ++pos) {
3106 switch (insn_op_types(insn)[pos]) {
3107 case TS_OFFSET:
3108 unref_destination((INSN *)i, pos);
3109 break;
3110 case TS_CALLDATA:
3111 --(body->ci_size);
3112 break;
3113 }
3114 }
3115 }
3116 ELEM_REMOVE(i);
3117 } while ((i != end) && (i = i->next) != 0);
3118 return 1;
3119}
3120
3121static int
3122iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3123{
3124 switch (OPERAND_AT(iobj, 0)) {
3125 case INT2FIX(0): /* empty array */
3126 ELEM_REMOVE(&iobj->link);
3127 return TRUE;
3128 case INT2FIX(1): /* single element array */
3129 ELEM_REMOVE(&iobj->link);
3130 return FALSE;
3131 default:
3132 iobj->insn_id = BIN(adjuststack);
3133 return TRUE;
3134 }
3135}
3136
3137static int
3138is_frozen_putstring(INSN *insn, VALUE *op)
3139{
3140 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3141 *op = OPERAND_AT(insn, 0);
3142 return 1;
3143 }
3144 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3145 *op = OPERAND_AT(insn, 0);
3146 return RB_TYPE_P(*op, T_STRING);
3147 }
3148 return 0;
3149}
3150
3151static int
3152optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3153{
3154 /*
3155 * putobject obj
3156 * dup
3157 * checktype T_XXX
3158 * branchif l1
3159 * l2:
3160 * ...
3161 * l1:
3162 *
3163 * => obj is a T_XXX
3164 *
3165 * putobject obj (T_XXX)
3166 * jump L1
3167 * L1:
3168 *
3169 * => obj is not a T_XXX
3170 *
3171 * putobject obj (T_XXX)
3172 * jump L2
3173 * L2:
3174 */
3175 int line, node_id;
3176 INSN *niobj, *ciobj, *dup = 0;
3177 LABEL *dest = 0;
3178 VALUE type;
3179
3180 switch (INSN_OF(iobj)) {
3181 case BIN(putstring):
3182 case BIN(putchilledstring):
3184 break;
3185 case BIN(putnil):
3186 type = INT2FIX(T_NIL);
3187 break;
3188 case BIN(putobject):
3189 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3190 break;
3191 default: return FALSE;
3192 }
3193
3194 ciobj = (INSN *)get_next_insn(iobj);
3195 if (IS_INSN_ID(ciobj, jump)) {
3196 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3197 }
3198 if (IS_INSN_ID(ciobj, dup)) {
3199 ciobj = (INSN *)get_next_insn(dup = ciobj);
3200 }
3201 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3202 niobj = (INSN *)get_next_insn(ciobj);
3203 if (!niobj) {
3204 /* TODO: putobject true/false */
3205 return FALSE;
3206 }
3207 switch (INSN_OF(niobj)) {
3208 case BIN(branchif):
3209 if (OPERAND_AT(ciobj, 0) == type) {
3210 dest = (LABEL *)OPERAND_AT(niobj, 0);
3211 }
3212 break;
3213 case BIN(branchunless):
3214 if (OPERAND_AT(ciobj, 0) != type) {
3215 dest = (LABEL *)OPERAND_AT(niobj, 0);
3216 }
3217 break;
3218 default:
3219 return FALSE;
3220 }
3221 line = ciobj->insn_info.line_no;
3222 node_id = ciobj->insn_info.node_id;
3223 if (!dest) {
3224 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3225 dest = (LABEL *)niobj->link.next; /* reuse label */
3226 }
3227 else {
3228 dest = NEW_LABEL(line);
3229 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3230 }
3231 }
3232 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3233 LABEL_REF(dest);
3234 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3235 return TRUE;
3236}
3237
3238static const struct rb_callinfo *
3239ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3240{
3241 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3242 vm_ci_flag(ci) | add,
3243 vm_ci_argc(ci),
3244 vm_ci_kwarg(ci));
3245 RB_OBJ_WRITTEN(iseq, ci, nci);
3246 return nci;
3247}
3248
3249static const struct rb_callinfo *
3250ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3251{
3252 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3253 vm_ci_flag(ci),
3254 argc,
3255 vm_ci_kwarg(ci));
3256 RB_OBJ_WRITTEN(iseq, ci, nci);
3257 return nci;
3258}
3259
3260#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3261
3262static int
3263iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3264{
3265 INSN *const iobj = (INSN *)list;
3266
3267 again:
3268 optimize_checktype(iseq, iobj);
3269
3270 if (IS_INSN_ID(iobj, jump)) {
3271 INSN *niobj, *diobj, *piobj;
3272 diobj = (INSN *)get_destination_insn(iobj);
3273 niobj = (INSN *)get_next_insn(iobj);
3274
3275 if (diobj == niobj) {
3276 /*
3277 * jump LABEL
3278 * LABEL:
3279 * =>
3280 * LABEL:
3281 */
3282 unref_destination(iobj, 0);
3283 ELEM_REMOVE(&iobj->link);
3284 return COMPILE_OK;
3285 }
3286 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3287 IS_INSN_ID(diobj, jump) &&
3288 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3289 diobj->insn_info.events == 0) {
3290 /*
3291 * useless jump elimination:
3292 * jump LABEL1
3293 * ...
3294 * LABEL1:
3295 * jump LABEL2
3296 *
3297 * => in this case, first jump instruction should jump to
3298 * LABEL2 directly
3299 */
3300 if (replace_destination(iobj, diobj)) {
3301 remove_unreachable_chunk(iseq, iobj->link.next);
3302 goto again;
3303 }
3304 }
3305 else if (IS_INSN_ID(diobj, leave)) {
3306 /*
3307 * jump LABEL
3308 * ...
3309 * LABEL:
3310 * leave
3311 * =>
3312 * leave
3313 * ...
3314 * LABEL:
3315 * leave
3316 */
3317 /* replace */
3318 unref_destination(iobj, 0);
3319 iobj->insn_id = BIN(leave);
3320 iobj->operand_size = 0;
3321 iobj->insn_info = diobj->insn_info;
3322 goto again;
3323 }
3324 else if (IS_INSN(iobj->link.prev) &&
3325 (piobj = (INSN *)iobj->link.prev) &&
3326 (IS_INSN_ID(piobj, branchif) ||
3327 IS_INSN_ID(piobj, branchunless))) {
3328 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3329 if (niobj == pdiobj) {
3330 int refcnt = IS_LABEL(piobj->link.next) ?
3331 ((LABEL *)piobj->link.next)->refcnt : 0;
3332 /*
3333 * useless jump elimination (if/unless destination):
3334 * if L1
3335 * jump L2
3336 * L1:
3337 * ...
3338 * L2:
3339 *
3340 * ==>
3341 * unless L2
3342 * L1:
3343 * ...
3344 * L2:
3345 */
3346 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3347 ? BIN(branchunless) : BIN(branchif);
3348 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3349 ELEM_REMOVE(&iobj->link);
3350 }
3351 else {
3352 /* TODO: replace other branch destinations too */
3353 }
3354 return COMPILE_OK;
3355 }
3356 else if (diobj == pdiobj) {
3357 /*
3358 * useless jump elimination (if/unless before jump):
3359 * L1:
3360 * ...
3361 * if L1
3362 * jump L1
3363 *
3364 * ==>
3365 * L1:
3366 * ...
3367 * pop
3368 * jump L1
3369 */
3370 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3371 ELEM_REPLACE(&piobj->link, &popiobj->link);
3372 }
3373 }
3374 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3375 goto again;
3376 }
3377 }
3378
3379 /*
3380 * putstring "beg"
3381 * putstring "end"
3382 * newrange excl
3383 *
3384 * ==>
3385 *
3386 * putobject "beg".."end"
3387 */
3388 if (IS_INSN_ID(iobj, newrange)) {
3389 INSN *const range = iobj;
3390 INSN *beg, *end;
3391 VALUE str_beg, str_end;
3392
3393 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3394 is_frozen_putstring(end, &str_end) &&
3395 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3396 is_frozen_putstring(beg, &str_beg)) {
3397 int excl = FIX2INT(OPERAND_AT(range, 0));
3398 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3399
3400 ELEM_REMOVE(&beg->link);
3401 ELEM_REMOVE(&end->link);
3402 range->insn_id = BIN(putobject);
3403 OPERAND_AT(range, 0) = lit_range;
3404 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3405 }
3406 }
3407
3408 if (IS_INSN_ID(iobj, leave)) {
3409 remove_unreachable_chunk(iseq, iobj->link.next);
3410 }
3411
3412 /*
3413 * ...
3414 * duparray [...]
3415 * concatarray | concattoarray
3416 * =>
3417 * ...
3418 * putobject [...]
3419 * concatarray | concattoarray
3420 */
3421 if (IS_INSN_ID(iobj, duparray)) {
3422 LINK_ELEMENT *next = iobj->link.next;
3423 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3424 iobj->insn_id = BIN(putobject);
3425 }
3426 }
3427
3428 /*
3429 * duparray [...]
3430 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3431 * =>
3432 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3433 */
3434 if (IS_INSN_ID(iobj, duparray)) {
3435 LINK_ELEMENT *next = iobj->link.next;
3436 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3437 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3438 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3439
3440 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3441 VALUE ary = iobj->operands[0];
3443
3444 iobj->insn_id = BIN(opt_ary_freeze);
3445 iobj->operand_size = 2;
3446 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3447 iobj->operands[0] = ary;
3448 iobj->operands[1] = (VALUE)ci;
3449 ELEM_REMOVE(next);
3450 }
3451 }
3452 }
3453
3454 /*
3455 * duphash {...}
3456 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3457 * =>
3458 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3459 */
3460 if (IS_INSN_ID(iobj, duphash)) {
3461 LINK_ELEMENT *next = iobj->link.next;
3462 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3463 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3464 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3465
3466 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3467 VALUE hash = iobj->operands[0];
3468 rb_obj_reveal(hash, rb_cHash);
3469
3470 iobj->insn_id = BIN(opt_hash_freeze);
3471 iobj->operand_size = 2;
3472 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3473 iobj->operands[0] = hash;
3474 iobj->operands[1] = (VALUE)ci;
3475 ELEM_REMOVE(next);
3476 }
3477 }
3478 }
3479
3480 /*
3481 * newarray 0
3482 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3483 * =>
3484 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3485 */
3486 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3487 LINK_ELEMENT *next = iobj->link.next;
3488 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3489 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3490 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3491
3492 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3493 iobj->insn_id = BIN(opt_ary_freeze);
3494 iobj->operand_size = 2;
3495 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3496 iobj->operands[0] = rb_cArray_empty_frozen;
3497 iobj->operands[1] = (VALUE)ci;
3498 ELEM_REMOVE(next);
3499 }
3500 }
3501 }
3502
3503 /*
3504 * newhash 0
3505 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3506 * =>
3507 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3508 */
3509 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3510 LINK_ELEMENT *next = iobj->link.next;
3511 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3512 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3513 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3514
3515 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3516 iobj->insn_id = BIN(opt_hash_freeze);
3517 iobj->operand_size = 2;
3518 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3519 iobj->operands[0] = rb_cHash_empty_frozen;
3520 iobj->operands[1] = (VALUE)ci;
3521 ELEM_REMOVE(next);
3522 }
3523 }
3524 }
3525
3526 if (IS_INSN_ID(iobj, branchif) ||
3527 IS_INSN_ID(iobj, branchnil) ||
3528 IS_INSN_ID(iobj, branchunless)) {
3529 /*
3530 * if L1
3531 * ...
3532 * L1:
3533 * jump L2
3534 * =>
3535 * if L2
3536 */
3537 INSN *nobj = (INSN *)get_destination_insn(iobj);
3538
3539 /* This is super nasty hack!!!
3540 *
3541 * This jump-jump optimization may ignore event flags of the jump
3542 * instruction being skipped. Actually, Line 2 TracePoint event
3543 * is never fired in the following code:
3544 *
3545 * 1: raise if 1 == 2
3546 * 2: while true
3547 * 3: break
3548 * 4: end
3549 *
3550 * This is critical for coverage measurement. [Bug #15980]
3551 *
3552 * This is a stopgap measure: stop the jump-jump optimization if
3553 * coverage measurement is enabled and if the skipped instruction
3554 * has any event flag.
3555 *
3556 * Note that, still, TracePoint Line event does not occur on Line 2.
3557 * This should be fixed in future.
3558 */
3559 int stop_optimization =
3560 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3561 nobj->link.type == ISEQ_ELEMENT_INSN &&
3562 nobj->insn_info.events;
3563 if (!stop_optimization) {
3564 INSN *pobj = (INSN *)iobj->link.prev;
3565 int prev_dup = 0;
3566 if (pobj) {
3567 if (!IS_INSN(&pobj->link))
3568 pobj = 0;
3569 else if (IS_INSN_ID(pobj, dup))
3570 prev_dup = 1;
3571 }
3572
3573 for (;;) {
3574 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3575 if (!replace_destination(iobj, nobj)) break;
3576 }
3577 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3578 !!(nobj = (INSN *)nobj->link.next) &&
3579 /* basic blocks, with no labels in the middle */
3580 nobj->insn_id == iobj->insn_id) {
3581 /*
3582 * dup
3583 * if L1
3584 * ...
3585 * L1:
3586 * dup
3587 * if L2
3588 * =>
3589 * dup
3590 * if L2
3591 * ...
3592 * L1:
3593 * dup
3594 * if L2
3595 */
3596 if (!replace_destination(iobj, nobj)) break;
3597 }
3598 else if (pobj) {
3599 /*
3600 * putnil
3601 * if L1
3602 * =>
3603 * # nothing
3604 *
3605 * putobject true
3606 * if L1
3607 * =>
3608 * jump L1
3609 *
3610 * putstring ".."
3611 * if L1
3612 * =>
3613 * jump L1
3614 *
3615 * putstring ".."
3616 * dup
3617 * if L1
3618 * =>
3619 * putstring ".."
3620 * jump L1
3621 *
3622 */
3623 int cond;
3624 if (prev_dup && IS_INSN(pobj->link.prev)) {
3625 pobj = (INSN *)pobj->link.prev;
3626 }
3627 if (IS_INSN_ID(pobj, putobject)) {
3628 cond = (IS_INSN_ID(iobj, branchif) ?
3629 OPERAND_AT(pobj, 0) != Qfalse :
3630 IS_INSN_ID(iobj, branchunless) ?
3631 OPERAND_AT(pobj, 0) == Qfalse :
3632 FALSE);
3633 }
3634 else if (IS_INSN_ID(pobj, putstring) ||
3635 IS_INSN_ID(pobj, duparray) ||
3636 IS_INSN_ID(pobj, newarray)) {
3637 cond = IS_INSN_ID(iobj, branchif);
3638 }
3639 else if (IS_INSN_ID(pobj, putnil)) {
3640 cond = !IS_INSN_ID(iobj, branchif);
3641 }
3642 else break;
3643 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3644 ELEM_REMOVE(iobj->link.prev);
3645 }
3646 else if (!iseq_pop_newarray(iseq, pobj)) {
3647 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3648 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3649 }
3650 if (cond) {
3651 if (prev_dup) {
3652 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3653 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3654 }
3655 iobj->insn_id = BIN(jump);
3656 goto again;
3657 }
3658 else {
3659 unref_destination(iobj, 0);
3660 ELEM_REMOVE(&iobj->link);
3661 }
3662 break;
3663 }
3664 else break;
3665 nobj = (INSN *)get_destination_insn(nobj);
3666 }
3667 }
3668 }
3669
3670 if (IS_INSN_ID(iobj, pop)) {
3671 /*
3672 * putself / putnil / putobject obj / putstring "..."
3673 * pop
3674 * =>
3675 * # do nothing
3676 */
3677 LINK_ELEMENT *prev = iobj->link.prev;
3678 if (IS_INSN(prev)) {
3679 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3680 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3681 previ == BIN(putself) || previ == BIN(putstring) ||
3682 previ == BIN(putchilledstring) ||
3683 previ == BIN(dup) ||
3684 previ == BIN(getlocal) ||
3685 previ == BIN(getblockparam) ||
3686 previ == BIN(getblockparamproxy) ||
3687 previ == BIN(getinstancevariable) ||
3688 previ == BIN(duparray)) {
3689 /* just push operand or static value and pop soon, no
3690 * side effects */
3691 ELEM_REMOVE(prev);
3692 ELEM_REMOVE(&iobj->link);
3693 }
3694 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3695 ELEM_REMOVE(&iobj->link);
3696 }
3697 else if (previ == BIN(concatarray)) {
3698 INSN *piobj = (INSN *)prev;
3699 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3700 INSN_OF(piobj) = BIN(pop);
3701 }
3702 else if (previ == BIN(concatstrings)) {
3703 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3704 ELEM_REMOVE(prev);
3705 }
3706 else {
3707 ELEM_REMOVE(&iobj->link);
3708 INSN_OF(prev) = BIN(adjuststack);
3709 }
3710 }
3711 }
3712 }
3713
3714 if (IS_INSN_ID(iobj, newarray) ||
3715 IS_INSN_ID(iobj, duparray) ||
3716 IS_INSN_ID(iobj, concatarray) ||
3717 IS_INSN_ID(iobj, splatarray) ||
3718 0) {
3719 /*
3720 * newarray N
3721 * splatarray
3722 * =>
3723 * newarray N
3724 * newarray always puts an array
3725 */
3726 LINK_ELEMENT *next = iobj->link.next;
3727 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3728 /* remove splatarray following always-array insn */
3729 ELEM_REMOVE(next);
3730 }
3731 }
3732
3733 if (IS_INSN_ID(iobj, newarray)) {
3734 LINK_ELEMENT *next = iobj->link.next;
3735 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3736 OPERAND_AT(next, 1) == INT2FIX(0)) {
3737 VALUE op1, op2;
3738 op1 = OPERAND_AT(iobj, 0);
3739 op2 = OPERAND_AT(next, 0);
3740 ELEM_REMOVE(next);
3741
3742 if (op1 == op2) {
3743 /*
3744 * newarray 2
3745 * expandarray 2, 0
3746 * =>
3747 * swap
3748 */
3749 if (op1 == INT2FIX(2)) {
3750 INSN_OF(iobj) = BIN(swap);
3751 iobj->operand_size = 0;
3752 }
3753 /*
3754 * newarray X
3755 * expandarray X, 0
3756 * =>
3757 * opt_reverse X
3758 */
3759 else {
3760 INSN_OF(iobj) = BIN(opt_reverse);
3761 }
3762 }
3763 else {
3764 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3765 INSN_OF(iobj) = BIN(opt_reverse);
3766 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3767
3768 if (op1 > op2) {
3769 /* X > Y
3770 * newarray X
3771 * expandarray Y, 0
3772 * =>
3773 * pop * (Y-X)
3774 * opt_reverse Y
3775 */
3776 for (; diff > 0; diff--) {
3777 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3778 }
3779 }
3780 else { /* (op1 < op2) */
3781 /* X < Y
3782 * newarray X
3783 * expandarray Y, 0
3784 * =>
3785 * putnil * (Y-X)
3786 * opt_reverse Y
3787 */
3788 for (; diff < 0; diff++) {
3789 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3790 }
3791 }
3792 }
3793 }
3794 }
3795
3796 if (IS_INSN_ID(iobj, duparray)) {
3797 LINK_ELEMENT *next = iobj->link.next;
3798 /*
3799 * duparray obj
3800 * expandarray X, 0
3801 * =>
3802 * putobject obj
3803 * expandarray X, 0
3804 */
3805 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3806 INSN_OF(iobj) = BIN(putobject);
3807 }
3808 }
3809
3810 if (IS_INSN_ID(iobj, anytostring)) {
3811 LINK_ELEMENT *next = iobj->link.next;
3812 /*
3813 * anytostring
3814 * concatstrings 1
3815 * =>
3816 * anytostring
3817 */
3818 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3819 OPERAND_AT(next, 0) == INT2FIX(1)) {
3820 ELEM_REMOVE(next);
3821 }
3822 }
3823
3824 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3825 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3826 /*
3827 * putstring ""
3828 * concatstrings N
3829 * =>
3830 * concatstrings N-1
3831 */
3832 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3833 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3834 INSN *next = (INSN *)iobj->link.next;
3835 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3836 ELEM_REMOVE(&next->link);
3837 }
3838 ELEM_REMOVE(&iobj->link);
3839 }
3840 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3841 INSN *next = (INSN *)iobj->link.next;
3842 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3843 VALUE src = OPERAND_AT(iobj, 0);
3844 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3845 VALUE path = rb_iseq_path(iseq);
3846 int line = iobj->insn_info.line_no;
3847 VALUE errinfo = rb_errinfo();
3848 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3849 if (NIL_P(re)) {
3850 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3851 rb_set_errinfo(errinfo);
3852 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3853 }
3854 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3855 ELEM_REMOVE(iobj->link.next);
3856 }
3857 }
3858 }
3859
3860 if (IS_INSN_ID(iobj, concatstrings)) {
3861 /*
3862 * concatstrings N
3863 * concatstrings M
3864 * =>
3865 * concatstrings N+M-1
3866 */
3867 LINK_ELEMENT *next = iobj->link.next;
3868 INSN *jump = 0;
3869 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3870 next = get_destination_insn(jump = (INSN *)next);
3871 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3872 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3873 OPERAND_AT(iobj, 0) = INT2FIX(n);
3874 if (jump) {
3875 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3876 if (!--label->refcnt) {
3877 ELEM_REMOVE(&label->link);
3878 }
3879 else {
3880 label = NEW_LABEL(0);
3881 OPERAND_AT(jump, 0) = (VALUE)label;
3882 }
3883 label->refcnt++;
3884 ELEM_INSERT_NEXT(next, &label->link);
3885 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3886 }
3887 else {
3888 ELEM_REMOVE(next);
3889 }
3890 }
3891 }
3892
3893 if (do_tailcallopt &&
3894 (IS_INSN_ID(iobj, send) ||
3895 IS_INSN_ID(iobj, opt_aref_with) ||
3896 IS_INSN_ID(iobj, opt_aset_with) ||
3897 IS_INSN_ID(iobj, invokesuper))) {
3898 /*
3899 * send ...
3900 * leave
3901 * =>
3902 * send ..., ... | VM_CALL_TAILCALL, ...
3903 * leave # unreachable
3904 */
3905 INSN *piobj = NULL;
3906 if (iobj->link.next) {
3907 LINK_ELEMENT *next = iobj->link.next;
3908 do {
3909 if (!IS_INSN(next)) {
3910 next = next->next;
3911 continue;
3912 }
3913 switch (INSN_OF(next)) {
3914 case BIN(nop):
3915 next = next->next;
3916 break;
3917 case BIN(jump):
3918 /* if cond
3919 * return tailcall
3920 * end
3921 */
3922 next = get_destination_insn((INSN *)next);
3923 break;
3924 case BIN(leave):
3925 piobj = iobj;
3926 /* fall through */
3927 default:
3928 next = NULL;
3929 break;
3930 }
3931 } while (next);
3932 }
3933
3934 if (piobj) {
3935 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3936 if (IS_INSN_ID(piobj, send) ||
3937 IS_INSN_ID(piobj, invokesuper)) {
3938 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3939 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3940 OPERAND_AT(piobj, 0) = (VALUE)ci;
3941 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3942 }
3943 }
3944 else {
3945 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3946 OPERAND_AT(piobj, 0) = (VALUE)ci;
3947 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3948 }
3949 }
3950 }
3951
3952 if (IS_INSN_ID(iobj, dup)) {
3953 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3954 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3955
3956 /*
3957 * dup
3958 * setlocal x, y
3959 * setlocal x, y
3960 * =>
3961 * dup
3962 * setlocal x, y
3963 */
3964 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3965 set2 = set1->next;
3966 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3967 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3968 ELEM_REMOVE(set1);
3969 ELEM_REMOVE(&iobj->link);
3970 }
3971 }
3972
3973 /*
3974 * dup
3975 * setlocal x, y
3976 * dup
3977 * setlocal x, y
3978 * =>
3979 * dup
3980 * setlocal x, y
3981 */
3982 else if (IS_NEXT_INSN_ID(set1, dup) &&
3983 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3984 set2 = set1->next->next;
3985 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3986 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3987 ELEM_REMOVE(set1->next);
3988 ELEM_REMOVE(set2);
3989 }
3990 }
3991 }
3992 }
3993
3994 /*
3995 * getlocal x, y
3996 * dup
3997 * setlocal x, y
3998 * =>
3999 * dup
4000 */
4001 if (IS_INSN_ID(iobj, getlocal)) {
4002 LINK_ELEMENT *niobj = &iobj->link;
4003 if (IS_NEXT_INSN_ID(niobj, dup)) {
4004 niobj = niobj->next;
4005 }
4006 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4007 LINK_ELEMENT *set1 = niobj->next;
4008 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4009 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4010 ELEM_REMOVE(set1);
4011 ELEM_REMOVE(niobj);
4012 }
4013 }
4014 }
4015
4016 /*
4017 * opt_invokebuiltin_delegate
4018 * trace
4019 * leave
4020 * =>
4021 * opt_invokebuiltin_delegate_leave
4022 * trace
4023 * leave
4024 */
4025 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4026 if (IS_TRACE(iobj->link.next)) {
4027 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4028 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4029 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4030 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4031 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4032 }
4033 }
4034 }
4035 }
4036
4037 /*
4038 * getblockparam
4039 * branchif / branchunless
4040 * =>
4041 * getblockparamproxy
4042 * branchif / branchunless
4043 */
4044 if (IS_INSN_ID(iobj, getblockparam)) {
4045 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4046 iobj->insn_id = BIN(getblockparamproxy);
4047 }
4048 }
4049
4050 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4051 LINK_ELEMENT *niobj = &iobj->link;
4052 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4053 niobj = niobj->next;
4054 LINK_ELEMENT *siobj;
4055 unsigned int set_flags = 0, unset_flags = 0;
4056
4057 /*
4058 * Eliminate hash allocation for f(*a, kw: 1)
4059 *
4060 * splatarray false
4061 * duphash
4062 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4063 * =>
4064 * splatarray false
4065 * putobject
4066 * send ARGS_SPLAT|KW_SPLAT
4067 */
4068 if (IS_NEXT_INSN_ID(niobj, send)) {
4069 siobj = niobj->next;
4070 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4071 unset_flags = VM_CALL_ARGS_BLOCKARG;
4072 }
4073 /*
4074 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4075 *
4076 * splatarray false
4077 * duphash
4078 * getlocal / getinstancevariable / getblockparamproxy
4079 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4080 * =>
4081 * splatarray false
4082 * putobject
4083 * getlocal / getinstancevariable / getblockparamproxy
4084 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4085 */
4086 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4087 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4088 siobj = niobj->next->next;
4089 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4090 }
4091
4092 if (set_flags) {
4093 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4094 unsigned int flags = vm_ci_flag(ci);
4095 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4096 ((INSN*)niobj)->insn_id = BIN(putobject);
4097 OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
4098
4099 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4100 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4101 RB_OBJ_WRITTEN(iseq, ci, nci);
4102 OPERAND_AT(siobj, 0) = (VALUE)nci;
4103 }
4104 }
4105 }
4106 }
4107
4108 return COMPILE_OK;
4109}
4110
4111static int
4112insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4113{
4114 iobj->insn_id = insn_id;
4115 iobj->operand_size = insn_len(insn_id) - 1;
4116 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4117
4118 if (insn_id == BIN(opt_neq)) {
4119 VALUE original_ci = iobj->operands[0];
4120 iobj->operand_size = 2;
4121 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4122 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4123 iobj->operands[1] = original_ci;
4124 }
4125
4126 return COMPILE_OK;
4127}
4128
4129static int
4130iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4131{
4132 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4133 IS_INSN(iobj->link.next)) {
4134 /*
4135 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4136 */
4137 INSN *niobj = (INSN *)iobj->link.next;
4138 if (IS_INSN_ID(niobj, send)) {
4139 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4140 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4141 VALUE method = INT2FIX(0);
4142 switch (vm_ci_mid(ci)) {
4143 case idMax:
4144 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4145 break;
4146 case idMin:
4147 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4148 break;
4149 case idHash:
4150 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4151 break;
4152 }
4153
4154 if (method != INT2FIX(0)) {
4155 VALUE num = iobj->operands[0];
4156 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4157 iobj->insn_id = BIN(opt_newarray_send);
4158 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4159 iobj->operands[0] = num;
4160 iobj->operands[1] = method;
4161 iobj->operand_size = operand_len;
4162 ELEM_REMOVE(&niobj->link);
4163 return COMPILE_OK;
4164 }
4165 }
4166 }
4167 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4168 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4169 IS_NEXT_INSN_ID(&niobj->link, send)) {
4170 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4171 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4172 VALUE num = iobj->operands[0];
4173 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4174 iobj->insn_id = BIN(opt_newarray_send);
4175 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4176 iobj->operands[0] = FIXNUM_INC(num, 1);
4177 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4178 iobj->operand_size = operand_len;
4179 ELEM_REMOVE(&iobj->link);
4180 ELEM_REMOVE(niobj->link.next);
4181 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4182 return COMPILE_OK;
4183 }
4184 }
4185 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4186 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4187 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4188 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4189 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4190 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4191 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4192 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4193 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4194 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4195 VALUE num = iobj->operands[0];
4196 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4197 iobj->insn_id = BIN(opt_newarray_send);
4198 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4199 iobj->operands[0] = FIXNUM_INC(num, 2);
4200 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4201 iobj->operand_size = operand_len;
4202 // Remove the "send" insn.
4203 ELEM_REMOVE((niobj->link.next)->next);
4204 // Remove the modified insn from its original "newarray" position...
4205 ELEM_REMOVE(&iobj->link);
4206 // and insert it after the buffer insn.
4207 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4208 return COMPILE_OK;
4209 }
4210 }
4211
4212 // Break the "else if" chain since some prior checks abort after sub-ifs.
4213 // We already found "newarray". To match `[...].include?(arg)` we look for
4214 // the instruction(s) representing the argument followed by a "send".
4215 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4216 IS_INSN_ID(niobj, putobject) ||
4217 IS_INSN_ID(niobj, putself) ||
4218 IS_INSN_ID(niobj, getlocal) ||
4219 IS_INSN_ID(niobj, getinstancevariable)) &&
4220 IS_NEXT_INSN_ID(&niobj->link, send)) {
4221
4222 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4223 const struct rb_callinfo *ci;
4224 // Allow any number (0 or more) of simple method calls on the argument
4225 // (as in `[...].include?(arg.method1.method2)`.
4226 do {
4227 sendobj = sendobj->next;
4228 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4229 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4230
4231 // If this send is for .include? with one arg we can do our opt.
4232 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4233 VALUE num = iobj->operands[0];
4234 INSN *sendins = (INSN *)sendobj;
4235 sendins->insn_id = BIN(opt_newarray_send);
4236 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4237 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4238 sendins->operands[0] = FIXNUM_INC(num, 1);
4239 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4240 // Remove the original "newarray" insn.
4241 ELEM_REMOVE(&iobj->link);
4242 return COMPILE_OK;
4243 }
4244 }
4245 }
4246
4247 /*
4248 * duparray [...]
4249 * some insn for the arg...
4250 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4251 * =>
4252 * arg insn...
4253 * opt_duparray_send [...], :include?, 1
4254 */
4255 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4256 INSN *niobj = (INSN *)iobj->link.next;
4257 if ((IS_INSN_ID(niobj, getlocal) ||
4258 IS_INSN_ID(niobj, getinstancevariable) ||
4259 IS_INSN_ID(niobj, putself)) &&
4260 IS_NEXT_INSN_ID(&niobj->link, send)) {
4261
4262 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4263 const struct rb_callinfo *ci;
4264 // Allow any number (0 or more) of simple method calls on the argument
4265 // (as in `[...].include?(arg.method1.method2)`.
4266 do {
4267 sendobj = sendobj->next;
4268 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4269 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4270
4271 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4272 // Move the array arg from duparray to opt_duparray_send.
4273 VALUE ary = iobj->operands[0];
4275
4276 INSN *sendins = (INSN *)sendobj;
4277 sendins->insn_id = BIN(opt_duparray_send);
4278 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4279 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4280 sendins->operands[0] = ary;
4281 sendins->operands[1] = rb_id2sym(idIncludeP);
4282 sendins->operands[2] = INT2FIX(1);
4283
4284 // Remove the duparray insn.
4285 ELEM_REMOVE(&iobj->link);
4286 return COMPILE_OK;
4287 }
4288 }
4289 }
4290
4291
4292 if (IS_INSN_ID(iobj, send)) {
4293 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4294 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4295
4296#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4297 if (vm_ci_simple(ci)) {
4298 switch (vm_ci_argc(ci)) {
4299 case 0:
4300 switch (vm_ci_mid(ci)) {
4301 case idLength: SP_INSN(length); return COMPILE_OK;
4302 case idSize: SP_INSN(size); return COMPILE_OK;
4303 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4304 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4305 case idSucc: SP_INSN(succ); return COMPILE_OK;
4306 case idNot: SP_INSN(not); return COMPILE_OK;
4307 }
4308 break;
4309 case 1:
4310 switch (vm_ci_mid(ci)) {
4311 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4312 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4313 case idMULT: SP_INSN(mult); return COMPILE_OK;
4314 case idDIV: SP_INSN(div); return COMPILE_OK;
4315 case idMOD: SP_INSN(mod); return COMPILE_OK;
4316 case idEq: SP_INSN(eq); return COMPILE_OK;
4317 case idNeq: SP_INSN(neq); return COMPILE_OK;
4318 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4319 case idLT: SP_INSN(lt); return COMPILE_OK;
4320 case idLE: SP_INSN(le); return COMPILE_OK;
4321 case idGT: SP_INSN(gt); return COMPILE_OK;
4322 case idGE: SP_INSN(ge); return COMPILE_OK;
4323 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4324 case idAREF: SP_INSN(aref); return COMPILE_OK;
4325 case idAnd: SP_INSN(and); return COMPILE_OK;
4326 case idOr: SP_INSN(or); return COMPILE_OK;
4327 }
4328 break;
4329 case 2:
4330 switch (vm_ci_mid(ci)) {
4331 case idASET: SP_INSN(aset); return COMPILE_OK;
4332 }
4333 break;
4334 }
4335 }
4336
4337 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4338 iobj->insn_id = BIN(opt_send_without_block);
4339 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4340 }
4341 }
4342#undef SP_INSN
4343
4344 return COMPILE_OK;
4345}
4346
4347static inline int
4348tailcallable_p(rb_iseq_t *iseq)
4349{
4350 switch (ISEQ_BODY(iseq)->type) {
4351 case ISEQ_TYPE_TOP:
4352 case ISEQ_TYPE_EVAL:
4353 case ISEQ_TYPE_MAIN:
4354 /* not tail callable because cfp will be over popped */
4355 case ISEQ_TYPE_RESCUE:
4356 case ISEQ_TYPE_ENSURE:
4357 /* rescue block can't tail call because of errinfo */
4358 return FALSE;
4359 default:
4360 return TRUE;
4361 }
4362}
4363
4364static int
4365iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4366{
4367 LINK_ELEMENT *list;
4368 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4369 const int do_tailcallopt = tailcallable_p(iseq) &&
4370 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4371 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4372 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4373 int rescue_level = 0;
4374 int tailcallopt = do_tailcallopt;
4375
4376 list = FIRST_ELEMENT(anchor);
4377
4378 int do_block_optimization = 0;
4379 LABEL * block_loop_label = NULL;
4380
4381 // If we're optimizing a block
4382 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4383 do_block_optimization = 1;
4384
4385 // If the block starts with a nop and a label,
4386 // record the label so we can detect if it's a jump target
4387 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4388 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4389 block_loop_label = (LABEL *)le->next;
4390 }
4391 }
4392
4393 while (list) {
4394 if (IS_INSN(list)) {
4395 if (do_peepholeopt) {
4396 iseq_peephole_optimize(iseq, list, tailcallopt);
4397 }
4398 if (do_si) {
4399 iseq_specialized_instruction(iseq, (INSN *)list);
4400 }
4401 if (do_ou) {
4402 insn_operands_unification((INSN *)list);
4403 }
4404
4405 if (do_block_optimization) {
4406 INSN * item = (INSN *)list;
4407 // Give up if there is a throw
4408 if (IS_INSN_ID(item, throw)) {
4409 do_block_optimization = 0;
4410 }
4411 else {
4412 // If the instruction has a jump target, check if the
4413 // jump target is the block loop label
4414 const char *types = insn_op_types(item->insn_id);
4415 for (int j = 0; types[j]; j++) {
4416 if (types[j] == TS_OFFSET) {
4417 // If the jump target is equal to the block loop
4418 // label, then we can't do the optimization because
4419 // the leading `nop` instruction fires the block
4420 // entry tracepoint
4421 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4422 if (target == block_loop_label) {
4423 do_block_optimization = 0;
4424 }
4425 }
4426 }
4427 }
4428 }
4429 }
4430 if (IS_LABEL(list)) {
4431 switch (((LABEL *)list)->rescued) {
4432 case LABEL_RESCUE_BEG:
4433 rescue_level++;
4434 tailcallopt = FALSE;
4435 break;
4436 case LABEL_RESCUE_END:
4437 if (!--rescue_level) tailcallopt = do_tailcallopt;
4438 break;
4439 }
4440 }
4441 list = list->next;
4442 }
4443
4444 if (do_block_optimization) {
4445 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4446 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4447 ELEM_REMOVE(le);
4448 }
4449 }
4450 return COMPILE_OK;
4451}
4452
4453#if OPT_INSTRUCTIONS_UNIFICATION
4454static INSN *
4455new_unified_insn(rb_iseq_t *iseq,
4456 int insn_id, int size, LINK_ELEMENT *seq_list)
4457{
4458 INSN *iobj = 0;
4459 LINK_ELEMENT *list = seq_list;
4460 int i, argc = 0;
4461 VALUE *operands = 0, *ptr = 0;
4462
4463
4464 /* count argc */
4465 for (i = 0; i < size; i++) {
4466 iobj = (INSN *)list;
4467 argc += iobj->operand_size;
4468 list = list->next;
4469 }
4470
4471 if (argc > 0) {
4472 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4473 }
4474
4475 /* copy operands */
4476 list = seq_list;
4477 for (i = 0; i < size; i++) {
4478 iobj = (INSN *)list;
4479 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4480 ptr += iobj->operand_size;
4481 list = list->next;
4482 }
4483
4484 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4485}
4486#endif
4487
4488/*
4489 * This scheme can get more performance if do this optimize with
4490 * label address resolving.
4491 * It's future work (if compile time was bottle neck).
4492 */
4493static int
4494iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4495{
4496#if OPT_INSTRUCTIONS_UNIFICATION
4497 LINK_ELEMENT *list;
4498 INSN *iobj, *niobj;
4499 int id, k;
4500 intptr_t j;
4501
4502 list = FIRST_ELEMENT(anchor);
4503 while (list) {
4504 if (IS_INSN(list)) {
4505 iobj = (INSN *)list;
4506 id = iobj->insn_id;
4507 if (unified_insns_data[id] != 0) {
4508 const int *const *entry = unified_insns_data[id];
4509 for (j = 1; j < (intptr_t)entry[0]; j++) {
4510 const int *unified = entry[j];
4511 LINK_ELEMENT *li = list->next;
4512 for (k = 2; k < unified[1]; k++) {
4513 if (!IS_INSN(li) ||
4514 ((INSN *)li)->insn_id != unified[k]) {
4515 goto miss;
4516 }
4517 li = li->next;
4518 }
4519 /* matched */
4520 niobj =
4521 new_unified_insn(iseq, unified[0], unified[1] - 1,
4522 list);
4523
4524 /* insert to list */
4525 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4526 niobj->link.next = li;
4527 if (li) {
4528 li->prev = (LINK_ELEMENT *)niobj;
4529 }
4530
4531 list->prev->next = (LINK_ELEMENT *)niobj;
4532 list = (LINK_ELEMENT *)niobj;
4533 break;
4534 miss:;
4535 }
4536 }
4537 }
4538 list = list->next;
4539 }
4540#endif
4541 return COMPILE_OK;
4542}
4543
4544static int
4545all_string_result_p(const NODE *node)
4546{
4547 if (!node) return FALSE;
4548 switch (nd_type(node)) {
4549 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4550 return TRUE;
4551 case NODE_IF: case NODE_UNLESS:
4552 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4553 if (all_string_result_p(RNODE_IF(node)->nd_body))
4554 return all_string_result_p(RNODE_IF(node)->nd_else);
4555 return FALSE;
4556 case NODE_AND: case NODE_OR:
4557 if (!RNODE_AND(node)->nd_2nd)
4558 return all_string_result_p(RNODE_AND(node)->nd_1st);
4559 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4560 return FALSE;
4561 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4562 default:
4563 return FALSE;
4564 }
4565}
4566
4568 rb_iseq_t *const iseq;
4569 LINK_ANCHOR *const ret;
4570 VALUE lit;
4571 const NODE *lit_node;
4572 int cnt;
4573 int dregx;
4574};
4575
4576static int
4577append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4578{
4579 VALUE s = rb_str_new_mutable_parser_string(str);
4580 if (args->dregx) {
4581 VALUE error = rb_reg_check_preprocess(s);
4582 if (!NIL_P(error)) {
4583 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4584 return COMPILE_NG;
4585 }
4586 }
4587 if (NIL_P(args->lit)) {
4588 args->lit = s;
4589 args->lit_node = node;
4590 }
4591 else {
4592 rb_str_buf_append(args->lit, s);
4593 }
4594 return COMPILE_OK;
4595}
4596
4597static void
4598flush_dstr_fragment(struct dstr_ctxt *args)
4599{
4600 if (!NIL_P(args->lit)) {
4601 rb_iseq_t *iseq = args->iseq;
4602 VALUE lit = args->lit;
4603 args->lit = Qnil;
4604 lit = rb_fstring(lit);
4605 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4606 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4607 args->cnt++;
4608 }
4609}
4610
4611static int
4612compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4613{
4614 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4615 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4616
4617 if (str) {
4618 CHECK(append_dstr_fragment(args, node, str));
4619 }
4620
4621 while (list) {
4622 const NODE *const head = list->nd_head;
4623 if (nd_type_p(head, NODE_STR)) {
4624 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4625 }
4626 else if (nd_type_p(head, NODE_DSTR)) {
4627 CHECK(compile_dstr_fragments_0(args, head));
4628 }
4629 else {
4630 flush_dstr_fragment(args);
4631 rb_iseq_t *iseq = args->iseq;
4632 CHECK(COMPILE(args->ret, "each string", head));
4633 args->cnt++;
4634 }
4635 list = (struct RNode_LIST *)list->nd_next;
4636 }
4637 return COMPILE_OK;
4638}
4639
4640static int
4641compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4642{
4643 struct dstr_ctxt args = {
4644 .iseq = iseq, .ret = ret,
4645 .lit = Qnil, .lit_node = NULL,
4646 .cnt = 0, .dregx = dregx,
4647 };
4648 CHECK(compile_dstr_fragments_0(&args, node));
4649 flush_dstr_fragment(&args);
4650
4651 *cntp = args.cnt;
4652
4653 return COMPILE_OK;
4654}
4655
4656static int
4657compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4658{
4659 while (node && nd_type_p(node, NODE_BLOCK)) {
4660 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4661 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4662 node = RNODE_BLOCK(node)->nd_next;
4663 }
4664 if (node) {
4665 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4666 }
4667 return COMPILE_OK;
4668}
4669
4670static int
4671compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4672{
4673 int cnt;
4674 if (!RNODE_DSTR(node)->nd_next) {
4675 VALUE lit = rb_node_dstr_string_val(node);
4676 ADD_INSN1(ret, node, putstring, lit);
4677 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4678 }
4679 else {
4680 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4681 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4682 }
4683 return COMPILE_OK;
4684}
4685
4686static int
4687compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4688{
4689 int cnt;
4690 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4691
4692 if (!RNODE_DREGX(node)->nd_next) {
4693 if (!popped) {
4694 VALUE src = rb_node_dregx_string_val(node);
4695 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4696 ADD_INSN1(ret, node, putobject, match);
4697 RB_OBJ_WRITTEN(iseq, Qundef, match);
4698 }
4699 return COMPILE_OK;
4700 }
4701
4702 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4703 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4704
4705 if (popped) {
4706 ADD_INSN(ret, node, pop);
4707 }
4708
4709 return COMPILE_OK;
4710}
4711
4712static int
4713compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4714 LABEL *then_label, LABEL *else_label)
4715{
4716 const int line = nd_line(node);
4717 LABEL *lend = NEW_LABEL(line);
4718 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4719 + VM_SVAR_FLIPFLOP_START;
4720 VALUE key = INT2FIX(cnt);
4721
4722 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4723 ADD_INSNL(ret, node, branchif, lend);
4724
4725 /* *flip == 0 */
4726 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4727 ADD_INSNL(ret, node, branchunless, else_label);
4728 ADD_INSN1(ret, node, putobject, Qtrue);
4729 ADD_INSN1(ret, node, setspecial, key);
4730 if (!again) {
4731 ADD_INSNL(ret, node, jump, then_label);
4732 }
4733
4734 /* *flip == 1 */
4735 ADD_LABEL(ret, lend);
4736 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4737 ADD_INSNL(ret, node, branchunless, then_label);
4738 ADD_INSN1(ret, node, putobject, Qfalse);
4739 ADD_INSN1(ret, node, setspecial, key);
4740 ADD_INSNL(ret, node, jump, then_label);
4741
4742 return COMPILE_OK;
4743}
4744
4745static int
4746compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4747 LABEL *then_label, LABEL *else_label);
4748
4749#define COMPILE_SINGLE 2
4750static int
4751compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4752 LABEL *then_label, LABEL *else_label)
4753{
4754 DECL_ANCHOR(seq);
4755 INIT_ANCHOR(seq);
4756 LABEL *label = NEW_LABEL(nd_line(cond));
4757 if (!then_label) then_label = label;
4758 else if (!else_label) else_label = label;
4759
4760 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4761
4762 if (LIST_INSN_SIZE_ONE(seq)) {
4763 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4764 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4765 return COMPILE_OK;
4766 }
4767 if (!label->refcnt) {
4768 return COMPILE_SINGLE;
4769 }
4770 ADD_LABEL(seq, label);
4771 ADD_SEQ(ret, seq);
4772 return COMPILE_OK;
4773}
4774
4775static int
4776compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4777 LABEL *then_label, LABEL *else_label)
4778{
4779 int ok;
4780 DECL_ANCHOR(ignore);
4781
4782 again:
4783 switch (nd_type(cond)) {
4784 case NODE_AND:
4785 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4786 cond = RNODE_AND(cond)->nd_2nd;
4787 if (ok == COMPILE_SINGLE) {
4788 INIT_ANCHOR(ignore);
4789 ret = ignore;
4790 then_label = NEW_LABEL(nd_line(cond));
4791 }
4792 goto again;
4793 case NODE_OR:
4794 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4795 cond = RNODE_OR(cond)->nd_2nd;
4796 if (ok == COMPILE_SINGLE) {
4797 INIT_ANCHOR(ignore);
4798 ret = ignore;
4799 else_label = NEW_LABEL(nd_line(cond));
4800 }
4801 goto again;
4802 case NODE_SYM:
4803 case NODE_LINE:
4804 case NODE_FILE:
4805 case NODE_ENCODING:
4806 case NODE_INTEGER: /* NODE_INTEGER is always true */
4807 case NODE_FLOAT: /* NODE_FLOAT is always true */
4808 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4809 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4810 case NODE_TRUE:
4811 case NODE_STR:
4812 case NODE_REGX:
4813 case NODE_ZLIST:
4814 case NODE_LAMBDA:
4815 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4816 ADD_INSNL(ret, cond, jump, then_label);
4817 return COMPILE_OK;
4818 case NODE_FALSE:
4819 case NODE_NIL:
4820 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4821 ADD_INSNL(ret, cond, jump, else_label);
4822 return COMPILE_OK;
4823 case NODE_LIST:
4824 case NODE_ARGSCAT:
4825 case NODE_DREGX:
4826 case NODE_DSTR:
4827 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4828 ADD_INSNL(ret, cond, jump, then_label);
4829 return COMPILE_OK;
4830 case NODE_FLIP2:
4831 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4832 return COMPILE_OK;
4833 case NODE_FLIP3:
4834 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4835 return COMPILE_OK;
4836 case NODE_DEFINED:
4837 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4838 break;
4839 default:
4840 {
4841 DECL_ANCHOR(cond_seq);
4842 INIT_ANCHOR(cond_seq);
4843
4844 CHECK(COMPILE(cond_seq, "branch condition", cond));
4845
4846 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4847 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4848 if (insn->insn_id == BIN(putobject)) {
4849 if (RTEST(insn->operands[0])) {
4850 ADD_INSNL(ret, cond, jump, then_label);
4851 // maybe unreachable
4852 return COMPILE_OK;
4853 }
4854 else {
4855 ADD_INSNL(ret, cond, jump, else_label);
4856 return COMPILE_OK;
4857 }
4858 }
4859 }
4860 ADD_SEQ(ret, cond_seq);
4861 }
4862 break;
4863 }
4864
4865 ADD_INSNL(ret, cond, branchunless, else_label);
4866 ADD_INSNL(ret, cond, jump, then_label);
4867 return COMPILE_OK;
4868}
4869
4870#define HASH_BRACE 1
4871
4872static int
4873keyword_node_p(const NODE *const node)
4874{
4875 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4876}
4877
4878static VALUE
4879get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4880{
4881 switch (nd_type(node)) {
4882 case NODE_SYM:
4883 return rb_node_sym_string_val(node);
4884 default:
4885 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4886 }
4887}
4888
4889static VALUE
4890node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4891{
4892 NODE *node = node_hash->nd_head;
4893 VALUE hash = rb_hash_new();
4894 VALUE ary = rb_ary_new();
4895
4896 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4897 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4898 VALUE idx = rb_hash_aref(hash, key);
4899 if (!NIL_P(idx)) {
4900 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4901 (*count_ptr)--;
4902 }
4903 rb_hash_aset(hash, key, INT2FIX(i));
4904 rb_ary_store(ary, i, Qtrue);
4905 (*count_ptr)++;
4906 }
4907
4908 return ary;
4909}
4910
4911static int
4912compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4913 const NODE *const root_node,
4914 struct rb_callinfo_kwarg **const kw_arg_ptr,
4915 unsigned int *flag)
4916{
4917 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4918 RUBY_ASSERT(kw_arg_ptr != NULL);
4919 RUBY_ASSERT(flag != NULL);
4920
4921 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4922 const NODE *node = RNODE_HASH(root_node)->nd_head;
4923 int seen_nodes = 0;
4924
4925 while (node) {
4926 const NODE *key_node = RNODE_LIST(node)->nd_head;
4927 seen_nodes++;
4928
4929 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4930 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4931 /* can be keywords */
4932 }
4933 else {
4934 if (flag) {
4935 *flag |= VM_CALL_KW_SPLAT;
4936 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4937 /* A new hash will be created for the keyword arguments
4938 * in this case, so mark the method as passing mutable
4939 * keyword splat.
4940 */
4941 *flag |= VM_CALL_KW_SPLAT_MUT;
4942 }
4943 }
4944 return FALSE;
4945 }
4946 node = RNODE_LIST(node)->nd_next; /* skip value node */
4947 node = RNODE_LIST(node)->nd_next;
4948 }
4949
4950 /* may be keywords */
4951 node = RNODE_HASH(root_node)->nd_head;
4952 {
4953 int len = 0;
4954 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4955 struct rb_callinfo_kwarg *kw_arg =
4956 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4957 VALUE *keywords = kw_arg->keywords;
4958 int i = 0;
4959 int j = 0;
4960 kw_arg->references = 0;
4961 kw_arg->keyword_len = len;
4962
4963 *kw_arg_ptr = kw_arg;
4964
4965 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4966 const NODE *key_node = RNODE_LIST(node)->nd_head;
4967 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4968 int popped = TRUE;
4969 if (rb_ary_entry(key_index, i)) {
4970 keywords[j] = get_symbol_value(iseq, key_node);
4971 j++;
4972 popped = FALSE;
4973 }
4974 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4975 }
4976 RUBY_ASSERT(j == len);
4977 return TRUE;
4978 }
4979 }
4980 return FALSE;
4981}
4982
4983static int
4984compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4985{
4986 int len = 0;
4987
4988 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4989 if (CPDEBUG > 0) {
4990 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4991 }
4992
4993 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4994 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4995 }
4996 else {
4997 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4998 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4999 }
5000 }
5001
5002 return len;
5003}
5004
5005static inline bool
5006frozen_string_literal_p(const rb_iseq_t *iseq)
5007{
5008 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5009}
5010
5011static inline bool
5012static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5013{
5014 switch (nd_type(node)) {
5015 case NODE_SYM:
5016 case NODE_REGX:
5017 case NODE_LINE:
5018 case NODE_ENCODING:
5019 case NODE_INTEGER:
5020 case NODE_FLOAT:
5021 case NODE_RATIONAL:
5022 case NODE_IMAGINARY:
5023 case NODE_NIL:
5024 case NODE_TRUE:
5025 case NODE_FALSE:
5026 return TRUE;
5027 case NODE_STR:
5028 case NODE_FILE:
5029 return hash_key || frozen_string_literal_p(iseq);
5030 default:
5031 return FALSE;
5032 }
5033}
5034
5035static inline VALUE
5036static_literal_value(const NODE *node, rb_iseq_t *iseq)
5037{
5038 switch (nd_type(node)) {
5039 case NODE_INTEGER:
5040 return rb_node_integer_literal_val(node);
5041 case NODE_FLOAT:
5042 return rb_node_float_literal_val(node);
5043 case NODE_RATIONAL:
5044 return rb_node_rational_literal_val(node);
5045 case NODE_IMAGINARY:
5046 return rb_node_imaginary_literal_val(node);
5047 case NODE_NIL:
5048 return Qnil;
5049 case NODE_TRUE:
5050 return Qtrue;
5051 case NODE_FALSE:
5052 return Qfalse;
5053 case NODE_SYM:
5054 return rb_node_sym_string_val(node);
5055 case NODE_REGX:
5056 return rb_node_regx_string_val(node);
5057 case NODE_LINE:
5058 return rb_node_line_lineno_val(node);
5059 case NODE_ENCODING:
5060 return rb_node_encoding_val(node);
5061 case NODE_FILE:
5062 case NODE_STR:
5063 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5064 VALUE lit = get_string_value(node);
5065 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5066 }
5067 else {
5068 return get_string_value(node);
5069 }
5070 default:
5071 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5072 }
5073}
5074
5075static int
5076compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5077{
5078 const NODE *line_node = node;
5079
5080 if (nd_type_p(node, NODE_ZLIST)) {
5081 if (!popped) {
5082 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5083 }
5084 return 0;
5085 }
5086
5087 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5088
5089 if (popped) {
5090 for (; node; node = RNODE_LIST(node)->nd_next) {
5091 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5092 }
5093 return 1;
5094 }
5095
5096 /* Compilation of an array literal.
5097 * The following code is essentially the same as:
5098 *
5099 * for (int count = 0; node; count++; node->nd_next) {
5100 * compile(node->nd_head);
5101 * }
5102 * ADD_INSN(newarray, count);
5103 *
5104 * However, there are three points.
5105 *
5106 * - The code above causes stack overflow for a big string literal.
5107 * The following limits the stack length up to max_stack_len.
5108 *
5109 * [x1,x2,...,x10000] =>
5110 * push x1 ; push x2 ; ...; push x256; newarray 256;
5111 * push x257; push x258; ...; push x512; pushtoarray 256;
5112 * push x513; push x514; ...; push x768; pushtoarray 256;
5113 * ...
5114 *
5115 * - Long subarray can be optimized by pre-allocating a hidden array.
5116 *
5117 * [1,2,3,...,100] =>
5118 * duparray [1,2,3,...,100]
5119 *
5120 * [x, 1,2,3,...,100, z] =>
5121 * push x; newarray 1;
5122 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5123 * push z; pushtoarray 1;
5124 *
5125 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5126 * to only push it onto the array if it is not empty
5127 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5128 *
5129 * [1,2,3,**kw] =>
5130 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5131 */
5132
5133 const int max_stack_len = 0x100;
5134 const int min_tmp_ary_len = 0x40;
5135 int stack_len = 0;
5136
5137 /* Either create a new array, or push to the existing array */
5138#define FLUSH_CHUNK \
5139 if (stack_len) { \
5140 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5141 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5142 first_chunk = FALSE; \
5143 stack_len = 0; \
5144 }
5145
5146 while (node) {
5147 int count = 1;
5148
5149 /* pre-allocation check (this branch can be omittable) */
5150 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5151 /* count the elements that are optimizable */
5152 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5153 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5154 count++;
5155
5156 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5157 /* The literal contains only optimizable elements, or the subarray is long enough */
5158 VALUE ary = rb_ary_hidden_new(count);
5159
5160 /* Create a hidden array */
5161 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5162 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5163 OBJ_FREEZE(ary);
5164
5165 /* Emit optimized code */
5166 FLUSH_CHUNK;
5167 if (first_chunk) {
5168 ADD_INSN1(ret, line_node, duparray, ary);
5169 first_chunk = FALSE;
5170 }
5171 else {
5172 ADD_INSN1(ret, line_node, putobject, ary);
5173 ADD_INSN(ret, line_node, concattoarray);
5174 }
5175 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5176 }
5177 }
5178
5179 /* Base case: Compile "count" elements */
5180 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5181 if (CPDEBUG > 0) {
5182 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5183 }
5184
5185 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5186 /* Create array or push existing non-keyword elements onto array */
5187 if (stack_len == 0 && first_chunk) {
5188 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5189 }
5190 else {
5191 FLUSH_CHUNK;
5192 }
5193 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5194 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5195 return 1;
5196 }
5197 else {
5198 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5199 stack_len++;
5200 }
5201
5202 /* If there are many pushed elements, flush them to avoid stack overflow */
5203 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5204 }
5205 }
5206
5207 FLUSH_CHUNK;
5208#undef FLUSH_CHUNK
5209 return 1;
5210}
5211
5212static inline int
5213static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5214{
5215 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);
5216}
5217
5218static int
5219compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5220{
5221 const NODE *line_node = node;
5222
5223 node = RNODE_HASH(node)->nd_head;
5224
5225 if (!node || nd_type_p(node, NODE_ZLIST)) {
5226 if (!popped) {
5227 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5228 }
5229 return 0;
5230 }
5231
5232 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5233
5234 if (popped) {
5235 for (; node; node = RNODE_LIST(node)->nd_next) {
5236 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5237 }
5238 return 1;
5239 }
5240
5241 /* Compilation of a hash literal (or keyword arguments).
5242 * This is very similar to compile_array, but there are some differences:
5243 *
5244 * - It contains key-value pairs. So we need to take every two elements.
5245 * We can assume that the length is always even.
5246 *
5247 * - Merging is done by a method call (id_core_hash_merge_ptr).
5248 * Sometimes we need to insert the receiver, so "anchor" is needed.
5249 * In addition, a method call is much slower than concatarray.
5250 * So it pays only when the subsequence is really long.
5251 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5252 *
5253 * - We need to handle keyword splat: **kw.
5254 * For **kw, the key part (node->nd_head) is NULL, and the value part
5255 * (node->nd_next->nd_head) is "kw".
5256 * The code is a bit difficult to avoid hash allocation for **{}.
5257 */
5258
5259 const int max_stack_len = 0x100;
5260 const int min_tmp_hash_len = 0x800;
5261 int stack_len = 0;
5262 int first_chunk = 1;
5263 DECL_ANCHOR(anchor);
5264 INIT_ANCHOR(anchor);
5265
5266 /* Convert pushed elements to a hash, and merge if needed */
5267#define FLUSH_CHUNK() \
5268 if (stack_len) { \
5269 if (first_chunk) { \
5270 APPEND_LIST(ret, anchor); \
5271 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5272 } \
5273 else { \
5274 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5275 ADD_INSN(ret, line_node, swap); \
5276 APPEND_LIST(ret, anchor); \
5277 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5278 } \
5279 INIT_ANCHOR(anchor); \
5280 first_chunk = stack_len = 0; \
5281 }
5282
5283 while (node) {
5284 int count = 1;
5285
5286 /* pre-allocation check (this branch can be omittable) */
5287 if (static_literal_node_pair_p(node, iseq)) {
5288 /* count the elements that are optimizable */
5289 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5290 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5291 count++;
5292
5293 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5294 /* The literal contains only optimizable elements, or the subsequence is long enough */
5295 VALUE ary = rb_ary_hidden_new(count);
5296
5297 /* Create a hidden hash */
5298 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5299 VALUE elem[2];
5300 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5301 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5302 rb_ary_cat(ary, elem, 2);
5303 }
5304 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5305 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5306 hash = rb_obj_hide(hash);
5307 OBJ_FREEZE(hash);
5308
5309 /* Emit optimized code */
5310 FLUSH_CHUNK();
5311 if (first_chunk) {
5312 ADD_INSN1(ret, line_node, duphash, hash);
5313 first_chunk = 0;
5314 }
5315 else {
5316 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5317 ADD_INSN(ret, line_node, swap);
5318
5319 ADD_INSN1(ret, line_node, putobject, hash);
5320
5321 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5322 }
5323 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5324 }
5325 }
5326
5327 /* Base case: Compile "count" elements */
5328 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5329
5330 if (CPDEBUG > 0) {
5331 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5332 }
5333
5334 if (RNODE_LIST(node)->nd_head) {
5335 /* Normal key-value pair */
5336 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5337 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5338 stack_len += 2;
5339
5340 /* If there are many pushed elements, flush them to avoid stack overflow */
5341 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5342 }
5343 else {
5344 /* kwsplat case: foo(..., **kw, ...) */
5345 FLUSH_CHUNK();
5346
5347 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5348 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5349 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5350 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5351 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5352
5353 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5354 if (empty_kw) {
5355 if (only_kw && method_call_keywords) {
5356 /* **{} appears at the only keyword argument in method call,
5357 * so it won't be modified.
5358 * kw is a special NODE_LIT that contains a special empty hash,
5359 * so this emits: putobject {}.
5360 * This is only done for method calls and not for literal hashes,
5361 * because literal hashes should always result in a new hash.
5362 */
5363 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5364 }
5365 else if (first_kw) {
5366 /* **{} appears as the first keyword argument, so it may be modified.
5367 * We need to create a fresh hash object.
5368 */
5369 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5370 }
5371 /* Any empty keyword splats that are not the first can be ignored.
5372 * since merging an empty hash into the existing hash is the same
5373 * as not merging it. */
5374 }
5375 else {
5376 if (only_kw && method_call_keywords) {
5377 /* **kw is only keyword argument in method call.
5378 * Use directly. This will be not be flagged as mutable.
5379 * This is only done for method calls and not for literal hashes,
5380 * because literal hashes should always result in a new hash.
5381 */
5382 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5383 }
5384 else {
5385 /* There is more than one keyword argument, or this is not a method
5386 * call. In that case, we need to add an empty hash (if first keyword),
5387 * or merge the hash to the accumulated hash (if not the first keyword).
5388 */
5389 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5390 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5391 else ADD_INSN(ret, line_node, swap);
5392
5393 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5394
5395 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5396 }
5397 }
5398
5399 first_chunk = 0;
5400 }
5401 }
5402 }
5403
5404 FLUSH_CHUNK();
5405#undef FLUSH_CHUNK
5406 return 1;
5407}
5408
5409VALUE
5410rb_node_case_when_optimizable_literal(const NODE *const node)
5411{
5412 switch (nd_type(node)) {
5413 case NODE_INTEGER:
5414 return rb_node_integer_literal_val(node);
5415 case NODE_FLOAT: {
5416 VALUE v = rb_node_float_literal_val(node);
5417 double ival;
5418
5419 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5420 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5421 }
5422 return v;
5423 }
5424 case NODE_RATIONAL:
5425 case NODE_IMAGINARY:
5426 return Qundef;
5427 case NODE_NIL:
5428 return Qnil;
5429 case NODE_TRUE:
5430 return Qtrue;
5431 case NODE_FALSE:
5432 return Qfalse;
5433 case NODE_SYM:
5434 return rb_node_sym_string_val(node);
5435 case NODE_LINE:
5436 return rb_node_line_lineno_val(node);
5437 case NODE_STR:
5438 return rb_node_str_string_val(node);
5439 case NODE_FILE:
5440 return rb_node_file_path_val(node);
5441 }
5442 return Qundef;
5443}
5444
5445static int
5446when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5447 LABEL *l1, int only_special_literals, VALUE literals)
5448{
5449 while (vals) {
5450 const NODE *val = RNODE_LIST(vals)->nd_head;
5451 VALUE lit = rb_node_case_when_optimizable_literal(val);
5452
5453 if (UNDEF_P(lit)) {
5454 only_special_literals = 0;
5455 }
5456 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5457 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5458 }
5459
5460 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5461 debugp_param("nd_lit", get_string_value(val));
5462 lit = get_string_value(val);
5463 ADD_INSN1(cond_seq, val, putobject, lit);
5464 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5465 }
5466 else {
5467 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5468 }
5469
5470 // Emit pattern === target
5471 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5472 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5473 ADD_INSNL(cond_seq, val, branchif, l1);
5474 vals = RNODE_LIST(vals)->nd_next;
5475 }
5476 return only_special_literals;
5477}
5478
5479static int
5480when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5481 LABEL *l1, int only_special_literals, VALUE literals)
5482{
5483 const NODE *line_node = vals;
5484
5485 switch (nd_type(vals)) {
5486 case NODE_LIST:
5487 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5488 return COMPILE_NG;
5489 break;
5490 case NODE_SPLAT:
5491 ADD_INSN (cond_seq, line_node, dup);
5492 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5493 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5494 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5495 ADD_INSNL(cond_seq, line_node, branchif, l1);
5496 break;
5497 case NODE_ARGSCAT:
5498 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5499 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5500 break;
5501 case NODE_ARGSPUSH:
5502 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5503 ADD_INSN (cond_seq, line_node, dup);
5504 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5505 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5506 ADD_INSNL(cond_seq, line_node, branchif, l1);
5507 break;
5508 default:
5509 ADD_INSN (cond_seq, line_node, dup);
5510 CHECK(COMPILE(cond_seq, "when val", vals));
5511 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5512 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5513 ADD_INSNL(cond_seq, line_node, branchif, l1);
5514 break;
5515 }
5516 return COMPILE_OK;
5517}
5518
5519/* Multiple Assignment Handling
5520 *
5521 * In order to handle evaluation of multiple assignment such that the left hand side
5522 * is evaluated before the right hand side, we need to process the left hand side
5523 * and see if there are any attributes that need to be assigned, or constants set
5524 * on explicit objects. If so, we add instructions to evaluate the receiver of
5525 * any assigned attributes or constants before we process the right hand side.
5526 *
5527 * For a multiple assignment such as:
5528 *
5529 * l1.m1, l2[0] = r3, r4
5530 *
5531 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5532 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5533 * On the VM stack, this looks like:
5534 *
5535 * self # putself
5536 * l1 # send
5537 * l1, self # putself
5538 * l1, l2 # send
5539 * l1, l2, 0 # putobject 0
5540 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5541 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5542 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5543 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5544 * l1, l2, 0, [r3, r4], r4, m1= # send
5545 * l1, l2, 0, [r3, r4], r4 # pop
5546 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5547 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5548 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5549 * l1, l2, 0, [r3, r4], r4, []= # send
5550 * l1, l2, 0, [r3, r4], r4 # pop
5551 * l1, l2, 0, [r3, r4] # pop
5552 * [r3, r4], l2, 0, [r3, r4] # setn 3
5553 * [r3, r4], l2, 0 # pop
5554 * [r3, r4], l2 # pop
5555 * [r3, r4] # pop
5556 *
5557 * This is made more complex when you have to handle splats, post args,
5558 * and arbitrary levels of nesting. You need to keep track of the total
5559 * number of attributes to set, and for each attribute, how many entries
5560 * are on the stack before the final attribute, in order to correctly
5561 * calculate the topn value to use to get the receiver of the attribute
5562 * setter method.
5563 *
5564 * A brief description of the VM stack for simple multiple assignment
5565 * with no splat (rhs_array will not be present if the return value of
5566 * the multiple assignment is not needed):
5567 *
5568 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5569 *
5570 * For multiple assignment with splats, while processing the part before
5571 * the splat (splat+post here is an array of the splat and the post arguments):
5572 *
5573 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5574 *
5575 * When processing the splat and post arguments:
5576 *
5577 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5578 *
5579 * When processing nested multiple assignment, existing values on the stack
5580 * are kept. So for:
5581 *
5582 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5583 *
5584 * The stack layout would be the following before processing the nested
5585 * multiple assignment:
5586 *
5587 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5588 *
5589 * In order to handle this correctly, we need to keep track of the nesting
5590 * level for each attribute assignment, as well as the attribute number
5591 * (left hand side attributes are processed left to right) and number of
5592 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5593 * this information.
5594 *
5595 * We also need to track information for the entire multiple assignment, such
5596 * as the total number of arguments, and the current nesting level, to
5597 * handle both nested multiple assignment as well as cases where the
5598 * rhs is not needed. We also need to keep track of all attribute
5599 * assignments in this, which we do using a linked listed. struct masgn_state
5600 * tracks this information.
5601 */
5602
5604 INSN *before_insn;
5605 struct masgn_lhs_node *next;
5606 const NODE *line_node;
5607 int argn;
5608 int num_args;
5609 int lhs_pos;
5610};
5611
5613 struct masgn_lhs_node *first_memo;
5614 struct masgn_lhs_node *last_memo;
5615 int lhs_level;
5616 int num_args;
5617 bool nested;
5618};
5619
5620static int
5621add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5622{
5623 if (!state) {
5624 rb_bug("no masgn_state");
5625 }
5626
5627 struct masgn_lhs_node *memo;
5628 memo = malloc(sizeof(struct masgn_lhs_node));
5629 if (!memo) {
5630 return COMPILE_NG;
5631 }
5632
5633 memo->before_insn = before_insn;
5634 memo->line_node = line_node;
5635 memo->argn = state->num_args + 1;
5636 memo->num_args = argc;
5637 state->num_args += argc;
5638 memo->lhs_pos = lhs_pos;
5639 memo->next = NULL;
5640 if (!state->first_memo) {
5641 state->first_memo = memo;
5642 }
5643 else {
5644 state->last_memo->next = memo;
5645 }
5646 state->last_memo = memo;
5647
5648 return COMPILE_OK;
5649}
5650
5651static 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);
5652
5653static int
5654compile_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)
5655{
5656 switch (nd_type(node)) {
5657 case NODE_ATTRASGN: {
5658 INSN *iobj;
5659 const NODE *line_node = node;
5660
5661 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5662
5663 bool safenav_call = false;
5664 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5665 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5666 ASSUME(iobj);
5667 ELEM_REMOVE(insn_element);
5668 if (!IS_INSN_ID(iobj, send)) {
5669 safenav_call = true;
5670 iobj = (INSN *)get_prev_insn(iobj);
5671 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5672 }
5673 (pre->last = iobj->link.prev)->next = 0;
5674
5675 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5676 int argc = vm_ci_argc(ci) + 1;
5677 ci = ci_argc_set(iseq, ci, argc);
5678 OPERAND_AT(iobj, 0) = (VALUE)ci;
5679 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5680
5681 if (argc == 1) {
5682 ADD_INSN(lhs, line_node, swap);
5683 }
5684 else {
5685 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5686 }
5687
5688 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5689 return COMPILE_NG;
5690 }
5691
5692 iobj->link.prev = lhs->last;
5693 lhs->last->next = &iobj->link;
5694 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5695 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5696 int argc = vm_ci_argc(ci);
5697 bool dupsplat = false;
5698 ci = ci_argc_set(iseq, ci, argc - 1);
5699 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5700 /* Given h[*a], _ = ary
5701 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5702 * `a` must be dupped, because it will be appended with ary[0]
5703 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5704 */
5705 dupsplat = true;
5706 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5707 }
5708 OPERAND_AT(iobj, 0) = (VALUE)ci;
5709 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5710
5711 /* Given: h[*a], h[*b, 1] = ary
5712 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5713 * so this uses splatarray true on a to dup it before using pushtoarray
5714 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5715 * so you can use pushtoarray directly
5716 */
5717 int line_no = nd_line(line_node);
5718 int node_id = nd_node_id(line_node);
5719
5720 if (dupsplat) {
5721 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5722 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5723 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5724 }
5725 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5726 }
5727 if (!safenav_call) {
5728 ADD_INSN(lhs, line_node, pop);
5729 if (argc != 1) {
5730 ADD_INSN(lhs, line_node, pop);
5731 }
5732 }
5733 for (int i=0; i < argc; i++) {
5734 ADD_INSN(post, line_node, pop);
5735 }
5736 break;
5737 }
5738 case NODE_MASGN: {
5739 DECL_ANCHOR(nest_rhs);
5740 INIT_ANCHOR(nest_rhs);
5741 DECL_ANCHOR(nest_lhs);
5742 INIT_ANCHOR(nest_lhs);
5743
5744 int prev_level = state->lhs_level;
5745 bool prev_nested = state->nested;
5746 state->nested = 1;
5747 state->lhs_level = lhs_pos - 1;
5748 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5749 state->lhs_level = prev_level;
5750 state->nested = prev_nested;
5751
5752 ADD_SEQ(lhs, nest_rhs);
5753 ADD_SEQ(lhs, nest_lhs);
5754 break;
5755 }
5756 case NODE_CDECL:
5757 if (!RNODE_CDECL(node)->nd_vid) {
5758 /* Special handling only needed for expr::C, not for C */
5759 INSN *iobj;
5760
5761 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5762
5763 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5764 iobj = (INSN *)insn_element; /* setconstant insn */
5765 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5766 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5767 ELEM_REMOVE(insn_element);
5768 pre->last = iobj->link.prev;
5769 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5770
5771 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5772 return COMPILE_NG;
5773 }
5774
5775 ADD_INSN(post, node, pop);
5776 break;
5777 }
5778 /* Fallthrough */
5779 default: {
5780 DECL_ANCHOR(anchor);
5781 INIT_ANCHOR(anchor);
5782 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5783 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5784 ADD_SEQ(lhs, anchor);
5785 }
5786 }
5787
5788 return COMPILE_OK;
5789}
5790
5791static int
5792compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5793{
5794 if (lhsn) {
5795 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5796 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5797 }
5798 return COMPILE_OK;
5799}
5800
5801static int
5802compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5803 const NODE *rhsn, const NODE *orig_lhsn)
5804{
5805 VALUE mem[64];
5806 const int memsize = numberof(mem);
5807 int memindex = 0;
5808 int llen = 0, rlen = 0;
5809 int i;
5810 const NODE *lhsn = orig_lhsn;
5811
5812#define MEMORY(v) { \
5813 int i; \
5814 if (memindex == memsize) return 0; \
5815 for (i=0; i<memindex; i++) { \
5816 if (mem[i] == (v)) return 0; \
5817 } \
5818 mem[memindex++] = (v); \
5819}
5820
5821 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5822 return 0;
5823 }
5824
5825 while (lhsn) {
5826 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5827 switch (nd_type(ln)) {
5828 case NODE_LASGN:
5829 case NODE_DASGN:
5830 case NODE_IASGN:
5831 case NODE_CVASGN:
5832 MEMORY(get_nd_vid(ln));
5833 break;
5834 default:
5835 return 0;
5836 }
5837 lhsn = RNODE_LIST(lhsn)->nd_next;
5838 llen++;
5839 }
5840
5841 while (rhsn) {
5842 if (llen <= rlen) {
5843 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5844 }
5845 else {
5846 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5847 }
5848 rhsn = RNODE_LIST(rhsn)->nd_next;
5849 rlen++;
5850 }
5851
5852 if (llen > rlen) {
5853 for (i=0; i<llen-rlen; i++) {
5854 ADD_INSN(ret, orig_lhsn, putnil);
5855 }
5856 }
5857
5858 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5859 return 1;
5860}
5861
5862static int
5863compile_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)
5864{
5865 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5866 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5867 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5868 const NODE *lhsn_count = lhsn;
5869 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5870
5871 int llen = 0;
5872 int lpos = 0;
5873
5874 while (lhsn_count) {
5875 llen++;
5876 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5877 }
5878 while (lhsn) {
5879 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5880 lpos++;
5881 lhsn = RNODE_LIST(lhsn)->nd_next;
5882 }
5883
5884 if (lhs_splat) {
5885 if (nd_type_p(splatn, NODE_POSTARG)) {
5886 /*a, b, *r, p1, p2 */
5887 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5888 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5889 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5890 int ppos = 0;
5891 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5892
5893 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5894
5895 if (NODE_NAMED_REST_P(restn)) {
5896 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5897 }
5898 while (postn) {
5899 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5900 ppos++;
5901 postn = RNODE_LIST(postn)->nd_next;
5902 }
5903 }
5904 else {
5905 /* a, b, *r */
5906 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5907 }
5908 }
5909
5910 if (!state->nested) {
5911 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5912 }
5913
5914 if (!popped) {
5915 ADD_INSN(rhs, node, dup);
5916 }
5917 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5918 return COMPILE_OK;
5919}
5920
5921static int
5922compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5923{
5924 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5925 struct masgn_state state;
5926 state.lhs_level = popped ? 0 : 1;
5927 state.nested = 0;
5928 state.num_args = 0;
5929 state.first_memo = NULL;
5930 state.last_memo = NULL;
5931
5932 DECL_ANCHOR(pre);
5933 INIT_ANCHOR(pre);
5934 DECL_ANCHOR(rhs);
5935 INIT_ANCHOR(rhs);
5936 DECL_ANCHOR(lhs);
5937 INIT_ANCHOR(lhs);
5938 DECL_ANCHOR(post);
5939 INIT_ANCHOR(post);
5940 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5941
5942 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5943 while (memo) {
5944 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5945 for (int i = 0; i < memo->num_args; i++) {
5946 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5947 }
5948 tmp_memo = memo->next;
5949 free(memo);
5950 memo = tmp_memo;
5951 }
5952 CHECK(ok);
5953
5954 ADD_SEQ(ret, pre);
5955 ADD_SEQ(ret, rhs);
5956 ADD_SEQ(ret, lhs);
5957 if (!popped && state.num_args >= 1) {
5958 /* make sure rhs array is returned before popping */
5959 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5960 }
5961 ADD_SEQ(ret, post);
5962 }
5963 return COMPILE_OK;
5964}
5965
5966static VALUE
5967collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5968{
5969 VALUE arr = rb_ary_new();
5970 for (;;) {
5971 switch (nd_type(node)) {
5972 case NODE_CONST:
5973 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5974 return arr;
5975 case NODE_COLON3:
5976 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5977 rb_ary_unshift(arr, ID2SYM(idNULL));
5978 return arr;
5979 case NODE_COLON2:
5980 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5981 node = RNODE_COLON2(node)->nd_head;
5982 break;
5983 default:
5984 return Qfalse;
5985 }
5986 }
5987}
5988
5989static int
5990compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5991 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5992{
5993 switch (nd_type(node)) {
5994 case NODE_CONST:
5995 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5996 ADD_INSN1(body, node, putobject, Qtrue);
5997 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5998 break;
5999 case NODE_COLON3:
6000 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6001 ADD_INSN(body, node, pop);
6002 ADD_INSN1(body, node, putobject, rb_cObject);
6003 ADD_INSN1(body, node, putobject, Qtrue);
6004 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6005 break;
6006 case NODE_COLON2:
6007 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6008 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6009 ADD_INSN1(body, node, putobject, Qfalse);
6010 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6011 break;
6012 default:
6013 CHECK(COMPILE(pref, "const colon2 prefix", node));
6014 break;
6015 }
6016 return COMPILE_OK;
6017}
6018
6019static int
6020compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6021{
6022 if (nd_type_p(cpath, NODE_COLON3)) {
6023 /* toplevel class ::Foo */
6024 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6025 return VM_DEFINECLASS_FLAG_SCOPED;
6026 }
6027 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6028 /* Bar::Foo */
6029 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6030 return VM_DEFINECLASS_FLAG_SCOPED;
6031 }
6032 else {
6033 /* class at cbase Foo */
6034 ADD_INSN1(ret, cpath, putspecialobject,
6035 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6036 return 0;
6037 }
6038}
6039
6040static inline int
6041private_recv_p(const NODE *node)
6042{
6043 NODE *recv = get_nd_recv(node);
6044 if (recv && nd_type_p(recv, NODE_SELF)) {
6045 return RNODE_SELF(recv)->nd_state != 0;
6046 }
6047 return 0;
6048}
6049
6050static void
6051defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6052 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6053
6054static int
6055compile_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);
6056
6057static void
6058defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6059 const NODE *const node, LABEL **lfinish, VALUE needstr,
6060 bool keep_result)
6061{
6062 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6063 enum node_type type;
6064 const int line = nd_line(node);
6065 const NODE *line_node = node;
6066
6067 switch (type = nd_type(node)) {
6068
6069 /* easy literals */
6070 case NODE_NIL:
6071 expr_type = DEFINED_NIL;
6072 break;
6073 case NODE_SELF:
6074 expr_type = DEFINED_SELF;
6075 break;
6076 case NODE_TRUE:
6077 expr_type = DEFINED_TRUE;
6078 break;
6079 case NODE_FALSE:
6080 expr_type = DEFINED_FALSE;
6081 break;
6082
6083 case NODE_HASH:
6084 case NODE_LIST:{
6085 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6086
6087 if (vals) {
6088 do {
6089 if (RNODE_LIST(vals)->nd_head) {
6090 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6091
6092 if (!lfinish[1]) {
6093 lfinish[1] = NEW_LABEL(line);
6094 }
6095 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6096 }
6097 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6098 }
6099 }
6100 /* fall through */
6101 case NODE_STR:
6102 case NODE_SYM:
6103 case NODE_REGX:
6104 case NODE_LINE:
6105 case NODE_FILE:
6106 case NODE_ENCODING:
6107 case NODE_INTEGER:
6108 case NODE_FLOAT:
6109 case NODE_RATIONAL:
6110 case NODE_IMAGINARY:
6111 case NODE_ZLIST:
6112 case NODE_AND:
6113 case NODE_OR:
6114 default:
6115 expr_type = DEFINED_EXPR;
6116 break;
6117
6118 case NODE_SPLAT:
6119 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6120 if (!lfinish[1]) {
6121 lfinish[1] = NEW_LABEL(line);
6122 }
6123 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6124 expr_type = DEFINED_EXPR;
6125 break;
6126
6127 /* variables */
6128 case NODE_LVAR:
6129 case NODE_DVAR:
6130 expr_type = DEFINED_LVAR;
6131 break;
6132
6133#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6134 case NODE_IVAR:
6135 ADD_INSN3(ret, line_node, definedivar,
6136 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6137 return;
6138
6139 case NODE_GVAR:
6140 ADD_INSN(ret, line_node, putnil);
6141 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6142 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6143 return;
6144
6145 case NODE_CVAR:
6146 ADD_INSN(ret, line_node, putnil);
6147 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6148 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6149 return;
6150
6151 case NODE_CONST:
6152 ADD_INSN(ret, line_node, putnil);
6153 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6154 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6155 return;
6156 case NODE_COLON2:
6157 if (!lfinish[1]) {
6158 lfinish[1] = NEW_LABEL(line);
6159 }
6160 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6161 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6162 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6163
6164 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6165 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6166 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6167 }
6168 else {
6169 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6170 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6171 }
6172 return;
6173 case NODE_COLON3:
6174 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6175 ADD_INSN3(ret, line_node, defined,
6176 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6177 return;
6178
6179 /* method dispatch */
6180 case NODE_CALL:
6181 case NODE_OPCALL:
6182 case NODE_VCALL:
6183 case NODE_FCALL:
6184 case NODE_ATTRASGN:{
6185 const int explicit_receiver =
6186 (type == NODE_CALL || type == NODE_OPCALL ||
6187 (type == NODE_ATTRASGN && !private_recv_p(node)));
6188
6189 if (get_nd_args(node) || explicit_receiver) {
6190 if (!lfinish[1]) {
6191 lfinish[1] = NEW_LABEL(line);
6192 }
6193 if (!lfinish[2]) {
6194 lfinish[2] = NEW_LABEL(line);
6195 }
6196 }
6197 if (get_nd_args(node)) {
6198 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6199 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6200 }
6201 if (explicit_receiver) {
6202 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6203 switch (nd_type(get_nd_recv(node))) {
6204 case NODE_CALL:
6205 case NODE_OPCALL:
6206 case NODE_VCALL:
6207 case NODE_FCALL:
6208 case NODE_ATTRASGN:
6209 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6210 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6211 break;
6212 default:
6213 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6214 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6215 break;
6216 }
6217 if (keep_result) {
6218 ADD_INSN(ret, line_node, dup);
6219 }
6220 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6221 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6222 }
6223 else {
6224 ADD_INSN(ret, line_node, putself);
6225 if (keep_result) {
6226 ADD_INSN(ret, line_node, dup);
6227 }
6228 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6229 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6230 }
6231 return;
6232 }
6233
6234 case NODE_YIELD:
6235 ADD_INSN(ret, line_node, putnil);
6236 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6237 PUSH_VAL(DEFINED_YIELD));
6238 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6239 return;
6240
6241 case NODE_BACK_REF:
6242 case NODE_NTH_REF:
6243 ADD_INSN(ret, line_node, putnil);
6244 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6245 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6246 PUSH_VAL(DEFINED_GVAR));
6247 return;
6248
6249 case NODE_SUPER:
6250 case NODE_ZSUPER:
6251 ADD_INSN(ret, line_node, putnil);
6252 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6253 PUSH_VAL(DEFINED_ZSUPER));
6254 return;
6255
6256#undef PUSH_VAL
6257 case NODE_OP_ASGN1:
6258 case NODE_OP_ASGN2:
6259 case NODE_OP_ASGN_OR:
6260 case NODE_OP_ASGN_AND:
6261 case NODE_MASGN:
6262 case NODE_LASGN:
6263 case NODE_DASGN:
6264 case NODE_GASGN:
6265 case NODE_IASGN:
6266 case NODE_CDECL:
6267 case NODE_CVASGN:
6268 case NODE_OP_CDECL:
6269 expr_type = DEFINED_ASGN;
6270 break;
6271 }
6272
6273 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6274
6275 if (needstr != Qfalse) {
6276 VALUE str = rb_iseq_defined_string(expr_type);
6277 ADD_INSN1(ret, line_node, putobject, str);
6278 }
6279 else {
6280 ADD_INSN1(ret, line_node, putobject, Qtrue);
6281 }
6282}
6283
6284static void
6285build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6286{
6287 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6288 iseq_set_exception_local_table(iseq);
6289}
6290
6291static void
6292defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6293 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6294{
6295 LINK_ELEMENT *lcur = ret->last;
6296 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6297 if (lfinish[1]) {
6298 int line = nd_line(node);
6299 LABEL *lstart = NEW_LABEL(line);
6300 LABEL *lend = NEW_LABEL(line);
6301 const rb_iseq_t *rescue;
6303 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6304 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6305 rb_str_concat(rb_str_new2("defined guard in "),
6306 ISEQ_BODY(iseq)->location.label),
6307 ISEQ_TYPE_RESCUE, 0);
6308 lstart->rescued = LABEL_RESCUE_BEG;
6309 lend->rescued = LABEL_RESCUE_END;
6310 APPEND_LABEL(ret, lcur, lstart);
6311 ADD_LABEL(ret, lend);
6312 if (!ignore) {
6313 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6314 }
6315 }
6316}
6317
6318static int
6319compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6320{
6321 const int line = nd_line(node);
6322 const NODE *line_node = node;
6323 if (!RNODE_DEFINED(node)->nd_head) {
6324 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6325 ADD_INSN1(ret, line_node, putobject, str);
6326 }
6327 else {
6328 LABEL *lfinish[3];
6329 LINK_ELEMENT *last = ret->last;
6330 lfinish[0] = NEW_LABEL(line);
6331 lfinish[1] = 0;
6332 lfinish[2] = 0;
6333 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6334 if (lfinish[1]) {
6335 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6336 ADD_INSN(ret, line_node, swap);
6337 if (lfinish[2]) {
6338 ADD_LABEL(ret, lfinish[2]);
6339 }
6340 ADD_INSN(ret, line_node, pop);
6341 ADD_LABEL(ret, lfinish[1]);
6342 }
6343 ADD_LABEL(ret, lfinish[0]);
6344 }
6345 return COMPILE_OK;
6346}
6347
6348static VALUE
6349make_name_for_block(const rb_iseq_t *orig_iseq)
6350{
6351 int level = 1;
6352 const rb_iseq_t *iseq = orig_iseq;
6353
6354 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6355 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6356 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6357 level++;
6358 }
6359 iseq = ISEQ_BODY(iseq)->parent_iseq;
6360 }
6361 }
6362
6363 if (level == 1) {
6364 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6365 }
6366 else {
6367 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6368 }
6369}
6370
6371static void
6372push_ensure_entry(rb_iseq_t *iseq,
6374 struct ensure_range *er, const void *const node)
6375{
6376 enl->ensure_node = node;
6377 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6378 enl->erange = er;
6379 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6380}
6381
6382static void
6383add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6384 LABEL *lstart, LABEL *lend)
6385{
6386 struct ensure_range *ne =
6387 compile_data_alloc(iseq, sizeof(struct ensure_range));
6388
6389 while (erange->next != 0) {
6390 erange = erange->next;
6391 }
6392 ne->next = 0;
6393 ne->begin = lend;
6394 ne->end = erange->end;
6395 erange->end = lstart;
6396
6397 erange->next = ne;
6398}
6399
6400static bool
6401can_add_ensure_iseq(const rb_iseq_t *iseq)
6402{
6404 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6405 while (e) {
6406 if (e->ensure_node) return false;
6407 e = e->prev;
6408 }
6409 }
6410 return true;
6411}
6412
6413static void
6414add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6415{
6416 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6417
6419 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6420 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6421 DECL_ANCHOR(ensure);
6422
6423 INIT_ANCHOR(ensure);
6424 while (enlp) {
6425 if (enlp->erange != NULL) {
6426 DECL_ANCHOR(ensure_part);
6427 LABEL *lstart = NEW_LABEL(0);
6428 LABEL *lend = NEW_LABEL(0);
6429 INIT_ANCHOR(ensure_part);
6430
6431 add_ensure_range(iseq, enlp->erange, lstart, lend);
6432
6433 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6434 ADD_LABEL(ensure_part, lstart);
6435 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6436 ADD_LABEL(ensure_part, lend);
6437 ADD_SEQ(ensure, ensure_part);
6438 }
6439 else {
6440 if (!is_return) {
6441 break;
6442 }
6443 }
6444 enlp = enlp->prev;
6445 }
6446 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6447 ADD_SEQ(ret, ensure);
6448}
6449
6450#if RUBY_DEBUG
6451static int
6452check_keyword(const NODE *node)
6453{
6454 /* This check is essentially a code clone of compile_keyword_arg. */
6455
6456 if (nd_type_p(node, NODE_LIST)) {
6457 while (RNODE_LIST(node)->nd_next) {
6458 node = RNODE_LIST(node)->nd_next;
6459 }
6460 node = RNODE_LIST(node)->nd_head;
6461 }
6462
6463 return keyword_node_p(node);
6464}
6465#endif
6466
6467static bool
6468keyword_node_single_splat_p(NODE *kwnode)
6469{
6470 RUBY_ASSERT(keyword_node_p(kwnode));
6471
6472 NODE *node = RNODE_HASH(kwnode)->nd_head;
6473 return RNODE_LIST(node)->nd_head == NULL &&
6474 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6475}
6476
6477static void
6478compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6479 NODE *kwnode, unsigned int *flag_ptr)
6480{
6481 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6482 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6483 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6484 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6485 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6486}
6487
6488#define SPLATARRAY_FALSE 0
6489#define SPLATARRAY_TRUE 1
6490#define DUP_SINGLE_KW_SPLAT 2
6491
6492static int
6493setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6494 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6495{
6496 if (!argn) return 0;
6497
6498 NODE *kwnode = NULL;
6499
6500 switch (nd_type(argn)) {
6501 case NODE_LIST: {
6502 // f(x, y, z)
6503 int len = compile_args(iseq, args, argn, &kwnode);
6504 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6505
6506 if (kwnode) {
6507 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6508 len -= 1;
6509 }
6510 else {
6511 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6512 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6513 }
6514 else {
6515 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6516 }
6517 }
6518 }
6519
6520 return len;
6521 }
6522 case NODE_SPLAT: {
6523 // f(*a)
6524 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6525 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6526 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6527 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6528 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6529 return 1;
6530 }
6531 case NODE_ARGSCAT: {
6532 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6533 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6534 bool args_pushed = false;
6535
6536 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6537 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6538 if (kwnode) rest_len--;
6539 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6540 args_pushed = true;
6541 }
6542 else {
6543 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6544 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6545 }
6546
6547 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6548 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6549 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6550 argc += 1;
6551 }
6552 else if (!args_pushed) {
6553 ADD_INSN(args, argn, concattoarray);
6554 }
6555
6556 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6557 if (kwnode) {
6558 // kwsplat
6559 *flag_ptr |= VM_CALL_KW_SPLAT;
6560 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6561 argc += 1;
6562 }
6563
6564 return argc;
6565 }
6566 case NODE_ARGSPUSH: {
6567 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6568 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6569
6570 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6571 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6572 if (kwnode) rest_len--;
6573 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6574 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6575 }
6576 else {
6577 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6578 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6579 }
6580 else {
6581 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6582 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6583 }
6584 }
6585
6586 if (kwnode) {
6587 // f(*a, k:1)
6588 *flag_ptr |= VM_CALL_KW_SPLAT;
6589 if (!keyword_node_single_splat_p(kwnode)) {
6590 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6591 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6592 }
6593 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6594 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6595 }
6596 else {
6597 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6598 }
6599 argc += 1;
6600 }
6601
6602 return argc;
6603 }
6604 default: {
6605 UNKNOWN_NODE("setup_arg", argn, Qnil);
6606 }
6607 }
6608}
6609
6610static void
6611setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6612{
6613 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6614 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6615 }
6616}
6617
6618static bool
6619setup_args_dup_rest_p(const NODE *argn)
6620{
6621 switch(nd_type(argn)) {
6622 case NODE_LVAR:
6623 case NODE_DVAR:
6624 case NODE_GVAR:
6625 case NODE_IVAR:
6626 case NODE_CVAR:
6627 case NODE_CONST:
6628 case NODE_COLON3:
6629 case NODE_INTEGER:
6630 case NODE_FLOAT:
6631 case NODE_RATIONAL:
6632 case NODE_IMAGINARY:
6633 case NODE_STR:
6634 case NODE_SYM:
6635 case NODE_REGX:
6636 case NODE_SELF:
6637 case NODE_NIL:
6638 case NODE_TRUE:
6639 case NODE_FALSE:
6640 case NODE_LAMBDA:
6641 case NODE_NTH_REF:
6642 case NODE_BACK_REF:
6643 return false;
6644 case NODE_COLON2:
6645 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6646 default:
6647 return true;
6648 }
6649}
6650
6651static VALUE
6652setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6653 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6654{
6655 VALUE ret;
6656 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6657
6658 if (argn) {
6659 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6660 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6661
6662 if (check_arg) {
6663 switch(nd_type(check_arg)) {
6664 case(NODE_SPLAT):
6665 // avoid caller side array allocation for f(*arg)
6666 dup_rest = SPLATARRAY_FALSE;
6667 break;
6668 case(NODE_ARGSCAT):
6669 // avoid caller side array allocation for f(1, *arg)
6670 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6671 break;
6672 case(NODE_ARGSPUSH):
6673 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6674 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6675 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6676 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6677 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6678 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6679
6680 if (dup_rest == SPLATARRAY_FALSE) {
6681 // require allocation for keyword key/value/splat that may modify splatted argument
6682 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6683 while (node) {
6684 NODE *key_node = RNODE_LIST(node)->nd_head;
6685 if (key_node && setup_args_dup_rest_p(key_node)) {
6686 dup_rest = SPLATARRAY_TRUE;
6687 break;
6688 }
6689
6690 node = RNODE_LIST(node)->nd_next;
6691 NODE *value_node = RNODE_LIST(node)->nd_head;
6692 if (setup_args_dup_rest_p(value_node)) {
6693 dup_rest = SPLATARRAY_TRUE;
6694 break;
6695 }
6696
6697 node = RNODE_LIST(node)->nd_next;
6698 }
6699 }
6700 break;
6701 default:
6702 break;
6703 }
6704 }
6705
6706 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6707 // for block pass that may modify splatted argument, dup rest and kwrest if given
6708 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6709 }
6710 }
6711 initial_dup_rest = dup_rest;
6712
6713 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6714 DECL_ANCHOR(arg_block);
6715 INIT_ANCHOR(arg_block);
6716
6717 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6718 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6719
6720 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6721 const NODE * arg_node =
6722 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6723
6724 int argc = 0;
6725
6726 // Only compile leading args:
6727 // foo(x, y, ...)
6728 // ^^^^
6729 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6730 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6731 }
6732
6733 *flag |= VM_CALL_FORWARDING;
6734
6735 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6736 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6737 return INT2FIX(argc);
6738 }
6739 else {
6740 *flag |= VM_CALL_ARGS_BLOCKARG;
6741
6742 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6743 }
6744
6745 if (LIST_INSN_SIZE_ONE(arg_block)) {
6746 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6747 if (IS_INSN(elem)) {
6748 INSN *iobj = (INSN *)elem;
6749 if (iobj->insn_id == BIN(getblockparam)) {
6750 iobj->insn_id = BIN(getblockparamproxy);
6751 }
6752 }
6753 }
6754 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6755 ADD_SEQ(args, arg_block);
6756 }
6757 else {
6758 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6759 }
6760 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6761 return ret;
6762}
6763
6764static void
6765build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6766{
6767 const NODE *body = ptr;
6768 int line = nd_line(body);
6769 VALUE argc = INT2FIX(0);
6770 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6771
6772 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6773 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6774 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6775 iseq_set_local_table(iseq, 0, 0);
6776}
6777
6778static void
6779compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6780{
6781 const NODE *vars;
6782 LINK_ELEMENT *last;
6783 int line = nd_line(node);
6784 const NODE *line_node = node;
6785 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6786
6787#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6788 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6789#else
6790 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6791#endif
6792 ADD_INSN(ret, line_node, dup);
6793 ADD_INSNL(ret, line_node, branchunless, fail_label);
6794
6795 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6796 INSN *cap;
6797 if (RNODE_BLOCK(vars)->nd_next) {
6798 ADD_INSN(ret, line_node, dup);
6799 }
6800 last = ret->last;
6801 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6802 last = last->next; /* putobject :var */
6803 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6804 NULL, INT2FIX(0), NULL);
6805 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6806#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6807 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6808 /* only one name */
6809 DECL_ANCHOR(nom);
6810
6811 INIT_ANCHOR(nom);
6812 ADD_INSNL(nom, line_node, jump, end_label);
6813 ADD_LABEL(nom, fail_label);
6814# if 0 /* $~ must be MatchData or nil */
6815 ADD_INSN(nom, line_node, pop);
6816 ADD_INSN(nom, line_node, putnil);
6817# endif
6818 ADD_LABEL(nom, end_label);
6819 (nom->last->next = cap->link.next)->prev = nom->last;
6820 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6821 return;
6822 }
6823#endif
6824 }
6825 ADD_INSNL(ret, line_node, jump, end_label);
6826 ADD_LABEL(ret, fail_label);
6827 ADD_INSN(ret, line_node, pop);
6828 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6829 last = ret->last;
6830 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6831 last = last->next; /* putobject :var */
6832 ((INSN*)last)->insn_id = BIN(putnil);
6833 ((INSN*)last)->operand_size = 0;
6834 }
6835 ADD_LABEL(ret, end_label);
6836}
6837
6838static int
6839optimizable_range_item_p(const NODE *n)
6840{
6841 if (!n) return FALSE;
6842 switch (nd_type(n)) {
6843 case NODE_LINE:
6844 return TRUE;
6845 case NODE_INTEGER:
6846 return TRUE;
6847 case NODE_NIL:
6848 return TRUE;
6849 default:
6850 return FALSE;
6851 }
6852}
6853
6854static VALUE
6855optimized_range_item(const NODE *n)
6856{
6857 switch (nd_type(n)) {
6858 case NODE_LINE:
6859 return rb_node_line_lineno_val(n);
6860 case NODE_INTEGER:
6861 return rb_node_integer_literal_val(n);
6862 case NODE_FLOAT:
6863 return rb_node_float_literal_val(n);
6864 case NODE_RATIONAL:
6865 return rb_node_rational_literal_val(n);
6866 case NODE_IMAGINARY:
6867 return rb_node_imaginary_literal_val(n);
6868 case NODE_NIL:
6869 return Qnil;
6870 default:
6871 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6872 }
6873}
6874
6875static int
6876compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6877{
6878 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6879 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6880
6881 const int line = nd_line(node);
6882 const NODE *line_node = node;
6883 DECL_ANCHOR(cond_seq);
6884 LABEL *then_label, *else_label, *end_label;
6885 VALUE branches = Qfalse;
6886
6887 INIT_ANCHOR(cond_seq);
6888 then_label = NEW_LABEL(line);
6889 else_label = NEW_LABEL(line);
6890 end_label = 0;
6891
6892 NODE *cond = RNODE_IF(node)->nd_cond;
6893 if (nd_type(cond) == NODE_BLOCK) {
6894 cond = RNODE_BLOCK(cond)->nd_head;
6895 }
6896
6897 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6898 ADD_SEQ(ret, cond_seq);
6899
6900 if (then_label->refcnt && else_label->refcnt) {
6901 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6902 }
6903
6904 if (then_label->refcnt) {
6905 ADD_LABEL(ret, then_label);
6906
6907 DECL_ANCHOR(then_seq);
6908 INIT_ANCHOR(then_seq);
6909 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6910
6911 if (else_label->refcnt) {
6912 const NODE *const coverage_node = node_body ? node_body : node;
6913 add_trace_branch_coverage(
6914 iseq,
6915 ret,
6916 nd_code_loc(coverage_node),
6917 nd_node_id(coverage_node),
6918 0,
6919 type == NODE_IF ? "then" : "else",
6920 branches);
6921 end_label = NEW_LABEL(line);
6922 ADD_INSNL(then_seq, line_node, jump, end_label);
6923 if (!popped) {
6924 ADD_INSN(then_seq, line_node, pop);
6925 }
6926 }
6927 ADD_SEQ(ret, then_seq);
6928 }
6929
6930 if (else_label->refcnt) {
6931 ADD_LABEL(ret, else_label);
6932
6933 DECL_ANCHOR(else_seq);
6934 INIT_ANCHOR(else_seq);
6935 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6936
6937 if (then_label->refcnt) {
6938 const NODE *const coverage_node = node_else ? node_else : node;
6939 add_trace_branch_coverage(
6940 iseq,
6941 ret,
6942 nd_code_loc(coverage_node),
6943 nd_node_id(coverage_node),
6944 1,
6945 type == NODE_IF ? "else" : "then",
6946 branches);
6947 }
6948 ADD_SEQ(ret, else_seq);
6949 }
6950
6951 if (end_label) {
6952 ADD_LABEL(ret, end_label);
6953 }
6954
6955 return COMPILE_OK;
6956}
6957
6958static int
6959compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6960{
6961 const NODE *vals;
6962 const NODE *node = orig_node;
6963 LABEL *endlabel, *elselabel;
6964 DECL_ANCHOR(head);
6965 DECL_ANCHOR(body_seq);
6966 DECL_ANCHOR(cond_seq);
6967 int only_special_literals = 1;
6968 VALUE literals = rb_hash_new();
6969 int line;
6970 enum node_type type;
6971 const NODE *line_node;
6972 VALUE branches = Qfalse;
6973 int branch_id = 0;
6974
6975 INIT_ANCHOR(head);
6976 INIT_ANCHOR(body_seq);
6977 INIT_ANCHOR(cond_seq);
6978
6979 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6980
6981 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6982
6983 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6984
6985 node = RNODE_CASE(node)->nd_body;
6986 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6987 type = nd_type(node);
6988 line = nd_line(node);
6989 line_node = node;
6990
6991 endlabel = NEW_LABEL(line);
6992 elselabel = NEW_LABEL(line);
6993
6994 ADD_SEQ(ret, head); /* case VAL */
6995
6996 while (type == NODE_WHEN) {
6997 LABEL *l1;
6998
6999 l1 = NEW_LABEL(line);
7000 ADD_LABEL(body_seq, l1);
7001 ADD_INSN(body_seq, line_node, pop);
7002
7003 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7004 add_trace_branch_coverage(
7005 iseq,
7006 body_seq,
7007 nd_code_loc(coverage_node),
7008 nd_node_id(coverage_node),
7009 branch_id++,
7010 "when",
7011 branches);
7012
7013 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7014 ADD_INSNL(body_seq, line_node, jump, endlabel);
7015
7016 vals = RNODE_WHEN(node)->nd_head;
7017 if (vals) {
7018 switch (nd_type(vals)) {
7019 case NODE_LIST:
7020 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7021 if (only_special_literals < 0) return COMPILE_NG;
7022 break;
7023 case NODE_SPLAT:
7024 case NODE_ARGSCAT:
7025 case NODE_ARGSPUSH:
7026 only_special_literals = 0;
7027 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7028 break;
7029 default:
7030 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7031 }
7032 }
7033 else {
7034 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7035 }
7036
7037 node = RNODE_WHEN(node)->nd_next;
7038 if (!node) {
7039 break;
7040 }
7041 type = nd_type(node);
7042 line = nd_line(node);
7043 line_node = node;
7044 }
7045 /* else */
7046 if (node) {
7047 ADD_LABEL(cond_seq, elselabel);
7048 ADD_INSN(cond_seq, line_node, pop);
7049 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7050 CHECK(COMPILE_(cond_seq, "else", node, popped));
7051 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7052 }
7053 else {
7054 debugs("== else (implicit)\n");
7055 ADD_LABEL(cond_seq, elselabel);
7056 ADD_INSN(cond_seq, orig_node, pop);
7057 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7058 if (!popped) {
7059 ADD_INSN(cond_seq, orig_node, putnil);
7060 }
7061 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7062 }
7063
7064 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7065 ADD_INSN(ret, orig_node, dup);
7066 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7067 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7068 LABEL_REF(elselabel);
7069 }
7070
7071 ADD_SEQ(ret, cond_seq);
7072 ADD_SEQ(ret, body_seq);
7073 ADD_LABEL(ret, endlabel);
7074 return COMPILE_OK;
7075}
7076
7077static int
7078compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7079{
7080 const NODE *vals;
7081 const NODE *val;
7082 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7083 LABEL *endlabel;
7084 DECL_ANCHOR(body_seq);
7085 VALUE branches = Qfalse;
7086 int branch_id = 0;
7087
7088 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7089
7090 INIT_ANCHOR(body_seq);
7091 endlabel = NEW_LABEL(nd_line(node));
7092
7093 while (node && nd_type_p(node, NODE_WHEN)) {
7094 const int line = nd_line(node);
7095 LABEL *l1 = NEW_LABEL(line);
7096 ADD_LABEL(body_seq, l1);
7097
7098 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7099 add_trace_branch_coverage(
7100 iseq,
7101 body_seq,
7102 nd_code_loc(coverage_node),
7103 nd_node_id(coverage_node),
7104 branch_id++,
7105 "when",
7106 branches);
7107
7108 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7109 ADD_INSNL(body_seq, node, jump, endlabel);
7110
7111 vals = RNODE_WHEN(node)->nd_head;
7112 if (!vals) {
7113 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7114 }
7115 switch (nd_type(vals)) {
7116 case NODE_LIST:
7117 while (vals) {
7118 LABEL *lnext;
7119 val = RNODE_LIST(vals)->nd_head;
7120 lnext = NEW_LABEL(nd_line(val));
7121 debug_compile("== when2\n", (void)0);
7122 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7123 ADD_LABEL(ret, lnext);
7124 vals = RNODE_LIST(vals)->nd_next;
7125 }
7126 break;
7127 case NODE_SPLAT:
7128 case NODE_ARGSCAT:
7129 case NODE_ARGSPUSH:
7130 ADD_INSN(ret, vals, putnil);
7131 CHECK(COMPILE(ret, "when2/cond splat", vals));
7132 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7133 ADD_INSNL(ret, vals, branchif, l1);
7134 break;
7135 default:
7136 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7137 }
7138 node = RNODE_WHEN(node)->nd_next;
7139 }
7140 /* else */
7141 const NODE *const coverage_node = node ? node : orig_node;
7142 add_trace_branch_coverage(
7143 iseq,
7144 ret,
7145 nd_code_loc(coverage_node),
7146 nd_node_id(coverage_node),
7147 branch_id,
7148 "else",
7149 branches);
7150 CHECK(COMPILE_(ret, "else", node, popped));
7151 ADD_INSNL(ret, orig_node, jump, endlabel);
7152
7153 ADD_SEQ(ret, body_seq);
7154 ADD_LABEL(ret, endlabel);
7155 return COMPILE_OK;
7156}
7157
7158static 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);
7159
7160static 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);
7161static 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);
7162static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7163static 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);
7164static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7165
7166#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7167#define CASE3_BI_OFFSET_ERROR_STRING 1
7168#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7169#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7170#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7171
7172static int
7173iseq_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)
7174{
7175 const int line = nd_line(node);
7176 const NODE *line_node = node;
7177
7178 switch (nd_type(node)) {
7179 case NODE_ARYPTN: {
7180 /*
7181 * if pattern.use_rest_num?
7182 * rest_num = 0
7183 * end
7184 * if pattern.has_constant_node?
7185 * unless pattern.constant === obj
7186 * goto match_failed
7187 * end
7188 * end
7189 * unless obj.respond_to?(:deconstruct)
7190 * goto match_failed
7191 * end
7192 * d = obj.deconstruct
7193 * unless Array === d
7194 * goto type_error
7195 * end
7196 * min_argc = pattern.pre_args_num + pattern.post_args_num
7197 * if pattern.has_rest_arg?
7198 * unless d.length >= min_argc
7199 * goto match_failed
7200 * end
7201 * else
7202 * unless d.length == min_argc
7203 * goto match_failed
7204 * end
7205 * end
7206 * pattern.pre_args_num.each do |i|
7207 * unless pattern.pre_args[i].match?(d[i])
7208 * goto match_failed
7209 * end
7210 * end
7211 * if pattern.use_rest_num?
7212 * rest_num = d.length - min_argc
7213 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7214 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7215 * goto match_failed
7216 * end
7217 * end
7218 * end
7219 * pattern.post_args_num.each do |i|
7220 * j = pattern.pre_args_num + i
7221 * j += rest_num
7222 * unless pattern.post_args[i].match?(d[j])
7223 * goto match_failed
7224 * end
7225 * end
7226 * goto matched
7227 * type_error:
7228 * FrozenCore.raise TypeError
7229 * match_failed:
7230 * goto unmatched
7231 */
7232 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7233 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7234 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7235
7236 const int min_argc = pre_args_num + post_args_num;
7237 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7238 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7239
7240 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7241 int i;
7242 match_failed = NEW_LABEL(line);
7243 type_error = NEW_LABEL(line);
7244 deconstruct = NEW_LABEL(line);
7245 deconstructed = NEW_LABEL(line);
7246
7247 if (use_rest_num) {
7248 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7249 ADD_INSN(ret, line_node, swap);
7250 if (base_index) {
7251 base_index++;
7252 }
7253 }
7254
7255 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7256
7257 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7258
7259 ADD_INSN(ret, line_node, dup);
7260 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7261 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7262 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7263 if (in_single_pattern) {
7264 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7265 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7266 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7267 INT2FIX(min_argc), base_index + 1 /* (1) */));
7268 }
7269 ADD_INSNL(ret, line_node, branchunless, match_failed);
7270
7271 for (i = 0; i < pre_args_num; i++) {
7272 ADD_INSN(ret, line_node, dup);
7273 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7274 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7275 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));
7276 args = RNODE_LIST(args)->nd_next;
7277 }
7278
7279 if (RNODE_ARYPTN(node)->rest_arg) {
7280 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7281 ADD_INSN(ret, line_node, dup);
7282 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7283 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7284 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7285 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7286 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7287 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7288 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7289
7290 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));
7291 }
7292 else {
7293 if (post_args_num > 0) {
7294 ADD_INSN(ret, line_node, dup);
7295 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7296 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7297 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7298 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7299 ADD_INSN(ret, line_node, pop);
7300 }
7301 }
7302 }
7303
7304 args = RNODE_ARYPTN(node)->post_args;
7305 for (i = 0; i < post_args_num; i++) {
7306 ADD_INSN(ret, line_node, dup);
7307
7308 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7309 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7310 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7311
7312 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7313 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));
7314 args = RNODE_LIST(args)->nd_next;
7315 }
7316
7317 ADD_INSN(ret, line_node, pop);
7318 if (use_rest_num) {
7319 ADD_INSN(ret, line_node, pop);
7320 }
7321 ADD_INSNL(ret, line_node, jump, matched);
7322 ADD_INSN(ret, line_node, putnil);
7323 if (use_rest_num) {
7324 ADD_INSN(ret, line_node, putnil);
7325 }
7326
7327 ADD_LABEL(ret, type_error);
7328 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7329 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7330 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7331 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7332 ADD_INSN(ret, line_node, pop);
7333
7334 ADD_LABEL(ret, match_failed);
7335 ADD_INSN(ret, line_node, pop);
7336 if (use_rest_num) {
7337 ADD_INSN(ret, line_node, pop);
7338 }
7339 ADD_INSNL(ret, line_node, jump, unmatched);
7340
7341 break;
7342 }
7343 case NODE_FNDPTN: {
7344 /*
7345 * if pattern.has_constant_node?
7346 * unless pattern.constant === obj
7347 * goto match_failed
7348 * end
7349 * end
7350 * unless obj.respond_to?(:deconstruct)
7351 * goto match_failed
7352 * end
7353 * d = obj.deconstruct
7354 * unless Array === d
7355 * goto type_error
7356 * end
7357 * unless d.length >= pattern.args_num
7358 * goto match_failed
7359 * end
7360 *
7361 * begin
7362 * len = d.length
7363 * limit = d.length - pattern.args_num
7364 * i = 0
7365 * while i <= limit
7366 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7367 * if pattern.has_pre_rest_arg_id
7368 * unless pattern.pre_rest_arg.match?(d[0, i])
7369 * goto find_failed
7370 * end
7371 * end
7372 * if pattern.has_post_rest_arg_id
7373 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7374 * goto find_failed
7375 * end
7376 * end
7377 * goto find_succeeded
7378 * end
7379 * i+=1
7380 * end
7381 * find_failed:
7382 * goto match_failed
7383 * find_succeeded:
7384 * end
7385 *
7386 * goto matched
7387 * type_error:
7388 * FrozenCore.raise TypeError
7389 * match_failed:
7390 * goto unmatched
7391 */
7392 const NODE *args = RNODE_FNDPTN(node)->args;
7393 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7394
7395 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7396 match_failed = NEW_LABEL(line);
7397 type_error = NEW_LABEL(line);
7398 deconstruct = NEW_LABEL(line);
7399 deconstructed = NEW_LABEL(line);
7400
7401 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7402
7403 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7404
7405 ADD_INSN(ret, line_node, dup);
7406 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7407 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7408 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7409 if (in_single_pattern) {
7410 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) */));
7411 }
7412 ADD_INSNL(ret, line_node, branchunless, match_failed);
7413
7414 {
7415 LABEL *while_begin = NEW_LABEL(nd_line(node));
7416 LABEL *next_loop = NEW_LABEL(nd_line(node));
7417 LABEL *find_succeeded = NEW_LABEL(line);
7418 LABEL *find_failed = NEW_LABEL(nd_line(node));
7419 int j;
7420
7421 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7422 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7423
7424 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7425 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7426 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7427
7428 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7429
7430 ADD_LABEL(ret, while_begin);
7431
7432 ADD_INSN(ret, line_node, dup);
7433 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7434 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7435 ADD_INSNL(ret, line_node, branchunless, find_failed);
7436
7437 for (j = 0; j < args_num; j++) {
7438 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7439 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7440 if (j != 0) {
7441 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7442 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7443 }
7444 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7445
7446 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));
7447 args = RNODE_LIST(args)->nd_next;
7448 }
7449
7450 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7451 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7452 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7453 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7454 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7455 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));
7456 }
7457 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7458 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7459 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7460 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7461 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7462 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7463 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7464 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));
7465 }
7466 ADD_INSNL(ret, line_node, jump, find_succeeded);
7467
7468 ADD_LABEL(ret, next_loop);
7469 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7470 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7471 ADD_INSNL(ret, line_node, jump, while_begin);
7472
7473 ADD_LABEL(ret, find_failed);
7474 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7475 if (in_single_pattern) {
7476 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7477 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7478 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7479 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7480 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7481
7482 ADD_INSN1(ret, line_node, putobject, Qfalse);
7483 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7484
7485 ADD_INSN(ret, line_node, pop);
7486 ADD_INSN(ret, line_node, pop);
7487 }
7488 ADD_INSNL(ret, line_node, jump, match_failed);
7489 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7490
7491 ADD_LABEL(ret, find_succeeded);
7492 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7493 }
7494
7495 ADD_INSN(ret, line_node, pop);
7496 ADD_INSNL(ret, line_node, jump, matched);
7497 ADD_INSN(ret, line_node, putnil);
7498
7499 ADD_LABEL(ret, type_error);
7500 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7501 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7502 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7503 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7504 ADD_INSN(ret, line_node, pop);
7505
7506 ADD_LABEL(ret, match_failed);
7507 ADD_INSN(ret, line_node, pop);
7508 ADD_INSNL(ret, line_node, jump, unmatched);
7509
7510 break;
7511 }
7512 case NODE_HSHPTN: {
7513 /*
7514 * keys = nil
7515 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7516 * keys = pattern.kw_args_node.keys
7517 * end
7518 * if pattern.has_constant_node?
7519 * unless pattern.constant === obj
7520 * goto match_failed
7521 * end
7522 * end
7523 * unless obj.respond_to?(:deconstruct_keys)
7524 * goto match_failed
7525 * end
7526 * d = obj.deconstruct_keys(keys)
7527 * unless Hash === d
7528 * goto type_error
7529 * end
7530 * if pattern.has_kw_rest_arg_node?
7531 * d = d.dup
7532 * end
7533 * if pattern.has_kw_args_node?
7534 * pattern.kw_args_node.each |k,|
7535 * unless d.key?(k)
7536 * goto match_failed
7537 * end
7538 * end
7539 * pattern.kw_args_node.each |k, pat|
7540 * if pattern.has_kw_rest_arg_node?
7541 * unless pat.match?(d.delete(k))
7542 * goto match_failed
7543 * end
7544 * else
7545 * unless pat.match?(d[k])
7546 * goto match_failed
7547 * end
7548 * end
7549 * end
7550 * else
7551 * unless d.empty?
7552 * goto match_failed
7553 * end
7554 * end
7555 * if pattern.has_kw_rest_arg_node?
7556 * if pattern.no_rest_keyword?
7557 * unless d.empty?
7558 * goto match_failed
7559 * end
7560 * else
7561 * unless pattern.kw_rest_arg_node.match?(d)
7562 * goto match_failed
7563 * end
7564 * end
7565 * end
7566 * goto matched
7567 * type_error:
7568 * FrozenCore.raise TypeError
7569 * match_failed:
7570 * goto unmatched
7571 */
7572 LABEL *match_failed, *type_error;
7573 VALUE keys = Qnil;
7574
7575 match_failed = NEW_LABEL(line);
7576 type_error = NEW_LABEL(line);
7577
7578 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7579 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7580 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7581 while (kw_args) {
7582 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7583 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7584 }
7585 }
7586
7587 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7588
7589 ADD_INSN(ret, line_node, dup);
7590 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7591 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7592 if (in_single_pattern) {
7593 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7594 }
7595 ADD_INSNL(ret, line_node, branchunless, match_failed);
7596
7597 if (NIL_P(keys)) {
7598 ADD_INSN(ret, line_node, putnil);
7599 }
7600 else {
7601 ADD_INSN1(ret, line_node, duparray, keys);
7602 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7603 }
7604 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7605
7606 ADD_INSN(ret, line_node, dup);
7607 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7608 ADD_INSNL(ret, line_node, branchunless, type_error);
7609
7610 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7611 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7612 }
7613
7614 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7615 int i;
7616 int keys_num;
7617 const NODE *args;
7618 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7619 if (args) {
7620 DECL_ANCHOR(match_values);
7621 INIT_ANCHOR(match_values);
7622 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7623 for (i = 0; i < keys_num; i++) {
7624 NODE *key_node = RNODE_LIST(args)->nd_head;
7625 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7626 VALUE key = get_symbol_value(iseq, key_node);
7627
7628 ADD_INSN(ret, line_node, dup);
7629 ADD_INSN1(ret, line_node, putobject, key);
7630 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7631 if (in_single_pattern) {
7632 LABEL *match_succeeded;
7633 match_succeeded = NEW_LABEL(line);
7634
7635 ADD_INSN(ret, line_node, dup);
7636 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7637
7638 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7639 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7640 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7641 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7642 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7643 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7644 ADD_INSN1(ret, line_node, putobject, key); // (7)
7645 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7646
7647 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7648
7649 ADD_LABEL(ret, match_succeeded);
7650 }
7651 ADD_INSNL(ret, line_node, branchunless, match_failed);
7652
7653 ADD_INSN(match_values, line_node, dup);
7654 ADD_INSN1(match_values, line_node, putobject, key);
7655 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7656 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7657 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7658 }
7659 ADD_SEQ(ret, match_values);
7660 }
7661 }
7662 else {
7663 ADD_INSN(ret, line_node, dup);
7664 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7665 if (in_single_pattern) {
7666 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7667 }
7668 ADD_INSNL(ret, line_node, branchunless, match_failed);
7669 }
7670
7671 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7672 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7673 ADD_INSN(ret, line_node, dup);
7674 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7675 if (in_single_pattern) {
7676 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7677 }
7678 ADD_INSNL(ret, line_node, branchunless, match_failed);
7679 }
7680 else {
7681 ADD_INSN(ret, line_node, dup); // (11)
7682 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));
7683 }
7684 }
7685
7686 ADD_INSN(ret, line_node, pop);
7687 ADD_INSNL(ret, line_node, jump, matched);
7688 ADD_INSN(ret, line_node, putnil);
7689
7690 ADD_LABEL(ret, type_error);
7691 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7692 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7693 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7694 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7695 ADD_INSN(ret, line_node, pop);
7696
7697 ADD_LABEL(ret, match_failed);
7698 ADD_INSN(ret, line_node, pop);
7699 ADD_INSNL(ret, line_node, jump, unmatched);
7700 break;
7701 }
7702 case NODE_SYM:
7703 case NODE_REGX:
7704 case NODE_LINE:
7705 case NODE_INTEGER:
7706 case NODE_FLOAT:
7707 case NODE_RATIONAL:
7708 case NODE_IMAGINARY:
7709 case NODE_FILE:
7710 case NODE_ENCODING:
7711 case NODE_STR:
7712 case NODE_XSTR:
7713 case NODE_DSTR:
7714 case NODE_DSYM:
7715 case NODE_DREGX:
7716 case NODE_LIST:
7717 case NODE_ZLIST:
7718 case NODE_LAMBDA:
7719 case NODE_DOT2:
7720 case NODE_DOT3:
7721 case NODE_CONST:
7722 case NODE_LVAR:
7723 case NODE_DVAR:
7724 case NODE_IVAR:
7725 case NODE_CVAR:
7726 case NODE_GVAR:
7727 case NODE_TRUE:
7728 case NODE_FALSE:
7729 case NODE_SELF:
7730 case NODE_NIL:
7731 case NODE_COLON2:
7732 case NODE_COLON3:
7733 case NODE_BEGIN:
7734 case NODE_BLOCK:
7735 case NODE_ONCE:
7736 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7737 if (in_single_pattern) {
7738 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7739 }
7740 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7741 if (in_single_pattern) {
7742 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7743 }
7744 ADD_INSNL(ret, line_node, branchif, matched);
7745 ADD_INSNL(ret, line_node, jump, unmatched);
7746 break;
7747 case NODE_LASGN: {
7748 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7749 ID id = RNODE_LASGN(node)->nd_vid;
7750 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7751
7752 if (in_alt_pattern) {
7753 const char *name = rb_id2name(id);
7754 if (name && strlen(name) > 0 && name[0] != '_') {
7755 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7756 rb_id2str(id));
7757 return COMPILE_NG;
7758 }
7759 }
7760
7761 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7762 ADD_INSNL(ret, line_node, jump, matched);
7763 break;
7764 }
7765 case NODE_DASGN: {
7766 int idx, lv, ls;
7767 ID id = RNODE_DASGN(node)->nd_vid;
7768
7769 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7770
7771 if (in_alt_pattern) {
7772 const char *name = rb_id2name(id);
7773 if (name && strlen(name) > 0 && name[0] != '_') {
7774 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7775 rb_id2str(id));
7776 return COMPILE_NG;
7777 }
7778 }
7779
7780 if (idx < 0) {
7781 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7782 rb_id2str(id));
7783 return COMPILE_NG;
7784 }
7785 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7786 ADD_INSNL(ret, line_node, jump, matched);
7787 break;
7788 }
7789 case NODE_IF:
7790 case NODE_UNLESS: {
7791 LABEL *match_failed;
7792 match_failed = unmatched;
7793 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7794 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7795 if (in_single_pattern) {
7796 LABEL *match_succeeded;
7797 match_succeeded = NEW_LABEL(line);
7798
7799 ADD_INSN(ret, line_node, dup);
7800 if (nd_type_p(node, NODE_IF)) {
7801 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7802 }
7803 else {
7804 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7805 }
7806
7807 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7808 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7809 ADD_INSN1(ret, line_node, putobject, Qfalse);
7810 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7811
7812 ADD_INSN(ret, line_node, pop);
7813 ADD_INSN(ret, line_node, pop);
7814
7815 ADD_LABEL(ret, match_succeeded);
7816 }
7817 if (nd_type_p(node, NODE_IF)) {
7818 ADD_INSNL(ret, line_node, branchunless, match_failed);
7819 }
7820 else {
7821 ADD_INSNL(ret, line_node, branchif, match_failed);
7822 }
7823 ADD_INSNL(ret, line_node, jump, matched);
7824 break;
7825 }
7826 case NODE_HASH: {
7827 NODE *n;
7828 LABEL *match_failed;
7829 match_failed = NEW_LABEL(line);
7830
7831 n = RNODE_HASH(node)->nd_head;
7832 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7833 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7834 return COMPILE_NG;
7835 }
7836
7837 ADD_INSN(ret, line_node, dup); // (1)
7838 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));
7839 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));
7840 ADD_INSN(ret, line_node, putnil);
7841
7842 ADD_LABEL(ret, match_failed);
7843 ADD_INSN(ret, line_node, pop);
7844 ADD_INSNL(ret, line_node, jump, unmatched);
7845 break;
7846 }
7847 case NODE_OR: {
7848 LABEL *match_succeeded, *fin;
7849 match_succeeded = NEW_LABEL(line);
7850 fin = NEW_LABEL(line);
7851
7852 ADD_INSN(ret, line_node, dup); // (1)
7853 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));
7854 ADD_LABEL(ret, match_succeeded);
7855 ADD_INSN(ret, line_node, pop);
7856 ADD_INSNL(ret, line_node, jump, matched);
7857 ADD_INSN(ret, line_node, putnil);
7858 ADD_LABEL(ret, fin);
7859 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7860 break;
7861 }
7862 default:
7863 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7864 }
7865 return COMPILE_OK;
7866}
7867
7868static int
7869iseq_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)
7870{
7871 LABEL *fin = NEW_LABEL(nd_line(node));
7872 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7873 ADD_LABEL(ret, fin);
7874 return COMPILE_OK;
7875}
7876
7877static int
7878iseq_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)
7879{
7880 const NODE *line_node = node;
7881
7882 if (RNODE_ARYPTN(node)->nd_pconst) {
7883 ADD_INSN(ret, line_node, dup); // (1)
7884 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7885 if (in_single_pattern) {
7886 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7887 }
7888 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7889 if (in_single_pattern) {
7890 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7891 }
7892 ADD_INSNL(ret, line_node, branchunless, match_failed);
7893 }
7894 return COMPILE_OK;
7895}
7896
7897
7898static int
7899iseq_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)
7900{
7901 const NODE *line_node = node;
7902
7903 // NOTE: this optimization allows us to re-use the #deconstruct value
7904 // (or its absence).
7905 if (use_deconstructed_cache) {
7906 // If value is nil then we haven't tried to deconstruct
7907 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7908 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7909
7910 // If false then the value is not deconstructable
7911 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7912 ADD_INSNL(ret, line_node, branchunless, match_failed);
7913
7914 // Drop value, add deconstructed to the stack and jump
7915 ADD_INSN(ret, line_node, pop); // (1)
7916 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7917 ADD_INSNL(ret, line_node, jump, deconstructed);
7918 }
7919 else {
7920 ADD_INSNL(ret, line_node, jump, deconstruct);
7921 }
7922
7923 ADD_LABEL(ret, deconstruct);
7924 ADD_INSN(ret, line_node, dup);
7925 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7926 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7927
7928 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7929 if (use_deconstructed_cache) {
7930 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7931 }
7932
7933 if (in_single_pattern) {
7934 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7935 }
7936
7937 ADD_INSNL(ret, line_node, branchunless, match_failed);
7938
7939 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7940
7941 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7942 if (use_deconstructed_cache) {
7943 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7944 }
7945
7946 ADD_INSN(ret, line_node, dup);
7947 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7948 ADD_INSNL(ret, line_node, branchunless, type_error);
7949
7950 ADD_LABEL(ret, deconstructed);
7951
7952 return COMPILE_OK;
7953}
7954
7955static int
7956iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7957{
7958 /*
7959 * if match_succeeded?
7960 * goto match_succeeded
7961 * end
7962 * error_string = FrozenCore.sprintf(errmsg, matchee)
7963 * key_error_p = false
7964 * match_succeeded:
7965 */
7966 const int line = nd_line(node);
7967 const NODE *line_node = node;
7968 LABEL *match_succeeded = NEW_LABEL(line);
7969
7970 ADD_INSN(ret, line_node, dup);
7971 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7972
7973 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7974 ADD_INSN1(ret, line_node, putobject, errmsg);
7975 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7976 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7977 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7978
7979 ADD_INSN1(ret, line_node, putobject, Qfalse);
7980 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7981
7982 ADD_INSN(ret, line_node, pop);
7983 ADD_INSN(ret, line_node, pop);
7984 ADD_LABEL(ret, match_succeeded);
7985
7986 return COMPILE_OK;
7987}
7988
7989static int
7990iseq_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)
7991{
7992 /*
7993 * if match_succeeded?
7994 * goto match_succeeded
7995 * end
7996 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7997 * key_error_p = false
7998 * match_succeeded:
7999 */
8000 const int line = nd_line(node);
8001 const NODE *line_node = node;
8002 LABEL *match_succeeded = NEW_LABEL(line);
8003
8004 ADD_INSN(ret, line_node, dup);
8005 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8006
8007 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8008 ADD_INSN1(ret, line_node, putobject, errmsg);
8009 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8010 ADD_INSN(ret, line_node, dup);
8011 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8012 ADD_INSN1(ret, line_node, putobject, pattern_length);
8013 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8014 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8015
8016 ADD_INSN1(ret, line_node, putobject, Qfalse);
8017 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8018
8019 ADD_INSN(ret, line_node, pop);
8020 ADD_INSN(ret, line_node, pop);
8021 ADD_LABEL(ret, match_succeeded);
8022
8023 return COMPILE_OK;
8024}
8025
8026static int
8027iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8028{
8029 /*
8030 * if match_succeeded?
8031 * goto match_succeeded
8032 * end
8033 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8034 * key_error_p = false
8035 * match_succeeded:
8036 */
8037 const int line = nd_line(node);
8038 const NODE *line_node = node;
8039 LABEL *match_succeeded = NEW_LABEL(line);
8040
8041 ADD_INSN(ret, line_node, dup);
8042 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8043
8044 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8045 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8046 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8047 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8048 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8049 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8050
8051 ADD_INSN1(ret, line_node, putobject, Qfalse);
8052 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8053
8054 ADD_INSN(ret, line_node, pop);
8055 ADD_INSN(ret, line_node, pop);
8056
8057 ADD_LABEL(ret, match_succeeded);
8058 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8059 ADD_INSN(ret, line_node, pop);
8060 ADD_INSN(ret, line_node, pop);
8061
8062 return COMPILE_OK;
8063}
8064
8065static int
8066compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8067{
8068 const NODE *pattern;
8069 const NODE *node = orig_node;
8070 LABEL *endlabel, *elselabel;
8071 DECL_ANCHOR(head);
8072 DECL_ANCHOR(body_seq);
8073 DECL_ANCHOR(cond_seq);
8074 int line;
8075 enum node_type type;
8076 const NODE *line_node;
8077 VALUE branches = 0;
8078 int branch_id = 0;
8079 bool single_pattern;
8080
8081 INIT_ANCHOR(head);
8082 INIT_ANCHOR(body_seq);
8083 INIT_ANCHOR(cond_seq);
8084
8085 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8086
8087 node = RNODE_CASE3(node)->nd_body;
8088 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8089 type = nd_type(node);
8090 line = nd_line(node);
8091 line_node = node;
8092 single_pattern = !RNODE_IN(node)->nd_next;
8093
8094 endlabel = NEW_LABEL(line);
8095 elselabel = NEW_LABEL(line);
8096
8097 if (single_pattern) {
8098 /* allocate stack for ... */
8099 ADD_INSN(head, line_node, putnil); /* key_error_key */
8100 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8101 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8102 ADD_INSN(head, line_node, putnil); /* error_string */
8103 }
8104 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8105
8106 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8107
8108 ADD_SEQ(ret, head); /* case VAL */
8109
8110 while (type == NODE_IN) {
8111 LABEL *l1;
8112
8113 if (branch_id) {
8114 ADD_INSN(body_seq, line_node, putnil);
8115 }
8116 l1 = NEW_LABEL(line);
8117 ADD_LABEL(body_seq, l1);
8118 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8119
8120 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8121 add_trace_branch_coverage(
8122 iseq,
8123 body_seq,
8124 nd_code_loc(coverage_node),
8125 nd_node_id(coverage_node),
8126 branch_id++,
8127 "in",
8128 branches);
8129
8130 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8131 ADD_INSNL(body_seq, line_node, jump, endlabel);
8132
8133 pattern = RNODE_IN(node)->nd_head;
8134 if (pattern) {
8135 int pat_line = nd_line(pattern);
8136 LABEL *next_pat = NEW_LABEL(pat_line);
8137 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8138 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8139 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8140 ADD_LABEL(cond_seq, next_pat);
8141 LABEL_UNREMOVABLE(next_pat);
8142 }
8143 else {
8144 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8145 return COMPILE_NG;
8146 }
8147
8148 node = RNODE_IN(node)->nd_next;
8149 if (!node) {
8150 break;
8151 }
8152 type = nd_type(node);
8153 line = nd_line(node);
8154 line_node = node;
8155 }
8156 /* else */
8157 if (node) {
8158 ADD_LABEL(cond_seq, elselabel);
8159 ADD_INSN(cond_seq, line_node, pop);
8160 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8161 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8162 CHECK(COMPILE_(cond_seq, "else", node, popped));
8163 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8164 ADD_INSN(cond_seq, line_node, putnil);
8165 if (popped) {
8166 ADD_INSN(cond_seq, line_node, putnil);
8167 }
8168 }
8169 else {
8170 debugs("== else (implicit)\n");
8171 ADD_LABEL(cond_seq, elselabel);
8172 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8173 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8174
8175 if (single_pattern) {
8176 /*
8177 * if key_error_p
8178 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8179 * else
8180 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8181 * end
8182 */
8183 LABEL *key_error, *fin;
8184 struct rb_callinfo_kwarg *kw_arg;
8185
8186 key_error = NEW_LABEL(line);
8187 fin = NEW_LABEL(line);
8188
8189 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8190 kw_arg->references = 0;
8191 kw_arg->keyword_len = 2;
8192 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8193 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8194
8195 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8196 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8197 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8198 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8199 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8200 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8201 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8202 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8203 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8204 ADD_INSNL(cond_seq, orig_node, jump, fin);
8205
8206 ADD_LABEL(cond_seq, key_error);
8207 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8208 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8209 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8210 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8211 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8212 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8213 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8214 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8215 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8216 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8217
8218 ADD_LABEL(cond_seq, fin);
8219 }
8220 else {
8221 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8222 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8223 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8224 }
8225 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8226 if (!popped) {
8227 ADD_INSN(cond_seq, orig_node, putnil);
8228 }
8229 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8230 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8231 if (popped) {
8232 ADD_INSN(cond_seq, line_node, putnil);
8233 }
8234 }
8235
8236 ADD_SEQ(ret, cond_seq);
8237 ADD_SEQ(ret, body_seq);
8238 ADD_LABEL(ret, endlabel);
8239 return COMPILE_OK;
8240}
8241
8242#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8243#undef CASE3_BI_OFFSET_ERROR_STRING
8244#undef CASE3_BI_OFFSET_KEY_ERROR_P
8245#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8246#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8247
8248static int
8249compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8250{
8251 const int line = (int)nd_line(node);
8252 const NODE *line_node = node;
8253
8254 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8255 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8256 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8257 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8258 VALUE branches = Qfalse;
8259
8261
8262 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8263 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8264 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8265 LABEL *end_label = NEW_LABEL(line);
8266 LABEL *adjust_label = NEW_LABEL(line);
8267
8268 LABEL *next_catch_label = NEW_LABEL(line);
8269 LABEL *tmp_label = NULL;
8270
8271 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8272 push_ensure_entry(iseq, &enl, NULL, NULL);
8273
8274 if (RNODE_WHILE(node)->nd_state == 1) {
8275 ADD_INSNL(ret, line_node, jump, next_label);
8276 }
8277 else {
8278 tmp_label = NEW_LABEL(line);
8279 ADD_INSNL(ret, line_node, jump, tmp_label);
8280 }
8281 ADD_LABEL(ret, adjust_label);
8282 ADD_INSN(ret, line_node, putnil);
8283 ADD_LABEL(ret, next_catch_label);
8284 ADD_INSN(ret, line_node, pop);
8285 ADD_INSNL(ret, line_node, jump, next_label);
8286 if (tmp_label) ADD_LABEL(ret, tmp_label);
8287
8288 ADD_LABEL(ret, redo_label);
8289 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8290
8291 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8292 add_trace_branch_coverage(
8293 iseq,
8294 ret,
8295 nd_code_loc(coverage_node),
8296 nd_node_id(coverage_node),
8297 0,
8298 "body",
8299 branches);
8300
8301 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8302 ADD_LABEL(ret, next_label); /* next */
8303
8304 if (type == NODE_WHILE) {
8305 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8306 redo_label, end_label));
8307 }
8308 else {
8309 /* until */
8310 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8311 end_label, redo_label));
8312 }
8313
8314 ADD_LABEL(ret, end_label);
8315 ADD_ADJUST_RESTORE(ret, adjust_label);
8316
8317 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8318 /* ADD_INSN(ret, line_node, putundef); */
8319 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8320 return COMPILE_NG;
8321 }
8322 else {
8323 ADD_INSN(ret, line_node, putnil);
8324 }
8325
8326 ADD_LABEL(ret, break_label); /* break */
8327
8328 if (popped) {
8329 ADD_INSN(ret, line_node, pop);
8330 }
8331
8332 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8333 break_label);
8334 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8335 next_catch_label);
8336 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8337 ISEQ_COMPILE_DATA(iseq)->redo_label);
8338
8339 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8340 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8341 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8342 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8343 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8344 return COMPILE_OK;
8345}
8346
8347static int
8348compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8349{
8350 const int line = nd_line(node);
8351 const NODE *line_node = node;
8352 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8353 LABEL *retry_label = NEW_LABEL(line);
8354 LABEL *retry_end_l = NEW_LABEL(line);
8355 const rb_iseq_t *child_iseq;
8356
8357 ADD_LABEL(ret, retry_label);
8358 if (nd_type_p(node, NODE_FOR)) {
8359 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8360
8361 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8362 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8363 ISEQ_TYPE_BLOCK, line);
8364 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8365 }
8366 else {
8367 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8368 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8369 ISEQ_TYPE_BLOCK, line);
8370 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8371 }
8372
8373 {
8374 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8375 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8376 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8377 //
8378 // Normally, "send" instruction is at the last.
8379 // However, qcall under branch coverage measurement adds some instructions after the "send".
8380 //
8381 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8382 INSN *iobj;
8383 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8384 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8385 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8386 iobj = (INSN*) get_prev_insn(iobj);
8387 }
8388 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8389
8390 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8391 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8392 if (&iobj->link == LAST_ELEMENT(ret)) {
8393 ret->last = (LINK_ELEMENT*) retry_end_l;
8394 }
8395 }
8396
8397 if (popped) {
8398 ADD_INSN(ret, line_node, pop);
8399 }
8400
8401 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8402
8403 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8404 return COMPILE_OK;
8405}
8406
8407static int
8408compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8409{
8410 /* massign to var in "for"
8411 * (args.length == 1 && Array.try_convert(args[0])) || args
8412 */
8413 const NODE *line_node = node;
8414 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8415 LABEL *not_single = NEW_LABEL(nd_line(var));
8416 LABEL *not_ary = NEW_LABEL(nd_line(var));
8417 CHECK(COMPILE(ret, "for var", var));
8418 ADD_INSN(ret, line_node, dup);
8419 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8420 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8421 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8422 ADD_INSNL(ret, line_node, branchunless, not_single);
8423 ADD_INSN(ret, line_node, dup);
8424 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8425 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8426 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8427 ADD_INSN(ret, line_node, swap);
8428 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8429 ADD_INSN(ret, line_node, dup);
8430 ADD_INSNL(ret, line_node, branchunless, not_ary);
8431 ADD_INSN(ret, line_node, swap);
8432 ADD_LABEL(ret, not_ary);
8433 ADD_INSN(ret, line_node, pop);
8434 ADD_LABEL(ret, not_single);
8435 return COMPILE_OK;
8436}
8437
8438static int
8439compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8440{
8441 const NODE *line_node = node;
8442 unsigned long throw_flag = 0;
8443
8444 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8445 /* while/until */
8446 LABEL *splabel = NEW_LABEL(0);
8447 ADD_LABEL(ret, splabel);
8448 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8449 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8450 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8451 add_ensure_iseq(ret, iseq, 0);
8452 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8453 ADD_ADJUST_RESTORE(ret, splabel);
8454
8455 if (!popped) {
8456 ADD_INSN(ret, line_node, putnil);
8457 }
8458 }
8459 else {
8460 const rb_iseq_t *ip = iseq;
8461
8462 while (ip) {
8463 if (!ISEQ_COMPILE_DATA(ip)) {
8464 ip = 0;
8465 break;
8466 }
8467
8468 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8469 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8470 }
8471 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8472 throw_flag = 0;
8473 }
8474 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8475 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8476 return COMPILE_NG;
8477 }
8478 else {
8479 ip = ISEQ_BODY(ip)->parent_iseq;
8480 continue;
8481 }
8482
8483 /* escape from block */
8484 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8485 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8486 if (popped) {
8487 ADD_INSN(ret, line_node, pop);
8488 }
8489 return COMPILE_OK;
8490 }
8491 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8492 return COMPILE_NG;
8493 }
8494 return COMPILE_OK;
8495}
8496
8497static int
8498compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8499{
8500 const NODE *line_node = node;
8501 unsigned long throw_flag = 0;
8502
8503 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8504 LABEL *splabel = NEW_LABEL(0);
8505 debugs("next in while loop\n");
8506 ADD_LABEL(ret, splabel);
8507 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8508 add_ensure_iseq(ret, iseq, 0);
8509 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8510 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8511 ADD_ADJUST_RESTORE(ret, splabel);
8512 if (!popped) {
8513 ADD_INSN(ret, line_node, putnil);
8514 }
8515 }
8516 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8517 LABEL *splabel = NEW_LABEL(0);
8518 debugs("next in block\n");
8519 ADD_LABEL(ret, splabel);
8520 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8521 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8522 add_ensure_iseq(ret, iseq, 0);
8523 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8524 ADD_ADJUST_RESTORE(ret, splabel);
8525
8526 if (!popped) {
8527 ADD_INSN(ret, line_node, putnil);
8528 }
8529 }
8530 else {
8531 const rb_iseq_t *ip = iseq;
8532
8533 while (ip) {
8534 if (!ISEQ_COMPILE_DATA(ip)) {
8535 ip = 0;
8536 break;
8537 }
8538
8539 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8540 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8541 /* while loop */
8542 break;
8543 }
8544 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8545 break;
8546 }
8547 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8548 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8549 return COMPILE_NG;
8550 }
8551
8552 ip = ISEQ_BODY(ip)->parent_iseq;
8553 }
8554 if (ip != 0) {
8555 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8556 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8557
8558 if (popped) {
8559 ADD_INSN(ret, line_node, pop);
8560 }
8561 }
8562 else {
8563 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8564 return COMPILE_NG;
8565 }
8566 }
8567 return COMPILE_OK;
8568}
8569
8570static int
8571compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8572{
8573 const NODE *line_node = node;
8574
8575 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8576 LABEL *splabel = NEW_LABEL(0);
8577 debugs("redo in while");
8578 ADD_LABEL(ret, splabel);
8579 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8580 add_ensure_iseq(ret, iseq, 0);
8581 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8582 ADD_ADJUST_RESTORE(ret, splabel);
8583 if (!popped) {
8584 ADD_INSN(ret, line_node, putnil);
8585 }
8586 }
8587 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8588 LABEL *splabel = NEW_LABEL(0);
8589
8590 debugs("redo in block");
8591 ADD_LABEL(ret, splabel);
8592 add_ensure_iseq(ret, iseq, 0);
8593 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8594 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8595 ADD_ADJUST_RESTORE(ret, splabel);
8596
8597 if (!popped) {
8598 ADD_INSN(ret, line_node, putnil);
8599 }
8600 }
8601 else {
8602 const rb_iseq_t *ip = iseq;
8603
8604 while (ip) {
8605 if (!ISEQ_COMPILE_DATA(ip)) {
8606 ip = 0;
8607 break;
8608 }
8609
8610 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8611 break;
8612 }
8613 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8614 break;
8615 }
8616 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8617 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8618 return COMPILE_NG;
8619 }
8620
8621 ip = ISEQ_BODY(ip)->parent_iseq;
8622 }
8623 if (ip != 0) {
8624 ADD_INSN(ret, line_node, putnil);
8625 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8626
8627 if (popped) {
8628 ADD_INSN(ret, line_node, pop);
8629 }
8630 }
8631 else {
8632 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8633 return COMPILE_NG;
8634 }
8635 }
8636 return COMPILE_OK;
8637}
8638
8639static int
8640compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8641{
8642 const NODE *line_node = node;
8643
8644 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8645 ADD_INSN(ret, line_node, putnil);
8646 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8647
8648 if (popped) {
8649 ADD_INSN(ret, line_node, pop);
8650 }
8651 }
8652 else {
8653 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8654 return COMPILE_NG;
8655 }
8656 return COMPILE_OK;
8657}
8658
8659static int
8660compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8661{
8662 const int line = nd_line(node);
8663 const NODE *line_node = node;
8664 LABEL *lstart = NEW_LABEL(line);
8665 LABEL *lend = NEW_LABEL(line);
8666 LABEL *lcont = NEW_LABEL(line);
8667 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8668 rb_str_concat(rb_str_new2("rescue in "),
8669 ISEQ_BODY(iseq)->location.label),
8670 ISEQ_TYPE_RESCUE, line);
8671
8672 lstart->rescued = LABEL_RESCUE_BEG;
8673 lend->rescued = LABEL_RESCUE_END;
8674 ADD_LABEL(ret, lstart);
8675
8676 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8677 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8678 {
8679 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8680 }
8681 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8682
8683 ADD_LABEL(ret, lend);
8684 if (RNODE_RESCUE(node)->nd_else) {
8685 ADD_INSN(ret, line_node, pop);
8686 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8687 }
8688 ADD_INSN(ret, line_node, nop);
8689 ADD_LABEL(ret, lcont);
8690
8691 if (popped) {
8692 ADD_INSN(ret, line_node, pop);
8693 }
8694
8695 /* register catch entry */
8696 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8697 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8698 return COMPILE_OK;
8699}
8700
8701static int
8702compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8703{
8704 const int line = nd_line(node);
8705 const NODE *line_node = node;
8706 const NODE *resq = node;
8707 const NODE *narg;
8708 LABEL *label_miss, *label_hit;
8709
8710 while (resq) {
8711 label_miss = NEW_LABEL(line);
8712 label_hit = NEW_LABEL(line);
8713
8714 narg = RNODE_RESBODY(resq)->nd_args;
8715 if (narg) {
8716 switch (nd_type(narg)) {
8717 case NODE_LIST:
8718 while (narg) {
8719 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8720 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8721 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8722 ADD_INSNL(ret, line_node, branchif, label_hit);
8723 narg = RNODE_LIST(narg)->nd_next;
8724 }
8725 break;
8726 case NODE_SPLAT:
8727 case NODE_ARGSCAT:
8728 case NODE_ARGSPUSH:
8729 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8730 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8731 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8732 ADD_INSNL(ret, line_node, branchif, label_hit);
8733 break;
8734 default:
8735 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8736 }
8737 }
8738 else {
8739 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8740 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8741 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8742 ADD_INSNL(ret, line_node, branchif, label_hit);
8743 }
8744 ADD_INSNL(ret, line_node, jump, label_miss);
8745 ADD_LABEL(ret, label_hit);
8746 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8747
8748 if (RNODE_RESBODY(resq)->nd_exc_var) {
8749 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8750 }
8751
8752 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) {
8753 // empty body
8754 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8755 }
8756 else {
8757 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8758 }
8759
8760 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8761 ADD_INSN(ret, line_node, nop);
8762 }
8763 ADD_INSN(ret, line_node, leave);
8764 ADD_LABEL(ret, label_miss);
8765 resq = RNODE_RESBODY(resq)->nd_next;
8766 }
8767 return COMPILE_OK;
8768}
8769
8770static int
8771compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8772{
8773 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8774 const NODE *line_node = node;
8775 DECL_ANCHOR(ensr);
8776 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8777 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8778 ISEQ_TYPE_ENSURE, line);
8779 LABEL *lstart = NEW_LABEL(line);
8780 LABEL *lend = NEW_LABEL(line);
8781 LABEL *lcont = NEW_LABEL(line);
8782 LINK_ELEMENT *last;
8783 int last_leave = 0;
8784 struct ensure_range er;
8786 struct ensure_range *erange;
8787
8788 INIT_ANCHOR(ensr);
8789 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8790 last = ensr->last;
8791 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8792
8793 er.begin = lstart;
8794 er.end = lend;
8795 er.next = 0;
8796 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8797
8798 ADD_LABEL(ret, lstart);
8799 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8800 ADD_LABEL(ret, lend);
8801 ADD_SEQ(ret, ensr);
8802 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8803 ADD_LABEL(ret, lcont);
8804 if (last_leave) ADD_INSN(ret, line_node, pop);
8805
8806 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8807 if (lstart->link.next != &lend->link) {
8808 while (erange) {
8809 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8810 ensure, lcont);
8811 erange = erange->next;
8812 }
8813 }
8814
8815 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8816 return COMPILE_OK;
8817}
8818
8819static int
8820compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8821{
8822 const NODE *line_node = node;
8823
8824 if (iseq) {
8825 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8826 const rb_iseq_t *is = iseq;
8827 enum rb_iseq_type t = type;
8828 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8829 LABEL *splabel = 0;
8830
8831 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8832 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8833 t = ISEQ_BODY(is)->type;
8834 }
8835 switch (t) {
8836 case ISEQ_TYPE_TOP:
8837 case ISEQ_TYPE_MAIN:
8838 if (retval) {
8839 rb_warn("argument of top-level return is ignored");
8840 }
8841 if (is == iseq) {
8842 /* plain top-level, leave directly */
8843 type = ISEQ_TYPE_METHOD;
8844 }
8845 break;
8846 default:
8847 break;
8848 }
8849
8850 if (type == ISEQ_TYPE_METHOD) {
8851 splabel = NEW_LABEL(0);
8852 ADD_LABEL(ret, splabel);
8853 ADD_ADJUST(ret, line_node, 0);
8854 }
8855
8856 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8857
8858 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8859 add_ensure_iseq(ret, iseq, 1);
8860 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8861 ADD_INSN(ret, line_node, leave);
8862 ADD_ADJUST_RESTORE(ret, splabel);
8863
8864 if (!popped) {
8865 ADD_INSN(ret, line_node, putnil);
8866 }
8867 }
8868 else {
8869 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8870 if (popped) {
8871 ADD_INSN(ret, line_node, pop);
8872 }
8873 }
8874 }
8875 return COMPILE_OK;
8876}
8877
8878static bool
8879drop_unreachable_return(LINK_ANCHOR *ret)
8880{
8881 LINK_ELEMENT *i = ret->last, *last;
8882 if (!i) return false;
8883 if (IS_TRACE(i)) i = i->prev;
8884 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8885 last = i = i->prev;
8886 if (IS_ADJUST(i)) i = i->prev;
8887 if (!IS_INSN(i)) return false;
8888 switch (INSN_OF(i)) {
8889 case BIN(leave):
8890 case BIN(jump):
8891 break;
8892 default:
8893 return false;
8894 }
8895 (ret->last = last->prev)->next = NULL;
8896 return true;
8897}
8898
8899static int
8900compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8901{
8902 CHECK(COMPILE_(ret, "nd_body", node, popped));
8903
8904 if (!popped && !all_string_result_p(node)) {
8905 const NODE *line_node = node;
8906 const unsigned int flag = VM_CALL_FCALL;
8907
8908 // Note, this dup could be removed if we are willing to change anytostring. It pops
8909 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8910 ADD_INSN(ret, line_node, dup);
8911 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8912 ADD_INSN(ret, line_node, anytostring);
8913 }
8914 return COMPILE_OK;
8915}
8916
8917static void
8918compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8919{
8920 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8921
8922 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8923 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8924}
8925
8926static LABEL *
8927qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8928{
8929 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8930 VALUE br = 0;
8931
8932 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8933 *branches = br;
8934 ADD_INSN(recv, line_node, dup);
8935 ADD_INSNL(recv, line_node, branchnil, else_label);
8936 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8937 return else_label;
8938}
8939
8940static void
8941qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8942{
8943 LABEL *end_label;
8944 if (!else_label) return;
8945 end_label = NEW_LABEL(nd_line(line_node));
8946 ADD_INSNL(ret, line_node, jump, end_label);
8947 ADD_LABEL(ret, else_label);
8948 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8949 ADD_LABEL(ret, end_label);
8950}
8951
8952static int
8953compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8954{
8955 /* optimization shortcut
8956 * "literal".freeze -> opt_str_freeze("literal")
8957 */
8958 if (get_nd_recv(node) &&
8959 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8960 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8961 get_nd_args(node) == NULL &&
8962 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8963 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8964 VALUE str = get_string_value(get_nd_recv(node));
8965 if (get_node_call_nd_mid(node) == idUMinus) {
8966 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8967 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8968 }
8969 else {
8970 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8971 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8972 }
8973 RB_OBJ_WRITTEN(iseq, Qundef, str);
8974 if (popped) {
8975 ADD_INSN(ret, line_node, pop);
8976 }
8977 return TRUE;
8978 }
8979 /* optimization shortcut
8980 * obj["literal"] -> opt_aref_with(obj, "literal")
8981 */
8982 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8983 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8984 (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)) &&
8985 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8986 !frozen_string_literal_p(iseq) &&
8987 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8988 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8989 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8990 ADD_INSN2(ret, line_node, opt_aref_with, str,
8991 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8992 RB_OBJ_WRITTEN(iseq, Qundef, str);
8993 if (popped) {
8994 ADD_INSN(ret, line_node, pop);
8995 }
8996 return TRUE;
8997 }
8998 return FALSE;
8999}
9000
9001static int
9002iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9003{
9004 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9005}
9006
9007static const struct rb_builtin_function *
9008iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9009{
9010 int i;
9011 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9012 for (i=0; table[i].index != -1; i++) {
9013 if (strcmp(table[i].name, name) == 0) {
9014 return &table[i];
9015 }
9016 }
9017 return NULL;
9018}
9019
9020static const char *
9021iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9022{
9023 const char *name = rb_id2name(mid);
9024 static const char prefix[] = "__builtin_";
9025 const size_t prefix_len = sizeof(prefix) - 1;
9026
9027 switch (type) {
9028 case NODE_CALL:
9029 if (recv) {
9030 switch (nd_type(recv)) {
9031 case NODE_VCALL:
9032 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9033 return name;
9034 }
9035 break;
9036 case NODE_CONST:
9037 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9038 return name;
9039 }
9040 break;
9041 default: break;
9042 }
9043 }
9044 break;
9045 case NODE_VCALL:
9046 case NODE_FCALL:
9047 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9048 return &name[prefix_len];
9049 }
9050 break;
9051 default: break;
9052 }
9053 return NULL;
9054}
9055
9056static int
9057delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9058{
9059
9060 if (argc == 0) {
9061 *pstart_index = 0;
9062 return TRUE;
9063 }
9064 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9065 unsigned int start=0;
9066
9067 // local_table: [p1, p2, p3, l1, l2, l3]
9068 // arguments: [p3, l1, l2] -> 2
9069 for (start = 0;
9070 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9071 start++) {
9072 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9073
9074 for (unsigned int i=start; i-start<argc; i++) {
9075 if (IS_INSN(elem) &&
9076 INSN_OF(elem) == BIN(getlocal)) {
9077 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9078 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9079
9080 if (local_level == 0) {
9081 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9082 if (0) { // for debug
9083 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9084 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9085 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9086 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9087 }
9088 if (i == index) {
9089 elem = elem->next;
9090 continue; /* for */
9091 }
9092 else {
9093 goto next;
9094 }
9095 }
9096 else {
9097 goto fail; // level != 0 is unsupported
9098 }
9099 }
9100 else {
9101 goto fail; // insn is not a getlocal
9102 }
9103 }
9104 goto success;
9105 next:;
9106 }
9107 fail:
9108 return FALSE;
9109 success:
9110 *pstart_index = start;
9111 return TRUE;
9112 }
9113 else {
9114 return FALSE;
9115 }
9116}
9117
9118// Compile Primitive.attr! :leaf, ...
9119static int
9120compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9121{
9122 VALUE symbol;
9123 VALUE string;
9124 if (!node) goto no_arg;
9125 while (node) {
9126 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9127 const NODE *next = RNODE_LIST(node)->nd_next;
9128
9129 node = RNODE_LIST(node)->nd_head;
9130 if (!node) goto no_arg;
9131 switch (nd_type(node)) {
9132 case NODE_SYM:
9133 symbol = rb_node_sym_string_val(node);
9134 break;
9135 default:
9136 goto bad_arg;
9137 }
9138
9139 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9140
9141 string = rb_sym2str(symbol);
9142 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9143 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9144 }
9145 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9146 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9147 }
9148 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9149 iseq_set_use_block(iseq);
9150 }
9151 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9152 // Let the iseq act like a C method in backtraces
9153 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9154 }
9155 else {
9156 goto unknown_arg;
9157 }
9158 node = next;
9159 }
9160 return COMPILE_OK;
9161 no_arg:
9162 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9163 return COMPILE_NG;
9164 non_symbol_arg:
9165 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9166 return COMPILE_NG;
9167 unknown_arg:
9168 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9169 return COMPILE_NG;
9170 bad_arg:
9171 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9172}
9173
9174static int
9175compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9176{
9177 VALUE name;
9178
9179 if (!node) goto no_arg;
9180 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9181 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9182 node = RNODE_LIST(node)->nd_head;
9183 if (!node) goto no_arg;
9184 switch (nd_type(node)) {
9185 case NODE_SYM:
9186 name = rb_node_sym_string_val(node);
9187 break;
9188 default:
9189 goto bad_arg;
9190 }
9191 if (!SYMBOL_P(name)) goto non_symbol_arg;
9192 if (!popped) {
9193 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9194 }
9195 return COMPILE_OK;
9196 no_arg:
9197 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9198 return COMPILE_NG;
9199 too_many_arg:
9200 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9201 return COMPILE_NG;
9202 non_symbol_arg:
9203 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9204 rb_builtin_class_name(name));
9205 return COMPILE_NG;
9206 bad_arg:
9207 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9208}
9209
9210static NODE *
9211mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9212{
9213 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9214 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9215 return RNODE_IF(node)->nd_body;
9216 }
9217 else {
9218 rb_bug("mandatory_node: can't find mandatory node");
9219 }
9220}
9221
9222static int
9223compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9224{
9225 // arguments
9226 struct rb_args_info args = {
9227 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9228 };
9229 rb_node_args_t args_node;
9230 rb_node_init(RNODE(&args_node), NODE_ARGS);
9231 args_node.nd_ainfo = args;
9232
9233 // local table without non-mandatory parameters
9234 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9235 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9236
9237 VALUE idtmp = 0;
9238 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9239 tbl->size = table_size;
9240
9241 int i;
9242
9243 // lead parameters
9244 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9245 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9246 }
9247 // local variables
9248 for (; i<table_size; i++) {
9249 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9250 }
9251
9252 rb_node_scope_t scope_node;
9253 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9254 scope_node.nd_tbl = tbl;
9255 scope_node.nd_body = mandatory_node(iseq, node);
9256 scope_node.nd_args = &args_node;
9257
9258 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9259
9260 ISEQ_BODY(iseq)->mandatory_only_iseq =
9261 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9262 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9263 nd_line(line_node), NULL, 0,
9264 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9265 ISEQ_BODY(iseq)->variable.script_lines);
9266
9267 ALLOCV_END(idtmp);
9268 return COMPILE_OK;
9269}
9270
9271static int
9272compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9273 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9274{
9275 NODE *args_node = get_nd_args(node);
9276
9277 if (parent_block != NULL) {
9278 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9279 return COMPILE_NG;
9280 }
9281 else {
9282# define BUILTIN_INLINE_PREFIX "_bi"
9283 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9284 bool cconst = false;
9285 retry:;
9286 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9287
9288 if (bf == NULL) {
9289 if (strcmp("cstmt!", builtin_func) == 0 ||
9290 strcmp("cexpr!", builtin_func) == 0) {
9291 // ok
9292 }
9293 else if (strcmp("cconst!", builtin_func) == 0) {
9294 cconst = true;
9295 }
9296 else if (strcmp("cinit!", builtin_func) == 0) {
9297 // ignore
9298 return COMPILE_OK;
9299 }
9300 else if (strcmp("attr!", builtin_func) == 0) {
9301 return compile_builtin_attr(iseq, args_node);
9302 }
9303 else if (strcmp("arg!", builtin_func) == 0) {
9304 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9305 }
9306 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9307 if (popped) {
9308 rb_bug("mandatory_only? should be in if condition");
9309 }
9310 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9311 rb_bug("mandatory_only? should be put on top");
9312 }
9313
9314 ADD_INSN1(ret, line_node, putobject, Qfalse);
9315 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9316 }
9317 else if (1) {
9318 rb_bug("can't find builtin function:%s", builtin_func);
9319 }
9320 else {
9321 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9322 return COMPILE_NG;
9323 }
9324
9325 int inline_index = nd_line(node);
9326 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9327 builtin_func = inline_func;
9328 args_node = NULL;
9329 goto retry;
9330 }
9331
9332 if (cconst) {
9333 typedef VALUE(*builtin_func0)(void *, VALUE);
9334 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9335 ADD_INSN1(ret, line_node, putobject, const_val);
9336 return COMPILE_OK;
9337 }
9338
9339 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9340
9341 unsigned int flag = 0;
9342 struct rb_callinfo_kwarg *keywords = NULL;
9343 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9344
9345 if (FIX2INT(argc) != bf->argc) {
9346 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9347 builtin_func, bf->argc, FIX2INT(argc));
9348 return COMPILE_NG;
9349 }
9350
9351 unsigned int start_index;
9352 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9353 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9354 }
9355 else {
9356 ADD_SEQ(ret, args);
9357 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9358 }
9359
9360 if (popped) ADD_INSN(ret, line_node, pop);
9361 return COMPILE_OK;
9362 }
9363}
9364
9365static int
9366compile_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)
9367{
9368 /* call: obj.method(...)
9369 * fcall: func(...)
9370 * vcall: func
9371 */
9372 DECL_ANCHOR(recv);
9373 DECL_ANCHOR(args);
9374 ID mid = get_node_call_nd_mid(node);
9375 VALUE argc;
9376 unsigned int flag = 0;
9377 struct rb_callinfo_kwarg *keywords = NULL;
9378 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9379 LABEL *else_label = NULL;
9380 VALUE branches = Qfalse;
9381
9382 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9383
9384 INIT_ANCHOR(recv);
9385 INIT_ANCHOR(args);
9386
9387#if OPT_SUPPORT_JOKE
9388 if (nd_type_p(node, NODE_VCALL)) {
9389 ID id_bitblt;
9390 ID id_answer;
9391
9392 CONST_ID(id_bitblt, "bitblt");
9393 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9394
9395 if (mid == id_bitblt) {
9396 ADD_INSN(ret, line_node, bitblt);
9397 return COMPILE_OK;
9398 }
9399 else if (mid == id_answer) {
9400 ADD_INSN(ret, line_node, answer);
9401 return COMPILE_OK;
9402 }
9403 }
9404 /* only joke */
9405 {
9406 ID goto_id;
9407 ID label_id;
9408
9409 CONST_ID(goto_id, "__goto__");
9410 CONST_ID(label_id, "__label__");
9411
9412 if (nd_type_p(node, NODE_FCALL) &&
9413 (mid == goto_id || mid == label_id)) {
9414 LABEL *label;
9415 st_data_t data;
9416 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9417 VALUE label_name;
9418
9419 if (!labels_table) {
9420 labels_table = st_init_numtable();
9421 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9422 }
9423 {
9424 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9425 return COMPILE_NG;
9426 }
9427
9428 if (mid == goto_id) {
9429 ADD_INSNL(ret, line_node, jump, label);
9430 }
9431 else {
9432 ADD_LABEL(ret, label);
9433 }
9434 return COMPILE_OK;
9435 }
9436 }
9437#endif
9438
9439 const char *builtin_func;
9440 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9441 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9442 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9443 }
9444
9445 /* receiver */
9446 if (!assume_receiver) {
9447 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9448 int idx, level;
9449
9450 if (mid == idCall &&
9451 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9452 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9453 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9454 }
9455 else if (private_recv_p(node)) {
9456 ADD_INSN(recv, node, putself);
9457 flag |= VM_CALL_FCALL;
9458 }
9459 else {
9460 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9461 }
9462
9463 if (type == NODE_QCALL) {
9464 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9465 }
9466 }
9467 else if (type == NODE_FCALL || type == NODE_VCALL) {
9468 ADD_CALL_RECEIVER(recv, line_node);
9469 }
9470 }
9471
9472 /* args */
9473 if (type != NODE_VCALL) {
9474 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9475 CHECK(!NIL_P(argc));
9476 }
9477 else {
9478 argc = INT2FIX(0);
9479 }
9480
9481 ADD_SEQ(ret, recv);
9482
9483 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9484 mid == rb_intern("new") &&
9485 parent_block == NULL &&
9486 !(flag & VM_CALL_ARGS_BLOCKARG);
9487
9488 if (inline_new) {
9489 ADD_INSN(ret, node, putnil);
9490 ADD_INSN(ret, node, swap);
9491 }
9492
9493 ADD_SEQ(ret, args);
9494
9495 debugp_param("call args argc", argc);
9496 debugp_param("call method", ID2SYM(mid));
9497
9498 switch ((int)type) {
9499 case NODE_VCALL:
9500 flag |= VM_CALL_VCALL;
9501 /* VCALL is funcall, so fall through */
9502 case NODE_FCALL:
9503 flag |= VM_CALL_FCALL;
9504 }
9505
9506 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9507 ADD_INSN(ret, line_node, splatkw);
9508 }
9509
9510 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9511 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9512
9513 if (inline_new) {
9514 // Jump unless the receiver uses the "basic" implementation of "new"
9515 VALUE ci;
9516 if (flag & VM_CALL_FORWARDING) {
9517 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9518 }
9519 else {
9520 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9521 }
9522 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9523 LABEL_REF(not_basic_new);
9524
9525 // optimized path
9526 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9527 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9528
9529 ADD_LABEL(ret, not_basic_new);
9530 // Fall back to normal send
9531 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9532 ADD_INSN(ret, line_node, swap);
9533
9534 ADD_LABEL(ret, not_basic_new_finish);
9535 ADD_INSN(ret, line_node, pop);
9536 }
9537 else {
9538 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9539 }
9540
9541 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9542 if (popped) {
9543 ADD_INSN(ret, line_node, pop);
9544 }
9545 return COMPILE_OK;
9546}
9547
9548static int
9549compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9550{
9551 const int line = nd_line(node);
9552 VALUE argc;
9553 unsigned int flag = 0;
9554 int asgnflag = 0;
9555 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9556
9557 /*
9558 * a[x] (op)= y
9559 *
9560 * nil # nil
9561 * eval a # nil a
9562 * eval x # nil a x
9563 * dupn 2 # nil a x a x
9564 * send :[] # nil a x a[x]
9565 * eval y # nil a x a[x] y
9566 * send op # nil a x ret
9567 * setn 3 # ret a x ret
9568 * send []= # ret ?
9569 * pop # ret
9570 */
9571
9572 /*
9573 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9574 * NODE_OP_ASGN nd_recv
9575 * nd_args->nd_head
9576 * nd_args->nd_body
9577 * nd_mid
9578 */
9579
9580 if (!popped) {
9581 ADD_INSN(ret, node, putnil);
9582 }
9583 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9584 CHECK(asgnflag != -1);
9585 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9586 case NODE_ZLIST:
9587 argc = INT2FIX(0);
9588 break;
9589 default:
9590 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9591 CHECK(!NIL_P(argc));
9592 }
9593 int dup_argn = FIX2INT(argc) + 1;
9594 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9595 flag |= asgnflag;
9596 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9597
9598 if (id == idOROP || id == idANDOP) {
9599 /* a[x] ||= y or a[x] &&= y
9600
9601 unless/if a[x]
9602 a[x]= y
9603 else
9604 nil
9605 end
9606 */
9607 LABEL *label = NEW_LABEL(line);
9608 LABEL *lfin = NEW_LABEL(line);
9609
9610 ADD_INSN(ret, node, dup);
9611 if (id == idOROP) {
9612 ADD_INSNL(ret, node, branchif, label);
9613 }
9614 else { /* idANDOP */
9615 ADD_INSNL(ret, node, branchunless, label);
9616 }
9617 ADD_INSN(ret, node, pop);
9618
9619 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9620 if (!popped) {
9621 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9622 }
9623 if (flag & VM_CALL_ARGS_SPLAT) {
9624 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9625 ADD_INSN(ret, node, swap);
9626 ADD_INSN1(ret, node, splatarray, Qtrue);
9627 ADD_INSN(ret, node, swap);
9628 flag |= VM_CALL_ARGS_SPLAT_MUT;
9629 }
9630 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9631 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9632 }
9633 else {
9634 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9635 }
9636 ADD_INSN(ret, node, pop);
9637 ADD_INSNL(ret, node, jump, lfin);
9638 ADD_LABEL(ret, label);
9639 if (!popped) {
9640 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9641 }
9642 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9643 ADD_LABEL(ret, lfin);
9644 }
9645 else {
9646 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9647 ADD_SEND(ret, node, id, INT2FIX(1));
9648 if (!popped) {
9649 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9650 }
9651 if (flag & VM_CALL_ARGS_SPLAT) {
9652 if (flag & VM_CALL_KW_SPLAT) {
9653 ADD_INSN1(ret, node, topn, INT2FIX(2));
9654 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9655 ADD_INSN1(ret, node, splatarray, Qtrue);
9656 flag |= VM_CALL_ARGS_SPLAT_MUT;
9657 }
9658 ADD_INSN(ret, node, swap);
9659 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9660 ADD_INSN1(ret, node, setn, INT2FIX(2));
9661 ADD_INSN(ret, node, pop);
9662 }
9663 else {
9664 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9665 ADD_INSN(ret, node, swap);
9666 ADD_INSN1(ret, node, splatarray, Qtrue);
9667 ADD_INSN(ret, node, swap);
9668 flag |= VM_CALL_ARGS_SPLAT_MUT;
9669 }
9670 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9671 }
9672 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9673 }
9674 else {
9675 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9676 }
9677 ADD_INSN(ret, node, pop);
9678 }
9679 return COMPILE_OK;
9680}
9681
9682static int
9683compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9684{
9685 const int line = nd_line(node);
9686 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9687 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9688 int asgnflag;
9689 LABEL *lfin = NEW_LABEL(line);
9690 LABEL *lcfin = NEW_LABEL(line);
9691 LABEL *lskip = 0;
9692 /*
9693 class C; attr_accessor :c; end
9694 r = C.new
9695 r.a &&= v # asgn2
9696
9697 eval r # r
9698 dup # r r
9699 eval r.a # r o
9700
9701 # or
9702 dup # r o o
9703 if lcfin # r o
9704 pop # r
9705 eval v # r v
9706 swap # v r
9707 topn 1 # v r v
9708 send a= # v ?
9709 jump lfin # v ?
9710
9711 lcfin: # r o
9712 swap # o r
9713
9714 lfin: # o ?
9715 pop # o
9716
9717 # or (popped)
9718 if lcfin # r
9719 eval v # r v
9720 send a= # ?
9721 jump lfin # ?
9722
9723 lcfin: # r
9724
9725 lfin: # ?
9726 pop #
9727
9728 # and
9729 dup # r o o
9730 unless lcfin
9731 pop # r
9732 eval v # r v
9733 swap # v r
9734 topn 1 # v r v
9735 send a= # v ?
9736 jump lfin # v ?
9737
9738 # others
9739 eval v # r o v
9740 send ?? # r w
9741 send a= # w
9742
9743 */
9744
9745 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9746 CHECK(asgnflag != -1);
9747 if (RNODE_OP_ASGN2(node)->nd_aid) {
9748 lskip = NEW_LABEL(line);
9749 ADD_INSN(ret, node, dup);
9750 ADD_INSNL(ret, node, branchnil, lskip);
9751 }
9752 ADD_INSN(ret, node, dup);
9753 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9754
9755 if (atype == idOROP || atype == idANDOP) {
9756 if (!popped) {
9757 ADD_INSN(ret, node, dup);
9758 }
9759 if (atype == idOROP) {
9760 ADD_INSNL(ret, node, branchif, lcfin);
9761 }
9762 else { /* idANDOP */
9763 ADD_INSNL(ret, node, branchunless, lcfin);
9764 }
9765 if (!popped) {
9766 ADD_INSN(ret, node, pop);
9767 }
9768 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9769 if (!popped) {
9770 ADD_INSN(ret, node, swap);
9771 ADD_INSN1(ret, node, topn, INT2FIX(1));
9772 }
9773 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9774 ADD_INSNL(ret, node, jump, lfin);
9775
9776 ADD_LABEL(ret, lcfin);
9777 if (!popped) {
9778 ADD_INSN(ret, node, swap);
9779 }
9780
9781 ADD_LABEL(ret, lfin);
9782 }
9783 else {
9784 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9785 ADD_SEND(ret, node, atype, INT2FIX(1));
9786 if (!popped) {
9787 ADD_INSN(ret, node, swap);
9788 ADD_INSN1(ret, node, topn, INT2FIX(1));
9789 }
9790 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9791 }
9792 if (lskip && popped) {
9793 ADD_LABEL(ret, lskip);
9794 }
9795 ADD_INSN(ret, node, pop);
9796 if (lskip && !popped) {
9797 ADD_LABEL(ret, lskip);
9798 }
9799 return COMPILE_OK;
9800}
9801
9802static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9803
9804static int
9805compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9806{
9807 const int line = nd_line(node);
9808 LABEL *lfin = 0;
9809 LABEL *lassign = 0;
9810 ID mid;
9811
9812 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9813 case NODE_COLON3:
9814 ADD_INSN1(ret, node, putobject, rb_cObject);
9815 break;
9816 case NODE_COLON2:
9817 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9818 break;
9819 default:
9820 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9821 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9822 return COMPILE_NG;
9823 }
9824 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9825 /* cref */
9826 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9827 lassign = NEW_LABEL(line);
9828 ADD_INSN(ret, node, dup); /* cref cref */
9829 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9830 ID2SYM(mid), Qtrue); /* cref bool */
9831 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9832 }
9833 ADD_INSN(ret, node, dup); /* cref cref */
9834 ADD_INSN1(ret, node, putobject, Qtrue);
9835 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9836
9837 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9838 lfin = NEW_LABEL(line);
9839 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9840 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9841 ADD_INSNL(ret, node, branchif, lfin);
9842 else /* idANDOP */
9843 ADD_INSNL(ret, node, branchunless, lfin);
9844 /* cref [obj] */
9845 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9846 if (lassign) ADD_LABEL(ret, lassign);
9847 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9848 /* cref value */
9849 if (popped)
9850 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9851 else {
9852 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9853 ADD_INSN(ret, node, swap); /* cref value value cref */
9854 }
9855 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9856 ADD_LABEL(ret, lfin); /* cref [value] */
9857 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9858 ADD_INSN(ret, node, pop); /* [value] */
9859 }
9860 else {
9861 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9862 /* cref obj value */
9863 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9864 /* cref value */
9865 ADD_INSN(ret, node, swap); /* value cref */
9866 if (!popped) {
9867 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9868 ADD_INSN(ret, node, swap); /* value value cref */
9869 }
9870 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9871 }
9872 return COMPILE_OK;
9873}
9874
9875static int
9876compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9877{
9878 const int line = nd_line(node);
9879 LABEL *lfin = NEW_LABEL(line);
9880 LABEL *lassign;
9881
9882 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9883 LABEL *lfinish[2];
9884 lfinish[0] = lfin;
9885 lfinish[1] = 0;
9886 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9887 lassign = lfinish[1];
9888 if (!lassign) {
9889 lassign = NEW_LABEL(line);
9890 }
9891 ADD_INSNL(ret, node, branchunless, lassign);
9892 }
9893 else {
9894 lassign = NEW_LABEL(line);
9895 }
9896
9897 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9898
9899 if (!popped) {
9900 ADD_INSN(ret, node, dup);
9901 }
9902
9903 if (type == NODE_OP_ASGN_AND) {
9904 ADD_INSNL(ret, node, branchunless, lfin);
9905 }
9906 else {
9907 ADD_INSNL(ret, node, branchif, lfin);
9908 }
9909
9910 if (!popped) {
9911 ADD_INSN(ret, node, pop);
9912 }
9913
9914 ADD_LABEL(ret, lassign);
9915 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9916 ADD_LABEL(ret, lfin);
9917 return COMPILE_OK;
9918}
9919
9920static int
9921compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9922{
9923 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9924 DECL_ANCHOR(args);
9925 int argc;
9926 unsigned int flag = 0;
9927 struct rb_callinfo_kwarg *keywords = NULL;
9928 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9929 int use_block = 1;
9930
9931 INIT_ANCHOR(args);
9932 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9933
9934 if (type == NODE_SUPER) {
9935 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9936 CHECK(!NIL_P(vargc));
9937 argc = FIX2INT(vargc);
9938 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9939 ADD_INSN(args, node, splatkw);
9940 }
9941
9942 if (flag & VM_CALL_ARGS_BLOCKARG) {
9943 use_block = 0;
9944 }
9945 }
9946 else {
9947 /* NODE_ZSUPER */
9948 int i;
9949 const rb_iseq_t *liseq = body->local_iseq;
9950 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9951 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9952 int lvar_level = get_lvar_level(iseq);
9953
9954 argc = local_body->param.lead_num;
9955
9956 /* normal arguments */
9957 for (i = 0; i < local_body->param.lead_num; i++) {
9958 int idx = local_body->local_table_size - i;
9959 ADD_GETLOCAL(args, node, idx, lvar_level);
9960 }
9961
9962 /* forward ... */
9963 if (local_body->param.flags.forwardable) {
9964 flag |= VM_CALL_FORWARDING;
9965 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9966 ADD_GETLOCAL(args, node, idx, lvar_level);
9967 }
9968
9969 if (local_body->param.flags.has_opt) {
9970 /* optional arguments */
9971 int j;
9972 for (j = 0; j < local_body->param.opt_num; j++) {
9973 int idx = local_body->local_table_size - (i + j);
9974 ADD_GETLOCAL(args, node, idx, lvar_level);
9975 }
9976 i += j;
9977 argc = i;
9978 }
9979 if (local_body->param.flags.has_rest) {
9980 /* rest argument */
9981 int idx = local_body->local_table_size - local_body->param.rest_start;
9982 ADD_GETLOCAL(args, node, idx, lvar_level);
9983 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9984
9985 argc = local_body->param.rest_start + 1;
9986 flag |= VM_CALL_ARGS_SPLAT;
9987 }
9988 if (local_body->param.flags.has_post) {
9989 /* post arguments */
9990 int post_len = local_body->param.post_num;
9991 int post_start = local_body->param.post_start;
9992
9993 if (local_body->param.flags.has_rest) {
9994 int j;
9995 for (j=0; j<post_len; j++) {
9996 int idx = local_body->local_table_size - (post_start + j);
9997 ADD_GETLOCAL(args, node, idx, lvar_level);
9998 }
9999 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10000 flag |= VM_CALL_ARGS_SPLAT_MUT;
10001 /* argc is settled at above */
10002 }
10003 else {
10004 int j;
10005 for (j=0; j<post_len; j++) {
10006 int idx = local_body->local_table_size - (post_start + j);
10007 ADD_GETLOCAL(args, node, idx, lvar_level);
10008 }
10009 argc = post_len + post_start;
10010 }
10011 }
10012
10013 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10014 int local_size = local_body->local_table_size;
10015 argc++;
10016
10017 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10018
10019 if (local_body->param.flags.has_kwrest) {
10020 int idx = local_body->local_table_size - local_kwd->rest_start;
10021 ADD_GETLOCAL(args, node, idx, lvar_level);
10022 RUBY_ASSERT(local_kwd->num > 0);
10023 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10024 }
10025 else {
10026 ADD_INSN1(args, node, newhash, INT2FIX(0));
10027 }
10028 for (i = 0; i < local_kwd->num; ++i) {
10029 ID id = local_kwd->table[i];
10030 int idx = local_size - get_local_var_idx(liseq, id);
10031 ADD_INSN1(args, node, putobject, ID2SYM(id));
10032 ADD_GETLOCAL(args, node, idx, lvar_level);
10033 }
10034 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10035 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10036 }
10037 else if (local_body->param.flags.has_kwrest) {
10038 int idx = local_body->local_table_size - local_kwd->rest_start;
10039 ADD_GETLOCAL(args, node, idx, lvar_level);
10040 argc++;
10041 flag |= VM_CALL_KW_SPLAT;
10042 }
10043 }
10044
10045 if (use_block && parent_block == NULL) {
10046 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10047 }
10048
10049 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10050 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10051 ADD_INSN(ret, node, putself);
10052 ADD_SEQ(ret, args);
10053
10054 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10055
10056 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10057 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10058 }
10059 else {
10060 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10061 }
10062
10063 if (popped) {
10064 ADD_INSN(ret, node, pop);
10065 }
10066 return COMPILE_OK;
10067}
10068
10069static int
10070compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10071{
10072 DECL_ANCHOR(args);
10073 VALUE argc;
10074 unsigned int flag = 0;
10075 struct rb_callinfo_kwarg *keywords = NULL;
10076
10077 INIT_ANCHOR(args);
10078
10079 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10080 case ISEQ_TYPE_TOP:
10081 case ISEQ_TYPE_MAIN:
10082 case ISEQ_TYPE_CLASS:
10083 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10084 return COMPILE_NG;
10085 default: /* valid */;
10086 }
10087
10088 if (RNODE_YIELD(node)->nd_head) {
10089 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10090 CHECK(!NIL_P(argc));
10091 }
10092 else {
10093 argc = INT2FIX(0);
10094 }
10095
10096 ADD_SEQ(ret, args);
10097 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10098 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10099
10100 if (popped) {
10101 ADD_INSN(ret, node, pop);
10102 }
10103
10104 int level = 0;
10105 const rb_iseq_t *tmp_iseq = iseq;
10106 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10107 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10108 }
10109 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10110
10111 return COMPILE_OK;
10112}
10113
10114static int
10115compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10116{
10117 DECL_ANCHOR(recv);
10118 DECL_ANCHOR(val);
10119
10120 INIT_ANCHOR(recv);
10121 INIT_ANCHOR(val);
10122 switch ((int)type) {
10123 case NODE_MATCH:
10124 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10125 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10126 INT2FIX(0));
10127 break;
10128 case NODE_MATCH2:
10129 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10130 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10131 break;
10132 case NODE_MATCH3:
10133 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10134 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10135 break;
10136 }
10137
10138 ADD_SEQ(ret, recv);
10139 ADD_SEQ(ret, val);
10140 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10141
10142 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10143 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10144 }
10145
10146 if (popped) {
10147 ADD_INSN(ret, node, pop);
10148 }
10149 return COMPILE_OK;
10150}
10151
10152static int
10153compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10154{
10155 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10156 /* constant */
10157 VALUE segments;
10158 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10159 (segments = collect_const_segments(iseq, node))) {
10160 ISEQ_BODY(iseq)->ic_size++;
10161 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10162 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10163 }
10164 else {
10165 /* constant */
10166 DECL_ANCHOR(pref);
10167 DECL_ANCHOR(body);
10168
10169 INIT_ANCHOR(pref);
10170 INIT_ANCHOR(body);
10171 CHECK(compile_const_prefix(iseq, node, pref, body));
10172 if (LIST_INSN_SIZE_ZERO(pref)) {
10173 ADD_INSN(ret, node, putnil);
10174 ADD_SEQ(ret, body);
10175 }
10176 else {
10177 ADD_SEQ(ret, pref);
10178 ADD_SEQ(ret, body);
10179 }
10180 }
10181 }
10182 else {
10183 /* function call */
10184 ADD_CALL_RECEIVER(ret, node);
10185 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10186 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10187 }
10188 if (popped) {
10189 ADD_INSN(ret, node, pop);
10190 }
10191 return COMPILE_OK;
10192}
10193
10194static int
10195compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10196{
10197 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10198
10199 /* add cache insn */
10200 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10201 ISEQ_BODY(iseq)->ic_size++;
10202 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10203 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10204 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10205 }
10206 else {
10207 ADD_INSN1(ret, node, putobject, rb_cObject);
10208 ADD_INSN1(ret, node, putobject, Qtrue);
10209 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10210 }
10211
10212 if (popped) {
10213 ADD_INSN(ret, node, pop);
10214 }
10215 return COMPILE_OK;
10216}
10217
10218static int
10219compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10220{
10221 VALUE flag = INT2FIX(excl);
10222 const NODE *b = RNODE_DOT2(node)->nd_beg;
10223 const NODE *e = RNODE_DOT2(node)->nd_end;
10224
10225 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10226 if (!popped) {
10227 VALUE bv = optimized_range_item(b);
10228 VALUE ev = optimized_range_item(e);
10229 VALUE val = rb_range_new(bv, ev, excl);
10230 ADD_INSN1(ret, node, putobject, val);
10231 RB_OBJ_WRITTEN(iseq, Qundef, val);
10232 }
10233 }
10234 else {
10235 CHECK(COMPILE_(ret, "min", b, popped));
10236 CHECK(COMPILE_(ret, "max", e, popped));
10237 if (!popped) {
10238 ADD_INSN1(ret, node, newrange, flag);
10239 }
10240 }
10241 return COMPILE_OK;
10242}
10243
10244static int
10245compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10246{
10247 if (!popped) {
10248 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10249 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10250 }
10251 else {
10252 const rb_iseq_t *ip = iseq;
10253 int level = 0;
10254 while (ip) {
10255 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10256 break;
10257 }
10258 ip = ISEQ_BODY(ip)->parent_iseq;
10259 level++;
10260 }
10261 if (ip) {
10262 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10263 }
10264 else {
10265 ADD_INSN(ret, node, putnil);
10266 }
10267 }
10268 }
10269 return COMPILE_OK;
10270}
10271
10272static int
10273compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10274{
10275 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10276 LABEL *end_label = NEW_LABEL(nd_line(node));
10277 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10278
10279 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10280 /* required argument. do nothing */
10281 COMPILE_ERROR(ERROR_ARGS "unreachable");
10282 return COMPILE_NG;
10283 }
10284 else if (nd_type_p(default_value, NODE_SYM) ||
10285 nd_type_p(default_value, NODE_REGX) ||
10286 nd_type_p(default_value, NODE_LINE) ||
10287 nd_type_p(default_value, NODE_INTEGER) ||
10288 nd_type_p(default_value, NODE_FLOAT) ||
10289 nd_type_p(default_value, NODE_RATIONAL) ||
10290 nd_type_p(default_value, NODE_IMAGINARY) ||
10291 nd_type_p(default_value, NODE_NIL) ||
10292 nd_type_p(default_value, NODE_TRUE) ||
10293 nd_type_p(default_value, NODE_FALSE)) {
10294 COMPILE_ERROR(ERROR_ARGS "unreachable");
10295 return COMPILE_NG;
10296 }
10297 else {
10298 /* if keywordcheck(_kw_bits, nth_keyword)
10299 * kw = default_value
10300 * end
10301 */
10302 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10303 int keyword_idx = body->param.keyword->num;
10304
10305 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10306 ADD_INSNL(ret, node, branchif, end_label);
10307 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10308 ADD_LABEL(ret, end_label);
10309 }
10310 return COMPILE_OK;
10311}
10312
10313static int
10314compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10315{
10316 DECL_ANCHOR(recv);
10317 DECL_ANCHOR(args);
10318 unsigned int flag = 0;
10319 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10320 VALUE argc;
10321 LABEL *else_label = NULL;
10322 VALUE branches = Qfalse;
10323
10324 /* optimization shortcut
10325 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10326 */
10327 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10328 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10329 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10330 (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)) &&
10331 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10332 !frozen_string_literal_p(iseq) &&
10333 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10334 {
10335 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10336 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10337 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10338 if (!popped) {
10339 ADD_INSN(ret, node, swap);
10340 ADD_INSN1(ret, node, topn, INT2FIX(1));
10341 }
10342 ADD_INSN2(ret, node, opt_aset_with, str,
10343 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10344 RB_OBJ_WRITTEN(iseq, Qundef, str);
10345 ADD_INSN(ret, node, pop);
10346 return COMPILE_OK;
10347 }
10348
10349 INIT_ANCHOR(recv);
10350 INIT_ANCHOR(args);
10351 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10352 CHECK(!NIL_P(argc));
10353
10354 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10355 CHECK(asgnflag != -1);
10356 flag |= (unsigned int)asgnflag;
10357
10358 debugp_param("argc", argc);
10359 debugp_param("nd_mid", ID2SYM(mid));
10360
10361 if (!rb_is_attrset_id(mid)) {
10362 /* safe nav attr */
10363 mid = rb_id_attrset(mid);
10364 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10365 }
10366 if (!popped) {
10367 ADD_INSN(ret, node, putnil);
10368 ADD_SEQ(ret, recv);
10369 ADD_SEQ(ret, args);
10370
10371 if (flag & VM_CALL_ARGS_SPLAT) {
10372 ADD_INSN(ret, node, dup);
10373 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10374 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10375 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10376 ADD_INSN (ret, node, pop);
10377 }
10378 else {
10379 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10380 }
10381 }
10382 else {
10383 ADD_SEQ(ret, recv);
10384 ADD_SEQ(ret, args);
10385 }
10386 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10387 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10388 ADD_INSN(ret, node, pop);
10389 return COMPILE_OK;
10390}
10391
10392static int
10393compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10394{
10395 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10396 ADD_SEQ(ret, sub);
10397
10398 if (copy) {
10399 /*
10400 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10401 * NEW_LIST(value, loc), loc);
10402 */
10403 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10404 }
10405 else {
10406 /*
10407 * NEW_CALL(fcore, rb_intern("make_shareable"),
10408 * NEW_LIST(value, loc), loc);
10409 */
10410 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10411 }
10412
10413 return COMPILE_OK;
10414}
10415
10416static VALUE
10417node_const_decl_val(const NODE *node)
10418{
10419 VALUE path;
10420 switch (nd_type(node)) {
10421 case NODE_CDECL:
10422 if (RNODE_CDECL(node)->nd_vid) {
10423 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10424 goto end;
10425 }
10426 else {
10427 node = RNODE_CDECL(node)->nd_else;
10428 }
10429 break;
10430 case NODE_COLON2:
10431 break;
10432 case NODE_COLON3:
10433 // ::Const
10434 path = rb_str_new_cstr("::");
10435 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10436 goto end;
10437 default:
10438 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10440 }
10441
10442 path = rb_ary_new();
10443 if (node) {
10444 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10445 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10446 }
10447 if (node && nd_type_p(node, NODE_CONST)) {
10448 // Const::Name
10449 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10450 }
10451 else if (node && nd_type_p(node, NODE_COLON3)) {
10452 // ::Const::Name
10453 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10454 rb_ary_push(path, rb_str_new(0, 0));
10455 }
10456 else {
10457 // expression::Name
10458 rb_ary_push(path, rb_str_new_cstr("..."));
10459 }
10460 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10461 }
10462 end:
10463 path = rb_fstring(path);
10464 return path;
10465}
10466
10467static VALUE
10468const_decl_path(NODE *dest)
10469{
10470 VALUE path = Qnil;
10471 if (!nd_type_p(dest, NODE_CALL)) {
10472 path = node_const_decl_val(dest);
10473 }
10474 return path;
10475}
10476
10477static int
10478compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10479{
10480 /*
10481 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10482 */
10483 VALUE path = const_decl_path(dest);
10484 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10485 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10486 ADD_INSN1(ret, value, putobject, path);
10487 RB_OBJ_WRITTEN(iseq, Qundef, path);
10488 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10489
10490 return COMPILE_OK;
10491}
10492
10493#ifndef SHAREABLE_BARE_EXPRESSION
10494#define SHAREABLE_BARE_EXPRESSION 1
10495#endif
10496
10497static int
10498compile_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)
10499{
10500# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10501 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10502 VALUE lit = Qnil;
10503 DECL_ANCHOR(anchor);
10504
10505 enum node_type type = node ? nd_type(node) : NODE_NIL;
10506 switch (type) {
10507 case NODE_TRUE:
10508 *value_p = Qtrue;
10509 goto compile;
10510 case NODE_FALSE:
10511 *value_p = Qfalse;
10512 goto compile;
10513 case NODE_NIL:
10514 *value_p = Qnil;
10515 goto compile;
10516 case NODE_SYM:
10517 *value_p = rb_node_sym_string_val(node);
10518 goto compile;
10519 case NODE_REGX:
10520 *value_p = rb_node_regx_string_val(node);
10521 goto compile;
10522 case NODE_LINE:
10523 *value_p = rb_node_line_lineno_val(node);
10524 goto compile;
10525 case NODE_INTEGER:
10526 *value_p = rb_node_integer_literal_val(node);
10527 goto compile;
10528 case NODE_FLOAT:
10529 *value_p = rb_node_float_literal_val(node);
10530 goto compile;
10531 case NODE_RATIONAL:
10532 *value_p = rb_node_rational_literal_val(node);
10533 goto compile;
10534 case NODE_IMAGINARY:
10535 *value_p = rb_node_imaginary_literal_val(node);
10536 goto compile;
10537 case NODE_ENCODING:
10538 *value_p = rb_node_encoding_val(node);
10539
10540 compile:
10541 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10542 *shareable_literal_p = 1;
10543 return COMPILE_OK;
10544
10545 case NODE_DSTR:
10546 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10547 if (shareable == rb_parser_shareable_literal) {
10548 /*
10549 * NEW_CALL(node, idUMinus, 0, loc);
10550 *
10551 * -"#{var}"
10552 */
10553 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10554 }
10555 *value_p = Qundef;
10556 *shareable_literal_p = 1;
10557 return COMPILE_OK;
10558
10559 case NODE_STR:{
10560 VALUE lit = rb_node_str_string_val(node);
10561 ADD_INSN1(ret, node, putobject, lit);
10562 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10563 *value_p = lit;
10564 *shareable_literal_p = 1;
10565
10566 return COMPILE_OK;
10567 }
10568
10569 case NODE_FILE:{
10570 VALUE lit = rb_node_file_path_val(node);
10571 ADD_INSN1(ret, node, putobject, lit);
10572 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10573 *value_p = lit;
10574 *shareable_literal_p = 1;
10575
10576 return COMPILE_OK;
10577 }
10578
10579 case NODE_ZLIST:{
10580 VALUE lit = rb_ary_new();
10581 OBJ_FREEZE(lit);
10582 ADD_INSN1(ret, node, putobject, lit);
10583 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10584 *value_p = lit;
10585 *shareable_literal_p = 1;
10586
10587 return COMPILE_OK;
10588 }
10589
10590 case NODE_LIST:{
10591 INIT_ANCHOR(anchor);
10592 lit = rb_ary_new();
10593 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10594 VALUE val;
10595 int shareable_literal_p2;
10596 NODE *elt = RNODE_LIST(n)->nd_head;
10597 if (elt) {
10598 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10599 if (shareable_literal_p2) {
10600 /* noop */
10601 }
10602 else if (RTEST(lit)) {
10603 rb_ary_clear(lit);
10604 lit = Qfalse;
10605 }
10606 }
10607 if (RTEST(lit)) {
10608 if (!UNDEF_P(val)) {
10609 rb_ary_push(lit, val);
10610 }
10611 else {
10612 rb_ary_clear(lit);
10613 lit = Qnil; /* make shareable at runtime */
10614 }
10615 }
10616 }
10617 break;
10618 }
10619 case NODE_HASH:{
10620 if (!RNODE_HASH(node)->nd_brace) {
10621 *value_p = Qundef;
10622 *shareable_literal_p = 0;
10623 return COMPILE_OK;
10624 }
10625 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10626 if (!RNODE_LIST(n)->nd_head) {
10627 // If the hash node have a keyword splat, fall back to the default case.
10628 goto compile_shareable;
10629 }
10630 }
10631
10632 INIT_ANCHOR(anchor);
10633 lit = rb_hash_new();
10634 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10635 VALUE key_val = 0;
10636 VALUE value_val = 0;
10637 int shareable_literal_p2;
10638 NODE *key = RNODE_LIST(n)->nd_head;
10639 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10640 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10641 if (shareable_literal_p2) {
10642 /* noop */
10643 }
10644 else if (RTEST(lit)) {
10645 rb_hash_clear(lit);
10646 lit = Qfalse;
10647 }
10648 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10649 if (shareable_literal_p2) {
10650 /* noop */
10651 }
10652 else if (RTEST(lit)) {
10653 rb_hash_clear(lit);
10654 lit = Qfalse;
10655 }
10656 if (RTEST(lit)) {
10657 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10658 rb_hash_aset(lit, key_val, value_val);
10659 }
10660 else {
10661 rb_hash_clear(lit);
10662 lit = Qnil; /* make shareable at runtime */
10663 }
10664 }
10665 }
10666 break;
10667 }
10668
10669 default:
10670
10671 compile_shareable:
10672 if (shareable == rb_parser_shareable_literal &&
10673 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10674 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10675 *value_p = Qundef;
10676 *shareable_literal_p = 1;
10677 return COMPILE_OK;
10678 }
10679 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10680 *value_p = Qundef;
10681 *shareable_literal_p = 0;
10682 return COMPILE_OK;
10683 }
10684
10685 /* Array or Hash that does not have keyword splat */
10686 if (!lit) {
10687 if (nd_type(node) == NODE_LIST) {
10688 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10689 }
10690 else if (nd_type(node) == NODE_HASH) {
10691 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10692 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10693 }
10694 *value_p = Qundef;
10695 *shareable_literal_p = 0;
10696 ADD_SEQ(ret, anchor);
10697 return COMPILE_OK;
10698 }
10699 if (NIL_P(lit)) {
10700 // if shareable_literal, all elements should have been ensured
10701 // as shareable
10702 if (nd_type(node) == NODE_LIST) {
10703 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10704 }
10705 else if (nd_type(node) == NODE_HASH) {
10706 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10707 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10708 }
10709 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10710 *value_p = Qundef;
10711 *shareable_literal_p = 1;
10712 }
10713 else {
10715 ADD_INSN1(ret, node, putobject, val);
10716 RB_OBJ_WRITTEN(iseq, Qundef, val);
10717 *value_p = val;
10718 *shareable_literal_p = 1;
10719 }
10720
10721 return COMPILE_OK;
10722}
10723
10724static int
10725compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10726{
10727 int literal_p = 0;
10728 VALUE val;
10729 DECL_ANCHOR(anchor);
10730 INIT_ANCHOR(anchor);
10731
10732 switch (shareable) {
10733 case rb_parser_shareable_none:
10734 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10735 return COMPILE_OK;
10736
10737 case rb_parser_shareable_literal:
10738 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10739 ADD_SEQ(ret, anchor);
10740 return COMPILE_OK;
10741
10742 case rb_parser_shareable_copy:
10743 case rb_parser_shareable_everything:
10744 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10745 if (!literal_p) {
10746 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10747 }
10748 else {
10749 ADD_SEQ(ret, anchor);
10750 }
10751 return COMPILE_OK;
10752 default:
10753 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10754 }
10755}
10756
10757static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10765static int
10766iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10767{
10768 if (node == 0) {
10769 if (!popped) {
10770 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10771 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10772 debugs("node: NODE_NIL(implicit)\n");
10773 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10774 }
10775 return COMPILE_OK;
10776 }
10777 return iseq_compile_each0(iseq, ret, node, popped);
10778}
10779
10780static int
10781iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10782{
10783 const int line = (int)nd_line(node);
10784 const enum node_type type = nd_type(node);
10785 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10786
10787 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10788 /* ignore */
10789 }
10790 else {
10791 if (nd_fl_newline(node)) {
10792 int event = RUBY_EVENT_LINE;
10793 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10794 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10795 event |= RUBY_EVENT_COVERAGE_LINE;
10796 }
10797 ADD_TRACE(ret, event);
10798 }
10799 }
10800
10801 debug_node_start(node);
10802#undef BEFORE_RETURN
10803#define BEFORE_RETURN debug_node_end()
10804
10805 switch (type) {
10806 case NODE_BLOCK:
10807 CHECK(compile_block(iseq, ret, node, popped));
10808 break;
10809 case NODE_IF:
10810 case NODE_UNLESS:
10811 CHECK(compile_if(iseq, ret, node, popped, type));
10812 break;
10813 case NODE_CASE:
10814 CHECK(compile_case(iseq, ret, node, popped));
10815 break;
10816 case NODE_CASE2:
10817 CHECK(compile_case2(iseq, ret, node, popped));
10818 break;
10819 case NODE_CASE3:
10820 CHECK(compile_case3(iseq, ret, node, popped));
10821 break;
10822 case NODE_WHILE:
10823 case NODE_UNTIL:
10824 CHECK(compile_loop(iseq, ret, node, popped, type));
10825 break;
10826 case NODE_FOR:
10827 case NODE_ITER:
10828 CHECK(compile_iter(iseq, ret, node, popped));
10829 break;
10830 case NODE_FOR_MASGN:
10831 CHECK(compile_for_masgn(iseq, ret, node, popped));
10832 break;
10833 case NODE_BREAK:
10834 CHECK(compile_break(iseq, ret, node, popped));
10835 break;
10836 case NODE_NEXT:
10837 CHECK(compile_next(iseq, ret, node, popped));
10838 break;
10839 case NODE_REDO:
10840 CHECK(compile_redo(iseq, ret, node, popped));
10841 break;
10842 case NODE_RETRY:
10843 CHECK(compile_retry(iseq, ret, node, popped));
10844 break;
10845 case NODE_BEGIN:{
10846 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10847 break;
10848 }
10849 case NODE_RESCUE:
10850 CHECK(compile_rescue(iseq, ret, node, popped));
10851 break;
10852 case NODE_RESBODY:
10853 CHECK(compile_resbody(iseq, ret, node, popped));
10854 break;
10855 case NODE_ENSURE:
10856 CHECK(compile_ensure(iseq, ret, node, popped));
10857 break;
10858
10859 case NODE_AND:
10860 case NODE_OR:{
10861 LABEL *end_label = NEW_LABEL(line);
10862 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10863 if (!popped) {
10864 ADD_INSN(ret, node, dup);
10865 }
10866 if (type == NODE_AND) {
10867 ADD_INSNL(ret, node, branchunless, end_label);
10868 }
10869 else {
10870 ADD_INSNL(ret, node, branchif, end_label);
10871 }
10872 if (!popped) {
10873 ADD_INSN(ret, node, pop);
10874 }
10875 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10876 ADD_LABEL(ret, end_label);
10877 break;
10878 }
10879
10880 case NODE_MASGN:{
10881 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10882 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10883 compile_massign(iseq, ret, node, popped);
10884 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10885 break;
10886 }
10887
10888 case NODE_LASGN:{
10889 ID id = RNODE_LASGN(node)->nd_vid;
10890 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10891
10892 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10893 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10894
10895 if (!popped) {
10896 ADD_INSN(ret, node, dup);
10897 }
10898 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10899 break;
10900 }
10901 case NODE_DASGN: {
10902 int idx, lv, ls;
10903 ID id = RNODE_DASGN(node)->nd_vid;
10904 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10905 debugi("dassn id", rb_id2str(id) ? id : '*');
10906
10907 if (!popped) {
10908 ADD_INSN(ret, node, dup);
10909 }
10910
10911 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10912
10913 if (idx < 0) {
10914 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10915 rb_id2str(id));
10916 goto ng;
10917 }
10918 ADD_SETLOCAL(ret, node, ls - idx, lv);
10919 break;
10920 }
10921 case NODE_GASGN:{
10922 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10923
10924 if (!popped) {
10925 ADD_INSN(ret, node, dup);
10926 }
10927 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10928 break;
10929 }
10930 case NODE_IASGN:{
10931 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10932 if (!popped) {
10933 ADD_INSN(ret, node, dup);
10934 }
10935 ADD_INSN2(ret, node, setinstancevariable,
10936 ID2SYM(RNODE_IASGN(node)->nd_vid),
10937 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10938 break;
10939 }
10940 case NODE_CDECL:{
10941 if (RNODE_CDECL(node)->nd_vid) {
10942 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10943
10944 if (!popped) {
10945 ADD_INSN(ret, node, dup);
10946 }
10947
10948 ADD_INSN1(ret, node, putspecialobject,
10949 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10950 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10951 }
10952 else {
10953 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10954 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10955 ADD_INSN(ret, node, swap);
10956
10957 if (!popped) {
10958 ADD_INSN1(ret, node, topn, INT2FIX(1));
10959 ADD_INSN(ret, node, swap);
10960 }
10961
10962 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10963 }
10964 break;
10965 }
10966 case NODE_CVASGN:{
10967 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10968 if (!popped) {
10969 ADD_INSN(ret, node, dup);
10970 }
10971 ADD_INSN2(ret, node, setclassvariable,
10972 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10973 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10974 break;
10975 }
10976 case NODE_OP_ASGN1:
10977 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10978 break;
10979 case NODE_OP_ASGN2:
10980 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10981 break;
10982 case NODE_OP_CDECL:
10983 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10984 break;
10985 case NODE_OP_ASGN_AND:
10986 case NODE_OP_ASGN_OR:
10987 CHECK(compile_op_log(iseq, ret, node, popped, type));
10988 break;
10989 case NODE_CALL: /* obj.foo */
10990 case NODE_OPCALL: /* foo[] */
10991 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10992 break;
10993 }
10994 case NODE_QCALL: /* obj&.foo */
10995 case NODE_FCALL: /* foo() */
10996 case NODE_VCALL: /* foo (variable or call) */
10997 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10998 goto ng;
10999 }
11000 break;
11001 case NODE_SUPER:
11002 case NODE_ZSUPER:
11003 CHECK(compile_super(iseq, ret, node, popped, type));
11004 break;
11005 case NODE_LIST:{
11006 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11007 break;
11008 }
11009 case NODE_ZLIST:{
11010 if (!popped) {
11011 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11012 }
11013 break;
11014 }
11015 case NODE_HASH:
11016 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11017 break;
11018 case NODE_RETURN:
11019 CHECK(compile_return(iseq, ret, node, popped));
11020 break;
11021 case NODE_YIELD:
11022 CHECK(compile_yield(iseq, ret, node, popped));
11023 break;
11024 case NODE_LVAR:{
11025 if (!popped) {
11026 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11027 }
11028 break;
11029 }
11030 case NODE_DVAR:{
11031 int lv, idx, ls;
11032 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11033 if (!popped) {
11034 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11035 if (idx < 0) {
11036 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11037 rb_id2str(RNODE_DVAR(node)->nd_vid));
11038 goto ng;
11039 }
11040 ADD_GETLOCAL(ret, node, ls - idx, lv);
11041 }
11042 break;
11043 }
11044 case NODE_GVAR:{
11045 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11046 if (popped) {
11047 ADD_INSN(ret, node, pop);
11048 }
11049 break;
11050 }
11051 case NODE_IVAR:{
11052 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11053 if (!popped) {
11054 ADD_INSN2(ret, node, getinstancevariable,
11055 ID2SYM(RNODE_IVAR(node)->nd_vid),
11056 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11057 }
11058 break;
11059 }
11060 case NODE_CONST:{
11061 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11062
11063 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11064 body->ic_size++;
11065 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11066 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11067 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11068 }
11069 else {
11070 ADD_INSN(ret, node, putnil);
11071 ADD_INSN1(ret, node, putobject, Qtrue);
11072 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11073 }
11074
11075 if (popped) {
11076 ADD_INSN(ret, node, pop);
11077 }
11078 break;
11079 }
11080 case NODE_CVAR:{
11081 if (!popped) {
11082 ADD_INSN2(ret, node, getclassvariable,
11083 ID2SYM(RNODE_CVAR(node)->nd_vid),
11084 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11085 }
11086 break;
11087 }
11088 case NODE_NTH_REF:{
11089 if (!popped) {
11090 if (!RNODE_NTH_REF(node)->nd_nth) {
11091 ADD_INSN(ret, node, putnil);
11092 break;
11093 }
11094 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11095 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11096 }
11097 break;
11098 }
11099 case NODE_BACK_REF:{
11100 if (!popped) {
11101 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11102 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11103 }
11104 break;
11105 }
11106 case NODE_MATCH:
11107 case NODE_MATCH2:
11108 case NODE_MATCH3:
11109 CHECK(compile_match(iseq, ret, node, popped, type));
11110 break;
11111 case NODE_SYM:{
11112 if (!popped) {
11113 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11114 }
11115 break;
11116 }
11117 case NODE_LINE:{
11118 if (!popped) {
11119 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11120 }
11121 break;
11122 }
11123 case NODE_ENCODING:{
11124 if (!popped) {
11125 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11126 }
11127 break;
11128 }
11129 case NODE_INTEGER:{
11130 VALUE lit = rb_node_integer_literal_val(node);
11131 debugp_param("integer", lit);
11132 if (!popped) {
11133 ADD_INSN1(ret, node, putobject, lit);
11134 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11135 }
11136 break;
11137 }
11138 case NODE_FLOAT:{
11139 VALUE lit = rb_node_float_literal_val(node);
11140 debugp_param("float", lit);
11141 if (!popped) {
11142 ADD_INSN1(ret, node, putobject, lit);
11143 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11144 }
11145 break;
11146 }
11147 case NODE_RATIONAL:{
11148 VALUE lit = rb_node_rational_literal_val(node);
11149 debugp_param("rational", lit);
11150 if (!popped) {
11151 ADD_INSN1(ret, node, putobject, lit);
11152 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11153 }
11154 break;
11155 }
11156 case NODE_IMAGINARY:{
11157 VALUE lit = rb_node_imaginary_literal_val(node);
11158 debugp_param("imaginary", lit);
11159 if (!popped) {
11160 ADD_INSN1(ret, node, putobject, lit);
11161 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11162 }
11163 break;
11164 }
11165 case NODE_FILE:
11166 case NODE_STR:{
11167 debugp_param("nd_lit", get_string_value(node));
11168 if (!popped) {
11169 VALUE lit = get_string_value(node);
11170 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11171 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11172 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11173 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11174 }
11175 switch (option->frozen_string_literal) {
11176 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11177 ADD_INSN1(ret, node, putchilledstring, lit);
11178 break;
11179 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11180 ADD_INSN1(ret, node, putstring, lit);
11181 break;
11182 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11183 ADD_INSN1(ret, node, putobject, lit);
11184 break;
11185 default:
11186 rb_bug("invalid frozen_string_literal");
11187 }
11188 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11189 }
11190 break;
11191 }
11192 case NODE_DSTR:{
11193 compile_dstr(iseq, ret, node);
11194
11195 if (popped) {
11196 ADD_INSN(ret, node, pop);
11197 }
11198 break;
11199 }
11200 case NODE_XSTR:{
11201 ADD_CALL_RECEIVER(ret, node);
11202 VALUE str = rb_node_str_string_val(node);
11203 ADD_INSN1(ret, node, putobject, str);
11204 RB_OBJ_WRITTEN(iseq, Qundef, str);
11205 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11206
11207 if (popped) {
11208 ADD_INSN(ret, node, pop);
11209 }
11210 break;
11211 }
11212 case NODE_DXSTR:{
11213 ADD_CALL_RECEIVER(ret, node);
11214 compile_dstr(iseq, ret, node);
11215 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11216
11217 if (popped) {
11218 ADD_INSN(ret, node, pop);
11219 }
11220 break;
11221 }
11222 case NODE_EVSTR:
11223 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11224 break;
11225 case NODE_REGX:{
11226 if (!popped) {
11227 VALUE lit = rb_node_regx_string_val(node);
11228 ADD_INSN1(ret, node, putobject, lit);
11229 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11230 }
11231 break;
11232 }
11233 case NODE_DREGX:
11234 compile_dregx(iseq, ret, node, popped);
11235 break;
11236 case NODE_ONCE:{
11237 int ic_index = body->ise_size++;
11238 const rb_iseq_t *block_iseq;
11239 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11240
11241 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11242 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11243
11244 if (popped) {
11245 ADD_INSN(ret, node, pop);
11246 }
11247 break;
11248 }
11249 case NODE_ARGSCAT:{
11250 if (popped) {
11251 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11252 ADD_INSN1(ret, node, splatarray, Qfalse);
11253 ADD_INSN(ret, node, pop);
11254 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11255 ADD_INSN1(ret, node, splatarray, Qfalse);
11256 ADD_INSN(ret, node, pop);
11257 }
11258 else {
11259 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11260 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11261 if (nd_type_p(body_node, NODE_LIST)) {
11262 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11263 }
11264 else {
11265 CHECK(COMPILE(ret, "argscat body", body_node));
11266 ADD_INSN(ret, node, concattoarray);
11267 }
11268 }
11269 break;
11270 }
11271 case NODE_ARGSPUSH:{
11272 if (popped) {
11273 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11274 ADD_INSN1(ret, node, splatarray, Qfalse);
11275 ADD_INSN(ret, node, pop);
11276 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11277 }
11278 else {
11279 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11280 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11281 if (keyword_node_p(body_node)) {
11282 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11283 ADD_INSN(ret, node, pushtoarraykwsplat);
11284 }
11285 else if (static_literal_node_p(body_node, iseq, false)) {
11286 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11287 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11288 }
11289 else {
11290 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11291 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11292 }
11293 }
11294 break;
11295 }
11296 case NODE_SPLAT:{
11297 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11298 ADD_INSN1(ret, node, splatarray, Qtrue);
11299
11300 if (popped) {
11301 ADD_INSN(ret, node, pop);
11302 }
11303 break;
11304 }
11305 case NODE_DEFN:{
11306 ID mid = RNODE_DEFN(node)->nd_mid;
11307 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11308 rb_id2str(mid),
11309 ISEQ_TYPE_METHOD, line);
11310
11311 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11312 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11313 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11314
11315 if (!popped) {
11316 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11317 }
11318
11319 break;
11320 }
11321 case NODE_DEFS:{
11322 ID mid = RNODE_DEFS(node)->nd_mid;
11323 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11324 rb_id2str(mid),
11325 ISEQ_TYPE_METHOD, line);
11326
11327 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11328 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11329 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11330 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11331
11332 if (!popped) {
11333 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11334 }
11335 break;
11336 }
11337 case NODE_ALIAS:{
11338 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11339 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11340 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11341 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11342 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11343
11344 if (popped) {
11345 ADD_INSN(ret, node, pop);
11346 }
11347 break;
11348 }
11349 case NODE_VALIAS:{
11350 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11351 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11352 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11353 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11354
11355 if (popped) {
11356 ADD_INSN(ret, node, pop);
11357 }
11358 break;
11359 }
11360 case NODE_UNDEF:{
11361 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11362
11363 for (long i = 0; i < ary->len; i++) {
11364 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11365 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11366 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11367 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11368
11369 if (i < ary->len - 1) {
11370 ADD_INSN(ret, node, pop);
11371 }
11372 }
11373
11374 if (popped) {
11375 ADD_INSN(ret, node, pop);
11376 }
11377 break;
11378 }
11379 case NODE_CLASS:{
11380 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11381 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11382 ISEQ_TYPE_CLASS, line);
11383 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11384 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11385 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11386
11387 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11388 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11389 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11390
11391 if (popped) {
11392 ADD_INSN(ret, node, pop);
11393 }
11394 break;
11395 }
11396 case NODE_MODULE:{
11397 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11398 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11399 ISEQ_TYPE_CLASS, line);
11400 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11401 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11402
11403 ADD_INSN (ret, node, putnil); /* dummy */
11404 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11405 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11406
11407 if (popped) {
11408 ADD_INSN(ret, node, pop);
11409 }
11410 break;
11411 }
11412 case NODE_SCLASS:{
11413 ID singletonclass;
11414 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11415 ISEQ_TYPE_CLASS, line);
11416
11417 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11418 ADD_INSN (ret, node, putnil);
11419 CONST_ID(singletonclass, "singletonclass");
11420 ADD_INSN3(ret, node, defineclass,
11421 ID2SYM(singletonclass), singleton_class,
11422 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11423 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11424
11425 if (popped) {
11426 ADD_INSN(ret, node, pop);
11427 }
11428 break;
11429 }
11430 case NODE_COLON2:
11431 CHECK(compile_colon2(iseq, ret, node, popped));
11432 break;
11433 case NODE_COLON3:
11434 CHECK(compile_colon3(iseq, ret, node, popped));
11435 break;
11436 case NODE_DOT2:
11437 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11438 break;
11439 case NODE_DOT3:
11440 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11441 break;
11442 case NODE_FLIP2:
11443 case NODE_FLIP3:{
11444 LABEL *lend = NEW_LABEL(line);
11445 LABEL *ltrue = NEW_LABEL(line);
11446 LABEL *lfalse = NEW_LABEL(line);
11447 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11448 ltrue, lfalse));
11449 ADD_LABEL(ret, ltrue);
11450 ADD_INSN1(ret, node, putobject, Qtrue);
11451 ADD_INSNL(ret, node, jump, lend);
11452 ADD_LABEL(ret, lfalse);
11453 ADD_INSN1(ret, node, putobject, Qfalse);
11454 ADD_LABEL(ret, lend);
11455 break;
11456 }
11457 case NODE_SELF:{
11458 if (!popped) {
11459 ADD_INSN(ret, node, putself);
11460 }
11461 break;
11462 }
11463 case NODE_NIL:{
11464 if (!popped) {
11465 ADD_INSN(ret, node, putnil);
11466 }
11467 break;
11468 }
11469 case NODE_TRUE:{
11470 if (!popped) {
11471 ADD_INSN1(ret, node, putobject, Qtrue);
11472 }
11473 break;
11474 }
11475 case NODE_FALSE:{
11476 if (!popped) {
11477 ADD_INSN1(ret, node, putobject, Qfalse);
11478 }
11479 break;
11480 }
11481 case NODE_ERRINFO:
11482 CHECK(compile_errinfo(iseq, ret, node, popped));
11483 break;
11484 case NODE_DEFINED:
11485 if (!popped) {
11486 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11487 }
11488 break;
11489 case NODE_POSTEXE:{
11490 /* compiled to:
11491 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11492 */
11493 int is_index = body->ise_size++;
11495 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11496 const rb_iseq_t *once_iseq =
11497 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11498
11499 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11500 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11501
11502 if (popped) {
11503 ADD_INSN(ret, node, pop);
11504 }
11505 break;
11506 }
11507 case NODE_KW_ARG:
11508 CHECK(compile_kw_arg(iseq, ret, node, popped));
11509 break;
11510 case NODE_DSYM:{
11511 compile_dstr(iseq, ret, node);
11512 if (!popped) {
11513 ADD_INSN(ret, node, intern);
11514 }
11515 else {
11516 ADD_INSN(ret, node, pop);
11517 }
11518 break;
11519 }
11520 case NODE_ATTRASGN:
11521 CHECK(compile_attrasgn(iseq, ret, node, popped));
11522 break;
11523 case NODE_LAMBDA:{
11524 /* compile same as lambda{...} */
11525 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11526 VALUE argc = INT2FIX(0);
11527
11528 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11529 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11530 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11531
11532 if (popped) {
11533 ADD_INSN(ret, node, pop);
11534 }
11535 break;
11536 }
11537 default:
11538 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11539 ng:
11540 debug_node_end();
11541 return COMPILE_NG;
11542 }
11543
11544 debug_node_end();
11545 return COMPILE_OK;
11546}
11547
11548/***************************/
11549/* instruction information */
11550/***************************/
11551
11552static int
11553insn_data_length(INSN *iobj)
11554{
11555 return insn_len(iobj->insn_id);
11556}
11557
11558static int
11559calc_sp_depth(int depth, INSN *insn)
11560{
11561 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11562}
11563
11564static VALUE
11565opobj_inspect(VALUE obj)
11566{
11567 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11568 switch (BUILTIN_TYPE(obj)) {
11569 case T_STRING:
11570 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11571 break;
11572 case T_ARRAY:
11573 obj = rb_ary_dup(obj);
11574 break;
11575 default:
11576 break;
11577 }
11578 }
11579 return rb_inspect(obj);
11580}
11581
11582
11583
11584static VALUE
11585insn_data_to_s_detail(INSN *iobj)
11586{
11587 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11588
11589 if (iobj->operands) {
11590 const char *types = insn_op_types(iobj->insn_id);
11591 int j;
11592
11593 for (j = 0; types[j]; j++) {
11594 char type = types[j];
11595
11596 switch (type) {
11597 case TS_OFFSET: /* label(destination position) */
11598 {
11599 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11600 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11601 break;
11602 }
11603 break;
11604 case TS_ISEQ: /* iseq */
11605 {
11606 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11607 VALUE val = Qnil;
11608 if (0 && iseq) { /* TODO: invalidate now */
11609 val = (VALUE)iseq;
11610 }
11611 rb_str_concat(str, opobj_inspect(val));
11612 }
11613 break;
11614 case TS_LINDEX:
11615 case TS_NUM: /* ulong */
11616 case TS_VALUE: /* VALUE */
11617 {
11618 VALUE v = OPERAND_AT(iobj, j);
11619 if (!CLASS_OF(v))
11620 rb_str_cat2(str, "<hidden>");
11621 else {
11622 rb_str_concat(str, opobj_inspect(v));
11623 }
11624 break;
11625 }
11626 case TS_ID: /* ID */
11627 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11628 break;
11629 case TS_IC: /* inline cache */
11630 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11631 break;
11632 case TS_IVC: /* inline ivar cache */
11633 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11634 break;
11635 case TS_ICVARC: /* inline cvar cache */
11636 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11637 break;
11638 case TS_ISE: /* inline storage entry */
11639 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11640 break;
11641 case TS_CALLDATA: /* we store these as call infos at compile time */
11642 {
11643 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11644 rb_str_cat2(str, "<calldata:");
11645 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11646 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11647 break;
11648 }
11649 case TS_CDHASH: /* case/when condition cache */
11650 rb_str_cat2(str, "<ch>");
11651 break;
11652 case TS_FUNCPTR:
11653 {
11654 void *func = (void *)OPERAND_AT(iobj, j);
11655#ifdef HAVE_DLADDR
11656 Dl_info info;
11657 if (dladdr(func, &info) && info.dli_sname) {
11658 rb_str_cat2(str, info.dli_sname);
11659 break;
11660 }
11661#endif
11662 rb_str_catf(str, "<%p>", func);
11663 }
11664 break;
11665 case TS_BUILTIN:
11666 rb_str_cat2(str, "<TS_BUILTIN>");
11667 break;
11668 default:{
11669 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11670 }
11671 }
11672 if (types[j + 1]) {
11673 rb_str_cat2(str, ", ");
11674 }
11675 }
11676 }
11677 return str;
11678}
11679
11680static void
11681dump_disasm_list(const LINK_ELEMENT *link)
11682{
11683 dump_disasm_list_with_cursor(link, NULL, NULL);
11684}
11685
11686static void
11687dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11688{
11689 int pos = 0;
11690 INSN *iobj;
11691 LABEL *lobj;
11692 VALUE str;
11693
11694 printf("-- raw disasm--------\n");
11695
11696 while (link) {
11697 if (curr) printf(curr == link ? "*" : " ");
11698 switch (link->type) {
11699 case ISEQ_ELEMENT_INSN:
11700 {
11701 iobj = (INSN *)link;
11702 str = insn_data_to_s_detail(iobj);
11703 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11704 pos += insn_data_length(iobj);
11705 break;
11706 }
11707 case ISEQ_ELEMENT_LABEL:
11708 {
11709 lobj = (LABEL *)link;
11710 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11711 dest == lobj ? " <---" : "");
11712 break;
11713 }
11714 case ISEQ_ELEMENT_TRACE:
11715 {
11716 TRACE *trace = (TRACE *)link;
11717 printf(" trace: %0x\n", trace->event);
11718 break;
11719 }
11720 case ISEQ_ELEMENT_ADJUST:
11721 {
11722 ADJUST *adjust = (ADJUST *)link;
11723 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11724 break;
11725 }
11726 default:
11727 /* ignore */
11728 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11729 }
11730 link = link->next;
11731 }
11732 printf("---------------------\n");
11733 fflush(stdout);
11734}
11735
11736int
11737rb_insn_len(VALUE insn)
11738{
11739 return insn_len(insn);
11740}
11741
11742const char *
11743rb_insns_name(int i)
11744{
11745 return insn_name(i);
11746}
11747
11748VALUE
11749rb_insns_name_array(void)
11750{
11751 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11752 int i;
11753 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11754 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11755 }
11756 return rb_ary_freeze(ary);
11757}
11758
11759static LABEL *
11760register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11761{
11762 LABEL *label = 0;
11763 st_data_t tmp;
11764 obj = rb_to_symbol_type(obj);
11765
11766 if (st_lookup(labels_table, obj, &tmp) == 0) {
11767 label = NEW_LABEL(0);
11768 st_insert(labels_table, obj, (st_data_t)label);
11769 }
11770 else {
11771 label = (LABEL *)tmp;
11772 }
11773 LABEL_REF(label);
11774 return label;
11775}
11776
11777static VALUE
11778get_exception_sym2type(VALUE sym)
11779{
11780 static VALUE symRescue, symEnsure, symRetry;
11781 static VALUE symBreak, symRedo, symNext;
11782
11783 if (symRescue == 0) {
11784 symRescue = ID2SYM(rb_intern_const("rescue"));
11785 symEnsure = ID2SYM(rb_intern_const("ensure"));
11786 symRetry = ID2SYM(rb_intern_const("retry"));
11787 symBreak = ID2SYM(rb_intern_const("break"));
11788 symRedo = ID2SYM(rb_intern_const("redo"));
11789 symNext = ID2SYM(rb_intern_const("next"));
11790 }
11791
11792 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11793 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11794 if (sym == symRetry) return CATCH_TYPE_RETRY;
11795 if (sym == symBreak) return CATCH_TYPE_BREAK;
11796 if (sym == symRedo) return CATCH_TYPE_REDO;
11797 if (sym == symNext) return CATCH_TYPE_NEXT;
11798 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11799 return 0;
11800}
11801
11802static int
11803iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11804 VALUE exception)
11805{
11806 int i;
11807
11808 for (i=0; i<RARRAY_LEN(exception); i++) {
11809 const rb_iseq_t *eiseq;
11810 VALUE v, type;
11811 LABEL *lstart, *lend, *lcont;
11812 unsigned int sp;
11813
11814 v = rb_to_array_type(RARRAY_AREF(exception, i));
11815 if (RARRAY_LEN(v) != 6) {
11816 rb_raise(rb_eSyntaxError, "wrong exception entry");
11817 }
11818 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11819 if (NIL_P(RARRAY_AREF(v, 1))) {
11820 eiseq = NULL;
11821 }
11822 else {
11823 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11824 }
11825
11826 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11827 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11828 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11829 sp = NUM2UINT(RARRAY_AREF(v, 5));
11830
11831 /* TODO: Dirty Hack! Fix me */
11832 if (type == CATCH_TYPE_RESCUE ||
11833 type == CATCH_TYPE_BREAK ||
11834 type == CATCH_TYPE_NEXT) {
11835 ++sp;
11836 }
11837
11838 lcont->sp = sp;
11839
11840 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11841
11842 RB_GC_GUARD(v);
11843 }
11844 return COMPILE_OK;
11845}
11846
11847static struct st_table *
11848insn_make_insn_table(void)
11849{
11850 struct st_table *table;
11851 int i;
11852 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11853
11854 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11855 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11856 }
11857
11858 return table;
11859}
11860
11861static const rb_iseq_t *
11862iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11863{
11864 VALUE iseqw;
11865 const rb_iseq_t *loaded_iseq;
11866
11867 if (RB_TYPE_P(op, T_ARRAY)) {
11868 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11869 }
11870 else if (CLASS_OF(op) == rb_cISeq) {
11871 iseqw = op;
11872 }
11873 else {
11874 rb_raise(rb_eSyntaxError, "ISEQ is required");
11875 }
11876
11877 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11878 return loaded_iseq;
11879}
11880
11881static VALUE
11882iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11883{
11884 ID mid = 0;
11885 int orig_argc = 0;
11886 unsigned int flag = 0;
11887 struct rb_callinfo_kwarg *kw_arg = 0;
11888
11889 if (!NIL_P(op)) {
11890 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11891 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11892 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11893 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11894
11895 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11896 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11897 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11898
11899 if (!NIL_P(vkw_arg)) {
11900 int i;
11901 int len = RARRAY_LENINT(vkw_arg);
11902 size_t n = rb_callinfo_kwarg_bytes(len);
11903
11904 kw_arg = xmalloc(n);
11905 kw_arg->references = 0;
11906 kw_arg->keyword_len = len;
11907 for (i = 0; i < len; i++) {
11908 VALUE kw = RARRAY_AREF(vkw_arg, i);
11909 SYM2ID(kw); /* make immortal */
11910 kw_arg->keywords[i] = kw;
11911 }
11912 }
11913 }
11914
11915 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11916 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11917 return (VALUE)ci;
11918}
11919
11920static rb_event_flag_t
11921event_name_to_flag(VALUE sym)
11922{
11923#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11924 CHECK_EVENT(RUBY_EVENT_LINE);
11925 CHECK_EVENT(RUBY_EVENT_CLASS);
11926 CHECK_EVENT(RUBY_EVENT_END);
11927 CHECK_EVENT(RUBY_EVENT_CALL);
11928 CHECK_EVENT(RUBY_EVENT_RETURN);
11929 CHECK_EVENT(RUBY_EVENT_B_CALL);
11930 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11931 CHECK_EVENT(RUBY_EVENT_RESCUE);
11932#undef CHECK_EVENT
11933 return RUBY_EVENT_NONE;
11934}
11935
11936static int
11937iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11938 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11939{
11940 /* TODO: body should be frozen */
11941 long i, len = RARRAY_LEN(body);
11942 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11943 int j;
11944 int line_no = 0, node_id = -1, insn_idx = 0;
11945 int ret = COMPILE_OK;
11946
11947 /*
11948 * index -> LABEL *label
11949 */
11950 static struct st_table *insn_table;
11951
11952 if (insn_table == 0) {
11953 insn_table = insn_make_insn_table();
11954 }
11955
11956 for (i=0; i<len; i++) {
11957 VALUE obj = RARRAY_AREF(body, i);
11958
11959 if (SYMBOL_P(obj)) {
11960 rb_event_flag_t event;
11961 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11962 ADD_TRACE(anchor, event);
11963 }
11964 else {
11965 LABEL *label = register_label(iseq, labels_table, obj);
11966 ADD_LABEL(anchor, label);
11967 }
11968 }
11969 else if (FIXNUM_P(obj)) {
11970 line_no = NUM2INT(obj);
11971 }
11972 else if (RB_TYPE_P(obj, T_ARRAY)) {
11973 VALUE *argv = 0;
11974 int argc = RARRAY_LENINT(obj) - 1;
11975 st_data_t insn_id;
11976 VALUE insn;
11977
11978 if (node_ids) {
11979 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11980 }
11981
11982 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11983 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11984 /* TODO: exception */
11985 COMPILE_ERROR(iseq, line_no,
11986 "unknown instruction: %+"PRIsVALUE, insn);
11987 ret = COMPILE_NG;
11988 break;
11989 }
11990
11991 if (argc != insn_len((VALUE)insn_id)-1) {
11992 COMPILE_ERROR(iseq, line_no,
11993 "operand size mismatch");
11994 ret = COMPILE_NG;
11995 break;
11996 }
11997
11998 if (argc > 0) {
11999 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12000
12001 // add element before operand setup to make GC root
12002 ADD_ELEM(anchor,
12003 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12004 (enum ruby_vminsn_type)insn_id, argc, argv));
12005
12006 for (j=0; j<argc; j++) {
12007 VALUE op = rb_ary_entry(obj, j+1);
12008 switch (insn_op_type((VALUE)insn_id, j)) {
12009 case TS_OFFSET: {
12010 LABEL *label = register_label(iseq, labels_table, op);
12011 argv[j] = (VALUE)label;
12012 break;
12013 }
12014 case TS_LINDEX:
12015 case TS_NUM:
12016 (void)NUM2INT(op);
12017 argv[j] = op;
12018 break;
12019 case TS_VALUE:
12020 argv[j] = op;
12021 RB_OBJ_WRITTEN(iseq, Qundef, op);
12022 break;
12023 case TS_ISEQ:
12024 {
12025 if (op != Qnil) {
12026 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12027 argv[j] = v;
12028 RB_OBJ_WRITTEN(iseq, Qundef, v);
12029 }
12030 else {
12031 argv[j] = 0;
12032 }
12033 }
12034 break;
12035 case TS_ISE:
12036 argv[j] = op;
12037 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12038 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12039 }
12040 break;
12041 case TS_IC:
12042 {
12043 VALUE segments = rb_ary_new();
12044 op = rb_to_array_type(op);
12045
12046 for (int i = 0; i < RARRAY_LEN(op); i++) {
12047 VALUE sym = RARRAY_AREF(op, i);
12048 sym = rb_to_symbol_type(sym);
12049 rb_ary_push(segments, sym);
12050 }
12051
12052 RB_GC_GUARD(op);
12053 argv[j] = segments;
12054 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12055 ISEQ_BODY(iseq)->ic_size++;
12056 }
12057 break;
12058 case TS_IVC: /* inline ivar cache */
12059 argv[j] = op;
12060 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12061 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12062 }
12063 break;
12064 case TS_ICVARC: /* inline cvar cache */
12065 argv[j] = op;
12066 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12067 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12068 }
12069 break;
12070 case TS_CALLDATA:
12071 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12072 break;
12073 case TS_ID:
12074 argv[j] = rb_to_symbol_type(op);
12075 break;
12076 case TS_CDHASH:
12077 {
12078 int i;
12079 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12080
12081 RHASH_TBL_RAW(map)->type = &cdhash_type;
12082 op = rb_to_array_type(op);
12083 for (i=0; i<RARRAY_LEN(op); i+=2) {
12084 VALUE key = RARRAY_AREF(op, i);
12085 VALUE sym = RARRAY_AREF(op, i+1);
12086 LABEL *label =
12087 register_label(iseq, labels_table, sym);
12088 rb_hash_aset(map, key, (VALUE)label | 1);
12089 }
12090 RB_GC_GUARD(op);
12091 argv[j] = map;
12092 RB_OBJ_WRITTEN(iseq, Qundef, map);
12093 }
12094 break;
12095 case TS_FUNCPTR:
12096 {
12097#if SIZEOF_VALUE <= SIZEOF_LONG
12098 long funcptr = NUM2LONG(op);
12099#else
12100 LONG_LONG funcptr = NUM2LL(op);
12101#endif
12102 argv[j] = (VALUE)funcptr;
12103 }
12104 break;
12105 default:
12106 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12107 }
12108 }
12109 }
12110 else {
12111 ADD_ELEM(anchor,
12112 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12113 (enum ruby_vminsn_type)insn_id, argc, NULL));
12114 }
12115 }
12116 else {
12117 rb_raise(rb_eTypeError, "unexpected object for instruction");
12118 }
12119 }
12120 RTYPEDDATA_DATA(labels_wrapper) = 0;
12121 RB_GC_GUARD(labels_wrapper);
12122 validate_labels(iseq, labels_table);
12123 if (!ret) return ret;
12124 return iseq_setup(iseq, anchor);
12125}
12126
12127#define CHECK_ARRAY(v) rb_to_array_type(v)
12128#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12129
12130static int
12131int_param(int *dst, VALUE param, VALUE sym)
12132{
12133 VALUE val = rb_hash_aref(param, sym);
12134 if (FIXNUM_P(val)) {
12135 *dst = FIX2INT(val);
12136 return TRUE;
12137 }
12138 else if (!NIL_P(val)) {
12139 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12140 sym, val);
12141 }
12142 return FALSE;
12143}
12144
12145static const struct rb_iseq_param_keyword *
12146iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12147{
12148 int i, j;
12149 int len = RARRAY_LENINT(keywords);
12150 int default_len;
12151 VALUE key, sym, default_val;
12152 VALUE *dvs;
12153 ID *ids;
12154 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12155
12156 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12157
12158 keyword->num = len;
12159#define SYM(s) ID2SYM(rb_intern_const(#s))
12160 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12161 i = keyword->bits_start - keyword->num;
12162 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12163#undef SYM
12164
12165 /* required args */
12166 for (i = 0; i < len; i++) {
12167 VALUE val = RARRAY_AREF(keywords, i);
12168
12169 if (!SYMBOL_P(val)) {
12170 goto default_values;
12171 }
12172 ids[i] = SYM2ID(val);
12173 keyword->required_num++;
12174 }
12175
12176 default_values: /* note: we intentionally preserve `i' from previous loop */
12177 default_len = len - i;
12178 if (default_len == 0) {
12179 keyword->table = ids;
12180 return keyword;
12181 }
12182 else if (default_len < 0) {
12184 }
12185
12186 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12187
12188 for (j = 0; i < len; i++, j++) {
12189 key = RARRAY_AREF(keywords, i);
12190 CHECK_ARRAY(key);
12191
12192 switch (RARRAY_LEN(key)) {
12193 case 1:
12194 sym = RARRAY_AREF(key, 0);
12195 default_val = Qundef;
12196 break;
12197 case 2:
12198 sym = RARRAY_AREF(key, 0);
12199 default_val = RARRAY_AREF(key, 1);
12200 break;
12201 default:
12202 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12203 }
12204 ids[i] = SYM2ID(sym);
12205 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12206 }
12207
12208 keyword->table = ids;
12209 keyword->default_values = dvs;
12210
12211 return keyword;
12212}
12213
12214static void
12215iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12216{
12217 rb_gc_mark_and_move(obj);
12218}
12219
12220void
12221rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12222{
12223 INSN *iobj = 0;
12224 size_t size = sizeof(INSN);
12225 unsigned int pos = 0;
12226
12227 while (storage) {
12228#ifdef STRICT_ALIGNMENT
12229 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12230#else
12231 const size_t padding = 0; /* expected to be optimized by compiler */
12232#endif /* STRICT_ALIGNMENT */
12233 size_t offset = pos + size + padding;
12234 if (offset > storage->size || offset > storage->pos) {
12235 pos = 0;
12236 storage = storage->next;
12237 }
12238 else {
12239#ifdef STRICT_ALIGNMENT
12240 pos += (int)padding;
12241#endif /* STRICT_ALIGNMENT */
12242
12243 iobj = (INSN *)&storage->buff[pos];
12244
12245 if (iobj->operands) {
12246 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12247 }
12248 pos += (int)size;
12249 }
12250 }
12251}
12252
12253static const rb_data_type_t labels_wrapper_type = {
12254 .wrap_struct_name = "compiler/labels_wrapper",
12255 .function = {
12256 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12257 .dfree = (RUBY_DATA_FUNC)st_free_table,
12258 },
12259 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12260};
12261
12262void
12263rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12264 VALUE exception, VALUE body)
12265{
12266#define SYM(s) ID2SYM(rb_intern_const(#s))
12267 int i, len;
12268 unsigned int arg_size, local_size, stack_max;
12269 ID *tbl;
12270 struct st_table *labels_table = st_init_numtable();
12271 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12272 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12273 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12274 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12275 DECL_ANCHOR(anchor);
12276 INIT_ANCHOR(anchor);
12277
12278 len = RARRAY_LENINT(locals);
12279 ISEQ_BODY(iseq)->local_table_size = len;
12280 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12281
12282 for (i = 0; i < len; i++) {
12283 VALUE lv = RARRAY_AREF(locals, i);
12284
12285 if (sym_arg_rest == lv) {
12286 tbl[i] = 0;
12287 }
12288 else {
12289 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12290 }
12291 }
12292
12293#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12294 if (INT_PARAM(lead_num)) {
12295 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12296 }
12297 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12298 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12299 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12300 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12301#undef INT_PARAM
12302 {
12303#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12304 int x;
12305 INT_PARAM(arg_size);
12306 INT_PARAM(local_size);
12307 INT_PARAM(stack_max);
12308#undef INT_PARAM
12309 }
12310
12311 VALUE node_ids = Qfalse;
12312#ifdef USE_ISEQ_NODE_ID
12313 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12314 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12315 rb_raise(rb_eTypeError, "node_ids is not an array");
12316 }
12317#endif
12318
12319 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12320 len = RARRAY_LENINT(arg_opt_labels);
12321 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12322
12323 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12324 VALUE *opt_table = ALLOC_N(VALUE, len);
12325
12326 for (i = 0; i < len; i++) {
12327 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12328 LABEL *label = register_label(iseq, labels_table, ent);
12329 opt_table[i] = (VALUE)label;
12330 }
12331
12332 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12333 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12334 }
12335 }
12336 else if (!NIL_P(arg_opt_labels)) {
12337 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12338 arg_opt_labels);
12339 }
12340
12341 if (RB_TYPE_P(keywords, T_ARRAY)) {
12342 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12343 }
12344 else if (!NIL_P(keywords)) {
12345 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12346 keywords);
12347 }
12348
12349 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12350 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12351 }
12352
12353 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12354 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12355 }
12356
12357 if (int_param(&i, params, SYM(kwrest))) {
12358 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12359 if (keyword == NULL) {
12360 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12361 }
12362 keyword->rest_start = i;
12363 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12364 }
12365#undef SYM
12366 iseq_calc_param_size(iseq);
12367
12368 /* exception */
12369 iseq_build_from_ary_exception(iseq, labels_table, exception);
12370
12371 /* body */
12372 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12373
12374 ISEQ_BODY(iseq)->param.size = arg_size;
12375 ISEQ_BODY(iseq)->local_table_size = local_size;
12376 ISEQ_BODY(iseq)->stack_max = stack_max;
12377}
12378
12379/* for parser */
12380
12381int
12382rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12383{
12384 if (iseq) {
12385 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12386 while (body->type == ISEQ_TYPE_BLOCK ||
12387 body->type == ISEQ_TYPE_RESCUE ||
12388 body->type == ISEQ_TYPE_ENSURE ||
12389 body->type == ISEQ_TYPE_EVAL ||
12390 body->type == ISEQ_TYPE_MAIN
12391 ) {
12392 unsigned int i;
12393
12394 for (i = 0; i < body->local_table_size; i++) {
12395 if (body->local_table[i] == id) {
12396 return 1;
12397 }
12398 }
12399 iseq = body->parent_iseq;
12400 body = ISEQ_BODY(iseq);
12401 }
12402 }
12403 return 0;
12404}
12405
12406int
12407rb_local_defined(ID id, const rb_iseq_t *iseq)
12408{
12409 if (iseq) {
12410 unsigned int i;
12411 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12412
12413 for (i=0; i<body->local_table_size; i++) {
12414 if (body->local_table[i] == id) {
12415 return 1;
12416 }
12417 }
12418 }
12419 return 0;
12420}
12421
12422/* ISeq binary format */
12423
12424#ifndef IBF_ISEQ_DEBUG
12425#define IBF_ISEQ_DEBUG 0
12426#endif
12427
12428#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12429#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12430#endif
12431
12432typedef uint32_t ibf_offset_t;
12433#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12434
12435#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12436#ifdef RUBY_DEVEL
12437#define IBF_DEVEL_VERSION 4
12438#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12439#else
12440#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12441#endif
12442
12443static const char IBF_ENDIAN_MARK =
12444#ifdef WORDS_BIGENDIAN
12445 'b'
12446#else
12447 'l'
12448#endif
12449 ;
12450
12452 char magic[4]; /* YARB */
12453 uint32_t major_version;
12454 uint32_t minor_version;
12455 uint32_t size;
12456 uint32_t extra_size;
12457
12458 uint32_t iseq_list_size;
12459 uint32_t global_object_list_size;
12460 ibf_offset_t iseq_list_offset;
12461 ibf_offset_t global_object_list_offset;
12462 uint8_t endian;
12463 uint8_t wordsize; /* assume no 2048-bit CPU */
12464};
12465
12467 VALUE str;
12468 st_table *obj_table; /* obj -> obj number */
12469};
12470
12471struct ibf_dump {
12472 st_table *iseq_table; /* iseq -> iseq number */
12473 struct ibf_dump_buffer global_buffer;
12474 struct ibf_dump_buffer *current_buffer;
12475};
12476
12478 const char *buff;
12479 ibf_offset_t size;
12480
12481 VALUE obj_list; /* [obj0, ...] */
12482 unsigned int obj_list_size;
12483 ibf_offset_t obj_list_offset;
12484};
12485
12486struct ibf_load {
12487 const struct ibf_header *header;
12488 VALUE iseq_list; /* [iseq0, ...] */
12489 struct ibf_load_buffer global_buffer;
12490 VALUE loader_obj;
12491 rb_iseq_t *iseq;
12492 VALUE str;
12493 struct ibf_load_buffer *current_buffer;
12494};
12495
12497 long size;
12498 VALUE buffer[1];
12499};
12500
12501static void
12502pinned_list_mark(void *ptr)
12503{
12504 long i;
12505 struct pinned_list *list = (struct pinned_list *)ptr;
12506 for (i = 0; i < list->size; i++) {
12507 if (list->buffer[i]) {
12508 rb_gc_mark(list->buffer[i]);
12509 }
12510 }
12511}
12512
12513static const rb_data_type_t pinned_list_type = {
12514 "pinned_list",
12515 {
12516 pinned_list_mark,
12518 NULL, // No external memory to report,
12519 },
12520 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12521};
12522
12523static VALUE
12524pinned_list_fetch(VALUE list, long offset)
12525{
12526 struct pinned_list * ptr;
12527
12528 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12529
12530 if (offset >= ptr->size) {
12531 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12532 }
12533
12534 return ptr->buffer[offset];
12535}
12536
12537static void
12538pinned_list_store(VALUE list, long offset, VALUE object)
12539{
12540 struct pinned_list * ptr;
12541
12542 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12543
12544 if (offset >= ptr->size) {
12545 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12546 }
12547
12548 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12549}
12550
12551static VALUE
12552pinned_list_new(long size)
12553{
12554 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12555 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12556 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12557 ptr->size = size;
12558 return obj_list;
12559}
12560
12561static ibf_offset_t
12562ibf_dump_pos(struct ibf_dump *dump)
12563{
12564 long pos = RSTRING_LEN(dump->current_buffer->str);
12565#if SIZEOF_LONG > SIZEOF_INT
12566 if (pos >= UINT_MAX) {
12567 rb_raise(rb_eRuntimeError, "dump size exceeds");
12568 }
12569#endif
12570 return (unsigned int)pos;
12571}
12572
12573static void
12574ibf_dump_align(struct ibf_dump *dump, size_t align)
12575{
12576 ibf_offset_t pos = ibf_dump_pos(dump);
12577 if (pos % align) {
12578 static const char padding[sizeof(VALUE)];
12579 size_t size = align - ((size_t)pos % align);
12580#if SIZEOF_LONG > SIZEOF_INT
12581 if (pos + size >= UINT_MAX) {
12582 rb_raise(rb_eRuntimeError, "dump size exceeds");
12583 }
12584#endif
12585 for (; size > sizeof(padding); size -= sizeof(padding)) {
12586 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12587 }
12588 rb_str_cat(dump->current_buffer->str, padding, size);
12589 }
12590}
12591
12592static ibf_offset_t
12593ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12594{
12595 ibf_offset_t pos = ibf_dump_pos(dump);
12596 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12597 /* TODO: overflow check */
12598 return pos;
12599}
12600
12601static ibf_offset_t
12602ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12603{
12604 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12605}
12606
12607static void
12608ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12609{
12610 VALUE str = dump->current_buffer->str;
12611 char *ptr = RSTRING_PTR(str);
12612 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12613 rb_bug("ibf_dump_overwrite: overflow");
12614 memcpy(ptr + offset, buff, size);
12615}
12616
12617static const void *
12618ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12619{
12620 ibf_offset_t beg = *offset;
12621 *offset += size;
12622 return load->current_buffer->buff + beg;
12623}
12624
12625static void *
12626ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12627{
12628 void *buff = ruby_xmalloc2(x, y);
12629 size_t size = x * y;
12630 memcpy(buff, load->current_buffer->buff + offset, size);
12631 return buff;
12632}
12633
12634#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12635
12636#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12637#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12638#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12639#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12640#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12641
12642static int
12643ibf_table_lookup(struct st_table *table, st_data_t key)
12644{
12645 st_data_t val;
12646
12647 if (st_lookup(table, key, &val)) {
12648 return (int)val;
12649 }
12650 else {
12651 return -1;
12652 }
12653}
12654
12655static int
12656ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12657{
12658 int index = ibf_table_lookup(table, key);
12659
12660 if (index < 0) { /* not found */
12661 index = (int)table->num_entries;
12662 st_insert(table, key, (st_data_t)index);
12663 }
12664
12665 return index;
12666}
12667
12668/* dump/load generic */
12669
12670static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12671
12672static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12673static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12674
12675static st_table *
12676ibf_dump_object_table_new(void)
12677{
12678 st_table *obj_table = st_init_numtable(); /* need free */
12679 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12680
12681 return obj_table;
12682}
12683
12684static VALUE
12685ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12686{
12687 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12688}
12689
12690static VALUE
12691ibf_dump_id(struct ibf_dump *dump, ID id)
12692{
12693 if (id == 0 || rb_id2name(id) == NULL) {
12694 return 0;
12695 }
12696 return ibf_dump_object(dump, rb_id2sym(id));
12697}
12698
12699static ID
12700ibf_load_id(const struct ibf_load *load, const ID id_index)
12701{
12702 if (id_index == 0) {
12703 return 0;
12704 }
12705 VALUE sym = ibf_load_object(load, id_index);
12706 if (rb_integer_type_p(sym)) {
12707 /* Load hidden local variables as indexes */
12708 return NUM2ULONG(sym);
12709 }
12710 return rb_sym2id(sym);
12711}
12712
12713/* dump/load: code */
12714
12715static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12716
12717static int
12718ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12719{
12720 if (iseq == NULL) {
12721 return -1;
12722 }
12723 else {
12724 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12725 }
12726}
12727
12728static unsigned char
12729ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12730{
12731 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12732 return (unsigned char)load->current_buffer->buff[(*offset)++];
12733}
12734
12735/*
12736 * Small uint serialization
12737 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12738 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12739 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12740 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12741 * ...
12742 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12743 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12744 */
12745static void
12746ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12747{
12748 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12749 ibf_dump_write(dump, &x, sizeof(VALUE));
12750 return;
12751 }
12752
12753 enum { max_byte_length = sizeof(VALUE) + 1 };
12754
12755 unsigned char bytes[max_byte_length];
12756 ibf_offset_t n;
12757
12758 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12759 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12760 }
12761
12762 x <<= 1;
12763 x |= 1;
12764 x <<= n;
12765 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12766 n++;
12767
12768 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12769}
12770
12771static VALUE
12772ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12773{
12774 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12775 union { char s[sizeof(VALUE)]; VALUE v; } x;
12776
12777 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12778 *offset += sizeof(VALUE);
12779
12780 return x.v;
12781 }
12782
12783 enum { max_byte_length = sizeof(VALUE) + 1 };
12784
12785 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12786 const unsigned char c = buffer[*offset];
12787
12788 ibf_offset_t n =
12789 c & 1 ? 1 :
12790 c == 0 ? 9 : ntz_int32(c) + 1;
12791 VALUE x = (VALUE)c >> n;
12792
12793 if (*offset + n > load->current_buffer->size) {
12794 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12795 }
12796
12797 ibf_offset_t i;
12798 for (i = 1; i < n; i++) {
12799 x <<= 8;
12800 x |= (VALUE)buffer[*offset + i];
12801 }
12802
12803 *offset += n;
12804 return x;
12805}
12806
12807static void
12808ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12809{
12810 // short: index
12811 // short: name.length
12812 // bytes: name
12813 // // omit argc (only verify with name)
12814 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12815
12816 size_t len = strlen(bf->name);
12817 ibf_dump_write_small_value(dump, (VALUE)len);
12818 ibf_dump_write(dump, bf->name, len);
12819}
12820
12821static const struct rb_builtin_function *
12822ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12823{
12824 int i = (int)ibf_load_small_value(load, offset);
12825 int len = (int)ibf_load_small_value(load, offset);
12826 const char *name = (char *)ibf_load_ptr(load, offset, len);
12827
12828 if (0) {
12829 fprintf(stderr, "%.*s!!\n", len, name);
12830 }
12831
12832 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12833 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12834 if (strncmp(table[i].name, name, len) != 0) {
12835 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12836 }
12837 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12838
12839 return &table[i];
12840}
12841
12842static ibf_offset_t
12843ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12844{
12845 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12846 const int iseq_size = body->iseq_size;
12847 int code_index;
12848 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12849
12850 ibf_offset_t offset = ibf_dump_pos(dump);
12851
12852 for (code_index=0; code_index<iseq_size;) {
12853 const VALUE insn = orig_code[code_index++];
12854 const char *types = insn_op_types(insn);
12855 int op_index;
12856
12857 /* opcode */
12858 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12859 ibf_dump_write_small_value(dump, insn);
12860
12861 /* operands */
12862 for (op_index=0; types[op_index]; op_index++, code_index++) {
12863 VALUE op = orig_code[code_index];
12864 VALUE wv;
12865
12866 switch (types[op_index]) {
12867 case TS_CDHASH:
12868 case TS_VALUE:
12869 wv = ibf_dump_object(dump, op);
12870 break;
12871 case TS_ISEQ:
12872 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12873 break;
12874 case TS_IC:
12875 {
12876 IC ic = (IC)op;
12877 VALUE arr = idlist_to_array(ic->segments);
12878 wv = ibf_dump_object(dump, arr);
12879 }
12880 break;
12881 case TS_ISE:
12882 case TS_IVC:
12883 case TS_ICVARC:
12884 {
12886 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12887 }
12888 break;
12889 case TS_CALLDATA:
12890 {
12891 goto skip_wv;
12892 }
12893 case TS_ID:
12894 wv = ibf_dump_id(dump, (ID)op);
12895 break;
12896 case TS_FUNCPTR:
12897 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12898 goto skip_wv;
12899 case TS_BUILTIN:
12900 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12901 goto skip_wv;
12902 default:
12903 wv = op;
12904 break;
12905 }
12906 ibf_dump_write_small_value(dump, wv);
12907 skip_wv:;
12908 }
12909 RUBY_ASSERT(insn_len(insn) == op_index+1);
12910 }
12911
12912 return offset;
12913}
12914
12915static VALUE *
12916ibf_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)
12917{
12918 VALUE iseqv = (VALUE)iseq;
12919 unsigned int code_index;
12920 ibf_offset_t reading_pos = bytecode_offset;
12921 VALUE *code = ALLOC_N(VALUE, iseq_size);
12922
12923 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12924 struct rb_call_data *cd_entries = load_body->call_data;
12925 int ic_index = 0;
12926
12927 iseq_bits_t * mark_offset_bits;
12928
12929 iseq_bits_t tmp[1] = {0};
12930
12931 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12932 mark_offset_bits = tmp;
12933 }
12934 else {
12935 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12936 }
12937 bool needs_bitmap = false;
12938
12939 for (code_index=0; code_index<iseq_size;) {
12940 /* opcode */
12941 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12942 const char *types = insn_op_types(insn);
12943 int op_index;
12944
12945 code_index++;
12946
12947 /* operands */
12948 for (op_index=0; types[op_index]; op_index++, code_index++) {
12949 const char operand_type = types[op_index];
12950 switch (operand_type) {
12951 case TS_VALUE:
12952 {
12953 VALUE op = ibf_load_small_value(load, &reading_pos);
12954 VALUE v = ibf_load_object(load, op);
12955 code[code_index] = v;
12956 if (!SPECIAL_CONST_P(v)) {
12957 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12958 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12959 needs_bitmap = true;
12960 }
12961 break;
12962 }
12963 case TS_CDHASH:
12964 {
12965 VALUE op = ibf_load_small_value(load, &reading_pos);
12966 VALUE v = ibf_load_object(load, op);
12967 v = rb_hash_dup(v); // hash dumped as frozen
12968 RHASH_TBL_RAW(v)->type = &cdhash_type;
12969 rb_hash_rehash(v); // hash function changed
12970 freeze_hide_obj(v);
12971
12972 // Overwrite the existing hash in the object list. This
12973 // is to keep the object alive during load time.
12974 // [Bug #17984] [ruby-core:104259]
12975 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12976
12977 code[code_index] = v;
12978 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12979 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12980 needs_bitmap = true;
12981 break;
12982 }
12983 case TS_ISEQ:
12984 {
12985 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12986 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12987 code[code_index] = v;
12988 if (!SPECIAL_CONST_P(v)) {
12989 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12990 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12991 needs_bitmap = true;
12992 }
12993 break;
12994 }
12995 case TS_IC:
12996 {
12997 VALUE op = ibf_load_small_value(load, &reading_pos);
12998 VALUE arr = ibf_load_object(load, op);
12999
13000 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13001 ic->segments = array_to_idlist(arr);
13002
13003 code[code_index] = (VALUE)ic;
13004 }
13005 break;
13006 case TS_ISE:
13007 case TS_ICVARC:
13008 case TS_IVC:
13009 {
13010 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13011
13012 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13013 code[code_index] = (VALUE)ic;
13014
13015 if (operand_type == TS_IVC) {
13016 IVC cache = (IVC)ic;
13017
13018 if (insn == BIN(setinstancevariable)) {
13019 ID iv_name = (ID)code[code_index - 1];
13020 cache->iv_set_name = iv_name;
13021 }
13022 else {
13023 cache->iv_set_name = 0;
13024 }
13025
13026 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13027 }
13028
13029 }
13030 break;
13031 case TS_CALLDATA:
13032 {
13033 code[code_index] = (VALUE)cd_entries++;
13034 }
13035 break;
13036 case TS_ID:
13037 {
13038 VALUE op = ibf_load_small_value(load, &reading_pos);
13039 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13040 }
13041 break;
13042 case TS_FUNCPTR:
13043 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13044 break;
13045 case TS_BUILTIN:
13046 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13047 break;
13048 default:
13049 code[code_index] = ibf_load_small_value(load, &reading_pos);
13050 continue;
13051 }
13052 }
13053 if (insn_len(insn) != op_index+1) {
13054 rb_raise(rb_eRuntimeError, "operand size mismatch");
13055 }
13056 }
13057
13058 load_body->iseq_encoded = code;
13059 load_body->iseq_size = code_index;
13060
13061 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13062 load_body->mark_bits.single = mark_offset_bits[0];
13063 }
13064 else {
13065 if (needs_bitmap) {
13066 load_body->mark_bits.list = mark_offset_bits;
13067 }
13068 else {
13069 load_body->mark_bits.list = 0;
13070 ruby_xfree(mark_offset_bits);
13071 }
13072 }
13073
13074 RUBY_ASSERT(code_index == iseq_size);
13075 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13076 return code;
13077}
13078
13079static ibf_offset_t
13080ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13081{
13082 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13083
13084 if (opt_num > 0) {
13085 IBF_W_ALIGN(VALUE);
13086 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13087 }
13088 else {
13089 return ibf_dump_pos(dump);
13090 }
13091}
13092
13093static VALUE *
13094ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13095{
13096 if (opt_num > 0) {
13097 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13098 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13099 return table;
13100 }
13101 else {
13102 return NULL;
13103 }
13104}
13105
13106static ibf_offset_t
13107ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13108{
13109 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13110
13111 if (kw) {
13112 struct rb_iseq_param_keyword dump_kw = *kw;
13113 int dv_num = kw->num - kw->required_num;
13114 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13115 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13116 int i;
13117
13118 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13119 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13120
13121 dump_kw.table = IBF_W(ids, ID, kw->num);
13122 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13123 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13124 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13125 }
13126 else {
13127 return 0;
13128 }
13129}
13130
13131static const struct rb_iseq_param_keyword *
13132ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13133{
13134 if (param_keyword_offset) {
13135 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13136 int dv_num = kw->num - kw->required_num;
13137 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13138
13139 int i;
13140 for (i=0; i<dv_num; i++) {
13141 dvs[i] = ibf_load_object(load, dvs[i]);
13142 }
13143
13144 // Will be set once the local table is loaded.
13145 kw->table = NULL;
13146
13147 kw->default_values = dvs;
13148 return kw;
13149 }
13150 else {
13151 return NULL;
13152 }
13153}
13154
13155static ibf_offset_t
13156ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13157{
13158 ibf_offset_t offset = ibf_dump_pos(dump);
13159 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13160
13161 unsigned int i;
13162 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13163 ibf_dump_write_small_value(dump, entries[i].line_no);
13164#ifdef USE_ISEQ_NODE_ID
13165 ibf_dump_write_small_value(dump, entries[i].node_id);
13166#endif
13167 ibf_dump_write_small_value(dump, entries[i].events);
13168 }
13169
13170 return offset;
13171}
13172
13173static struct iseq_insn_info_entry *
13174ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13175{
13176 ibf_offset_t reading_pos = body_offset;
13177 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13178
13179 unsigned int i;
13180 for (i = 0; i < size; i++) {
13181 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13182#ifdef USE_ISEQ_NODE_ID
13183 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13184#endif
13185 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13186 }
13187
13188 return entries;
13189}
13190
13191static ibf_offset_t
13192ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13193{
13194 ibf_offset_t offset = ibf_dump_pos(dump);
13195
13196 unsigned int last = 0;
13197 unsigned int i;
13198 for (i = 0; i < size; i++) {
13199 ibf_dump_write_small_value(dump, positions[i] - last);
13200 last = positions[i];
13201 }
13202
13203 return offset;
13204}
13205
13206static unsigned int *
13207ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13208{
13209 ibf_offset_t reading_pos = positions_offset;
13210 unsigned int *positions = ALLOC_N(unsigned int, size);
13211
13212 unsigned int last = 0;
13213 unsigned int i;
13214 for (i = 0; i < size; i++) {
13215 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13216 last = positions[i];
13217 }
13218
13219 return positions;
13220}
13221
13222static ibf_offset_t
13223ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13224{
13225 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13226 const int size = body->local_table_size;
13227 ID *table = ALLOCA_N(ID, size);
13228 int i;
13229
13230 for (i=0; i<size; i++) {
13231 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13232 if (v == 0) {
13233 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13234 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13235 }
13236 table[i] = v;
13237 }
13238
13239 IBF_W_ALIGN(ID);
13240 return ibf_dump_write(dump, table, sizeof(ID) * size);
13241}
13242
13243static ID *
13244ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13245{
13246 if (size > 0) {
13247 ID *table = IBF_R(local_table_offset, ID, size);
13248 int i;
13249
13250 for (i=0; i<size; i++) {
13251 table[i] = ibf_load_id(load, table[i]);
13252 }
13253 return table;
13254 }
13255 else {
13256 return NULL;
13257 }
13258}
13259
13260static ibf_offset_t
13261ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13262{
13263 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13264
13265 if (table) {
13266 int *iseq_indices = ALLOCA_N(int, table->size);
13267 unsigned int i;
13268
13269 for (i=0; i<table->size; i++) {
13270 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13271 }
13272
13273 const ibf_offset_t offset = ibf_dump_pos(dump);
13274
13275 for (i=0; i<table->size; i++) {
13276 ibf_dump_write_small_value(dump, iseq_indices[i]);
13277 ibf_dump_write_small_value(dump, table->entries[i].type);
13278 ibf_dump_write_small_value(dump, table->entries[i].start);
13279 ibf_dump_write_small_value(dump, table->entries[i].end);
13280 ibf_dump_write_small_value(dump, table->entries[i].cont);
13281 ibf_dump_write_small_value(dump, table->entries[i].sp);
13282 }
13283 return offset;
13284 }
13285 else {
13286 return ibf_dump_pos(dump);
13287 }
13288}
13289
13290static struct iseq_catch_table *
13291ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
13292{
13293 if (size) {
13294 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13295 table->size = size;
13296
13297 ibf_offset_t reading_pos = catch_table_offset;
13298
13299 unsigned int i;
13300 for (i=0; i<table->size; i++) {
13301 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13302 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13303 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13304 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13305 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13306 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13307
13308 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13309 }
13310 return table;
13311 }
13312 else {
13313 return NULL;
13314 }
13315}
13316
13317static ibf_offset_t
13318ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13319{
13320 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13321 const unsigned int ci_size = body->ci_size;
13322 const struct rb_call_data *cds = body->call_data;
13323
13324 ibf_offset_t offset = ibf_dump_pos(dump);
13325
13326 unsigned int i;
13327
13328 for (i = 0; i < ci_size; i++) {
13329 const struct rb_callinfo *ci = cds[i].ci;
13330 if (ci != NULL) {
13331 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13332 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13333 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13334
13335 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13336 if (kwarg) {
13337 int len = kwarg->keyword_len;
13338 ibf_dump_write_small_value(dump, len);
13339 for (int j=0; j<len; j++) {
13340 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13341 ibf_dump_write_small_value(dump, keyword);
13342 }
13343 }
13344 else {
13345 ibf_dump_write_small_value(dump, 0);
13346 }
13347 }
13348 else {
13349 // TODO: truncate NULL ci from call_data.
13350 ibf_dump_write_small_value(dump, (VALUE)-1);
13351 }
13352 }
13353
13354 return offset;
13355}
13356
13358 ID id;
13359 VALUE name;
13360 VALUE val;
13361};
13362
13364 size_t num;
13365 struct outer_variable_pair pairs[1];
13366};
13367
13368static enum rb_id_table_iterator_result
13369store_outer_variable(ID id, VALUE val, void *dump)
13370{
13371 struct outer_variable_list *ovlist = dump;
13372 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13373 pair->id = id;
13374 pair->name = rb_id2str(id);
13375 pair->val = val;
13376 return ID_TABLE_CONTINUE;
13377}
13378
13379static int
13380outer_variable_cmp(const void *a, const void *b, void *arg)
13381{
13382 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13383 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13384
13385 if (!ap->name) {
13386 return -1;
13387 } else if (!bp->name) {
13388 return 1;
13389 }
13390
13391 return rb_str_cmp(ap->name, bp->name);
13392}
13393
13394static ibf_offset_t
13395ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13396{
13397 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13398
13399 ibf_offset_t offset = ibf_dump_pos(dump);
13400
13401 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13402 ibf_dump_write_small_value(dump, (VALUE)size);
13403 if (size > 0) {
13404 VALUE buff;
13405 size_t buffsize =
13406 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13407 offsetof(struct outer_variable_list, pairs),
13408 rb_eArgError);
13409 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13410 ovlist->num = 0;
13411 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13412 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13413 for (size_t i = 0; i < size; ++i) {
13414 ID id = ovlist->pairs[i].id;
13415 ID val = ovlist->pairs[i].val;
13416 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13417 ibf_dump_write_small_value(dump, val);
13418 }
13419 }
13420
13421 return offset;
13422}
13423
13424/* note that we dump out rb_call_info but load back rb_call_data */
13425static void
13426ibf_load_ci_entries(const struct ibf_load *load,
13427 ibf_offset_t ci_entries_offset,
13428 unsigned int ci_size,
13429 struct rb_call_data **cd_ptr)
13430{
13431 if (!ci_size) {
13432 *cd_ptr = NULL;
13433 return;
13434 }
13435
13436 ibf_offset_t reading_pos = ci_entries_offset;
13437
13438 unsigned int i;
13439
13440 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13441 *cd_ptr = cds;
13442
13443 for (i = 0; i < ci_size; i++) {
13444 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13445 if (mid_index != (VALUE)-1) {
13446 ID mid = ibf_load_id(load, mid_index);
13447 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13448 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13449
13450 struct rb_callinfo_kwarg *kwarg = NULL;
13451 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13452 if (kwlen > 0) {
13453 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13454 kwarg->references = 0;
13455 kwarg->keyword_len = kwlen;
13456 for (int j=0; j<kwlen; j++) {
13457 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13458 kwarg->keywords[j] = ibf_load_object(load, keyword);
13459 }
13460 }
13461
13462 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13463 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13464 cds[i].cc = vm_cc_empty();
13465 }
13466 else {
13467 // NULL ci
13468 cds[i].ci = NULL;
13469 cds[i].cc = NULL;
13470 }
13471 }
13472}
13473
13474static struct rb_id_table *
13475ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13476{
13477 ibf_offset_t reading_pos = outer_variables_offset;
13478
13479 struct rb_id_table *tbl = NULL;
13480
13481 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13482
13483 if (table_size > 0) {
13484 tbl = rb_id_table_create(table_size);
13485 }
13486
13487 for (size_t i = 0; i < table_size; i++) {
13488 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13489 VALUE value = ibf_load_small_value(load, &reading_pos);
13490 if (!key) key = rb_make_temporary_id(i);
13491 rb_id_table_insert(tbl, key, value);
13492 }
13493
13494 return tbl;
13495}
13496
13497static ibf_offset_t
13498ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13499{
13500 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13501
13502 unsigned int *positions;
13503
13504 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13505
13506 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13507 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13508 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13509
13510#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13511 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13512
13513 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13514 struct ibf_dump_buffer buffer;
13515 buffer.str = rb_str_new(0, 0);
13516 buffer.obj_table = ibf_dump_object_table_new();
13517 dump->current_buffer = &buffer;
13518#endif
13519
13520 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13521 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13522 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13523 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13524 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13525
13526 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13527 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13528 ruby_xfree(positions);
13529
13530 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13531 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13532 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13533 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13534 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13535 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13536 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13537 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13538
13539#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13540 ibf_offset_t local_obj_list_offset;
13541 unsigned int local_obj_list_size;
13542
13543 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13544#endif
13545
13546 ibf_offset_t body_offset = ibf_dump_pos(dump);
13547
13548 /* dump the constant body */
13549 unsigned int param_flags =
13550 (body->param.flags.has_lead << 0) |
13551 (body->param.flags.has_opt << 1) |
13552 (body->param.flags.has_rest << 2) |
13553 (body->param.flags.has_post << 3) |
13554 (body->param.flags.has_kw << 4) |
13555 (body->param.flags.has_kwrest << 5) |
13556 (body->param.flags.has_block << 6) |
13557 (body->param.flags.ambiguous_param0 << 7) |
13558 (body->param.flags.accepts_no_kwarg << 8) |
13559 (body->param.flags.ruby2_keywords << 9) |
13560 (body->param.flags.anon_rest << 10) |
13561 (body->param.flags.anon_kwrest << 11) |
13562 (body->param.flags.use_block << 12) |
13563 (body->param.flags.forwardable << 13) ;
13564
13565#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13566# define IBF_BODY_OFFSET(x) (x)
13567#else
13568# define IBF_BODY_OFFSET(x) (body_offset - (x))
13569#endif
13570
13571 ibf_dump_write_small_value(dump, body->type);
13572 ibf_dump_write_small_value(dump, body->iseq_size);
13573 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13574 ibf_dump_write_small_value(dump, bytecode_size);
13575 ibf_dump_write_small_value(dump, param_flags);
13576 ibf_dump_write_small_value(dump, body->param.size);
13577 ibf_dump_write_small_value(dump, body->param.lead_num);
13578 ibf_dump_write_small_value(dump, body->param.opt_num);
13579 ibf_dump_write_small_value(dump, body->param.rest_start);
13580 ibf_dump_write_small_value(dump, body->param.post_start);
13581 ibf_dump_write_small_value(dump, body->param.post_num);
13582 ibf_dump_write_small_value(dump, body->param.block_start);
13583 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13584 ibf_dump_write_small_value(dump, param_keyword_offset);
13585 ibf_dump_write_small_value(dump, location_pathobj_index);
13586 ibf_dump_write_small_value(dump, location_base_label_index);
13587 ibf_dump_write_small_value(dump, location_label_index);
13588 ibf_dump_write_small_value(dump, body->location.first_lineno);
13589 ibf_dump_write_small_value(dump, body->location.node_id);
13590 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13591 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13592 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13593 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13594 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13595 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13596 ibf_dump_write_small_value(dump, body->insns_info.size);
13597 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13598 ibf_dump_write_small_value(dump, catch_table_size);
13599 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13600 ibf_dump_write_small_value(dump, parent_iseq_index);
13601 ibf_dump_write_small_value(dump, local_iseq_index);
13602 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13603 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13604 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13605 ibf_dump_write_small_value(dump, body->variable.flip_count);
13606 ibf_dump_write_small_value(dump, body->local_table_size);
13607 ibf_dump_write_small_value(dump, body->ivc_size);
13608 ibf_dump_write_small_value(dump, body->icvarc_size);
13609 ibf_dump_write_small_value(dump, body->ise_size);
13610 ibf_dump_write_small_value(dump, body->ic_size);
13611 ibf_dump_write_small_value(dump, body->ci_size);
13612 ibf_dump_write_small_value(dump, body->stack_max);
13613 ibf_dump_write_small_value(dump, body->builtin_attrs);
13614 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13615
13616#undef IBF_BODY_OFFSET
13617
13618#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13619 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13620
13621 dump->current_buffer = saved_buffer;
13622 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13623
13624 ibf_offset_t offset = ibf_dump_pos(dump);
13625 ibf_dump_write_small_value(dump, iseq_start);
13626 ibf_dump_write_small_value(dump, iseq_length_bytes);
13627 ibf_dump_write_small_value(dump, body_offset);
13628
13629 ibf_dump_write_small_value(dump, local_obj_list_offset);
13630 ibf_dump_write_small_value(dump, local_obj_list_size);
13631
13632 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13633
13634 return offset;
13635#else
13636 return body_offset;
13637#endif
13638}
13639
13640static VALUE
13641ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13642{
13643 VALUE str = ibf_load_object(load, str_index);
13644 if (str != Qnil) {
13645 str = rb_fstring(str);
13646 }
13647 return str;
13648}
13649
13650static void
13651ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13652{
13653 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13654
13655 ibf_offset_t reading_pos = offset;
13656
13657#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13658 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13659 load->current_buffer = &load->global_buffer;
13660
13661 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13662 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13663 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13664
13665 struct ibf_load_buffer buffer;
13666 buffer.buff = load->global_buffer.buff + iseq_start;
13667 buffer.size = iseq_length_bytes;
13668 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13669 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13670 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13671
13672 load->current_buffer = &buffer;
13673 reading_pos = body_offset;
13674#endif
13675
13676#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13677# define IBF_BODY_OFFSET(x) (x)
13678#else
13679# define IBF_BODY_OFFSET(x) (offset - (x))
13680#endif
13681
13682 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13683 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13684 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13685 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13686 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13687 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13688 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13689 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13690 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13691 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13692 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13693 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13694 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13695 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13696 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13697 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13698 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13699 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13700 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13701 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13702 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13703 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13704 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13705 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13706 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13707 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13708 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13709 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13710 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13711 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13712 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13713 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13714 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13715 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13716 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13717 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13718
13719 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13720 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13721 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13722 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13723
13724 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13725 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13726 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13727 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13728
13729 // setup fname and dummy frame
13730 VALUE path = ibf_load_object(load, location_pathobj_index);
13731 {
13732 VALUE realpath = Qnil;
13733
13734 if (RB_TYPE_P(path, T_STRING)) {
13735 realpath = path = rb_fstring(path);
13736 }
13737 else if (RB_TYPE_P(path, T_ARRAY)) {
13738 VALUE pathobj = path;
13739 if (RARRAY_LEN(pathobj) != 2) {
13740 rb_raise(rb_eRuntimeError, "path object size mismatch");
13741 }
13742 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13743 realpath = RARRAY_AREF(pathobj, 1);
13744 if (!NIL_P(realpath)) {
13745 if (!RB_TYPE_P(realpath, T_STRING)) {
13746 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13747 "(%x), path=%+"PRIsVALUE,
13748 realpath, TYPE(realpath), path);
13749 }
13750 realpath = rb_fstring(realpath);
13751 }
13752 }
13753 else {
13754 rb_raise(rb_eRuntimeError, "unexpected path object");
13755 }
13756 rb_iseq_pathobj_set(iseq, path, realpath);
13757 }
13758
13759 // push dummy frame
13760 rb_execution_context_t *ec = GET_EC();
13761 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13762
13763#undef IBF_BODY_OFFSET
13764
13765 load_body->type = type;
13766 load_body->stack_max = stack_max;
13767 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13768 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13769 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13770 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13771 load_body->param.flags.has_kw = FALSE;
13772 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13773 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13774 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13775 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13776 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13777 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13778 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13779 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13780 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13781 load_body->param.size = param_size;
13782 load_body->param.lead_num = param_lead_num;
13783 load_body->param.opt_num = param_opt_num;
13784 load_body->param.rest_start = param_rest_start;
13785 load_body->param.post_start = param_post_start;
13786 load_body->param.post_num = param_post_num;
13787 load_body->param.block_start = param_block_start;
13788 load_body->local_table_size = local_table_size;
13789 load_body->ci_size = ci_size;
13790 load_body->insns_info.size = insns_info_size;
13791
13792 ISEQ_COVERAGE_SET(iseq, Qnil);
13793 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13794 load_body->variable.flip_count = variable_flip_count;
13795 load_body->variable.script_lines = Qnil;
13796
13797 load_body->location.first_lineno = location_first_lineno;
13798 load_body->location.node_id = location_node_id;
13799 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13800 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13801 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13802 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13803 load_body->builtin_attrs = builtin_attrs;
13804 load_body->prism = prism;
13805
13806 load_body->ivc_size = ivc_size;
13807 load_body->icvarc_size = icvarc_size;
13808 load_body->ise_size = ise_size;
13809 load_body->ic_size = ic_size;
13810
13811 if (ISEQ_IS_SIZE(load_body)) {
13812 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13813 }
13814 else {
13815 load_body->is_entries = NULL;
13816 }
13817 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13818 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13819 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13820 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13821 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13822 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13823 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13824 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13825 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
13826 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13827 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13828 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13829
13830 // This must be done after the local table is loaded.
13831 if (load_body->param.keyword != NULL) {
13832 RUBY_ASSERT(load_body->local_table);
13833 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13834 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13835 }
13836
13837 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13838#if VM_INSN_INFO_TABLE_IMPL == 2
13839 rb_iseq_insns_info_encode_positions(iseq);
13840#endif
13841
13842 rb_iseq_translate_threaded_code(iseq);
13843
13844#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13845 load->current_buffer = &load->global_buffer;
13846#endif
13847
13848 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13849 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13850
13851#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13852 load->current_buffer = saved_buffer;
13853#endif
13854 verify_call_cache(iseq);
13855
13856 RB_GC_GUARD(dummy_frame);
13857 rb_vm_pop_frame_no_int(ec);
13858}
13859
13861{
13862 struct ibf_dump *dump;
13863 VALUE offset_list;
13864};
13865
13866static int
13867ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13868{
13869 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13870 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13871
13872 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13873 rb_ary_push(args->offset_list, UINT2NUM(offset));
13874
13875 return ST_CONTINUE;
13876}
13877
13878static void
13879ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13880{
13881 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13882
13883 struct ibf_dump_iseq_list_arg args;
13884 args.dump = dump;
13885 args.offset_list = offset_list;
13886
13887 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13888
13889 st_index_t i;
13890 st_index_t size = dump->iseq_table->num_entries;
13891 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13892
13893 for (i = 0; i < size; i++) {
13894 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13895 }
13896
13897 ibf_dump_align(dump, sizeof(ibf_offset_t));
13898 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13899 header->iseq_list_size = (unsigned int)size;
13900}
13901
13902#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13903
13904/*
13905 * Binary format
13906 * - ibf_object_header
13907 * - ibf_object_xxx (xxx is type)
13908 */
13909
13911 unsigned int type: 5;
13912 unsigned int special_const: 1;
13913 unsigned int frozen: 1;
13914 unsigned int internal: 1;
13915};
13916
13917enum ibf_object_class_index {
13918 IBF_OBJECT_CLASS_OBJECT,
13919 IBF_OBJECT_CLASS_ARRAY,
13920 IBF_OBJECT_CLASS_STANDARD_ERROR,
13921 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13922 IBF_OBJECT_CLASS_TYPE_ERROR,
13923 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13924};
13925
13927 long srcstr;
13928 char option;
13929};
13930
13932 long len;
13933 long keyval[FLEX_ARY_LEN];
13934};
13935
13937 long class_index;
13938 long len;
13939 long beg;
13940 long end;
13941 int excl;
13942};
13943
13945 ssize_t slen;
13946 BDIGIT digits[FLEX_ARY_LEN];
13947};
13948
13949enum ibf_object_data_type {
13950 IBF_OBJECT_DATA_ENCODING,
13951};
13952
13954 long a, b;
13955};
13956
13958 long str;
13959};
13960
13961#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13962 ((((offset) - 1) / (align) + 1) * (align))
13963#define IBF_OBJBODY(type, offset) (const type *)\
13964 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13965
13966static const void *
13967ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13968{
13969 if (offset >= load->current_buffer->size) {
13970 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13971 }
13972 return load->current_buffer->buff + offset;
13973}
13974
13975NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13976
13977static void
13978ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13979{
13980 char buff[0x100];
13981 rb_raw_obj_info(buff, sizeof(buff), obj);
13982 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13983}
13984
13985NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13986
13987static VALUE
13988ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13989{
13990 rb_raise(rb_eArgError, "unsupported");
13992}
13993
13994static void
13995ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13996{
13997 enum ibf_object_class_index cindex;
13998 if (obj == rb_cObject) {
13999 cindex = IBF_OBJECT_CLASS_OBJECT;
14000 }
14001 else if (obj == rb_cArray) {
14002 cindex = IBF_OBJECT_CLASS_ARRAY;
14003 }
14004 else if (obj == rb_eStandardError) {
14005 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14006 }
14007 else if (obj == rb_eNoMatchingPatternError) {
14008 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14009 }
14010 else if (obj == rb_eTypeError) {
14011 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14012 }
14013 else if (obj == rb_eNoMatchingPatternKeyError) {
14014 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14015 }
14016 else {
14017 rb_obj_info_dump(obj);
14018 rb_p(obj);
14019 rb_bug("unsupported class");
14020 }
14021 ibf_dump_write_small_value(dump, (VALUE)cindex);
14022}
14023
14024static VALUE
14025ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14026{
14027 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14028
14029 switch (cindex) {
14030 case IBF_OBJECT_CLASS_OBJECT:
14031 return rb_cObject;
14032 case IBF_OBJECT_CLASS_ARRAY:
14033 return rb_cArray;
14034 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14035 return rb_eStandardError;
14036 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14038 case IBF_OBJECT_CLASS_TYPE_ERROR:
14039 return rb_eTypeError;
14040 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14042 }
14043
14044 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14045}
14046
14047
14048static void
14049ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14050{
14051 double dbl = RFLOAT_VALUE(obj);
14052 (void)IBF_W(&dbl, double, 1);
14053}
14054
14055static VALUE
14056ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14057{
14058 const double *dblp = IBF_OBJBODY(double, offset);
14059 return DBL2NUM(*dblp);
14060}
14061
14062static void
14063ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14064{
14065 long encindex = (long)rb_enc_get_index(obj);
14066 long len = RSTRING_LEN(obj);
14067 const char *ptr = RSTRING_PTR(obj);
14068
14069 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14070 rb_encoding *enc = rb_enc_from_index((int)encindex);
14071 const char *enc_name = rb_enc_name(enc);
14072 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14073 }
14074
14075 ibf_dump_write_small_value(dump, encindex);
14076 ibf_dump_write_small_value(dump, len);
14077 IBF_WP(ptr, char, len);
14078}
14079
14080static VALUE
14081ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14082{
14083 ibf_offset_t reading_pos = offset;
14084
14085 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14086 const long len = (long)ibf_load_small_value(load, &reading_pos);
14087 const char *ptr = load->current_buffer->buff + reading_pos;
14088
14089 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14090 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14091 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14092 }
14093
14094 VALUE str;
14095 if (header->frozen && !header->internal) {
14096 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14097 }
14098 else {
14099 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14100
14101 if (header->internal) rb_obj_hide(str);
14102 if (header->frozen) str = rb_fstring(str);
14103 }
14104 return str;
14105}
14106
14107static void
14108ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14109{
14110 VALUE srcstr = RREGEXP_SRC(obj);
14111 struct ibf_object_regexp regexp;
14112 regexp.option = (char)rb_reg_options(obj);
14113 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14114
14115 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14116 ibf_dump_write_small_value(dump, regexp.srcstr);
14117}
14118
14119static VALUE
14120ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14121{
14122 struct ibf_object_regexp regexp;
14123 regexp.option = ibf_load_byte(load, &offset);
14124 regexp.srcstr = ibf_load_small_value(load, &offset);
14125
14126 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14127 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14128
14129 if (header->internal) rb_obj_hide(reg);
14130 if (header->frozen) rb_obj_freeze(reg);
14131
14132 return reg;
14133}
14134
14135static void
14136ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14137{
14138 long i, len = RARRAY_LEN(obj);
14139 ibf_dump_write_small_value(dump, len);
14140 for (i=0; i<len; i++) {
14141 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14142 ibf_dump_write_small_value(dump, index);
14143 }
14144}
14145
14146static VALUE
14147ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14148{
14149 ibf_offset_t reading_pos = offset;
14150
14151 const long len = (long)ibf_load_small_value(load, &reading_pos);
14152
14153 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14154 int i;
14155
14156 for (i=0; i<len; i++) {
14157 const VALUE index = ibf_load_small_value(load, &reading_pos);
14158 rb_ary_push(ary, ibf_load_object(load, index));
14159 }
14160
14161 if (header->frozen) rb_ary_freeze(ary);
14162
14163 return ary;
14164}
14165
14166static int
14167ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14168{
14169 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14170
14171 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14172 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14173
14174 ibf_dump_write_small_value(dump, key_index);
14175 ibf_dump_write_small_value(dump, val_index);
14176 return ST_CONTINUE;
14177}
14178
14179static void
14180ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14181{
14182 long len = RHASH_SIZE(obj);
14183 ibf_dump_write_small_value(dump, (VALUE)len);
14184
14185 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14186}
14187
14188static VALUE
14189ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14190{
14191 long len = (long)ibf_load_small_value(load, &offset);
14192 VALUE obj = rb_hash_new_with_size(len);
14193 int i;
14194
14195 for (i = 0; i < len; i++) {
14196 VALUE key_index = ibf_load_small_value(load, &offset);
14197 VALUE val_index = ibf_load_small_value(load, &offset);
14198
14199 VALUE key = ibf_load_object(load, key_index);
14200 VALUE val = ibf_load_object(load, val_index);
14201 rb_hash_aset(obj, key, val);
14202 }
14203 rb_hash_rehash(obj);
14204
14205 if (header->internal) rb_obj_hide(obj);
14206 if (header->frozen) rb_obj_freeze(obj);
14207
14208 return obj;
14209}
14210
14211static void
14212ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14213{
14214 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14215 struct ibf_object_struct_range range;
14216 VALUE beg, end;
14217 IBF_ZERO(range);
14218 range.len = 3;
14219 range.class_index = 0;
14220
14221 rb_range_values(obj, &beg, &end, &range.excl);
14222 range.beg = (long)ibf_dump_object(dump, beg);
14223 range.end = (long)ibf_dump_object(dump, end);
14224
14225 IBF_W_ALIGN(struct ibf_object_struct_range);
14226 IBF_WV(range);
14227 }
14228 else {
14229 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14230 rb_class_name(CLASS_OF(obj)));
14231 }
14232}
14233
14234static VALUE
14235ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14236{
14237 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14238 VALUE beg = ibf_load_object(load, range->beg);
14239 VALUE end = ibf_load_object(load, range->end);
14240 VALUE obj = rb_range_new(beg, end, range->excl);
14241 if (header->internal) rb_obj_hide(obj);
14242 if (header->frozen) rb_obj_freeze(obj);
14243 return obj;
14244}
14245
14246static void
14247ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14248{
14249 ssize_t len = BIGNUM_LEN(obj);
14250 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14251 BDIGIT *d = BIGNUM_DIGITS(obj);
14252
14253 (void)IBF_W(&slen, ssize_t, 1);
14254 IBF_WP(d, BDIGIT, len);
14255}
14256
14257static VALUE
14258ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14259{
14260 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14261 int sign = bignum->slen > 0;
14262 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14263 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14266 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14267 big_unpack_flags |
14268 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14269 if (header->internal) rb_obj_hide(obj);
14270 if (header->frozen) rb_obj_freeze(obj);
14271 return obj;
14272}
14273
14274static void
14275ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14276{
14277 if (rb_data_is_encoding(obj)) {
14278 rb_encoding *enc = rb_to_encoding(obj);
14279 const char *name = rb_enc_name(enc);
14280 long len = strlen(name) + 1;
14281 long data[2];
14282 data[0] = IBF_OBJECT_DATA_ENCODING;
14283 data[1] = len;
14284 (void)IBF_W(data, long, 2);
14285 IBF_WP(name, char, len);
14286 }
14287 else {
14288 ibf_dump_object_unsupported(dump, obj);
14289 }
14290}
14291
14292static VALUE
14293ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14294{
14295 const long *body = IBF_OBJBODY(long, offset);
14296 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14297 /* const long len = body[1]; */
14298 const char *data = (const char *)&body[2];
14299
14300 switch (type) {
14301 case IBF_OBJECT_DATA_ENCODING:
14302 {
14303 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14304 return encobj;
14305 }
14306 }
14307
14308 return ibf_load_object_unsupported(load, header, offset);
14309}
14310
14311static void
14312ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14313{
14314 long data[2];
14315 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14316 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14317
14318 (void)IBF_W(data, long, 2);
14319}
14320
14321static VALUE
14322ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14323{
14324 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14325 VALUE a = ibf_load_object(load, nums->a);
14326 VALUE b = ibf_load_object(load, nums->b);
14327 VALUE obj = header->type == T_COMPLEX ?
14328 rb_complex_new(a, b) : rb_rational_new(a, b);
14329
14330 if (header->internal) rb_obj_hide(obj);
14331 if (header->frozen) rb_obj_freeze(obj);
14332 return obj;
14333}
14334
14335static void
14336ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14337{
14338 ibf_dump_object_string(dump, rb_sym2str(obj));
14339}
14340
14341static VALUE
14342ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14343{
14344 ibf_offset_t reading_pos = offset;
14345
14346 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14347 const long len = (long)ibf_load_small_value(load, &reading_pos);
14348 const char *ptr = load->current_buffer->buff + reading_pos;
14349
14350 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14351 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14352 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14353 }
14354
14355 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14356 return ID2SYM(id);
14357}
14358
14359typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14360static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14361 ibf_dump_object_unsupported, /* T_NONE */
14362 ibf_dump_object_unsupported, /* T_OBJECT */
14363 ibf_dump_object_class, /* T_CLASS */
14364 ibf_dump_object_unsupported, /* T_MODULE */
14365 ibf_dump_object_float, /* T_FLOAT */
14366 ibf_dump_object_string, /* T_STRING */
14367 ibf_dump_object_regexp, /* T_REGEXP */
14368 ibf_dump_object_array, /* T_ARRAY */
14369 ibf_dump_object_hash, /* T_HASH */
14370 ibf_dump_object_struct, /* T_STRUCT */
14371 ibf_dump_object_bignum, /* T_BIGNUM */
14372 ibf_dump_object_unsupported, /* T_FILE */
14373 ibf_dump_object_data, /* T_DATA */
14374 ibf_dump_object_unsupported, /* T_MATCH */
14375 ibf_dump_object_complex_rational, /* T_COMPLEX */
14376 ibf_dump_object_complex_rational, /* T_RATIONAL */
14377 ibf_dump_object_unsupported, /* 0x10 */
14378 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14379 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14380 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14381 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14382 ibf_dump_object_unsupported, /* T_FIXNUM */
14383 ibf_dump_object_unsupported, /* T_UNDEF */
14384 ibf_dump_object_unsupported, /* 0x17 */
14385 ibf_dump_object_unsupported, /* 0x18 */
14386 ibf_dump_object_unsupported, /* 0x19 */
14387 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14388 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14389 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14390 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14391 ibf_dump_object_unsupported, /* 0x1e */
14392 ibf_dump_object_unsupported, /* 0x1f */
14393};
14394
14395static void
14396ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14397{
14398 unsigned char byte =
14399 (header.type << 0) |
14400 (header.special_const << 5) |
14401 (header.frozen << 6) |
14402 (header.internal << 7);
14403
14404 IBF_WV(byte);
14405}
14406
14407static struct ibf_object_header
14408ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14409{
14410 unsigned char byte = ibf_load_byte(load, offset);
14411
14412 struct ibf_object_header header;
14413 header.type = (byte >> 0) & 0x1f;
14414 header.special_const = (byte >> 5) & 0x01;
14415 header.frozen = (byte >> 6) & 0x01;
14416 header.internal = (byte >> 7) & 0x01;
14417
14418 return header;
14419}
14420
14421static ibf_offset_t
14422ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14423{
14424 struct ibf_object_header obj_header;
14425 ibf_offset_t current_offset;
14426 IBF_ZERO(obj_header);
14427 obj_header.type = TYPE(obj);
14428
14429 IBF_W_ALIGN(ibf_offset_t);
14430 current_offset = ibf_dump_pos(dump);
14431
14432 if (SPECIAL_CONST_P(obj) &&
14433 ! (SYMBOL_P(obj) ||
14434 RB_FLOAT_TYPE_P(obj))) {
14435 obj_header.special_const = TRUE;
14436 obj_header.frozen = TRUE;
14437 obj_header.internal = TRUE;
14438 ibf_dump_object_object_header(dump, obj_header);
14439 ibf_dump_write_small_value(dump, obj);
14440 }
14441 else {
14442 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14443 obj_header.special_const = FALSE;
14444 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14445 ibf_dump_object_object_header(dump, obj_header);
14446 (*dump_object_functions[obj_header.type])(dump, obj);
14447 }
14448
14449 return current_offset;
14450}
14451
14452typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14453static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14454 ibf_load_object_unsupported, /* T_NONE */
14455 ibf_load_object_unsupported, /* T_OBJECT */
14456 ibf_load_object_class, /* T_CLASS */
14457 ibf_load_object_unsupported, /* T_MODULE */
14458 ibf_load_object_float, /* T_FLOAT */
14459 ibf_load_object_string, /* T_STRING */
14460 ibf_load_object_regexp, /* T_REGEXP */
14461 ibf_load_object_array, /* T_ARRAY */
14462 ibf_load_object_hash, /* T_HASH */
14463 ibf_load_object_struct, /* T_STRUCT */
14464 ibf_load_object_bignum, /* T_BIGNUM */
14465 ibf_load_object_unsupported, /* T_FILE */
14466 ibf_load_object_data, /* T_DATA */
14467 ibf_load_object_unsupported, /* T_MATCH */
14468 ibf_load_object_complex_rational, /* T_COMPLEX */
14469 ibf_load_object_complex_rational, /* T_RATIONAL */
14470 ibf_load_object_unsupported, /* 0x10 */
14471 ibf_load_object_unsupported, /* T_NIL */
14472 ibf_load_object_unsupported, /* T_TRUE */
14473 ibf_load_object_unsupported, /* T_FALSE */
14474 ibf_load_object_symbol,
14475 ibf_load_object_unsupported, /* T_FIXNUM */
14476 ibf_load_object_unsupported, /* T_UNDEF */
14477 ibf_load_object_unsupported, /* 0x17 */
14478 ibf_load_object_unsupported, /* 0x18 */
14479 ibf_load_object_unsupported, /* 0x19 */
14480 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14481 ibf_load_object_unsupported, /* T_NODE 0x1b */
14482 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14483 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14484 ibf_load_object_unsupported, /* 0x1e */
14485 ibf_load_object_unsupported, /* 0x1f */
14486};
14487
14488static VALUE
14489ibf_load_object(const struct ibf_load *load, VALUE object_index)
14490{
14491 if (object_index == 0) {
14492 return Qnil;
14493 }
14494 else {
14495 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14496 if (!obj) {
14497 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14498 ibf_offset_t offset = offsets[object_index];
14499 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14500
14501#if IBF_ISEQ_DEBUG
14502 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14503 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14504 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14505 header.type, header.special_const, header.frozen, header.internal);
14506#endif
14507 if (offset >= load->current_buffer->size) {
14508 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14509 }
14510
14511 if (header.special_const) {
14512 ibf_offset_t reading_pos = offset;
14513
14514 obj = ibf_load_small_value(load, &reading_pos);
14515 }
14516 else {
14517 obj = (*load_object_functions[header.type])(load, &header, offset);
14518 }
14519
14520 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14521 }
14522#if IBF_ISEQ_DEBUG
14523 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14524 object_index, obj);
14525#endif
14526 return obj;
14527 }
14528}
14529
14531{
14532 struct ibf_dump *dump;
14533 VALUE offset_list;
14534};
14535
14536static int
14537ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14538{
14539 VALUE obj = (VALUE)key;
14540 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14541
14542 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14543 rb_ary_push(args->offset_list, UINT2NUM(offset));
14544
14545 return ST_CONTINUE;
14546}
14547
14548static void
14549ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14550{
14551 st_table *obj_table = dump->current_buffer->obj_table;
14552 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14553
14554 struct ibf_dump_object_list_arg args;
14555 args.dump = dump;
14556 args.offset_list = offset_list;
14557
14558 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14559
14560 IBF_W_ALIGN(ibf_offset_t);
14561 *obj_list_offset = ibf_dump_pos(dump);
14562
14563 st_index_t size = obj_table->num_entries;
14564 st_index_t i;
14565
14566 for (i=0; i<size; i++) {
14567 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14568 IBF_WV(offset);
14569 }
14570
14571 *obj_list_size = (unsigned int)size;
14572}
14573
14574static void
14575ibf_dump_mark(void *ptr)
14576{
14577 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14578 rb_gc_mark(dump->global_buffer.str);
14579
14580 rb_mark_set(dump->global_buffer.obj_table);
14581 rb_mark_set(dump->iseq_table);
14582}
14583
14584static void
14585ibf_dump_free(void *ptr)
14586{
14587 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14588 if (dump->global_buffer.obj_table) {
14589 st_free_table(dump->global_buffer.obj_table);
14590 dump->global_buffer.obj_table = 0;
14591 }
14592 if (dump->iseq_table) {
14593 st_free_table(dump->iseq_table);
14594 dump->iseq_table = 0;
14595 }
14596}
14597
14598static size_t
14599ibf_dump_memsize(const void *ptr)
14600{
14601 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14602 size_t size = 0;
14603 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14604 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14605 return size;
14606}
14607
14608static const rb_data_type_t ibf_dump_type = {
14609 "ibf_dump",
14610 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14611 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14612};
14613
14614static void
14615ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14616{
14617 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14618 dump->iseq_table = NULL;
14619
14620 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14621 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14622 dump->iseq_table = st_init_numtable(); /* need free */
14623
14624 dump->current_buffer = &dump->global_buffer;
14625}
14626
14627VALUE
14628rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14629{
14630 struct ibf_dump *dump;
14631 struct ibf_header header = {{0}};
14632 VALUE dump_obj;
14633 VALUE str;
14634
14635 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14636 ISEQ_BODY(iseq)->local_iseq != iseq) {
14637 rb_raise(rb_eRuntimeError, "should be top of iseq");
14638 }
14639 if (RTEST(ISEQ_COVERAGE(iseq))) {
14640 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14641 }
14642
14643 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14644 ibf_dump_setup(dump, dump_obj);
14645
14646 ibf_dump_write(dump, &header, sizeof(header));
14647 ibf_dump_iseq(dump, iseq);
14648
14649 header.magic[0] = 'Y'; /* YARB */
14650 header.magic[1] = 'A';
14651 header.magic[2] = 'R';
14652 header.magic[3] = 'B';
14653 header.major_version = IBF_MAJOR_VERSION;
14654 header.minor_version = IBF_MINOR_VERSION;
14655 header.endian = IBF_ENDIAN_MARK;
14656 header.wordsize = (uint8_t)SIZEOF_VALUE;
14657 ibf_dump_iseq_list(dump, &header);
14658 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14659 header.size = ibf_dump_pos(dump);
14660
14661 if (RTEST(opt)) {
14662 VALUE opt_str = opt;
14663 const char *ptr = StringValuePtr(opt_str);
14664 header.extra_size = RSTRING_LENINT(opt_str);
14665 ibf_dump_write(dump, ptr, header.extra_size);
14666 }
14667 else {
14668 header.extra_size = 0;
14669 }
14670
14671 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14672
14673 str = dump->global_buffer.str;
14674 RB_GC_GUARD(dump_obj);
14675 return str;
14676}
14677
14678static const ibf_offset_t *
14679ibf_iseq_list(const struct ibf_load *load)
14680{
14681 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14682}
14683
14684void
14685rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14686{
14687 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14688 rb_iseq_t *prev_src_iseq = load->iseq;
14689 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14690 load->iseq = iseq;
14691#if IBF_ISEQ_DEBUG
14692 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14693 iseq->aux.loader.index, offset,
14694 load->header->size);
14695#endif
14696 ibf_load_iseq_each(load, iseq, offset);
14697 ISEQ_COMPILE_DATA_CLEAR(iseq);
14698 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14699 rb_iseq_init_trace(iseq);
14700 load->iseq = prev_src_iseq;
14701}
14702
14703#if USE_LAZY_LOAD
14704const rb_iseq_t *
14705rb_iseq_complete(const rb_iseq_t *iseq)
14706{
14707 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14708 return iseq;
14709}
14710#endif
14711
14712static rb_iseq_t *
14713ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14714{
14715 int iseq_index = (int)(VALUE)index_iseq;
14716
14717#if IBF_ISEQ_DEBUG
14718 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14719 (void *)index_iseq, (void *)load->iseq_list);
14720#endif
14721 if (iseq_index == -1) {
14722 return NULL;
14723 }
14724 else {
14725 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14726
14727#if IBF_ISEQ_DEBUG
14728 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14729#endif
14730 if (iseqv) {
14731 return (rb_iseq_t *)iseqv;
14732 }
14733 else {
14734 rb_iseq_t *iseq = iseq_imemo_alloc();
14735#if IBF_ISEQ_DEBUG
14736 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14737#endif
14738 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14739 iseq->aux.loader.obj = load->loader_obj;
14740 iseq->aux.loader.index = iseq_index;
14741#if IBF_ISEQ_DEBUG
14742 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14743 (void *)iseq, (void *)load->loader_obj, iseq_index);
14744#endif
14745 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14746
14747 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14748#if IBF_ISEQ_DEBUG
14749 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14750#endif
14751 rb_ibf_load_iseq_complete(iseq);
14752 }
14753
14754#if IBF_ISEQ_DEBUG
14755 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14756 (void *)iseq, (void *)load->iseq);
14757#endif
14758 return iseq;
14759 }
14760 }
14761}
14762
14763static void
14764ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14765{
14766 struct ibf_header *header = (struct ibf_header *)bytes;
14767 load->loader_obj = loader_obj;
14768 load->global_buffer.buff = bytes;
14769 load->header = header;
14770 load->global_buffer.size = header->size;
14771 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14772 load->global_buffer.obj_list_size = header->global_object_list_size;
14773 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14774 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14775 load->iseq = NULL;
14776
14777 load->current_buffer = &load->global_buffer;
14778
14779 if (size < header->size) {
14780 rb_raise(rb_eRuntimeError, "broken binary format");
14781 }
14782 if (strncmp(header->magic, "YARB", 4) != 0) {
14783 rb_raise(rb_eRuntimeError, "unknown binary format");
14784 }
14785 if (header->major_version != IBF_MAJOR_VERSION ||
14786 header->minor_version != IBF_MINOR_VERSION) {
14787 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14788 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14789 }
14790 if (header->endian != IBF_ENDIAN_MARK) {
14791 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14792 }
14793 if (header->wordsize != SIZEOF_VALUE) {
14794 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14795 }
14796 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14797 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14798 header->iseq_list_offset);
14799 }
14800 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14801 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14802 load->global_buffer.obj_list_offset);
14803 }
14804}
14805
14806static void
14807ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14808{
14809 StringValue(str);
14810
14811 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14812 rb_raise(rb_eRuntimeError, "broken binary format");
14813 }
14814
14815 if (USE_LAZY_LOAD) {
14816 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14817 }
14818
14819 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14820 RB_OBJ_WRITE(loader_obj, &load->str, str);
14821}
14822
14823static void
14824ibf_loader_mark(void *ptr)
14825{
14826 struct ibf_load *load = (struct ibf_load *)ptr;
14827 rb_gc_mark(load->str);
14828 rb_gc_mark(load->iseq_list);
14829 rb_gc_mark(load->global_buffer.obj_list);
14830}
14831
14832static void
14833ibf_loader_free(void *ptr)
14834{
14835 struct ibf_load *load = (struct ibf_load *)ptr;
14836 ruby_xfree(load);
14837}
14838
14839static size_t
14840ibf_loader_memsize(const void *ptr)
14841{
14842 return sizeof(struct ibf_load);
14843}
14844
14845static const rb_data_type_t ibf_load_type = {
14846 "ibf_loader",
14847 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14848 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14849};
14850
14851const rb_iseq_t *
14852rb_iseq_ibf_load(VALUE str)
14853{
14854 struct ibf_load *load;
14855 rb_iseq_t *iseq;
14856 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14857
14858 ibf_load_setup(load, loader_obj, str);
14859 iseq = ibf_load_iseq(load, 0);
14860
14861 RB_GC_GUARD(loader_obj);
14862 return iseq;
14863}
14864
14865const rb_iseq_t *
14866rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14867{
14868 struct ibf_load *load;
14869 rb_iseq_t *iseq;
14870 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14871
14872 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14873 iseq = ibf_load_iseq(load, 0);
14874
14875 RB_GC_GUARD(loader_obj);
14876 return iseq;
14877}
14878
14879VALUE
14880rb_iseq_ibf_load_extra_data(VALUE str)
14881{
14882 struct ibf_load *load;
14883 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14884 VALUE extra_str;
14885
14886 ibf_load_setup(load, loader_obj, str);
14887 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14888 RB_GC_GUARD(loader_obj);
14889 return extra_str;
14890}
14891
14892#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 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:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define 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 FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:130
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:66
#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:694
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_cHash
Hash class.
Definition hash.c:113
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:660
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:845
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1264
#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:1063
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1087
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:4219
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:4107
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:2064
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4483
#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:4469
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3875
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:4073
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4539
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:4356
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3590
#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:493
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:953
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:972
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:921
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:1382
#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::@153 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