Ruby 3.5.0dev (2025-04-26 revision b1283b45e6246a85ce34be54e5806fb0ca2e3d2d)
compile.c (b1283b45e6246a85ce34be54e5806fb0ca2e3d2d)
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 st_insert(vm->unused_block_warning_table, key, 1);
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 ID *ids = (ID *)ALLOC_N(ID, size);
2188 MEMCPY(ids, tbl->ids + offset, ID, size);
2189 ISEQ_BODY(iseq)->local_table = ids;
2190 }
2191 ISEQ_BODY(iseq)->local_table_size = size;
2192
2193 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2194 return COMPILE_OK;
2195}
2196
2197int
2198rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2199{
2200 int tval, tlit;
2201
2202 if (val == lit) {
2203 return 0;
2204 }
2205 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2206 return val != lit;
2207 }
2208 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2209 return -1;
2210 }
2211 else if (tlit != tval) {
2212 return -1;
2213 }
2214 else if (tlit == T_SYMBOL) {
2215 return val != lit;
2216 }
2217 else if (tlit == T_STRING) {
2218 return rb_str_hash_cmp(lit, val);
2219 }
2220 else if (tlit == T_BIGNUM) {
2221 long x = FIX2LONG(rb_big_cmp(lit, val));
2222
2223 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2224 * There is no need to call rb_fix2int here. */
2225 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2226 return (int)x;
2227 }
2228 else if (tlit == T_FLOAT) {
2229 return rb_float_cmp(lit, val);
2230 }
2231 else if (tlit == T_RATIONAL) {
2232 const struct RRational *rat1 = RRATIONAL(val);
2233 const struct RRational *rat2 = RRATIONAL(lit);
2234 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2235 }
2236 else if (tlit == T_COMPLEX) {
2237 const struct RComplex *comp1 = RCOMPLEX(val);
2238 const struct RComplex *comp2 = RCOMPLEX(lit);
2239 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2240 }
2241 else if (tlit == T_REGEXP) {
2242 return rb_reg_equal(val, lit) ? 0 : -1;
2243 }
2244 else {
2246 }
2247}
2248
2249st_index_t
2250rb_iseq_cdhash_hash(VALUE a)
2251{
2252 switch (OBJ_BUILTIN_TYPE(a)) {
2253 case -1:
2254 case T_SYMBOL:
2255 return (st_index_t)a;
2256 case T_STRING:
2257 return rb_str_hash(a);
2258 case T_BIGNUM:
2259 return FIX2LONG(rb_big_hash(a));
2260 case T_FLOAT:
2261 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2262 case T_RATIONAL:
2263 return rb_rational_hash(a);
2264 case T_COMPLEX:
2265 return rb_complex_hash(a);
2266 case T_REGEXP:
2267 return NUM2LONG(rb_reg_hash(a));
2268 default:
2270 }
2271}
2272
2273static const struct st_hash_type cdhash_type = {
2274 rb_iseq_cdhash_cmp,
2275 rb_iseq_cdhash_hash,
2276};
2277
2279 VALUE hash;
2280 int pos;
2281 int len;
2282};
2283
2284static int
2285cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2286{
2287 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2288 LABEL *lobj = (LABEL *)(val & ~1);
2289 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2290 return ST_CONTINUE;
2291}
2292
2293
2294static inline VALUE
2295get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2296{
2297 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2298}
2299
2300static inline VALUE
2301get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2302{
2303 VALUE val;
2304 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2305 if (tbl) {
2306 if (rb_id_table_lookup(tbl,id,&val)) {
2307 return val;
2308 }
2309 }
2310 else {
2311 tbl = rb_id_table_create(1);
2312 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2313 }
2314 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2315 rb_id_table_insert(tbl,id,val);
2316 return val;
2317}
2318
2319#define BADINSN_DUMP(anchor, list, dest) \
2320 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2321
2322#define BADINSN_ERROR \
2323 (xfree(generated_iseq), \
2324 xfree(insns_info), \
2325 BADINSN_DUMP(anchor, list, NULL), \
2326 COMPILE_ERROR)
2327
2328static int
2329fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2330{
2331 int stack_max = 0, sp = 0, line = 0;
2332 LINK_ELEMENT *list;
2333
2334 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2335 if (IS_LABEL(list)) {
2336 LABEL *lobj = (LABEL *)list;
2337 lobj->set = TRUE;
2338 }
2339 }
2340
2341 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2342 switch (list->type) {
2343 case ISEQ_ELEMENT_INSN:
2344 {
2345 int j, len, insn;
2346 const char *types;
2347 VALUE *operands;
2348 INSN *iobj = (INSN *)list;
2349
2350 /* update sp */
2351 sp = calc_sp_depth(sp, iobj);
2352 if (sp < 0) {
2353 BADINSN_DUMP(anchor, list, NULL);
2354 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2355 "argument stack underflow (%d)", sp);
2356 return -1;
2357 }
2358 if (sp > stack_max) {
2359 stack_max = sp;
2360 }
2361
2362 line = iobj->insn_info.line_no;
2363 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2364 operands = iobj->operands;
2365 insn = iobj->insn_id;
2366 types = insn_op_types(insn);
2367 len = insn_len(insn);
2368
2369 /* operand check */
2370 if (iobj->operand_size != len - 1) {
2371 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2372 BADINSN_DUMP(anchor, list, NULL);
2373 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2374 "operand size miss! (%d for %d)",
2375 iobj->operand_size, len - 1);
2376 return -1;
2377 }
2378
2379 for (j = 0; types[j]; j++) {
2380 if (types[j] == TS_OFFSET) {
2381 /* label(destination position) */
2382 LABEL *lobj = (LABEL *)operands[j];
2383 if (!lobj->set) {
2384 BADINSN_DUMP(anchor, list, NULL);
2385 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2386 "unknown label: "LABEL_FORMAT, lobj->label_no);
2387 return -1;
2388 }
2389 if (lobj->sp == -1) {
2390 lobj->sp = sp;
2391 }
2392 else if (lobj->sp != sp) {
2393 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2394 RSTRING_PTR(rb_iseq_path(iseq)), line,
2395 lobj->label_no, lobj->sp, sp);
2396 }
2397 }
2398 }
2399 break;
2400 }
2401 case ISEQ_ELEMENT_LABEL:
2402 {
2403 LABEL *lobj = (LABEL *)list;
2404 if (lobj->sp == -1) {
2405 lobj->sp = sp;
2406 }
2407 else {
2408 if (lobj->sp != sp) {
2409 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2410 RSTRING_PTR(rb_iseq_path(iseq)), line,
2411 lobj->label_no, lobj->sp, sp);
2412 }
2413 sp = lobj->sp;
2414 }
2415 break;
2416 }
2417 case ISEQ_ELEMENT_TRACE:
2418 {
2419 /* ignore */
2420 break;
2421 }
2422 case ISEQ_ELEMENT_ADJUST:
2423 {
2424 ADJUST *adjust = (ADJUST *)list;
2425 int orig_sp = sp;
2426
2427 sp = adjust->label ? adjust->label->sp : 0;
2428 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2429 BADINSN_DUMP(anchor, list, NULL);
2430 COMPILE_ERROR(iseq, adjust->line_no,
2431 "iseq_set_sequence: adjust bug %d < %d",
2432 orig_sp, sp);
2433 return -1;
2434 }
2435 break;
2436 }
2437 default:
2438 BADINSN_DUMP(anchor, list, NULL);
2439 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2440 return -1;
2441 }
2442 }
2443 return stack_max;
2444}
2445
2446static int
2447add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2448 int insns_info_index, int code_index, const INSN *iobj)
2449{
2450 if (insns_info_index == 0 ||
2451 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2452#ifdef USE_ISEQ_NODE_ID
2453 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2454#endif
2455 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2456 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2457#ifdef USE_ISEQ_NODE_ID
2458 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2459#endif
2460 insns_info[insns_info_index].events = iobj->insn_info.events;
2461 positions[insns_info_index] = code_index;
2462 return TRUE;
2463 }
2464 return FALSE;
2465}
2466
2467static int
2468add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2469 int insns_info_index, int code_index, const ADJUST *adjust)
2470{
2471 insns_info[insns_info_index].line_no = adjust->line_no;
2472 insns_info[insns_info_index].node_id = -1;
2473 insns_info[insns_info_index].events = 0;
2474 positions[insns_info_index] = code_index;
2475 return TRUE;
2476}
2477
2478static ID *
2479array_to_idlist(VALUE arr)
2480{
2482 long size = RARRAY_LEN(arr);
2483 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2484 for (int i = 0; i < size; i++) {
2485 VALUE sym = RARRAY_AREF(arr, i);
2486 ids[i] = SYM2ID(sym);
2487 }
2488 ids[size] = 0;
2489 return ids;
2490}
2491
2492static VALUE
2493idlist_to_array(const ID *ids)
2494{
2495 VALUE arr = rb_ary_new();
2496 while (*ids) {
2497 rb_ary_push(arr, ID2SYM(*ids++));
2498 }
2499 return arr;
2500}
2501
2505static int
2506iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2507{
2508 struct iseq_insn_info_entry *insns_info;
2509 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2510 unsigned int *positions;
2511 LINK_ELEMENT *list;
2512 VALUE *generated_iseq;
2513 rb_event_flag_t events = 0;
2514 long data = 0;
2515
2516 int insn_num, code_index, insns_info_index, sp = 0;
2517 int stack_max = fix_sp_depth(iseq, anchor);
2518
2519 if (stack_max < 0) return COMPILE_NG;
2520
2521 /* fix label position */
2522 insn_num = code_index = 0;
2523 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2524 switch (list->type) {
2525 case ISEQ_ELEMENT_INSN:
2526 {
2527 INSN *iobj = (INSN *)list;
2528 /* update sp */
2529 sp = calc_sp_depth(sp, iobj);
2530 insn_num++;
2531 events = iobj->insn_info.events |= events;
2532 if (ISEQ_COVERAGE(iseq)) {
2533 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2534 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2535 int line = iobj->insn_info.line_no - 1;
2536 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2537 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2538 }
2539 }
2540 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2541 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2542 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2543 }
2544 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2545 }
2546 }
2547 code_index += insn_data_length(iobj);
2548 events = 0;
2549 data = 0;
2550 break;
2551 }
2552 case ISEQ_ELEMENT_LABEL:
2553 {
2554 LABEL *lobj = (LABEL *)list;
2555 lobj->position = code_index;
2556 if (lobj->sp != sp) {
2557 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2558 RSTRING_PTR(rb_iseq_path(iseq)),
2559 lobj->label_no, lobj->sp, sp);
2560 }
2561 sp = lobj->sp;
2562 break;
2563 }
2564 case ISEQ_ELEMENT_TRACE:
2565 {
2566 TRACE *trace = (TRACE *)list;
2567 events |= trace->event;
2568 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2569 break;
2570 }
2571 case ISEQ_ELEMENT_ADJUST:
2572 {
2573 ADJUST *adjust = (ADJUST *)list;
2574 if (adjust->line_no != -1) {
2575 int orig_sp = sp;
2576 sp = adjust->label ? adjust->label->sp : 0;
2577 if (orig_sp - sp > 0) {
2578 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2579 code_index++; /* insn */
2580 insn_num++;
2581 }
2582 }
2583 break;
2584 }
2585 default: break;
2586 }
2587 }
2588
2589 /* make instruction sequence */
2590 generated_iseq = ALLOC_N(VALUE, code_index);
2591 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2592 positions = ALLOC_N(unsigned int, insn_num);
2593 if (ISEQ_IS_SIZE(body)) {
2594 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2595 }
2596 else {
2597 body->is_entries = NULL;
2598 }
2599
2600 if (body->ci_size) {
2601 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2602 }
2603 else {
2604 body->call_data = NULL;
2605 }
2606 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2607
2608 // Calculate the bitmask buffer size.
2609 // Round the generated_iseq size up to the nearest multiple
2610 // of the number of bits in an unsigned long.
2611
2612 // Allocate enough room for the bitmask list
2613 iseq_bits_t * mark_offset_bits;
2614 int code_size = code_index;
2615
2616 bool needs_bitmap = false;
2617
2618 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2619 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2620 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2621 }
2622 else {
2623 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2624 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2625 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2626 }
2627
2628 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2629 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2630
2631 list = FIRST_ELEMENT(anchor);
2632 insns_info_index = code_index = sp = 0;
2633
2634 while (list) {
2635 switch (list->type) {
2636 case ISEQ_ELEMENT_INSN:
2637 {
2638 int j, len, insn;
2639 const char *types;
2640 VALUE *operands;
2641 INSN *iobj = (INSN *)list;
2642
2643 /* update sp */
2644 sp = calc_sp_depth(sp, iobj);
2645 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2646 operands = iobj->operands;
2647 insn = iobj->insn_id;
2648 generated_iseq[code_index] = insn;
2649 types = insn_op_types(insn);
2650 len = insn_len(insn);
2651
2652 for (j = 0; types[j]; j++) {
2653 char type = types[j];
2654
2655 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2656 switch (type) {
2657 case TS_OFFSET:
2658 {
2659 /* label(destination position) */
2660 LABEL *lobj = (LABEL *)operands[j];
2661 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2662 break;
2663 }
2664 case TS_CDHASH:
2665 {
2666 VALUE map = operands[j];
2667 struct cdhash_set_label_struct data;
2668 data.hash = map;
2669 data.pos = code_index;
2670 data.len = len;
2671 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2672
2673 rb_hash_rehash(map);
2674 freeze_hide_obj(map);
2675 generated_iseq[code_index + 1 + j] = map;
2676 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2677 RB_OBJ_WRITTEN(iseq, Qundef, map);
2678 needs_bitmap = true;
2679 break;
2680 }
2681 case TS_LINDEX:
2682 case TS_NUM: /* ulong */
2683 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2684 break;
2685 case TS_ISEQ: /* iseq */
2686 case TS_VALUE: /* VALUE */
2687 {
2688 VALUE v = operands[j];
2689 generated_iseq[code_index + 1 + j] = v;
2690 /* to mark ruby object */
2691 if (!SPECIAL_CONST_P(v)) {
2692 RB_OBJ_WRITTEN(iseq, Qundef, v);
2693 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2694 needs_bitmap = true;
2695 }
2696 break;
2697 }
2698 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2699 case TS_IC: /* inline cache: constants */
2700 {
2701 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2702 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2703 if (UNLIKELY(ic_index >= body->ic_size)) {
2704 BADINSN_DUMP(anchor, &iobj->link, 0);
2705 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2706 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2707 ic_index, ISEQ_IS_SIZE(body));
2708 }
2709
2710 ic->segments = array_to_idlist(operands[j]);
2711
2712 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2713 }
2714 break;
2715 case TS_IVC: /* inline ivar cache */
2716 {
2717 unsigned int ic_index = FIX2UINT(operands[j]);
2718
2719 IVC cache = ((IVC)&body->is_entries[ic_index]);
2720
2721 if (insn == BIN(setinstancevariable)) {
2722 cache->iv_set_name = SYM2ID(operands[j - 1]);
2723 }
2724 else {
2725 cache->iv_set_name = 0;
2726 }
2727
2728 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2729 }
2730 case TS_ISE: /* inline storage entry: `once` insn */
2731 case TS_ICVARC: /* inline cvar cache */
2732 {
2733 unsigned int ic_index = FIX2UINT(operands[j]);
2734 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2735 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2736 BADINSN_DUMP(anchor, &iobj->link, 0);
2737 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2738 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2739 ic_index, ISEQ_IS_SIZE(body));
2740 }
2741 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2742
2743 break;
2744 }
2745 case TS_CALLDATA:
2746 {
2747 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2748 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2749 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2750 cd->ci = source_ci;
2751 cd->cc = vm_cc_empty();
2752 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2753 break;
2754 }
2755 case TS_ID: /* ID */
2756 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2757 break;
2758 case TS_FUNCPTR:
2759 generated_iseq[code_index + 1 + j] = operands[j];
2760 break;
2761 case TS_BUILTIN:
2762 generated_iseq[code_index + 1 + j] = operands[j];
2763 break;
2764 default:
2765 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2766 "unknown operand type: %c", type);
2767 return COMPILE_NG;
2768 }
2769 }
2770 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2771 code_index += len;
2772 break;
2773 }
2774 case ISEQ_ELEMENT_LABEL:
2775 {
2776 LABEL *lobj = (LABEL *)list;
2777 if (lobj->sp != sp) {
2778 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2779 RSTRING_PTR(rb_iseq_path(iseq)),
2780 lobj->label_no, lobj->sp, sp);
2781 }
2782 sp = lobj->sp;
2783 break;
2784 }
2785 case ISEQ_ELEMENT_ADJUST:
2786 {
2787 ADJUST *adjust = (ADJUST *)list;
2788 int orig_sp = sp;
2789
2790 if (adjust->label) {
2791 sp = adjust->label->sp;
2792 }
2793 else {
2794 sp = 0;
2795 }
2796
2797 if (adjust->line_no != -1) {
2798 const int diff = orig_sp - sp;
2799 if (diff > 0) {
2800 if (insns_info_index == 0) {
2801 COMPILE_ERROR(iseq, adjust->line_no,
2802 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2803 }
2804 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2805 }
2806 if (diff > 1) {
2807 generated_iseq[code_index++] = BIN(adjuststack);
2808 generated_iseq[code_index++] = orig_sp - sp;
2809 }
2810 else if (diff == 1) {
2811 generated_iseq[code_index++] = BIN(pop);
2812 }
2813 else if (diff < 0) {
2814 int label_no = adjust->label ? adjust->label->label_no : -1;
2815 xfree(generated_iseq);
2816 xfree(insns_info);
2817 xfree(positions);
2818 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2819 xfree(mark_offset_bits);
2820 }
2821 debug_list(anchor, list);
2822 COMPILE_ERROR(iseq, adjust->line_no,
2823 "iseq_set_sequence: adjust bug to %d %d < %d",
2824 label_no, orig_sp, sp);
2825 return COMPILE_NG;
2826 }
2827 }
2828 break;
2829 }
2830 default:
2831 /* ignore */
2832 break;
2833 }
2834 list = list->next;
2835 }
2836
2837 body->iseq_encoded = (void *)generated_iseq;
2838 body->iseq_size = code_index;
2839 body->stack_max = stack_max;
2840
2841 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2842 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2843 }
2844 else {
2845 if (needs_bitmap) {
2846 body->mark_bits.list = mark_offset_bits;
2847 }
2848 else {
2849 body->mark_bits.list = NULL;
2850 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2851 ruby_xfree(mark_offset_bits);
2852 }
2853 }
2854
2855 /* get rid of memory leak when REALLOC failed */
2856 body->insns_info.body = insns_info;
2857 body->insns_info.positions = positions;
2858
2859 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2860 body->insns_info.body = insns_info;
2861 REALLOC_N(positions, unsigned int, insns_info_index);
2862 body->insns_info.positions = positions;
2863 body->insns_info.size = insns_info_index;
2864
2865 return COMPILE_OK;
2866}
2867
2868static int
2869label_get_position(LABEL *lobj)
2870{
2871 return lobj->position;
2872}
2873
2874static int
2875label_get_sp(LABEL *lobj)
2876{
2877 return lobj->sp;
2878}
2879
2880static int
2881iseq_set_exception_table(rb_iseq_t *iseq)
2882{
2883 const VALUE *tptr, *ptr;
2884 unsigned int tlen, i;
2885 struct iseq_catch_table_entry *entry;
2886
2887 ISEQ_BODY(iseq)->catch_table = NULL;
2888
2889 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2890 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2891 tlen = (int)RARRAY_LEN(catch_table_ary);
2892 tptr = RARRAY_CONST_PTR(catch_table_ary);
2893
2894 if (tlen > 0) {
2895 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2896 table->size = tlen;
2897
2898 for (i = 0; i < table->size; i++) {
2899 int pos;
2900 ptr = RARRAY_CONST_PTR(tptr[i]);
2901 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2902 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2903 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2904 RUBY_ASSERT(pos >= 0);
2905 entry->start = (unsigned int)pos;
2906 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2907 RUBY_ASSERT(pos >= 0);
2908 entry->end = (unsigned int)pos;
2909 entry->iseq = (rb_iseq_t *)ptr[3];
2910 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2911
2912 /* stack depth */
2913 if (ptr[4]) {
2914 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2915 entry->cont = label_get_position(lobj);
2916 entry->sp = label_get_sp(lobj);
2917
2918 /* TODO: Dirty Hack! Fix me */
2919 if (entry->type == CATCH_TYPE_RESCUE ||
2920 entry->type == CATCH_TYPE_BREAK ||
2921 entry->type == CATCH_TYPE_NEXT) {
2922 RUBY_ASSERT(entry->sp > 0);
2923 entry->sp--;
2924 }
2925 }
2926 else {
2927 entry->cont = 0;
2928 }
2929 }
2930 ISEQ_BODY(iseq)->catch_table = table;
2931 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2932 }
2933
2934 RB_GC_GUARD(catch_table_ary);
2935
2936 return COMPILE_OK;
2937}
2938
2939/*
2940 * set optional argument table
2941 * def foo(a, b=expr1, c=expr2)
2942 * =>
2943 * b:
2944 * expr1
2945 * c:
2946 * expr2
2947 */
2948static int
2949iseq_set_optargs_table(rb_iseq_t *iseq)
2950{
2951 int i;
2952 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2953
2954 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2955 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2956 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2957 }
2958 }
2959 return COMPILE_OK;
2960}
2961
2962static LINK_ELEMENT *
2963get_destination_insn(INSN *iobj)
2964{
2965 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2966 LINK_ELEMENT *list;
2967 rb_event_flag_t events = 0;
2968
2969 list = lobj->link.next;
2970 while (list) {
2971 switch (list->type) {
2972 case ISEQ_ELEMENT_INSN:
2973 case ISEQ_ELEMENT_ADJUST:
2974 goto found;
2975 case ISEQ_ELEMENT_LABEL:
2976 /* ignore */
2977 break;
2978 case ISEQ_ELEMENT_TRACE:
2979 {
2980 TRACE *trace = (TRACE *)list;
2981 events |= trace->event;
2982 }
2983 break;
2984 default: break;
2985 }
2986 list = list->next;
2987 }
2988 found:
2989 if (list && IS_INSN(list)) {
2990 INSN *iobj = (INSN *)list;
2991 iobj->insn_info.events |= events;
2992 }
2993 return list;
2994}
2995
2996static LINK_ELEMENT *
2997get_next_insn(INSN *iobj)
2998{
2999 LINK_ELEMENT *list = iobj->link.next;
3000
3001 while (list) {
3002 if (IS_INSN(list) || IS_ADJUST(list)) {
3003 return list;
3004 }
3005 list = list->next;
3006 }
3007 return 0;
3008}
3009
3010static LINK_ELEMENT *
3011get_prev_insn(INSN *iobj)
3012{
3013 LINK_ELEMENT *list = iobj->link.prev;
3014
3015 while (list) {
3016 if (IS_INSN(list) || IS_ADJUST(list)) {
3017 return list;
3018 }
3019 list = list->prev;
3020 }
3021 return 0;
3022}
3023
3024static void
3025unref_destination(INSN *iobj, int pos)
3026{
3027 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3028 --lobj->refcnt;
3029 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3030}
3031
3032static bool
3033replace_destination(INSN *dobj, INSN *nobj)
3034{
3035 VALUE n = OPERAND_AT(nobj, 0);
3036 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3037 LABEL *nl = (LABEL *)n;
3038 if (dl == nl) return false;
3039 --dl->refcnt;
3040 ++nl->refcnt;
3041 OPERAND_AT(dobj, 0) = n;
3042 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3043 return true;
3044}
3045
3046static LABEL*
3047find_destination(INSN *i)
3048{
3049 int pos, len = insn_len(i->insn_id);
3050 for (pos = 0; pos < len; ++pos) {
3051 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3052 return (LABEL *)OPERAND_AT(i, pos);
3053 }
3054 }
3055 return 0;
3056}
3057
3058static int
3059remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3060{
3061 LINK_ELEMENT *first = i, *end;
3062 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3063
3064 if (!i) return 0;
3065 unref_counts = ALLOCA_N(int, nlabels);
3066 MEMZERO(unref_counts, int, nlabels);
3067 end = i;
3068 do {
3069 LABEL *lab;
3070 if (IS_INSN(i)) {
3071 if (IS_INSN_ID(i, leave)) {
3072 end = i;
3073 break;
3074 }
3075 else if ((lab = find_destination((INSN *)i)) != 0) {
3076 unref_counts[lab->label_no]++;
3077 }
3078 }
3079 else if (IS_LABEL(i)) {
3080 lab = (LABEL *)i;
3081 if (lab->unremovable) return 0;
3082 if (lab->refcnt > unref_counts[lab->label_no]) {
3083 if (i == first) return 0;
3084 break;
3085 }
3086 continue;
3087 }
3088 else if (IS_TRACE(i)) {
3089 /* do nothing */
3090 }
3091 else if (IS_ADJUST(i)) {
3092 return 0;
3093 }
3094 end = i;
3095 } while ((i = i->next) != 0);
3096 i = first;
3097 do {
3098 if (IS_INSN(i)) {
3099 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3100 VALUE insn = INSN_OF(i);
3101 int pos, len = insn_len(insn);
3102 for (pos = 0; pos < len; ++pos) {
3103 switch (insn_op_types(insn)[pos]) {
3104 case TS_OFFSET:
3105 unref_destination((INSN *)i, pos);
3106 break;
3107 case TS_CALLDATA:
3108 --(body->ci_size);
3109 break;
3110 }
3111 }
3112 }
3113 ELEM_REMOVE(i);
3114 } while ((i != end) && (i = i->next) != 0);
3115 return 1;
3116}
3117
3118static int
3119iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3120{
3121 switch (OPERAND_AT(iobj, 0)) {
3122 case INT2FIX(0): /* empty array */
3123 ELEM_REMOVE(&iobj->link);
3124 return TRUE;
3125 case INT2FIX(1): /* single element array */
3126 ELEM_REMOVE(&iobj->link);
3127 return FALSE;
3128 default:
3129 iobj->insn_id = BIN(adjuststack);
3130 return TRUE;
3131 }
3132}
3133
3134static int
3135is_frozen_putstring(INSN *insn, VALUE *op)
3136{
3137 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3138 *op = OPERAND_AT(insn, 0);
3139 return 1;
3140 }
3141 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3142 *op = OPERAND_AT(insn, 0);
3143 return RB_TYPE_P(*op, T_STRING);
3144 }
3145 return 0;
3146}
3147
3148static int
3149optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3150{
3151 /*
3152 * putobject obj
3153 * dup
3154 * checktype T_XXX
3155 * branchif l1
3156 * l2:
3157 * ...
3158 * l1:
3159 *
3160 * => obj is a T_XXX
3161 *
3162 * putobject obj (T_XXX)
3163 * jump L1
3164 * L1:
3165 *
3166 * => obj is not a T_XXX
3167 *
3168 * putobject obj (T_XXX)
3169 * jump L2
3170 * L2:
3171 */
3172 int line, node_id;
3173 INSN *niobj, *ciobj, *dup = 0;
3174 LABEL *dest = 0;
3175 VALUE type;
3176
3177 switch (INSN_OF(iobj)) {
3178 case BIN(putstring):
3179 case BIN(putchilledstring):
3181 break;
3182 case BIN(putnil):
3183 type = INT2FIX(T_NIL);
3184 break;
3185 case BIN(putobject):
3186 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3187 break;
3188 default: return FALSE;
3189 }
3190
3191 ciobj = (INSN *)get_next_insn(iobj);
3192 if (IS_INSN_ID(ciobj, jump)) {
3193 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3194 }
3195 if (IS_INSN_ID(ciobj, dup)) {
3196 ciobj = (INSN *)get_next_insn(dup = ciobj);
3197 }
3198 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3199 niobj = (INSN *)get_next_insn(ciobj);
3200 if (!niobj) {
3201 /* TODO: putobject true/false */
3202 return FALSE;
3203 }
3204 switch (INSN_OF(niobj)) {
3205 case BIN(branchif):
3206 if (OPERAND_AT(ciobj, 0) == type) {
3207 dest = (LABEL *)OPERAND_AT(niobj, 0);
3208 }
3209 break;
3210 case BIN(branchunless):
3211 if (OPERAND_AT(ciobj, 0) != type) {
3212 dest = (LABEL *)OPERAND_AT(niobj, 0);
3213 }
3214 break;
3215 default:
3216 return FALSE;
3217 }
3218 line = ciobj->insn_info.line_no;
3219 node_id = ciobj->insn_info.node_id;
3220 if (!dest) {
3221 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3222 dest = (LABEL *)niobj->link.next; /* reuse label */
3223 }
3224 else {
3225 dest = NEW_LABEL(line);
3226 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3227 }
3228 }
3229 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3230 LABEL_REF(dest);
3231 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3232 return TRUE;
3233}
3234
3235static const struct rb_callinfo *
3236ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3237{
3238 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3239 vm_ci_flag(ci) | add,
3240 vm_ci_argc(ci),
3241 vm_ci_kwarg(ci));
3242 RB_OBJ_WRITTEN(iseq, ci, nci);
3243 return nci;
3244}
3245
3246static const struct rb_callinfo *
3247ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3248{
3249 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3250 vm_ci_flag(ci),
3251 argc,
3252 vm_ci_kwarg(ci));
3253 RB_OBJ_WRITTEN(iseq, ci, nci);
3254 return nci;
3255}
3256
3257#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3258
3259static int
3260iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3261{
3262 INSN *const iobj = (INSN *)list;
3263
3264 again:
3265 optimize_checktype(iseq, iobj);
3266
3267 if (IS_INSN_ID(iobj, jump)) {
3268 INSN *niobj, *diobj, *piobj;
3269 diobj = (INSN *)get_destination_insn(iobj);
3270 niobj = (INSN *)get_next_insn(iobj);
3271
3272 if (diobj == niobj) {
3273 /*
3274 * jump LABEL
3275 * LABEL:
3276 * =>
3277 * LABEL:
3278 */
3279 unref_destination(iobj, 0);
3280 ELEM_REMOVE(&iobj->link);
3281 return COMPILE_OK;
3282 }
3283 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3284 IS_INSN_ID(diobj, jump) &&
3285 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3286 diobj->insn_info.events == 0) {
3287 /*
3288 * useless jump elimination:
3289 * jump LABEL1
3290 * ...
3291 * LABEL1:
3292 * jump LABEL2
3293 *
3294 * => in this case, first jump instruction should jump to
3295 * LABEL2 directly
3296 */
3297 if (replace_destination(iobj, diobj)) {
3298 remove_unreachable_chunk(iseq, iobj->link.next);
3299 goto again;
3300 }
3301 }
3302 else if (IS_INSN_ID(diobj, leave)) {
3303 /*
3304 * jump LABEL
3305 * ...
3306 * LABEL:
3307 * leave
3308 * =>
3309 * leave
3310 * ...
3311 * LABEL:
3312 * leave
3313 */
3314 /* replace */
3315 unref_destination(iobj, 0);
3316 iobj->insn_id = BIN(leave);
3317 iobj->operand_size = 0;
3318 iobj->insn_info = diobj->insn_info;
3319 goto again;
3320 }
3321 else if (IS_INSN(iobj->link.prev) &&
3322 (piobj = (INSN *)iobj->link.prev) &&
3323 (IS_INSN_ID(piobj, branchif) ||
3324 IS_INSN_ID(piobj, branchunless))) {
3325 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3326 if (niobj == pdiobj) {
3327 int refcnt = IS_LABEL(piobj->link.next) ?
3328 ((LABEL *)piobj->link.next)->refcnt : 0;
3329 /*
3330 * useless jump elimination (if/unless destination):
3331 * if L1
3332 * jump L2
3333 * L1:
3334 * ...
3335 * L2:
3336 *
3337 * ==>
3338 * unless L2
3339 * L1:
3340 * ...
3341 * L2:
3342 */
3343 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3344 ? BIN(branchunless) : BIN(branchif);
3345 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3346 ELEM_REMOVE(&iobj->link);
3347 }
3348 else {
3349 /* TODO: replace other branch destinations too */
3350 }
3351 return COMPILE_OK;
3352 }
3353 else if (diobj == pdiobj) {
3354 /*
3355 * useless jump elimination (if/unless before jump):
3356 * L1:
3357 * ...
3358 * if L1
3359 * jump L1
3360 *
3361 * ==>
3362 * L1:
3363 * ...
3364 * pop
3365 * jump L1
3366 */
3367 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3368 ELEM_REPLACE(&piobj->link, &popiobj->link);
3369 }
3370 }
3371 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3372 goto again;
3373 }
3374 }
3375
3376 /*
3377 * putstring "beg"
3378 * putstring "end"
3379 * newrange excl
3380 *
3381 * ==>
3382 *
3383 * putobject "beg".."end"
3384 */
3385 if (IS_INSN_ID(iobj, newrange)) {
3386 INSN *const range = iobj;
3387 INSN *beg, *end;
3388 VALUE str_beg, str_end;
3389
3390 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3391 is_frozen_putstring(end, &str_end) &&
3392 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3393 is_frozen_putstring(beg, &str_beg)) {
3394 int excl = FIX2INT(OPERAND_AT(range, 0));
3395 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3396
3397 ELEM_REMOVE(&beg->link);
3398 ELEM_REMOVE(&end->link);
3399 range->insn_id = BIN(putobject);
3400 OPERAND_AT(range, 0) = lit_range;
3401 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3402 }
3403 }
3404
3405 if (IS_INSN_ID(iobj, leave)) {
3406 remove_unreachable_chunk(iseq, iobj->link.next);
3407 }
3408
3409 /*
3410 * ...
3411 * duparray [...]
3412 * concatarray | concattoarray
3413 * =>
3414 * ...
3415 * putobject [...]
3416 * concatarray | concattoarray
3417 */
3418 if (IS_INSN_ID(iobj, duparray)) {
3419 LINK_ELEMENT *next = iobj->link.next;
3420 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3421 iobj->insn_id = BIN(putobject);
3422 }
3423 }
3424
3425 /*
3426 * duparray [...]
3427 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3428 * =>
3429 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3430 */
3431 if (IS_INSN_ID(iobj, duparray)) {
3432 LINK_ELEMENT *next = iobj->link.next;
3433 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3434 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3435 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3436
3437 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3438 VALUE ary = iobj->operands[0];
3440
3441 iobj->insn_id = BIN(opt_ary_freeze);
3442 iobj->operand_size = 2;
3443 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3444 iobj->operands[0] = ary;
3445 iobj->operands[1] = (VALUE)ci;
3446 ELEM_REMOVE(next);
3447 }
3448 }
3449 }
3450
3451 /*
3452 * duphash {...}
3453 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3454 * =>
3455 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3456 */
3457 if (IS_INSN_ID(iobj, duphash)) {
3458 LINK_ELEMENT *next = iobj->link.next;
3459 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3460 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3461 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3462
3463 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3464 VALUE hash = iobj->operands[0];
3465 rb_obj_reveal(hash, rb_cHash);
3466
3467 iobj->insn_id = BIN(opt_hash_freeze);
3468 iobj->operand_size = 2;
3469 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3470 iobj->operands[0] = hash;
3471 iobj->operands[1] = (VALUE)ci;
3472 ELEM_REMOVE(next);
3473 }
3474 }
3475 }
3476
3477 /*
3478 * newarray 0
3479 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3480 * =>
3481 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3482 */
3483 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3484 LINK_ELEMENT *next = iobj->link.next;
3485 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3486 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3487 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3488
3489 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3490 iobj->insn_id = BIN(opt_ary_freeze);
3491 iobj->operand_size = 2;
3492 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3493 iobj->operands[0] = rb_cArray_empty_frozen;
3494 iobj->operands[1] = (VALUE)ci;
3495 ELEM_REMOVE(next);
3496 }
3497 }
3498 }
3499
3500 /*
3501 * newhash 0
3502 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3503 * =>
3504 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3505 */
3506 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3507 LINK_ELEMENT *next = iobj->link.next;
3508 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3509 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3510 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3511
3512 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3513 iobj->insn_id = BIN(opt_hash_freeze);
3514 iobj->operand_size = 2;
3515 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3516 iobj->operands[0] = rb_cHash_empty_frozen;
3517 iobj->operands[1] = (VALUE)ci;
3518 ELEM_REMOVE(next);
3519 }
3520 }
3521 }
3522
3523 if (IS_INSN_ID(iobj, branchif) ||
3524 IS_INSN_ID(iobj, branchnil) ||
3525 IS_INSN_ID(iobj, branchunless)) {
3526 /*
3527 * if L1
3528 * ...
3529 * L1:
3530 * jump L2
3531 * =>
3532 * if L2
3533 */
3534 INSN *nobj = (INSN *)get_destination_insn(iobj);
3535
3536 /* This is super nasty hack!!!
3537 *
3538 * This jump-jump optimization may ignore event flags of the jump
3539 * instruction being skipped. Actually, Line 2 TracePoint event
3540 * is never fired in the following code:
3541 *
3542 * 1: raise if 1 == 2
3543 * 2: while true
3544 * 3: break
3545 * 4: end
3546 *
3547 * This is critical for coverage measurement. [Bug #15980]
3548 *
3549 * This is a stopgap measure: stop the jump-jump optimization if
3550 * coverage measurement is enabled and if the skipped instruction
3551 * has any event flag.
3552 *
3553 * Note that, still, TracePoint Line event does not occur on Line 2.
3554 * This should be fixed in future.
3555 */
3556 int stop_optimization =
3557 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3558 nobj->link.type == ISEQ_ELEMENT_INSN &&
3559 nobj->insn_info.events;
3560 if (!stop_optimization) {
3561 INSN *pobj = (INSN *)iobj->link.prev;
3562 int prev_dup = 0;
3563 if (pobj) {
3564 if (!IS_INSN(&pobj->link))
3565 pobj = 0;
3566 else if (IS_INSN_ID(pobj, dup))
3567 prev_dup = 1;
3568 }
3569
3570 for (;;) {
3571 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3572 if (!replace_destination(iobj, nobj)) break;
3573 }
3574 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3575 !!(nobj = (INSN *)nobj->link.next) &&
3576 /* basic blocks, with no labels in the middle */
3577 nobj->insn_id == iobj->insn_id) {
3578 /*
3579 * dup
3580 * if L1
3581 * ...
3582 * L1:
3583 * dup
3584 * if L2
3585 * =>
3586 * dup
3587 * if L2
3588 * ...
3589 * L1:
3590 * dup
3591 * if L2
3592 */
3593 if (!replace_destination(iobj, nobj)) break;
3594 }
3595 else if (pobj) {
3596 /*
3597 * putnil
3598 * if L1
3599 * =>
3600 * # nothing
3601 *
3602 * putobject true
3603 * if L1
3604 * =>
3605 * jump L1
3606 *
3607 * putstring ".."
3608 * if L1
3609 * =>
3610 * jump L1
3611 *
3612 * putstring ".."
3613 * dup
3614 * if L1
3615 * =>
3616 * putstring ".."
3617 * jump L1
3618 *
3619 */
3620 int cond;
3621 if (prev_dup && IS_INSN(pobj->link.prev)) {
3622 pobj = (INSN *)pobj->link.prev;
3623 }
3624 if (IS_INSN_ID(pobj, putobject)) {
3625 cond = (IS_INSN_ID(iobj, branchif) ?
3626 OPERAND_AT(pobj, 0) != Qfalse :
3627 IS_INSN_ID(iobj, branchunless) ?
3628 OPERAND_AT(pobj, 0) == Qfalse :
3629 FALSE);
3630 }
3631 else if (IS_INSN_ID(pobj, putstring) ||
3632 IS_INSN_ID(pobj, duparray) ||
3633 IS_INSN_ID(pobj, newarray)) {
3634 cond = IS_INSN_ID(iobj, branchif);
3635 }
3636 else if (IS_INSN_ID(pobj, putnil)) {
3637 cond = !IS_INSN_ID(iobj, branchif);
3638 }
3639 else break;
3640 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3641 ELEM_REMOVE(iobj->link.prev);
3642 }
3643 else if (!iseq_pop_newarray(iseq, pobj)) {
3644 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3645 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3646 }
3647 if (cond) {
3648 if (prev_dup) {
3649 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3650 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3651 }
3652 iobj->insn_id = BIN(jump);
3653 goto again;
3654 }
3655 else {
3656 unref_destination(iobj, 0);
3657 ELEM_REMOVE(&iobj->link);
3658 }
3659 break;
3660 }
3661 else break;
3662 nobj = (INSN *)get_destination_insn(nobj);
3663 }
3664 }
3665 }
3666
3667 if (IS_INSN_ID(iobj, pop)) {
3668 /*
3669 * putself / putnil / putobject obj / putstring "..."
3670 * pop
3671 * =>
3672 * # do nothing
3673 */
3674 LINK_ELEMENT *prev = iobj->link.prev;
3675 if (IS_INSN(prev)) {
3676 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3677 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3678 previ == BIN(putself) || previ == BIN(putstring) ||
3679 previ == BIN(putchilledstring) ||
3680 previ == BIN(dup) ||
3681 previ == BIN(getlocal) ||
3682 previ == BIN(getblockparam) ||
3683 previ == BIN(getblockparamproxy) ||
3684 previ == BIN(getinstancevariable) ||
3685 previ == BIN(duparray)) {
3686 /* just push operand or static value and pop soon, no
3687 * side effects */
3688 ELEM_REMOVE(prev);
3689 ELEM_REMOVE(&iobj->link);
3690 }
3691 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3692 ELEM_REMOVE(&iobj->link);
3693 }
3694 else if (previ == BIN(concatarray)) {
3695 INSN *piobj = (INSN *)prev;
3696 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3697 INSN_OF(piobj) = BIN(pop);
3698 }
3699 else if (previ == BIN(concatstrings)) {
3700 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3701 ELEM_REMOVE(prev);
3702 }
3703 else {
3704 ELEM_REMOVE(&iobj->link);
3705 INSN_OF(prev) = BIN(adjuststack);
3706 }
3707 }
3708 }
3709 }
3710
3711 if (IS_INSN_ID(iobj, newarray) ||
3712 IS_INSN_ID(iobj, duparray) ||
3713 IS_INSN_ID(iobj, concatarray) ||
3714 IS_INSN_ID(iobj, splatarray) ||
3715 0) {
3716 /*
3717 * newarray N
3718 * splatarray
3719 * =>
3720 * newarray N
3721 * newarray always puts an array
3722 */
3723 LINK_ELEMENT *next = iobj->link.next;
3724 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3725 /* remove splatarray following always-array insn */
3726 ELEM_REMOVE(next);
3727 }
3728 }
3729
3730 if (IS_INSN_ID(iobj, newarray)) {
3731 LINK_ELEMENT *next = iobj->link.next;
3732 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3733 OPERAND_AT(next, 1) == INT2FIX(0)) {
3734 VALUE op1, op2;
3735 op1 = OPERAND_AT(iobj, 0);
3736 op2 = OPERAND_AT(next, 0);
3737 ELEM_REMOVE(next);
3738
3739 if (op1 == op2) {
3740 /*
3741 * newarray 2
3742 * expandarray 2, 0
3743 * =>
3744 * swap
3745 */
3746 if (op1 == INT2FIX(2)) {
3747 INSN_OF(iobj) = BIN(swap);
3748 iobj->operand_size = 0;
3749 }
3750 /*
3751 * newarray X
3752 * expandarray X, 0
3753 * =>
3754 * opt_reverse X
3755 */
3756 else {
3757 INSN_OF(iobj) = BIN(opt_reverse);
3758 }
3759 }
3760 else {
3761 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3762 INSN_OF(iobj) = BIN(opt_reverse);
3763 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3764
3765 if (op1 > op2) {
3766 /* X > Y
3767 * newarray X
3768 * expandarray Y, 0
3769 * =>
3770 * pop * (Y-X)
3771 * opt_reverse Y
3772 */
3773 for (; diff > 0; diff--) {
3774 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3775 }
3776 }
3777 else { /* (op1 < op2) */
3778 /* X < Y
3779 * newarray X
3780 * expandarray Y, 0
3781 * =>
3782 * putnil * (Y-X)
3783 * opt_reverse Y
3784 */
3785 for (; diff < 0; diff++) {
3786 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3787 }
3788 }
3789 }
3790 }
3791 }
3792
3793 if (IS_INSN_ID(iobj, duparray)) {
3794 LINK_ELEMENT *next = iobj->link.next;
3795 /*
3796 * duparray obj
3797 * expandarray X, 0
3798 * =>
3799 * putobject obj
3800 * expandarray X, 0
3801 */
3802 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3803 INSN_OF(iobj) = BIN(putobject);
3804 }
3805 }
3806
3807 if (IS_INSN_ID(iobj, anytostring)) {
3808 LINK_ELEMENT *next = iobj->link.next;
3809 /*
3810 * anytostring
3811 * concatstrings 1
3812 * =>
3813 * anytostring
3814 */
3815 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3816 OPERAND_AT(next, 0) == INT2FIX(1)) {
3817 ELEM_REMOVE(next);
3818 }
3819 }
3820
3821 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3822 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3823 /*
3824 * putstring ""
3825 * concatstrings N
3826 * =>
3827 * concatstrings N-1
3828 */
3829 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3830 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3831 INSN *next = (INSN *)iobj->link.next;
3832 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3833 ELEM_REMOVE(&next->link);
3834 }
3835 ELEM_REMOVE(&iobj->link);
3836 }
3837 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3838 INSN *next = (INSN *)iobj->link.next;
3839 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3840 VALUE src = OPERAND_AT(iobj, 0);
3841 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3842 VALUE path = rb_iseq_path(iseq);
3843 int line = iobj->insn_info.line_no;
3844 VALUE errinfo = rb_errinfo();
3845 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3846 if (NIL_P(re)) {
3847 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3848 rb_set_errinfo(errinfo);
3849 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3850 }
3851 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3852 ELEM_REMOVE(iobj->link.next);
3853 }
3854 }
3855 }
3856
3857 if (IS_INSN_ID(iobj, concatstrings)) {
3858 /*
3859 * concatstrings N
3860 * concatstrings M
3861 * =>
3862 * concatstrings N+M-1
3863 */
3864 LINK_ELEMENT *next = iobj->link.next;
3865 INSN *jump = 0;
3866 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3867 next = get_destination_insn(jump = (INSN *)next);
3868 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3869 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3870 OPERAND_AT(iobj, 0) = INT2FIX(n);
3871 if (jump) {
3872 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3873 if (!--label->refcnt) {
3874 ELEM_REMOVE(&label->link);
3875 }
3876 else {
3877 label = NEW_LABEL(0);
3878 OPERAND_AT(jump, 0) = (VALUE)label;
3879 }
3880 label->refcnt++;
3881 ELEM_INSERT_NEXT(next, &label->link);
3882 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3883 }
3884 else {
3885 ELEM_REMOVE(next);
3886 }
3887 }
3888 }
3889
3890 if (do_tailcallopt &&
3891 (IS_INSN_ID(iobj, send) ||
3892 IS_INSN_ID(iobj, opt_aref_with) ||
3893 IS_INSN_ID(iobj, opt_aset_with) ||
3894 IS_INSN_ID(iobj, invokesuper))) {
3895 /*
3896 * send ...
3897 * leave
3898 * =>
3899 * send ..., ... | VM_CALL_TAILCALL, ...
3900 * leave # unreachable
3901 */
3902 INSN *piobj = NULL;
3903 if (iobj->link.next) {
3904 LINK_ELEMENT *next = iobj->link.next;
3905 do {
3906 if (!IS_INSN(next)) {
3907 next = next->next;
3908 continue;
3909 }
3910 switch (INSN_OF(next)) {
3911 case BIN(nop):
3912 next = next->next;
3913 break;
3914 case BIN(jump):
3915 /* if cond
3916 * return tailcall
3917 * end
3918 */
3919 next = get_destination_insn((INSN *)next);
3920 break;
3921 case BIN(leave):
3922 piobj = iobj;
3923 /* fall through */
3924 default:
3925 next = NULL;
3926 break;
3927 }
3928 } while (next);
3929 }
3930
3931 if (piobj) {
3932 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3933 if (IS_INSN_ID(piobj, send) ||
3934 IS_INSN_ID(piobj, invokesuper)) {
3935 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3936 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3937 OPERAND_AT(piobj, 0) = (VALUE)ci;
3938 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3939 }
3940 }
3941 else {
3942 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3943 OPERAND_AT(piobj, 0) = (VALUE)ci;
3944 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3945 }
3946 }
3947 }
3948
3949 if (IS_INSN_ID(iobj, dup)) {
3950 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3951 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3952
3953 /*
3954 * dup
3955 * setlocal x, y
3956 * setlocal x, y
3957 * =>
3958 * dup
3959 * setlocal x, y
3960 */
3961 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3962 set2 = set1->next;
3963 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3964 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3965 ELEM_REMOVE(set1);
3966 ELEM_REMOVE(&iobj->link);
3967 }
3968 }
3969
3970 /*
3971 * dup
3972 * setlocal x, y
3973 * dup
3974 * setlocal x, y
3975 * =>
3976 * dup
3977 * setlocal x, y
3978 */
3979 else if (IS_NEXT_INSN_ID(set1, dup) &&
3980 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3981 set2 = set1->next->next;
3982 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3983 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3984 ELEM_REMOVE(set1->next);
3985 ELEM_REMOVE(set2);
3986 }
3987 }
3988 }
3989 }
3990
3991 /*
3992 * getlocal x, y
3993 * dup
3994 * setlocal x, y
3995 * =>
3996 * dup
3997 */
3998 if (IS_INSN_ID(iobj, getlocal)) {
3999 LINK_ELEMENT *niobj = &iobj->link;
4000 if (IS_NEXT_INSN_ID(niobj, dup)) {
4001 niobj = niobj->next;
4002 }
4003 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4004 LINK_ELEMENT *set1 = niobj->next;
4005 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4006 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4007 ELEM_REMOVE(set1);
4008 ELEM_REMOVE(niobj);
4009 }
4010 }
4011 }
4012
4013 /*
4014 * opt_invokebuiltin_delegate
4015 * trace
4016 * leave
4017 * =>
4018 * opt_invokebuiltin_delegate_leave
4019 * trace
4020 * leave
4021 */
4022 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4023 if (IS_TRACE(iobj->link.next)) {
4024 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4025 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4026 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4027 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4028 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4029 }
4030 }
4031 }
4032 }
4033
4034 /*
4035 * getblockparam
4036 * branchif / branchunless
4037 * =>
4038 * getblockparamproxy
4039 * branchif / branchunless
4040 */
4041 if (IS_INSN_ID(iobj, getblockparam)) {
4042 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4043 iobj->insn_id = BIN(getblockparamproxy);
4044 }
4045 }
4046
4047 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4048 LINK_ELEMENT *niobj = &iobj->link;
4049 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4050 niobj = niobj->next;
4051 LINK_ELEMENT *siobj;
4052 unsigned int set_flags = 0, unset_flags = 0;
4053
4054 /*
4055 * Eliminate hash allocation for f(*a, kw: 1)
4056 *
4057 * splatarray false
4058 * duphash
4059 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4060 * =>
4061 * splatarray false
4062 * putobject
4063 * send ARGS_SPLAT|KW_SPLAT
4064 */
4065 if (IS_NEXT_INSN_ID(niobj, send)) {
4066 siobj = niobj->next;
4067 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4068 unset_flags = VM_CALL_ARGS_BLOCKARG;
4069 }
4070 /*
4071 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4072 *
4073 * splatarray false
4074 * duphash
4075 * getlocal / getinstancevariable / getblockparamproxy
4076 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4077 * =>
4078 * splatarray false
4079 * putobject
4080 * getlocal / getinstancevariable / getblockparamproxy
4081 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4082 */
4083 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4084 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4085 siobj = niobj->next->next;
4086 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4087 }
4088
4089 if (set_flags) {
4090 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4091 unsigned int flags = vm_ci_flag(ci);
4092 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4093 ((INSN*)niobj)->insn_id = BIN(putobject);
4094 OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
4095
4096 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4097 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4098 RB_OBJ_WRITTEN(iseq, ci, nci);
4099 OPERAND_AT(siobj, 0) = (VALUE)nci;
4100 }
4101 }
4102 }
4103 }
4104
4105 return COMPILE_OK;
4106}
4107
4108static int
4109insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4110{
4111 iobj->insn_id = insn_id;
4112 iobj->operand_size = insn_len(insn_id) - 1;
4113 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4114
4115 if (insn_id == BIN(opt_neq)) {
4116 VALUE original_ci = iobj->operands[0];
4117 iobj->operand_size = 2;
4118 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4119 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4120 iobj->operands[1] = original_ci;
4121 }
4122
4123 return COMPILE_OK;
4124}
4125
4126static int
4127iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4128{
4129 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4130 IS_INSN(iobj->link.next)) {
4131 /*
4132 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4133 */
4134 INSN *niobj = (INSN *)iobj->link.next;
4135 if (IS_INSN_ID(niobj, send)) {
4136 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4137 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4138 VALUE method = INT2FIX(0);
4139 switch (vm_ci_mid(ci)) {
4140 case idMax:
4141 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4142 break;
4143 case idMin:
4144 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4145 break;
4146 case idHash:
4147 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4148 break;
4149 }
4150
4151 if (method != INT2FIX(0)) {
4152 VALUE num = iobj->operands[0];
4153 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4154 iobj->insn_id = BIN(opt_newarray_send);
4155 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4156 iobj->operands[0] = num;
4157 iobj->operands[1] = method;
4158 iobj->operand_size = operand_len;
4159 ELEM_REMOVE(&niobj->link);
4160 return COMPILE_OK;
4161 }
4162 }
4163 }
4164 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4165 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4166 IS_NEXT_INSN_ID(&niobj->link, send)) {
4167 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4168 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4169 VALUE num = iobj->operands[0];
4170 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4171 iobj->insn_id = BIN(opt_newarray_send);
4172 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4173 iobj->operands[0] = FIXNUM_INC(num, 1);
4174 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4175 iobj->operand_size = operand_len;
4176 ELEM_REMOVE(&iobj->link);
4177 ELEM_REMOVE(niobj->link.next);
4178 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4179 return COMPILE_OK;
4180 }
4181 }
4182 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4183 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4184 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4185 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4186 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4187 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4188 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4189 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4190 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4191 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4192 VALUE num = iobj->operands[0];
4193 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4194 iobj->insn_id = BIN(opt_newarray_send);
4195 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4196 iobj->operands[0] = FIXNUM_INC(num, 2);
4197 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4198 iobj->operand_size = operand_len;
4199 // Remove the "send" insn.
4200 ELEM_REMOVE((niobj->link.next)->next);
4201 // Remove the modified insn from its original "newarray" position...
4202 ELEM_REMOVE(&iobj->link);
4203 // and insert it after the buffer insn.
4204 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4205 return COMPILE_OK;
4206 }
4207 }
4208
4209 // Break the "else if" chain since some prior checks abort after sub-ifs.
4210 // We already found "newarray". To match `[...].include?(arg)` we look for
4211 // the instruction(s) representing the argument followed by a "send".
4212 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4213 IS_INSN_ID(niobj, putobject) ||
4214 IS_INSN_ID(niobj, putself) ||
4215 IS_INSN_ID(niobj, getlocal) ||
4216 IS_INSN_ID(niobj, getinstancevariable)) &&
4217 IS_NEXT_INSN_ID(&niobj->link, send)) {
4218
4219 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4220 const struct rb_callinfo *ci;
4221 // Allow any number (0 or more) of simple method calls on the argument
4222 // (as in `[...].include?(arg.method1.method2)`.
4223 do {
4224 sendobj = sendobj->next;
4225 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4226 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4227
4228 // If this send is for .include? with one arg we can do our opt.
4229 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4230 VALUE num = iobj->operands[0];
4231 INSN *sendins = (INSN *)sendobj;
4232 sendins->insn_id = BIN(opt_newarray_send);
4233 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4234 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4235 sendins->operands[0] = FIXNUM_INC(num, 1);
4236 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4237 // Remove the original "newarray" insn.
4238 ELEM_REMOVE(&iobj->link);
4239 return COMPILE_OK;
4240 }
4241 }
4242 }
4243
4244 /*
4245 * duparray [...]
4246 * some insn for the arg...
4247 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4248 * =>
4249 * arg insn...
4250 * opt_duparray_send [...], :include?, 1
4251 */
4252 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4253 INSN *niobj = (INSN *)iobj->link.next;
4254 if ((IS_INSN_ID(niobj, getlocal) ||
4255 IS_INSN_ID(niobj, getinstancevariable) ||
4256 IS_INSN_ID(niobj, putself)) &&
4257 IS_NEXT_INSN_ID(&niobj->link, send)) {
4258
4259 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4260 const struct rb_callinfo *ci;
4261 // Allow any number (0 or more) of simple method calls on the argument
4262 // (as in `[...].include?(arg.method1.method2)`.
4263 do {
4264 sendobj = sendobj->next;
4265 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4266 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4267
4268 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4269 // Move the array arg from duparray to opt_duparray_send.
4270 VALUE ary = iobj->operands[0];
4272
4273 INSN *sendins = (INSN *)sendobj;
4274 sendins->insn_id = BIN(opt_duparray_send);
4275 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4276 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4277 sendins->operands[0] = ary;
4278 sendins->operands[1] = rb_id2sym(idIncludeP);
4279 sendins->operands[2] = INT2FIX(1);
4280
4281 // Remove the duparray insn.
4282 ELEM_REMOVE(&iobj->link);
4283 return COMPILE_OK;
4284 }
4285 }
4286 }
4287
4288
4289 if (IS_INSN_ID(iobj, send)) {
4290 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4291 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4292
4293#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4294 if (vm_ci_simple(ci)) {
4295 switch (vm_ci_argc(ci)) {
4296 case 0:
4297 switch (vm_ci_mid(ci)) {
4298 case idLength: SP_INSN(length); return COMPILE_OK;
4299 case idSize: SP_INSN(size); return COMPILE_OK;
4300 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4301 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4302 case idSucc: SP_INSN(succ); return COMPILE_OK;
4303 case idNot: SP_INSN(not); return COMPILE_OK;
4304 }
4305 break;
4306 case 1:
4307 switch (vm_ci_mid(ci)) {
4308 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4309 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4310 case idMULT: SP_INSN(mult); return COMPILE_OK;
4311 case idDIV: SP_INSN(div); return COMPILE_OK;
4312 case idMOD: SP_INSN(mod); return COMPILE_OK;
4313 case idEq: SP_INSN(eq); return COMPILE_OK;
4314 case idNeq: SP_INSN(neq); return COMPILE_OK;
4315 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4316 case idLT: SP_INSN(lt); return COMPILE_OK;
4317 case idLE: SP_INSN(le); return COMPILE_OK;
4318 case idGT: SP_INSN(gt); return COMPILE_OK;
4319 case idGE: SP_INSN(ge); return COMPILE_OK;
4320 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4321 case idAREF: SP_INSN(aref); return COMPILE_OK;
4322 case idAnd: SP_INSN(and); return COMPILE_OK;
4323 case idOr: SP_INSN(or); return COMPILE_OK;
4324 }
4325 break;
4326 case 2:
4327 switch (vm_ci_mid(ci)) {
4328 case idASET: SP_INSN(aset); return COMPILE_OK;
4329 }
4330 break;
4331 }
4332 }
4333
4334 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4335 iobj->insn_id = BIN(opt_send_without_block);
4336 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4337 }
4338 }
4339#undef SP_INSN
4340
4341 return COMPILE_OK;
4342}
4343
4344static inline int
4345tailcallable_p(rb_iseq_t *iseq)
4346{
4347 switch (ISEQ_BODY(iseq)->type) {
4348 case ISEQ_TYPE_TOP:
4349 case ISEQ_TYPE_EVAL:
4350 case ISEQ_TYPE_MAIN:
4351 /* not tail callable because cfp will be over popped */
4352 case ISEQ_TYPE_RESCUE:
4353 case ISEQ_TYPE_ENSURE:
4354 /* rescue block can't tail call because of errinfo */
4355 return FALSE;
4356 default:
4357 return TRUE;
4358 }
4359}
4360
4361static int
4362iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4363{
4364 LINK_ELEMENT *list;
4365 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4366 const int do_tailcallopt = tailcallable_p(iseq) &&
4367 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4368 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4369 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4370 int rescue_level = 0;
4371 int tailcallopt = do_tailcallopt;
4372
4373 list = FIRST_ELEMENT(anchor);
4374
4375 int do_block_optimization = 0;
4376 LABEL * block_loop_label = NULL;
4377
4378 // If we're optimizing a block
4379 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4380 do_block_optimization = 1;
4381
4382 // If the block starts with a nop and a label,
4383 // record the label so we can detect if it's a jump target
4384 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4385 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4386 block_loop_label = (LABEL *)le->next;
4387 }
4388 }
4389
4390 while (list) {
4391 if (IS_INSN(list)) {
4392 if (do_peepholeopt) {
4393 iseq_peephole_optimize(iseq, list, tailcallopt);
4394 }
4395 if (do_si) {
4396 iseq_specialized_instruction(iseq, (INSN *)list);
4397 }
4398 if (do_ou) {
4399 insn_operands_unification((INSN *)list);
4400 }
4401
4402 if (do_block_optimization) {
4403 INSN * item = (INSN *)list;
4404 // Give up if there is a throw
4405 if (IS_INSN_ID(item, throw)) {
4406 do_block_optimization = 0;
4407 }
4408 else {
4409 // If the instruction has a jump target, check if the
4410 // jump target is the block loop label
4411 const char *types = insn_op_types(item->insn_id);
4412 for (int j = 0; types[j]; j++) {
4413 if (types[j] == TS_OFFSET) {
4414 // If the jump target is equal to the block loop
4415 // label, then we can't do the optimization because
4416 // the leading `nop` instruction fires the block
4417 // entry tracepoint
4418 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4419 if (target == block_loop_label) {
4420 do_block_optimization = 0;
4421 }
4422 }
4423 }
4424 }
4425 }
4426 }
4427 if (IS_LABEL(list)) {
4428 switch (((LABEL *)list)->rescued) {
4429 case LABEL_RESCUE_BEG:
4430 rescue_level++;
4431 tailcallopt = FALSE;
4432 break;
4433 case LABEL_RESCUE_END:
4434 if (!--rescue_level) tailcallopt = do_tailcallopt;
4435 break;
4436 }
4437 }
4438 list = list->next;
4439 }
4440
4441 if (do_block_optimization) {
4442 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4443 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4444 ELEM_REMOVE(le);
4445 }
4446 }
4447 return COMPILE_OK;
4448}
4449
4450#if OPT_INSTRUCTIONS_UNIFICATION
4451static INSN *
4452new_unified_insn(rb_iseq_t *iseq,
4453 int insn_id, int size, LINK_ELEMENT *seq_list)
4454{
4455 INSN *iobj = 0;
4456 LINK_ELEMENT *list = seq_list;
4457 int i, argc = 0;
4458 VALUE *operands = 0, *ptr = 0;
4459
4460
4461 /* count argc */
4462 for (i = 0; i < size; i++) {
4463 iobj = (INSN *)list;
4464 argc += iobj->operand_size;
4465 list = list->next;
4466 }
4467
4468 if (argc > 0) {
4469 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4470 }
4471
4472 /* copy operands */
4473 list = seq_list;
4474 for (i = 0; i < size; i++) {
4475 iobj = (INSN *)list;
4476 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4477 ptr += iobj->operand_size;
4478 list = list->next;
4479 }
4480
4481 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4482}
4483#endif
4484
4485/*
4486 * This scheme can get more performance if do this optimize with
4487 * label address resolving.
4488 * It's future work (if compile time was bottle neck).
4489 */
4490static int
4491iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4492{
4493#if OPT_INSTRUCTIONS_UNIFICATION
4494 LINK_ELEMENT *list;
4495 INSN *iobj, *niobj;
4496 int id, k;
4497 intptr_t j;
4498
4499 list = FIRST_ELEMENT(anchor);
4500 while (list) {
4501 if (IS_INSN(list)) {
4502 iobj = (INSN *)list;
4503 id = iobj->insn_id;
4504 if (unified_insns_data[id] != 0) {
4505 const int *const *entry = unified_insns_data[id];
4506 for (j = 1; j < (intptr_t)entry[0]; j++) {
4507 const int *unified = entry[j];
4508 LINK_ELEMENT *li = list->next;
4509 for (k = 2; k < unified[1]; k++) {
4510 if (!IS_INSN(li) ||
4511 ((INSN *)li)->insn_id != unified[k]) {
4512 goto miss;
4513 }
4514 li = li->next;
4515 }
4516 /* matched */
4517 niobj =
4518 new_unified_insn(iseq, unified[0], unified[1] - 1,
4519 list);
4520
4521 /* insert to list */
4522 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4523 niobj->link.next = li;
4524 if (li) {
4525 li->prev = (LINK_ELEMENT *)niobj;
4526 }
4527
4528 list->prev->next = (LINK_ELEMENT *)niobj;
4529 list = (LINK_ELEMENT *)niobj;
4530 break;
4531 miss:;
4532 }
4533 }
4534 }
4535 list = list->next;
4536 }
4537#endif
4538 return COMPILE_OK;
4539}
4540
4541static int
4542all_string_result_p(const NODE *node)
4543{
4544 if (!node) return FALSE;
4545 switch (nd_type(node)) {
4546 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4547 return TRUE;
4548 case NODE_IF: case NODE_UNLESS:
4549 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4550 if (all_string_result_p(RNODE_IF(node)->nd_body))
4551 return all_string_result_p(RNODE_IF(node)->nd_else);
4552 return FALSE;
4553 case NODE_AND: case NODE_OR:
4554 if (!RNODE_AND(node)->nd_2nd)
4555 return all_string_result_p(RNODE_AND(node)->nd_1st);
4556 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4557 return FALSE;
4558 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4559 default:
4560 return FALSE;
4561 }
4562}
4563
4565 rb_iseq_t *const iseq;
4566 LINK_ANCHOR *const ret;
4567 VALUE lit;
4568 const NODE *lit_node;
4569 int cnt;
4570 int dregx;
4571};
4572
4573static int
4574append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4575{
4576 VALUE s = rb_str_new_mutable_parser_string(str);
4577 if (args->dregx) {
4578 VALUE error = rb_reg_check_preprocess(s);
4579 if (!NIL_P(error)) {
4580 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4581 return COMPILE_NG;
4582 }
4583 }
4584 if (NIL_P(args->lit)) {
4585 args->lit = s;
4586 args->lit_node = node;
4587 }
4588 else {
4589 rb_str_buf_append(args->lit, s);
4590 }
4591 return COMPILE_OK;
4592}
4593
4594static void
4595flush_dstr_fragment(struct dstr_ctxt *args)
4596{
4597 if (!NIL_P(args->lit)) {
4598 rb_iseq_t *iseq = args->iseq;
4599 VALUE lit = args->lit;
4600 args->lit = Qnil;
4601 lit = rb_fstring(lit);
4602 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4603 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4604 args->cnt++;
4605 }
4606}
4607
4608static int
4609compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4610{
4611 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4612 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4613
4614 if (str) {
4615 CHECK(append_dstr_fragment(args, node, str));
4616 }
4617
4618 while (list) {
4619 const NODE *const head = list->nd_head;
4620 if (nd_type_p(head, NODE_STR)) {
4621 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4622 }
4623 else if (nd_type_p(head, NODE_DSTR)) {
4624 CHECK(compile_dstr_fragments_0(args, head));
4625 }
4626 else {
4627 flush_dstr_fragment(args);
4628 rb_iseq_t *iseq = args->iseq;
4629 CHECK(COMPILE(args->ret, "each string", head));
4630 args->cnt++;
4631 }
4632 list = (struct RNode_LIST *)list->nd_next;
4633 }
4634 return COMPILE_OK;
4635}
4636
4637static int
4638compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4639{
4640 struct dstr_ctxt args = {
4641 .iseq = iseq, .ret = ret,
4642 .lit = Qnil, .lit_node = NULL,
4643 .cnt = 0, .dregx = dregx,
4644 };
4645 CHECK(compile_dstr_fragments_0(&args, node));
4646 flush_dstr_fragment(&args);
4647
4648 *cntp = args.cnt;
4649
4650 return COMPILE_OK;
4651}
4652
4653static int
4654compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4655{
4656 while (node && nd_type_p(node, NODE_BLOCK)) {
4657 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4658 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4659 node = RNODE_BLOCK(node)->nd_next;
4660 }
4661 if (node) {
4662 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4663 }
4664 return COMPILE_OK;
4665}
4666
4667static int
4668compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4669{
4670 int cnt;
4671 if (!RNODE_DSTR(node)->nd_next) {
4672 VALUE lit = rb_node_dstr_string_val(node);
4673 ADD_INSN1(ret, node, putstring, lit);
4674 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4675 }
4676 else {
4677 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4678 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4679 }
4680 return COMPILE_OK;
4681}
4682
4683static int
4684compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4685{
4686 int cnt;
4687 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4688
4689 if (!RNODE_DREGX(node)->nd_next) {
4690 if (!popped) {
4691 VALUE src = rb_node_dregx_string_val(node);
4692 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4693 ADD_INSN1(ret, node, putobject, match);
4694 RB_OBJ_WRITTEN(iseq, Qundef, match);
4695 }
4696 return COMPILE_OK;
4697 }
4698
4699 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4700 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4701
4702 if (popped) {
4703 ADD_INSN(ret, node, pop);
4704 }
4705
4706 return COMPILE_OK;
4707}
4708
4709static int
4710compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4711 LABEL *then_label, LABEL *else_label)
4712{
4713 const int line = nd_line(node);
4714 LABEL *lend = NEW_LABEL(line);
4715 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4716 + VM_SVAR_FLIPFLOP_START;
4717 VALUE key = INT2FIX(cnt);
4718
4719 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4720 ADD_INSNL(ret, node, branchif, lend);
4721
4722 /* *flip == 0 */
4723 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4724 ADD_INSNL(ret, node, branchunless, else_label);
4725 ADD_INSN1(ret, node, putobject, Qtrue);
4726 ADD_INSN1(ret, node, setspecial, key);
4727 if (!again) {
4728 ADD_INSNL(ret, node, jump, then_label);
4729 }
4730
4731 /* *flip == 1 */
4732 ADD_LABEL(ret, lend);
4733 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4734 ADD_INSNL(ret, node, branchunless, then_label);
4735 ADD_INSN1(ret, node, putobject, Qfalse);
4736 ADD_INSN1(ret, node, setspecial, key);
4737 ADD_INSNL(ret, node, jump, then_label);
4738
4739 return COMPILE_OK;
4740}
4741
4742static int
4743compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4744 LABEL *then_label, LABEL *else_label);
4745
4746#define COMPILE_SINGLE 2
4747static int
4748compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4749 LABEL *then_label, LABEL *else_label)
4750{
4751 DECL_ANCHOR(seq);
4752 INIT_ANCHOR(seq);
4753 LABEL *label = NEW_LABEL(nd_line(cond));
4754 if (!then_label) then_label = label;
4755 else if (!else_label) else_label = label;
4756
4757 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4758
4759 if (LIST_INSN_SIZE_ONE(seq)) {
4760 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4761 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4762 return COMPILE_OK;
4763 }
4764 if (!label->refcnt) {
4765 return COMPILE_SINGLE;
4766 }
4767 ADD_LABEL(seq, label);
4768 ADD_SEQ(ret, seq);
4769 return COMPILE_OK;
4770}
4771
4772static int
4773compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4774 LABEL *then_label, LABEL *else_label)
4775{
4776 int ok;
4777 DECL_ANCHOR(ignore);
4778
4779 again:
4780 switch (nd_type(cond)) {
4781 case NODE_AND:
4782 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4783 cond = RNODE_AND(cond)->nd_2nd;
4784 if (ok == COMPILE_SINGLE) {
4785 INIT_ANCHOR(ignore);
4786 ret = ignore;
4787 then_label = NEW_LABEL(nd_line(cond));
4788 }
4789 goto again;
4790 case NODE_OR:
4791 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4792 cond = RNODE_OR(cond)->nd_2nd;
4793 if (ok == COMPILE_SINGLE) {
4794 INIT_ANCHOR(ignore);
4795 ret = ignore;
4796 else_label = NEW_LABEL(nd_line(cond));
4797 }
4798 goto again;
4799 case NODE_SYM:
4800 case NODE_LINE:
4801 case NODE_FILE:
4802 case NODE_ENCODING:
4803 case NODE_INTEGER: /* NODE_INTEGER is always true */
4804 case NODE_FLOAT: /* NODE_FLOAT is always true */
4805 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4806 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4807 case NODE_TRUE:
4808 case NODE_STR:
4809 case NODE_REGX:
4810 case NODE_ZLIST:
4811 case NODE_LAMBDA:
4812 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4813 ADD_INSNL(ret, cond, jump, then_label);
4814 return COMPILE_OK;
4815 case NODE_FALSE:
4816 case NODE_NIL:
4817 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4818 ADD_INSNL(ret, cond, jump, else_label);
4819 return COMPILE_OK;
4820 case NODE_LIST:
4821 case NODE_ARGSCAT:
4822 case NODE_DREGX:
4823 case NODE_DSTR:
4824 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4825 ADD_INSNL(ret, cond, jump, then_label);
4826 return COMPILE_OK;
4827 case NODE_FLIP2:
4828 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4829 return COMPILE_OK;
4830 case NODE_FLIP3:
4831 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4832 return COMPILE_OK;
4833 case NODE_DEFINED:
4834 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4835 break;
4836 default:
4837 {
4838 DECL_ANCHOR(cond_seq);
4839 INIT_ANCHOR(cond_seq);
4840
4841 CHECK(COMPILE(cond_seq, "branch condition", cond));
4842
4843 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4844 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4845 if (insn->insn_id == BIN(putobject)) {
4846 if (RTEST(insn->operands[0])) {
4847 ADD_INSNL(ret, cond, jump, then_label);
4848 // maybe unreachable
4849 return COMPILE_OK;
4850 }
4851 else {
4852 ADD_INSNL(ret, cond, jump, else_label);
4853 return COMPILE_OK;
4854 }
4855 }
4856 }
4857 ADD_SEQ(ret, cond_seq);
4858 }
4859 break;
4860 }
4861
4862 ADD_INSNL(ret, cond, branchunless, else_label);
4863 ADD_INSNL(ret, cond, jump, then_label);
4864 return COMPILE_OK;
4865}
4866
4867#define HASH_BRACE 1
4868
4869static int
4870keyword_node_p(const NODE *const node)
4871{
4872 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4873}
4874
4875static VALUE
4876get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4877{
4878 switch (nd_type(node)) {
4879 case NODE_SYM:
4880 return rb_node_sym_string_val(node);
4881 default:
4882 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4883 }
4884}
4885
4886static VALUE
4887node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4888{
4889 NODE *node = node_hash->nd_head;
4890 VALUE hash = rb_hash_new();
4891 VALUE ary = rb_ary_new();
4892
4893 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4894 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4895 VALUE idx = rb_hash_aref(hash, key);
4896 if (!NIL_P(idx)) {
4897 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4898 (*count_ptr)--;
4899 }
4900 rb_hash_aset(hash, key, INT2FIX(i));
4901 rb_ary_store(ary, i, Qtrue);
4902 (*count_ptr)++;
4903 }
4904
4905 return ary;
4906}
4907
4908static int
4909compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4910 const NODE *const root_node,
4911 struct rb_callinfo_kwarg **const kw_arg_ptr,
4912 unsigned int *flag)
4913{
4914 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4915 RUBY_ASSERT(kw_arg_ptr != NULL);
4916 RUBY_ASSERT(flag != NULL);
4917
4918 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4919 const NODE *node = RNODE_HASH(root_node)->nd_head;
4920 int seen_nodes = 0;
4921
4922 while (node) {
4923 const NODE *key_node = RNODE_LIST(node)->nd_head;
4924 seen_nodes++;
4925
4926 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4927 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4928 /* can be keywords */
4929 }
4930 else {
4931 if (flag) {
4932 *flag |= VM_CALL_KW_SPLAT;
4933 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4934 /* A new hash will be created for the keyword arguments
4935 * in this case, so mark the method as passing mutable
4936 * keyword splat.
4937 */
4938 *flag |= VM_CALL_KW_SPLAT_MUT;
4939 }
4940 }
4941 return FALSE;
4942 }
4943 node = RNODE_LIST(node)->nd_next; /* skip value node */
4944 node = RNODE_LIST(node)->nd_next;
4945 }
4946
4947 /* may be keywords */
4948 node = RNODE_HASH(root_node)->nd_head;
4949 {
4950 int len = 0;
4951 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4952 struct rb_callinfo_kwarg *kw_arg =
4953 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4954 VALUE *keywords = kw_arg->keywords;
4955 int i = 0;
4956 int j = 0;
4957 kw_arg->references = 0;
4958 kw_arg->keyword_len = len;
4959
4960 *kw_arg_ptr = kw_arg;
4961
4962 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4963 const NODE *key_node = RNODE_LIST(node)->nd_head;
4964 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4965 int popped = TRUE;
4966 if (rb_ary_entry(key_index, i)) {
4967 keywords[j] = get_symbol_value(iseq, key_node);
4968 j++;
4969 popped = FALSE;
4970 }
4971 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4972 }
4973 RUBY_ASSERT(j == len);
4974 return TRUE;
4975 }
4976 }
4977 return FALSE;
4978}
4979
4980static int
4981compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4982{
4983 int len = 0;
4984
4985 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4986 if (CPDEBUG > 0) {
4987 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4988 }
4989
4990 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4991 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4992 }
4993 else {
4994 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4995 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4996 }
4997 }
4998
4999 return len;
5000}
5001
5002static inline bool
5003frozen_string_literal_p(const rb_iseq_t *iseq)
5004{
5005 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5006}
5007
5008static inline bool
5009static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5010{
5011 switch (nd_type(node)) {
5012 case NODE_SYM:
5013 case NODE_REGX:
5014 case NODE_LINE:
5015 case NODE_ENCODING:
5016 case NODE_INTEGER:
5017 case NODE_FLOAT:
5018 case NODE_RATIONAL:
5019 case NODE_IMAGINARY:
5020 case NODE_NIL:
5021 case NODE_TRUE:
5022 case NODE_FALSE:
5023 return TRUE;
5024 case NODE_STR:
5025 case NODE_FILE:
5026 return hash_key || frozen_string_literal_p(iseq);
5027 default:
5028 return FALSE;
5029 }
5030}
5031
5032static inline VALUE
5033static_literal_value(const NODE *node, rb_iseq_t *iseq)
5034{
5035 switch (nd_type(node)) {
5036 case NODE_INTEGER:
5037 return rb_node_integer_literal_val(node);
5038 case NODE_FLOAT:
5039 return rb_node_float_literal_val(node);
5040 case NODE_RATIONAL:
5041 return rb_node_rational_literal_val(node);
5042 case NODE_IMAGINARY:
5043 return rb_node_imaginary_literal_val(node);
5044 case NODE_NIL:
5045 return Qnil;
5046 case NODE_TRUE:
5047 return Qtrue;
5048 case NODE_FALSE:
5049 return Qfalse;
5050 case NODE_SYM:
5051 return rb_node_sym_string_val(node);
5052 case NODE_REGX:
5053 return rb_node_regx_string_val(node);
5054 case NODE_LINE:
5055 return rb_node_line_lineno_val(node);
5056 case NODE_ENCODING:
5057 return rb_node_encoding_val(node);
5058 case NODE_FILE:
5059 case NODE_STR:
5060 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5061 VALUE lit = get_string_value(node);
5062 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5063 }
5064 else {
5065 return get_string_value(node);
5066 }
5067 default:
5068 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5069 }
5070}
5071
5072static int
5073compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5074{
5075 const NODE *line_node = node;
5076
5077 if (nd_type_p(node, NODE_ZLIST)) {
5078 if (!popped) {
5079 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5080 }
5081 return 0;
5082 }
5083
5084 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5085
5086 if (popped) {
5087 for (; node; node = RNODE_LIST(node)->nd_next) {
5088 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5089 }
5090 return 1;
5091 }
5092
5093 /* Compilation of an array literal.
5094 * The following code is essentially the same as:
5095 *
5096 * for (int count = 0; node; count++; node->nd_next) {
5097 * compile(node->nd_head);
5098 * }
5099 * ADD_INSN(newarray, count);
5100 *
5101 * However, there are three points.
5102 *
5103 * - The code above causes stack overflow for a big string literal.
5104 * The following limits the stack length up to max_stack_len.
5105 *
5106 * [x1,x2,...,x10000] =>
5107 * push x1 ; push x2 ; ...; push x256; newarray 256;
5108 * push x257; push x258; ...; push x512; pushtoarray 256;
5109 * push x513; push x514; ...; push x768; pushtoarray 256;
5110 * ...
5111 *
5112 * - Long subarray can be optimized by pre-allocating a hidden array.
5113 *
5114 * [1,2,3,...,100] =>
5115 * duparray [1,2,3,...,100]
5116 *
5117 * [x, 1,2,3,...,100, z] =>
5118 * push x; newarray 1;
5119 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5120 * push z; pushtoarray 1;
5121 *
5122 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5123 * to only push it onto the array if it is not empty
5124 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5125 *
5126 * [1,2,3,**kw] =>
5127 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5128 */
5129
5130 const int max_stack_len = 0x100;
5131 const int min_tmp_ary_len = 0x40;
5132 int stack_len = 0;
5133
5134 /* Either create a new array, or push to the existing array */
5135#define FLUSH_CHUNK \
5136 if (stack_len) { \
5137 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5138 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5139 first_chunk = FALSE; \
5140 stack_len = 0; \
5141 }
5142
5143 while (node) {
5144 int count = 1;
5145
5146 /* pre-allocation check (this branch can be omittable) */
5147 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5148 /* count the elements that are optimizable */
5149 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5150 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5151 count++;
5152
5153 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5154 /* The literal contains only optimizable elements, or the subarray is long enough */
5155 VALUE ary = rb_ary_hidden_new(count);
5156
5157 /* Create a hidden array */
5158 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5159 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5160 OBJ_FREEZE(ary);
5161
5162 /* Emit optimized code */
5163 FLUSH_CHUNK;
5164 if (first_chunk) {
5165 ADD_INSN1(ret, line_node, duparray, ary);
5166 first_chunk = FALSE;
5167 }
5168 else {
5169 ADD_INSN1(ret, line_node, putobject, ary);
5170 ADD_INSN(ret, line_node, concattoarray);
5171 }
5172 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5173 }
5174 }
5175
5176 /* Base case: Compile "count" elements */
5177 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5178 if (CPDEBUG > 0) {
5179 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5180 }
5181
5182 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5183 /* Create array or push existing non-keyword elements onto array */
5184 if (stack_len == 0 && first_chunk) {
5185 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5186 }
5187 else {
5188 FLUSH_CHUNK;
5189 }
5190 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5191 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5192 return 1;
5193 }
5194 else {
5195 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5196 stack_len++;
5197 }
5198
5199 /* If there are many pushed elements, flush them to avoid stack overflow */
5200 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5201 }
5202 }
5203
5204 FLUSH_CHUNK;
5205#undef FLUSH_CHUNK
5206 return 1;
5207}
5208
5209static inline int
5210static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5211{
5212 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);
5213}
5214
5215static int
5216compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5217{
5218 const NODE *line_node = node;
5219
5220 node = RNODE_HASH(node)->nd_head;
5221
5222 if (!node || nd_type_p(node, NODE_ZLIST)) {
5223 if (!popped) {
5224 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5225 }
5226 return 0;
5227 }
5228
5229 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5230
5231 if (popped) {
5232 for (; node; node = RNODE_LIST(node)->nd_next) {
5233 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5234 }
5235 return 1;
5236 }
5237
5238 /* Compilation of a hash literal (or keyword arguments).
5239 * This is very similar to compile_array, but there are some differences:
5240 *
5241 * - It contains key-value pairs. So we need to take every two elements.
5242 * We can assume that the length is always even.
5243 *
5244 * - Merging is done by a method call (id_core_hash_merge_ptr).
5245 * Sometimes we need to insert the receiver, so "anchor" is needed.
5246 * In addition, a method call is much slower than concatarray.
5247 * So it pays only when the subsequence is really long.
5248 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5249 *
5250 * - We need to handle keyword splat: **kw.
5251 * For **kw, the key part (node->nd_head) is NULL, and the value part
5252 * (node->nd_next->nd_head) is "kw".
5253 * The code is a bit difficult to avoid hash allocation for **{}.
5254 */
5255
5256 const int max_stack_len = 0x100;
5257 const int min_tmp_hash_len = 0x800;
5258 int stack_len = 0;
5259 int first_chunk = 1;
5260 DECL_ANCHOR(anchor);
5261 INIT_ANCHOR(anchor);
5262
5263 /* Convert pushed elements to a hash, and merge if needed */
5264#define FLUSH_CHUNK() \
5265 if (stack_len) { \
5266 if (first_chunk) { \
5267 APPEND_LIST(ret, anchor); \
5268 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5269 } \
5270 else { \
5271 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5272 ADD_INSN(ret, line_node, swap); \
5273 APPEND_LIST(ret, anchor); \
5274 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5275 } \
5276 INIT_ANCHOR(anchor); \
5277 first_chunk = stack_len = 0; \
5278 }
5279
5280 while (node) {
5281 int count = 1;
5282
5283 /* pre-allocation check (this branch can be omittable) */
5284 if (static_literal_node_pair_p(node, iseq)) {
5285 /* count the elements that are optimizable */
5286 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5287 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5288 count++;
5289
5290 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5291 /* The literal contains only optimizable elements, or the subsequence is long enough */
5292 VALUE ary = rb_ary_hidden_new(count);
5293
5294 /* Create a hidden hash */
5295 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5296 VALUE elem[2];
5297 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5298 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5299 rb_ary_cat(ary, elem, 2);
5300 }
5301 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5302 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5303 hash = rb_obj_hide(hash);
5304 OBJ_FREEZE(hash);
5305
5306 /* Emit optimized code */
5307 FLUSH_CHUNK();
5308 if (first_chunk) {
5309 ADD_INSN1(ret, line_node, duphash, hash);
5310 first_chunk = 0;
5311 }
5312 else {
5313 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5314 ADD_INSN(ret, line_node, swap);
5315
5316 ADD_INSN1(ret, line_node, putobject, hash);
5317
5318 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5319 }
5320 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5321 }
5322 }
5323
5324 /* Base case: Compile "count" elements */
5325 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5326
5327 if (CPDEBUG > 0) {
5328 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5329 }
5330
5331 if (RNODE_LIST(node)->nd_head) {
5332 /* Normal key-value pair */
5333 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5334 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5335 stack_len += 2;
5336
5337 /* If there are many pushed elements, flush them to avoid stack overflow */
5338 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5339 }
5340 else {
5341 /* kwsplat case: foo(..., **kw, ...) */
5342 FLUSH_CHUNK();
5343
5344 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5345 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5346 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5347 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5348 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5349
5350 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5351 if (empty_kw) {
5352 if (only_kw && method_call_keywords) {
5353 /* **{} appears at the only keyword argument in method call,
5354 * so it won't be modified.
5355 * kw is a special NODE_LIT that contains a special empty hash,
5356 * so this emits: putobject {}.
5357 * This is only done for method calls and not for literal hashes,
5358 * because literal hashes should always result in a new hash.
5359 */
5360 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5361 }
5362 else if (first_kw) {
5363 /* **{} appears as the first keyword argument, so it may be modified.
5364 * We need to create a fresh hash object.
5365 */
5366 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5367 }
5368 /* Any empty keyword splats that are not the first can be ignored.
5369 * since merging an empty hash into the existing hash is the same
5370 * as not merging it. */
5371 }
5372 else {
5373 if (only_kw && method_call_keywords) {
5374 /* **kw is only keyword argument in method call.
5375 * Use directly. This will be not be flagged as mutable.
5376 * This is only done for method calls and not for literal hashes,
5377 * because literal hashes should always result in a new hash.
5378 */
5379 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5380 }
5381 else {
5382 /* There is more than one keyword argument, or this is not a method
5383 * call. In that case, we need to add an empty hash (if first keyword),
5384 * or merge the hash to the accumulated hash (if not the first keyword).
5385 */
5386 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5387 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5388 else ADD_INSN(ret, line_node, swap);
5389
5390 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5391
5392 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5393 }
5394 }
5395
5396 first_chunk = 0;
5397 }
5398 }
5399 }
5400
5401 FLUSH_CHUNK();
5402#undef FLUSH_CHUNK
5403 return 1;
5404}
5405
5406VALUE
5407rb_node_case_when_optimizable_literal(const NODE *const node)
5408{
5409 switch (nd_type(node)) {
5410 case NODE_INTEGER:
5411 return rb_node_integer_literal_val(node);
5412 case NODE_FLOAT: {
5413 VALUE v = rb_node_float_literal_val(node);
5414 double ival;
5415
5416 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5417 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5418 }
5419 return v;
5420 }
5421 case NODE_RATIONAL:
5422 case NODE_IMAGINARY:
5423 return Qundef;
5424 case NODE_NIL:
5425 return Qnil;
5426 case NODE_TRUE:
5427 return Qtrue;
5428 case NODE_FALSE:
5429 return Qfalse;
5430 case NODE_SYM:
5431 return rb_node_sym_string_val(node);
5432 case NODE_LINE:
5433 return rb_node_line_lineno_val(node);
5434 case NODE_STR:
5435 return rb_node_str_string_val(node);
5436 case NODE_FILE:
5437 return rb_node_file_path_val(node);
5438 }
5439 return Qundef;
5440}
5441
5442static int
5443when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5444 LABEL *l1, int only_special_literals, VALUE literals)
5445{
5446 while (vals) {
5447 const NODE *val = RNODE_LIST(vals)->nd_head;
5448 VALUE lit = rb_node_case_when_optimizable_literal(val);
5449
5450 if (UNDEF_P(lit)) {
5451 only_special_literals = 0;
5452 }
5453 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5454 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5455 }
5456
5457 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5458 debugp_param("nd_lit", get_string_value(val));
5459 lit = get_string_value(val);
5460 ADD_INSN1(cond_seq, val, putobject, lit);
5461 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5462 }
5463 else {
5464 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5465 }
5466
5467 // Emit pattern === target
5468 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5469 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5470 ADD_INSNL(cond_seq, val, branchif, l1);
5471 vals = RNODE_LIST(vals)->nd_next;
5472 }
5473 return only_special_literals;
5474}
5475
5476static int
5477when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5478 LABEL *l1, int only_special_literals, VALUE literals)
5479{
5480 const NODE *line_node = vals;
5481
5482 switch (nd_type(vals)) {
5483 case NODE_LIST:
5484 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5485 return COMPILE_NG;
5486 break;
5487 case NODE_SPLAT:
5488 ADD_INSN (cond_seq, line_node, dup);
5489 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5490 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5491 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5492 ADD_INSNL(cond_seq, line_node, branchif, l1);
5493 break;
5494 case NODE_ARGSCAT:
5495 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5496 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5497 break;
5498 case NODE_ARGSPUSH:
5499 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5500 ADD_INSN (cond_seq, line_node, dup);
5501 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5502 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5503 ADD_INSNL(cond_seq, line_node, branchif, l1);
5504 break;
5505 default:
5506 ADD_INSN (cond_seq, line_node, dup);
5507 CHECK(COMPILE(cond_seq, "when val", vals));
5508 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5509 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5510 ADD_INSNL(cond_seq, line_node, branchif, l1);
5511 break;
5512 }
5513 return COMPILE_OK;
5514}
5515
5516/* Multiple Assignment Handling
5517 *
5518 * In order to handle evaluation of multiple assignment such that the left hand side
5519 * is evaluated before the right hand side, we need to process the left hand side
5520 * and see if there are any attributes that need to be assigned, or constants set
5521 * on explicit objects. If so, we add instructions to evaluate the receiver of
5522 * any assigned attributes or constants before we process the right hand side.
5523 *
5524 * For a multiple assignment such as:
5525 *
5526 * l1.m1, l2[0] = r3, r4
5527 *
5528 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5529 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5530 * On the VM stack, this looks like:
5531 *
5532 * self # putself
5533 * l1 # send
5534 * l1, self # putself
5535 * l1, l2 # send
5536 * l1, l2, 0 # putobject 0
5537 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5538 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5539 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5540 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5541 * l1, l2, 0, [r3, r4], r4, m1= # send
5542 * l1, l2, 0, [r3, r4], r4 # pop
5543 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5544 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5545 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5546 * l1, l2, 0, [r3, r4], r4, []= # send
5547 * l1, l2, 0, [r3, r4], r4 # pop
5548 * l1, l2, 0, [r3, r4] # pop
5549 * [r3, r4], l2, 0, [r3, r4] # setn 3
5550 * [r3, r4], l2, 0 # pop
5551 * [r3, r4], l2 # pop
5552 * [r3, r4] # pop
5553 *
5554 * This is made more complex when you have to handle splats, post args,
5555 * and arbitrary levels of nesting. You need to keep track of the total
5556 * number of attributes to set, and for each attribute, how many entries
5557 * are on the stack before the final attribute, in order to correctly
5558 * calculate the topn value to use to get the receiver of the attribute
5559 * setter method.
5560 *
5561 * A brief description of the VM stack for simple multiple assignment
5562 * with no splat (rhs_array will not be present if the return value of
5563 * the multiple assignment is not needed):
5564 *
5565 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5566 *
5567 * For multiple assignment with splats, while processing the part before
5568 * the splat (splat+post here is an array of the splat and the post arguments):
5569 *
5570 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5571 *
5572 * When processing the splat and post arguments:
5573 *
5574 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5575 *
5576 * When processing nested multiple assignment, existing values on the stack
5577 * are kept. So for:
5578 *
5579 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5580 *
5581 * The stack layout would be the following before processing the nested
5582 * multiple assignment:
5583 *
5584 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5585 *
5586 * In order to handle this correctly, we need to keep track of the nesting
5587 * level for each attribute assignment, as well as the attribute number
5588 * (left hand side attributes are processed left to right) and number of
5589 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5590 * this information.
5591 *
5592 * We also need to track information for the entire multiple assignment, such
5593 * as the total number of arguments, and the current nesting level, to
5594 * handle both nested multiple assignment as well as cases where the
5595 * rhs is not needed. We also need to keep track of all attribute
5596 * assignments in this, which we do using a linked listed. struct masgn_state
5597 * tracks this information.
5598 */
5599
5601 INSN *before_insn;
5602 struct masgn_lhs_node *next;
5603 const NODE *line_node;
5604 int argn;
5605 int num_args;
5606 int lhs_pos;
5607};
5608
5610 struct masgn_lhs_node *first_memo;
5611 struct masgn_lhs_node *last_memo;
5612 int lhs_level;
5613 int num_args;
5614 bool nested;
5615};
5616
5617static int
5618add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5619{
5620 if (!state) {
5621 rb_bug("no masgn_state");
5622 }
5623
5624 struct masgn_lhs_node *memo;
5625 memo = malloc(sizeof(struct masgn_lhs_node));
5626 if (!memo) {
5627 return COMPILE_NG;
5628 }
5629
5630 memo->before_insn = before_insn;
5631 memo->line_node = line_node;
5632 memo->argn = state->num_args + 1;
5633 memo->num_args = argc;
5634 state->num_args += argc;
5635 memo->lhs_pos = lhs_pos;
5636 memo->next = NULL;
5637 if (!state->first_memo) {
5638 state->first_memo = memo;
5639 }
5640 else {
5641 state->last_memo->next = memo;
5642 }
5643 state->last_memo = memo;
5644
5645 return COMPILE_OK;
5646}
5647
5648static 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);
5649
5650static int
5651compile_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)
5652{
5653 switch (nd_type(node)) {
5654 case NODE_ATTRASGN: {
5655 INSN *iobj;
5656 const NODE *line_node = node;
5657
5658 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5659
5660 bool safenav_call = false;
5661 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5662 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5663 ASSUME(iobj);
5664 ELEM_REMOVE(insn_element);
5665 if (!IS_INSN_ID(iobj, send)) {
5666 safenav_call = true;
5667 iobj = (INSN *)get_prev_insn(iobj);
5668 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5669 }
5670 (pre->last = iobj->link.prev)->next = 0;
5671
5672 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5673 int argc = vm_ci_argc(ci) + 1;
5674 ci = ci_argc_set(iseq, ci, argc);
5675 OPERAND_AT(iobj, 0) = (VALUE)ci;
5676 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5677
5678 if (argc == 1) {
5679 ADD_INSN(lhs, line_node, swap);
5680 }
5681 else {
5682 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5683 }
5684
5685 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5686 return COMPILE_NG;
5687 }
5688
5689 iobj->link.prev = lhs->last;
5690 lhs->last->next = &iobj->link;
5691 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5692 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5693 int argc = vm_ci_argc(ci);
5694 bool dupsplat = false;
5695 ci = ci_argc_set(iseq, ci, argc - 1);
5696 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5697 /* Given h[*a], _ = ary
5698 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5699 * `a` must be dupped, because it will be appended with ary[0]
5700 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5701 */
5702 dupsplat = true;
5703 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5704 }
5705 OPERAND_AT(iobj, 0) = (VALUE)ci;
5706 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5707
5708 /* Given: h[*a], h[*b, 1] = ary
5709 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5710 * so this uses splatarray true on a to dup it before using pushtoarray
5711 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5712 * so you can use pushtoarray directly
5713 */
5714 int line_no = nd_line(line_node);
5715 int node_id = nd_node_id(line_node);
5716
5717 if (dupsplat) {
5718 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5719 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5720 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5721 }
5722 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5723 }
5724 if (!safenav_call) {
5725 ADD_INSN(lhs, line_node, pop);
5726 if (argc != 1) {
5727 ADD_INSN(lhs, line_node, pop);
5728 }
5729 }
5730 for (int i=0; i < argc; i++) {
5731 ADD_INSN(post, line_node, pop);
5732 }
5733 break;
5734 }
5735 case NODE_MASGN: {
5736 DECL_ANCHOR(nest_rhs);
5737 INIT_ANCHOR(nest_rhs);
5738 DECL_ANCHOR(nest_lhs);
5739 INIT_ANCHOR(nest_lhs);
5740
5741 int prev_level = state->lhs_level;
5742 bool prev_nested = state->nested;
5743 state->nested = 1;
5744 state->lhs_level = lhs_pos - 1;
5745 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5746 state->lhs_level = prev_level;
5747 state->nested = prev_nested;
5748
5749 ADD_SEQ(lhs, nest_rhs);
5750 ADD_SEQ(lhs, nest_lhs);
5751 break;
5752 }
5753 case NODE_CDECL:
5754 if (!RNODE_CDECL(node)->nd_vid) {
5755 /* Special handling only needed for expr::C, not for C */
5756 INSN *iobj;
5757
5758 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5759
5760 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5761 iobj = (INSN *)insn_element; /* setconstant insn */
5762 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5763 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5764 ELEM_REMOVE(insn_element);
5765 pre->last = iobj->link.prev;
5766 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5767
5768 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5769 return COMPILE_NG;
5770 }
5771
5772 ADD_INSN(post, node, pop);
5773 break;
5774 }
5775 /* Fallthrough */
5776 default: {
5777 DECL_ANCHOR(anchor);
5778 INIT_ANCHOR(anchor);
5779 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5780 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5781 ADD_SEQ(lhs, anchor);
5782 }
5783 }
5784
5785 return COMPILE_OK;
5786}
5787
5788static int
5789compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5790{
5791 if (lhsn) {
5792 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5793 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5794 }
5795 return COMPILE_OK;
5796}
5797
5798static int
5799compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5800 const NODE *rhsn, const NODE *orig_lhsn)
5801{
5802 VALUE mem[64];
5803 const int memsize = numberof(mem);
5804 int memindex = 0;
5805 int llen = 0, rlen = 0;
5806 int i;
5807 const NODE *lhsn = orig_lhsn;
5808
5809#define MEMORY(v) { \
5810 int i; \
5811 if (memindex == memsize) return 0; \
5812 for (i=0; i<memindex; i++) { \
5813 if (mem[i] == (v)) return 0; \
5814 } \
5815 mem[memindex++] = (v); \
5816}
5817
5818 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5819 return 0;
5820 }
5821
5822 while (lhsn) {
5823 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5824 switch (nd_type(ln)) {
5825 case NODE_LASGN:
5826 case NODE_DASGN:
5827 case NODE_IASGN:
5828 case NODE_CVASGN:
5829 MEMORY(get_nd_vid(ln));
5830 break;
5831 default:
5832 return 0;
5833 }
5834 lhsn = RNODE_LIST(lhsn)->nd_next;
5835 llen++;
5836 }
5837
5838 while (rhsn) {
5839 if (llen <= rlen) {
5840 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5841 }
5842 else {
5843 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5844 }
5845 rhsn = RNODE_LIST(rhsn)->nd_next;
5846 rlen++;
5847 }
5848
5849 if (llen > rlen) {
5850 for (i=0; i<llen-rlen; i++) {
5851 ADD_INSN(ret, orig_lhsn, putnil);
5852 }
5853 }
5854
5855 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5856 return 1;
5857}
5858
5859static int
5860compile_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)
5861{
5862 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5863 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5864 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5865 const NODE *lhsn_count = lhsn;
5866 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5867
5868 int llen = 0;
5869 int lpos = 0;
5870
5871 while (lhsn_count) {
5872 llen++;
5873 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5874 }
5875 while (lhsn) {
5876 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5877 lpos++;
5878 lhsn = RNODE_LIST(lhsn)->nd_next;
5879 }
5880
5881 if (lhs_splat) {
5882 if (nd_type_p(splatn, NODE_POSTARG)) {
5883 /*a, b, *r, p1, p2 */
5884 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5885 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5886 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5887 int ppos = 0;
5888 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5889
5890 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5891
5892 if (NODE_NAMED_REST_P(restn)) {
5893 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5894 }
5895 while (postn) {
5896 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5897 ppos++;
5898 postn = RNODE_LIST(postn)->nd_next;
5899 }
5900 }
5901 else {
5902 /* a, b, *r */
5903 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5904 }
5905 }
5906
5907 if (!state->nested) {
5908 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5909 }
5910
5911 if (!popped) {
5912 ADD_INSN(rhs, node, dup);
5913 }
5914 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5915 return COMPILE_OK;
5916}
5917
5918static int
5919compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5920{
5921 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5922 struct masgn_state state;
5923 state.lhs_level = popped ? 0 : 1;
5924 state.nested = 0;
5925 state.num_args = 0;
5926 state.first_memo = NULL;
5927 state.last_memo = NULL;
5928
5929 DECL_ANCHOR(pre);
5930 INIT_ANCHOR(pre);
5931 DECL_ANCHOR(rhs);
5932 INIT_ANCHOR(rhs);
5933 DECL_ANCHOR(lhs);
5934 INIT_ANCHOR(lhs);
5935 DECL_ANCHOR(post);
5936 INIT_ANCHOR(post);
5937 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5938
5939 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5940 while (memo) {
5941 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5942 for (int i = 0; i < memo->num_args; i++) {
5943 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5944 }
5945 tmp_memo = memo->next;
5946 free(memo);
5947 memo = tmp_memo;
5948 }
5949 CHECK(ok);
5950
5951 ADD_SEQ(ret, pre);
5952 ADD_SEQ(ret, rhs);
5953 ADD_SEQ(ret, lhs);
5954 if (!popped && state.num_args >= 1) {
5955 /* make sure rhs array is returned before popping */
5956 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5957 }
5958 ADD_SEQ(ret, post);
5959 }
5960 return COMPILE_OK;
5961}
5962
5963static VALUE
5964collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5965{
5966 VALUE arr = rb_ary_new();
5967 for (;;) {
5968 switch (nd_type(node)) {
5969 case NODE_CONST:
5970 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5971 return arr;
5972 case NODE_COLON3:
5973 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5974 rb_ary_unshift(arr, ID2SYM(idNULL));
5975 return arr;
5976 case NODE_COLON2:
5977 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5978 node = RNODE_COLON2(node)->nd_head;
5979 break;
5980 default:
5981 return Qfalse;
5982 }
5983 }
5984}
5985
5986static int
5987compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5988 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5989{
5990 switch (nd_type(node)) {
5991 case NODE_CONST:
5992 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5993 ADD_INSN1(body, node, putobject, Qtrue);
5994 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5995 break;
5996 case NODE_COLON3:
5997 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5998 ADD_INSN(body, node, pop);
5999 ADD_INSN1(body, node, putobject, rb_cObject);
6000 ADD_INSN1(body, node, putobject, Qtrue);
6001 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6002 break;
6003 case NODE_COLON2:
6004 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6005 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6006 ADD_INSN1(body, node, putobject, Qfalse);
6007 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6008 break;
6009 default:
6010 CHECK(COMPILE(pref, "const colon2 prefix", node));
6011 break;
6012 }
6013 return COMPILE_OK;
6014}
6015
6016static int
6017compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6018{
6019 if (nd_type_p(cpath, NODE_COLON3)) {
6020 /* toplevel class ::Foo */
6021 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6022 return VM_DEFINECLASS_FLAG_SCOPED;
6023 }
6024 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6025 /* Bar::Foo */
6026 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6027 return VM_DEFINECLASS_FLAG_SCOPED;
6028 }
6029 else {
6030 /* class at cbase Foo */
6031 ADD_INSN1(ret, cpath, putspecialobject,
6032 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6033 return 0;
6034 }
6035}
6036
6037static inline int
6038private_recv_p(const NODE *node)
6039{
6040 NODE *recv = get_nd_recv(node);
6041 if (recv && nd_type_p(recv, NODE_SELF)) {
6042 return RNODE_SELF(recv)->nd_state != 0;
6043 }
6044 return 0;
6045}
6046
6047static void
6048defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6049 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6050
6051static int
6052compile_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);
6053
6054static void
6055defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6056 const NODE *const node, LABEL **lfinish, VALUE needstr,
6057 bool keep_result)
6058{
6059 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6060 enum node_type type;
6061 const int line = nd_line(node);
6062 const NODE *line_node = node;
6063
6064 switch (type = nd_type(node)) {
6065
6066 /* easy literals */
6067 case NODE_NIL:
6068 expr_type = DEFINED_NIL;
6069 break;
6070 case NODE_SELF:
6071 expr_type = DEFINED_SELF;
6072 break;
6073 case NODE_TRUE:
6074 expr_type = DEFINED_TRUE;
6075 break;
6076 case NODE_FALSE:
6077 expr_type = DEFINED_FALSE;
6078 break;
6079
6080 case NODE_HASH:
6081 case NODE_LIST:{
6082 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6083
6084 if (vals) {
6085 do {
6086 if (RNODE_LIST(vals)->nd_head) {
6087 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6088
6089 if (!lfinish[1]) {
6090 lfinish[1] = NEW_LABEL(line);
6091 }
6092 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6093 }
6094 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6095 }
6096 }
6097 /* fall through */
6098 case NODE_STR:
6099 case NODE_SYM:
6100 case NODE_REGX:
6101 case NODE_LINE:
6102 case NODE_FILE:
6103 case NODE_ENCODING:
6104 case NODE_INTEGER:
6105 case NODE_FLOAT:
6106 case NODE_RATIONAL:
6107 case NODE_IMAGINARY:
6108 case NODE_ZLIST:
6109 case NODE_AND:
6110 case NODE_OR:
6111 default:
6112 expr_type = DEFINED_EXPR;
6113 break;
6114
6115 case NODE_SPLAT:
6116 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6117 if (!lfinish[1]) {
6118 lfinish[1] = NEW_LABEL(line);
6119 }
6120 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6121 expr_type = DEFINED_EXPR;
6122 break;
6123
6124 /* variables */
6125 case NODE_LVAR:
6126 case NODE_DVAR:
6127 expr_type = DEFINED_LVAR;
6128 break;
6129
6130#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6131 case NODE_IVAR:
6132 ADD_INSN3(ret, line_node, definedivar,
6133 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6134 return;
6135
6136 case NODE_GVAR:
6137 ADD_INSN(ret, line_node, putnil);
6138 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6139 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6140 return;
6141
6142 case NODE_CVAR:
6143 ADD_INSN(ret, line_node, putnil);
6144 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6145 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6146 return;
6147
6148 case NODE_CONST:
6149 ADD_INSN(ret, line_node, putnil);
6150 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6151 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6152 return;
6153 case NODE_COLON2:
6154 if (!lfinish[1]) {
6155 lfinish[1] = NEW_LABEL(line);
6156 }
6157 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6158 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6159 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6160
6161 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6162 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6163 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6164 }
6165 else {
6166 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6167 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6168 }
6169 return;
6170 case NODE_COLON3:
6171 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6172 ADD_INSN3(ret, line_node, defined,
6173 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6174 return;
6175
6176 /* method dispatch */
6177 case NODE_CALL:
6178 case NODE_OPCALL:
6179 case NODE_VCALL:
6180 case NODE_FCALL:
6181 case NODE_ATTRASGN:{
6182 const int explicit_receiver =
6183 (type == NODE_CALL || type == NODE_OPCALL ||
6184 (type == NODE_ATTRASGN && !private_recv_p(node)));
6185
6186 if (get_nd_args(node) || explicit_receiver) {
6187 if (!lfinish[1]) {
6188 lfinish[1] = NEW_LABEL(line);
6189 }
6190 if (!lfinish[2]) {
6191 lfinish[2] = NEW_LABEL(line);
6192 }
6193 }
6194 if (get_nd_args(node)) {
6195 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6196 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6197 }
6198 if (explicit_receiver) {
6199 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6200 switch (nd_type(get_nd_recv(node))) {
6201 case NODE_CALL:
6202 case NODE_OPCALL:
6203 case NODE_VCALL:
6204 case NODE_FCALL:
6205 case NODE_ATTRASGN:
6206 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6207 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6208 break;
6209 default:
6210 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6211 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6212 break;
6213 }
6214 if (keep_result) {
6215 ADD_INSN(ret, line_node, dup);
6216 }
6217 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6218 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6219 }
6220 else {
6221 ADD_INSN(ret, line_node, putself);
6222 if (keep_result) {
6223 ADD_INSN(ret, line_node, dup);
6224 }
6225 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6226 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6227 }
6228 return;
6229 }
6230
6231 case NODE_YIELD:
6232 ADD_INSN(ret, line_node, putnil);
6233 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6234 PUSH_VAL(DEFINED_YIELD));
6235 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6236 return;
6237
6238 case NODE_BACK_REF:
6239 case NODE_NTH_REF:
6240 ADD_INSN(ret, line_node, putnil);
6241 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6242 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6243 PUSH_VAL(DEFINED_GVAR));
6244 return;
6245
6246 case NODE_SUPER:
6247 case NODE_ZSUPER:
6248 ADD_INSN(ret, line_node, putnil);
6249 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6250 PUSH_VAL(DEFINED_ZSUPER));
6251 return;
6252
6253#undef PUSH_VAL
6254 case NODE_OP_ASGN1:
6255 case NODE_OP_ASGN2:
6256 case NODE_OP_ASGN_OR:
6257 case NODE_OP_ASGN_AND:
6258 case NODE_MASGN:
6259 case NODE_LASGN:
6260 case NODE_DASGN:
6261 case NODE_GASGN:
6262 case NODE_IASGN:
6263 case NODE_CDECL:
6264 case NODE_CVASGN:
6265 case NODE_OP_CDECL:
6266 expr_type = DEFINED_ASGN;
6267 break;
6268 }
6269
6270 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6271
6272 if (needstr != Qfalse) {
6273 VALUE str = rb_iseq_defined_string(expr_type);
6274 ADD_INSN1(ret, line_node, putobject, str);
6275 }
6276 else {
6277 ADD_INSN1(ret, line_node, putobject, Qtrue);
6278 }
6279}
6280
6281static void
6282build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6283{
6284 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6285 iseq_set_exception_local_table(iseq);
6286}
6287
6288static void
6289defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6290 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6291{
6292 LINK_ELEMENT *lcur = ret->last;
6293 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6294 if (lfinish[1]) {
6295 int line = nd_line(node);
6296 LABEL *lstart = NEW_LABEL(line);
6297 LABEL *lend = NEW_LABEL(line);
6298 const rb_iseq_t *rescue;
6300 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6301 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6302 rb_str_concat(rb_str_new2("defined guard in "),
6303 ISEQ_BODY(iseq)->location.label),
6304 ISEQ_TYPE_RESCUE, 0);
6305 lstart->rescued = LABEL_RESCUE_BEG;
6306 lend->rescued = LABEL_RESCUE_END;
6307 APPEND_LABEL(ret, lcur, lstart);
6308 ADD_LABEL(ret, lend);
6309 if (!ignore) {
6310 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6311 }
6312 }
6313}
6314
6315static int
6316compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6317{
6318 const int line = nd_line(node);
6319 const NODE *line_node = node;
6320 if (!RNODE_DEFINED(node)->nd_head) {
6321 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6322 ADD_INSN1(ret, line_node, putobject, str);
6323 }
6324 else {
6325 LABEL *lfinish[3];
6326 LINK_ELEMENT *last = ret->last;
6327 lfinish[0] = NEW_LABEL(line);
6328 lfinish[1] = 0;
6329 lfinish[2] = 0;
6330 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6331 if (lfinish[1]) {
6332 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6333 ADD_INSN(ret, line_node, swap);
6334 if (lfinish[2]) {
6335 ADD_LABEL(ret, lfinish[2]);
6336 }
6337 ADD_INSN(ret, line_node, pop);
6338 ADD_LABEL(ret, lfinish[1]);
6339 }
6340 ADD_LABEL(ret, lfinish[0]);
6341 }
6342 return COMPILE_OK;
6343}
6344
6345static VALUE
6346make_name_for_block(const rb_iseq_t *orig_iseq)
6347{
6348 int level = 1;
6349 const rb_iseq_t *iseq = orig_iseq;
6350
6351 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6352 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6353 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6354 level++;
6355 }
6356 iseq = ISEQ_BODY(iseq)->parent_iseq;
6357 }
6358 }
6359
6360 if (level == 1) {
6361 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6362 }
6363 else {
6364 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6365 }
6366}
6367
6368static void
6369push_ensure_entry(rb_iseq_t *iseq,
6371 struct ensure_range *er, const void *const node)
6372{
6373 enl->ensure_node = node;
6374 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6375 enl->erange = er;
6376 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6377}
6378
6379static void
6380add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6381 LABEL *lstart, LABEL *lend)
6382{
6383 struct ensure_range *ne =
6384 compile_data_alloc(iseq, sizeof(struct ensure_range));
6385
6386 while (erange->next != 0) {
6387 erange = erange->next;
6388 }
6389 ne->next = 0;
6390 ne->begin = lend;
6391 ne->end = erange->end;
6392 erange->end = lstart;
6393
6394 erange->next = ne;
6395}
6396
6397static bool
6398can_add_ensure_iseq(const rb_iseq_t *iseq)
6399{
6401 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6402 while (e) {
6403 if (e->ensure_node) return false;
6404 e = e->prev;
6405 }
6406 }
6407 return true;
6408}
6409
6410static void
6411add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6412{
6413 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6414
6416 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6417 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6418 DECL_ANCHOR(ensure);
6419
6420 INIT_ANCHOR(ensure);
6421 while (enlp) {
6422 if (enlp->erange != NULL) {
6423 DECL_ANCHOR(ensure_part);
6424 LABEL *lstart = NEW_LABEL(0);
6425 LABEL *lend = NEW_LABEL(0);
6426 INIT_ANCHOR(ensure_part);
6427
6428 add_ensure_range(iseq, enlp->erange, lstart, lend);
6429
6430 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6431 ADD_LABEL(ensure_part, lstart);
6432 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6433 ADD_LABEL(ensure_part, lend);
6434 ADD_SEQ(ensure, ensure_part);
6435 }
6436 else {
6437 if (!is_return) {
6438 break;
6439 }
6440 }
6441 enlp = enlp->prev;
6442 }
6443 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6444 ADD_SEQ(ret, ensure);
6445}
6446
6447#if RUBY_DEBUG
6448static int
6449check_keyword(const NODE *node)
6450{
6451 /* This check is essentially a code clone of compile_keyword_arg. */
6452
6453 if (nd_type_p(node, NODE_LIST)) {
6454 while (RNODE_LIST(node)->nd_next) {
6455 node = RNODE_LIST(node)->nd_next;
6456 }
6457 node = RNODE_LIST(node)->nd_head;
6458 }
6459
6460 return keyword_node_p(node);
6461}
6462#endif
6463
6464static bool
6465keyword_node_single_splat_p(NODE *kwnode)
6466{
6467 RUBY_ASSERT(keyword_node_p(kwnode));
6468
6469 NODE *node = RNODE_HASH(kwnode)->nd_head;
6470 return RNODE_LIST(node)->nd_head == NULL &&
6471 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6472}
6473
6474static void
6475compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6476 NODE *kwnode, unsigned int *flag_ptr)
6477{
6478 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6479 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6480 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6481 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6482 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6483}
6484
6485#define SPLATARRAY_FALSE 0
6486#define SPLATARRAY_TRUE 1
6487#define DUP_SINGLE_KW_SPLAT 2
6488
6489static int
6490setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6491 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6492{
6493 if (!argn) return 0;
6494
6495 NODE *kwnode = NULL;
6496
6497 switch (nd_type(argn)) {
6498 case NODE_LIST: {
6499 // f(x, y, z)
6500 int len = compile_args(iseq, args, argn, &kwnode);
6501 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6502
6503 if (kwnode) {
6504 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6505 len -= 1;
6506 }
6507 else {
6508 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6509 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6510 }
6511 else {
6512 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6513 }
6514 }
6515 }
6516
6517 return len;
6518 }
6519 case NODE_SPLAT: {
6520 // f(*a)
6521 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6522 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6523 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6524 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6525 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6526 return 1;
6527 }
6528 case NODE_ARGSCAT: {
6529 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6530 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6531 bool args_pushed = false;
6532
6533 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6534 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6535 if (kwnode) rest_len--;
6536 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6537 args_pushed = true;
6538 }
6539 else {
6540 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6541 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6542 }
6543
6544 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6545 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6546 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6547 argc += 1;
6548 }
6549 else if (!args_pushed) {
6550 ADD_INSN(args, argn, concattoarray);
6551 }
6552
6553 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6554 if (kwnode) {
6555 // kwsplat
6556 *flag_ptr |= VM_CALL_KW_SPLAT;
6557 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6558 argc += 1;
6559 }
6560
6561 return argc;
6562 }
6563 case NODE_ARGSPUSH: {
6564 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6565 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6566
6567 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6568 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6569 if (kwnode) rest_len--;
6570 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6571 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6572 }
6573 else {
6574 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6575 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6576 }
6577 else {
6578 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6579 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6580 }
6581 }
6582
6583 if (kwnode) {
6584 // f(*a, k:1)
6585 *flag_ptr |= VM_CALL_KW_SPLAT;
6586 if (!keyword_node_single_splat_p(kwnode)) {
6587 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6588 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6589 }
6590 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6591 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6592 }
6593 else {
6594 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6595 }
6596 argc += 1;
6597 }
6598
6599 return argc;
6600 }
6601 default: {
6602 UNKNOWN_NODE("setup_arg", argn, Qnil);
6603 }
6604 }
6605}
6606
6607static void
6608setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6609{
6610 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6611 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6612 }
6613}
6614
6615static bool
6616setup_args_dup_rest_p(const NODE *argn)
6617{
6618 switch(nd_type(argn)) {
6619 case NODE_LVAR:
6620 case NODE_DVAR:
6621 case NODE_GVAR:
6622 case NODE_IVAR:
6623 case NODE_CVAR:
6624 case NODE_CONST:
6625 case NODE_COLON3:
6626 case NODE_INTEGER:
6627 case NODE_FLOAT:
6628 case NODE_RATIONAL:
6629 case NODE_IMAGINARY:
6630 case NODE_STR:
6631 case NODE_SYM:
6632 case NODE_REGX:
6633 case NODE_SELF:
6634 case NODE_NIL:
6635 case NODE_TRUE:
6636 case NODE_FALSE:
6637 case NODE_LAMBDA:
6638 case NODE_NTH_REF:
6639 case NODE_BACK_REF:
6640 return false;
6641 case NODE_COLON2:
6642 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6643 default:
6644 return true;
6645 }
6646}
6647
6648static VALUE
6649setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6650 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6651{
6652 VALUE ret;
6653 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6654
6655 if (argn) {
6656 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6657 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6658
6659 if (check_arg) {
6660 switch(nd_type(check_arg)) {
6661 case(NODE_SPLAT):
6662 // avoid caller side array allocation for f(*arg)
6663 dup_rest = SPLATARRAY_FALSE;
6664 break;
6665 case(NODE_ARGSCAT):
6666 // avoid caller side array allocation for f(1, *arg)
6667 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6668 break;
6669 case(NODE_ARGSPUSH):
6670 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6671 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6672 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6673 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6674 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6675 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6676
6677 if (dup_rest == SPLATARRAY_FALSE) {
6678 // require allocation for keyword key/value/splat that may modify splatted argument
6679 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6680 while (node) {
6681 NODE *key_node = RNODE_LIST(node)->nd_head;
6682 if (key_node && setup_args_dup_rest_p(key_node)) {
6683 dup_rest = SPLATARRAY_TRUE;
6684 break;
6685 }
6686
6687 node = RNODE_LIST(node)->nd_next;
6688 NODE *value_node = RNODE_LIST(node)->nd_head;
6689 if (setup_args_dup_rest_p(value_node)) {
6690 dup_rest = SPLATARRAY_TRUE;
6691 break;
6692 }
6693
6694 node = RNODE_LIST(node)->nd_next;
6695 }
6696 }
6697 break;
6698 default:
6699 break;
6700 }
6701 }
6702
6703 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6704 // for block pass that may modify splatted argument, dup rest and kwrest if given
6705 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6706 }
6707 }
6708 initial_dup_rest = dup_rest;
6709
6710 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6711 DECL_ANCHOR(arg_block);
6712 INIT_ANCHOR(arg_block);
6713
6714 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6715 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6716
6717 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6718 const NODE * arg_node =
6719 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6720
6721 int argc = 0;
6722
6723 // Only compile leading args:
6724 // foo(x, y, ...)
6725 // ^^^^
6726 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6727 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6728 }
6729
6730 *flag |= VM_CALL_FORWARDING;
6731
6732 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6733 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6734 return INT2FIX(argc);
6735 }
6736 else {
6737 *flag |= VM_CALL_ARGS_BLOCKARG;
6738
6739 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6740 }
6741
6742 if (LIST_INSN_SIZE_ONE(arg_block)) {
6743 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6744 if (IS_INSN(elem)) {
6745 INSN *iobj = (INSN *)elem;
6746 if (iobj->insn_id == BIN(getblockparam)) {
6747 iobj->insn_id = BIN(getblockparamproxy);
6748 }
6749 }
6750 }
6751 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6752 ADD_SEQ(args, arg_block);
6753 }
6754 else {
6755 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6756 }
6757 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6758 return ret;
6759}
6760
6761static void
6762build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6763{
6764 const NODE *body = ptr;
6765 int line = nd_line(body);
6766 VALUE argc = INT2FIX(0);
6767 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6768
6769 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6770 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6771 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6772 iseq_set_local_table(iseq, 0, 0);
6773}
6774
6775static void
6776compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6777{
6778 const NODE *vars;
6779 LINK_ELEMENT *last;
6780 int line = nd_line(node);
6781 const NODE *line_node = node;
6782 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6783
6784#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6785 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6786#else
6787 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6788#endif
6789 ADD_INSN(ret, line_node, dup);
6790 ADD_INSNL(ret, line_node, branchunless, fail_label);
6791
6792 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6793 INSN *cap;
6794 if (RNODE_BLOCK(vars)->nd_next) {
6795 ADD_INSN(ret, line_node, dup);
6796 }
6797 last = ret->last;
6798 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6799 last = last->next; /* putobject :var */
6800 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6801 NULL, INT2FIX(0), NULL);
6802 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6803#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6804 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6805 /* only one name */
6806 DECL_ANCHOR(nom);
6807
6808 INIT_ANCHOR(nom);
6809 ADD_INSNL(nom, line_node, jump, end_label);
6810 ADD_LABEL(nom, fail_label);
6811# if 0 /* $~ must be MatchData or nil */
6812 ADD_INSN(nom, line_node, pop);
6813 ADD_INSN(nom, line_node, putnil);
6814# endif
6815 ADD_LABEL(nom, end_label);
6816 (nom->last->next = cap->link.next)->prev = nom->last;
6817 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6818 return;
6819 }
6820#endif
6821 }
6822 ADD_INSNL(ret, line_node, jump, end_label);
6823 ADD_LABEL(ret, fail_label);
6824 ADD_INSN(ret, line_node, pop);
6825 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6826 last = ret->last;
6827 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6828 last = last->next; /* putobject :var */
6829 ((INSN*)last)->insn_id = BIN(putnil);
6830 ((INSN*)last)->operand_size = 0;
6831 }
6832 ADD_LABEL(ret, end_label);
6833}
6834
6835static int
6836optimizable_range_item_p(const NODE *n)
6837{
6838 if (!n) return FALSE;
6839 switch (nd_type(n)) {
6840 case NODE_LINE:
6841 return TRUE;
6842 case NODE_INTEGER:
6843 return TRUE;
6844 case NODE_NIL:
6845 return TRUE;
6846 default:
6847 return FALSE;
6848 }
6849}
6850
6851static VALUE
6852optimized_range_item(const NODE *n)
6853{
6854 switch (nd_type(n)) {
6855 case NODE_LINE:
6856 return rb_node_line_lineno_val(n);
6857 case NODE_INTEGER:
6858 return rb_node_integer_literal_val(n);
6859 case NODE_FLOAT:
6860 return rb_node_float_literal_val(n);
6861 case NODE_RATIONAL:
6862 return rb_node_rational_literal_val(n);
6863 case NODE_IMAGINARY:
6864 return rb_node_imaginary_literal_val(n);
6865 case NODE_NIL:
6866 return Qnil;
6867 default:
6868 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6869 }
6870}
6871
6872static int
6873compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6874{
6875 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6876 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6877
6878 const int line = nd_line(node);
6879 const NODE *line_node = node;
6880 DECL_ANCHOR(cond_seq);
6881 LABEL *then_label, *else_label, *end_label;
6882 VALUE branches = Qfalse;
6883
6884 INIT_ANCHOR(cond_seq);
6885 then_label = NEW_LABEL(line);
6886 else_label = NEW_LABEL(line);
6887 end_label = 0;
6888
6889 NODE *cond = RNODE_IF(node)->nd_cond;
6890 if (nd_type(cond) == NODE_BLOCK) {
6891 cond = RNODE_BLOCK(cond)->nd_head;
6892 }
6893
6894 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6895 ADD_SEQ(ret, cond_seq);
6896
6897 if (then_label->refcnt && else_label->refcnt) {
6898 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6899 }
6900
6901 if (then_label->refcnt) {
6902 ADD_LABEL(ret, then_label);
6903
6904 DECL_ANCHOR(then_seq);
6905 INIT_ANCHOR(then_seq);
6906 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6907
6908 if (else_label->refcnt) {
6909 const NODE *const coverage_node = node_body ? node_body : node;
6910 add_trace_branch_coverage(
6911 iseq,
6912 ret,
6913 nd_code_loc(coverage_node),
6914 nd_node_id(coverage_node),
6915 0,
6916 type == NODE_IF ? "then" : "else",
6917 branches);
6918 end_label = NEW_LABEL(line);
6919 ADD_INSNL(then_seq, line_node, jump, end_label);
6920 if (!popped) {
6921 ADD_INSN(then_seq, line_node, pop);
6922 }
6923 }
6924 ADD_SEQ(ret, then_seq);
6925 }
6926
6927 if (else_label->refcnt) {
6928 ADD_LABEL(ret, else_label);
6929
6930 DECL_ANCHOR(else_seq);
6931 INIT_ANCHOR(else_seq);
6932 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6933
6934 if (then_label->refcnt) {
6935 const NODE *const coverage_node = node_else ? node_else : node;
6936 add_trace_branch_coverage(
6937 iseq,
6938 ret,
6939 nd_code_loc(coverage_node),
6940 nd_node_id(coverage_node),
6941 1,
6942 type == NODE_IF ? "else" : "then",
6943 branches);
6944 }
6945 ADD_SEQ(ret, else_seq);
6946 }
6947
6948 if (end_label) {
6949 ADD_LABEL(ret, end_label);
6950 }
6951
6952 return COMPILE_OK;
6953}
6954
6955static int
6956compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6957{
6958 const NODE *vals;
6959 const NODE *node = orig_node;
6960 LABEL *endlabel, *elselabel;
6961 DECL_ANCHOR(head);
6962 DECL_ANCHOR(body_seq);
6963 DECL_ANCHOR(cond_seq);
6964 int only_special_literals = 1;
6965 VALUE literals = rb_hash_new();
6966 int line;
6967 enum node_type type;
6968 const NODE *line_node;
6969 VALUE branches = Qfalse;
6970 int branch_id = 0;
6971
6972 INIT_ANCHOR(head);
6973 INIT_ANCHOR(body_seq);
6974 INIT_ANCHOR(cond_seq);
6975
6976 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6977
6978 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6979
6980 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6981
6982 node = RNODE_CASE(node)->nd_body;
6983 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6984 type = nd_type(node);
6985 line = nd_line(node);
6986 line_node = node;
6987
6988 endlabel = NEW_LABEL(line);
6989 elselabel = NEW_LABEL(line);
6990
6991 ADD_SEQ(ret, head); /* case VAL */
6992
6993 while (type == NODE_WHEN) {
6994 LABEL *l1;
6995
6996 l1 = NEW_LABEL(line);
6997 ADD_LABEL(body_seq, l1);
6998 ADD_INSN(body_seq, line_node, pop);
6999
7000 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7001 add_trace_branch_coverage(
7002 iseq,
7003 body_seq,
7004 nd_code_loc(coverage_node),
7005 nd_node_id(coverage_node),
7006 branch_id++,
7007 "when",
7008 branches);
7009
7010 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7011 ADD_INSNL(body_seq, line_node, jump, endlabel);
7012
7013 vals = RNODE_WHEN(node)->nd_head;
7014 if (vals) {
7015 switch (nd_type(vals)) {
7016 case NODE_LIST:
7017 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7018 if (only_special_literals < 0) return COMPILE_NG;
7019 break;
7020 case NODE_SPLAT:
7021 case NODE_ARGSCAT:
7022 case NODE_ARGSPUSH:
7023 only_special_literals = 0;
7024 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7025 break;
7026 default:
7027 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7028 }
7029 }
7030 else {
7031 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7032 }
7033
7034 node = RNODE_WHEN(node)->nd_next;
7035 if (!node) {
7036 break;
7037 }
7038 type = nd_type(node);
7039 line = nd_line(node);
7040 line_node = node;
7041 }
7042 /* else */
7043 if (node) {
7044 ADD_LABEL(cond_seq, elselabel);
7045 ADD_INSN(cond_seq, line_node, pop);
7046 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7047 CHECK(COMPILE_(cond_seq, "else", node, popped));
7048 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7049 }
7050 else {
7051 debugs("== else (implicit)\n");
7052 ADD_LABEL(cond_seq, elselabel);
7053 ADD_INSN(cond_seq, orig_node, pop);
7054 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7055 if (!popped) {
7056 ADD_INSN(cond_seq, orig_node, putnil);
7057 }
7058 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7059 }
7060
7061 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7062 ADD_INSN(ret, orig_node, dup);
7063 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7064 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7065 LABEL_REF(elselabel);
7066 }
7067
7068 ADD_SEQ(ret, cond_seq);
7069 ADD_SEQ(ret, body_seq);
7070 ADD_LABEL(ret, endlabel);
7071 return COMPILE_OK;
7072}
7073
7074static int
7075compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7076{
7077 const NODE *vals;
7078 const NODE *val;
7079 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7080 LABEL *endlabel;
7081 DECL_ANCHOR(body_seq);
7082 VALUE branches = Qfalse;
7083 int branch_id = 0;
7084
7085 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7086
7087 INIT_ANCHOR(body_seq);
7088 endlabel = NEW_LABEL(nd_line(node));
7089
7090 while (node && nd_type_p(node, NODE_WHEN)) {
7091 const int line = nd_line(node);
7092 LABEL *l1 = NEW_LABEL(line);
7093 ADD_LABEL(body_seq, l1);
7094
7095 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7096 add_trace_branch_coverage(
7097 iseq,
7098 body_seq,
7099 nd_code_loc(coverage_node),
7100 nd_node_id(coverage_node),
7101 branch_id++,
7102 "when",
7103 branches);
7104
7105 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7106 ADD_INSNL(body_seq, node, jump, endlabel);
7107
7108 vals = RNODE_WHEN(node)->nd_head;
7109 if (!vals) {
7110 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7111 }
7112 switch (nd_type(vals)) {
7113 case NODE_LIST:
7114 while (vals) {
7115 LABEL *lnext;
7116 val = RNODE_LIST(vals)->nd_head;
7117 lnext = NEW_LABEL(nd_line(val));
7118 debug_compile("== when2\n", (void)0);
7119 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7120 ADD_LABEL(ret, lnext);
7121 vals = RNODE_LIST(vals)->nd_next;
7122 }
7123 break;
7124 case NODE_SPLAT:
7125 case NODE_ARGSCAT:
7126 case NODE_ARGSPUSH:
7127 ADD_INSN(ret, vals, putnil);
7128 CHECK(COMPILE(ret, "when2/cond splat", vals));
7129 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7130 ADD_INSNL(ret, vals, branchif, l1);
7131 break;
7132 default:
7133 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7134 }
7135 node = RNODE_WHEN(node)->nd_next;
7136 }
7137 /* else */
7138 const NODE *const coverage_node = node ? node : orig_node;
7139 add_trace_branch_coverage(
7140 iseq,
7141 ret,
7142 nd_code_loc(coverage_node),
7143 nd_node_id(coverage_node),
7144 branch_id,
7145 "else",
7146 branches);
7147 CHECK(COMPILE_(ret, "else", node, popped));
7148 ADD_INSNL(ret, orig_node, jump, endlabel);
7149
7150 ADD_SEQ(ret, body_seq);
7151 ADD_LABEL(ret, endlabel);
7152 return COMPILE_OK;
7153}
7154
7155static 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);
7156
7157static 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);
7158static 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);
7159static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7160static 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);
7161static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7162
7163#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7164#define CASE3_BI_OFFSET_ERROR_STRING 1
7165#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7166#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7167#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7168
7169static int
7170iseq_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)
7171{
7172 const int line = nd_line(node);
7173 const NODE *line_node = node;
7174
7175 switch (nd_type(node)) {
7176 case NODE_ARYPTN: {
7177 /*
7178 * if pattern.use_rest_num?
7179 * rest_num = 0
7180 * end
7181 * if pattern.has_constant_node?
7182 * unless pattern.constant === obj
7183 * goto match_failed
7184 * end
7185 * end
7186 * unless obj.respond_to?(:deconstruct)
7187 * goto match_failed
7188 * end
7189 * d = obj.deconstruct
7190 * unless Array === d
7191 * goto type_error
7192 * end
7193 * min_argc = pattern.pre_args_num + pattern.post_args_num
7194 * if pattern.has_rest_arg?
7195 * unless d.length >= min_argc
7196 * goto match_failed
7197 * end
7198 * else
7199 * unless d.length == min_argc
7200 * goto match_failed
7201 * end
7202 * end
7203 * pattern.pre_args_num.each do |i|
7204 * unless pattern.pre_args[i].match?(d[i])
7205 * goto match_failed
7206 * end
7207 * end
7208 * if pattern.use_rest_num?
7209 * rest_num = d.length - min_argc
7210 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7211 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7212 * goto match_failed
7213 * end
7214 * end
7215 * end
7216 * pattern.post_args_num.each do |i|
7217 * j = pattern.pre_args_num + i
7218 * j += rest_num
7219 * unless pattern.post_args[i].match?(d[j])
7220 * goto match_failed
7221 * end
7222 * end
7223 * goto matched
7224 * type_error:
7225 * FrozenCore.raise TypeError
7226 * match_failed:
7227 * goto unmatched
7228 */
7229 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7230 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7231 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7232
7233 const int min_argc = pre_args_num + post_args_num;
7234 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7235 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7236
7237 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7238 int i;
7239 match_failed = NEW_LABEL(line);
7240 type_error = NEW_LABEL(line);
7241 deconstruct = NEW_LABEL(line);
7242 deconstructed = NEW_LABEL(line);
7243
7244 if (use_rest_num) {
7245 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7246 ADD_INSN(ret, line_node, swap);
7247 if (base_index) {
7248 base_index++;
7249 }
7250 }
7251
7252 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7253
7254 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7255
7256 ADD_INSN(ret, line_node, dup);
7257 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7258 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7259 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7260 if (in_single_pattern) {
7261 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7262 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7263 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7264 INT2FIX(min_argc), base_index + 1 /* (1) */));
7265 }
7266 ADD_INSNL(ret, line_node, branchunless, match_failed);
7267
7268 for (i = 0; i < pre_args_num; i++) {
7269 ADD_INSN(ret, line_node, dup);
7270 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7271 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7272 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));
7273 args = RNODE_LIST(args)->nd_next;
7274 }
7275
7276 if (RNODE_ARYPTN(node)->rest_arg) {
7277 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7278 ADD_INSN(ret, line_node, dup);
7279 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7280 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7281 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7282 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7283 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7284 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7285 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7286
7287 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));
7288 }
7289 else {
7290 if (post_args_num > 0) {
7291 ADD_INSN(ret, line_node, dup);
7292 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7293 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7294 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7295 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7296 ADD_INSN(ret, line_node, pop);
7297 }
7298 }
7299 }
7300
7301 args = RNODE_ARYPTN(node)->post_args;
7302 for (i = 0; i < post_args_num; i++) {
7303 ADD_INSN(ret, line_node, dup);
7304
7305 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7306 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7307 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7308
7309 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7310 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));
7311 args = RNODE_LIST(args)->nd_next;
7312 }
7313
7314 ADD_INSN(ret, line_node, pop);
7315 if (use_rest_num) {
7316 ADD_INSN(ret, line_node, pop);
7317 }
7318 ADD_INSNL(ret, line_node, jump, matched);
7319 ADD_INSN(ret, line_node, putnil);
7320 if (use_rest_num) {
7321 ADD_INSN(ret, line_node, putnil);
7322 }
7323
7324 ADD_LABEL(ret, type_error);
7325 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7326 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7327 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7328 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7329 ADD_INSN(ret, line_node, pop);
7330
7331 ADD_LABEL(ret, match_failed);
7332 ADD_INSN(ret, line_node, pop);
7333 if (use_rest_num) {
7334 ADD_INSN(ret, line_node, pop);
7335 }
7336 ADD_INSNL(ret, line_node, jump, unmatched);
7337
7338 break;
7339 }
7340 case NODE_FNDPTN: {
7341 /*
7342 * if pattern.has_constant_node?
7343 * unless pattern.constant === obj
7344 * goto match_failed
7345 * end
7346 * end
7347 * unless obj.respond_to?(:deconstruct)
7348 * goto match_failed
7349 * end
7350 * d = obj.deconstruct
7351 * unless Array === d
7352 * goto type_error
7353 * end
7354 * unless d.length >= pattern.args_num
7355 * goto match_failed
7356 * end
7357 *
7358 * begin
7359 * len = d.length
7360 * limit = d.length - pattern.args_num
7361 * i = 0
7362 * while i <= limit
7363 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7364 * if pattern.has_pre_rest_arg_id
7365 * unless pattern.pre_rest_arg.match?(d[0, i])
7366 * goto find_failed
7367 * end
7368 * end
7369 * if pattern.has_post_rest_arg_id
7370 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7371 * goto find_failed
7372 * end
7373 * end
7374 * goto find_succeeded
7375 * end
7376 * i+=1
7377 * end
7378 * find_failed:
7379 * goto match_failed
7380 * find_succeeded:
7381 * end
7382 *
7383 * goto matched
7384 * type_error:
7385 * FrozenCore.raise TypeError
7386 * match_failed:
7387 * goto unmatched
7388 */
7389 const NODE *args = RNODE_FNDPTN(node)->args;
7390 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7391
7392 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7393 match_failed = NEW_LABEL(line);
7394 type_error = NEW_LABEL(line);
7395 deconstruct = NEW_LABEL(line);
7396 deconstructed = NEW_LABEL(line);
7397
7398 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7399
7400 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7401
7402 ADD_INSN(ret, line_node, dup);
7403 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7404 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7405 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7406 if (in_single_pattern) {
7407 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) */));
7408 }
7409 ADD_INSNL(ret, line_node, branchunless, match_failed);
7410
7411 {
7412 LABEL *while_begin = NEW_LABEL(nd_line(node));
7413 LABEL *next_loop = NEW_LABEL(nd_line(node));
7414 LABEL *find_succeeded = NEW_LABEL(line);
7415 LABEL *find_failed = NEW_LABEL(nd_line(node));
7416 int j;
7417
7418 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7419 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7420
7421 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7422 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7423 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7424
7425 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7426
7427 ADD_LABEL(ret, while_begin);
7428
7429 ADD_INSN(ret, line_node, dup);
7430 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7431 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7432 ADD_INSNL(ret, line_node, branchunless, find_failed);
7433
7434 for (j = 0; j < args_num; j++) {
7435 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7436 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7437 if (j != 0) {
7438 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7439 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7440 }
7441 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7442
7443 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));
7444 args = RNODE_LIST(args)->nd_next;
7445 }
7446
7447 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7448 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7449 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7450 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7451 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7452 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));
7453 }
7454 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7455 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7456 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7457 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7458 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7459 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7460 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7461 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));
7462 }
7463 ADD_INSNL(ret, line_node, jump, find_succeeded);
7464
7465 ADD_LABEL(ret, next_loop);
7466 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7467 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7468 ADD_INSNL(ret, line_node, jump, while_begin);
7469
7470 ADD_LABEL(ret, find_failed);
7471 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7472 if (in_single_pattern) {
7473 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7474 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7475 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7476 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7477 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7478
7479 ADD_INSN1(ret, line_node, putobject, Qfalse);
7480 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7481
7482 ADD_INSN(ret, line_node, pop);
7483 ADD_INSN(ret, line_node, pop);
7484 }
7485 ADD_INSNL(ret, line_node, jump, match_failed);
7486 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7487
7488 ADD_LABEL(ret, find_succeeded);
7489 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7490 }
7491
7492 ADD_INSN(ret, line_node, pop);
7493 ADD_INSNL(ret, line_node, jump, matched);
7494 ADD_INSN(ret, line_node, putnil);
7495
7496 ADD_LABEL(ret, type_error);
7497 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7498 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7499 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7500 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7501 ADD_INSN(ret, line_node, pop);
7502
7503 ADD_LABEL(ret, match_failed);
7504 ADD_INSN(ret, line_node, pop);
7505 ADD_INSNL(ret, line_node, jump, unmatched);
7506
7507 break;
7508 }
7509 case NODE_HSHPTN: {
7510 /*
7511 * keys = nil
7512 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7513 * keys = pattern.kw_args_node.keys
7514 * end
7515 * if pattern.has_constant_node?
7516 * unless pattern.constant === obj
7517 * goto match_failed
7518 * end
7519 * end
7520 * unless obj.respond_to?(:deconstruct_keys)
7521 * goto match_failed
7522 * end
7523 * d = obj.deconstruct_keys(keys)
7524 * unless Hash === d
7525 * goto type_error
7526 * end
7527 * if pattern.has_kw_rest_arg_node?
7528 * d = d.dup
7529 * end
7530 * if pattern.has_kw_args_node?
7531 * pattern.kw_args_node.each |k,|
7532 * unless d.key?(k)
7533 * goto match_failed
7534 * end
7535 * end
7536 * pattern.kw_args_node.each |k, pat|
7537 * if pattern.has_kw_rest_arg_node?
7538 * unless pat.match?(d.delete(k))
7539 * goto match_failed
7540 * end
7541 * else
7542 * unless pat.match?(d[k])
7543 * goto match_failed
7544 * end
7545 * end
7546 * end
7547 * else
7548 * unless d.empty?
7549 * goto match_failed
7550 * end
7551 * end
7552 * if pattern.has_kw_rest_arg_node?
7553 * if pattern.no_rest_keyword?
7554 * unless d.empty?
7555 * goto match_failed
7556 * end
7557 * else
7558 * unless pattern.kw_rest_arg_node.match?(d)
7559 * goto match_failed
7560 * end
7561 * end
7562 * end
7563 * goto matched
7564 * type_error:
7565 * FrozenCore.raise TypeError
7566 * match_failed:
7567 * goto unmatched
7568 */
7569 LABEL *match_failed, *type_error;
7570 VALUE keys = Qnil;
7571
7572 match_failed = NEW_LABEL(line);
7573 type_error = NEW_LABEL(line);
7574
7575 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7576 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7577 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7578 while (kw_args) {
7579 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7580 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7581 }
7582 }
7583
7584 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7585
7586 ADD_INSN(ret, line_node, dup);
7587 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7588 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7589 if (in_single_pattern) {
7590 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7591 }
7592 ADD_INSNL(ret, line_node, branchunless, match_failed);
7593
7594 if (NIL_P(keys)) {
7595 ADD_INSN(ret, line_node, putnil);
7596 }
7597 else {
7598 ADD_INSN1(ret, line_node, duparray, keys);
7599 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7600 }
7601 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7602
7603 ADD_INSN(ret, line_node, dup);
7604 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7605 ADD_INSNL(ret, line_node, branchunless, type_error);
7606
7607 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7608 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7609 }
7610
7611 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7612 int i;
7613 int keys_num;
7614 const NODE *args;
7615 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7616 if (args) {
7617 DECL_ANCHOR(match_values);
7618 INIT_ANCHOR(match_values);
7619 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7620 for (i = 0; i < keys_num; i++) {
7621 NODE *key_node = RNODE_LIST(args)->nd_head;
7622 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7623 VALUE key = get_symbol_value(iseq, key_node);
7624
7625 ADD_INSN(ret, line_node, dup);
7626 ADD_INSN1(ret, line_node, putobject, key);
7627 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7628 if (in_single_pattern) {
7629 LABEL *match_succeeded;
7630 match_succeeded = NEW_LABEL(line);
7631
7632 ADD_INSN(ret, line_node, dup);
7633 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7634
7635 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7636 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7637 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7638 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7639 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7640 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7641 ADD_INSN1(ret, line_node, putobject, key); // (7)
7642 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7643
7644 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7645
7646 ADD_LABEL(ret, match_succeeded);
7647 }
7648 ADD_INSNL(ret, line_node, branchunless, match_failed);
7649
7650 ADD_INSN(match_values, line_node, dup);
7651 ADD_INSN1(match_values, line_node, putobject, key);
7652 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7653 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7654 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7655 }
7656 ADD_SEQ(ret, match_values);
7657 }
7658 }
7659 else {
7660 ADD_INSN(ret, line_node, dup);
7661 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7662 if (in_single_pattern) {
7663 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7664 }
7665 ADD_INSNL(ret, line_node, branchunless, match_failed);
7666 }
7667
7668 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7669 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7670 ADD_INSN(ret, line_node, dup);
7671 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7672 if (in_single_pattern) {
7673 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7674 }
7675 ADD_INSNL(ret, line_node, branchunless, match_failed);
7676 }
7677 else {
7678 ADD_INSN(ret, line_node, dup); // (11)
7679 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));
7680 }
7681 }
7682
7683 ADD_INSN(ret, line_node, pop);
7684 ADD_INSNL(ret, line_node, jump, matched);
7685 ADD_INSN(ret, line_node, putnil);
7686
7687 ADD_LABEL(ret, type_error);
7688 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7689 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7690 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7691 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7692 ADD_INSN(ret, line_node, pop);
7693
7694 ADD_LABEL(ret, match_failed);
7695 ADD_INSN(ret, line_node, pop);
7696 ADD_INSNL(ret, line_node, jump, unmatched);
7697 break;
7698 }
7699 case NODE_SYM:
7700 case NODE_REGX:
7701 case NODE_LINE:
7702 case NODE_INTEGER:
7703 case NODE_FLOAT:
7704 case NODE_RATIONAL:
7705 case NODE_IMAGINARY:
7706 case NODE_FILE:
7707 case NODE_ENCODING:
7708 case NODE_STR:
7709 case NODE_XSTR:
7710 case NODE_DSTR:
7711 case NODE_DSYM:
7712 case NODE_DREGX:
7713 case NODE_LIST:
7714 case NODE_ZLIST:
7715 case NODE_LAMBDA:
7716 case NODE_DOT2:
7717 case NODE_DOT3:
7718 case NODE_CONST:
7719 case NODE_LVAR:
7720 case NODE_DVAR:
7721 case NODE_IVAR:
7722 case NODE_CVAR:
7723 case NODE_GVAR:
7724 case NODE_TRUE:
7725 case NODE_FALSE:
7726 case NODE_SELF:
7727 case NODE_NIL:
7728 case NODE_COLON2:
7729 case NODE_COLON3:
7730 case NODE_BEGIN:
7731 case NODE_BLOCK:
7732 case NODE_ONCE:
7733 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7734 if (in_single_pattern) {
7735 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7736 }
7737 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7738 if (in_single_pattern) {
7739 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7740 }
7741 ADD_INSNL(ret, line_node, branchif, matched);
7742 ADD_INSNL(ret, line_node, jump, unmatched);
7743 break;
7744 case NODE_LASGN: {
7745 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7746 ID id = RNODE_LASGN(node)->nd_vid;
7747 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7748
7749 if (in_alt_pattern) {
7750 const char *name = rb_id2name(id);
7751 if (name && strlen(name) > 0 && name[0] != '_') {
7752 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7753 rb_id2str(id));
7754 return COMPILE_NG;
7755 }
7756 }
7757
7758 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7759 ADD_INSNL(ret, line_node, jump, matched);
7760 break;
7761 }
7762 case NODE_DASGN: {
7763 int idx, lv, ls;
7764 ID id = RNODE_DASGN(node)->nd_vid;
7765
7766 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7767
7768 if (in_alt_pattern) {
7769 const char *name = rb_id2name(id);
7770 if (name && strlen(name) > 0 && name[0] != '_') {
7771 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7772 rb_id2str(id));
7773 return COMPILE_NG;
7774 }
7775 }
7776
7777 if (idx < 0) {
7778 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7779 rb_id2str(id));
7780 return COMPILE_NG;
7781 }
7782 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7783 ADD_INSNL(ret, line_node, jump, matched);
7784 break;
7785 }
7786 case NODE_IF:
7787 case NODE_UNLESS: {
7788 LABEL *match_failed;
7789 match_failed = unmatched;
7790 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7791 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7792 if (in_single_pattern) {
7793 LABEL *match_succeeded;
7794 match_succeeded = NEW_LABEL(line);
7795
7796 ADD_INSN(ret, line_node, dup);
7797 if (nd_type_p(node, NODE_IF)) {
7798 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7799 }
7800 else {
7801 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7802 }
7803
7804 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7805 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7806 ADD_INSN1(ret, line_node, putobject, Qfalse);
7807 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7808
7809 ADD_INSN(ret, line_node, pop);
7810 ADD_INSN(ret, line_node, pop);
7811
7812 ADD_LABEL(ret, match_succeeded);
7813 }
7814 if (nd_type_p(node, NODE_IF)) {
7815 ADD_INSNL(ret, line_node, branchunless, match_failed);
7816 }
7817 else {
7818 ADD_INSNL(ret, line_node, branchif, match_failed);
7819 }
7820 ADD_INSNL(ret, line_node, jump, matched);
7821 break;
7822 }
7823 case NODE_HASH: {
7824 NODE *n;
7825 LABEL *match_failed;
7826 match_failed = NEW_LABEL(line);
7827
7828 n = RNODE_HASH(node)->nd_head;
7829 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7830 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7831 return COMPILE_NG;
7832 }
7833
7834 ADD_INSN(ret, line_node, dup); // (1)
7835 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));
7836 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));
7837 ADD_INSN(ret, line_node, putnil);
7838
7839 ADD_LABEL(ret, match_failed);
7840 ADD_INSN(ret, line_node, pop);
7841 ADD_INSNL(ret, line_node, jump, unmatched);
7842 break;
7843 }
7844 case NODE_OR: {
7845 LABEL *match_succeeded, *fin;
7846 match_succeeded = NEW_LABEL(line);
7847 fin = NEW_LABEL(line);
7848
7849 ADD_INSN(ret, line_node, dup); // (1)
7850 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));
7851 ADD_LABEL(ret, match_succeeded);
7852 ADD_INSN(ret, line_node, pop);
7853 ADD_INSNL(ret, line_node, jump, matched);
7854 ADD_INSN(ret, line_node, putnil);
7855 ADD_LABEL(ret, fin);
7856 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7857 break;
7858 }
7859 default:
7860 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7861 }
7862 return COMPILE_OK;
7863}
7864
7865static int
7866iseq_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)
7867{
7868 LABEL *fin = NEW_LABEL(nd_line(node));
7869 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7870 ADD_LABEL(ret, fin);
7871 return COMPILE_OK;
7872}
7873
7874static int
7875iseq_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)
7876{
7877 const NODE *line_node = node;
7878
7879 if (RNODE_ARYPTN(node)->nd_pconst) {
7880 ADD_INSN(ret, line_node, dup); // (1)
7881 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7882 if (in_single_pattern) {
7883 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7884 }
7885 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7886 if (in_single_pattern) {
7887 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7888 }
7889 ADD_INSNL(ret, line_node, branchunless, match_failed);
7890 }
7891 return COMPILE_OK;
7892}
7893
7894
7895static int
7896iseq_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)
7897{
7898 const NODE *line_node = node;
7899
7900 // NOTE: this optimization allows us to re-use the #deconstruct value
7901 // (or its absence).
7902 if (use_deconstructed_cache) {
7903 // If value is nil then we haven't tried to deconstruct
7904 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7905 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7906
7907 // If false then the value is not deconstructable
7908 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7909 ADD_INSNL(ret, line_node, branchunless, match_failed);
7910
7911 // Drop value, add deconstructed to the stack and jump
7912 ADD_INSN(ret, line_node, pop); // (1)
7913 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7914 ADD_INSNL(ret, line_node, jump, deconstructed);
7915 }
7916 else {
7917 ADD_INSNL(ret, line_node, jump, deconstruct);
7918 }
7919
7920 ADD_LABEL(ret, deconstruct);
7921 ADD_INSN(ret, line_node, dup);
7922 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7923 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7924
7925 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7926 if (use_deconstructed_cache) {
7927 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7928 }
7929
7930 if (in_single_pattern) {
7931 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7932 }
7933
7934 ADD_INSNL(ret, line_node, branchunless, match_failed);
7935
7936 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7937
7938 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7939 if (use_deconstructed_cache) {
7940 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7941 }
7942
7943 ADD_INSN(ret, line_node, dup);
7944 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7945 ADD_INSNL(ret, line_node, branchunless, type_error);
7946
7947 ADD_LABEL(ret, deconstructed);
7948
7949 return COMPILE_OK;
7950}
7951
7952static int
7953iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7954{
7955 /*
7956 * if match_succeeded?
7957 * goto match_succeeded
7958 * end
7959 * error_string = FrozenCore.sprintf(errmsg, matchee)
7960 * key_error_p = false
7961 * match_succeeded:
7962 */
7963 const int line = nd_line(node);
7964 const NODE *line_node = node;
7965 LABEL *match_succeeded = NEW_LABEL(line);
7966
7967 ADD_INSN(ret, line_node, dup);
7968 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7969
7970 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7971 ADD_INSN1(ret, line_node, putobject, errmsg);
7972 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7973 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7974 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7975
7976 ADD_INSN1(ret, line_node, putobject, Qfalse);
7977 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7978
7979 ADD_INSN(ret, line_node, pop);
7980 ADD_INSN(ret, line_node, pop);
7981 ADD_LABEL(ret, match_succeeded);
7982
7983 return COMPILE_OK;
7984}
7985
7986static int
7987iseq_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)
7988{
7989 /*
7990 * if match_succeeded?
7991 * goto match_succeeded
7992 * end
7993 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7994 * key_error_p = false
7995 * match_succeeded:
7996 */
7997 const int line = nd_line(node);
7998 const NODE *line_node = node;
7999 LABEL *match_succeeded = NEW_LABEL(line);
8000
8001 ADD_INSN(ret, line_node, dup);
8002 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8003
8004 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8005 ADD_INSN1(ret, line_node, putobject, errmsg);
8006 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8007 ADD_INSN(ret, line_node, dup);
8008 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8009 ADD_INSN1(ret, line_node, putobject, pattern_length);
8010 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8011 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8012
8013 ADD_INSN1(ret, line_node, putobject, Qfalse);
8014 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8015
8016 ADD_INSN(ret, line_node, pop);
8017 ADD_INSN(ret, line_node, pop);
8018 ADD_LABEL(ret, match_succeeded);
8019
8020 return COMPILE_OK;
8021}
8022
8023static int
8024iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8025{
8026 /*
8027 * if match_succeeded?
8028 * goto match_succeeded
8029 * end
8030 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8031 * key_error_p = false
8032 * match_succeeded:
8033 */
8034 const int line = nd_line(node);
8035 const NODE *line_node = node;
8036 LABEL *match_succeeded = NEW_LABEL(line);
8037
8038 ADD_INSN(ret, line_node, dup);
8039 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8040
8041 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8042 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8043 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8044 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8045 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8046 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8047
8048 ADD_INSN1(ret, line_node, putobject, Qfalse);
8049 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8050
8051 ADD_INSN(ret, line_node, pop);
8052 ADD_INSN(ret, line_node, pop);
8053
8054 ADD_LABEL(ret, match_succeeded);
8055 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8056 ADD_INSN(ret, line_node, pop);
8057 ADD_INSN(ret, line_node, pop);
8058
8059 return COMPILE_OK;
8060}
8061
8062static int
8063compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8064{
8065 const NODE *pattern;
8066 const NODE *node = orig_node;
8067 LABEL *endlabel, *elselabel;
8068 DECL_ANCHOR(head);
8069 DECL_ANCHOR(body_seq);
8070 DECL_ANCHOR(cond_seq);
8071 int line;
8072 enum node_type type;
8073 const NODE *line_node;
8074 VALUE branches = 0;
8075 int branch_id = 0;
8076 bool single_pattern;
8077
8078 INIT_ANCHOR(head);
8079 INIT_ANCHOR(body_seq);
8080 INIT_ANCHOR(cond_seq);
8081
8082 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8083
8084 node = RNODE_CASE3(node)->nd_body;
8085 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8086 type = nd_type(node);
8087 line = nd_line(node);
8088 line_node = node;
8089 single_pattern = !RNODE_IN(node)->nd_next;
8090
8091 endlabel = NEW_LABEL(line);
8092 elselabel = NEW_LABEL(line);
8093
8094 if (single_pattern) {
8095 /* allocate stack for ... */
8096 ADD_INSN(head, line_node, putnil); /* key_error_key */
8097 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8098 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8099 ADD_INSN(head, line_node, putnil); /* error_string */
8100 }
8101 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8102
8103 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8104
8105 ADD_SEQ(ret, head); /* case VAL */
8106
8107 while (type == NODE_IN) {
8108 LABEL *l1;
8109
8110 if (branch_id) {
8111 ADD_INSN(body_seq, line_node, putnil);
8112 }
8113 l1 = NEW_LABEL(line);
8114 ADD_LABEL(body_seq, l1);
8115 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8116
8117 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8118 add_trace_branch_coverage(
8119 iseq,
8120 body_seq,
8121 nd_code_loc(coverage_node),
8122 nd_node_id(coverage_node),
8123 branch_id++,
8124 "in",
8125 branches);
8126
8127 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8128 ADD_INSNL(body_seq, line_node, jump, endlabel);
8129
8130 pattern = RNODE_IN(node)->nd_head;
8131 if (pattern) {
8132 int pat_line = nd_line(pattern);
8133 LABEL *next_pat = NEW_LABEL(pat_line);
8134 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8135 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8136 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8137 ADD_LABEL(cond_seq, next_pat);
8138 LABEL_UNREMOVABLE(next_pat);
8139 }
8140 else {
8141 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8142 return COMPILE_NG;
8143 }
8144
8145 node = RNODE_IN(node)->nd_next;
8146 if (!node) {
8147 break;
8148 }
8149 type = nd_type(node);
8150 line = nd_line(node);
8151 line_node = node;
8152 }
8153 /* else */
8154 if (node) {
8155 ADD_LABEL(cond_seq, elselabel);
8156 ADD_INSN(cond_seq, line_node, pop);
8157 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8158 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8159 CHECK(COMPILE_(cond_seq, "else", node, popped));
8160 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8161 ADD_INSN(cond_seq, line_node, putnil);
8162 if (popped) {
8163 ADD_INSN(cond_seq, line_node, putnil);
8164 }
8165 }
8166 else {
8167 debugs("== else (implicit)\n");
8168 ADD_LABEL(cond_seq, elselabel);
8169 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8170 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8171
8172 if (single_pattern) {
8173 /*
8174 * if key_error_p
8175 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8176 * else
8177 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8178 * end
8179 */
8180 LABEL *key_error, *fin;
8181 struct rb_callinfo_kwarg *kw_arg;
8182
8183 key_error = NEW_LABEL(line);
8184 fin = NEW_LABEL(line);
8185
8186 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8187 kw_arg->references = 0;
8188 kw_arg->keyword_len = 2;
8189 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8190 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8191
8192 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8193 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8194 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8195 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8196 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8197 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8198 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8199 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8200 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8201 ADD_INSNL(cond_seq, orig_node, jump, fin);
8202
8203 ADD_LABEL(cond_seq, key_error);
8204 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8205 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8206 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8207 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8208 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8209 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8210 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8211 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8212 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8213 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8214
8215 ADD_LABEL(cond_seq, fin);
8216 }
8217 else {
8218 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8219 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8220 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8221 }
8222 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8223 if (!popped) {
8224 ADD_INSN(cond_seq, orig_node, putnil);
8225 }
8226 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8227 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8228 if (popped) {
8229 ADD_INSN(cond_seq, line_node, putnil);
8230 }
8231 }
8232
8233 ADD_SEQ(ret, cond_seq);
8234 ADD_SEQ(ret, body_seq);
8235 ADD_LABEL(ret, endlabel);
8236 return COMPILE_OK;
8237}
8238
8239#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8240#undef CASE3_BI_OFFSET_ERROR_STRING
8241#undef CASE3_BI_OFFSET_KEY_ERROR_P
8242#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8243#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8244
8245static int
8246compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8247{
8248 const int line = (int)nd_line(node);
8249 const NODE *line_node = node;
8250
8251 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8252 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8253 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8254 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8255 VALUE branches = Qfalse;
8256
8258
8259 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8260 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8261 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8262 LABEL *end_label = NEW_LABEL(line);
8263 LABEL *adjust_label = NEW_LABEL(line);
8264
8265 LABEL *next_catch_label = NEW_LABEL(line);
8266 LABEL *tmp_label = NULL;
8267
8268 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8269 push_ensure_entry(iseq, &enl, NULL, NULL);
8270
8271 if (RNODE_WHILE(node)->nd_state == 1) {
8272 ADD_INSNL(ret, line_node, jump, next_label);
8273 }
8274 else {
8275 tmp_label = NEW_LABEL(line);
8276 ADD_INSNL(ret, line_node, jump, tmp_label);
8277 }
8278 ADD_LABEL(ret, adjust_label);
8279 ADD_INSN(ret, line_node, putnil);
8280 ADD_LABEL(ret, next_catch_label);
8281 ADD_INSN(ret, line_node, pop);
8282 ADD_INSNL(ret, line_node, jump, next_label);
8283 if (tmp_label) ADD_LABEL(ret, tmp_label);
8284
8285 ADD_LABEL(ret, redo_label);
8286 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8287
8288 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8289 add_trace_branch_coverage(
8290 iseq,
8291 ret,
8292 nd_code_loc(coverage_node),
8293 nd_node_id(coverage_node),
8294 0,
8295 "body",
8296 branches);
8297
8298 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8299 ADD_LABEL(ret, next_label); /* next */
8300
8301 if (type == NODE_WHILE) {
8302 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8303 redo_label, end_label));
8304 }
8305 else {
8306 /* until */
8307 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8308 end_label, redo_label));
8309 }
8310
8311 ADD_LABEL(ret, end_label);
8312 ADD_ADJUST_RESTORE(ret, adjust_label);
8313
8314 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8315 /* ADD_INSN(ret, line_node, putundef); */
8316 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8317 return COMPILE_NG;
8318 }
8319 else {
8320 ADD_INSN(ret, line_node, putnil);
8321 }
8322
8323 ADD_LABEL(ret, break_label); /* break */
8324
8325 if (popped) {
8326 ADD_INSN(ret, line_node, pop);
8327 }
8328
8329 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8330 break_label);
8331 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8332 next_catch_label);
8333 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8334 ISEQ_COMPILE_DATA(iseq)->redo_label);
8335
8336 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8337 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8338 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8339 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8340 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8341 return COMPILE_OK;
8342}
8343
8344static int
8345compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8346{
8347 const int line = nd_line(node);
8348 const NODE *line_node = node;
8349 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8350 LABEL *retry_label = NEW_LABEL(line);
8351 LABEL *retry_end_l = NEW_LABEL(line);
8352 const rb_iseq_t *child_iseq;
8353
8354 ADD_LABEL(ret, retry_label);
8355 if (nd_type_p(node, NODE_FOR)) {
8356 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8357
8358 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8359 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8360 ISEQ_TYPE_BLOCK, line);
8361 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8362 }
8363 else {
8364 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8365 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8366 ISEQ_TYPE_BLOCK, line);
8367 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8368 }
8369
8370 {
8371 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8372 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8373 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8374 //
8375 // Normally, "send" instruction is at the last.
8376 // However, qcall under branch coverage measurement adds some instructions after the "send".
8377 //
8378 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8379 INSN *iobj;
8380 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8381 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8382 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8383 iobj = (INSN*) get_prev_insn(iobj);
8384 }
8385 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8386
8387 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8388 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8389 if (&iobj->link == LAST_ELEMENT(ret)) {
8390 ret->last = (LINK_ELEMENT*) retry_end_l;
8391 }
8392 }
8393
8394 if (popped) {
8395 ADD_INSN(ret, line_node, pop);
8396 }
8397
8398 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8399
8400 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8401 return COMPILE_OK;
8402}
8403
8404static int
8405compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8406{
8407 /* massign to var in "for"
8408 * (args.length == 1 && Array.try_convert(args[0])) || args
8409 */
8410 const NODE *line_node = node;
8411 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8412 LABEL *not_single = NEW_LABEL(nd_line(var));
8413 LABEL *not_ary = NEW_LABEL(nd_line(var));
8414 CHECK(COMPILE(ret, "for var", var));
8415 ADD_INSN(ret, line_node, dup);
8416 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8417 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8418 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8419 ADD_INSNL(ret, line_node, branchunless, not_single);
8420 ADD_INSN(ret, line_node, dup);
8421 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8422 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8423 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8424 ADD_INSN(ret, line_node, swap);
8425 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8426 ADD_INSN(ret, line_node, dup);
8427 ADD_INSNL(ret, line_node, branchunless, not_ary);
8428 ADD_INSN(ret, line_node, swap);
8429 ADD_LABEL(ret, not_ary);
8430 ADD_INSN(ret, line_node, pop);
8431 ADD_LABEL(ret, not_single);
8432 return COMPILE_OK;
8433}
8434
8435static int
8436compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8437{
8438 const NODE *line_node = node;
8439 unsigned long throw_flag = 0;
8440
8441 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8442 /* while/until */
8443 LABEL *splabel = NEW_LABEL(0);
8444 ADD_LABEL(ret, splabel);
8445 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8446 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8447 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8448 add_ensure_iseq(ret, iseq, 0);
8449 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8450 ADD_ADJUST_RESTORE(ret, splabel);
8451
8452 if (!popped) {
8453 ADD_INSN(ret, line_node, putnil);
8454 }
8455 }
8456 else {
8457 const rb_iseq_t *ip = iseq;
8458
8459 while (ip) {
8460 if (!ISEQ_COMPILE_DATA(ip)) {
8461 ip = 0;
8462 break;
8463 }
8464
8465 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8466 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8467 }
8468 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8469 throw_flag = 0;
8470 }
8471 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8472 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8473 return COMPILE_NG;
8474 }
8475 else {
8476 ip = ISEQ_BODY(ip)->parent_iseq;
8477 continue;
8478 }
8479
8480 /* escape from block */
8481 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8482 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8483 if (popped) {
8484 ADD_INSN(ret, line_node, pop);
8485 }
8486 return COMPILE_OK;
8487 }
8488 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8489 return COMPILE_NG;
8490 }
8491 return COMPILE_OK;
8492}
8493
8494static int
8495compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8496{
8497 const NODE *line_node = node;
8498 unsigned long throw_flag = 0;
8499
8500 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8501 LABEL *splabel = NEW_LABEL(0);
8502 debugs("next in while loop\n");
8503 ADD_LABEL(ret, splabel);
8504 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8505 add_ensure_iseq(ret, iseq, 0);
8506 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8507 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8508 ADD_ADJUST_RESTORE(ret, splabel);
8509 if (!popped) {
8510 ADD_INSN(ret, line_node, putnil);
8511 }
8512 }
8513 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8514 LABEL *splabel = NEW_LABEL(0);
8515 debugs("next in block\n");
8516 ADD_LABEL(ret, splabel);
8517 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8518 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8519 add_ensure_iseq(ret, iseq, 0);
8520 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8521 ADD_ADJUST_RESTORE(ret, splabel);
8522
8523 if (!popped) {
8524 ADD_INSN(ret, line_node, putnil);
8525 }
8526 }
8527 else {
8528 const rb_iseq_t *ip = iseq;
8529
8530 while (ip) {
8531 if (!ISEQ_COMPILE_DATA(ip)) {
8532 ip = 0;
8533 break;
8534 }
8535
8536 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8537 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8538 /* while loop */
8539 break;
8540 }
8541 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8542 break;
8543 }
8544 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8545 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8546 return COMPILE_NG;
8547 }
8548
8549 ip = ISEQ_BODY(ip)->parent_iseq;
8550 }
8551 if (ip != 0) {
8552 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8553 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8554
8555 if (popped) {
8556 ADD_INSN(ret, line_node, pop);
8557 }
8558 }
8559 else {
8560 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8561 return COMPILE_NG;
8562 }
8563 }
8564 return COMPILE_OK;
8565}
8566
8567static int
8568compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8569{
8570 const NODE *line_node = node;
8571
8572 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8573 LABEL *splabel = NEW_LABEL(0);
8574 debugs("redo in while");
8575 ADD_LABEL(ret, splabel);
8576 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8577 add_ensure_iseq(ret, iseq, 0);
8578 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8579 ADD_ADJUST_RESTORE(ret, splabel);
8580 if (!popped) {
8581 ADD_INSN(ret, line_node, putnil);
8582 }
8583 }
8584 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8585 LABEL *splabel = NEW_LABEL(0);
8586
8587 debugs("redo in block");
8588 ADD_LABEL(ret, splabel);
8589 add_ensure_iseq(ret, iseq, 0);
8590 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8591 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8592 ADD_ADJUST_RESTORE(ret, splabel);
8593
8594 if (!popped) {
8595 ADD_INSN(ret, line_node, putnil);
8596 }
8597 }
8598 else {
8599 const rb_iseq_t *ip = iseq;
8600
8601 while (ip) {
8602 if (!ISEQ_COMPILE_DATA(ip)) {
8603 ip = 0;
8604 break;
8605 }
8606
8607 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8608 break;
8609 }
8610 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8611 break;
8612 }
8613 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8614 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8615 return COMPILE_NG;
8616 }
8617
8618 ip = ISEQ_BODY(ip)->parent_iseq;
8619 }
8620 if (ip != 0) {
8621 ADD_INSN(ret, line_node, putnil);
8622 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8623
8624 if (popped) {
8625 ADD_INSN(ret, line_node, pop);
8626 }
8627 }
8628 else {
8629 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8630 return COMPILE_NG;
8631 }
8632 }
8633 return COMPILE_OK;
8634}
8635
8636static int
8637compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8638{
8639 const NODE *line_node = node;
8640
8641 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8642 ADD_INSN(ret, line_node, putnil);
8643 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8644
8645 if (popped) {
8646 ADD_INSN(ret, line_node, pop);
8647 }
8648 }
8649 else {
8650 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8651 return COMPILE_NG;
8652 }
8653 return COMPILE_OK;
8654}
8655
8656static int
8657compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8658{
8659 const int line = nd_line(node);
8660 const NODE *line_node = node;
8661 LABEL *lstart = NEW_LABEL(line);
8662 LABEL *lend = NEW_LABEL(line);
8663 LABEL *lcont = NEW_LABEL(line);
8664 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8665 rb_str_concat(rb_str_new2("rescue in "),
8666 ISEQ_BODY(iseq)->location.label),
8667 ISEQ_TYPE_RESCUE, line);
8668
8669 lstart->rescued = LABEL_RESCUE_BEG;
8670 lend->rescued = LABEL_RESCUE_END;
8671 ADD_LABEL(ret, lstart);
8672
8673 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8674 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8675 {
8676 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8677 }
8678 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8679
8680 ADD_LABEL(ret, lend);
8681 if (RNODE_RESCUE(node)->nd_else) {
8682 ADD_INSN(ret, line_node, pop);
8683 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8684 }
8685 ADD_INSN(ret, line_node, nop);
8686 ADD_LABEL(ret, lcont);
8687
8688 if (popped) {
8689 ADD_INSN(ret, line_node, pop);
8690 }
8691
8692 /* register catch entry */
8693 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8694 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8695 return COMPILE_OK;
8696}
8697
8698static int
8699compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8700{
8701 const int line = nd_line(node);
8702 const NODE *line_node = node;
8703 const NODE *resq = node;
8704 const NODE *narg;
8705 LABEL *label_miss, *label_hit;
8706
8707 while (resq) {
8708 label_miss = NEW_LABEL(line);
8709 label_hit = NEW_LABEL(line);
8710
8711 narg = RNODE_RESBODY(resq)->nd_args;
8712 if (narg) {
8713 switch (nd_type(narg)) {
8714 case NODE_LIST:
8715 while (narg) {
8716 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8717 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8718 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8719 ADD_INSNL(ret, line_node, branchif, label_hit);
8720 narg = RNODE_LIST(narg)->nd_next;
8721 }
8722 break;
8723 case NODE_SPLAT:
8724 case NODE_ARGSCAT:
8725 case NODE_ARGSPUSH:
8726 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8727 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8728 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8729 ADD_INSNL(ret, line_node, branchif, label_hit);
8730 break;
8731 default:
8732 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8733 }
8734 }
8735 else {
8736 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8737 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8738 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8739 ADD_INSNL(ret, line_node, branchif, label_hit);
8740 }
8741 ADD_INSNL(ret, line_node, jump, label_miss);
8742 ADD_LABEL(ret, label_hit);
8743 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8744
8745 if (RNODE_RESBODY(resq)->nd_exc_var) {
8746 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8747 }
8748
8749 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) {
8750 // empty body
8751 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8752 }
8753 else {
8754 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8755 }
8756
8757 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8758 ADD_INSN(ret, line_node, nop);
8759 }
8760 ADD_INSN(ret, line_node, leave);
8761 ADD_LABEL(ret, label_miss);
8762 resq = RNODE_RESBODY(resq)->nd_next;
8763 }
8764 return COMPILE_OK;
8765}
8766
8767static int
8768compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8769{
8770 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8771 const NODE *line_node = node;
8772 DECL_ANCHOR(ensr);
8773 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8774 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8775 ISEQ_TYPE_ENSURE, line);
8776 LABEL *lstart = NEW_LABEL(line);
8777 LABEL *lend = NEW_LABEL(line);
8778 LABEL *lcont = NEW_LABEL(line);
8779 LINK_ELEMENT *last;
8780 int last_leave = 0;
8781 struct ensure_range er;
8783 struct ensure_range *erange;
8784
8785 INIT_ANCHOR(ensr);
8786 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8787 last = ensr->last;
8788 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8789
8790 er.begin = lstart;
8791 er.end = lend;
8792 er.next = 0;
8793 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8794
8795 ADD_LABEL(ret, lstart);
8796 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8797 ADD_LABEL(ret, lend);
8798 ADD_SEQ(ret, ensr);
8799 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8800 ADD_LABEL(ret, lcont);
8801 if (last_leave) ADD_INSN(ret, line_node, pop);
8802
8803 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8804 if (lstart->link.next != &lend->link) {
8805 while (erange) {
8806 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8807 ensure, lcont);
8808 erange = erange->next;
8809 }
8810 }
8811
8812 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8813 return COMPILE_OK;
8814}
8815
8816static int
8817compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8818{
8819 const NODE *line_node = node;
8820
8821 if (iseq) {
8822 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8823 const rb_iseq_t *is = iseq;
8824 enum rb_iseq_type t = type;
8825 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8826 LABEL *splabel = 0;
8827
8828 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8829 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8830 t = ISEQ_BODY(is)->type;
8831 }
8832 switch (t) {
8833 case ISEQ_TYPE_TOP:
8834 case ISEQ_TYPE_MAIN:
8835 if (retval) {
8836 rb_warn("argument of top-level return is ignored");
8837 }
8838 if (is == iseq) {
8839 /* plain top-level, leave directly */
8840 type = ISEQ_TYPE_METHOD;
8841 }
8842 break;
8843 default:
8844 break;
8845 }
8846
8847 if (type == ISEQ_TYPE_METHOD) {
8848 splabel = NEW_LABEL(0);
8849 ADD_LABEL(ret, splabel);
8850 ADD_ADJUST(ret, line_node, 0);
8851 }
8852
8853 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8854
8855 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8856 add_ensure_iseq(ret, iseq, 1);
8857 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8858 ADD_INSN(ret, line_node, leave);
8859 ADD_ADJUST_RESTORE(ret, splabel);
8860
8861 if (!popped) {
8862 ADD_INSN(ret, line_node, putnil);
8863 }
8864 }
8865 else {
8866 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8867 if (popped) {
8868 ADD_INSN(ret, line_node, pop);
8869 }
8870 }
8871 }
8872 return COMPILE_OK;
8873}
8874
8875static bool
8876drop_unreachable_return(LINK_ANCHOR *ret)
8877{
8878 LINK_ELEMENT *i = ret->last, *last;
8879 if (!i) return false;
8880 if (IS_TRACE(i)) i = i->prev;
8881 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8882 last = i = i->prev;
8883 if (IS_ADJUST(i)) i = i->prev;
8884 if (!IS_INSN(i)) return false;
8885 switch (INSN_OF(i)) {
8886 case BIN(leave):
8887 case BIN(jump):
8888 break;
8889 default:
8890 return false;
8891 }
8892 (ret->last = last->prev)->next = NULL;
8893 return true;
8894}
8895
8896static int
8897compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8898{
8899 CHECK(COMPILE_(ret, "nd_body", node, popped));
8900
8901 if (!popped && !all_string_result_p(node)) {
8902 const NODE *line_node = node;
8903 const unsigned int flag = VM_CALL_FCALL;
8904
8905 // Note, this dup could be removed if we are willing to change anytostring. It pops
8906 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8907 ADD_INSN(ret, line_node, dup);
8908 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8909 ADD_INSN(ret, line_node, anytostring);
8910 }
8911 return COMPILE_OK;
8912}
8913
8914static void
8915compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8916{
8917 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8918
8919 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8920 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8921}
8922
8923static LABEL *
8924qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8925{
8926 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8927 VALUE br = 0;
8928
8929 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8930 *branches = br;
8931 ADD_INSN(recv, line_node, dup);
8932 ADD_INSNL(recv, line_node, branchnil, else_label);
8933 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8934 return else_label;
8935}
8936
8937static void
8938qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8939{
8940 LABEL *end_label;
8941 if (!else_label) return;
8942 end_label = NEW_LABEL(nd_line(line_node));
8943 ADD_INSNL(ret, line_node, jump, end_label);
8944 ADD_LABEL(ret, else_label);
8945 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8946 ADD_LABEL(ret, end_label);
8947}
8948
8949static int
8950compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8951{
8952 /* optimization shortcut
8953 * "literal".freeze -> opt_str_freeze("literal")
8954 */
8955 if (get_nd_recv(node) &&
8956 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8957 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8958 get_nd_args(node) == NULL &&
8959 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8960 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8961 VALUE str = get_string_value(get_nd_recv(node));
8962 if (get_node_call_nd_mid(node) == idUMinus) {
8963 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8964 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8965 }
8966 else {
8967 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8968 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8969 }
8970 RB_OBJ_WRITTEN(iseq, Qundef, str);
8971 if (popped) {
8972 ADD_INSN(ret, line_node, pop);
8973 }
8974 return TRUE;
8975 }
8976 /* optimization shortcut
8977 * obj["literal"] -> opt_aref_with(obj, "literal")
8978 */
8979 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8980 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8981 (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)) &&
8982 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8983 !frozen_string_literal_p(iseq) &&
8984 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8985 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8986 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8987 ADD_INSN2(ret, line_node, opt_aref_with, str,
8988 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8989 RB_OBJ_WRITTEN(iseq, Qundef, str);
8990 if (popped) {
8991 ADD_INSN(ret, line_node, pop);
8992 }
8993 return TRUE;
8994 }
8995 return FALSE;
8996}
8997
8998static int
8999iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9000{
9001 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9002}
9003
9004static const struct rb_builtin_function *
9005iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9006{
9007 int i;
9008 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9009 for (i=0; table[i].index != -1; i++) {
9010 if (strcmp(table[i].name, name) == 0) {
9011 return &table[i];
9012 }
9013 }
9014 return NULL;
9015}
9016
9017static const char *
9018iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9019{
9020 const char *name = rb_id2name(mid);
9021 static const char prefix[] = "__builtin_";
9022 const size_t prefix_len = sizeof(prefix) - 1;
9023
9024 switch (type) {
9025 case NODE_CALL:
9026 if (recv) {
9027 switch (nd_type(recv)) {
9028 case NODE_VCALL:
9029 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9030 return name;
9031 }
9032 break;
9033 case NODE_CONST:
9034 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9035 return name;
9036 }
9037 break;
9038 default: break;
9039 }
9040 }
9041 break;
9042 case NODE_VCALL:
9043 case NODE_FCALL:
9044 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9045 return &name[prefix_len];
9046 }
9047 break;
9048 default: break;
9049 }
9050 return NULL;
9051}
9052
9053static int
9054delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9055{
9056
9057 if (argc == 0) {
9058 *pstart_index = 0;
9059 return TRUE;
9060 }
9061 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9062 unsigned int start=0;
9063
9064 // local_table: [p1, p2, p3, l1, l2, l3]
9065 // arguments: [p3, l1, l2] -> 2
9066 for (start = 0;
9067 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9068 start++) {
9069 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9070
9071 for (unsigned int i=start; i-start<argc; i++) {
9072 if (IS_INSN(elem) &&
9073 INSN_OF(elem) == BIN(getlocal)) {
9074 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9075 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9076
9077 if (local_level == 0) {
9078 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9079 if (0) { // for debug
9080 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9081 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9082 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9083 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9084 }
9085 if (i == index) {
9086 elem = elem->next;
9087 continue; /* for */
9088 }
9089 else {
9090 goto next;
9091 }
9092 }
9093 else {
9094 goto fail; // level != 0 is unsupported
9095 }
9096 }
9097 else {
9098 goto fail; // insn is not a getlocal
9099 }
9100 }
9101 goto success;
9102 next:;
9103 }
9104 fail:
9105 return FALSE;
9106 success:
9107 *pstart_index = start;
9108 return TRUE;
9109 }
9110 else {
9111 return FALSE;
9112 }
9113}
9114
9115// Compile Primitive.attr! :leaf, ...
9116static int
9117compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9118{
9119 VALUE symbol;
9120 VALUE string;
9121 if (!node) goto no_arg;
9122 while (node) {
9123 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9124 const NODE *next = RNODE_LIST(node)->nd_next;
9125
9126 node = RNODE_LIST(node)->nd_head;
9127 if (!node) goto no_arg;
9128 switch (nd_type(node)) {
9129 case NODE_SYM:
9130 symbol = rb_node_sym_string_val(node);
9131 break;
9132 default:
9133 goto bad_arg;
9134 }
9135
9136 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9137
9138 string = rb_sym2str(symbol);
9139 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9140 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9141 }
9142 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9143 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9144 }
9145 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9146 iseq_set_use_block(iseq);
9147 }
9148 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9149 // Let the iseq act like a C method in backtraces
9150 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9151 }
9152 else {
9153 goto unknown_arg;
9154 }
9155 node = next;
9156 }
9157 return COMPILE_OK;
9158 no_arg:
9159 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9160 return COMPILE_NG;
9161 non_symbol_arg:
9162 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9163 return COMPILE_NG;
9164 unknown_arg:
9165 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9166 return COMPILE_NG;
9167 bad_arg:
9168 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9169}
9170
9171static int
9172compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9173{
9174 VALUE name;
9175
9176 if (!node) goto no_arg;
9177 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9178 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9179 node = RNODE_LIST(node)->nd_head;
9180 if (!node) goto no_arg;
9181 switch (nd_type(node)) {
9182 case NODE_SYM:
9183 name = rb_node_sym_string_val(node);
9184 break;
9185 default:
9186 goto bad_arg;
9187 }
9188 if (!SYMBOL_P(name)) goto non_symbol_arg;
9189 if (!popped) {
9190 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9191 }
9192 return COMPILE_OK;
9193 no_arg:
9194 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9195 return COMPILE_NG;
9196 too_many_arg:
9197 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9198 return COMPILE_NG;
9199 non_symbol_arg:
9200 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9201 rb_builtin_class_name(name));
9202 return COMPILE_NG;
9203 bad_arg:
9204 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9205}
9206
9207static NODE *
9208mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9209{
9210 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9211 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9212 return RNODE_IF(node)->nd_body;
9213 }
9214 else {
9215 rb_bug("mandatory_node: can't find mandatory node");
9216 }
9217}
9218
9219static int
9220compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9221{
9222 // arguments
9223 struct rb_args_info args = {
9224 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9225 };
9226 rb_node_args_t args_node;
9227 rb_node_init(RNODE(&args_node), NODE_ARGS);
9228 args_node.nd_ainfo = args;
9229
9230 // local table without non-mandatory parameters
9231 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9232 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9233
9234 VALUE idtmp = 0;
9235 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9236 tbl->size = table_size;
9237
9238 int i;
9239
9240 // lead parameters
9241 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9242 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9243 }
9244 // local variables
9245 for (; i<table_size; i++) {
9246 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9247 }
9248
9249 rb_node_scope_t scope_node;
9250 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9251 scope_node.nd_tbl = tbl;
9252 scope_node.nd_body = mandatory_node(iseq, node);
9253 scope_node.nd_args = &args_node;
9254
9255 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9256
9257 ISEQ_BODY(iseq)->mandatory_only_iseq =
9258 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9259 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9260 nd_line(line_node), NULL, 0,
9261 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9262 ISEQ_BODY(iseq)->variable.script_lines);
9263
9264 ALLOCV_END(idtmp);
9265 return COMPILE_OK;
9266}
9267
9268static int
9269compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9270 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9271{
9272 NODE *args_node = get_nd_args(node);
9273
9274 if (parent_block != NULL) {
9275 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9276 return COMPILE_NG;
9277 }
9278 else {
9279# define BUILTIN_INLINE_PREFIX "_bi"
9280 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9281 bool cconst = false;
9282 retry:;
9283 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9284
9285 if (bf == NULL) {
9286 if (strcmp("cstmt!", builtin_func) == 0 ||
9287 strcmp("cexpr!", builtin_func) == 0) {
9288 // ok
9289 }
9290 else if (strcmp("cconst!", builtin_func) == 0) {
9291 cconst = true;
9292 }
9293 else if (strcmp("cinit!", builtin_func) == 0) {
9294 // ignore
9295 return COMPILE_OK;
9296 }
9297 else if (strcmp("attr!", builtin_func) == 0) {
9298 return compile_builtin_attr(iseq, args_node);
9299 }
9300 else if (strcmp("arg!", builtin_func) == 0) {
9301 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9302 }
9303 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9304 if (popped) {
9305 rb_bug("mandatory_only? should be in if condition");
9306 }
9307 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9308 rb_bug("mandatory_only? should be put on top");
9309 }
9310
9311 ADD_INSN1(ret, line_node, putobject, Qfalse);
9312 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9313 }
9314 else if (1) {
9315 rb_bug("can't find builtin function:%s", builtin_func);
9316 }
9317 else {
9318 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9319 return COMPILE_NG;
9320 }
9321
9322 int inline_index = nd_line(node);
9323 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9324 builtin_func = inline_func;
9325 args_node = NULL;
9326 goto retry;
9327 }
9328
9329 if (cconst) {
9330 typedef VALUE(*builtin_func0)(void *, VALUE);
9331 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9332 ADD_INSN1(ret, line_node, putobject, const_val);
9333 return COMPILE_OK;
9334 }
9335
9336 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9337
9338 unsigned int flag = 0;
9339 struct rb_callinfo_kwarg *keywords = NULL;
9340 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9341
9342 if (FIX2INT(argc) != bf->argc) {
9343 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9344 builtin_func, bf->argc, FIX2INT(argc));
9345 return COMPILE_NG;
9346 }
9347
9348 unsigned int start_index;
9349 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9350 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9351 }
9352 else {
9353 ADD_SEQ(ret, args);
9354 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9355 }
9356
9357 if (popped) ADD_INSN(ret, line_node, pop);
9358 return COMPILE_OK;
9359 }
9360}
9361
9362static int
9363compile_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)
9364{
9365 /* call: obj.method(...)
9366 * fcall: func(...)
9367 * vcall: func
9368 */
9369 DECL_ANCHOR(recv);
9370 DECL_ANCHOR(args);
9371 ID mid = get_node_call_nd_mid(node);
9372 VALUE argc;
9373 unsigned int flag = 0;
9374 struct rb_callinfo_kwarg *keywords = NULL;
9375 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9376 LABEL *else_label = NULL;
9377 VALUE branches = Qfalse;
9378
9379 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9380
9381 INIT_ANCHOR(recv);
9382 INIT_ANCHOR(args);
9383
9384#if OPT_SUPPORT_JOKE
9385 if (nd_type_p(node, NODE_VCALL)) {
9386 ID id_bitblt;
9387 ID id_answer;
9388
9389 CONST_ID(id_bitblt, "bitblt");
9390 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9391
9392 if (mid == id_bitblt) {
9393 ADD_INSN(ret, line_node, bitblt);
9394 return COMPILE_OK;
9395 }
9396 else if (mid == id_answer) {
9397 ADD_INSN(ret, line_node, answer);
9398 return COMPILE_OK;
9399 }
9400 }
9401 /* only joke */
9402 {
9403 ID goto_id;
9404 ID label_id;
9405
9406 CONST_ID(goto_id, "__goto__");
9407 CONST_ID(label_id, "__label__");
9408
9409 if (nd_type_p(node, NODE_FCALL) &&
9410 (mid == goto_id || mid == label_id)) {
9411 LABEL *label;
9412 st_data_t data;
9413 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9414 VALUE label_name;
9415
9416 if (!labels_table) {
9417 labels_table = st_init_numtable();
9418 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9419 }
9420 {
9421 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9422 return COMPILE_NG;
9423 }
9424
9425 if (mid == goto_id) {
9426 ADD_INSNL(ret, line_node, jump, label);
9427 }
9428 else {
9429 ADD_LABEL(ret, label);
9430 }
9431 return COMPILE_OK;
9432 }
9433 }
9434#endif
9435
9436 const char *builtin_func;
9437 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9438 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9439 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9440 }
9441
9442 /* receiver */
9443 if (!assume_receiver) {
9444 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9445 int idx, level;
9446
9447 if (mid == idCall &&
9448 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9449 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9450 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9451 }
9452 else if (private_recv_p(node)) {
9453 ADD_INSN(recv, node, putself);
9454 flag |= VM_CALL_FCALL;
9455 }
9456 else {
9457 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9458 }
9459
9460 if (type == NODE_QCALL) {
9461 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9462 }
9463 }
9464 else if (type == NODE_FCALL || type == NODE_VCALL) {
9465 ADD_CALL_RECEIVER(recv, line_node);
9466 }
9467 }
9468
9469 /* args */
9470 if (type != NODE_VCALL) {
9471 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9472 CHECK(!NIL_P(argc));
9473 }
9474 else {
9475 argc = INT2FIX(0);
9476 }
9477
9478 ADD_SEQ(ret, recv);
9479
9480 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9481 mid == rb_intern("new") &&
9482 parent_block == NULL &&
9483 !(flag & VM_CALL_ARGS_BLOCKARG);
9484
9485 if (inline_new) {
9486 ADD_INSN(ret, node, putnil);
9487 ADD_INSN(ret, node, swap);
9488 }
9489
9490 ADD_SEQ(ret, args);
9491
9492 debugp_param("call args argc", argc);
9493 debugp_param("call method", ID2SYM(mid));
9494
9495 switch ((int)type) {
9496 case NODE_VCALL:
9497 flag |= VM_CALL_VCALL;
9498 /* VCALL is funcall, so fall through */
9499 case NODE_FCALL:
9500 flag |= VM_CALL_FCALL;
9501 }
9502
9503 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9504 ADD_INSN(ret, line_node, splatkw);
9505 }
9506
9507 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9508 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9509
9510 if (inline_new) {
9511 // Jump unless the receiver uses the "basic" implementation of "new"
9512 VALUE ci;
9513 if (flag & VM_CALL_FORWARDING) {
9514 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9515 }
9516 else {
9517 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9518 }
9519 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9520 LABEL_REF(not_basic_new);
9521
9522 // optimized path
9523 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9524 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9525
9526 ADD_LABEL(ret, not_basic_new);
9527 // Fall back to normal send
9528 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9529 ADD_INSN(ret, line_node, swap);
9530
9531 ADD_LABEL(ret, not_basic_new_finish);
9532 ADD_INSN(ret, line_node, pop);
9533 } else {
9534 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9535 }
9536
9537 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9538 if (popped) {
9539 ADD_INSN(ret, line_node, pop);
9540 }
9541 return COMPILE_OK;
9542}
9543
9544static int
9545compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9546{
9547 const int line = nd_line(node);
9548 VALUE argc;
9549 unsigned int flag = 0;
9550 int asgnflag = 0;
9551 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9552
9553 /*
9554 * a[x] (op)= y
9555 *
9556 * nil # nil
9557 * eval a # nil a
9558 * eval x # nil a x
9559 * dupn 2 # nil a x a x
9560 * send :[] # nil a x a[x]
9561 * eval y # nil a x a[x] y
9562 * send op # nil a x ret
9563 * setn 3 # ret a x ret
9564 * send []= # ret ?
9565 * pop # ret
9566 */
9567
9568 /*
9569 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9570 * NODE_OP_ASGN nd_recv
9571 * nd_args->nd_head
9572 * nd_args->nd_body
9573 * nd_mid
9574 */
9575
9576 if (!popped) {
9577 ADD_INSN(ret, node, putnil);
9578 }
9579 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9580 CHECK(asgnflag != -1);
9581 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9582 case NODE_ZLIST:
9583 argc = INT2FIX(0);
9584 break;
9585 default:
9586 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9587 CHECK(!NIL_P(argc));
9588 }
9589 int dup_argn = FIX2INT(argc) + 1;
9590 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9591 flag |= asgnflag;
9592 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9593
9594 if (id == idOROP || id == idANDOP) {
9595 /* a[x] ||= y or a[x] &&= y
9596
9597 unless/if a[x]
9598 a[x]= y
9599 else
9600 nil
9601 end
9602 */
9603 LABEL *label = NEW_LABEL(line);
9604 LABEL *lfin = NEW_LABEL(line);
9605
9606 ADD_INSN(ret, node, dup);
9607 if (id == idOROP) {
9608 ADD_INSNL(ret, node, branchif, label);
9609 }
9610 else { /* idANDOP */
9611 ADD_INSNL(ret, node, branchunless, label);
9612 }
9613 ADD_INSN(ret, node, pop);
9614
9615 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9616 if (!popped) {
9617 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9618 }
9619 if (flag & VM_CALL_ARGS_SPLAT) {
9620 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9621 ADD_INSN(ret, node, swap);
9622 ADD_INSN1(ret, node, splatarray, Qtrue);
9623 ADD_INSN(ret, node, swap);
9624 flag |= VM_CALL_ARGS_SPLAT_MUT;
9625 }
9626 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9627 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9628 }
9629 else {
9630 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9631 }
9632 ADD_INSN(ret, node, pop);
9633 ADD_INSNL(ret, node, jump, lfin);
9634 ADD_LABEL(ret, label);
9635 if (!popped) {
9636 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9637 }
9638 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9639 ADD_LABEL(ret, lfin);
9640 }
9641 else {
9642 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9643 ADD_SEND(ret, node, id, INT2FIX(1));
9644 if (!popped) {
9645 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9646 }
9647 if (flag & VM_CALL_ARGS_SPLAT) {
9648 if (flag & VM_CALL_KW_SPLAT) {
9649 ADD_INSN1(ret, node, topn, INT2FIX(2));
9650 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9651 ADD_INSN1(ret, node, splatarray, Qtrue);
9652 flag |= VM_CALL_ARGS_SPLAT_MUT;
9653 }
9654 ADD_INSN(ret, node, swap);
9655 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9656 ADD_INSN1(ret, node, setn, INT2FIX(2));
9657 ADD_INSN(ret, node, pop);
9658 }
9659 else {
9660 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9661 ADD_INSN(ret, node, swap);
9662 ADD_INSN1(ret, node, splatarray, Qtrue);
9663 ADD_INSN(ret, node, swap);
9664 flag |= VM_CALL_ARGS_SPLAT_MUT;
9665 }
9666 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9667 }
9668 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9669 }
9670 else {
9671 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9672 }
9673 ADD_INSN(ret, node, pop);
9674 }
9675 return COMPILE_OK;
9676}
9677
9678static int
9679compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9680{
9681 const int line = nd_line(node);
9682 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9683 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9684 int asgnflag;
9685 LABEL *lfin = NEW_LABEL(line);
9686 LABEL *lcfin = NEW_LABEL(line);
9687 LABEL *lskip = 0;
9688 /*
9689 class C; attr_accessor :c; end
9690 r = C.new
9691 r.a &&= v # asgn2
9692
9693 eval r # r
9694 dup # r r
9695 eval r.a # r o
9696
9697 # or
9698 dup # r o o
9699 if lcfin # r o
9700 pop # r
9701 eval v # r v
9702 swap # v r
9703 topn 1 # v r v
9704 send a= # v ?
9705 jump lfin # v ?
9706
9707 lcfin: # r o
9708 swap # o r
9709
9710 lfin: # o ?
9711 pop # o
9712
9713 # or (popped)
9714 if lcfin # r
9715 eval v # r v
9716 send a= # ?
9717 jump lfin # ?
9718
9719 lcfin: # r
9720
9721 lfin: # ?
9722 pop #
9723
9724 # and
9725 dup # r o o
9726 unless lcfin
9727 pop # r
9728 eval v # r v
9729 swap # v r
9730 topn 1 # v r v
9731 send a= # v ?
9732 jump lfin # v ?
9733
9734 # others
9735 eval v # r o v
9736 send ?? # r w
9737 send a= # w
9738
9739 */
9740
9741 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9742 CHECK(asgnflag != -1);
9743 if (RNODE_OP_ASGN2(node)->nd_aid) {
9744 lskip = NEW_LABEL(line);
9745 ADD_INSN(ret, node, dup);
9746 ADD_INSNL(ret, node, branchnil, lskip);
9747 }
9748 ADD_INSN(ret, node, dup);
9749 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9750
9751 if (atype == idOROP || atype == idANDOP) {
9752 if (!popped) {
9753 ADD_INSN(ret, node, dup);
9754 }
9755 if (atype == idOROP) {
9756 ADD_INSNL(ret, node, branchif, lcfin);
9757 }
9758 else { /* idANDOP */
9759 ADD_INSNL(ret, node, branchunless, lcfin);
9760 }
9761 if (!popped) {
9762 ADD_INSN(ret, node, pop);
9763 }
9764 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9765 if (!popped) {
9766 ADD_INSN(ret, node, swap);
9767 ADD_INSN1(ret, node, topn, INT2FIX(1));
9768 }
9769 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9770 ADD_INSNL(ret, node, jump, lfin);
9771
9772 ADD_LABEL(ret, lcfin);
9773 if (!popped) {
9774 ADD_INSN(ret, node, swap);
9775 }
9776
9777 ADD_LABEL(ret, lfin);
9778 }
9779 else {
9780 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9781 ADD_SEND(ret, node, atype, INT2FIX(1));
9782 if (!popped) {
9783 ADD_INSN(ret, node, swap);
9784 ADD_INSN1(ret, node, topn, INT2FIX(1));
9785 }
9786 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9787 }
9788 if (lskip && popped) {
9789 ADD_LABEL(ret, lskip);
9790 }
9791 ADD_INSN(ret, node, pop);
9792 if (lskip && !popped) {
9793 ADD_LABEL(ret, lskip);
9794 }
9795 return COMPILE_OK;
9796}
9797
9798static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9799
9800static int
9801compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9802{
9803 const int line = nd_line(node);
9804 LABEL *lfin = 0;
9805 LABEL *lassign = 0;
9806 ID mid;
9807
9808 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9809 case NODE_COLON3:
9810 ADD_INSN1(ret, node, putobject, rb_cObject);
9811 break;
9812 case NODE_COLON2:
9813 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9814 break;
9815 default:
9816 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9817 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9818 return COMPILE_NG;
9819 }
9820 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9821 /* cref */
9822 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9823 lassign = NEW_LABEL(line);
9824 ADD_INSN(ret, node, dup); /* cref cref */
9825 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9826 ID2SYM(mid), Qtrue); /* cref bool */
9827 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9828 }
9829 ADD_INSN(ret, node, dup); /* cref cref */
9830 ADD_INSN1(ret, node, putobject, Qtrue);
9831 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9832
9833 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9834 lfin = NEW_LABEL(line);
9835 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9836 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9837 ADD_INSNL(ret, node, branchif, lfin);
9838 else /* idANDOP */
9839 ADD_INSNL(ret, node, branchunless, lfin);
9840 /* cref [obj] */
9841 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9842 if (lassign) ADD_LABEL(ret, lassign);
9843 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9844 /* cref value */
9845 if (popped)
9846 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9847 else {
9848 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9849 ADD_INSN(ret, node, swap); /* cref value value cref */
9850 }
9851 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9852 ADD_LABEL(ret, lfin); /* cref [value] */
9853 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9854 ADD_INSN(ret, node, pop); /* [value] */
9855 }
9856 else {
9857 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9858 /* cref obj value */
9859 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9860 /* cref value */
9861 ADD_INSN(ret, node, swap); /* value cref */
9862 if (!popped) {
9863 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9864 ADD_INSN(ret, node, swap); /* value value cref */
9865 }
9866 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9867 }
9868 return COMPILE_OK;
9869}
9870
9871static int
9872compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9873{
9874 const int line = nd_line(node);
9875 LABEL *lfin = NEW_LABEL(line);
9876 LABEL *lassign;
9877
9878 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9879 LABEL *lfinish[2];
9880 lfinish[0] = lfin;
9881 lfinish[1] = 0;
9882 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9883 lassign = lfinish[1];
9884 if (!lassign) {
9885 lassign = NEW_LABEL(line);
9886 }
9887 ADD_INSNL(ret, node, branchunless, lassign);
9888 }
9889 else {
9890 lassign = NEW_LABEL(line);
9891 }
9892
9893 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9894
9895 if (!popped) {
9896 ADD_INSN(ret, node, dup);
9897 }
9898
9899 if (type == NODE_OP_ASGN_AND) {
9900 ADD_INSNL(ret, node, branchunless, lfin);
9901 }
9902 else {
9903 ADD_INSNL(ret, node, branchif, lfin);
9904 }
9905
9906 if (!popped) {
9907 ADD_INSN(ret, node, pop);
9908 }
9909
9910 ADD_LABEL(ret, lassign);
9911 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9912 ADD_LABEL(ret, lfin);
9913 return COMPILE_OK;
9914}
9915
9916static int
9917compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9918{
9919 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9920 DECL_ANCHOR(args);
9921 int argc;
9922 unsigned int flag = 0;
9923 struct rb_callinfo_kwarg *keywords = NULL;
9924 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9925 int use_block = 1;
9926
9927 INIT_ANCHOR(args);
9928 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9929
9930 if (type == NODE_SUPER) {
9931 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9932 CHECK(!NIL_P(vargc));
9933 argc = FIX2INT(vargc);
9934 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9935 ADD_INSN(args, node, splatkw);
9936 }
9937
9938 if (flag & VM_CALL_ARGS_BLOCKARG) {
9939 use_block = 0;
9940 }
9941 }
9942 else {
9943 /* NODE_ZSUPER */
9944 int i;
9945 const rb_iseq_t *liseq = body->local_iseq;
9946 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9947 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9948 int lvar_level = get_lvar_level(iseq);
9949
9950 argc = local_body->param.lead_num;
9951
9952 /* normal arguments */
9953 for (i = 0; i < local_body->param.lead_num; i++) {
9954 int idx = local_body->local_table_size - i;
9955 ADD_GETLOCAL(args, node, idx, lvar_level);
9956 }
9957
9958 /* forward ... */
9959 if (local_body->param.flags.forwardable) {
9960 flag |= VM_CALL_FORWARDING;
9961 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9962 ADD_GETLOCAL(args, node, idx, lvar_level);
9963 }
9964
9965 if (local_body->param.flags.has_opt) {
9966 /* optional arguments */
9967 int j;
9968 for (j = 0; j < local_body->param.opt_num; j++) {
9969 int idx = local_body->local_table_size - (i + j);
9970 ADD_GETLOCAL(args, node, idx, lvar_level);
9971 }
9972 i += j;
9973 argc = i;
9974 }
9975 if (local_body->param.flags.has_rest) {
9976 /* rest argument */
9977 int idx = local_body->local_table_size - local_body->param.rest_start;
9978 ADD_GETLOCAL(args, node, idx, lvar_level);
9979 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9980
9981 argc = local_body->param.rest_start + 1;
9982 flag |= VM_CALL_ARGS_SPLAT;
9983 }
9984 if (local_body->param.flags.has_post) {
9985 /* post arguments */
9986 int post_len = local_body->param.post_num;
9987 int post_start = local_body->param.post_start;
9988
9989 if (local_body->param.flags.has_rest) {
9990 int j;
9991 for (j=0; j<post_len; j++) {
9992 int idx = local_body->local_table_size - (post_start + j);
9993 ADD_GETLOCAL(args, node, idx, lvar_level);
9994 }
9995 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9996 flag |= VM_CALL_ARGS_SPLAT_MUT;
9997 /* argc is settled at above */
9998 }
9999 else {
10000 int j;
10001 for (j=0; j<post_len; j++) {
10002 int idx = local_body->local_table_size - (post_start + j);
10003 ADD_GETLOCAL(args, node, idx, lvar_level);
10004 }
10005 argc = post_len + post_start;
10006 }
10007 }
10008
10009 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10010 int local_size = local_body->local_table_size;
10011 argc++;
10012
10013 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10014
10015 if (local_body->param.flags.has_kwrest) {
10016 int idx = local_body->local_table_size - local_kwd->rest_start;
10017 ADD_GETLOCAL(args, node, idx, lvar_level);
10018 RUBY_ASSERT(local_kwd->num > 0);
10019 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10020 }
10021 else {
10022 ADD_INSN1(args, node, newhash, INT2FIX(0));
10023 }
10024 for (i = 0; i < local_kwd->num; ++i) {
10025 ID id = local_kwd->table[i];
10026 int idx = local_size - get_local_var_idx(liseq, id);
10027 ADD_INSN1(args, node, putobject, ID2SYM(id));
10028 ADD_GETLOCAL(args, node, idx, lvar_level);
10029 }
10030 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10031 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10032 }
10033 else if (local_body->param.flags.has_kwrest) {
10034 int idx = local_body->local_table_size - local_kwd->rest_start;
10035 ADD_GETLOCAL(args, node, idx, lvar_level);
10036 argc++;
10037 flag |= VM_CALL_KW_SPLAT;
10038 }
10039 }
10040
10041 if (use_block && parent_block == NULL) {
10042 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10043 }
10044
10045 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10046 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10047 ADD_INSN(ret, node, putself);
10048 ADD_SEQ(ret, args);
10049
10050 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10051
10052 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10053 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10054 }
10055 else {
10056 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10057 }
10058
10059 if (popped) {
10060 ADD_INSN(ret, node, pop);
10061 }
10062 return COMPILE_OK;
10063}
10064
10065static int
10066compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10067{
10068 DECL_ANCHOR(args);
10069 VALUE argc;
10070 unsigned int flag = 0;
10071 struct rb_callinfo_kwarg *keywords = NULL;
10072
10073 INIT_ANCHOR(args);
10074
10075 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10076 case ISEQ_TYPE_TOP:
10077 case ISEQ_TYPE_MAIN:
10078 case ISEQ_TYPE_CLASS:
10079 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10080 return COMPILE_NG;
10081 default: /* valid */;
10082 }
10083
10084 if (RNODE_YIELD(node)->nd_head) {
10085 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10086 CHECK(!NIL_P(argc));
10087 }
10088 else {
10089 argc = INT2FIX(0);
10090 }
10091
10092 ADD_SEQ(ret, args);
10093 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10094 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10095
10096 if (popped) {
10097 ADD_INSN(ret, node, pop);
10098 }
10099
10100 int level = 0;
10101 const rb_iseq_t *tmp_iseq = iseq;
10102 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10103 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10104 }
10105 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10106
10107 return COMPILE_OK;
10108}
10109
10110static int
10111compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10112{
10113 DECL_ANCHOR(recv);
10114 DECL_ANCHOR(val);
10115
10116 INIT_ANCHOR(recv);
10117 INIT_ANCHOR(val);
10118 switch ((int)type) {
10119 case NODE_MATCH:
10120 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10121 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10122 INT2FIX(0));
10123 break;
10124 case NODE_MATCH2:
10125 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10126 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10127 break;
10128 case NODE_MATCH3:
10129 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10130 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10131 break;
10132 }
10133
10134 ADD_SEQ(ret, recv);
10135 ADD_SEQ(ret, val);
10136 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10137
10138 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10139 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10140 }
10141
10142 if (popped) {
10143 ADD_INSN(ret, node, pop);
10144 }
10145 return COMPILE_OK;
10146}
10147
10148static int
10149compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10150{
10151 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10152 /* constant */
10153 VALUE segments;
10154 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10155 (segments = collect_const_segments(iseq, node))) {
10156 ISEQ_BODY(iseq)->ic_size++;
10157 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10158 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10159 }
10160 else {
10161 /* constant */
10162 DECL_ANCHOR(pref);
10163 DECL_ANCHOR(body);
10164
10165 INIT_ANCHOR(pref);
10166 INIT_ANCHOR(body);
10167 CHECK(compile_const_prefix(iseq, node, pref, body));
10168 if (LIST_INSN_SIZE_ZERO(pref)) {
10169 ADD_INSN(ret, node, putnil);
10170 ADD_SEQ(ret, body);
10171 }
10172 else {
10173 ADD_SEQ(ret, pref);
10174 ADD_SEQ(ret, body);
10175 }
10176 }
10177 }
10178 else {
10179 /* function call */
10180 ADD_CALL_RECEIVER(ret, node);
10181 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10182 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10183 }
10184 if (popped) {
10185 ADD_INSN(ret, node, pop);
10186 }
10187 return COMPILE_OK;
10188}
10189
10190static int
10191compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10192{
10193 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10194
10195 /* add cache insn */
10196 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10197 ISEQ_BODY(iseq)->ic_size++;
10198 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10199 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10200 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10201 }
10202 else {
10203 ADD_INSN1(ret, node, putobject, rb_cObject);
10204 ADD_INSN1(ret, node, putobject, Qtrue);
10205 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10206 }
10207
10208 if (popped) {
10209 ADD_INSN(ret, node, pop);
10210 }
10211 return COMPILE_OK;
10212}
10213
10214static int
10215compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10216{
10217 VALUE flag = INT2FIX(excl);
10218 const NODE *b = RNODE_DOT2(node)->nd_beg;
10219 const NODE *e = RNODE_DOT2(node)->nd_end;
10220
10221 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10222 if (!popped) {
10223 VALUE bv = optimized_range_item(b);
10224 VALUE ev = optimized_range_item(e);
10225 VALUE val = rb_range_new(bv, ev, excl);
10226 ADD_INSN1(ret, node, putobject, val);
10227 RB_OBJ_WRITTEN(iseq, Qundef, val);
10228 }
10229 }
10230 else {
10231 CHECK(COMPILE_(ret, "min", b, popped));
10232 CHECK(COMPILE_(ret, "max", e, popped));
10233 if (!popped) {
10234 ADD_INSN1(ret, node, newrange, flag);
10235 }
10236 }
10237 return COMPILE_OK;
10238}
10239
10240static int
10241compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10242{
10243 if (!popped) {
10244 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10245 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10246 }
10247 else {
10248 const rb_iseq_t *ip = iseq;
10249 int level = 0;
10250 while (ip) {
10251 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10252 break;
10253 }
10254 ip = ISEQ_BODY(ip)->parent_iseq;
10255 level++;
10256 }
10257 if (ip) {
10258 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10259 }
10260 else {
10261 ADD_INSN(ret, node, putnil);
10262 }
10263 }
10264 }
10265 return COMPILE_OK;
10266}
10267
10268static int
10269compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10270{
10271 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10272 LABEL *end_label = NEW_LABEL(nd_line(node));
10273 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10274
10275 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10276 /* required argument. do nothing */
10277 COMPILE_ERROR(ERROR_ARGS "unreachable");
10278 return COMPILE_NG;
10279 }
10280 else if (nd_type_p(default_value, NODE_SYM) ||
10281 nd_type_p(default_value, NODE_REGX) ||
10282 nd_type_p(default_value, NODE_LINE) ||
10283 nd_type_p(default_value, NODE_INTEGER) ||
10284 nd_type_p(default_value, NODE_FLOAT) ||
10285 nd_type_p(default_value, NODE_RATIONAL) ||
10286 nd_type_p(default_value, NODE_IMAGINARY) ||
10287 nd_type_p(default_value, NODE_NIL) ||
10288 nd_type_p(default_value, NODE_TRUE) ||
10289 nd_type_p(default_value, NODE_FALSE)) {
10290 COMPILE_ERROR(ERROR_ARGS "unreachable");
10291 return COMPILE_NG;
10292 }
10293 else {
10294 /* if keywordcheck(_kw_bits, nth_keyword)
10295 * kw = default_value
10296 * end
10297 */
10298 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10299 int keyword_idx = body->param.keyword->num;
10300
10301 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10302 ADD_INSNL(ret, node, branchif, end_label);
10303 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10304 ADD_LABEL(ret, end_label);
10305 }
10306 return COMPILE_OK;
10307}
10308
10309static int
10310compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10311{
10312 DECL_ANCHOR(recv);
10313 DECL_ANCHOR(args);
10314 unsigned int flag = 0;
10315 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10316 VALUE argc;
10317 LABEL *else_label = NULL;
10318 VALUE branches = Qfalse;
10319
10320 /* optimization shortcut
10321 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10322 */
10323 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10324 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10325 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10326 (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)) &&
10327 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10328 !frozen_string_literal_p(iseq) &&
10329 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10330 {
10331 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10332 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10333 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10334 if (!popped) {
10335 ADD_INSN(ret, node, swap);
10336 ADD_INSN1(ret, node, topn, INT2FIX(1));
10337 }
10338 ADD_INSN2(ret, node, opt_aset_with, str,
10339 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10340 RB_OBJ_WRITTEN(iseq, Qundef, str);
10341 ADD_INSN(ret, node, pop);
10342 return COMPILE_OK;
10343 }
10344
10345 INIT_ANCHOR(recv);
10346 INIT_ANCHOR(args);
10347 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10348 CHECK(!NIL_P(argc));
10349
10350 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10351 CHECK(asgnflag != -1);
10352 flag |= (unsigned int)asgnflag;
10353
10354 debugp_param("argc", argc);
10355 debugp_param("nd_mid", ID2SYM(mid));
10356
10357 if (!rb_is_attrset_id(mid)) {
10358 /* safe nav attr */
10359 mid = rb_id_attrset(mid);
10360 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10361 }
10362 if (!popped) {
10363 ADD_INSN(ret, node, putnil);
10364 ADD_SEQ(ret, recv);
10365 ADD_SEQ(ret, args);
10366
10367 if (flag & VM_CALL_ARGS_SPLAT) {
10368 ADD_INSN(ret, node, dup);
10369 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10370 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10371 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10372 ADD_INSN (ret, node, pop);
10373 }
10374 else {
10375 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10376 }
10377 }
10378 else {
10379 ADD_SEQ(ret, recv);
10380 ADD_SEQ(ret, args);
10381 }
10382 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10383 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10384 ADD_INSN(ret, node, pop);
10385 return COMPILE_OK;
10386}
10387
10388static int
10389compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10390{
10391 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10392 ADD_SEQ(ret, sub);
10393
10394 if (copy) {
10395 /*
10396 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10397 * NEW_LIST(value, loc), loc);
10398 */
10399 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10400 }
10401 else {
10402 /*
10403 * NEW_CALL(fcore, rb_intern("make_shareable"),
10404 * NEW_LIST(value, loc), loc);
10405 */
10406 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10407 }
10408
10409 return COMPILE_OK;
10410}
10411
10412static VALUE
10413node_const_decl_val(const NODE *node)
10414{
10415 VALUE path;
10416 switch (nd_type(node)) {
10417 case NODE_CDECL:
10418 if (RNODE_CDECL(node)->nd_vid) {
10419 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10420 goto end;
10421 }
10422 else {
10423 node = RNODE_CDECL(node)->nd_else;
10424 }
10425 break;
10426 case NODE_COLON2:
10427 break;
10428 case NODE_COLON3:
10429 // ::Const
10430 path = rb_str_new_cstr("::");
10431 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10432 goto end;
10433 default:
10434 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10436 }
10437
10438 path = rb_ary_new();
10439 if (node) {
10440 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10441 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10442 }
10443 if (node && nd_type_p(node, NODE_CONST)) {
10444 // Const::Name
10445 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10446 }
10447 else if (node && nd_type_p(node, NODE_COLON3)) {
10448 // ::Const::Name
10449 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10450 rb_ary_push(path, rb_str_new(0, 0));
10451 }
10452 else {
10453 // expression::Name
10454 rb_ary_push(path, rb_str_new_cstr("..."));
10455 }
10456 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10457 }
10458 end:
10459 path = rb_fstring(path);
10460 return path;
10461}
10462
10463static VALUE
10464const_decl_path(NODE *dest)
10465{
10466 VALUE path = Qnil;
10467 if (!nd_type_p(dest, NODE_CALL)) {
10468 path = node_const_decl_val(dest);
10469 }
10470 return path;
10471}
10472
10473static int
10474compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10475{
10476 /*
10477 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10478 */
10479 VALUE path = const_decl_path(dest);
10480 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10481 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10482 ADD_INSN1(ret, value, putobject, path);
10483 RB_OBJ_WRITTEN(iseq, Qundef, path);
10484 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10485
10486 return COMPILE_OK;
10487}
10488
10489#ifndef SHAREABLE_BARE_EXPRESSION
10490#define SHAREABLE_BARE_EXPRESSION 1
10491#endif
10492
10493static int
10494compile_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)
10495{
10496# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10497 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10498 VALUE lit = Qnil;
10499 DECL_ANCHOR(anchor);
10500
10501 enum node_type type = node ? nd_type(node) : NODE_NIL;
10502 switch (type) {
10503 case NODE_TRUE:
10504 *value_p = Qtrue;
10505 goto compile;
10506 case NODE_FALSE:
10507 *value_p = Qfalse;
10508 goto compile;
10509 case NODE_NIL:
10510 *value_p = Qnil;
10511 goto compile;
10512 case NODE_SYM:
10513 *value_p = rb_node_sym_string_val(node);
10514 goto compile;
10515 case NODE_REGX:
10516 *value_p = rb_node_regx_string_val(node);
10517 goto compile;
10518 case NODE_LINE:
10519 *value_p = rb_node_line_lineno_val(node);
10520 goto compile;
10521 case NODE_INTEGER:
10522 *value_p = rb_node_integer_literal_val(node);
10523 goto compile;
10524 case NODE_FLOAT:
10525 *value_p = rb_node_float_literal_val(node);
10526 goto compile;
10527 case NODE_RATIONAL:
10528 *value_p = rb_node_rational_literal_val(node);
10529 goto compile;
10530 case NODE_IMAGINARY:
10531 *value_p = rb_node_imaginary_literal_val(node);
10532 goto compile;
10533 case NODE_ENCODING:
10534 *value_p = rb_node_encoding_val(node);
10535
10536 compile:
10537 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10538 *shareable_literal_p = 1;
10539 return COMPILE_OK;
10540
10541 case NODE_DSTR:
10542 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10543 if (shareable == rb_parser_shareable_literal) {
10544 /*
10545 * NEW_CALL(node, idUMinus, 0, loc);
10546 *
10547 * -"#{var}"
10548 */
10549 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10550 }
10551 *value_p = Qundef;
10552 *shareable_literal_p = 1;
10553 return COMPILE_OK;
10554
10555 case NODE_STR:{
10556 VALUE lit = rb_node_str_string_val(node);
10557 ADD_INSN1(ret, node, putobject, lit);
10558 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10559 *value_p = lit;
10560 *shareable_literal_p = 1;
10561
10562 return COMPILE_OK;
10563 }
10564
10565 case NODE_FILE:{
10566 VALUE lit = rb_node_file_path_val(node);
10567 ADD_INSN1(ret, node, putobject, lit);
10568 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10569 *value_p = lit;
10570 *shareable_literal_p = 1;
10571
10572 return COMPILE_OK;
10573 }
10574
10575 case NODE_ZLIST:{
10576 VALUE lit = rb_ary_new();
10577 OBJ_FREEZE(lit);
10578 ADD_INSN1(ret, node, putobject, lit);
10579 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10580 *value_p = lit;
10581 *shareable_literal_p = 1;
10582
10583 return COMPILE_OK;
10584 }
10585
10586 case NODE_LIST:{
10587 INIT_ANCHOR(anchor);
10588 lit = rb_ary_new();
10589 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10590 VALUE val;
10591 int shareable_literal_p2;
10592 NODE *elt = RNODE_LIST(n)->nd_head;
10593 if (elt) {
10594 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10595 if (shareable_literal_p2) {
10596 /* noop */
10597 }
10598 else if (RTEST(lit)) {
10599 rb_ary_clear(lit);
10600 lit = Qfalse;
10601 }
10602 }
10603 if (RTEST(lit)) {
10604 if (!UNDEF_P(val)) {
10605 rb_ary_push(lit, val);
10606 }
10607 else {
10608 rb_ary_clear(lit);
10609 lit = Qnil; /* make shareable at runtime */
10610 }
10611 }
10612 }
10613 break;
10614 }
10615 case NODE_HASH:{
10616 if (!RNODE_HASH(node)->nd_brace) {
10617 *value_p = Qundef;
10618 *shareable_literal_p = 0;
10619 return COMPILE_OK;
10620 }
10621 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10622 if (!RNODE_LIST(n)->nd_head) {
10623 // If the hash node have a keyword splat, fall back to the default case.
10624 goto compile_shareable;
10625 }
10626 }
10627
10628 INIT_ANCHOR(anchor);
10629 lit = rb_hash_new();
10630 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10631 VALUE key_val = 0;
10632 VALUE value_val = 0;
10633 int shareable_literal_p2;
10634 NODE *key = RNODE_LIST(n)->nd_head;
10635 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10636 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10637 if (shareable_literal_p2) {
10638 /* noop */
10639 }
10640 else if (RTEST(lit)) {
10641 rb_hash_clear(lit);
10642 lit = Qfalse;
10643 }
10644 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10645 if (shareable_literal_p2) {
10646 /* noop */
10647 }
10648 else if (RTEST(lit)) {
10649 rb_hash_clear(lit);
10650 lit = Qfalse;
10651 }
10652 if (RTEST(lit)) {
10653 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10654 rb_hash_aset(lit, key_val, value_val);
10655 }
10656 else {
10657 rb_hash_clear(lit);
10658 lit = Qnil; /* make shareable at runtime */
10659 }
10660 }
10661 }
10662 break;
10663 }
10664
10665 default:
10666
10667 compile_shareable:
10668 if (shareable == rb_parser_shareable_literal &&
10669 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10670 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10671 *value_p = Qundef;
10672 *shareable_literal_p = 1;
10673 return COMPILE_OK;
10674 }
10675 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10676 *value_p = Qundef;
10677 *shareable_literal_p = 0;
10678 return COMPILE_OK;
10679 }
10680
10681 /* Array or Hash that does not have keyword splat */
10682 if (!lit) {
10683 if (nd_type(node) == NODE_LIST) {
10684 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10685 }
10686 else if (nd_type(node) == NODE_HASH) {
10687 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10688 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10689 }
10690 *value_p = Qundef;
10691 *shareable_literal_p = 0;
10692 ADD_SEQ(ret, anchor);
10693 return COMPILE_OK;
10694 }
10695 if (NIL_P(lit)) {
10696 // if shareable_literal, all elements should have been ensured
10697 // as shareable
10698 if (nd_type(node) == NODE_LIST) {
10699 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10700 }
10701 else if (nd_type(node) == NODE_HASH) {
10702 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10703 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10704 }
10705 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10706 *value_p = Qundef;
10707 *shareable_literal_p = 1;
10708 }
10709 else {
10711 ADD_INSN1(ret, node, putobject, val);
10712 RB_OBJ_WRITTEN(iseq, Qundef, val);
10713 *value_p = val;
10714 *shareable_literal_p = 1;
10715 }
10716
10717 return COMPILE_OK;
10718}
10719
10720static int
10721compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10722{
10723 int literal_p = 0;
10724 VALUE val;
10725 DECL_ANCHOR(anchor);
10726 INIT_ANCHOR(anchor);
10727
10728 switch (shareable) {
10729 case rb_parser_shareable_none:
10730 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10731 return COMPILE_OK;
10732
10733 case rb_parser_shareable_literal:
10734 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10735 ADD_SEQ(ret, anchor);
10736 return COMPILE_OK;
10737
10738 case rb_parser_shareable_copy:
10739 case rb_parser_shareable_everything:
10740 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10741 if (!literal_p) {
10742 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10743 }
10744 else {
10745 ADD_SEQ(ret, anchor);
10746 }
10747 return COMPILE_OK;
10748 default:
10749 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10750 }
10751}
10752
10753static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10761static int
10762iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10763{
10764 if (node == 0) {
10765 if (!popped) {
10766 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10767 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10768 debugs("node: NODE_NIL(implicit)\n");
10769 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10770 }
10771 return COMPILE_OK;
10772 }
10773 return iseq_compile_each0(iseq, ret, node, popped);
10774}
10775
10776static int
10777iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10778{
10779 const int line = (int)nd_line(node);
10780 const enum node_type type = nd_type(node);
10781 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10782
10783 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10784 /* ignore */
10785 }
10786 else {
10787 if (nd_fl_newline(node)) {
10788 int event = RUBY_EVENT_LINE;
10789 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10790 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10791 event |= RUBY_EVENT_COVERAGE_LINE;
10792 }
10793 ADD_TRACE(ret, event);
10794 }
10795 }
10796
10797 debug_node_start(node);
10798#undef BEFORE_RETURN
10799#define BEFORE_RETURN debug_node_end()
10800
10801 switch (type) {
10802 case NODE_BLOCK:
10803 CHECK(compile_block(iseq, ret, node, popped));
10804 break;
10805 case NODE_IF:
10806 case NODE_UNLESS:
10807 CHECK(compile_if(iseq, ret, node, popped, type));
10808 break;
10809 case NODE_CASE:
10810 CHECK(compile_case(iseq, ret, node, popped));
10811 break;
10812 case NODE_CASE2:
10813 CHECK(compile_case2(iseq, ret, node, popped));
10814 break;
10815 case NODE_CASE3:
10816 CHECK(compile_case3(iseq, ret, node, popped));
10817 break;
10818 case NODE_WHILE:
10819 case NODE_UNTIL:
10820 CHECK(compile_loop(iseq, ret, node, popped, type));
10821 break;
10822 case NODE_FOR:
10823 case NODE_ITER:
10824 CHECK(compile_iter(iseq, ret, node, popped));
10825 break;
10826 case NODE_FOR_MASGN:
10827 CHECK(compile_for_masgn(iseq, ret, node, popped));
10828 break;
10829 case NODE_BREAK:
10830 CHECK(compile_break(iseq, ret, node, popped));
10831 break;
10832 case NODE_NEXT:
10833 CHECK(compile_next(iseq, ret, node, popped));
10834 break;
10835 case NODE_REDO:
10836 CHECK(compile_redo(iseq, ret, node, popped));
10837 break;
10838 case NODE_RETRY:
10839 CHECK(compile_retry(iseq, ret, node, popped));
10840 break;
10841 case NODE_BEGIN:{
10842 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10843 break;
10844 }
10845 case NODE_RESCUE:
10846 CHECK(compile_rescue(iseq, ret, node, popped));
10847 break;
10848 case NODE_RESBODY:
10849 CHECK(compile_resbody(iseq, ret, node, popped));
10850 break;
10851 case NODE_ENSURE:
10852 CHECK(compile_ensure(iseq, ret, node, popped));
10853 break;
10854
10855 case NODE_AND:
10856 case NODE_OR:{
10857 LABEL *end_label = NEW_LABEL(line);
10858 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10859 if (!popped) {
10860 ADD_INSN(ret, node, dup);
10861 }
10862 if (type == NODE_AND) {
10863 ADD_INSNL(ret, node, branchunless, end_label);
10864 }
10865 else {
10866 ADD_INSNL(ret, node, branchif, end_label);
10867 }
10868 if (!popped) {
10869 ADD_INSN(ret, node, pop);
10870 }
10871 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10872 ADD_LABEL(ret, end_label);
10873 break;
10874 }
10875
10876 case NODE_MASGN:{
10877 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10878 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10879 compile_massign(iseq, ret, node, popped);
10880 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10881 break;
10882 }
10883
10884 case NODE_LASGN:{
10885 ID id = RNODE_LASGN(node)->nd_vid;
10886 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10887
10888 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10889 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10890
10891 if (!popped) {
10892 ADD_INSN(ret, node, dup);
10893 }
10894 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10895 break;
10896 }
10897 case NODE_DASGN: {
10898 int idx, lv, ls;
10899 ID id = RNODE_DASGN(node)->nd_vid;
10900 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10901 debugi("dassn id", rb_id2str(id) ? id : '*');
10902
10903 if (!popped) {
10904 ADD_INSN(ret, node, dup);
10905 }
10906
10907 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10908
10909 if (idx < 0) {
10910 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10911 rb_id2str(id));
10912 goto ng;
10913 }
10914 ADD_SETLOCAL(ret, node, ls - idx, lv);
10915 break;
10916 }
10917 case NODE_GASGN:{
10918 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10919
10920 if (!popped) {
10921 ADD_INSN(ret, node, dup);
10922 }
10923 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10924 break;
10925 }
10926 case NODE_IASGN:{
10927 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10928 if (!popped) {
10929 ADD_INSN(ret, node, dup);
10930 }
10931 ADD_INSN2(ret, node, setinstancevariable,
10932 ID2SYM(RNODE_IASGN(node)->nd_vid),
10933 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10934 break;
10935 }
10936 case NODE_CDECL:{
10937 if (RNODE_CDECL(node)->nd_vid) {
10938 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10939
10940 if (!popped) {
10941 ADD_INSN(ret, node, dup);
10942 }
10943
10944 ADD_INSN1(ret, node, putspecialobject,
10945 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10946 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10947 }
10948 else {
10949 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10950 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10951 ADD_INSN(ret, node, swap);
10952
10953 if (!popped) {
10954 ADD_INSN1(ret, node, topn, INT2FIX(1));
10955 ADD_INSN(ret, node, swap);
10956 }
10957
10958 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10959 }
10960 break;
10961 }
10962 case NODE_CVASGN:{
10963 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10964 if (!popped) {
10965 ADD_INSN(ret, node, dup);
10966 }
10967 ADD_INSN2(ret, node, setclassvariable,
10968 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10969 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10970 break;
10971 }
10972 case NODE_OP_ASGN1:
10973 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10974 break;
10975 case NODE_OP_ASGN2:
10976 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10977 break;
10978 case NODE_OP_CDECL:
10979 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10980 break;
10981 case NODE_OP_ASGN_AND:
10982 case NODE_OP_ASGN_OR:
10983 CHECK(compile_op_log(iseq, ret, node, popped, type));
10984 break;
10985 case NODE_CALL: /* obj.foo */
10986 case NODE_OPCALL: /* foo[] */
10987 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10988 break;
10989 }
10990 case NODE_QCALL: /* obj&.foo */
10991 case NODE_FCALL: /* foo() */
10992 case NODE_VCALL: /* foo (variable or call) */
10993 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10994 goto ng;
10995 }
10996 break;
10997 case NODE_SUPER:
10998 case NODE_ZSUPER:
10999 CHECK(compile_super(iseq, ret, node, popped, type));
11000 break;
11001 case NODE_LIST:{
11002 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11003 break;
11004 }
11005 case NODE_ZLIST:{
11006 if (!popped) {
11007 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11008 }
11009 break;
11010 }
11011 case NODE_HASH:
11012 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11013 break;
11014 case NODE_RETURN:
11015 CHECK(compile_return(iseq, ret, node, popped));
11016 break;
11017 case NODE_YIELD:
11018 CHECK(compile_yield(iseq, ret, node, popped));
11019 break;
11020 case NODE_LVAR:{
11021 if (!popped) {
11022 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11023 }
11024 break;
11025 }
11026 case NODE_DVAR:{
11027 int lv, idx, ls;
11028 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11029 if (!popped) {
11030 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11031 if (idx < 0) {
11032 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11033 rb_id2str(RNODE_DVAR(node)->nd_vid));
11034 goto ng;
11035 }
11036 ADD_GETLOCAL(ret, node, ls - idx, lv);
11037 }
11038 break;
11039 }
11040 case NODE_GVAR:{
11041 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11042 if (popped) {
11043 ADD_INSN(ret, node, pop);
11044 }
11045 break;
11046 }
11047 case NODE_IVAR:{
11048 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11049 if (!popped) {
11050 ADD_INSN2(ret, node, getinstancevariable,
11051 ID2SYM(RNODE_IVAR(node)->nd_vid),
11052 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11053 }
11054 break;
11055 }
11056 case NODE_CONST:{
11057 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11058
11059 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11060 body->ic_size++;
11061 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11062 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11063 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11064 }
11065 else {
11066 ADD_INSN(ret, node, putnil);
11067 ADD_INSN1(ret, node, putobject, Qtrue);
11068 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11069 }
11070
11071 if (popped) {
11072 ADD_INSN(ret, node, pop);
11073 }
11074 break;
11075 }
11076 case NODE_CVAR:{
11077 if (!popped) {
11078 ADD_INSN2(ret, node, getclassvariable,
11079 ID2SYM(RNODE_CVAR(node)->nd_vid),
11080 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11081 }
11082 break;
11083 }
11084 case NODE_NTH_REF:{
11085 if (!popped) {
11086 if (!RNODE_NTH_REF(node)->nd_nth) {
11087 ADD_INSN(ret, node, putnil);
11088 break;
11089 }
11090 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11091 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11092 }
11093 break;
11094 }
11095 case NODE_BACK_REF:{
11096 if (!popped) {
11097 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11098 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11099 }
11100 break;
11101 }
11102 case NODE_MATCH:
11103 case NODE_MATCH2:
11104 case NODE_MATCH3:
11105 CHECK(compile_match(iseq, ret, node, popped, type));
11106 break;
11107 case NODE_SYM:{
11108 if (!popped) {
11109 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11110 }
11111 break;
11112 }
11113 case NODE_LINE:{
11114 if (!popped) {
11115 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11116 }
11117 break;
11118 }
11119 case NODE_ENCODING:{
11120 if (!popped) {
11121 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11122 }
11123 break;
11124 }
11125 case NODE_INTEGER:{
11126 VALUE lit = rb_node_integer_literal_val(node);
11127 debugp_param("integer", lit);
11128 if (!popped) {
11129 ADD_INSN1(ret, node, putobject, lit);
11130 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11131 }
11132 break;
11133 }
11134 case NODE_FLOAT:{
11135 VALUE lit = rb_node_float_literal_val(node);
11136 debugp_param("float", lit);
11137 if (!popped) {
11138 ADD_INSN1(ret, node, putobject, lit);
11139 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11140 }
11141 break;
11142 }
11143 case NODE_RATIONAL:{
11144 VALUE lit = rb_node_rational_literal_val(node);
11145 debugp_param("rational", lit);
11146 if (!popped) {
11147 ADD_INSN1(ret, node, putobject, lit);
11148 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11149 }
11150 break;
11151 }
11152 case NODE_IMAGINARY:{
11153 VALUE lit = rb_node_imaginary_literal_val(node);
11154 debugp_param("imaginary", lit);
11155 if (!popped) {
11156 ADD_INSN1(ret, node, putobject, lit);
11157 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11158 }
11159 break;
11160 }
11161 case NODE_FILE:
11162 case NODE_STR:{
11163 debugp_param("nd_lit", get_string_value(node));
11164 if (!popped) {
11165 VALUE lit = get_string_value(node);
11166 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11167 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11168 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11169 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11170 }
11171 switch (option->frozen_string_literal) {
11172 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11173 ADD_INSN1(ret, node, putchilledstring, lit);
11174 break;
11175 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11176 ADD_INSN1(ret, node, putstring, lit);
11177 break;
11178 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11179 ADD_INSN1(ret, node, putobject, lit);
11180 break;
11181 default:
11182 rb_bug("invalid frozen_string_literal");
11183 }
11184 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11185 }
11186 break;
11187 }
11188 case NODE_DSTR:{
11189 compile_dstr(iseq, ret, node);
11190
11191 if (popped) {
11192 ADD_INSN(ret, node, pop);
11193 }
11194 break;
11195 }
11196 case NODE_XSTR:{
11197 ADD_CALL_RECEIVER(ret, node);
11198 VALUE str = rb_node_str_string_val(node);
11199 ADD_INSN1(ret, node, putobject, str);
11200 RB_OBJ_WRITTEN(iseq, Qundef, str);
11201 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11202
11203 if (popped) {
11204 ADD_INSN(ret, node, pop);
11205 }
11206 break;
11207 }
11208 case NODE_DXSTR:{
11209 ADD_CALL_RECEIVER(ret, node);
11210 compile_dstr(iseq, ret, node);
11211 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11212
11213 if (popped) {
11214 ADD_INSN(ret, node, pop);
11215 }
11216 break;
11217 }
11218 case NODE_EVSTR:
11219 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11220 break;
11221 case NODE_REGX:{
11222 if (!popped) {
11223 VALUE lit = rb_node_regx_string_val(node);
11224 ADD_INSN1(ret, node, putobject, lit);
11225 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11226 }
11227 break;
11228 }
11229 case NODE_DREGX:
11230 compile_dregx(iseq, ret, node, popped);
11231 break;
11232 case NODE_ONCE:{
11233 int ic_index = body->ise_size++;
11234 const rb_iseq_t *block_iseq;
11235 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11236
11237 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11238 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11239
11240 if (popped) {
11241 ADD_INSN(ret, node, pop);
11242 }
11243 break;
11244 }
11245 case NODE_ARGSCAT:{
11246 if (popped) {
11247 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11248 ADD_INSN1(ret, node, splatarray, Qfalse);
11249 ADD_INSN(ret, node, pop);
11250 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11251 ADD_INSN1(ret, node, splatarray, Qfalse);
11252 ADD_INSN(ret, node, pop);
11253 }
11254 else {
11255 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11256 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11257 if (nd_type_p(body_node, NODE_LIST)) {
11258 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11259 }
11260 else {
11261 CHECK(COMPILE(ret, "argscat body", body_node));
11262 ADD_INSN(ret, node, concattoarray);
11263 }
11264 }
11265 break;
11266 }
11267 case NODE_ARGSPUSH:{
11268 if (popped) {
11269 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11270 ADD_INSN1(ret, node, splatarray, Qfalse);
11271 ADD_INSN(ret, node, pop);
11272 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11273 }
11274 else {
11275 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11276 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11277 if (keyword_node_p(body_node)) {
11278 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11279 ADD_INSN(ret, node, pushtoarraykwsplat);
11280 }
11281 else if (static_literal_node_p(body_node, iseq, false)) {
11282 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11283 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11284 }
11285 else {
11286 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11287 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11288 }
11289 }
11290 break;
11291 }
11292 case NODE_SPLAT:{
11293 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11294 ADD_INSN1(ret, node, splatarray, Qtrue);
11295
11296 if (popped) {
11297 ADD_INSN(ret, node, pop);
11298 }
11299 break;
11300 }
11301 case NODE_DEFN:{
11302 ID mid = RNODE_DEFN(node)->nd_mid;
11303 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11304 rb_id2str(mid),
11305 ISEQ_TYPE_METHOD, line);
11306
11307 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11308 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11309 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11310
11311 if (!popped) {
11312 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11313 }
11314
11315 break;
11316 }
11317 case NODE_DEFS:{
11318 ID mid = RNODE_DEFS(node)->nd_mid;
11319 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11320 rb_id2str(mid),
11321 ISEQ_TYPE_METHOD, line);
11322
11323 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11324 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11325 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11326 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11327
11328 if (!popped) {
11329 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11330 }
11331 break;
11332 }
11333 case NODE_ALIAS:{
11334 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11335 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11336 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11337 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11338 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11339
11340 if (popped) {
11341 ADD_INSN(ret, node, pop);
11342 }
11343 break;
11344 }
11345 case NODE_VALIAS:{
11346 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11347 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11348 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11349 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11350
11351 if (popped) {
11352 ADD_INSN(ret, node, pop);
11353 }
11354 break;
11355 }
11356 case NODE_UNDEF:{
11357 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11358
11359 for (long i = 0; i < ary->len; i++) {
11360 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11361 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11362 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11363 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11364
11365 if (i < ary->len - 1) {
11366 ADD_INSN(ret, node, pop);
11367 }
11368 }
11369
11370 if (popped) {
11371 ADD_INSN(ret, node, pop);
11372 }
11373 break;
11374 }
11375 case NODE_CLASS:{
11376 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11377 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11378 ISEQ_TYPE_CLASS, line);
11379 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11380 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11381 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11382
11383 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11384 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11385 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11386
11387 if (popped) {
11388 ADD_INSN(ret, node, pop);
11389 }
11390 break;
11391 }
11392 case NODE_MODULE:{
11393 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11394 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11395 ISEQ_TYPE_CLASS, line);
11396 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11397 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11398
11399 ADD_INSN (ret, node, putnil); /* dummy */
11400 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11401 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11402
11403 if (popped) {
11404 ADD_INSN(ret, node, pop);
11405 }
11406 break;
11407 }
11408 case NODE_SCLASS:{
11409 ID singletonclass;
11410 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11411 ISEQ_TYPE_CLASS, line);
11412
11413 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11414 ADD_INSN (ret, node, putnil);
11415 CONST_ID(singletonclass, "singletonclass");
11416 ADD_INSN3(ret, node, defineclass,
11417 ID2SYM(singletonclass), singleton_class,
11418 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11419 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11420
11421 if (popped) {
11422 ADD_INSN(ret, node, pop);
11423 }
11424 break;
11425 }
11426 case NODE_COLON2:
11427 CHECK(compile_colon2(iseq, ret, node, popped));
11428 break;
11429 case NODE_COLON3:
11430 CHECK(compile_colon3(iseq, ret, node, popped));
11431 break;
11432 case NODE_DOT2:
11433 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11434 break;
11435 case NODE_DOT3:
11436 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11437 break;
11438 case NODE_FLIP2:
11439 case NODE_FLIP3:{
11440 LABEL *lend = NEW_LABEL(line);
11441 LABEL *ltrue = NEW_LABEL(line);
11442 LABEL *lfalse = NEW_LABEL(line);
11443 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11444 ltrue, lfalse));
11445 ADD_LABEL(ret, ltrue);
11446 ADD_INSN1(ret, node, putobject, Qtrue);
11447 ADD_INSNL(ret, node, jump, lend);
11448 ADD_LABEL(ret, lfalse);
11449 ADD_INSN1(ret, node, putobject, Qfalse);
11450 ADD_LABEL(ret, lend);
11451 break;
11452 }
11453 case NODE_SELF:{
11454 if (!popped) {
11455 ADD_INSN(ret, node, putself);
11456 }
11457 break;
11458 }
11459 case NODE_NIL:{
11460 if (!popped) {
11461 ADD_INSN(ret, node, putnil);
11462 }
11463 break;
11464 }
11465 case NODE_TRUE:{
11466 if (!popped) {
11467 ADD_INSN1(ret, node, putobject, Qtrue);
11468 }
11469 break;
11470 }
11471 case NODE_FALSE:{
11472 if (!popped) {
11473 ADD_INSN1(ret, node, putobject, Qfalse);
11474 }
11475 break;
11476 }
11477 case NODE_ERRINFO:
11478 CHECK(compile_errinfo(iseq, ret, node, popped));
11479 break;
11480 case NODE_DEFINED:
11481 if (!popped) {
11482 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11483 }
11484 break;
11485 case NODE_POSTEXE:{
11486 /* compiled to:
11487 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11488 */
11489 int is_index = body->ise_size++;
11491 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11492 const rb_iseq_t *once_iseq =
11493 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11494
11495 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11496 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11497
11498 if (popped) {
11499 ADD_INSN(ret, node, pop);
11500 }
11501 break;
11502 }
11503 case NODE_KW_ARG:
11504 CHECK(compile_kw_arg(iseq, ret, node, popped));
11505 break;
11506 case NODE_DSYM:{
11507 compile_dstr(iseq, ret, node);
11508 if (!popped) {
11509 ADD_INSN(ret, node, intern);
11510 }
11511 else {
11512 ADD_INSN(ret, node, pop);
11513 }
11514 break;
11515 }
11516 case NODE_ATTRASGN:
11517 CHECK(compile_attrasgn(iseq, ret, node, popped));
11518 break;
11519 case NODE_LAMBDA:{
11520 /* compile same as lambda{...} */
11521 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11522 VALUE argc = INT2FIX(0);
11523
11524 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11525 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11526 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11527
11528 if (popped) {
11529 ADD_INSN(ret, node, pop);
11530 }
11531 break;
11532 }
11533 default:
11534 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11535 ng:
11536 debug_node_end();
11537 return COMPILE_NG;
11538 }
11539
11540 debug_node_end();
11541 return COMPILE_OK;
11542}
11543
11544/***************************/
11545/* instruction information */
11546/***************************/
11547
11548static int
11549insn_data_length(INSN *iobj)
11550{
11551 return insn_len(iobj->insn_id);
11552}
11553
11554static int
11555calc_sp_depth(int depth, INSN *insn)
11556{
11557 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11558}
11559
11560static VALUE
11561opobj_inspect(VALUE obj)
11562{
11563 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11564 switch (BUILTIN_TYPE(obj)) {
11565 case T_STRING:
11566 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11567 break;
11568 case T_ARRAY:
11569 obj = rb_ary_dup(obj);
11570 break;
11571 default:
11572 break;
11573 }
11574 }
11575 return rb_inspect(obj);
11576}
11577
11578
11579
11580static VALUE
11581insn_data_to_s_detail(INSN *iobj)
11582{
11583 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11584
11585 if (iobj->operands) {
11586 const char *types = insn_op_types(iobj->insn_id);
11587 int j;
11588
11589 for (j = 0; types[j]; j++) {
11590 char type = types[j];
11591
11592 switch (type) {
11593 case TS_OFFSET: /* label(destination position) */
11594 {
11595 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11596 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11597 break;
11598 }
11599 break;
11600 case TS_ISEQ: /* iseq */
11601 {
11602 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11603 VALUE val = Qnil;
11604 if (0 && iseq) { /* TODO: invalidate now */
11605 val = (VALUE)iseq;
11606 }
11607 rb_str_concat(str, opobj_inspect(val));
11608 }
11609 break;
11610 case TS_LINDEX:
11611 case TS_NUM: /* ulong */
11612 case TS_VALUE: /* VALUE */
11613 {
11614 VALUE v = OPERAND_AT(iobj, j);
11615 if (!CLASS_OF(v))
11616 rb_str_cat2(str, "<hidden>");
11617 else {
11618 rb_str_concat(str, opobj_inspect(v));
11619 }
11620 break;
11621 }
11622 case TS_ID: /* ID */
11623 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11624 break;
11625 case TS_IC: /* inline cache */
11626 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11627 break;
11628 case TS_IVC: /* inline ivar cache */
11629 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11630 break;
11631 case TS_ICVARC: /* inline cvar cache */
11632 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11633 break;
11634 case TS_ISE: /* inline storage entry */
11635 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11636 break;
11637 case TS_CALLDATA: /* we store these as call infos at compile time */
11638 {
11639 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11640 rb_str_cat2(str, "<calldata:");
11641 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11642 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11643 break;
11644 }
11645 case TS_CDHASH: /* case/when condition cache */
11646 rb_str_cat2(str, "<ch>");
11647 break;
11648 case TS_FUNCPTR:
11649 {
11650 void *func = (void *)OPERAND_AT(iobj, j);
11651#ifdef HAVE_DLADDR
11652 Dl_info info;
11653 if (dladdr(func, &info) && info.dli_sname) {
11654 rb_str_cat2(str, info.dli_sname);
11655 break;
11656 }
11657#endif
11658 rb_str_catf(str, "<%p>", func);
11659 }
11660 break;
11661 case TS_BUILTIN:
11662 rb_str_cat2(str, "<TS_BUILTIN>");
11663 break;
11664 default:{
11665 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11666 }
11667 }
11668 if (types[j + 1]) {
11669 rb_str_cat2(str, ", ");
11670 }
11671 }
11672 }
11673 return str;
11674}
11675
11676static void
11677dump_disasm_list(const LINK_ELEMENT *link)
11678{
11679 dump_disasm_list_with_cursor(link, NULL, NULL);
11680}
11681
11682static void
11683dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11684{
11685 int pos = 0;
11686 INSN *iobj;
11687 LABEL *lobj;
11688 VALUE str;
11689
11690 printf("-- raw disasm--------\n");
11691
11692 while (link) {
11693 if (curr) printf(curr == link ? "*" : " ");
11694 switch (link->type) {
11695 case ISEQ_ELEMENT_INSN:
11696 {
11697 iobj = (INSN *)link;
11698 str = insn_data_to_s_detail(iobj);
11699 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11700 pos += insn_data_length(iobj);
11701 break;
11702 }
11703 case ISEQ_ELEMENT_LABEL:
11704 {
11705 lobj = (LABEL *)link;
11706 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11707 dest == lobj ? " <---" : "");
11708 break;
11709 }
11710 case ISEQ_ELEMENT_TRACE:
11711 {
11712 TRACE *trace = (TRACE *)link;
11713 printf(" trace: %0x\n", trace->event);
11714 break;
11715 }
11716 case ISEQ_ELEMENT_ADJUST:
11717 {
11718 ADJUST *adjust = (ADJUST *)link;
11719 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11720 break;
11721 }
11722 default:
11723 /* ignore */
11724 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11725 }
11726 link = link->next;
11727 }
11728 printf("---------------------\n");
11729 fflush(stdout);
11730}
11731
11732int
11733rb_insn_len(VALUE insn)
11734{
11735 return insn_len(insn);
11736}
11737
11738const char *
11739rb_insns_name(int i)
11740{
11741 return insn_name(i);
11742}
11743
11744VALUE
11745rb_insns_name_array(void)
11746{
11747 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11748 int i;
11749 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11750 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11751 }
11752 return rb_ary_freeze(ary);
11753}
11754
11755static LABEL *
11756register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11757{
11758 LABEL *label = 0;
11759 st_data_t tmp;
11760 obj = rb_to_symbol_type(obj);
11761
11762 if (st_lookup(labels_table, obj, &tmp) == 0) {
11763 label = NEW_LABEL(0);
11764 st_insert(labels_table, obj, (st_data_t)label);
11765 }
11766 else {
11767 label = (LABEL *)tmp;
11768 }
11769 LABEL_REF(label);
11770 return label;
11771}
11772
11773static VALUE
11774get_exception_sym2type(VALUE sym)
11775{
11776 static VALUE symRescue, symEnsure, symRetry;
11777 static VALUE symBreak, symRedo, symNext;
11778
11779 if (symRescue == 0) {
11780 symRescue = ID2SYM(rb_intern_const("rescue"));
11781 symEnsure = ID2SYM(rb_intern_const("ensure"));
11782 symRetry = ID2SYM(rb_intern_const("retry"));
11783 symBreak = ID2SYM(rb_intern_const("break"));
11784 symRedo = ID2SYM(rb_intern_const("redo"));
11785 symNext = ID2SYM(rb_intern_const("next"));
11786 }
11787
11788 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11789 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11790 if (sym == symRetry) return CATCH_TYPE_RETRY;
11791 if (sym == symBreak) return CATCH_TYPE_BREAK;
11792 if (sym == symRedo) return CATCH_TYPE_REDO;
11793 if (sym == symNext) return CATCH_TYPE_NEXT;
11794 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11795 return 0;
11796}
11797
11798static int
11799iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11800 VALUE exception)
11801{
11802 int i;
11803
11804 for (i=0; i<RARRAY_LEN(exception); i++) {
11805 const rb_iseq_t *eiseq;
11806 VALUE v, type;
11807 LABEL *lstart, *lend, *lcont;
11808 unsigned int sp;
11809
11810 v = rb_to_array_type(RARRAY_AREF(exception, i));
11811 if (RARRAY_LEN(v) != 6) {
11812 rb_raise(rb_eSyntaxError, "wrong exception entry");
11813 }
11814 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11815 if (NIL_P(RARRAY_AREF(v, 1))) {
11816 eiseq = NULL;
11817 }
11818 else {
11819 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11820 }
11821
11822 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11823 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11824 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11825 sp = NUM2UINT(RARRAY_AREF(v, 5));
11826
11827 /* TODO: Dirty Hack! Fix me */
11828 if (type == CATCH_TYPE_RESCUE ||
11829 type == CATCH_TYPE_BREAK ||
11830 type == CATCH_TYPE_NEXT) {
11831 ++sp;
11832 }
11833
11834 lcont->sp = sp;
11835
11836 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11837
11838 RB_GC_GUARD(v);
11839 }
11840 return COMPILE_OK;
11841}
11842
11843static struct st_table *
11844insn_make_insn_table(void)
11845{
11846 struct st_table *table;
11847 int i;
11848 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11849
11850 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11851 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11852 }
11853
11854 return table;
11855}
11856
11857static const rb_iseq_t *
11858iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11859{
11860 VALUE iseqw;
11861 const rb_iseq_t *loaded_iseq;
11862
11863 if (RB_TYPE_P(op, T_ARRAY)) {
11864 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11865 }
11866 else if (CLASS_OF(op) == rb_cISeq) {
11867 iseqw = op;
11868 }
11869 else {
11870 rb_raise(rb_eSyntaxError, "ISEQ is required");
11871 }
11872
11873 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11874 return loaded_iseq;
11875}
11876
11877static VALUE
11878iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11879{
11880 ID mid = 0;
11881 int orig_argc = 0;
11882 unsigned int flag = 0;
11883 struct rb_callinfo_kwarg *kw_arg = 0;
11884
11885 if (!NIL_P(op)) {
11886 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11887 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11888 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11889 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11890
11891 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11892 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11893 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11894
11895 if (!NIL_P(vkw_arg)) {
11896 int i;
11897 int len = RARRAY_LENINT(vkw_arg);
11898 size_t n = rb_callinfo_kwarg_bytes(len);
11899
11900 kw_arg = xmalloc(n);
11901 kw_arg->references = 0;
11902 kw_arg->keyword_len = len;
11903 for (i = 0; i < len; i++) {
11904 VALUE kw = RARRAY_AREF(vkw_arg, i);
11905 SYM2ID(kw); /* make immortal */
11906 kw_arg->keywords[i] = kw;
11907 }
11908 }
11909 }
11910
11911 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11912 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11913 return (VALUE)ci;
11914}
11915
11916static rb_event_flag_t
11917event_name_to_flag(VALUE sym)
11918{
11919#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11920 CHECK_EVENT(RUBY_EVENT_LINE);
11921 CHECK_EVENT(RUBY_EVENT_CLASS);
11922 CHECK_EVENT(RUBY_EVENT_END);
11923 CHECK_EVENT(RUBY_EVENT_CALL);
11924 CHECK_EVENT(RUBY_EVENT_RETURN);
11925 CHECK_EVENT(RUBY_EVENT_B_CALL);
11926 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11927 CHECK_EVENT(RUBY_EVENT_RESCUE);
11928#undef CHECK_EVENT
11929 return RUBY_EVENT_NONE;
11930}
11931
11932static int
11933iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11934 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11935{
11936 /* TODO: body should be frozen */
11937 long i, len = RARRAY_LEN(body);
11938 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11939 int j;
11940 int line_no = 0, node_id = -1, insn_idx = 0;
11941 int ret = COMPILE_OK;
11942
11943 /*
11944 * index -> LABEL *label
11945 */
11946 static struct st_table *insn_table;
11947
11948 if (insn_table == 0) {
11949 insn_table = insn_make_insn_table();
11950 }
11951
11952 for (i=0; i<len; i++) {
11953 VALUE obj = RARRAY_AREF(body, i);
11954
11955 if (SYMBOL_P(obj)) {
11956 rb_event_flag_t event;
11957 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11958 ADD_TRACE(anchor, event);
11959 }
11960 else {
11961 LABEL *label = register_label(iseq, labels_table, obj);
11962 ADD_LABEL(anchor, label);
11963 }
11964 }
11965 else if (FIXNUM_P(obj)) {
11966 line_no = NUM2INT(obj);
11967 }
11968 else if (RB_TYPE_P(obj, T_ARRAY)) {
11969 VALUE *argv = 0;
11970 int argc = RARRAY_LENINT(obj) - 1;
11971 st_data_t insn_id;
11972 VALUE insn;
11973
11974 if (node_ids) {
11975 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11976 }
11977
11978 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11979 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11980 /* TODO: exception */
11981 COMPILE_ERROR(iseq, line_no,
11982 "unknown instruction: %+"PRIsVALUE, insn);
11983 ret = COMPILE_NG;
11984 break;
11985 }
11986
11987 if (argc != insn_len((VALUE)insn_id)-1) {
11988 COMPILE_ERROR(iseq, line_no,
11989 "operand size mismatch");
11990 ret = COMPILE_NG;
11991 break;
11992 }
11993
11994 if (argc > 0) {
11995 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11996
11997 // add element before operand setup to make GC root
11998 ADD_ELEM(anchor,
11999 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12000 (enum ruby_vminsn_type)insn_id, argc, argv));
12001
12002 for (j=0; j<argc; j++) {
12003 VALUE op = rb_ary_entry(obj, j+1);
12004 switch (insn_op_type((VALUE)insn_id, j)) {
12005 case TS_OFFSET: {
12006 LABEL *label = register_label(iseq, labels_table, op);
12007 argv[j] = (VALUE)label;
12008 break;
12009 }
12010 case TS_LINDEX:
12011 case TS_NUM:
12012 (void)NUM2INT(op);
12013 argv[j] = op;
12014 break;
12015 case TS_VALUE:
12016 argv[j] = op;
12017 RB_OBJ_WRITTEN(iseq, Qundef, op);
12018 break;
12019 case TS_ISEQ:
12020 {
12021 if (op != Qnil) {
12022 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12023 argv[j] = v;
12024 RB_OBJ_WRITTEN(iseq, Qundef, v);
12025 }
12026 else {
12027 argv[j] = 0;
12028 }
12029 }
12030 break;
12031 case TS_ISE:
12032 argv[j] = op;
12033 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12034 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12035 }
12036 break;
12037 case TS_IC:
12038 {
12039 VALUE segments = rb_ary_new();
12040 op = rb_to_array_type(op);
12041
12042 for (int i = 0; i < RARRAY_LEN(op); i++) {
12043 VALUE sym = RARRAY_AREF(op, i);
12044 sym = rb_to_symbol_type(sym);
12045 rb_ary_push(segments, sym);
12046 }
12047
12048 RB_GC_GUARD(op);
12049 argv[j] = segments;
12050 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12051 ISEQ_BODY(iseq)->ic_size++;
12052 }
12053 break;
12054 case TS_IVC: /* inline ivar cache */
12055 argv[j] = op;
12056 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12057 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12058 }
12059 break;
12060 case TS_ICVARC: /* inline cvar cache */
12061 argv[j] = op;
12062 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12063 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12064 }
12065 break;
12066 case TS_CALLDATA:
12067 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12068 break;
12069 case TS_ID:
12070 argv[j] = rb_to_symbol_type(op);
12071 break;
12072 case TS_CDHASH:
12073 {
12074 int i;
12075 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12076
12077 RHASH_TBL_RAW(map)->type = &cdhash_type;
12078 op = rb_to_array_type(op);
12079 for (i=0; i<RARRAY_LEN(op); i+=2) {
12080 VALUE key = RARRAY_AREF(op, i);
12081 VALUE sym = RARRAY_AREF(op, i+1);
12082 LABEL *label =
12083 register_label(iseq, labels_table, sym);
12084 rb_hash_aset(map, key, (VALUE)label | 1);
12085 }
12086 RB_GC_GUARD(op);
12087 argv[j] = map;
12088 RB_OBJ_WRITTEN(iseq, Qundef, map);
12089 }
12090 break;
12091 case TS_FUNCPTR:
12092 {
12093#if SIZEOF_VALUE <= SIZEOF_LONG
12094 long funcptr = NUM2LONG(op);
12095#else
12096 LONG_LONG funcptr = NUM2LL(op);
12097#endif
12098 argv[j] = (VALUE)funcptr;
12099 }
12100 break;
12101 default:
12102 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12103 }
12104 }
12105 }
12106 else {
12107 ADD_ELEM(anchor,
12108 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12109 (enum ruby_vminsn_type)insn_id, argc, NULL));
12110 }
12111 }
12112 else {
12113 rb_raise(rb_eTypeError, "unexpected object for instruction");
12114 }
12115 }
12116 RTYPEDDATA_DATA(labels_wrapper) = 0;
12117 RB_GC_GUARD(labels_wrapper);
12118 validate_labels(iseq, labels_table);
12119 if (!ret) return ret;
12120 return iseq_setup(iseq, anchor);
12121}
12122
12123#define CHECK_ARRAY(v) rb_to_array_type(v)
12124#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12125
12126static int
12127int_param(int *dst, VALUE param, VALUE sym)
12128{
12129 VALUE val = rb_hash_aref(param, sym);
12130 if (FIXNUM_P(val)) {
12131 *dst = FIX2INT(val);
12132 return TRUE;
12133 }
12134 else if (!NIL_P(val)) {
12135 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12136 sym, val);
12137 }
12138 return FALSE;
12139}
12140
12141static const struct rb_iseq_param_keyword *
12142iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12143{
12144 int i, j;
12145 int len = RARRAY_LENINT(keywords);
12146 int default_len;
12147 VALUE key, sym, default_val;
12148 VALUE *dvs;
12149 ID *ids;
12150 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12151
12152 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12153
12154 keyword->num = len;
12155#define SYM(s) ID2SYM(rb_intern_const(#s))
12156 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12157 i = keyword->bits_start - keyword->num;
12158 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12159#undef SYM
12160
12161 /* required args */
12162 for (i = 0; i < len; i++) {
12163 VALUE val = RARRAY_AREF(keywords, i);
12164
12165 if (!SYMBOL_P(val)) {
12166 goto default_values;
12167 }
12168 ids[i] = SYM2ID(val);
12169 keyword->required_num++;
12170 }
12171
12172 default_values: /* note: we intentionally preserve `i' from previous loop */
12173 default_len = len - i;
12174 if (default_len == 0) {
12175 keyword->table = ids;
12176 return keyword;
12177 }
12178 else if (default_len < 0) {
12180 }
12181
12182 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12183
12184 for (j = 0; i < len; i++, j++) {
12185 key = RARRAY_AREF(keywords, i);
12186 CHECK_ARRAY(key);
12187
12188 switch (RARRAY_LEN(key)) {
12189 case 1:
12190 sym = RARRAY_AREF(key, 0);
12191 default_val = Qundef;
12192 break;
12193 case 2:
12194 sym = RARRAY_AREF(key, 0);
12195 default_val = RARRAY_AREF(key, 1);
12196 break;
12197 default:
12198 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12199 }
12200 ids[i] = SYM2ID(sym);
12201 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12202 }
12203
12204 keyword->table = ids;
12205 keyword->default_values = dvs;
12206
12207 return keyword;
12208}
12209
12210static void
12211iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12212{
12213 rb_gc_mark_and_move(obj);
12214}
12215
12216void
12217rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12218{
12219 INSN *iobj = 0;
12220 size_t size = sizeof(INSN);
12221 unsigned int pos = 0;
12222
12223 while (storage) {
12224#ifdef STRICT_ALIGNMENT
12225 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12226#else
12227 const size_t padding = 0; /* expected to be optimized by compiler */
12228#endif /* STRICT_ALIGNMENT */
12229 size_t offset = pos + size + padding;
12230 if (offset > storage->size || offset > storage->pos) {
12231 pos = 0;
12232 storage = storage->next;
12233 }
12234 else {
12235#ifdef STRICT_ALIGNMENT
12236 pos += (int)padding;
12237#endif /* STRICT_ALIGNMENT */
12238
12239 iobj = (INSN *)&storage->buff[pos];
12240
12241 if (iobj->operands) {
12242 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12243 }
12244 pos += (int)size;
12245 }
12246 }
12247}
12248
12249static const rb_data_type_t labels_wrapper_type = {
12250 .wrap_struct_name = "compiler/labels_wrapper",
12251 .function = {
12252 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12253 .dfree = (RUBY_DATA_FUNC)st_free_table,
12254 },
12255 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12256};
12257
12258void
12259rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12260 VALUE exception, VALUE body)
12261{
12262#define SYM(s) ID2SYM(rb_intern_const(#s))
12263 int i, len;
12264 unsigned int arg_size, local_size, stack_max;
12265 ID *tbl;
12266 struct st_table *labels_table = st_init_numtable();
12267 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12268 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12269 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12270 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12271 DECL_ANCHOR(anchor);
12272 INIT_ANCHOR(anchor);
12273
12274 len = RARRAY_LENINT(locals);
12275 ISEQ_BODY(iseq)->local_table_size = len;
12276 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12277
12278 for (i = 0; i < len; i++) {
12279 VALUE lv = RARRAY_AREF(locals, i);
12280
12281 if (sym_arg_rest == lv) {
12282 tbl[i] = 0;
12283 }
12284 else {
12285 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12286 }
12287 }
12288
12289#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12290 if (INT_PARAM(lead_num)) {
12291 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12292 }
12293 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12294 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12295 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12296 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12297#undef INT_PARAM
12298 {
12299#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12300 int x;
12301 INT_PARAM(arg_size);
12302 INT_PARAM(local_size);
12303 INT_PARAM(stack_max);
12304#undef INT_PARAM
12305 }
12306
12307 VALUE node_ids = Qfalse;
12308#ifdef USE_ISEQ_NODE_ID
12309 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12310 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12311 rb_raise(rb_eTypeError, "node_ids is not an array");
12312 }
12313#endif
12314
12315 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12316 len = RARRAY_LENINT(arg_opt_labels);
12317 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12318
12319 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12320 VALUE *opt_table = ALLOC_N(VALUE, len);
12321
12322 for (i = 0; i < len; i++) {
12323 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12324 LABEL *label = register_label(iseq, labels_table, ent);
12325 opt_table[i] = (VALUE)label;
12326 }
12327
12328 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12329 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12330 }
12331 }
12332 else if (!NIL_P(arg_opt_labels)) {
12333 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12334 arg_opt_labels);
12335 }
12336
12337 if (RB_TYPE_P(keywords, T_ARRAY)) {
12338 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12339 }
12340 else if (!NIL_P(keywords)) {
12341 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12342 keywords);
12343 }
12344
12345 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12346 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12347 }
12348
12349 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12350 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12351 }
12352
12353 if (int_param(&i, params, SYM(kwrest))) {
12354 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12355 if (keyword == NULL) {
12356 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12357 }
12358 keyword->rest_start = i;
12359 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12360 }
12361#undef SYM
12362 iseq_calc_param_size(iseq);
12363
12364 /* exception */
12365 iseq_build_from_ary_exception(iseq, labels_table, exception);
12366
12367 /* body */
12368 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12369
12370 ISEQ_BODY(iseq)->param.size = arg_size;
12371 ISEQ_BODY(iseq)->local_table_size = local_size;
12372 ISEQ_BODY(iseq)->stack_max = stack_max;
12373}
12374
12375/* for parser */
12376
12377int
12378rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12379{
12380 if (iseq) {
12381 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12382 while (body->type == ISEQ_TYPE_BLOCK ||
12383 body->type == ISEQ_TYPE_RESCUE ||
12384 body->type == ISEQ_TYPE_ENSURE ||
12385 body->type == ISEQ_TYPE_EVAL ||
12386 body->type == ISEQ_TYPE_MAIN
12387 ) {
12388 unsigned int i;
12389
12390 for (i = 0; i < body->local_table_size; i++) {
12391 if (body->local_table[i] == id) {
12392 return 1;
12393 }
12394 }
12395 iseq = body->parent_iseq;
12396 body = ISEQ_BODY(iseq);
12397 }
12398 }
12399 return 0;
12400}
12401
12402int
12403rb_local_defined(ID id, const rb_iseq_t *iseq)
12404{
12405 if (iseq) {
12406 unsigned int i;
12407 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12408
12409 for (i=0; i<body->local_table_size; i++) {
12410 if (body->local_table[i] == id) {
12411 return 1;
12412 }
12413 }
12414 }
12415 return 0;
12416}
12417
12418/* ISeq binary format */
12419
12420#ifndef IBF_ISEQ_DEBUG
12421#define IBF_ISEQ_DEBUG 0
12422#endif
12423
12424#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12425#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12426#endif
12427
12428typedef uint32_t ibf_offset_t;
12429#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12430
12431#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12432#ifdef RUBY_DEVEL
12433#define IBF_DEVEL_VERSION 4
12434#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12435#else
12436#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12437#endif
12438
12439static const char IBF_ENDIAN_MARK =
12440#ifdef WORDS_BIGENDIAN
12441 'b'
12442#else
12443 'l'
12444#endif
12445 ;
12446
12448 char magic[4]; /* YARB */
12449 uint32_t major_version;
12450 uint32_t minor_version;
12451 uint32_t size;
12452 uint32_t extra_size;
12453
12454 uint32_t iseq_list_size;
12455 uint32_t global_object_list_size;
12456 ibf_offset_t iseq_list_offset;
12457 ibf_offset_t global_object_list_offset;
12458 uint8_t endian;
12459 uint8_t wordsize; /* assume no 2048-bit CPU */
12460};
12461
12463 VALUE str;
12464 st_table *obj_table; /* obj -> obj number */
12465};
12466
12467struct ibf_dump {
12468 st_table *iseq_table; /* iseq -> iseq number */
12469 struct ibf_dump_buffer global_buffer;
12470 struct ibf_dump_buffer *current_buffer;
12471};
12472
12474 const char *buff;
12475 ibf_offset_t size;
12476
12477 VALUE obj_list; /* [obj0, ...] */
12478 unsigned int obj_list_size;
12479 ibf_offset_t obj_list_offset;
12480};
12481
12482struct ibf_load {
12483 const struct ibf_header *header;
12484 VALUE iseq_list; /* [iseq0, ...] */
12485 struct ibf_load_buffer global_buffer;
12486 VALUE loader_obj;
12487 rb_iseq_t *iseq;
12488 VALUE str;
12489 struct ibf_load_buffer *current_buffer;
12490};
12491
12493 long size;
12494 VALUE buffer[1];
12495};
12496
12497static void
12498pinned_list_mark(void *ptr)
12499{
12500 long i;
12501 struct pinned_list *list = (struct pinned_list *)ptr;
12502 for (i = 0; i < list->size; i++) {
12503 if (list->buffer[i]) {
12504 rb_gc_mark(list->buffer[i]);
12505 }
12506 }
12507}
12508
12509static const rb_data_type_t pinned_list_type = {
12510 "pinned_list",
12511 {
12512 pinned_list_mark,
12514 NULL, // No external memory to report,
12515 },
12516 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12517};
12518
12519static VALUE
12520pinned_list_fetch(VALUE list, long offset)
12521{
12522 struct pinned_list * ptr;
12523
12524 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12525
12526 if (offset >= ptr->size) {
12527 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12528 }
12529
12530 return ptr->buffer[offset];
12531}
12532
12533static void
12534pinned_list_store(VALUE list, long offset, VALUE object)
12535{
12536 struct pinned_list * ptr;
12537
12538 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12539
12540 if (offset >= ptr->size) {
12541 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12542 }
12543
12544 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12545}
12546
12547static VALUE
12548pinned_list_new(long size)
12549{
12550 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12551 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12552 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12553 ptr->size = size;
12554 return obj_list;
12555}
12556
12557static ibf_offset_t
12558ibf_dump_pos(struct ibf_dump *dump)
12559{
12560 long pos = RSTRING_LEN(dump->current_buffer->str);
12561#if SIZEOF_LONG > SIZEOF_INT
12562 if (pos >= UINT_MAX) {
12563 rb_raise(rb_eRuntimeError, "dump size exceeds");
12564 }
12565#endif
12566 return (unsigned int)pos;
12567}
12568
12569static void
12570ibf_dump_align(struct ibf_dump *dump, size_t align)
12571{
12572 ibf_offset_t pos = ibf_dump_pos(dump);
12573 if (pos % align) {
12574 static const char padding[sizeof(VALUE)];
12575 size_t size = align - ((size_t)pos % align);
12576#if SIZEOF_LONG > SIZEOF_INT
12577 if (pos + size >= UINT_MAX) {
12578 rb_raise(rb_eRuntimeError, "dump size exceeds");
12579 }
12580#endif
12581 for (; size > sizeof(padding); size -= sizeof(padding)) {
12582 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12583 }
12584 rb_str_cat(dump->current_buffer->str, padding, size);
12585 }
12586}
12587
12588static ibf_offset_t
12589ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12590{
12591 ibf_offset_t pos = ibf_dump_pos(dump);
12592 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12593 /* TODO: overflow check */
12594 return pos;
12595}
12596
12597static ibf_offset_t
12598ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12599{
12600 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12601}
12602
12603static void
12604ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12605{
12606 VALUE str = dump->current_buffer->str;
12607 char *ptr = RSTRING_PTR(str);
12608 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12609 rb_bug("ibf_dump_overwrite: overflow");
12610 memcpy(ptr + offset, buff, size);
12611}
12612
12613static const void *
12614ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12615{
12616 ibf_offset_t beg = *offset;
12617 *offset += size;
12618 return load->current_buffer->buff + beg;
12619}
12620
12621static void *
12622ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12623{
12624 void *buff = ruby_xmalloc2(x, y);
12625 size_t size = x * y;
12626 memcpy(buff, load->current_buffer->buff + offset, size);
12627 return buff;
12628}
12629
12630#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12631
12632#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12633#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12634#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12635#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12636#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12637
12638static int
12639ibf_table_lookup(struct st_table *table, st_data_t key)
12640{
12641 st_data_t val;
12642
12643 if (st_lookup(table, key, &val)) {
12644 return (int)val;
12645 }
12646 else {
12647 return -1;
12648 }
12649}
12650
12651static int
12652ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12653{
12654 int index = ibf_table_lookup(table, key);
12655
12656 if (index < 0) { /* not found */
12657 index = (int)table->num_entries;
12658 st_insert(table, key, (st_data_t)index);
12659 }
12660
12661 return index;
12662}
12663
12664/* dump/load generic */
12665
12666static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12667
12668static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12669static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12670
12671static st_table *
12672ibf_dump_object_table_new(void)
12673{
12674 st_table *obj_table = st_init_numtable(); /* need free */
12675 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12676
12677 return obj_table;
12678}
12679
12680static VALUE
12681ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12682{
12683 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12684}
12685
12686static VALUE
12687ibf_dump_id(struct ibf_dump *dump, ID id)
12688{
12689 if (id == 0 || rb_id2name(id) == NULL) {
12690 return 0;
12691 }
12692 return ibf_dump_object(dump, rb_id2sym(id));
12693}
12694
12695static ID
12696ibf_load_id(const struct ibf_load *load, const ID id_index)
12697{
12698 if (id_index == 0) {
12699 return 0;
12700 }
12701 VALUE sym = ibf_load_object(load, id_index);
12702 if (rb_integer_type_p(sym)) {
12703 /* Load hidden local variables as indexes */
12704 return NUM2ULONG(sym);
12705 }
12706 return rb_sym2id(sym);
12707}
12708
12709/* dump/load: code */
12710
12711static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12712
12713static int
12714ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12715{
12716 if (iseq == NULL) {
12717 return -1;
12718 }
12719 else {
12720 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12721 }
12722}
12723
12724static unsigned char
12725ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12726{
12727 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12728 return (unsigned char)load->current_buffer->buff[(*offset)++];
12729}
12730
12731/*
12732 * Small uint serialization
12733 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12734 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12735 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12736 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12737 * ...
12738 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12739 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12740 */
12741static void
12742ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12743{
12744 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12745 ibf_dump_write(dump, &x, sizeof(VALUE));
12746 return;
12747 }
12748
12749 enum { max_byte_length = sizeof(VALUE) + 1 };
12750
12751 unsigned char bytes[max_byte_length];
12752 ibf_offset_t n;
12753
12754 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12755 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12756 }
12757
12758 x <<= 1;
12759 x |= 1;
12760 x <<= n;
12761 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12762 n++;
12763
12764 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12765}
12766
12767static VALUE
12768ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12769{
12770 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12771 union { char s[sizeof(VALUE)]; VALUE v; } x;
12772
12773 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12774 *offset += sizeof(VALUE);
12775
12776 return x.v;
12777 }
12778
12779 enum { max_byte_length = sizeof(VALUE) + 1 };
12780
12781 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12782 const unsigned char c = buffer[*offset];
12783
12784 ibf_offset_t n =
12785 c & 1 ? 1 :
12786 c == 0 ? 9 : ntz_int32(c) + 1;
12787 VALUE x = (VALUE)c >> n;
12788
12789 if (*offset + n > load->current_buffer->size) {
12790 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12791 }
12792
12793 ibf_offset_t i;
12794 for (i = 1; i < n; i++) {
12795 x <<= 8;
12796 x |= (VALUE)buffer[*offset + i];
12797 }
12798
12799 *offset += n;
12800 return x;
12801}
12802
12803static void
12804ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12805{
12806 // short: index
12807 // short: name.length
12808 // bytes: name
12809 // // omit argc (only verify with name)
12810 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12811
12812 size_t len = strlen(bf->name);
12813 ibf_dump_write_small_value(dump, (VALUE)len);
12814 ibf_dump_write(dump, bf->name, len);
12815}
12816
12817static const struct rb_builtin_function *
12818ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12819{
12820 int i = (int)ibf_load_small_value(load, offset);
12821 int len = (int)ibf_load_small_value(load, offset);
12822 const char *name = (char *)ibf_load_ptr(load, offset, len);
12823
12824 if (0) {
12825 fprintf(stderr, "%.*s!!\n", len, name);
12826 }
12827
12828 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12829 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12830 if (strncmp(table[i].name, name, len) != 0) {
12831 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12832 }
12833 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12834
12835 return &table[i];
12836}
12837
12838static ibf_offset_t
12839ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12840{
12841 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12842 const int iseq_size = body->iseq_size;
12843 int code_index;
12844 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12845
12846 ibf_offset_t offset = ibf_dump_pos(dump);
12847
12848 for (code_index=0; code_index<iseq_size;) {
12849 const VALUE insn = orig_code[code_index++];
12850 const char *types = insn_op_types(insn);
12851 int op_index;
12852
12853 /* opcode */
12854 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12855 ibf_dump_write_small_value(dump, insn);
12856
12857 /* operands */
12858 for (op_index=0; types[op_index]; op_index++, code_index++) {
12859 VALUE op = orig_code[code_index];
12860 VALUE wv;
12861
12862 switch (types[op_index]) {
12863 case TS_CDHASH:
12864 case TS_VALUE:
12865 wv = ibf_dump_object(dump, op);
12866 break;
12867 case TS_ISEQ:
12868 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12869 break;
12870 case TS_IC:
12871 {
12872 IC ic = (IC)op;
12873 VALUE arr = idlist_to_array(ic->segments);
12874 wv = ibf_dump_object(dump, arr);
12875 }
12876 break;
12877 case TS_ISE:
12878 case TS_IVC:
12879 case TS_ICVARC:
12880 {
12882 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12883 }
12884 break;
12885 case TS_CALLDATA:
12886 {
12887 goto skip_wv;
12888 }
12889 case TS_ID:
12890 wv = ibf_dump_id(dump, (ID)op);
12891 break;
12892 case TS_FUNCPTR:
12893 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12894 goto skip_wv;
12895 case TS_BUILTIN:
12896 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12897 goto skip_wv;
12898 default:
12899 wv = op;
12900 break;
12901 }
12902 ibf_dump_write_small_value(dump, wv);
12903 skip_wv:;
12904 }
12905 RUBY_ASSERT(insn_len(insn) == op_index+1);
12906 }
12907
12908 return offset;
12909}
12910
12911static VALUE *
12912ibf_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)
12913{
12914 VALUE iseqv = (VALUE)iseq;
12915 unsigned int code_index;
12916 ibf_offset_t reading_pos = bytecode_offset;
12917 VALUE *code = ALLOC_N(VALUE, iseq_size);
12918
12919 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12920 struct rb_call_data *cd_entries = load_body->call_data;
12921 int ic_index = 0;
12922
12923 iseq_bits_t * mark_offset_bits;
12924
12925 iseq_bits_t tmp[1] = {0};
12926
12927 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12928 mark_offset_bits = tmp;
12929 }
12930 else {
12931 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12932 }
12933 bool needs_bitmap = false;
12934
12935 for (code_index=0; code_index<iseq_size;) {
12936 /* opcode */
12937 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12938 const char *types = insn_op_types(insn);
12939 int op_index;
12940
12941 code_index++;
12942
12943 /* operands */
12944 for (op_index=0; types[op_index]; op_index++, code_index++) {
12945 const char operand_type = types[op_index];
12946 switch (operand_type) {
12947 case TS_VALUE:
12948 {
12949 VALUE op = ibf_load_small_value(load, &reading_pos);
12950 VALUE v = ibf_load_object(load, op);
12951 code[code_index] = v;
12952 if (!SPECIAL_CONST_P(v)) {
12953 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12954 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12955 needs_bitmap = true;
12956 }
12957 break;
12958 }
12959 case TS_CDHASH:
12960 {
12961 VALUE op = ibf_load_small_value(load, &reading_pos);
12962 VALUE v = ibf_load_object(load, op);
12963 v = rb_hash_dup(v); // hash dumped as frozen
12964 RHASH_TBL_RAW(v)->type = &cdhash_type;
12965 rb_hash_rehash(v); // hash function changed
12966 freeze_hide_obj(v);
12967
12968 // Overwrite the existing hash in the object list. This
12969 // is to keep the object alive during load time.
12970 // [Bug #17984] [ruby-core:104259]
12971 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12972
12973 code[code_index] = v;
12974 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12975 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12976 needs_bitmap = true;
12977 break;
12978 }
12979 case TS_ISEQ:
12980 {
12981 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12982 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12983 code[code_index] = v;
12984 if (!SPECIAL_CONST_P(v)) {
12985 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12986 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12987 needs_bitmap = true;
12988 }
12989 break;
12990 }
12991 case TS_IC:
12992 {
12993 VALUE op = ibf_load_small_value(load, &reading_pos);
12994 VALUE arr = ibf_load_object(load, op);
12995
12996 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12997 ic->segments = array_to_idlist(arr);
12998
12999 code[code_index] = (VALUE)ic;
13000 }
13001 break;
13002 case TS_ISE:
13003 case TS_ICVARC:
13004 case TS_IVC:
13005 {
13006 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13007
13008 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13009 code[code_index] = (VALUE)ic;
13010
13011 if (operand_type == TS_IVC) {
13012 IVC cache = (IVC)ic;
13013
13014 if (insn == BIN(setinstancevariable)) {
13015 ID iv_name = (ID)code[code_index - 1];
13016 cache->iv_set_name = iv_name;
13017 }
13018 else {
13019 cache->iv_set_name = 0;
13020 }
13021
13022 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13023 }
13024
13025 }
13026 break;
13027 case TS_CALLDATA:
13028 {
13029 code[code_index] = (VALUE)cd_entries++;
13030 }
13031 break;
13032 case TS_ID:
13033 {
13034 VALUE op = ibf_load_small_value(load, &reading_pos);
13035 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13036 }
13037 break;
13038 case TS_FUNCPTR:
13039 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13040 break;
13041 case TS_BUILTIN:
13042 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13043 break;
13044 default:
13045 code[code_index] = ibf_load_small_value(load, &reading_pos);
13046 continue;
13047 }
13048 }
13049 if (insn_len(insn) != op_index+1) {
13050 rb_raise(rb_eRuntimeError, "operand size mismatch");
13051 }
13052 }
13053
13054 load_body->iseq_encoded = code;
13055 load_body->iseq_size = code_index;
13056
13057 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13058 load_body->mark_bits.single = mark_offset_bits[0];
13059 }
13060 else {
13061 if (needs_bitmap) {
13062 load_body->mark_bits.list = mark_offset_bits;
13063 }
13064 else {
13065 load_body->mark_bits.list = 0;
13066 ruby_xfree(mark_offset_bits);
13067 }
13068 }
13069
13070 RUBY_ASSERT(code_index == iseq_size);
13071 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13072 return code;
13073}
13074
13075static ibf_offset_t
13076ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13077{
13078 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13079
13080 if (opt_num > 0) {
13081 IBF_W_ALIGN(VALUE);
13082 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13083 }
13084 else {
13085 return ibf_dump_pos(dump);
13086 }
13087}
13088
13089static VALUE *
13090ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13091{
13092 if (opt_num > 0) {
13093 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13094 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13095 return table;
13096 }
13097 else {
13098 return NULL;
13099 }
13100}
13101
13102static ibf_offset_t
13103ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13104{
13105 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13106
13107 if (kw) {
13108 struct rb_iseq_param_keyword dump_kw = *kw;
13109 int dv_num = kw->num - kw->required_num;
13110 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13111 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13112 int i;
13113
13114 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13115 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13116
13117 dump_kw.table = IBF_W(ids, ID, kw->num);
13118 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13119 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13120 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13121 }
13122 else {
13123 return 0;
13124 }
13125}
13126
13127static const struct rb_iseq_param_keyword *
13128ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13129{
13130 if (param_keyword_offset) {
13131 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13132 int dv_num = kw->num - kw->required_num;
13133 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13134
13135 int i;
13136 for (i=0; i<dv_num; i++) {
13137 dvs[i] = ibf_load_object(load, dvs[i]);
13138 }
13139
13140 // Will be set once the local table is loaded.
13141 kw->table = NULL;
13142
13143 kw->default_values = dvs;
13144 return kw;
13145 }
13146 else {
13147 return NULL;
13148 }
13149}
13150
13151static ibf_offset_t
13152ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13153{
13154 ibf_offset_t offset = ibf_dump_pos(dump);
13155 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13156
13157 unsigned int i;
13158 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13159 ibf_dump_write_small_value(dump, entries[i].line_no);
13160#ifdef USE_ISEQ_NODE_ID
13161 ibf_dump_write_small_value(dump, entries[i].node_id);
13162#endif
13163 ibf_dump_write_small_value(dump, entries[i].events);
13164 }
13165
13166 return offset;
13167}
13168
13169static struct iseq_insn_info_entry *
13170ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13171{
13172 ibf_offset_t reading_pos = body_offset;
13173 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13174
13175 unsigned int i;
13176 for (i = 0; i < size; i++) {
13177 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13178#ifdef USE_ISEQ_NODE_ID
13179 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13180#endif
13181 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13182 }
13183
13184 return entries;
13185}
13186
13187static ibf_offset_t
13188ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13189{
13190 ibf_offset_t offset = ibf_dump_pos(dump);
13191
13192 unsigned int last = 0;
13193 unsigned int i;
13194 for (i = 0; i < size; i++) {
13195 ibf_dump_write_small_value(dump, positions[i] - last);
13196 last = positions[i];
13197 }
13198
13199 return offset;
13200}
13201
13202static unsigned int *
13203ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13204{
13205 ibf_offset_t reading_pos = positions_offset;
13206 unsigned int *positions = ALLOC_N(unsigned int, size);
13207
13208 unsigned int last = 0;
13209 unsigned int i;
13210 for (i = 0; i < size; i++) {
13211 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13212 last = positions[i];
13213 }
13214
13215 return positions;
13216}
13217
13218static ibf_offset_t
13219ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13220{
13221 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13222 const int size = body->local_table_size;
13223 ID *table = ALLOCA_N(ID, size);
13224 int i;
13225
13226 for (i=0; i<size; i++) {
13227 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13228 if (v == 0) {
13229 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13230 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13231 }
13232 table[i] = v;
13233 }
13234
13235 IBF_W_ALIGN(ID);
13236 return ibf_dump_write(dump, table, sizeof(ID) * size);
13237}
13238
13239static ID *
13240ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13241{
13242 if (size > 0) {
13243 ID *table = IBF_R(local_table_offset, ID, size);
13244 int i;
13245
13246 for (i=0; i<size; i++) {
13247 table[i] = ibf_load_id(load, table[i]);
13248 }
13249 return table;
13250 }
13251 else {
13252 return NULL;
13253 }
13254}
13255
13256static ibf_offset_t
13257ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13258{
13259 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13260
13261 if (table) {
13262 int *iseq_indices = ALLOCA_N(int, table->size);
13263 unsigned int i;
13264
13265 for (i=0; i<table->size; i++) {
13266 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13267 }
13268
13269 const ibf_offset_t offset = ibf_dump_pos(dump);
13270
13271 for (i=0; i<table->size; i++) {
13272 ibf_dump_write_small_value(dump, iseq_indices[i]);
13273 ibf_dump_write_small_value(dump, table->entries[i].type);
13274 ibf_dump_write_small_value(dump, table->entries[i].start);
13275 ibf_dump_write_small_value(dump, table->entries[i].end);
13276 ibf_dump_write_small_value(dump, table->entries[i].cont);
13277 ibf_dump_write_small_value(dump, table->entries[i].sp);
13278 }
13279 return offset;
13280 }
13281 else {
13282 return ibf_dump_pos(dump);
13283 }
13284}
13285
13286static struct iseq_catch_table *
13287ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
13288{
13289 if (size) {
13290 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13291 table->size = size;
13292
13293 ibf_offset_t reading_pos = catch_table_offset;
13294
13295 unsigned int i;
13296 for (i=0; i<table->size; i++) {
13297 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13298 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13299 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13300 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13301 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13302 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13303
13304 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13305 }
13306 return table;
13307 }
13308 else {
13309 return NULL;
13310 }
13311}
13312
13313static ibf_offset_t
13314ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13315{
13316 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13317 const unsigned int ci_size = body->ci_size;
13318 const struct rb_call_data *cds = body->call_data;
13319
13320 ibf_offset_t offset = ibf_dump_pos(dump);
13321
13322 unsigned int i;
13323
13324 for (i = 0; i < ci_size; i++) {
13325 const struct rb_callinfo *ci = cds[i].ci;
13326 if (ci != NULL) {
13327 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13328 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13329 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13330
13331 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13332 if (kwarg) {
13333 int len = kwarg->keyword_len;
13334 ibf_dump_write_small_value(dump, len);
13335 for (int j=0; j<len; j++) {
13336 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13337 ibf_dump_write_small_value(dump, keyword);
13338 }
13339 }
13340 else {
13341 ibf_dump_write_small_value(dump, 0);
13342 }
13343 }
13344 else {
13345 // TODO: truncate NULL ci from call_data.
13346 ibf_dump_write_small_value(dump, (VALUE)-1);
13347 }
13348 }
13349
13350 return offset;
13351}
13352
13354 ID id;
13355 VALUE name;
13356 VALUE val;
13357};
13358
13360 size_t num;
13361 struct outer_variable_pair pairs[1];
13362};
13363
13364static enum rb_id_table_iterator_result
13365store_outer_variable(ID id, VALUE val, void *dump)
13366{
13367 struct outer_variable_list *ovlist = dump;
13368 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13369 pair->id = id;
13370 pair->name = rb_id2str(id);
13371 pair->val = val;
13372 return ID_TABLE_CONTINUE;
13373}
13374
13375static int
13376outer_variable_cmp(const void *a, const void *b, void *arg)
13377{
13378 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13379 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13380 return rb_str_cmp(ap->name, bp->name);
13381}
13382
13383static ibf_offset_t
13384ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13385{
13386 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13387
13388 ibf_offset_t offset = ibf_dump_pos(dump);
13389
13390 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13391 ibf_dump_write_small_value(dump, (VALUE)size);
13392 if (size > 0) {
13393 VALUE buff;
13394 size_t buffsize =
13395 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13396 offsetof(struct outer_variable_list, pairs),
13397 rb_eArgError);
13398 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13399 ovlist->num = 0;
13400 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13401 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13402 for (size_t i = 0; i < size; ++i) {
13403 ID id = ovlist->pairs[i].id;
13404 ID val = ovlist->pairs[i].val;
13405 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13406 ibf_dump_write_small_value(dump, val);
13407 }
13408 }
13409
13410 return offset;
13411}
13412
13413/* note that we dump out rb_call_info but load back rb_call_data */
13414static void
13415ibf_load_ci_entries(const struct ibf_load *load,
13416 ibf_offset_t ci_entries_offset,
13417 unsigned int ci_size,
13418 struct rb_call_data **cd_ptr)
13419{
13420 if (!ci_size) {
13421 *cd_ptr = NULL;
13422 return;
13423 }
13424
13425 ibf_offset_t reading_pos = ci_entries_offset;
13426
13427 unsigned int i;
13428
13429 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13430 *cd_ptr = cds;
13431
13432 for (i = 0; i < ci_size; i++) {
13433 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13434 if (mid_index != (VALUE)-1) {
13435 ID mid = ibf_load_id(load, mid_index);
13436 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13437 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13438
13439 struct rb_callinfo_kwarg *kwarg = NULL;
13440 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13441 if (kwlen > 0) {
13442 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13443 kwarg->references = 0;
13444 kwarg->keyword_len = kwlen;
13445 for (int j=0; j<kwlen; j++) {
13446 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13447 kwarg->keywords[j] = ibf_load_object(load, keyword);
13448 }
13449 }
13450
13451 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13452 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13453 cds[i].cc = vm_cc_empty();
13454 }
13455 else {
13456 // NULL ci
13457 cds[i].ci = NULL;
13458 cds[i].cc = NULL;
13459 }
13460 }
13461}
13462
13463static struct rb_id_table *
13464ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13465{
13466 ibf_offset_t reading_pos = outer_variables_offset;
13467
13468 struct rb_id_table *tbl = NULL;
13469
13470 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13471
13472 if (table_size > 0) {
13473 tbl = rb_id_table_create(table_size);
13474 }
13475
13476 for (size_t i = 0; i < table_size; i++) {
13477 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13478 VALUE value = ibf_load_small_value(load, &reading_pos);
13479 if (!key) key = rb_make_temporary_id(i);
13480 rb_id_table_insert(tbl, key, value);
13481 }
13482
13483 return tbl;
13484}
13485
13486static ibf_offset_t
13487ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13488{
13489 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13490
13491 unsigned int *positions;
13492
13493 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13494
13495 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13496 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13497 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13498
13499#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13500 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13501
13502 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13503 struct ibf_dump_buffer buffer;
13504 buffer.str = rb_str_new(0, 0);
13505 buffer.obj_table = ibf_dump_object_table_new();
13506 dump->current_buffer = &buffer;
13507#endif
13508
13509 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13510 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13511 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13512 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13513 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13514
13515 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13516 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13517 ruby_xfree(positions);
13518
13519 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13520 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13521 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13522 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13523 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13524 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13525 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13526 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13527
13528#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13529 ibf_offset_t local_obj_list_offset;
13530 unsigned int local_obj_list_size;
13531
13532 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13533#endif
13534
13535 ibf_offset_t body_offset = ibf_dump_pos(dump);
13536
13537 /* dump the constant body */
13538 unsigned int param_flags =
13539 (body->param.flags.has_lead << 0) |
13540 (body->param.flags.has_opt << 1) |
13541 (body->param.flags.has_rest << 2) |
13542 (body->param.flags.has_post << 3) |
13543 (body->param.flags.has_kw << 4) |
13544 (body->param.flags.has_kwrest << 5) |
13545 (body->param.flags.has_block << 6) |
13546 (body->param.flags.ambiguous_param0 << 7) |
13547 (body->param.flags.accepts_no_kwarg << 8) |
13548 (body->param.flags.ruby2_keywords << 9) |
13549 (body->param.flags.anon_rest << 10) |
13550 (body->param.flags.anon_kwrest << 11) |
13551 (body->param.flags.use_block << 12) |
13552 (body->param.flags.forwardable << 13) ;
13553
13554#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13555# define IBF_BODY_OFFSET(x) (x)
13556#else
13557# define IBF_BODY_OFFSET(x) (body_offset - (x))
13558#endif
13559
13560 ibf_dump_write_small_value(dump, body->type);
13561 ibf_dump_write_small_value(dump, body->iseq_size);
13562 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13563 ibf_dump_write_small_value(dump, bytecode_size);
13564 ibf_dump_write_small_value(dump, param_flags);
13565 ibf_dump_write_small_value(dump, body->param.size);
13566 ibf_dump_write_small_value(dump, body->param.lead_num);
13567 ibf_dump_write_small_value(dump, body->param.opt_num);
13568 ibf_dump_write_small_value(dump, body->param.rest_start);
13569 ibf_dump_write_small_value(dump, body->param.post_start);
13570 ibf_dump_write_small_value(dump, body->param.post_num);
13571 ibf_dump_write_small_value(dump, body->param.block_start);
13572 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13573 ibf_dump_write_small_value(dump, param_keyword_offset);
13574 ibf_dump_write_small_value(dump, location_pathobj_index);
13575 ibf_dump_write_small_value(dump, location_base_label_index);
13576 ibf_dump_write_small_value(dump, location_label_index);
13577 ibf_dump_write_small_value(dump, body->location.first_lineno);
13578 ibf_dump_write_small_value(dump, body->location.node_id);
13579 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13580 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13581 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13582 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13583 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13584 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13585 ibf_dump_write_small_value(dump, body->insns_info.size);
13586 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13587 ibf_dump_write_small_value(dump, catch_table_size);
13588 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13589 ibf_dump_write_small_value(dump, parent_iseq_index);
13590 ibf_dump_write_small_value(dump, local_iseq_index);
13591 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13592 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13593 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13594 ibf_dump_write_small_value(dump, body->variable.flip_count);
13595 ibf_dump_write_small_value(dump, body->local_table_size);
13596 ibf_dump_write_small_value(dump, body->ivc_size);
13597 ibf_dump_write_small_value(dump, body->icvarc_size);
13598 ibf_dump_write_small_value(dump, body->ise_size);
13599 ibf_dump_write_small_value(dump, body->ic_size);
13600 ibf_dump_write_small_value(dump, body->ci_size);
13601 ibf_dump_write_small_value(dump, body->stack_max);
13602 ibf_dump_write_small_value(dump, body->builtin_attrs);
13603 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13604
13605#undef IBF_BODY_OFFSET
13606
13607#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13608 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13609
13610 dump->current_buffer = saved_buffer;
13611 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13612
13613 ibf_offset_t offset = ibf_dump_pos(dump);
13614 ibf_dump_write_small_value(dump, iseq_start);
13615 ibf_dump_write_small_value(dump, iseq_length_bytes);
13616 ibf_dump_write_small_value(dump, body_offset);
13617
13618 ibf_dump_write_small_value(dump, local_obj_list_offset);
13619 ibf_dump_write_small_value(dump, local_obj_list_size);
13620
13621 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13622
13623 return offset;
13624#else
13625 return body_offset;
13626#endif
13627}
13628
13629static VALUE
13630ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13631{
13632 VALUE str = ibf_load_object(load, str_index);
13633 if (str != Qnil) {
13634 str = rb_fstring(str);
13635 }
13636 return str;
13637}
13638
13639static void
13640ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13641{
13642 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13643
13644 ibf_offset_t reading_pos = offset;
13645
13646#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13647 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13648 load->current_buffer = &load->global_buffer;
13649
13650 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13651 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13652 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13653
13654 struct ibf_load_buffer buffer;
13655 buffer.buff = load->global_buffer.buff + iseq_start;
13656 buffer.size = iseq_length_bytes;
13657 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13658 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13659 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13660
13661 load->current_buffer = &buffer;
13662 reading_pos = body_offset;
13663#endif
13664
13665#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13666# define IBF_BODY_OFFSET(x) (x)
13667#else
13668# define IBF_BODY_OFFSET(x) (offset - (x))
13669#endif
13670
13671 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13672 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13673 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13674 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13675 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13676 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13677 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13678 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13679 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13680 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13681 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13682 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13683 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13684 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13685 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13686 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13687 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13688 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13689 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13690 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13691 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13692 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13693 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13694 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13695 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13696 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13697 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13698 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13699 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13700 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13701 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13702 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13703 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13704 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13705 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13706 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13707
13708 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13709 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13710 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13711 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13712
13713 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13714 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13715 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13716 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13717
13718 // setup fname and dummy frame
13719 VALUE path = ibf_load_object(load, location_pathobj_index);
13720 {
13721 VALUE realpath = Qnil;
13722
13723 if (RB_TYPE_P(path, T_STRING)) {
13724 realpath = path = rb_fstring(path);
13725 }
13726 else if (RB_TYPE_P(path, T_ARRAY)) {
13727 VALUE pathobj = path;
13728 if (RARRAY_LEN(pathobj) != 2) {
13729 rb_raise(rb_eRuntimeError, "path object size mismatch");
13730 }
13731 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13732 realpath = RARRAY_AREF(pathobj, 1);
13733 if (!NIL_P(realpath)) {
13734 if (!RB_TYPE_P(realpath, T_STRING)) {
13735 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13736 "(%x), path=%+"PRIsVALUE,
13737 realpath, TYPE(realpath), path);
13738 }
13739 realpath = rb_fstring(realpath);
13740 }
13741 }
13742 else {
13743 rb_raise(rb_eRuntimeError, "unexpected path object");
13744 }
13745 rb_iseq_pathobj_set(iseq, path, realpath);
13746 }
13747
13748 // push dummy frame
13749 rb_execution_context_t *ec = GET_EC();
13750 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13751
13752#undef IBF_BODY_OFFSET
13753
13754 load_body->type = type;
13755 load_body->stack_max = stack_max;
13756 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13757 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13758 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13759 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13760 load_body->param.flags.has_kw = FALSE;
13761 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13762 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13763 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13764 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13765 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13766 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13767 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13768 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13769 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13770 load_body->param.size = param_size;
13771 load_body->param.lead_num = param_lead_num;
13772 load_body->param.opt_num = param_opt_num;
13773 load_body->param.rest_start = param_rest_start;
13774 load_body->param.post_start = param_post_start;
13775 load_body->param.post_num = param_post_num;
13776 load_body->param.block_start = param_block_start;
13777 load_body->local_table_size = local_table_size;
13778 load_body->ci_size = ci_size;
13779 load_body->insns_info.size = insns_info_size;
13780
13781 ISEQ_COVERAGE_SET(iseq, Qnil);
13782 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13783 load_body->variable.flip_count = variable_flip_count;
13784 load_body->variable.script_lines = Qnil;
13785
13786 load_body->location.first_lineno = location_first_lineno;
13787 load_body->location.node_id = location_node_id;
13788 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13789 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13790 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13791 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13792 load_body->builtin_attrs = builtin_attrs;
13793 load_body->prism = prism;
13794
13795 load_body->ivc_size = ivc_size;
13796 load_body->icvarc_size = icvarc_size;
13797 load_body->ise_size = ise_size;
13798 load_body->ic_size = ic_size;
13799
13800 if (ISEQ_IS_SIZE(load_body)) {
13801 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13802 }
13803 else {
13804 load_body->is_entries = NULL;
13805 }
13806 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13807 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13808 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13809 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13810 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13811 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13812 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13813 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13814 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
13815 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13816 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13817 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13818
13819 // This must be done after the local table is loaded.
13820 if (load_body->param.keyword != NULL) {
13821 RUBY_ASSERT(load_body->local_table);
13822 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13823 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13824 }
13825
13826 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13827#if VM_INSN_INFO_TABLE_IMPL == 2
13828 rb_iseq_insns_info_encode_positions(iseq);
13829#endif
13830
13831 rb_iseq_translate_threaded_code(iseq);
13832
13833#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13834 load->current_buffer = &load->global_buffer;
13835#endif
13836
13837 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13838 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13839
13840#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13841 load->current_buffer = saved_buffer;
13842#endif
13843 verify_call_cache(iseq);
13844
13845 RB_GC_GUARD(dummy_frame);
13846 rb_vm_pop_frame_no_int(ec);
13847}
13848
13850{
13851 struct ibf_dump *dump;
13852 VALUE offset_list;
13853};
13854
13855static int
13856ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13857{
13858 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13859 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13860
13861 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13862 rb_ary_push(args->offset_list, UINT2NUM(offset));
13863
13864 return ST_CONTINUE;
13865}
13866
13867static void
13868ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13869{
13870 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13871
13872 struct ibf_dump_iseq_list_arg args;
13873 args.dump = dump;
13874 args.offset_list = offset_list;
13875
13876 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13877
13878 st_index_t i;
13879 st_index_t size = dump->iseq_table->num_entries;
13880 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13881
13882 for (i = 0; i < size; i++) {
13883 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13884 }
13885
13886 ibf_dump_align(dump, sizeof(ibf_offset_t));
13887 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13888 header->iseq_list_size = (unsigned int)size;
13889}
13890
13891#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13892
13893/*
13894 * Binary format
13895 * - ibf_object_header
13896 * - ibf_object_xxx (xxx is type)
13897 */
13898
13900 unsigned int type: 5;
13901 unsigned int special_const: 1;
13902 unsigned int frozen: 1;
13903 unsigned int internal: 1;
13904};
13905
13906enum ibf_object_class_index {
13907 IBF_OBJECT_CLASS_OBJECT,
13908 IBF_OBJECT_CLASS_ARRAY,
13909 IBF_OBJECT_CLASS_STANDARD_ERROR,
13910 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13911 IBF_OBJECT_CLASS_TYPE_ERROR,
13912 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13913};
13914
13916 long srcstr;
13917 char option;
13918};
13919
13921 long len;
13922 long keyval[FLEX_ARY_LEN];
13923};
13924
13926 long class_index;
13927 long len;
13928 long beg;
13929 long end;
13930 int excl;
13931};
13932
13934 ssize_t slen;
13935 BDIGIT digits[FLEX_ARY_LEN];
13936};
13937
13938enum ibf_object_data_type {
13939 IBF_OBJECT_DATA_ENCODING,
13940};
13941
13943 long a, b;
13944};
13945
13947 long str;
13948};
13949
13950#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13951 ((((offset) - 1) / (align) + 1) * (align))
13952#define IBF_OBJBODY(type, offset) (const type *)\
13953 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13954
13955static const void *
13956ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13957{
13958 if (offset >= load->current_buffer->size) {
13959 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13960 }
13961 return load->current_buffer->buff + offset;
13962}
13963
13964NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13965
13966static void
13967ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13968{
13969 char buff[0x100];
13970 rb_raw_obj_info(buff, sizeof(buff), obj);
13971 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13972}
13973
13974NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13975
13976static VALUE
13977ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13978{
13979 rb_raise(rb_eArgError, "unsupported");
13981}
13982
13983static void
13984ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13985{
13986 enum ibf_object_class_index cindex;
13987 if (obj == rb_cObject) {
13988 cindex = IBF_OBJECT_CLASS_OBJECT;
13989 }
13990 else if (obj == rb_cArray) {
13991 cindex = IBF_OBJECT_CLASS_ARRAY;
13992 }
13993 else if (obj == rb_eStandardError) {
13994 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13995 }
13996 else if (obj == rb_eNoMatchingPatternError) {
13997 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13998 }
13999 else if (obj == rb_eTypeError) {
14000 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14001 }
14002 else if (obj == rb_eNoMatchingPatternKeyError) {
14003 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14004 }
14005 else {
14006 rb_obj_info_dump(obj);
14007 rb_p(obj);
14008 rb_bug("unsupported class");
14009 }
14010 ibf_dump_write_small_value(dump, (VALUE)cindex);
14011}
14012
14013static VALUE
14014ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14015{
14016 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14017
14018 switch (cindex) {
14019 case IBF_OBJECT_CLASS_OBJECT:
14020 return rb_cObject;
14021 case IBF_OBJECT_CLASS_ARRAY:
14022 return rb_cArray;
14023 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14024 return rb_eStandardError;
14025 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14027 case IBF_OBJECT_CLASS_TYPE_ERROR:
14028 return rb_eTypeError;
14029 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14031 }
14032
14033 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14034}
14035
14036
14037static void
14038ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14039{
14040 double dbl = RFLOAT_VALUE(obj);
14041 (void)IBF_W(&dbl, double, 1);
14042}
14043
14044static VALUE
14045ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14046{
14047 const double *dblp = IBF_OBJBODY(double, offset);
14048 return DBL2NUM(*dblp);
14049}
14050
14051static void
14052ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14053{
14054 long encindex = (long)rb_enc_get_index(obj);
14055 long len = RSTRING_LEN(obj);
14056 const char *ptr = RSTRING_PTR(obj);
14057
14058 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14059 rb_encoding *enc = rb_enc_from_index((int)encindex);
14060 const char *enc_name = rb_enc_name(enc);
14061 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14062 }
14063
14064 ibf_dump_write_small_value(dump, encindex);
14065 ibf_dump_write_small_value(dump, len);
14066 IBF_WP(ptr, char, len);
14067}
14068
14069static VALUE
14070ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14071{
14072 ibf_offset_t reading_pos = offset;
14073
14074 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14075 const long len = (long)ibf_load_small_value(load, &reading_pos);
14076 const char *ptr = load->current_buffer->buff + reading_pos;
14077
14078 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14079 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14080 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14081 }
14082
14083 VALUE str;
14084 if (header->frozen && !header->internal) {
14085 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14086 }
14087 else {
14088 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14089
14090 if (header->internal) rb_obj_hide(str);
14091 if (header->frozen) str = rb_fstring(str);
14092 }
14093 return str;
14094}
14095
14096static void
14097ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14098{
14099 VALUE srcstr = RREGEXP_SRC(obj);
14100 struct ibf_object_regexp regexp;
14101 regexp.option = (char)rb_reg_options(obj);
14102 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14103
14104 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14105 ibf_dump_write_small_value(dump, regexp.srcstr);
14106}
14107
14108static VALUE
14109ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14110{
14111 struct ibf_object_regexp regexp;
14112 regexp.option = ibf_load_byte(load, &offset);
14113 regexp.srcstr = ibf_load_small_value(load, &offset);
14114
14115 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14116 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14117
14118 if (header->internal) rb_obj_hide(reg);
14119 if (header->frozen) rb_obj_freeze(reg);
14120
14121 return reg;
14122}
14123
14124static void
14125ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14126{
14127 long i, len = RARRAY_LEN(obj);
14128 ibf_dump_write_small_value(dump, len);
14129 for (i=0; i<len; i++) {
14130 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14131 ibf_dump_write_small_value(dump, index);
14132 }
14133}
14134
14135static VALUE
14136ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14137{
14138 ibf_offset_t reading_pos = offset;
14139
14140 const long len = (long)ibf_load_small_value(load, &reading_pos);
14141
14142 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14143 int i;
14144
14145 for (i=0; i<len; i++) {
14146 const VALUE index = ibf_load_small_value(load, &reading_pos);
14147 rb_ary_push(ary, ibf_load_object(load, index));
14148 }
14149
14150 if (header->frozen) rb_ary_freeze(ary);
14151
14152 return ary;
14153}
14154
14155static int
14156ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14157{
14158 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14159
14160 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14161 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14162
14163 ibf_dump_write_small_value(dump, key_index);
14164 ibf_dump_write_small_value(dump, val_index);
14165 return ST_CONTINUE;
14166}
14167
14168static void
14169ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14170{
14171 long len = RHASH_SIZE(obj);
14172 ibf_dump_write_small_value(dump, (VALUE)len);
14173
14174 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14175}
14176
14177static VALUE
14178ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14179{
14180 long len = (long)ibf_load_small_value(load, &offset);
14181 VALUE obj = rb_hash_new_with_size(len);
14182 int i;
14183
14184 for (i = 0; i < len; i++) {
14185 VALUE key_index = ibf_load_small_value(load, &offset);
14186 VALUE val_index = ibf_load_small_value(load, &offset);
14187
14188 VALUE key = ibf_load_object(load, key_index);
14189 VALUE val = ibf_load_object(load, val_index);
14190 rb_hash_aset(obj, key, val);
14191 }
14192 rb_hash_rehash(obj);
14193
14194 if (header->internal) rb_obj_hide(obj);
14195 if (header->frozen) rb_obj_freeze(obj);
14196
14197 return obj;
14198}
14199
14200static void
14201ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14202{
14203 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14204 struct ibf_object_struct_range range;
14205 VALUE beg, end;
14206 IBF_ZERO(range);
14207 range.len = 3;
14208 range.class_index = 0;
14209
14210 rb_range_values(obj, &beg, &end, &range.excl);
14211 range.beg = (long)ibf_dump_object(dump, beg);
14212 range.end = (long)ibf_dump_object(dump, end);
14213
14214 IBF_W_ALIGN(struct ibf_object_struct_range);
14215 IBF_WV(range);
14216 }
14217 else {
14218 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14219 rb_class_name(CLASS_OF(obj)));
14220 }
14221}
14222
14223static VALUE
14224ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14225{
14226 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14227 VALUE beg = ibf_load_object(load, range->beg);
14228 VALUE end = ibf_load_object(load, range->end);
14229 VALUE obj = rb_range_new(beg, end, range->excl);
14230 if (header->internal) rb_obj_hide(obj);
14231 if (header->frozen) rb_obj_freeze(obj);
14232 return obj;
14233}
14234
14235static void
14236ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14237{
14238 ssize_t len = BIGNUM_LEN(obj);
14239 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14240 BDIGIT *d = BIGNUM_DIGITS(obj);
14241
14242 (void)IBF_W(&slen, ssize_t, 1);
14243 IBF_WP(d, BDIGIT, len);
14244}
14245
14246static VALUE
14247ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14248{
14249 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14250 int sign = bignum->slen > 0;
14251 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14252 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14255 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14256 big_unpack_flags |
14257 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14258 if (header->internal) rb_obj_hide(obj);
14259 if (header->frozen) rb_obj_freeze(obj);
14260 return obj;
14261}
14262
14263static void
14264ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14265{
14266 if (rb_data_is_encoding(obj)) {
14267 rb_encoding *enc = rb_to_encoding(obj);
14268 const char *name = rb_enc_name(enc);
14269 long len = strlen(name) + 1;
14270 long data[2];
14271 data[0] = IBF_OBJECT_DATA_ENCODING;
14272 data[1] = len;
14273 (void)IBF_W(data, long, 2);
14274 IBF_WP(name, char, len);
14275 }
14276 else {
14277 ibf_dump_object_unsupported(dump, obj);
14278 }
14279}
14280
14281static VALUE
14282ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14283{
14284 const long *body = IBF_OBJBODY(long, offset);
14285 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14286 /* const long len = body[1]; */
14287 const char *data = (const char *)&body[2];
14288
14289 switch (type) {
14290 case IBF_OBJECT_DATA_ENCODING:
14291 {
14292 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14293 return encobj;
14294 }
14295 }
14296
14297 return ibf_load_object_unsupported(load, header, offset);
14298}
14299
14300static void
14301ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14302{
14303 long data[2];
14304 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14305 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14306
14307 (void)IBF_W(data, long, 2);
14308}
14309
14310static VALUE
14311ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14312{
14313 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14314 VALUE a = ibf_load_object(load, nums->a);
14315 VALUE b = ibf_load_object(load, nums->b);
14316 VALUE obj = header->type == T_COMPLEX ?
14317 rb_complex_new(a, b) : rb_rational_new(a, b);
14318
14319 if (header->internal) rb_obj_hide(obj);
14320 if (header->frozen) rb_obj_freeze(obj);
14321 return obj;
14322}
14323
14324static void
14325ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14326{
14327 ibf_dump_object_string(dump, rb_sym2str(obj));
14328}
14329
14330static VALUE
14331ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14332{
14333 ibf_offset_t reading_pos = offset;
14334
14335 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14336 const long len = (long)ibf_load_small_value(load, &reading_pos);
14337 const char *ptr = load->current_buffer->buff + reading_pos;
14338
14339 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14340 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14341 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14342 }
14343
14344 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14345 return ID2SYM(id);
14346}
14347
14348typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14349static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14350 ibf_dump_object_unsupported, /* T_NONE */
14351 ibf_dump_object_unsupported, /* T_OBJECT */
14352 ibf_dump_object_class, /* T_CLASS */
14353 ibf_dump_object_unsupported, /* T_MODULE */
14354 ibf_dump_object_float, /* T_FLOAT */
14355 ibf_dump_object_string, /* T_STRING */
14356 ibf_dump_object_regexp, /* T_REGEXP */
14357 ibf_dump_object_array, /* T_ARRAY */
14358 ibf_dump_object_hash, /* T_HASH */
14359 ibf_dump_object_struct, /* T_STRUCT */
14360 ibf_dump_object_bignum, /* T_BIGNUM */
14361 ibf_dump_object_unsupported, /* T_FILE */
14362 ibf_dump_object_data, /* T_DATA */
14363 ibf_dump_object_unsupported, /* T_MATCH */
14364 ibf_dump_object_complex_rational, /* T_COMPLEX */
14365 ibf_dump_object_complex_rational, /* T_RATIONAL */
14366 ibf_dump_object_unsupported, /* 0x10 */
14367 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14368 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14369 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14370 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14371 ibf_dump_object_unsupported, /* T_FIXNUM */
14372 ibf_dump_object_unsupported, /* T_UNDEF */
14373 ibf_dump_object_unsupported, /* 0x17 */
14374 ibf_dump_object_unsupported, /* 0x18 */
14375 ibf_dump_object_unsupported, /* 0x19 */
14376 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14377 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14378 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14379 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14380 ibf_dump_object_unsupported, /* 0x1e */
14381 ibf_dump_object_unsupported, /* 0x1f */
14382};
14383
14384static void
14385ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14386{
14387 unsigned char byte =
14388 (header.type << 0) |
14389 (header.special_const << 5) |
14390 (header.frozen << 6) |
14391 (header.internal << 7);
14392
14393 IBF_WV(byte);
14394}
14395
14396static struct ibf_object_header
14397ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14398{
14399 unsigned char byte = ibf_load_byte(load, offset);
14400
14401 struct ibf_object_header header;
14402 header.type = (byte >> 0) & 0x1f;
14403 header.special_const = (byte >> 5) & 0x01;
14404 header.frozen = (byte >> 6) & 0x01;
14405 header.internal = (byte >> 7) & 0x01;
14406
14407 return header;
14408}
14409
14410static ibf_offset_t
14411ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14412{
14413 struct ibf_object_header obj_header;
14414 ibf_offset_t current_offset;
14415 IBF_ZERO(obj_header);
14416 obj_header.type = TYPE(obj);
14417
14418 IBF_W_ALIGN(ibf_offset_t);
14419 current_offset = ibf_dump_pos(dump);
14420
14421 if (SPECIAL_CONST_P(obj) &&
14422 ! (SYMBOL_P(obj) ||
14423 RB_FLOAT_TYPE_P(obj))) {
14424 obj_header.special_const = TRUE;
14425 obj_header.frozen = TRUE;
14426 obj_header.internal = TRUE;
14427 ibf_dump_object_object_header(dump, obj_header);
14428 ibf_dump_write_small_value(dump, obj);
14429 }
14430 else {
14431 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14432 obj_header.special_const = FALSE;
14433 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14434 ibf_dump_object_object_header(dump, obj_header);
14435 (*dump_object_functions[obj_header.type])(dump, obj);
14436 }
14437
14438 return current_offset;
14439}
14440
14441typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14442static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14443 ibf_load_object_unsupported, /* T_NONE */
14444 ibf_load_object_unsupported, /* T_OBJECT */
14445 ibf_load_object_class, /* T_CLASS */
14446 ibf_load_object_unsupported, /* T_MODULE */
14447 ibf_load_object_float, /* T_FLOAT */
14448 ibf_load_object_string, /* T_STRING */
14449 ibf_load_object_regexp, /* T_REGEXP */
14450 ibf_load_object_array, /* T_ARRAY */
14451 ibf_load_object_hash, /* T_HASH */
14452 ibf_load_object_struct, /* T_STRUCT */
14453 ibf_load_object_bignum, /* T_BIGNUM */
14454 ibf_load_object_unsupported, /* T_FILE */
14455 ibf_load_object_data, /* T_DATA */
14456 ibf_load_object_unsupported, /* T_MATCH */
14457 ibf_load_object_complex_rational, /* T_COMPLEX */
14458 ibf_load_object_complex_rational, /* T_RATIONAL */
14459 ibf_load_object_unsupported, /* 0x10 */
14460 ibf_load_object_unsupported, /* T_NIL */
14461 ibf_load_object_unsupported, /* T_TRUE */
14462 ibf_load_object_unsupported, /* T_FALSE */
14463 ibf_load_object_symbol,
14464 ibf_load_object_unsupported, /* T_FIXNUM */
14465 ibf_load_object_unsupported, /* T_UNDEF */
14466 ibf_load_object_unsupported, /* 0x17 */
14467 ibf_load_object_unsupported, /* 0x18 */
14468 ibf_load_object_unsupported, /* 0x19 */
14469 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14470 ibf_load_object_unsupported, /* T_NODE 0x1b */
14471 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14472 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14473 ibf_load_object_unsupported, /* 0x1e */
14474 ibf_load_object_unsupported, /* 0x1f */
14475};
14476
14477static VALUE
14478ibf_load_object(const struct ibf_load *load, VALUE object_index)
14479{
14480 if (object_index == 0) {
14481 return Qnil;
14482 }
14483 else {
14484 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14485 if (!obj) {
14486 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14487 ibf_offset_t offset = offsets[object_index];
14488 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14489
14490#if IBF_ISEQ_DEBUG
14491 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14492 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14493 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14494 header.type, header.special_const, header.frozen, header.internal);
14495#endif
14496 if (offset >= load->current_buffer->size) {
14497 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14498 }
14499
14500 if (header.special_const) {
14501 ibf_offset_t reading_pos = offset;
14502
14503 obj = ibf_load_small_value(load, &reading_pos);
14504 }
14505 else {
14506 obj = (*load_object_functions[header.type])(load, &header, offset);
14507 }
14508
14509 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14510 }
14511#if IBF_ISEQ_DEBUG
14512 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14513 object_index, obj);
14514#endif
14515 return obj;
14516 }
14517}
14518
14520{
14521 struct ibf_dump *dump;
14522 VALUE offset_list;
14523};
14524
14525static int
14526ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14527{
14528 VALUE obj = (VALUE)key;
14529 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14530
14531 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14532 rb_ary_push(args->offset_list, UINT2NUM(offset));
14533
14534 return ST_CONTINUE;
14535}
14536
14537static void
14538ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14539{
14540 st_table *obj_table = dump->current_buffer->obj_table;
14541 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14542
14543 struct ibf_dump_object_list_arg args;
14544 args.dump = dump;
14545 args.offset_list = offset_list;
14546
14547 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14548
14549 IBF_W_ALIGN(ibf_offset_t);
14550 *obj_list_offset = ibf_dump_pos(dump);
14551
14552 st_index_t size = obj_table->num_entries;
14553 st_index_t i;
14554
14555 for (i=0; i<size; i++) {
14556 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14557 IBF_WV(offset);
14558 }
14559
14560 *obj_list_size = (unsigned int)size;
14561}
14562
14563static void
14564ibf_dump_mark(void *ptr)
14565{
14566 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14567 rb_gc_mark(dump->global_buffer.str);
14568
14569 rb_mark_set(dump->global_buffer.obj_table);
14570 rb_mark_set(dump->iseq_table);
14571}
14572
14573static void
14574ibf_dump_free(void *ptr)
14575{
14576 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14577 if (dump->global_buffer.obj_table) {
14578 st_free_table(dump->global_buffer.obj_table);
14579 dump->global_buffer.obj_table = 0;
14580 }
14581 if (dump->iseq_table) {
14582 st_free_table(dump->iseq_table);
14583 dump->iseq_table = 0;
14584 }
14585}
14586
14587static size_t
14588ibf_dump_memsize(const void *ptr)
14589{
14590 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14591 size_t size = 0;
14592 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14593 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14594 return size;
14595}
14596
14597static const rb_data_type_t ibf_dump_type = {
14598 "ibf_dump",
14599 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14600 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14601};
14602
14603static void
14604ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14605{
14606 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14607 dump->iseq_table = NULL;
14608
14609 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14610 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14611 dump->iseq_table = st_init_numtable(); /* need free */
14612
14613 dump->current_buffer = &dump->global_buffer;
14614}
14615
14616VALUE
14617rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14618{
14619 struct ibf_dump *dump;
14620 struct ibf_header header = {{0}};
14621 VALUE dump_obj;
14622 VALUE str;
14623
14624 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14625 ISEQ_BODY(iseq)->local_iseq != iseq) {
14626 rb_raise(rb_eRuntimeError, "should be top of iseq");
14627 }
14628 if (RTEST(ISEQ_COVERAGE(iseq))) {
14629 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14630 }
14631
14632 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14633 ibf_dump_setup(dump, dump_obj);
14634
14635 ibf_dump_write(dump, &header, sizeof(header));
14636 ibf_dump_iseq(dump, iseq);
14637
14638 header.magic[0] = 'Y'; /* YARB */
14639 header.magic[1] = 'A';
14640 header.magic[2] = 'R';
14641 header.magic[3] = 'B';
14642 header.major_version = IBF_MAJOR_VERSION;
14643 header.minor_version = IBF_MINOR_VERSION;
14644 header.endian = IBF_ENDIAN_MARK;
14645 header.wordsize = (uint8_t)SIZEOF_VALUE;
14646 ibf_dump_iseq_list(dump, &header);
14647 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14648 header.size = ibf_dump_pos(dump);
14649
14650 if (RTEST(opt)) {
14651 VALUE opt_str = opt;
14652 const char *ptr = StringValuePtr(opt_str);
14653 header.extra_size = RSTRING_LENINT(opt_str);
14654 ibf_dump_write(dump, ptr, header.extra_size);
14655 }
14656 else {
14657 header.extra_size = 0;
14658 }
14659
14660 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14661
14662 str = dump->global_buffer.str;
14663 RB_GC_GUARD(dump_obj);
14664 return str;
14665}
14666
14667static const ibf_offset_t *
14668ibf_iseq_list(const struct ibf_load *load)
14669{
14670 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14671}
14672
14673void
14674rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14675{
14676 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14677 rb_iseq_t *prev_src_iseq = load->iseq;
14678 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14679 load->iseq = iseq;
14680#if IBF_ISEQ_DEBUG
14681 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14682 iseq->aux.loader.index, offset,
14683 load->header->size);
14684#endif
14685 ibf_load_iseq_each(load, iseq, offset);
14686 ISEQ_COMPILE_DATA_CLEAR(iseq);
14687 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14688 rb_iseq_init_trace(iseq);
14689 load->iseq = prev_src_iseq;
14690}
14691
14692#if USE_LAZY_LOAD
14693const rb_iseq_t *
14694rb_iseq_complete(const rb_iseq_t *iseq)
14695{
14696 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14697 return iseq;
14698}
14699#endif
14700
14701static rb_iseq_t *
14702ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14703{
14704 int iseq_index = (int)(VALUE)index_iseq;
14705
14706#if IBF_ISEQ_DEBUG
14707 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14708 (void *)index_iseq, (void *)load->iseq_list);
14709#endif
14710 if (iseq_index == -1) {
14711 return NULL;
14712 }
14713 else {
14714 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14715
14716#if IBF_ISEQ_DEBUG
14717 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14718#endif
14719 if (iseqv) {
14720 return (rb_iseq_t *)iseqv;
14721 }
14722 else {
14723 rb_iseq_t *iseq = iseq_imemo_alloc();
14724#if IBF_ISEQ_DEBUG
14725 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14726#endif
14727 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14728 iseq->aux.loader.obj = load->loader_obj;
14729 iseq->aux.loader.index = iseq_index;
14730#if IBF_ISEQ_DEBUG
14731 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14732 (void *)iseq, (void *)load->loader_obj, iseq_index);
14733#endif
14734 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14735
14736 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14737#if IBF_ISEQ_DEBUG
14738 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14739#endif
14740 rb_ibf_load_iseq_complete(iseq);
14741 }
14742
14743#if IBF_ISEQ_DEBUG
14744 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14745 (void *)iseq, (void *)load->iseq);
14746#endif
14747 return iseq;
14748 }
14749 }
14750}
14751
14752static void
14753ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14754{
14755 struct ibf_header *header = (struct ibf_header *)bytes;
14756 load->loader_obj = loader_obj;
14757 load->global_buffer.buff = bytes;
14758 load->header = header;
14759 load->global_buffer.size = header->size;
14760 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14761 load->global_buffer.obj_list_size = header->global_object_list_size;
14762 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14763 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14764 load->iseq = NULL;
14765
14766 load->current_buffer = &load->global_buffer;
14767
14768 if (size < header->size) {
14769 rb_raise(rb_eRuntimeError, "broken binary format");
14770 }
14771 if (strncmp(header->magic, "YARB", 4) != 0) {
14772 rb_raise(rb_eRuntimeError, "unknown binary format");
14773 }
14774 if (header->major_version != IBF_MAJOR_VERSION ||
14775 header->minor_version != IBF_MINOR_VERSION) {
14776 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14777 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14778 }
14779 if (header->endian != IBF_ENDIAN_MARK) {
14780 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14781 }
14782 if (header->wordsize != SIZEOF_VALUE) {
14783 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14784 }
14785 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14786 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14787 header->iseq_list_offset);
14788 }
14789 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14790 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14791 load->global_buffer.obj_list_offset);
14792 }
14793}
14794
14795static void
14796ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14797{
14798 StringValue(str);
14799
14800 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14801 rb_raise(rb_eRuntimeError, "broken binary format");
14802 }
14803
14804 if (USE_LAZY_LOAD) {
14805 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14806 }
14807
14808 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14809 RB_OBJ_WRITE(loader_obj, &load->str, str);
14810}
14811
14812static void
14813ibf_loader_mark(void *ptr)
14814{
14815 struct ibf_load *load = (struct ibf_load *)ptr;
14816 rb_gc_mark(load->str);
14817 rb_gc_mark(load->iseq_list);
14818 rb_gc_mark(load->global_buffer.obj_list);
14819}
14820
14821static void
14822ibf_loader_free(void *ptr)
14823{
14824 struct ibf_load *load = (struct ibf_load *)ptr;
14825 ruby_xfree(load);
14826}
14827
14828static size_t
14829ibf_loader_memsize(const void *ptr)
14830{
14831 return sizeof(struct ibf_load);
14832}
14833
14834static const rb_data_type_t ibf_load_type = {
14835 "ibf_loader",
14836 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14837 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14838};
14839
14840const rb_iseq_t *
14841rb_iseq_ibf_load(VALUE str)
14842{
14843 struct ibf_load *load;
14844 rb_iseq_t *iseq;
14845 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14846
14847 ibf_load_setup(load, loader_obj, str);
14848 iseq = ibf_load_iseq(load, 0);
14849
14850 RB_GC_GUARD(loader_obj);
14851 return iseq;
14852}
14853
14854const rb_iseq_t *
14855rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14856{
14857 struct ibf_load *load;
14858 rb_iseq_t *iseq;
14859 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14860
14861 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14862 iseq = ibf_load_iseq(load, 0);
14863
14864 RB_GC_GUARD(loader_obj);
14865 return iseq;
14866}
14867
14868VALUE
14869rb_iseq_ibf_load_extra_data(VALUE str)
14870{
14871 struct ibf_load *load;
14872 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14873 VALUE extra_str;
14874
14875 ibf_load_setup(load, loader_obj, str);
14876 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14877 RB_GC_GUARD(loader_obj);
14878 return extra_str;
14879}
14880
14881#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:135
#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:203
#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:129
#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:131
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:67
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:133
#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:689
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:113
VALUE rb_cArray
Array class.
Definition array.c:41
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:104
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:680
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:865
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1284
#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
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c: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:4068
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:2049
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4437
#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:4423
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3836
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:4034
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4493
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:4310
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3566
#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:492
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:967
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:986
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:933
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:3101
#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:150
#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:449
#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:9051
#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:29
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:285
Definition vm_core.h:288
Definition iseq.h:251
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:207
struct rb_iseq_constant_body::@155 param
parameter information
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145