Ruby 3.5.0dev (2025-06-27 revision fe9a3be2966b0e54b93e9349bf47d4e5b879a6e1)
compile.c (fe9a3be2966b0e54b93e9349bf47d4e5b879a6e1)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497
498static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
499static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
500
501/*
502 * To make Array to LinkedList, use link_anchor
503 */
504
505static void
506verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
507{
508#if CPDEBUG
509 int flag = 0;
510 LINK_ELEMENT *list, *plist;
511
512 if (!compile_debug) return;
513
514 list = anchor->anchor.next;
515 plist = &anchor->anchor;
516 while (list) {
517 if (plist != list->prev) {
518 flag += 1;
519 }
520 plist = list;
521 list = list->next;
522 }
523
524 if (anchor->last != plist && anchor->last != 0) {
525 flag |= 0x70000;
526 }
527
528 if (flag != 0) {
529 rb_bug("list verify error: %08x (%s)", flag, info);
530 }
531#endif
532}
533#if CPDEBUG < 0
534#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
535#endif
536
537static void
538verify_call_cache(rb_iseq_t *iseq)
539{
540#if CPDEBUG
541 VALUE *original = rb_iseq_original_iseq(iseq);
542 size_t i = 0;
543 while (i < ISEQ_BODY(iseq)->iseq_size) {
544 VALUE insn = original[i];
545 const char *types = insn_op_types(insn);
546
547 for (int j=0; types[j]; j++) {
548 if (types[j] == TS_CALLDATA) {
549 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
550 const struct rb_callinfo *ci = cd->ci;
551 const struct rb_callcache *cc = cd->cc;
552 if (cc != vm_cc_empty()) {
553 vm_ci_dump(ci);
554 rb_bug("call cache is not initialized by vm_cc_empty()");
555 }
556 }
557 }
558 i += insn_len(insn);
559 }
560
561 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
562 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
563 const struct rb_callinfo *ci = cd->ci;
564 const struct rb_callcache *cc = cd->cc;
565 if (cc != NULL && cc != vm_cc_empty()) {
566 vm_ci_dump(ci);
567 rb_bug("call cache is not initialized by vm_cc_empty()");
568 }
569 }
570#endif
571}
572
573/*
574 * elem1, elem2 => elem1, elem2, elem
575 */
576static void
577ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
578{
579 elem->prev = anchor->last;
580 anchor->last->next = elem;
581 anchor->last = elem;
582 verify_list("add", anchor);
583}
584
585/*
586 * elem1, before, elem2 => elem1, before, elem, elem2
587 */
588static void
589APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
590{
591 elem->prev = before;
592 elem->next = before->next;
593 elem->next->prev = elem;
594 before->next = elem;
595 if (before == anchor->last) anchor->last = elem;
596 verify_list("add", anchor);
597}
598#if CPDEBUG < 0
599#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
600#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
601#endif
602
603static int
604branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
605{
606 if (!ISEQ_COVERAGE(iseq)) return 0;
607 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
608 if (first_line <= 0) return 0;
609 return 1;
610}
611
612#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
613
614static VALUE
615setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
616{
617 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
618 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
619 VALUE branch = rb_ary_hidden_new(6);
620
621 rb_hash_aset(structure, key, branch);
622 rb_ary_push(branch, ID2SYM(rb_intern(type)));
623 rb_ary_push(branch, INT2FIX(first_lineno));
624 rb_ary_push(branch, INT2FIX(first_column));
625 rb_ary_push(branch, INT2FIX(last_lineno));
626 rb_ary_push(branch, INT2FIX(last_column));
627 return branch;
628}
629
630static VALUE
631decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
632{
633 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
634
635 /*
636 * if !structure[node]
637 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
638 * else
639 * branches = structure[node][5]
640 * end
641 */
642
643 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
644 VALUE branch_base = rb_hash_aref(structure, key);
645 VALUE branches;
646
647 if (NIL_P(branch_base)) {
648 branch_base = setup_branch(loc, type, structure, key);
649 branches = rb_hash_new();
650 rb_obj_hide(branches);
651 rb_ary_push(branch_base, branches);
652 }
653 else {
654 branches = RARRAY_AREF(branch_base, 5);
655 }
656
657 return branches;
658}
659
660static NODE
661generate_dummy_line_node(int lineno, int node_id)
662{
663 NODE dummy = { 0 };
664 nd_set_line(&dummy, lineno);
665 nd_set_node_id(&dummy, node_id);
666 return dummy;
667}
668
669static void
670add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
671{
672 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
673
674 /*
675 * if !branches[branch_id]
676 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
677 * else
678 * counter_idx= branches[branch_id][5]
679 * end
680 */
681
682 VALUE key = INT2FIX(branch_id);
683 VALUE branch = rb_hash_aref(branches, key);
684 long counter_idx;
685
686 if (NIL_P(branch)) {
687 branch = setup_branch(loc, type, branches, key);
688 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
689 counter_idx = RARRAY_LEN(counters);
690 rb_ary_push(branch, LONG2FIX(counter_idx));
691 rb_ary_push(counters, INT2FIX(0));
692 }
693 else {
694 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
695 }
696
697 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
698 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
699}
700
701#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
702
703static int
704validate_label(st_data_t name, st_data_t label, st_data_t arg)
705{
706 rb_iseq_t *iseq = (rb_iseq_t *)arg;
707 LABEL *lobj = (LABEL *)label;
708 if (!lobj->link.next) {
709 do {
710 COMPILE_ERROR(iseq, lobj->position,
711 "%"PRIsVALUE": undefined label",
712 rb_sym2str((VALUE)name));
713 } while (0);
714 }
715 return ST_CONTINUE;
716}
717
718static void
719validate_labels(rb_iseq_t *iseq, st_table *labels_table)
720{
721 st_foreach(labels_table, validate_label, (st_data_t)iseq);
722 st_free_table(labels_table);
723}
724
725static NODE *
726get_nd_recv(const NODE *node)
727{
728 switch (nd_type(node)) {
729 case NODE_CALL:
730 return RNODE_CALL(node)->nd_recv;
731 case NODE_OPCALL:
732 return RNODE_OPCALL(node)->nd_recv;
733 case NODE_FCALL:
734 return 0;
735 case NODE_QCALL:
736 return RNODE_QCALL(node)->nd_recv;
737 case NODE_VCALL:
738 return 0;
739 case NODE_ATTRASGN:
740 return RNODE_ATTRASGN(node)->nd_recv;
741 case NODE_OP_ASGN1:
742 return RNODE_OP_ASGN1(node)->nd_recv;
743 case NODE_OP_ASGN2:
744 return RNODE_OP_ASGN2(node)->nd_recv;
745 default:
746 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
747 }
748}
749
750static ID
751get_node_call_nd_mid(const NODE *node)
752{
753 switch (nd_type(node)) {
754 case NODE_CALL:
755 return RNODE_CALL(node)->nd_mid;
756 case NODE_OPCALL:
757 return RNODE_OPCALL(node)->nd_mid;
758 case NODE_FCALL:
759 return RNODE_FCALL(node)->nd_mid;
760 case NODE_QCALL:
761 return RNODE_QCALL(node)->nd_mid;
762 case NODE_VCALL:
763 return RNODE_VCALL(node)->nd_mid;
764 case NODE_ATTRASGN:
765 return RNODE_ATTRASGN(node)->nd_mid;
766 default:
767 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
768 }
769}
770
771static NODE *
772get_nd_args(const NODE *node)
773{
774 switch (nd_type(node)) {
775 case NODE_CALL:
776 return RNODE_CALL(node)->nd_args;
777 case NODE_OPCALL:
778 return RNODE_OPCALL(node)->nd_args;
779 case NODE_FCALL:
780 return RNODE_FCALL(node)->nd_args;
781 case NODE_QCALL:
782 return RNODE_QCALL(node)->nd_args;
783 case NODE_VCALL:
784 return 0;
785 case NODE_ATTRASGN:
786 return RNODE_ATTRASGN(node)->nd_args;
787 default:
788 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
789 }
790}
791
792static ID
793get_node_colon_nd_mid(const NODE *node)
794{
795 switch (nd_type(node)) {
796 case NODE_COLON2:
797 return RNODE_COLON2(node)->nd_mid;
798 case NODE_COLON3:
799 return RNODE_COLON3(node)->nd_mid;
800 default:
801 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
802 }
803}
804
805static ID
806get_nd_vid(const NODE *node)
807{
808 switch (nd_type(node)) {
809 case NODE_LASGN:
810 return RNODE_LASGN(node)->nd_vid;
811 case NODE_DASGN:
812 return RNODE_DASGN(node)->nd_vid;
813 case NODE_IASGN:
814 return RNODE_IASGN(node)->nd_vid;
815 case NODE_CVASGN:
816 return RNODE_CVASGN(node)->nd_vid;
817 default:
818 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
819 }
820}
821
822static NODE *
823get_nd_value(const NODE *node)
824{
825 switch (nd_type(node)) {
826 case NODE_LASGN:
827 return RNODE_LASGN(node)->nd_value;
828 case NODE_DASGN:
829 return RNODE_DASGN(node)->nd_value;
830 default:
831 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
832 }
833}
834
835static VALUE
836get_string_value(const NODE *node)
837{
838 switch (nd_type(node)) {
839 case NODE_STR:
840 return rb_node_str_string_val(node);
841 case NODE_FILE:
842 return rb_node_file_path_val(node);
843 default:
844 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
845 }
846}
847
848VALUE
849rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
850{
851 DECL_ANCHOR(ret);
852 INIT_ANCHOR(ret);
853
854 (*ifunc->func)(iseq, ret, ifunc->data);
855
856 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
857
858 CHECK(iseq_setup_insn(iseq, ret));
859 return iseq_setup(iseq, ret);
860}
861
862static bool drop_unreachable_return(LINK_ANCHOR *ret);
863
864VALUE
865rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
866{
867 DECL_ANCHOR(ret);
868 INIT_ANCHOR(ret);
869
870 if (node == 0) {
871 NO_CHECK(COMPILE(ret, "nil", node));
872 iseq_set_local_table(iseq, 0, 0);
873 }
874 /* assume node is T_NODE */
875 else if (nd_type_p(node, NODE_SCOPE)) {
876 /* iseq type of top, method, class, block */
877 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(&OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1401}
1402
1403static INSN *
1404new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1405{
1406 INSN *iobj = compile_data_alloc_insn(iseq);
1407
1408 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1409
1410 iobj->link.type = ISEQ_ELEMENT_INSN;
1411 iobj->link.next = 0;
1412 iobj->insn_id = insn_id;
1413 iobj->insn_info.line_no = line_no;
1414 iobj->insn_info.node_id = node_id;
1415 iobj->insn_info.events = 0;
1416 iobj->operands = argv;
1417 iobj->operand_size = argc;
1418 iobj->sc_state = 0;
1419
1420 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1421
1422 return iobj;
1423}
1424
1425static INSN *
1426new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1427{
1428 VALUE *operands = 0;
1429 va_list argv;
1430 if (argc > 0) {
1431 int i;
1432 va_start(argv, argc);
1433 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1434 for (i = 0; i < argc; i++) {
1435 VALUE v = va_arg(argv, VALUE);
1436 operands[i] = v;
1437 }
1438 va_end(argv);
1439 }
1440 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1441}
1442
1443static const struct rb_callinfo *
1444new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1445{
1446 VM_ASSERT(argc >= 0);
1447
1448 if (kw_arg) {
1449 flag |= VM_CALL_KWARG;
1450 argc += kw_arg->keyword_len;
1451 }
1452
1453 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1454 && !has_blockiseq) {
1455 flag |= VM_CALL_ARGS_SIMPLE;
1456 }
1457
1458 ISEQ_BODY(iseq)->ci_size++;
1459 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1460 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1461 return ci;
1462}
1463
1464static INSN *
1465new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1466{
1467 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1468 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1469 operands[0] = ci;
1470 operands[1] = (VALUE)blockiseq;
1471 if (blockiseq) {
1472 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1473 }
1474
1475 INSN *insn;
1476
1477 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1478 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1479 }
1480 else {
1481 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1482 }
1483
1484 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1485 RB_GC_GUARD(ci);
1486 return insn;
1487}
1488
1489static rb_iseq_t *
1490new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1491 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1492{
1493 rb_iseq_t *ret_iseq;
1494 VALUE ast_value = rb_ruby_ast_new(node);
1495
1496 debugs("[new_child_iseq]> ---------------------------------------\n");
1497 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1498 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1499 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1500 line_no, parent,
1501 isolated_depth ? isolated_depth + 1 : 0,
1502 type, ISEQ_COMPILE_DATA(iseq)->option,
1503 ISEQ_BODY(iseq)->variable.script_lines);
1504 debugs("[new_child_iseq]< ---------------------------------------\n");
1505 return ret_iseq;
1506}
1507
1508static rb_iseq_t *
1509new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1510 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1511{
1512 rb_iseq_t *ret_iseq;
1513
1514 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1515 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1516 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1517 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1518 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1519 return ret_iseq;
1520}
1521
1522static void
1523set_catch_except_p(rb_iseq_t *iseq)
1524{
1525 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1526 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1527 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1528 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1529 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1530 }
1531 }
1532}
1533
1534/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1535 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1536 if catch table exists. But we want to optimize while loop, which always has catch
1537 table entries for break/next/redo.
1538
1539 So this function sets true for limited ISeqs with break/next/redo catch table entries
1540 whose child ISeq would really raise an exception. */
1541static void
1542update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1543{
1544 unsigned int pos;
1545 size_t i;
1546 int insn;
1547 const struct iseq_catch_table *ct = body->catch_table;
1548
1549 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1550 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1551 pos = 0;
1552 while (pos < body->iseq_size) {
1553 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1554 if (insn == BIN(throw)) {
1555 set_catch_except_p(iseq);
1556 break;
1557 }
1558 pos += insn_len(insn);
1559 }
1560
1561 if (ct == NULL)
1562 return;
1563
1564 for (i = 0; i < ct->size; i++) {
1565 const struct iseq_catch_table_entry *entry =
1566 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1567 if (entry->type != CATCH_TYPE_BREAK
1568 && entry->type != CATCH_TYPE_NEXT
1569 && entry->type != CATCH_TYPE_REDO) {
1570 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1571 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1572 break;
1573 }
1574 }
1575}
1576
1577static void
1578iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1579{
1580 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1581 if (NIL_P(catch_table_ary)) return;
1582 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1583 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1584 for (i = 0; i < tlen; i++) {
1585 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1586 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1587 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1588 LINK_ELEMENT *e;
1589
1590 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1591
1592 if (ct != CATCH_TYPE_BREAK
1593 && ct != CATCH_TYPE_NEXT
1594 && ct != CATCH_TYPE_REDO) {
1595
1596 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1597 if (e == cont) {
1598 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1599 ELEM_INSERT_NEXT(end, &nop->link);
1600 break;
1601 }
1602 }
1603 }
1604 }
1605
1606 RB_GC_GUARD(catch_table_ary);
1607}
1608
1609static int
1610iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1611{
1612 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1613 return COMPILE_NG;
1614
1615 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1616
1617 if (compile_debug > 5)
1618 dump_disasm_list(FIRST_ELEMENT(anchor));
1619
1620 debugs("[compile step 3.1 (iseq_optimize)]\n");
1621 iseq_optimize(iseq, anchor);
1622
1623 if (compile_debug > 5)
1624 dump_disasm_list(FIRST_ELEMENT(anchor));
1625
1626 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1627 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1628 iseq_insns_unification(iseq, anchor);
1629 if (compile_debug > 5)
1630 dump_disasm_list(FIRST_ELEMENT(anchor));
1631 }
1632
1633 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1634 iseq_insert_nop_between_end_and_cont(iseq);
1635 if (compile_debug > 5)
1636 dump_disasm_list(FIRST_ELEMENT(anchor));
1637
1638 return COMPILE_OK;
1639}
1640
1641static int
1642iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1643{
1644 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1645 return COMPILE_NG;
1646
1647 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1648 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1649 if (compile_debug > 5)
1650 dump_disasm_list(FIRST_ELEMENT(anchor));
1651
1652 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1653 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1654
1655 debugs("[compile step 4.3 (set_optargs_table)] \n");
1656 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1657
1658 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1659 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1660
1661 debugs("[compile step 6 (update_catch_except_flags)] \n");
1662 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1663 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1664
1665 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1666 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1667 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1668 xfree(ISEQ_BODY(iseq)->catch_table);
1669 ISEQ_BODY(iseq)->catch_table = NULL;
1670 }
1671
1672#if VM_INSN_INFO_TABLE_IMPL == 2
1673 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1674 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1675 rb_iseq_insns_info_encode_positions(iseq);
1676 }
1677#endif
1678
1679 if (compile_debug > 1) {
1680 VALUE str = rb_iseq_disasm(iseq);
1681 printf("%s\n", StringValueCStr(str));
1682 }
1683 verify_call_cache(iseq);
1684 debugs("[compile step: finish]\n");
1685
1686 return COMPILE_OK;
1687}
1688
1689static int
1690iseq_set_exception_local_table(rb_iseq_t *iseq)
1691{
1692 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1693 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1694 return COMPILE_OK;
1695}
1696
1697static int
1698get_lvar_level(const rb_iseq_t *iseq)
1699{
1700 int lev = 0;
1701 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1702 lev++;
1703 iseq = ISEQ_BODY(iseq)->parent_iseq;
1704 }
1705 return lev;
1706}
1707
1708static int
1709get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1710{
1711 unsigned int i;
1712
1713 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1714 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1715 return (int)i;
1716 }
1717 }
1718 return -1;
1719}
1720
1721static int
1722get_local_var_idx(const rb_iseq_t *iseq, ID id)
1723{
1724 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1725
1726 if (idx < 0) {
1727 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1728 "get_local_var_idx: %d", idx);
1729 }
1730
1731 return idx;
1732}
1733
1734static int
1735get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1736{
1737 int lv = 0, idx = -1;
1738 const rb_iseq_t *const topmost_iseq = iseq;
1739
1740 while (iseq) {
1741 idx = get_dyna_var_idx_at_raw(iseq, id);
1742 if (idx >= 0) {
1743 break;
1744 }
1745 iseq = ISEQ_BODY(iseq)->parent_iseq;
1746 lv++;
1747 }
1748
1749 if (idx < 0) {
1750 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1751 "get_dyna_var_idx: -1");
1752 }
1753
1754 *level = lv;
1755 *ls = ISEQ_BODY(iseq)->local_table_size;
1756 return idx;
1757}
1758
1759static int
1760iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1761{
1762 const struct rb_iseq_constant_body *body;
1763 while (level > 0) {
1764 iseq = ISEQ_BODY(iseq)->parent_iseq;
1765 level--;
1766 }
1767 body = ISEQ_BODY(iseq);
1768 if (body->local_iseq == iseq && /* local variables */
1769 body->param.flags.has_block &&
1770 body->local_table_size - body->param.block_start == idx) {
1771 return TRUE;
1772 }
1773 else {
1774 return FALSE;
1775 }
1776}
1777
1778static int
1779iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1780{
1781 int level, ls;
1782 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1783 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1784 *pidx = ls - idx;
1785 *plevel = level;
1786 return TRUE;
1787 }
1788 else {
1789 return FALSE;
1790 }
1791}
1792
1793static void
1794access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1795{
1796 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1797
1798 if (isolated_depth && level >= isolated_depth) {
1799 if (id == rb_intern("yield")) {
1800 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1801 }
1802 else {
1803 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1804 }
1805 }
1806
1807 for (int i=0; i<level; i++) {
1808 VALUE val;
1809 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1810
1811 if (!ovs) {
1812 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1813 }
1814
1815 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1816 if (write && !val) {
1817 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1818 }
1819 }
1820 else {
1821 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1822 }
1823
1824 iseq = ISEQ_BODY(iseq)->parent_iseq;
1825 }
1826}
1827
1828static ID
1829iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1830{
1831 for (int i=0; i<level; i++) {
1832 iseq = ISEQ_BODY(iseq)->parent_iseq;
1833 }
1834
1835 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1836 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1837 return id;
1838}
1839
1840static void
1841iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1842{
1843 if (iseq_local_block_param_p(iseq, idx, level)) {
1844 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1845 }
1846 else {
1847 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1848 }
1849 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1850}
1851
1852static void
1853iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1854{
1855 if (iseq_local_block_param_p(iseq, idx, level)) {
1856 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1857 }
1858 else {
1859 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1860 }
1861 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1862}
1863
1864
1865
1866static void
1867iseq_calc_param_size(rb_iseq_t *iseq)
1868{
1869 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1870 if (body->param.flags.has_opt ||
1871 body->param.flags.has_post ||
1872 body->param.flags.has_rest ||
1873 body->param.flags.has_block ||
1874 body->param.flags.has_kw ||
1875 body->param.flags.has_kwrest) {
1876
1877 if (body->param.flags.has_block) {
1878 body->param.size = body->param.block_start + 1;
1879 }
1880 else if (body->param.flags.has_kwrest) {
1881 body->param.size = body->param.keyword->rest_start + 1;
1882 }
1883 else if (body->param.flags.has_kw) {
1884 body->param.size = body->param.keyword->bits_start + 1;
1885 }
1886 else if (body->param.flags.has_post) {
1887 body->param.size = body->param.post_start + body->param.post_num;
1888 }
1889 else if (body->param.flags.has_rest) {
1890 body->param.size = body->param.rest_start + 1;
1891 }
1892 else if (body->param.flags.has_opt) {
1893 body->param.size = body->param.lead_num + body->param.opt_num;
1894 }
1895 else {
1897 }
1898 }
1899 else {
1900 body->param.size = body->param.lead_num;
1901 }
1902}
1903
1904static int
1905iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1906 const struct rb_args_info *args, int arg_size)
1907{
1908 const rb_node_kw_arg_t *node = args->kw_args;
1909 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1910 struct rb_iseq_param_keyword *keyword;
1911 const VALUE default_values = rb_ary_hidden_new(1);
1912 const VALUE complex_mark = rb_str_tmp_new(0);
1913 int kw = 0, rkw = 0, di = 0, i;
1914
1915 body->param.flags.has_kw = TRUE;
1916 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1917
1918 while (node) {
1919 kw++;
1920 node = node->nd_next;
1921 }
1922 arg_size += kw;
1923 keyword->bits_start = arg_size++;
1924
1925 node = args->kw_args;
1926 while (node) {
1927 const NODE *val_node = get_nd_value(node->nd_body);
1928 VALUE dv;
1929
1930 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1931 ++rkw;
1932 }
1933 else {
1934 switch (nd_type(val_node)) {
1935 case NODE_SYM:
1936 dv = rb_node_sym_string_val(val_node);
1937 break;
1938 case NODE_REGX:
1939 dv = rb_node_regx_string_val(val_node);
1940 break;
1941 case NODE_LINE:
1942 dv = rb_node_line_lineno_val(val_node);
1943 break;
1944 case NODE_INTEGER:
1945 dv = rb_node_integer_literal_val(val_node);
1946 break;
1947 case NODE_FLOAT:
1948 dv = rb_node_float_literal_val(val_node);
1949 break;
1950 case NODE_RATIONAL:
1951 dv = rb_node_rational_literal_val(val_node);
1952 break;
1953 case NODE_IMAGINARY:
1954 dv = rb_node_imaginary_literal_val(val_node);
1955 break;
1956 case NODE_ENCODING:
1957 dv = rb_node_encoding_val(val_node);
1958 break;
1959 case NODE_NIL:
1960 dv = Qnil;
1961 break;
1962 case NODE_TRUE:
1963 dv = Qtrue;
1964 break;
1965 case NODE_FALSE:
1966 dv = Qfalse;
1967 break;
1968 default:
1969 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1970 dv = complex_mark;
1971 }
1972
1973 keyword->num = ++di;
1974 rb_ary_push(default_values, dv);
1975 }
1976
1977 node = node->nd_next;
1978 }
1979
1980 keyword->num = kw;
1981
1982 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1983 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
1984 keyword->rest_start = arg_size++;
1985 body->param.flags.has_kwrest = TRUE;
1986
1987 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
1988 }
1989 keyword->required_num = rkw;
1990 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1991
1992 if (RARRAY_LEN(default_values)) {
1993 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1994
1995 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1996 VALUE dv = RARRAY_AREF(default_values, i);
1997 if (dv == complex_mark) dv = Qundef;
1998 RB_OBJ_WRITE(iseq, &dvs[i], dv);
1999 }
2000
2001 keyword->default_values = dvs;
2002 }
2003 return arg_size;
2004}
2005
2006static void
2007iseq_set_use_block(rb_iseq_t *iseq)
2008{
2009 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2010 if (!body->param.flags.use_block) {
2011 body->param.flags.use_block = 1;
2012
2013 rb_vm_t *vm = GET_VM();
2014
2015 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2016 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2017 set_insert(vm->unused_block_warning_table, key);
2018 }
2019 }
2020}
2021
2022static int
2023iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2024{
2025 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2026
2027 if (node_args) {
2028 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2029 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2030 ID rest_id = 0;
2031 int last_comma = 0;
2032 ID block_id = 0;
2033 int arg_size;
2034
2035 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2036
2037 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2038 body->param.lead_num = arg_size = (int)args->pre_args_num;
2039 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2040 debugs(" - argc: %d\n", body->param.lead_num);
2041
2042 rest_id = args->rest_arg;
2043 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2044 last_comma = 1;
2045 rest_id = 0;
2046 }
2047 block_id = args->block_arg;
2048
2049 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2050
2051 if (optimized_forward) {
2052 rest_id = 0;
2053 block_id = 0;
2054 }
2055
2056 if (args->opt_args) {
2057 const rb_node_opt_arg_t *node = args->opt_args;
2058 LABEL *label;
2059 VALUE labels = rb_ary_hidden_new(1);
2060 VALUE *opt_table;
2061 int i = 0, j;
2062
2063 while (node) {
2064 label = NEW_LABEL(nd_line(RNODE(node)));
2065 rb_ary_push(labels, (VALUE)label | 1);
2066 ADD_LABEL(optargs, label);
2067 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2068 node = node->nd_next;
2069 i += 1;
2070 }
2071
2072 /* last label */
2073 label = NEW_LABEL(nd_line(node_args));
2074 rb_ary_push(labels, (VALUE)label | 1);
2075 ADD_LABEL(optargs, label);
2076
2077 opt_table = ALLOC_N(VALUE, i+1);
2078
2079 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2080 for (j = 0; j < i+1; j++) {
2081 opt_table[j] &= ~1;
2082 }
2083 rb_ary_clear(labels);
2084
2085 body->param.flags.has_opt = TRUE;
2086 body->param.opt_num = i;
2087 body->param.opt_table = opt_table;
2088 arg_size += i;
2089 }
2090
2091 if (rest_id) {
2092 body->param.rest_start = arg_size++;
2093 body->param.flags.has_rest = TRUE;
2094 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2095 RUBY_ASSERT(body->param.rest_start != -1);
2096 }
2097
2098 if (args->first_post_arg) {
2099 body->param.post_start = arg_size;
2100 body->param.post_num = args->post_args_num;
2101 body->param.flags.has_post = TRUE;
2102 arg_size += args->post_args_num;
2103
2104 if (body->param.flags.has_rest) { /* TODO: why that? */
2105 body->param.post_start = body->param.rest_start + 1;
2106 }
2107 }
2108
2109 if (args->kw_args) {
2110 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2111 }
2112 else if (args->kw_rest_arg && !optimized_forward) {
2113 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2114 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2115 keyword->rest_start = arg_size++;
2116 body->param.keyword = keyword;
2117 body->param.flags.has_kwrest = TRUE;
2118
2119 static ID anon_kwrest = 0;
2120 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2121 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2122 }
2123 else if (args->no_kwarg) {
2124 body->param.flags.accepts_no_kwarg = TRUE;
2125 }
2126
2127 if (block_id) {
2128 body->param.block_start = arg_size++;
2129 body->param.flags.has_block = TRUE;
2130 iseq_set_use_block(iseq);
2131 }
2132
2133 // Only optimize specifically methods like this: `foo(...)`
2134 if (optimized_forward) {
2135 body->param.flags.use_block = 1;
2136 body->param.flags.forwardable = TRUE;
2137 arg_size = 1;
2138 }
2139
2140 iseq_calc_param_size(iseq);
2141 body->param.size = arg_size;
2142
2143 if (args->pre_init) { /* m_init */
2144 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2145 }
2146 if (args->post_init) { /* p_init */
2147 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2148 }
2149
2150 if (body->type == ISEQ_TYPE_BLOCK) {
2151 if (body->param.flags.has_opt == FALSE &&
2152 body->param.flags.has_post == FALSE &&
2153 body->param.flags.has_rest == FALSE &&
2154 body->param.flags.has_kw == FALSE &&
2155 body->param.flags.has_kwrest == FALSE) {
2156
2157 if (body->param.lead_num == 1 && last_comma == 0) {
2158 /* {|a|} */
2159 body->param.flags.ambiguous_param0 = TRUE;
2160 }
2161 }
2162 }
2163 }
2164
2165 return COMPILE_OK;
2166}
2167
2168static int
2169iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2170{
2171 unsigned int size = tbl ? tbl->size : 0;
2172 unsigned int offset = 0;
2173
2174 if (node_args) {
2175 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2176
2177 // If we have a function that only has `...` as the parameter,
2178 // then its local table should only be `...`
2179 // FIXME: I think this should be fixed in the AST rather than special case here.
2180 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2181 size -= 3;
2182 offset += 3;
2183 }
2184 }
2185
2186 if (size > 0) {
2187#if SIZEOF_INT >= SIZEOF_SIZE_T
2188 ASSUME(size < SIZE_MAX / sizeof(ID)); /* checked in xmalloc2_size */
2189#endif
2190 ID *ids = ALLOC_N(ID, size);
2191 MEMCPY(ids, tbl->ids + offset, ID, size);
2192 ISEQ_BODY(iseq)->local_table = ids;
2193 }
2194 ISEQ_BODY(iseq)->local_table_size = size;
2195
2196 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2197 return COMPILE_OK;
2198}
2199
2200int
2201rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2202{
2203 int tval, tlit;
2204
2205 if (val == lit) {
2206 return 0;
2207 }
2208 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2209 return val != lit;
2210 }
2211 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2212 return -1;
2213 }
2214 else if (tlit != tval) {
2215 return -1;
2216 }
2217 else if (tlit == T_SYMBOL) {
2218 return val != lit;
2219 }
2220 else if (tlit == T_STRING) {
2221 return rb_str_hash_cmp(lit, val);
2222 }
2223 else if (tlit == T_BIGNUM) {
2224 long x = FIX2LONG(rb_big_cmp(lit, val));
2225
2226 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2227 * There is no need to call rb_fix2int here. */
2228 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2229 return (int)x;
2230 }
2231 else if (tlit == T_FLOAT) {
2232 return rb_float_cmp(lit, val);
2233 }
2234 else if (tlit == T_RATIONAL) {
2235 const struct RRational *rat1 = RRATIONAL(val);
2236 const struct RRational *rat2 = RRATIONAL(lit);
2237 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2238 }
2239 else if (tlit == T_COMPLEX) {
2240 const struct RComplex *comp1 = RCOMPLEX(val);
2241 const struct RComplex *comp2 = RCOMPLEX(lit);
2242 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2243 }
2244 else if (tlit == T_REGEXP) {
2245 return rb_reg_equal(val, lit) ? 0 : -1;
2246 }
2247 else {
2249 }
2250}
2251
2252st_index_t
2253rb_iseq_cdhash_hash(VALUE a)
2254{
2255 switch (OBJ_BUILTIN_TYPE(a)) {
2256 case -1:
2257 case T_SYMBOL:
2258 return (st_index_t)a;
2259 case T_STRING:
2260 return rb_str_hash(a);
2261 case T_BIGNUM:
2262 return FIX2LONG(rb_big_hash(a));
2263 case T_FLOAT:
2264 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2265 case T_RATIONAL:
2266 return rb_rational_hash(a);
2267 case T_COMPLEX:
2268 return rb_complex_hash(a);
2269 case T_REGEXP:
2270 return NUM2LONG(rb_reg_hash(a));
2271 default:
2273 }
2274}
2275
2276static const struct st_hash_type cdhash_type = {
2277 rb_iseq_cdhash_cmp,
2278 rb_iseq_cdhash_hash,
2279};
2280
2282 VALUE hash;
2283 int pos;
2284 int len;
2285};
2286
2287static int
2288cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2289{
2290 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2291 LABEL *lobj = (LABEL *)(val & ~1);
2292 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2293 return ST_CONTINUE;
2294}
2295
2296
2297static inline VALUE
2298get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2299{
2300 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2301}
2302
2303static inline VALUE
2304get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2305{
2306 VALUE val;
2307 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2308 if (tbl) {
2309 if (rb_id_table_lookup(tbl,id,&val)) {
2310 return val;
2311 }
2312 }
2313 else {
2314 tbl = rb_id_table_create(1);
2315 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2316 }
2317 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2318 rb_id_table_insert(tbl,id,val);
2319 return val;
2320}
2321
2322#define BADINSN_DUMP(anchor, list, dest) \
2323 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2324
2325#define BADINSN_ERROR \
2326 (xfree(generated_iseq), \
2327 xfree(insns_info), \
2328 BADINSN_DUMP(anchor, list, NULL), \
2329 COMPILE_ERROR)
2330
2331static int
2332fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2333{
2334 int stack_max = 0, sp = 0, line = 0;
2335 LINK_ELEMENT *list;
2336
2337 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2338 if (IS_LABEL(list)) {
2339 LABEL *lobj = (LABEL *)list;
2340 lobj->set = TRUE;
2341 }
2342 }
2343
2344 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2345 switch (list->type) {
2346 case ISEQ_ELEMENT_INSN:
2347 {
2348 int j, len, insn;
2349 const char *types;
2350 VALUE *operands;
2351 INSN *iobj = (INSN *)list;
2352
2353 /* update sp */
2354 sp = calc_sp_depth(sp, iobj);
2355 if (sp < 0) {
2356 BADINSN_DUMP(anchor, list, NULL);
2357 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2358 "argument stack underflow (%d)", sp);
2359 return -1;
2360 }
2361 if (sp > stack_max) {
2362 stack_max = sp;
2363 }
2364
2365 line = iobj->insn_info.line_no;
2366 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2367 operands = iobj->operands;
2368 insn = iobj->insn_id;
2369 types = insn_op_types(insn);
2370 len = insn_len(insn);
2371
2372 /* operand check */
2373 if (iobj->operand_size != len - 1) {
2374 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2375 BADINSN_DUMP(anchor, list, NULL);
2376 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2377 "operand size miss! (%d for %d)",
2378 iobj->operand_size, len - 1);
2379 return -1;
2380 }
2381
2382 for (j = 0; types[j]; j++) {
2383 if (types[j] == TS_OFFSET) {
2384 /* label(destination position) */
2385 LABEL *lobj = (LABEL *)operands[j];
2386 if (!lobj->set) {
2387 BADINSN_DUMP(anchor, list, NULL);
2388 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2389 "unknown label: "LABEL_FORMAT, lobj->label_no);
2390 return -1;
2391 }
2392 if (lobj->sp == -1) {
2393 lobj->sp = sp;
2394 }
2395 else if (lobj->sp != sp) {
2396 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2397 RSTRING_PTR(rb_iseq_path(iseq)), line,
2398 lobj->label_no, lobj->sp, sp);
2399 }
2400 }
2401 }
2402 break;
2403 }
2404 case ISEQ_ELEMENT_LABEL:
2405 {
2406 LABEL *lobj = (LABEL *)list;
2407 if (lobj->sp == -1) {
2408 lobj->sp = sp;
2409 }
2410 else {
2411 if (lobj->sp != sp) {
2412 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2413 RSTRING_PTR(rb_iseq_path(iseq)), line,
2414 lobj->label_no, lobj->sp, sp);
2415 }
2416 sp = lobj->sp;
2417 }
2418 break;
2419 }
2420 case ISEQ_ELEMENT_TRACE:
2421 {
2422 /* ignore */
2423 break;
2424 }
2425 case ISEQ_ELEMENT_ADJUST:
2426 {
2427 ADJUST *adjust = (ADJUST *)list;
2428 int orig_sp = sp;
2429
2430 sp = adjust->label ? adjust->label->sp : 0;
2431 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2432 BADINSN_DUMP(anchor, list, NULL);
2433 COMPILE_ERROR(iseq, adjust->line_no,
2434 "iseq_set_sequence: adjust bug %d < %d",
2435 orig_sp, sp);
2436 return -1;
2437 }
2438 break;
2439 }
2440 default:
2441 BADINSN_DUMP(anchor, list, NULL);
2442 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2443 return -1;
2444 }
2445 }
2446 return stack_max;
2447}
2448
2449static int
2450add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2451 int insns_info_index, int code_index, const INSN *iobj)
2452{
2453 if (insns_info_index == 0 ||
2454 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2455#ifdef USE_ISEQ_NODE_ID
2456 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2457#endif
2458 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2459 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2460#ifdef USE_ISEQ_NODE_ID
2461 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2462#endif
2463 insns_info[insns_info_index].events = iobj->insn_info.events;
2464 positions[insns_info_index] = code_index;
2465 return TRUE;
2466 }
2467 return FALSE;
2468}
2469
2470static int
2471add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2472 int insns_info_index, int code_index, const ADJUST *adjust)
2473{
2474 insns_info[insns_info_index].line_no = adjust->line_no;
2475 insns_info[insns_info_index].node_id = -1;
2476 insns_info[insns_info_index].events = 0;
2477 positions[insns_info_index] = code_index;
2478 return TRUE;
2479}
2480
2481static ID *
2482array_to_idlist(VALUE arr)
2483{
2485 long size = RARRAY_LEN(arr);
2486 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2487 for (long i = 0; i < size; i++) {
2488 VALUE sym = RARRAY_AREF(arr, i);
2489 ids[i] = SYM2ID(sym);
2490 }
2491 ids[size] = 0;
2492 return ids;
2493}
2494
2495static VALUE
2496idlist_to_array(const ID *ids)
2497{
2498 VALUE arr = rb_ary_new();
2499 while (*ids) {
2500 rb_ary_push(arr, ID2SYM(*ids++));
2501 }
2502 return arr;
2503}
2504
2508static int
2509iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2510{
2511 struct iseq_insn_info_entry *insns_info;
2512 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2513 unsigned int *positions;
2514 LINK_ELEMENT *list;
2515 VALUE *generated_iseq;
2516 rb_event_flag_t events = 0;
2517 long data = 0;
2518
2519 int insn_num, code_index, insns_info_index, sp = 0;
2520 int stack_max = fix_sp_depth(iseq, anchor);
2521
2522 if (stack_max < 0) return COMPILE_NG;
2523
2524 /* fix label position */
2525 insn_num = code_index = 0;
2526 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2527 switch (list->type) {
2528 case ISEQ_ELEMENT_INSN:
2529 {
2530 INSN *iobj = (INSN *)list;
2531 /* update sp */
2532 sp = calc_sp_depth(sp, iobj);
2533 insn_num++;
2534 events = iobj->insn_info.events |= events;
2535 if (ISEQ_COVERAGE(iseq)) {
2536 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2537 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2538 int line = iobj->insn_info.line_no - 1;
2539 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2540 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2541 }
2542 }
2543 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2544 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2545 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2546 }
2547 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2548 }
2549 }
2550 code_index += insn_data_length(iobj);
2551 events = 0;
2552 data = 0;
2553 break;
2554 }
2555 case ISEQ_ELEMENT_LABEL:
2556 {
2557 LABEL *lobj = (LABEL *)list;
2558 lobj->position = code_index;
2559 if (lobj->sp != sp) {
2560 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2561 RSTRING_PTR(rb_iseq_path(iseq)),
2562 lobj->label_no, lobj->sp, sp);
2563 }
2564 sp = lobj->sp;
2565 break;
2566 }
2567 case ISEQ_ELEMENT_TRACE:
2568 {
2569 TRACE *trace = (TRACE *)list;
2570 events |= trace->event;
2571 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2572 break;
2573 }
2574 case ISEQ_ELEMENT_ADJUST:
2575 {
2576 ADJUST *adjust = (ADJUST *)list;
2577 if (adjust->line_no != -1) {
2578 int orig_sp = sp;
2579 sp = adjust->label ? adjust->label->sp : 0;
2580 if (orig_sp - sp > 0) {
2581 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2582 code_index++; /* insn */
2583 insn_num++;
2584 }
2585 }
2586 break;
2587 }
2588 default: break;
2589 }
2590 }
2591
2592 /* make instruction sequence */
2593 generated_iseq = ALLOC_N(VALUE, code_index);
2594 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2595 positions = ALLOC_N(unsigned int, insn_num);
2596 if (ISEQ_IS_SIZE(body)) {
2597 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2598 }
2599 else {
2600 body->is_entries = NULL;
2601 }
2602
2603 if (body->ci_size) {
2604 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2605 }
2606 else {
2607 body->call_data = NULL;
2608 }
2609 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2610
2611 // Calculate the bitmask buffer size.
2612 // Round the generated_iseq size up to the nearest multiple
2613 // of the number of bits in an unsigned long.
2614
2615 // Allocate enough room for the bitmask list
2616 iseq_bits_t * mark_offset_bits;
2617 int code_size = code_index;
2618
2619 bool needs_bitmap = false;
2620
2621 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2622 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2623 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2624 }
2625 else {
2626 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2627 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2628 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2629 }
2630
2631 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2632 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2633
2634 list = FIRST_ELEMENT(anchor);
2635 insns_info_index = code_index = sp = 0;
2636
2637 while (list) {
2638 switch (list->type) {
2639 case ISEQ_ELEMENT_INSN:
2640 {
2641 int j, len, insn;
2642 const char *types;
2643 VALUE *operands;
2644 INSN *iobj = (INSN *)list;
2645
2646 /* update sp */
2647 sp = calc_sp_depth(sp, iobj);
2648 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2649 operands = iobj->operands;
2650 insn = iobj->insn_id;
2651 generated_iseq[code_index] = insn;
2652 types = insn_op_types(insn);
2653 len = insn_len(insn);
2654
2655 for (j = 0; types[j]; j++) {
2656 char type = types[j];
2657
2658 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2659 switch (type) {
2660 case TS_OFFSET:
2661 {
2662 /* label(destination position) */
2663 LABEL *lobj = (LABEL *)operands[j];
2664 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2665 break;
2666 }
2667 case TS_CDHASH:
2668 {
2669 VALUE map = operands[j];
2670 struct cdhash_set_label_struct data;
2671 data.hash = map;
2672 data.pos = code_index;
2673 data.len = len;
2674 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2675
2676 rb_hash_rehash(map);
2677 freeze_hide_obj(map);
2678 generated_iseq[code_index + 1 + j] = map;
2679 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2680 RB_OBJ_WRITTEN(iseq, Qundef, map);
2681 needs_bitmap = true;
2682 break;
2683 }
2684 case TS_LINDEX:
2685 case TS_NUM: /* ulong */
2686 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2687 break;
2688 case TS_ISEQ: /* iseq */
2689 case TS_VALUE: /* VALUE */
2690 {
2691 VALUE v = operands[j];
2692 generated_iseq[code_index + 1 + j] = v;
2693 /* to mark ruby object */
2694 if (!SPECIAL_CONST_P(v)) {
2695 RB_OBJ_WRITTEN(iseq, Qundef, v);
2696 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2697 needs_bitmap = true;
2698 }
2699 break;
2700 }
2701 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2702 case TS_IC: /* inline cache: constants */
2703 {
2704 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2705 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2706 if (UNLIKELY(ic_index >= body->ic_size)) {
2707 BADINSN_DUMP(anchor, &iobj->link, 0);
2708 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2709 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2710 ic_index, ISEQ_IS_SIZE(body));
2711 }
2712
2713 ic->segments = array_to_idlist(operands[j]);
2714
2715 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2716 }
2717 break;
2718 case TS_IVC: /* inline ivar cache */
2719 {
2720 unsigned int ic_index = FIX2UINT(operands[j]);
2721
2722 IVC cache = ((IVC)&body->is_entries[ic_index]);
2723
2724 if (insn == BIN(setinstancevariable)) {
2725 cache->iv_set_name = SYM2ID(operands[j - 1]);
2726 }
2727 else {
2728 cache->iv_set_name = 0;
2729 }
2730
2731 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2732 }
2733 case TS_ISE: /* inline storage entry: `once` insn */
2734 case TS_ICVARC: /* inline cvar cache */
2735 {
2736 unsigned int ic_index = FIX2UINT(operands[j]);
2737 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2738 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2739 BADINSN_DUMP(anchor, &iobj->link, 0);
2740 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2741 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2742 ic_index, ISEQ_IS_SIZE(body));
2743 }
2744 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2745
2746 break;
2747 }
2748 case TS_CALLDATA:
2749 {
2750 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2751 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2752 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2753 cd->ci = source_ci;
2754 cd->cc = vm_cc_empty();
2755 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2756 break;
2757 }
2758 case TS_ID: /* ID */
2759 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2760 break;
2761 case TS_FUNCPTR:
2762 generated_iseq[code_index + 1 + j] = operands[j];
2763 break;
2764 case TS_BUILTIN:
2765 generated_iseq[code_index + 1 + j] = operands[j];
2766 break;
2767 default:
2768 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2769 "unknown operand type: %c", type);
2770 return COMPILE_NG;
2771 }
2772 }
2773 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2774 code_index += len;
2775 break;
2776 }
2777 case ISEQ_ELEMENT_LABEL:
2778 {
2779 LABEL *lobj = (LABEL *)list;
2780 if (lobj->sp != sp) {
2781 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2782 RSTRING_PTR(rb_iseq_path(iseq)),
2783 lobj->label_no, lobj->sp, sp);
2784 }
2785 sp = lobj->sp;
2786 break;
2787 }
2788 case ISEQ_ELEMENT_ADJUST:
2789 {
2790 ADJUST *adjust = (ADJUST *)list;
2791 int orig_sp = sp;
2792
2793 if (adjust->label) {
2794 sp = adjust->label->sp;
2795 }
2796 else {
2797 sp = 0;
2798 }
2799
2800 if (adjust->line_no != -1) {
2801 const int diff = orig_sp - sp;
2802 if (diff > 0) {
2803 if (insns_info_index == 0) {
2804 COMPILE_ERROR(iseq, adjust->line_no,
2805 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2806 }
2807 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2808 }
2809 if (diff > 1) {
2810 generated_iseq[code_index++] = BIN(adjuststack);
2811 generated_iseq[code_index++] = orig_sp - sp;
2812 }
2813 else if (diff == 1) {
2814 generated_iseq[code_index++] = BIN(pop);
2815 }
2816 else if (diff < 0) {
2817 int label_no = adjust->label ? adjust->label->label_no : -1;
2818 xfree(generated_iseq);
2819 xfree(insns_info);
2820 xfree(positions);
2821 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2822 xfree(mark_offset_bits);
2823 }
2824 debug_list(anchor, list);
2825 COMPILE_ERROR(iseq, adjust->line_no,
2826 "iseq_set_sequence: adjust bug to %d %d < %d",
2827 label_no, orig_sp, sp);
2828 return COMPILE_NG;
2829 }
2830 }
2831 break;
2832 }
2833 default:
2834 /* ignore */
2835 break;
2836 }
2837 list = list->next;
2838 }
2839
2840 body->iseq_encoded = (void *)generated_iseq;
2841 body->iseq_size = code_index;
2842 body->stack_max = stack_max;
2843
2844 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2845 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2846 }
2847 else {
2848 if (needs_bitmap) {
2849 body->mark_bits.list = mark_offset_bits;
2850 }
2851 else {
2852 body->mark_bits.list = NULL;
2853 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2854 ruby_xfree(mark_offset_bits);
2855 }
2856 }
2857
2858 /* get rid of memory leak when REALLOC failed */
2859 body->insns_info.body = insns_info;
2860 body->insns_info.positions = positions;
2861
2862 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2863 body->insns_info.body = insns_info;
2864 REALLOC_N(positions, unsigned int, insns_info_index);
2865 body->insns_info.positions = positions;
2866 body->insns_info.size = insns_info_index;
2867
2868 return COMPILE_OK;
2869}
2870
2871static int
2872label_get_position(LABEL *lobj)
2873{
2874 return lobj->position;
2875}
2876
2877static int
2878label_get_sp(LABEL *lobj)
2879{
2880 return lobj->sp;
2881}
2882
2883static int
2884iseq_set_exception_table(rb_iseq_t *iseq)
2885{
2886 const VALUE *tptr, *ptr;
2887 unsigned int tlen, i;
2888 struct iseq_catch_table_entry *entry;
2889
2890 ISEQ_BODY(iseq)->catch_table = NULL;
2891
2892 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2893 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2894 tlen = (int)RARRAY_LEN(catch_table_ary);
2895 tptr = RARRAY_CONST_PTR(catch_table_ary);
2896
2897 if (tlen > 0) {
2898 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2899 table->size = tlen;
2900
2901 for (i = 0; i < table->size; i++) {
2902 int pos;
2903 ptr = RARRAY_CONST_PTR(tptr[i]);
2904 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2905 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2906 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2907 RUBY_ASSERT(pos >= 0);
2908 entry->start = (unsigned int)pos;
2909 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2910 RUBY_ASSERT(pos >= 0);
2911 entry->end = (unsigned int)pos;
2912 entry->iseq = (rb_iseq_t *)ptr[3];
2913 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2914
2915 /* stack depth */
2916 if (ptr[4]) {
2917 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2918 entry->cont = label_get_position(lobj);
2919 entry->sp = label_get_sp(lobj);
2920
2921 /* TODO: Dirty Hack! Fix me */
2922 if (entry->type == CATCH_TYPE_RESCUE ||
2923 entry->type == CATCH_TYPE_BREAK ||
2924 entry->type == CATCH_TYPE_NEXT) {
2925 RUBY_ASSERT(entry->sp > 0);
2926 entry->sp--;
2927 }
2928 }
2929 else {
2930 entry->cont = 0;
2931 }
2932 }
2933 ISEQ_BODY(iseq)->catch_table = table;
2934 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2935 }
2936
2937 RB_GC_GUARD(catch_table_ary);
2938
2939 return COMPILE_OK;
2940}
2941
2942/*
2943 * set optional argument table
2944 * def foo(a, b=expr1, c=expr2)
2945 * =>
2946 * b:
2947 * expr1
2948 * c:
2949 * expr2
2950 */
2951static int
2952iseq_set_optargs_table(rb_iseq_t *iseq)
2953{
2954 int i;
2955 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2956
2957 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2958 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2959 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2960 }
2961 }
2962 return COMPILE_OK;
2963}
2964
2965static LINK_ELEMENT *
2966get_destination_insn(INSN *iobj)
2967{
2968 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2969 LINK_ELEMENT *list;
2970 rb_event_flag_t events = 0;
2971
2972 list = lobj->link.next;
2973 while (list) {
2974 switch (list->type) {
2975 case ISEQ_ELEMENT_INSN:
2976 case ISEQ_ELEMENT_ADJUST:
2977 goto found;
2978 case ISEQ_ELEMENT_LABEL:
2979 /* ignore */
2980 break;
2981 case ISEQ_ELEMENT_TRACE:
2982 {
2983 TRACE *trace = (TRACE *)list;
2984 events |= trace->event;
2985 }
2986 break;
2987 default: break;
2988 }
2989 list = list->next;
2990 }
2991 found:
2992 if (list && IS_INSN(list)) {
2993 INSN *iobj = (INSN *)list;
2994 iobj->insn_info.events |= events;
2995 }
2996 return list;
2997}
2998
2999static LINK_ELEMENT *
3000get_next_insn(INSN *iobj)
3001{
3002 LINK_ELEMENT *list = iobj->link.next;
3003
3004 while (list) {
3005 if (IS_INSN(list) || IS_ADJUST(list)) {
3006 return list;
3007 }
3008 list = list->next;
3009 }
3010 return 0;
3011}
3012
3013static LINK_ELEMENT *
3014get_prev_insn(INSN *iobj)
3015{
3016 LINK_ELEMENT *list = iobj->link.prev;
3017
3018 while (list) {
3019 if (IS_INSN(list) || IS_ADJUST(list)) {
3020 return list;
3021 }
3022 list = list->prev;
3023 }
3024 return 0;
3025}
3026
3027static void
3028unref_destination(INSN *iobj, int pos)
3029{
3030 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3031 --lobj->refcnt;
3032 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3033}
3034
3035static bool
3036replace_destination(INSN *dobj, INSN *nobj)
3037{
3038 VALUE n = OPERAND_AT(nobj, 0);
3039 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3040 LABEL *nl = (LABEL *)n;
3041 if (dl == nl) return false;
3042 --dl->refcnt;
3043 ++nl->refcnt;
3044 OPERAND_AT(dobj, 0) = n;
3045 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3046 return true;
3047}
3048
3049static LABEL*
3050find_destination(INSN *i)
3051{
3052 int pos, len = insn_len(i->insn_id);
3053 for (pos = 0; pos < len; ++pos) {
3054 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3055 return (LABEL *)OPERAND_AT(i, pos);
3056 }
3057 }
3058 return 0;
3059}
3060
3061static int
3062remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3063{
3064 LINK_ELEMENT *first = i, *end;
3065 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3066
3067 if (!i) return 0;
3068 unref_counts = ALLOCA_N(int, nlabels);
3069 MEMZERO(unref_counts, int, nlabels);
3070 end = i;
3071 do {
3072 LABEL *lab;
3073 if (IS_INSN(i)) {
3074 if (IS_INSN_ID(i, leave)) {
3075 end = i;
3076 break;
3077 }
3078 else if ((lab = find_destination((INSN *)i)) != 0) {
3079 unref_counts[lab->label_no]++;
3080 }
3081 }
3082 else if (IS_LABEL(i)) {
3083 lab = (LABEL *)i;
3084 if (lab->unremovable) return 0;
3085 if (lab->refcnt > unref_counts[lab->label_no]) {
3086 if (i == first) return 0;
3087 break;
3088 }
3089 continue;
3090 }
3091 else if (IS_TRACE(i)) {
3092 /* do nothing */
3093 }
3094 else if (IS_ADJUST(i)) {
3095 return 0;
3096 }
3097 end = i;
3098 } while ((i = i->next) != 0);
3099 i = first;
3100 do {
3101 if (IS_INSN(i)) {
3102 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3103 VALUE insn = INSN_OF(i);
3104 int pos, len = insn_len(insn);
3105 for (pos = 0; pos < len; ++pos) {
3106 switch (insn_op_types(insn)[pos]) {
3107 case TS_OFFSET:
3108 unref_destination((INSN *)i, pos);
3109 break;
3110 case TS_CALLDATA:
3111 --(body->ci_size);
3112 break;
3113 }
3114 }
3115 }
3116 ELEM_REMOVE(i);
3117 } while ((i != end) && (i = i->next) != 0);
3118 return 1;
3119}
3120
3121static int
3122iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3123{
3124 switch (OPERAND_AT(iobj, 0)) {
3125 case INT2FIX(0): /* empty array */
3126 ELEM_REMOVE(&iobj->link);
3127 return TRUE;
3128 case INT2FIX(1): /* single element array */
3129 ELEM_REMOVE(&iobj->link);
3130 return FALSE;
3131 default:
3132 iobj->insn_id = BIN(adjuststack);
3133 return TRUE;
3134 }
3135}
3136
3137static int
3138is_frozen_putstring(INSN *insn, VALUE *op)
3139{
3140 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3141 *op = OPERAND_AT(insn, 0);
3142 return 1;
3143 }
3144 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3145 *op = OPERAND_AT(insn, 0);
3146 return RB_TYPE_P(*op, T_STRING);
3147 }
3148 return 0;
3149}
3150
3151static int
3152optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3153{
3154 /*
3155 * putobject obj
3156 * dup
3157 * checktype T_XXX
3158 * branchif l1
3159 * l2:
3160 * ...
3161 * l1:
3162 *
3163 * => obj is a T_XXX
3164 *
3165 * putobject obj (T_XXX)
3166 * jump L1
3167 * L1:
3168 *
3169 * => obj is not a T_XXX
3170 *
3171 * putobject obj (T_XXX)
3172 * jump L2
3173 * L2:
3174 */
3175 int line, node_id;
3176 INSN *niobj, *ciobj, *dup = 0;
3177 LABEL *dest = 0;
3178 VALUE type;
3179
3180 switch (INSN_OF(iobj)) {
3181 case BIN(putstring):
3182 case BIN(putchilledstring):
3184 break;
3185 case BIN(putnil):
3186 type = INT2FIX(T_NIL);
3187 break;
3188 case BIN(putobject):
3189 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3190 break;
3191 default: return FALSE;
3192 }
3193
3194 ciobj = (INSN *)get_next_insn(iobj);
3195 if (IS_INSN_ID(ciobj, jump)) {
3196 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3197 }
3198 if (IS_INSN_ID(ciobj, dup)) {
3199 ciobj = (INSN *)get_next_insn(dup = ciobj);
3200 }
3201 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3202 niobj = (INSN *)get_next_insn(ciobj);
3203 if (!niobj) {
3204 /* TODO: putobject true/false */
3205 return FALSE;
3206 }
3207 switch (INSN_OF(niobj)) {
3208 case BIN(branchif):
3209 if (OPERAND_AT(ciobj, 0) == type) {
3210 dest = (LABEL *)OPERAND_AT(niobj, 0);
3211 }
3212 break;
3213 case BIN(branchunless):
3214 if (OPERAND_AT(ciobj, 0) != type) {
3215 dest = (LABEL *)OPERAND_AT(niobj, 0);
3216 }
3217 break;
3218 default:
3219 return FALSE;
3220 }
3221 line = ciobj->insn_info.line_no;
3222 node_id = ciobj->insn_info.node_id;
3223 if (!dest) {
3224 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3225 dest = (LABEL *)niobj->link.next; /* reuse label */
3226 }
3227 else {
3228 dest = NEW_LABEL(line);
3229 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3230 }
3231 }
3232 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3233 LABEL_REF(dest);
3234 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3235 return TRUE;
3236}
3237
3238static const struct rb_callinfo *
3239ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3240{
3241 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3242 vm_ci_flag(ci) | add,
3243 vm_ci_argc(ci),
3244 vm_ci_kwarg(ci));
3245 RB_OBJ_WRITTEN(iseq, ci, nci);
3246 return nci;
3247}
3248
3249static const struct rb_callinfo *
3250ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3251{
3252 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3253 vm_ci_flag(ci),
3254 argc,
3255 vm_ci_kwarg(ci));
3256 RB_OBJ_WRITTEN(iseq, ci, nci);
3257 return nci;
3258}
3259
3260#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3261
3262static int
3263iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3264{
3265 INSN *const iobj = (INSN *)list;
3266
3267 again:
3268 optimize_checktype(iseq, iobj);
3269
3270 if (IS_INSN_ID(iobj, jump)) {
3271 INSN *niobj, *diobj, *piobj;
3272 diobj = (INSN *)get_destination_insn(iobj);
3273 niobj = (INSN *)get_next_insn(iobj);
3274
3275 if (diobj == niobj) {
3276 /*
3277 * jump LABEL
3278 * LABEL:
3279 * =>
3280 * LABEL:
3281 */
3282 unref_destination(iobj, 0);
3283 ELEM_REMOVE(&iobj->link);
3284 return COMPILE_OK;
3285 }
3286 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3287 IS_INSN_ID(diobj, jump) &&
3288 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3289 diobj->insn_info.events == 0) {
3290 /*
3291 * useless jump elimination:
3292 * jump LABEL1
3293 * ...
3294 * LABEL1:
3295 * jump LABEL2
3296 *
3297 * => in this case, first jump instruction should jump to
3298 * LABEL2 directly
3299 */
3300 if (replace_destination(iobj, diobj)) {
3301 remove_unreachable_chunk(iseq, iobj->link.next);
3302 goto again;
3303 }
3304 }
3305 else if (IS_INSN_ID(diobj, leave)) {
3306 /*
3307 * jump LABEL
3308 * ...
3309 * LABEL:
3310 * leave
3311 * =>
3312 * leave
3313 * ...
3314 * LABEL:
3315 * leave
3316 */
3317 /* replace */
3318 unref_destination(iobj, 0);
3319 iobj->insn_id = BIN(leave);
3320 iobj->operand_size = 0;
3321 iobj->insn_info = diobj->insn_info;
3322 goto again;
3323 }
3324 else if (IS_INSN(iobj->link.prev) &&
3325 (piobj = (INSN *)iobj->link.prev) &&
3326 (IS_INSN_ID(piobj, branchif) ||
3327 IS_INSN_ID(piobj, branchunless))) {
3328 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3329 if (niobj == pdiobj) {
3330 int refcnt = IS_LABEL(piobj->link.next) ?
3331 ((LABEL *)piobj->link.next)->refcnt : 0;
3332 /*
3333 * useless jump elimination (if/unless destination):
3334 * if L1
3335 * jump L2
3336 * L1:
3337 * ...
3338 * L2:
3339 *
3340 * ==>
3341 * unless L2
3342 * L1:
3343 * ...
3344 * L2:
3345 */
3346 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3347 ? BIN(branchunless) : BIN(branchif);
3348 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3349 ELEM_REMOVE(&iobj->link);
3350 }
3351 else {
3352 /* TODO: replace other branch destinations too */
3353 }
3354 return COMPILE_OK;
3355 }
3356 else if (diobj == pdiobj) {
3357 /*
3358 * useless jump elimination (if/unless before jump):
3359 * L1:
3360 * ...
3361 * if L1
3362 * jump L1
3363 *
3364 * ==>
3365 * L1:
3366 * ...
3367 * pop
3368 * jump L1
3369 */
3370 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3371 ELEM_REPLACE(&piobj->link, &popiobj->link);
3372 }
3373 }
3374 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3375 goto again;
3376 }
3377 }
3378
3379 /*
3380 * putstring "beg"
3381 * putstring "end"
3382 * newrange excl
3383 *
3384 * ==>
3385 *
3386 * putobject "beg".."end"
3387 */
3388 if (IS_INSN_ID(iobj, newrange)) {
3389 INSN *const range = iobj;
3390 INSN *beg, *end;
3391 VALUE str_beg, str_end;
3392
3393 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3394 is_frozen_putstring(end, &str_end) &&
3395 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3396 is_frozen_putstring(beg, &str_beg)) {
3397 int excl = FIX2INT(OPERAND_AT(range, 0));
3398 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3399
3400 ELEM_REMOVE(&beg->link);
3401 ELEM_REMOVE(&end->link);
3402 range->insn_id = BIN(putobject);
3403 OPERAND_AT(range, 0) = lit_range;
3404 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3405 }
3406 }
3407
3408 if (IS_INSN_ID(iobj, leave)) {
3409 remove_unreachable_chunk(iseq, iobj->link.next);
3410 }
3411
3412 /*
3413 * ...
3414 * duparray [...]
3415 * concatarray | concattoarray
3416 * =>
3417 * ...
3418 * putobject [...]
3419 * concatarray | concattoarray
3420 */
3421 if (IS_INSN_ID(iobj, duparray)) {
3422 LINK_ELEMENT *next = iobj->link.next;
3423 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3424 iobj->insn_id = BIN(putobject);
3425 }
3426 }
3427
3428 /*
3429 * duparray [...]
3430 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3431 * =>
3432 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3433 */
3434 if (IS_INSN_ID(iobj, duparray)) {
3435 LINK_ELEMENT *next = iobj->link.next;
3436 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3437 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3438 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3439
3440 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3441 VALUE ary = iobj->operands[0];
3443
3444 iobj->insn_id = BIN(opt_ary_freeze);
3445 iobj->operand_size = 2;
3446 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3447 iobj->operands[0] = ary;
3448 iobj->operands[1] = (VALUE)ci;
3449 ELEM_REMOVE(next);
3450 }
3451 }
3452 }
3453
3454 /*
3455 * duphash {...}
3456 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3457 * =>
3458 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3459 */
3460 if (IS_INSN_ID(iobj, duphash)) {
3461 LINK_ELEMENT *next = iobj->link.next;
3462 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3463 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3464 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3465
3466 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3467 VALUE hash = iobj->operands[0];
3468 rb_obj_reveal(hash, rb_cHash);
3469
3470 iobj->insn_id = BIN(opt_hash_freeze);
3471 iobj->operand_size = 2;
3472 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3473 iobj->operands[0] = hash;
3474 iobj->operands[1] = (VALUE)ci;
3475 ELEM_REMOVE(next);
3476 }
3477 }
3478 }
3479
3480 /*
3481 * newarray 0
3482 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3483 * =>
3484 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3485 */
3486 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3487 LINK_ELEMENT *next = iobj->link.next;
3488 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3489 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3490 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3491
3492 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3493 iobj->insn_id = BIN(opt_ary_freeze);
3494 iobj->operand_size = 2;
3495 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3496 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cArray_empty_frozen);
3497 iobj->operands[1] = (VALUE)ci;
3498 ELEM_REMOVE(next);
3499 }
3500 }
3501 }
3502
3503 /*
3504 * newhash 0
3505 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3506 * =>
3507 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3508 */
3509 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3510 LINK_ELEMENT *next = iobj->link.next;
3511 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3512 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3513 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3514
3515 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3516 iobj->insn_id = BIN(opt_hash_freeze);
3517 iobj->operand_size = 2;
3518 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3519 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cHash_empty_frozen);
3520 iobj->operands[1] = (VALUE)ci;
3521 ELEM_REMOVE(next);
3522 }
3523 }
3524 }
3525
3526 if (IS_INSN_ID(iobj, branchif) ||
3527 IS_INSN_ID(iobj, branchnil) ||
3528 IS_INSN_ID(iobj, branchunless)) {
3529 /*
3530 * if L1
3531 * ...
3532 * L1:
3533 * jump L2
3534 * =>
3535 * if L2
3536 */
3537 INSN *nobj = (INSN *)get_destination_insn(iobj);
3538
3539 /* This is super nasty hack!!!
3540 *
3541 * This jump-jump optimization may ignore event flags of the jump
3542 * instruction being skipped. Actually, Line 2 TracePoint event
3543 * is never fired in the following code:
3544 *
3545 * 1: raise if 1 == 2
3546 * 2: while true
3547 * 3: break
3548 * 4: end
3549 *
3550 * This is critical for coverage measurement. [Bug #15980]
3551 *
3552 * This is a stopgap measure: stop the jump-jump optimization if
3553 * coverage measurement is enabled and if the skipped instruction
3554 * has any event flag.
3555 *
3556 * Note that, still, TracePoint Line event does not occur on Line 2.
3557 * This should be fixed in future.
3558 */
3559 int stop_optimization =
3560 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3561 nobj->link.type == ISEQ_ELEMENT_INSN &&
3562 nobj->insn_info.events;
3563 if (!stop_optimization) {
3564 INSN *pobj = (INSN *)iobj->link.prev;
3565 int prev_dup = 0;
3566 if (pobj) {
3567 if (!IS_INSN(&pobj->link))
3568 pobj = 0;
3569 else if (IS_INSN_ID(pobj, dup))
3570 prev_dup = 1;
3571 }
3572
3573 for (;;) {
3574 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3575 if (!replace_destination(iobj, nobj)) break;
3576 }
3577 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3578 !!(nobj = (INSN *)nobj->link.next) &&
3579 /* basic blocks, with no labels in the middle */
3580 nobj->insn_id == iobj->insn_id) {
3581 /*
3582 * dup
3583 * if L1
3584 * ...
3585 * L1:
3586 * dup
3587 * if L2
3588 * =>
3589 * dup
3590 * if L2
3591 * ...
3592 * L1:
3593 * dup
3594 * if L2
3595 */
3596 if (!replace_destination(iobj, nobj)) break;
3597 }
3598 else if (pobj) {
3599 /*
3600 * putnil
3601 * if L1
3602 * =>
3603 * # nothing
3604 *
3605 * putobject true
3606 * if L1
3607 * =>
3608 * jump L1
3609 *
3610 * putstring ".."
3611 * if L1
3612 * =>
3613 * jump L1
3614 *
3615 * putstring ".."
3616 * dup
3617 * if L1
3618 * =>
3619 * putstring ".."
3620 * jump L1
3621 *
3622 */
3623 int cond;
3624 if (prev_dup && IS_INSN(pobj->link.prev)) {
3625 pobj = (INSN *)pobj->link.prev;
3626 }
3627 if (IS_INSN_ID(pobj, putobject)) {
3628 cond = (IS_INSN_ID(iobj, branchif) ?
3629 OPERAND_AT(pobj, 0) != Qfalse :
3630 IS_INSN_ID(iobj, branchunless) ?
3631 OPERAND_AT(pobj, 0) == Qfalse :
3632 FALSE);
3633 }
3634 else if (IS_INSN_ID(pobj, putstring) ||
3635 IS_INSN_ID(pobj, duparray) ||
3636 IS_INSN_ID(pobj, newarray)) {
3637 cond = IS_INSN_ID(iobj, branchif);
3638 }
3639 else if (IS_INSN_ID(pobj, putnil)) {
3640 cond = !IS_INSN_ID(iobj, branchif);
3641 }
3642 else break;
3643 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3644 ELEM_REMOVE(iobj->link.prev);
3645 }
3646 else if (!iseq_pop_newarray(iseq, pobj)) {
3647 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3648 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3649 }
3650 if (cond) {
3651 if (prev_dup) {
3652 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3653 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3654 }
3655 iobj->insn_id = BIN(jump);
3656 goto again;
3657 }
3658 else {
3659 unref_destination(iobj, 0);
3660 ELEM_REMOVE(&iobj->link);
3661 }
3662 break;
3663 }
3664 else break;
3665 nobj = (INSN *)get_destination_insn(nobj);
3666 }
3667 }
3668 }
3669
3670 if (IS_INSN_ID(iobj, pop)) {
3671 /*
3672 * putself / putnil / putobject obj / putstring "..."
3673 * pop
3674 * =>
3675 * # do nothing
3676 */
3677 LINK_ELEMENT *prev = iobj->link.prev;
3678 if (IS_INSN(prev)) {
3679 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3680 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3681 previ == BIN(putself) || previ == BIN(putstring) ||
3682 previ == BIN(putchilledstring) ||
3683 previ == BIN(dup) ||
3684 previ == BIN(getlocal) ||
3685 previ == BIN(getblockparam) ||
3686 previ == BIN(getblockparamproxy) ||
3687 previ == BIN(getinstancevariable) ||
3688 previ == BIN(duparray)) {
3689 /* just push operand or static value and pop soon, no
3690 * side effects */
3691 ELEM_REMOVE(prev);
3692 ELEM_REMOVE(&iobj->link);
3693 }
3694 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3695 ELEM_REMOVE(&iobj->link);
3696 }
3697 else if (previ == BIN(concatarray)) {
3698 INSN *piobj = (INSN *)prev;
3699 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3700 INSN_OF(piobj) = BIN(pop);
3701 }
3702 else if (previ == BIN(concatstrings)) {
3703 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3704 ELEM_REMOVE(prev);
3705 }
3706 else {
3707 ELEM_REMOVE(&iobj->link);
3708 INSN_OF(prev) = BIN(adjuststack);
3709 }
3710 }
3711 }
3712 }
3713
3714 if (IS_INSN_ID(iobj, newarray) ||
3715 IS_INSN_ID(iobj, duparray) ||
3716 IS_INSN_ID(iobj, concatarray) ||
3717 IS_INSN_ID(iobj, splatarray) ||
3718 0) {
3719 /*
3720 * newarray N
3721 * splatarray
3722 * =>
3723 * newarray N
3724 * newarray always puts an array
3725 */
3726 LINK_ELEMENT *next = iobj->link.next;
3727 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3728 /* remove splatarray following always-array insn */
3729 ELEM_REMOVE(next);
3730 }
3731 }
3732
3733 if (IS_INSN_ID(iobj, newarray)) {
3734 LINK_ELEMENT *next = iobj->link.next;
3735 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3736 OPERAND_AT(next, 1) == INT2FIX(0)) {
3737 VALUE op1, op2;
3738 op1 = OPERAND_AT(iobj, 0);
3739 op2 = OPERAND_AT(next, 0);
3740 ELEM_REMOVE(next);
3741
3742 if (op1 == op2) {
3743 /*
3744 * newarray 2
3745 * expandarray 2, 0
3746 * =>
3747 * swap
3748 */
3749 if (op1 == INT2FIX(2)) {
3750 INSN_OF(iobj) = BIN(swap);
3751 iobj->operand_size = 0;
3752 }
3753 /*
3754 * newarray X
3755 * expandarray X, 0
3756 * =>
3757 * opt_reverse X
3758 */
3759 else {
3760 INSN_OF(iobj) = BIN(opt_reverse);
3761 }
3762 }
3763 else {
3764 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3765 INSN_OF(iobj) = BIN(opt_reverse);
3766 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3767
3768 if (op1 > op2) {
3769 /* X > Y
3770 * newarray X
3771 * expandarray Y, 0
3772 * =>
3773 * pop * (Y-X)
3774 * opt_reverse Y
3775 */
3776 for (; diff > 0; diff--) {
3777 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3778 }
3779 }
3780 else { /* (op1 < op2) */
3781 /* X < Y
3782 * newarray X
3783 * expandarray Y, 0
3784 * =>
3785 * putnil * (Y-X)
3786 * opt_reverse Y
3787 */
3788 for (; diff < 0; diff++) {
3789 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3790 }
3791 }
3792 }
3793 }
3794 }
3795
3796 if (IS_INSN_ID(iobj, duparray)) {
3797 LINK_ELEMENT *next = iobj->link.next;
3798 /*
3799 * duparray obj
3800 * expandarray X, 0
3801 * =>
3802 * putobject obj
3803 * expandarray X, 0
3804 */
3805 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3806 INSN_OF(iobj) = BIN(putobject);
3807 }
3808 }
3809
3810 if (IS_INSN_ID(iobj, anytostring)) {
3811 LINK_ELEMENT *next = iobj->link.next;
3812 /*
3813 * anytostring
3814 * concatstrings 1
3815 * =>
3816 * anytostring
3817 */
3818 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3819 OPERAND_AT(next, 0) == INT2FIX(1)) {
3820 ELEM_REMOVE(next);
3821 }
3822 }
3823
3824 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3825 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3826 /*
3827 * putstring ""
3828 * concatstrings N
3829 * =>
3830 * concatstrings N-1
3831 */
3832 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3833 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3834 INSN *next = (INSN *)iobj->link.next;
3835 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3836 ELEM_REMOVE(&next->link);
3837 }
3838 ELEM_REMOVE(&iobj->link);
3839 }
3840 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3841 INSN *next = (INSN *)iobj->link.next;
3842 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3843 VALUE src = OPERAND_AT(iobj, 0);
3844 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3845 VALUE path = rb_iseq_path(iseq);
3846 int line = iobj->insn_info.line_no;
3847 VALUE errinfo = rb_errinfo();
3848 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3849 if (NIL_P(re)) {
3850 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3851 rb_set_errinfo(errinfo);
3852 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3853 }
3854 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3855 ELEM_REMOVE(iobj->link.next);
3856 }
3857 }
3858 }
3859
3860 if (IS_INSN_ID(iobj, concatstrings)) {
3861 /*
3862 * concatstrings N
3863 * concatstrings M
3864 * =>
3865 * concatstrings N+M-1
3866 */
3867 LINK_ELEMENT *next = iobj->link.next;
3868 INSN *jump = 0;
3869 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3870 next = get_destination_insn(jump = (INSN *)next);
3871 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3872 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3873 OPERAND_AT(iobj, 0) = INT2FIX(n);
3874 if (jump) {
3875 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3876 if (!--label->refcnt) {
3877 ELEM_REMOVE(&label->link);
3878 }
3879 else {
3880 label = NEW_LABEL(0);
3881 OPERAND_AT(jump, 0) = (VALUE)label;
3882 }
3883 label->refcnt++;
3884 ELEM_INSERT_NEXT(next, &label->link);
3885 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3886 }
3887 else {
3888 ELEM_REMOVE(next);
3889 }
3890 }
3891 }
3892
3893 if (do_tailcallopt &&
3894 (IS_INSN_ID(iobj, send) ||
3895 IS_INSN_ID(iobj, opt_aref_with) ||
3896 IS_INSN_ID(iobj, opt_aset_with) ||
3897 IS_INSN_ID(iobj, invokesuper))) {
3898 /*
3899 * send ...
3900 * leave
3901 * =>
3902 * send ..., ... | VM_CALL_TAILCALL, ...
3903 * leave # unreachable
3904 */
3905 INSN *piobj = NULL;
3906 if (iobj->link.next) {
3907 LINK_ELEMENT *next = iobj->link.next;
3908 do {
3909 if (!IS_INSN(next)) {
3910 next = next->next;
3911 continue;
3912 }
3913 switch (INSN_OF(next)) {
3914 case BIN(nop):
3915 next = next->next;
3916 break;
3917 case BIN(jump):
3918 /* if cond
3919 * return tailcall
3920 * end
3921 */
3922 next = get_destination_insn((INSN *)next);
3923 break;
3924 case BIN(leave):
3925 piobj = iobj;
3926 /* fall through */
3927 default:
3928 next = NULL;
3929 break;
3930 }
3931 } while (next);
3932 }
3933
3934 if (piobj) {
3935 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3936 if (IS_INSN_ID(piobj, send) ||
3937 IS_INSN_ID(piobj, invokesuper)) {
3938 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3939 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3940 OPERAND_AT(piobj, 0) = (VALUE)ci;
3941 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3942 }
3943 }
3944 else {
3945 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3946 OPERAND_AT(piobj, 0) = (VALUE)ci;
3947 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3948 }
3949 }
3950 }
3951
3952 if (IS_INSN_ID(iobj, dup)) {
3953 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3954 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3955
3956 /*
3957 * dup
3958 * setlocal x, y
3959 * setlocal x, y
3960 * =>
3961 * dup
3962 * setlocal x, y
3963 */
3964 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3965 set2 = set1->next;
3966 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3967 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3968 ELEM_REMOVE(set1);
3969 ELEM_REMOVE(&iobj->link);
3970 }
3971 }
3972
3973 /*
3974 * dup
3975 * setlocal x, y
3976 * dup
3977 * setlocal x, y
3978 * =>
3979 * dup
3980 * setlocal x, y
3981 */
3982 else if (IS_NEXT_INSN_ID(set1, dup) &&
3983 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3984 set2 = set1->next->next;
3985 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3986 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3987 ELEM_REMOVE(set1->next);
3988 ELEM_REMOVE(set2);
3989 }
3990 }
3991 }
3992 }
3993
3994 /*
3995 * getlocal x, y
3996 * dup
3997 * setlocal x, y
3998 * =>
3999 * dup
4000 */
4001 if (IS_INSN_ID(iobj, getlocal)) {
4002 LINK_ELEMENT *niobj = &iobj->link;
4003 if (IS_NEXT_INSN_ID(niobj, dup)) {
4004 niobj = niobj->next;
4005 }
4006 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4007 LINK_ELEMENT *set1 = niobj->next;
4008 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4009 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4010 ELEM_REMOVE(set1);
4011 ELEM_REMOVE(niobj);
4012 }
4013 }
4014 }
4015
4016 /*
4017 * opt_invokebuiltin_delegate
4018 * trace
4019 * leave
4020 * =>
4021 * opt_invokebuiltin_delegate_leave
4022 * trace
4023 * leave
4024 */
4025 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4026 if (IS_TRACE(iobj->link.next)) {
4027 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4028 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4029 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4030 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4031 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4032 }
4033 }
4034 }
4035 }
4036
4037 /*
4038 * getblockparam
4039 * branchif / branchunless
4040 * =>
4041 * getblockparamproxy
4042 * branchif / branchunless
4043 */
4044 if (IS_INSN_ID(iobj, getblockparam)) {
4045 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4046 iobj->insn_id = BIN(getblockparamproxy);
4047 }
4048 }
4049
4050 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4051 LINK_ELEMENT *niobj = &iobj->link;
4052 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4053 niobj = niobj->next;
4054 LINK_ELEMENT *siobj;
4055 unsigned int set_flags = 0, unset_flags = 0;
4056
4057 /*
4058 * Eliminate hash allocation for f(*a, kw: 1)
4059 *
4060 * splatarray false
4061 * duphash
4062 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4063 * =>
4064 * splatarray false
4065 * putobject
4066 * send ARGS_SPLAT|KW_SPLAT
4067 */
4068 if (IS_NEXT_INSN_ID(niobj, send)) {
4069 siobj = niobj->next;
4070 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4071 unset_flags = VM_CALL_ARGS_BLOCKARG;
4072 }
4073 /*
4074 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4075 *
4076 * splatarray false
4077 * duphash
4078 * getlocal / getinstancevariable / getblockparamproxy
4079 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4080 * =>
4081 * splatarray false
4082 * putobject
4083 * getlocal / getinstancevariable / getblockparamproxy
4084 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4085 */
4086 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4087 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4088 siobj = niobj->next->next;
4089 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4090 }
4091
4092 if (set_flags) {
4093 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4094 unsigned int flags = vm_ci_flag(ci);
4095 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4096 ((INSN*)niobj)->insn_id = BIN(putobject);
4097 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4098
4099 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4100 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4101 RB_OBJ_WRITTEN(iseq, ci, nci);
4102 OPERAND_AT(siobj, 0) = (VALUE)nci;
4103 }
4104 }
4105 }
4106 }
4107
4108 return COMPILE_OK;
4109}
4110
4111static int
4112insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4113{
4114 iobj->insn_id = insn_id;
4115 iobj->operand_size = insn_len(insn_id) - 1;
4116 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4117
4118 if (insn_id == BIN(opt_neq)) {
4119 VALUE original_ci = iobj->operands[0];
4120 iobj->operand_size = 2;
4121 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4122 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4123 iobj->operands[1] = original_ci;
4124 }
4125
4126 return COMPILE_OK;
4127}
4128
4129static int
4130iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4131{
4132 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4133 IS_INSN(iobj->link.next)) {
4134 /*
4135 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4136 */
4137 INSN *niobj = (INSN *)iobj->link.next;
4138 if (IS_INSN_ID(niobj, send)) {
4139 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4140 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4141 VALUE method = INT2FIX(0);
4142 switch (vm_ci_mid(ci)) {
4143 case idMax:
4144 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4145 break;
4146 case idMin:
4147 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4148 break;
4149 case idHash:
4150 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4151 break;
4152 }
4153
4154 if (method != INT2FIX(0)) {
4155 VALUE num = iobj->operands[0];
4156 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4157 iobj->insn_id = BIN(opt_newarray_send);
4158 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4159 iobj->operands[0] = num;
4160 iobj->operands[1] = method;
4161 iobj->operand_size = operand_len;
4162 ELEM_REMOVE(&niobj->link);
4163 return COMPILE_OK;
4164 }
4165 }
4166 }
4167 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4168 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4169 IS_NEXT_INSN_ID(&niobj->link, send)) {
4170 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4171 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4172 VALUE num = iobj->operands[0];
4173 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4174 iobj->insn_id = BIN(opt_newarray_send);
4175 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4176 iobj->operands[0] = FIXNUM_INC(num, 1);
4177 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4178 iobj->operand_size = operand_len;
4179 ELEM_REMOVE(&iobj->link);
4180 ELEM_REMOVE(niobj->link.next);
4181 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4182 return COMPILE_OK;
4183 }
4184 }
4185 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4186 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4187 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4188 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4189 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4190 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4191 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4192 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4193 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4194 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4195 VALUE num = iobj->operands[0];
4196 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4197 iobj->insn_id = BIN(opt_newarray_send);
4198 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4199 iobj->operands[0] = FIXNUM_INC(num, 2);
4200 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4201 iobj->operand_size = operand_len;
4202 // Remove the "send" insn.
4203 ELEM_REMOVE((niobj->link.next)->next);
4204 // Remove the modified insn from its original "newarray" position...
4205 ELEM_REMOVE(&iobj->link);
4206 // and insert it after the buffer insn.
4207 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4208 return COMPILE_OK;
4209 }
4210 }
4211
4212 // Break the "else if" chain since some prior checks abort after sub-ifs.
4213 // We already found "newarray". To match `[...].include?(arg)` we look for
4214 // the instruction(s) representing the argument followed by a "send".
4215 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4216 IS_INSN_ID(niobj, putobject) ||
4217 IS_INSN_ID(niobj, putself) ||
4218 IS_INSN_ID(niobj, getlocal) ||
4219 IS_INSN_ID(niobj, getinstancevariable)) &&
4220 IS_NEXT_INSN_ID(&niobj->link, send)) {
4221
4222 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4223 const struct rb_callinfo *ci;
4224 // Allow any number (0 or more) of simple method calls on the argument
4225 // (as in `[...].include?(arg.method1.method2)`.
4226 do {
4227 sendobj = sendobj->next;
4228 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4229 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4230
4231 // If this send is for .include? with one arg we can do our opt.
4232 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4233 VALUE num = iobj->operands[0];
4234 INSN *sendins = (INSN *)sendobj;
4235 sendins->insn_id = BIN(opt_newarray_send);
4236 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4237 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4238 sendins->operands[0] = FIXNUM_INC(num, 1);
4239 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4240 // Remove the original "newarray" insn.
4241 ELEM_REMOVE(&iobj->link);
4242 return COMPILE_OK;
4243 }
4244 }
4245 }
4246
4247 /*
4248 * duparray [...]
4249 * some insn for the arg...
4250 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4251 * =>
4252 * arg insn...
4253 * opt_duparray_send [...], :include?, 1
4254 */
4255 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4256 INSN *niobj = (INSN *)iobj->link.next;
4257 if ((IS_INSN_ID(niobj, getlocal) ||
4258 IS_INSN_ID(niobj, getinstancevariable) ||
4259 IS_INSN_ID(niobj, putself)) &&
4260 IS_NEXT_INSN_ID(&niobj->link, send)) {
4261
4262 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4263 const struct rb_callinfo *ci;
4264 // Allow any number (0 or more) of simple method calls on the argument
4265 // (as in `[...].include?(arg.method1.method2)`.
4266 do {
4267 sendobj = sendobj->next;
4268 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4269 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4270
4271 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4272 // Move the array arg from duparray to opt_duparray_send.
4273 VALUE ary = iobj->operands[0];
4275
4276 INSN *sendins = (INSN *)sendobj;
4277 sendins->insn_id = BIN(opt_duparray_send);
4278 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4279 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4280 sendins->operands[0] = ary;
4281 sendins->operands[1] = rb_id2sym(idIncludeP);
4282 sendins->operands[2] = INT2FIX(1);
4283
4284 // Remove the duparray insn.
4285 ELEM_REMOVE(&iobj->link);
4286 return COMPILE_OK;
4287 }
4288 }
4289 }
4290
4291
4292 if (IS_INSN_ID(iobj, send)) {
4293 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4294 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4295
4296#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4297 if (vm_ci_simple(ci)) {
4298 switch (vm_ci_argc(ci)) {
4299 case 0:
4300 switch (vm_ci_mid(ci)) {
4301 case idLength: SP_INSN(length); return COMPILE_OK;
4302 case idSize: SP_INSN(size); return COMPILE_OK;
4303 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4304 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4305 case idSucc: SP_INSN(succ); return COMPILE_OK;
4306 case idNot: SP_INSN(not); return COMPILE_OK;
4307 }
4308 break;
4309 case 1:
4310 switch (vm_ci_mid(ci)) {
4311 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4312 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4313 case idMULT: SP_INSN(mult); return COMPILE_OK;
4314 case idDIV: SP_INSN(div); return COMPILE_OK;
4315 case idMOD: SP_INSN(mod); return COMPILE_OK;
4316 case idEq: SP_INSN(eq); return COMPILE_OK;
4317 case idNeq: SP_INSN(neq); return COMPILE_OK;
4318 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4319 case idLT: SP_INSN(lt); return COMPILE_OK;
4320 case idLE: SP_INSN(le); return COMPILE_OK;
4321 case idGT: SP_INSN(gt); return COMPILE_OK;
4322 case idGE: SP_INSN(ge); return COMPILE_OK;
4323 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4324 case idAREF: SP_INSN(aref); return COMPILE_OK;
4325 case idAnd: SP_INSN(and); return COMPILE_OK;
4326 case idOr: SP_INSN(or); return COMPILE_OK;
4327 }
4328 break;
4329 case 2:
4330 switch (vm_ci_mid(ci)) {
4331 case idASET: SP_INSN(aset); return COMPILE_OK;
4332 }
4333 break;
4334 }
4335 }
4336
4337 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4338 iobj->insn_id = BIN(opt_send_without_block);
4339 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4340 }
4341 }
4342#undef SP_INSN
4343
4344 return COMPILE_OK;
4345}
4346
4347static inline int
4348tailcallable_p(rb_iseq_t *iseq)
4349{
4350 switch (ISEQ_BODY(iseq)->type) {
4351 case ISEQ_TYPE_TOP:
4352 case ISEQ_TYPE_EVAL:
4353 case ISEQ_TYPE_MAIN:
4354 /* not tail callable because cfp will be over popped */
4355 case ISEQ_TYPE_RESCUE:
4356 case ISEQ_TYPE_ENSURE:
4357 /* rescue block can't tail call because of errinfo */
4358 return FALSE;
4359 default:
4360 return TRUE;
4361 }
4362}
4363
4364static int
4365iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4366{
4367 LINK_ELEMENT *list;
4368 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4369 const int do_tailcallopt = tailcallable_p(iseq) &&
4370 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4371 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4372 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4373 int rescue_level = 0;
4374 int tailcallopt = do_tailcallopt;
4375
4376 list = FIRST_ELEMENT(anchor);
4377
4378 int do_block_optimization = 0;
4379 LABEL * block_loop_label = NULL;
4380
4381 // If we're optimizing a block
4382 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4383 do_block_optimization = 1;
4384
4385 // If the block starts with a nop and a label,
4386 // record the label so we can detect if it's a jump target
4387 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4388 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4389 block_loop_label = (LABEL *)le->next;
4390 }
4391 }
4392
4393 while (list) {
4394 if (IS_INSN(list)) {
4395 if (do_peepholeopt) {
4396 iseq_peephole_optimize(iseq, list, tailcallopt);
4397 }
4398 if (do_si) {
4399 iseq_specialized_instruction(iseq, (INSN *)list);
4400 }
4401 if (do_ou) {
4402 insn_operands_unification((INSN *)list);
4403 }
4404
4405 if (do_block_optimization) {
4406 INSN * item = (INSN *)list;
4407 // Give up if there is a throw
4408 if (IS_INSN_ID(item, throw)) {
4409 do_block_optimization = 0;
4410 }
4411 else {
4412 // If the instruction has a jump target, check if the
4413 // jump target is the block loop label
4414 const char *types = insn_op_types(item->insn_id);
4415 for (int j = 0; types[j]; j++) {
4416 if (types[j] == TS_OFFSET) {
4417 // If the jump target is equal to the block loop
4418 // label, then we can't do the optimization because
4419 // the leading `nop` instruction fires the block
4420 // entry tracepoint
4421 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4422 if (target == block_loop_label) {
4423 do_block_optimization = 0;
4424 }
4425 }
4426 }
4427 }
4428 }
4429 }
4430 if (IS_LABEL(list)) {
4431 switch (((LABEL *)list)->rescued) {
4432 case LABEL_RESCUE_BEG:
4433 rescue_level++;
4434 tailcallopt = FALSE;
4435 break;
4436 case LABEL_RESCUE_END:
4437 if (!--rescue_level) tailcallopt = do_tailcallopt;
4438 break;
4439 }
4440 }
4441 list = list->next;
4442 }
4443
4444 if (do_block_optimization) {
4445 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4446 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4447 ELEM_REMOVE(le);
4448 }
4449 }
4450 return COMPILE_OK;
4451}
4452
4453#if OPT_INSTRUCTIONS_UNIFICATION
4454static INSN *
4455new_unified_insn(rb_iseq_t *iseq,
4456 int insn_id, int size, LINK_ELEMENT *seq_list)
4457{
4458 INSN *iobj = 0;
4459 LINK_ELEMENT *list = seq_list;
4460 int i, argc = 0;
4461 VALUE *operands = 0, *ptr = 0;
4462
4463
4464 /* count argc */
4465 for (i = 0; i < size; i++) {
4466 iobj = (INSN *)list;
4467 argc += iobj->operand_size;
4468 list = list->next;
4469 }
4470
4471 if (argc > 0) {
4472 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4473 }
4474
4475 /* copy operands */
4476 list = seq_list;
4477 for (i = 0; i < size; i++) {
4478 iobj = (INSN *)list;
4479 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4480 ptr += iobj->operand_size;
4481 list = list->next;
4482 }
4483
4484 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4485}
4486#endif
4487
4488/*
4489 * This scheme can get more performance if do this optimize with
4490 * label address resolving.
4491 * It's future work (if compile time was bottle neck).
4492 */
4493static int
4494iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4495{
4496#if OPT_INSTRUCTIONS_UNIFICATION
4497 LINK_ELEMENT *list;
4498 INSN *iobj, *niobj;
4499 int id, k;
4500 intptr_t j;
4501
4502 list = FIRST_ELEMENT(anchor);
4503 while (list) {
4504 if (IS_INSN(list)) {
4505 iobj = (INSN *)list;
4506 id = iobj->insn_id;
4507 if (unified_insns_data[id] != 0) {
4508 const int *const *entry = unified_insns_data[id];
4509 for (j = 1; j < (intptr_t)entry[0]; j++) {
4510 const int *unified = entry[j];
4511 LINK_ELEMENT *li = list->next;
4512 for (k = 2; k < unified[1]; k++) {
4513 if (!IS_INSN(li) ||
4514 ((INSN *)li)->insn_id != unified[k]) {
4515 goto miss;
4516 }
4517 li = li->next;
4518 }
4519 /* matched */
4520 niobj =
4521 new_unified_insn(iseq, unified[0], unified[1] - 1,
4522 list);
4523
4524 /* insert to list */
4525 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4526 niobj->link.next = li;
4527 if (li) {
4528 li->prev = (LINK_ELEMENT *)niobj;
4529 }
4530
4531 list->prev->next = (LINK_ELEMENT *)niobj;
4532 list = (LINK_ELEMENT *)niobj;
4533 break;
4534 miss:;
4535 }
4536 }
4537 }
4538 list = list->next;
4539 }
4540#endif
4541 return COMPILE_OK;
4542}
4543
4544static int
4545all_string_result_p(const NODE *node)
4546{
4547 if (!node) return FALSE;
4548 switch (nd_type(node)) {
4549 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4550 return TRUE;
4551 case NODE_IF: case NODE_UNLESS:
4552 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4553 if (all_string_result_p(RNODE_IF(node)->nd_body))
4554 return all_string_result_p(RNODE_IF(node)->nd_else);
4555 return FALSE;
4556 case NODE_AND: case NODE_OR:
4557 if (!RNODE_AND(node)->nd_2nd)
4558 return all_string_result_p(RNODE_AND(node)->nd_1st);
4559 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4560 return FALSE;
4561 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4562 default:
4563 return FALSE;
4564 }
4565}
4566
4568 rb_iseq_t *const iseq;
4569 LINK_ANCHOR *const ret;
4570 VALUE lit;
4571 const NODE *lit_node;
4572 int cnt;
4573 int dregx;
4574};
4575
4576static int
4577append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4578{
4579 VALUE s = rb_str_new_mutable_parser_string(str);
4580 if (args->dregx) {
4581 VALUE error = rb_reg_check_preprocess(s);
4582 if (!NIL_P(error)) {
4583 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4584 return COMPILE_NG;
4585 }
4586 }
4587 if (NIL_P(args->lit)) {
4588 args->lit = s;
4589 args->lit_node = node;
4590 }
4591 else {
4592 rb_str_buf_append(args->lit, s);
4593 }
4594 return COMPILE_OK;
4595}
4596
4597static void
4598flush_dstr_fragment(struct dstr_ctxt *args)
4599{
4600 if (!NIL_P(args->lit)) {
4601 rb_iseq_t *iseq = args->iseq;
4602 VALUE lit = args->lit;
4603 args->lit = Qnil;
4604 lit = rb_fstring(lit);
4605 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4606 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4607 args->cnt++;
4608 }
4609}
4610
4611static int
4612compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4613{
4614 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4615 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4616
4617 if (str) {
4618 CHECK(append_dstr_fragment(args, node, str));
4619 }
4620
4621 while (list) {
4622 const NODE *const head = list->nd_head;
4623 if (nd_type_p(head, NODE_STR)) {
4624 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4625 }
4626 else if (nd_type_p(head, NODE_DSTR)) {
4627 CHECK(compile_dstr_fragments_0(args, head));
4628 }
4629 else {
4630 flush_dstr_fragment(args);
4631 rb_iseq_t *iseq = args->iseq;
4632 CHECK(COMPILE(args->ret, "each string", head));
4633 args->cnt++;
4634 }
4635 list = (struct RNode_LIST *)list->nd_next;
4636 }
4637 return COMPILE_OK;
4638}
4639
4640static int
4641compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4642{
4643 struct dstr_ctxt args = {
4644 .iseq = iseq, .ret = ret,
4645 .lit = Qnil, .lit_node = NULL,
4646 .cnt = 0, .dregx = dregx,
4647 };
4648 CHECK(compile_dstr_fragments_0(&args, node));
4649 flush_dstr_fragment(&args);
4650
4651 *cntp = args.cnt;
4652
4653 return COMPILE_OK;
4654}
4655
4656static int
4657compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4658{
4659 while (node && nd_type_p(node, NODE_BLOCK)) {
4660 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4661 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4662 node = RNODE_BLOCK(node)->nd_next;
4663 }
4664 if (node) {
4665 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4666 }
4667 return COMPILE_OK;
4668}
4669
4670static int
4671compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4672{
4673 int cnt;
4674 if (!RNODE_DSTR(node)->nd_next) {
4675 VALUE lit = rb_node_dstr_string_val(node);
4676 ADD_INSN1(ret, node, putstring, lit);
4677 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4678 }
4679 else {
4680 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4681 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4682 }
4683 return COMPILE_OK;
4684}
4685
4686static int
4687compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4688{
4689 int cnt;
4690 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4691
4692 if (!RNODE_DREGX(node)->nd_next) {
4693 if (!popped) {
4694 VALUE src = rb_node_dregx_string_val(node);
4695 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4696 ADD_INSN1(ret, node, putobject, match);
4697 RB_OBJ_WRITTEN(iseq, Qundef, match);
4698 }
4699 return COMPILE_OK;
4700 }
4701
4702 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4703 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4704
4705 if (popped) {
4706 ADD_INSN(ret, node, pop);
4707 }
4708
4709 return COMPILE_OK;
4710}
4711
4712static int
4713compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4714 LABEL *then_label, LABEL *else_label)
4715{
4716 const int line = nd_line(node);
4717 LABEL *lend = NEW_LABEL(line);
4718 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4719 + VM_SVAR_FLIPFLOP_START;
4720 VALUE key = INT2FIX(cnt);
4721
4722 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4723 ADD_INSNL(ret, node, branchif, lend);
4724
4725 /* *flip == 0 */
4726 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4727 ADD_INSNL(ret, node, branchunless, else_label);
4728 ADD_INSN1(ret, node, putobject, Qtrue);
4729 ADD_INSN1(ret, node, setspecial, key);
4730 if (!again) {
4731 ADD_INSNL(ret, node, jump, then_label);
4732 }
4733
4734 /* *flip == 1 */
4735 ADD_LABEL(ret, lend);
4736 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4737 ADD_INSNL(ret, node, branchunless, then_label);
4738 ADD_INSN1(ret, node, putobject, Qfalse);
4739 ADD_INSN1(ret, node, setspecial, key);
4740 ADD_INSNL(ret, node, jump, then_label);
4741
4742 return COMPILE_OK;
4743}
4744
4745static int
4746compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4747 LABEL *then_label, LABEL *else_label);
4748
4749#define COMPILE_SINGLE 2
4750static int
4751compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4752 LABEL *then_label, LABEL *else_label)
4753{
4754 DECL_ANCHOR(seq);
4755 INIT_ANCHOR(seq);
4756 LABEL *label = NEW_LABEL(nd_line(cond));
4757 if (!then_label) then_label = label;
4758 else if (!else_label) else_label = label;
4759
4760 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4761
4762 if (LIST_INSN_SIZE_ONE(seq)) {
4763 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4764 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4765 return COMPILE_OK;
4766 }
4767 if (!label->refcnt) {
4768 return COMPILE_SINGLE;
4769 }
4770 ADD_LABEL(seq, label);
4771 ADD_SEQ(ret, seq);
4772 return COMPILE_OK;
4773}
4774
4775static int
4776compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4777 LABEL *then_label, LABEL *else_label)
4778{
4779 int ok;
4780 DECL_ANCHOR(ignore);
4781
4782 again:
4783 switch (nd_type(cond)) {
4784 case NODE_AND:
4785 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4786 cond = RNODE_AND(cond)->nd_2nd;
4787 if (ok == COMPILE_SINGLE) {
4788 INIT_ANCHOR(ignore);
4789 ret = ignore;
4790 then_label = NEW_LABEL(nd_line(cond));
4791 }
4792 goto again;
4793 case NODE_OR:
4794 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4795 cond = RNODE_OR(cond)->nd_2nd;
4796 if (ok == COMPILE_SINGLE) {
4797 INIT_ANCHOR(ignore);
4798 ret = ignore;
4799 else_label = NEW_LABEL(nd_line(cond));
4800 }
4801 goto again;
4802 case NODE_SYM:
4803 case NODE_LINE:
4804 case NODE_FILE:
4805 case NODE_ENCODING:
4806 case NODE_INTEGER: /* NODE_INTEGER is always true */
4807 case NODE_FLOAT: /* NODE_FLOAT is always true */
4808 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4809 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4810 case NODE_TRUE:
4811 case NODE_STR:
4812 case NODE_REGX:
4813 case NODE_ZLIST:
4814 case NODE_LAMBDA:
4815 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4816 ADD_INSNL(ret, cond, jump, then_label);
4817 return COMPILE_OK;
4818 case NODE_FALSE:
4819 case NODE_NIL:
4820 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4821 ADD_INSNL(ret, cond, jump, else_label);
4822 return COMPILE_OK;
4823 case NODE_LIST:
4824 case NODE_ARGSCAT:
4825 case NODE_DREGX:
4826 case NODE_DSTR:
4827 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4828 ADD_INSNL(ret, cond, jump, then_label);
4829 return COMPILE_OK;
4830 case NODE_FLIP2:
4831 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4832 return COMPILE_OK;
4833 case NODE_FLIP3:
4834 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4835 return COMPILE_OK;
4836 case NODE_DEFINED:
4837 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4838 break;
4839 default:
4840 {
4841 DECL_ANCHOR(cond_seq);
4842 INIT_ANCHOR(cond_seq);
4843
4844 CHECK(COMPILE(cond_seq, "branch condition", cond));
4845
4846 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4847 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4848 if (insn->insn_id == BIN(putobject)) {
4849 if (RTEST(insn->operands[0])) {
4850 ADD_INSNL(ret, cond, jump, then_label);
4851 // maybe unreachable
4852 return COMPILE_OK;
4853 }
4854 else {
4855 ADD_INSNL(ret, cond, jump, else_label);
4856 return COMPILE_OK;
4857 }
4858 }
4859 }
4860 ADD_SEQ(ret, cond_seq);
4861 }
4862 break;
4863 }
4864
4865 ADD_INSNL(ret, cond, branchunless, else_label);
4866 ADD_INSNL(ret, cond, jump, then_label);
4867 return COMPILE_OK;
4868}
4869
4870#define HASH_BRACE 1
4871
4872static int
4873keyword_node_p(const NODE *const node)
4874{
4875 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4876}
4877
4878static VALUE
4879get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4880{
4881 switch (nd_type(node)) {
4882 case NODE_SYM:
4883 return rb_node_sym_string_val(node);
4884 default:
4885 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4886 }
4887}
4888
4889static VALUE
4890node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4891{
4892 NODE *node = node_hash->nd_head;
4893 VALUE hash = rb_hash_new();
4894 VALUE ary = rb_ary_new();
4895
4896 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4897 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4898 VALUE idx = rb_hash_aref(hash, key);
4899 if (!NIL_P(idx)) {
4900 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4901 (*count_ptr)--;
4902 }
4903 rb_hash_aset(hash, key, INT2FIX(i));
4904 rb_ary_store(ary, i, Qtrue);
4905 (*count_ptr)++;
4906 }
4907
4908 return ary;
4909}
4910
4911static int
4912compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4913 const NODE *const root_node,
4914 struct rb_callinfo_kwarg **const kw_arg_ptr,
4915 unsigned int *flag)
4916{
4917 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4918 RUBY_ASSERT(kw_arg_ptr != NULL);
4919 RUBY_ASSERT(flag != NULL);
4920
4921 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4922 const NODE *node = RNODE_HASH(root_node)->nd_head;
4923 int seen_nodes = 0;
4924
4925 while (node) {
4926 const NODE *key_node = RNODE_LIST(node)->nd_head;
4927 seen_nodes++;
4928
4929 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4930 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4931 /* can be keywords */
4932 }
4933 else {
4934 if (flag) {
4935 *flag |= VM_CALL_KW_SPLAT;
4936 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4937 /* A new hash will be created for the keyword arguments
4938 * in this case, so mark the method as passing mutable
4939 * keyword splat.
4940 */
4941 *flag |= VM_CALL_KW_SPLAT_MUT;
4942 }
4943 }
4944 return FALSE;
4945 }
4946 node = RNODE_LIST(node)->nd_next; /* skip value node */
4947 node = RNODE_LIST(node)->nd_next;
4948 }
4949
4950 /* may be keywords */
4951 node = RNODE_HASH(root_node)->nd_head;
4952 {
4953 int len = 0;
4954 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4955 struct rb_callinfo_kwarg *kw_arg =
4956 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4957 VALUE *keywords = kw_arg->keywords;
4958 int i = 0;
4959 int j = 0;
4960 kw_arg->references = 0;
4961 kw_arg->keyword_len = len;
4962
4963 *kw_arg_ptr = kw_arg;
4964
4965 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4966 const NODE *key_node = RNODE_LIST(node)->nd_head;
4967 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4968 int popped = TRUE;
4969 if (rb_ary_entry(key_index, i)) {
4970 keywords[j] = get_symbol_value(iseq, key_node);
4971 j++;
4972 popped = FALSE;
4973 }
4974 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4975 }
4976 RUBY_ASSERT(j == len);
4977 return TRUE;
4978 }
4979 }
4980 return FALSE;
4981}
4982
4983static int
4984compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4985{
4986 int len = 0;
4987
4988 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4989 if (CPDEBUG > 0) {
4990 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4991 }
4992
4993 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4994 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4995 }
4996 else {
4997 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4998 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4999 }
5000 }
5001
5002 return len;
5003}
5004
5005static inline bool
5006frozen_string_literal_p(const rb_iseq_t *iseq)
5007{
5008 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5009}
5010
5011static inline bool
5012static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5013{
5014 switch (nd_type(node)) {
5015 case NODE_SYM:
5016 case NODE_REGX:
5017 case NODE_LINE:
5018 case NODE_ENCODING:
5019 case NODE_INTEGER:
5020 case NODE_FLOAT:
5021 case NODE_RATIONAL:
5022 case NODE_IMAGINARY:
5023 case NODE_NIL:
5024 case NODE_TRUE:
5025 case NODE_FALSE:
5026 return TRUE;
5027 case NODE_STR:
5028 case NODE_FILE:
5029 return hash_key || frozen_string_literal_p(iseq);
5030 default:
5031 return FALSE;
5032 }
5033}
5034
5035static inline VALUE
5036static_literal_value(const NODE *node, rb_iseq_t *iseq)
5037{
5038 switch (nd_type(node)) {
5039 case NODE_INTEGER:
5040 return rb_node_integer_literal_val(node);
5041 case NODE_FLOAT:
5042 return rb_node_float_literal_val(node);
5043 case NODE_RATIONAL:
5044 return rb_node_rational_literal_val(node);
5045 case NODE_IMAGINARY:
5046 return rb_node_imaginary_literal_val(node);
5047 case NODE_NIL:
5048 return Qnil;
5049 case NODE_TRUE:
5050 return Qtrue;
5051 case NODE_FALSE:
5052 return Qfalse;
5053 case NODE_SYM:
5054 return rb_node_sym_string_val(node);
5055 case NODE_REGX:
5056 return rb_node_regx_string_val(node);
5057 case NODE_LINE:
5058 return rb_node_line_lineno_val(node);
5059 case NODE_ENCODING:
5060 return rb_node_encoding_val(node);
5061 case NODE_FILE:
5062 case NODE_STR:
5063 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5064 VALUE lit = get_string_value(node);
5065 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5066 }
5067 else {
5068 return get_string_value(node);
5069 }
5070 default:
5071 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5072 }
5073}
5074
5075static int
5076compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5077{
5078 const NODE *line_node = node;
5079
5080 if (nd_type_p(node, NODE_ZLIST)) {
5081 if (!popped) {
5082 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5083 }
5084 return 0;
5085 }
5086
5087 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5088
5089 if (popped) {
5090 for (; node; node = RNODE_LIST(node)->nd_next) {
5091 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5092 }
5093 return 1;
5094 }
5095
5096 /* Compilation of an array literal.
5097 * The following code is essentially the same as:
5098 *
5099 * for (int count = 0; node; count++; node->nd_next) {
5100 * compile(node->nd_head);
5101 * }
5102 * ADD_INSN(newarray, count);
5103 *
5104 * However, there are three points.
5105 *
5106 * - The code above causes stack overflow for a big string literal.
5107 * The following limits the stack length up to max_stack_len.
5108 *
5109 * [x1,x2,...,x10000] =>
5110 * push x1 ; push x2 ; ...; push x256; newarray 256;
5111 * push x257; push x258; ...; push x512; pushtoarray 256;
5112 * push x513; push x514; ...; push x768; pushtoarray 256;
5113 * ...
5114 *
5115 * - Long subarray can be optimized by pre-allocating a hidden array.
5116 *
5117 * [1,2,3,...,100] =>
5118 * duparray [1,2,3,...,100]
5119 *
5120 * [x, 1,2,3,...,100, z] =>
5121 * push x; newarray 1;
5122 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5123 * push z; pushtoarray 1;
5124 *
5125 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5126 * to only push it onto the array if it is not empty
5127 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5128 *
5129 * [1,2,3,**kw] =>
5130 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5131 */
5132
5133 const int max_stack_len = 0x100;
5134 const int min_tmp_ary_len = 0x40;
5135 int stack_len = 0;
5136
5137 /* Either create a new array, or push to the existing array */
5138#define FLUSH_CHUNK \
5139 if (stack_len) { \
5140 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5141 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5142 first_chunk = FALSE; \
5143 stack_len = 0; \
5144 }
5145
5146 while (node) {
5147 int count = 1;
5148
5149 /* pre-allocation check (this branch can be omittable) */
5150 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5151 /* count the elements that are optimizable */
5152 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5153 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5154 count++;
5155
5156 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5157 /* The literal contains only optimizable elements, or the subarray is long enough */
5158 VALUE ary = rb_ary_hidden_new(count);
5159
5160 /* Create a hidden array */
5161 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5162 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5163 OBJ_FREEZE(ary);
5164
5165 /* Emit optimized code */
5166 FLUSH_CHUNK;
5167 if (first_chunk) {
5168 ADD_INSN1(ret, line_node, duparray, ary);
5169 first_chunk = FALSE;
5170 }
5171 else {
5172 ADD_INSN1(ret, line_node, putobject, ary);
5173 ADD_INSN(ret, line_node, concattoarray);
5174 }
5175 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5176 }
5177 }
5178
5179 /* Base case: Compile "count" elements */
5180 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5181 if (CPDEBUG > 0) {
5182 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5183 }
5184
5185 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5186 /* Create array or push existing non-keyword elements onto array */
5187 if (stack_len == 0 && first_chunk) {
5188 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5189 }
5190 else {
5191 FLUSH_CHUNK;
5192 }
5193 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5194 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5195 return 1;
5196 }
5197 else {
5198 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5199 stack_len++;
5200 }
5201
5202 /* If there are many pushed elements, flush them to avoid stack overflow */
5203 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5204 }
5205 }
5206
5207 FLUSH_CHUNK;
5208#undef FLUSH_CHUNK
5209 return 1;
5210}
5211
5212static inline int
5213static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5214{
5215 return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, true) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq, false);
5216}
5217
5218static int
5219compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5220{
5221 const NODE *line_node = node;
5222
5223 node = RNODE_HASH(node)->nd_head;
5224
5225 if (!node || nd_type_p(node, NODE_ZLIST)) {
5226 if (!popped) {
5227 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5228 }
5229 return 0;
5230 }
5231
5232 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5233
5234 if (popped) {
5235 for (; node; node = RNODE_LIST(node)->nd_next) {
5236 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5237 }
5238 return 1;
5239 }
5240
5241 /* Compilation of a hash literal (or keyword arguments).
5242 * This is very similar to compile_array, but there are some differences:
5243 *
5244 * - It contains key-value pairs. So we need to take every two elements.
5245 * We can assume that the length is always even.
5246 *
5247 * - Merging is done by a method call (id_core_hash_merge_ptr).
5248 * Sometimes we need to insert the receiver, so "anchor" is needed.
5249 * In addition, a method call is much slower than concatarray.
5250 * So it pays only when the subsequence is really long.
5251 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5252 *
5253 * - We need to handle keyword splat: **kw.
5254 * For **kw, the key part (node->nd_head) is NULL, and the value part
5255 * (node->nd_next->nd_head) is "kw".
5256 * The code is a bit difficult to avoid hash allocation for **{}.
5257 */
5258
5259 const int max_stack_len = 0x100;
5260 const int min_tmp_hash_len = 0x800;
5261 int stack_len = 0;
5262 int first_chunk = 1;
5263 DECL_ANCHOR(anchor);
5264 INIT_ANCHOR(anchor);
5265
5266 /* Convert pushed elements to a hash, and merge if needed */
5267#define FLUSH_CHUNK() \
5268 if (stack_len) { \
5269 if (first_chunk) { \
5270 APPEND_LIST(ret, anchor); \
5271 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5272 } \
5273 else { \
5274 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5275 ADD_INSN(ret, line_node, swap); \
5276 APPEND_LIST(ret, anchor); \
5277 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5278 } \
5279 INIT_ANCHOR(anchor); \
5280 first_chunk = stack_len = 0; \
5281 }
5282
5283 while (node) {
5284 int count = 1;
5285
5286 /* pre-allocation check (this branch can be omittable) */
5287 if (static_literal_node_pair_p(node, iseq)) {
5288 /* count the elements that are optimizable */
5289 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5290 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5291 count++;
5292
5293 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5294 /* The literal contains only optimizable elements, or the subsequence is long enough */
5295 VALUE ary = rb_ary_hidden_new(count);
5296
5297 /* Create a hidden hash */
5298 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5299 VALUE elem[2];
5300 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5301 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5302 rb_ary_cat(ary, elem, 2);
5303 }
5304 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5305 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5306 hash = rb_obj_hide(hash);
5307 OBJ_FREEZE(hash);
5308
5309 /* Emit optimized code */
5310 FLUSH_CHUNK();
5311 if (first_chunk) {
5312 ADD_INSN1(ret, line_node, duphash, hash);
5313 first_chunk = 0;
5314 }
5315 else {
5316 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5317 ADD_INSN(ret, line_node, swap);
5318
5319 ADD_INSN1(ret, line_node, putobject, hash);
5320
5321 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5322 }
5323 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5324 }
5325 }
5326
5327 /* Base case: Compile "count" elements */
5328 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5329
5330 if (CPDEBUG > 0) {
5331 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5332 }
5333
5334 if (RNODE_LIST(node)->nd_head) {
5335 /* Normal key-value pair */
5336 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5337 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5338 stack_len += 2;
5339
5340 /* If there are many pushed elements, flush them to avoid stack overflow */
5341 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5342 }
5343 else {
5344 /* kwsplat case: foo(..., **kw, ...) */
5345 FLUSH_CHUNK();
5346
5347 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5348 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5349 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5350 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5351 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5352
5353 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5354 if (empty_kw) {
5355 if (only_kw && method_call_keywords) {
5356 /* **{} appears at the only keyword argument in method call,
5357 * so it won't be modified.
5358 * kw is a special NODE_LIT that contains a special empty hash,
5359 * so this emits: putobject {}.
5360 * This is only done for method calls and not for literal hashes,
5361 * because literal hashes should always result in a new hash.
5362 */
5363 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5364 }
5365 else if (first_kw) {
5366 /* **{} appears as the first keyword argument, so it may be modified.
5367 * We need to create a fresh hash object.
5368 */
5369 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5370 }
5371 /* Any empty keyword splats that are not the first can be ignored.
5372 * since merging an empty hash into the existing hash is the same
5373 * as not merging it. */
5374 }
5375 else {
5376 if (only_kw && method_call_keywords) {
5377 /* **kw is only keyword argument in method call.
5378 * Use directly. This will be not be flagged as mutable.
5379 * This is only done for method calls and not for literal hashes,
5380 * because literal hashes should always result in a new hash.
5381 */
5382 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5383 }
5384 else {
5385 /* There is more than one keyword argument, or this is not a method
5386 * call. In that case, we need to add an empty hash (if first keyword),
5387 * or merge the hash to the accumulated hash (if not the first keyword).
5388 */
5389 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5390 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5391 else ADD_INSN(ret, line_node, swap);
5392
5393 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5394
5395 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5396 }
5397 }
5398
5399 first_chunk = 0;
5400 }
5401 }
5402 }
5403
5404 FLUSH_CHUNK();
5405#undef FLUSH_CHUNK
5406 return 1;
5407}
5408
5409VALUE
5410rb_node_case_when_optimizable_literal(const NODE *const node)
5411{
5412 switch (nd_type(node)) {
5413 case NODE_INTEGER:
5414 return rb_node_integer_literal_val(node);
5415 case NODE_FLOAT: {
5416 VALUE v = rb_node_float_literal_val(node);
5417 double ival;
5418
5419 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5420 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5421 }
5422 return v;
5423 }
5424 case NODE_RATIONAL:
5425 case NODE_IMAGINARY:
5426 return Qundef;
5427 case NODE_NIL:
5428 return Qnil;
5429 case NODE_TRUE:
5430 return Qtrue;
5431 case NODE_FALSE:
5432 return Qfalse;
5433 case NODE_SYM:
5434 return rb_node_sym_string_val(node);
5435 case NODE_LINE:
5436 return rb_node_line_lineno_val(node);
5437 case NODE_STR:
5438 return rb_node_str_string_val(node);
5439 case NODE_FILE:
5440 return rb_node_file_path_val(node);
5441 }
5442 return Qundef;
5443}
5444
5445static int
5446when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5447 LABEL *l1, int only_special_literals, VALUE literals)
5448{
5449 while (vals) {
5450 const NODE *val = RNODE_LIST(vals)->nd_head;
5451 VALUE lit = rb_node_case_when_optimizable_literal(val);
5452
5453 if (UNDEF_P(lit)) {
5454 only_special_literals = 0;
5455 }
5456 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5457 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5458 }
5459
5460 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5461 debugp_param("nd_lit", get_string_value(val));
5462 lit = get_string_value(val);
5463 ADD_INSN1(cond_seq, val, putobject, lit);
5464 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5465 }
5466 else {
5467 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5468 }
5469
5470 // Emit pattern === target
5471 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5472 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5473 ADD_INSNL(cond_seq, val, branchif, l1);
5474 vals = RNODE_LIST(vals)->nd_next;
5475 }
5476 return only_special_literals;
5477}
5478
5479static int
5480when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5481 LABEL *l1, int only_special_literals, VALUE literals)
5482{
5483 const NODE *line_node = vals;
5484
5485 switch (nd_type(vals)) {
5486 case NODE_LIST:
5487 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5488 return COMPILE_NG;
5489 break;
5490 case NODE_SPLAT:
5491 ADD_INSN (cond_seq, line_node, dup);
5492 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5493 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5494 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5495 ADD_INSNL(cond_seq, line_node, branchif, l1);
5496 break;
5497 case NODE_ARGSCAT:
5498 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5499 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5500 break;
5501 case NODE_ARGSPUSH:
5502 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5503 ADD_INSN (cond_seq, line_node, dup);
5504 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5505 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5506 ADD_INSNL(cond_seq, line_node, branchif, l1);
5507 break;
5508 default:
5509 ADD_INSN (cond_seq, line_node, dup);
5510 CHECK(COMPILE(cond_seq, "when val", vals));
5511 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5512 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5513 ADD_INSNL(cond_seq, line_node, branchif, l1);
5514 break;
5515 }
5516 return COMPILE_OK;
5517}
5518
5519/* Multiple Assignment Handling
5520 *
5521 * In order to handle evaluation of multiple assignment such that the left hand side
5522 * is evaluated before the right hand side, we need to process the left hand side
5523 * and see if there are any attributes that need to be assigned, or constants set
5524 * on explicit objects. If so, we add instructions to evaluate the receiver of
5525 * any assigned attributes or constants before we process the right hand side.
5526 *
5527 * For a multiple assignment such as:
5528 *
5529 * l1.m1, l2[0] = r3, r4
5530 *
5531 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5532 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5533 * On the VM stack, this looks like:
5534 *
5535 * self # putself
5536 * l1 # send
5537 * l1, self # putself
5538 * l1, l2 # send
5539 * l1, l2, 0 # putobject 0
5540 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5541 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5542 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5543 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5544 * l1, l2, 0, [r3, r4], r4, m1= # send
5545 * l1, l2, 0, [r3, r4], r4 # pop
5546 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5547 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5548 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5549 * l1, l2, 0, [r3, r4], r4, []= # send
5550 * l1, l2, 0, [r3, r4], r4 # pop
5551 * l1, l2, 0, [r3, r4] # pop
5552 * [r3, r4], l2, 0, [r3, r4] # setn 3
5553 * [r3, r4], l2, 0 # pop
5554 * [r3, r4], l2 # pop
5555 * [r3, r4] # pop
5556 *
5557 * This is made more complex when you have to handle splats, post args,
5558 * and arbitrary levels of nesting. You need to keep track of the total
5559 * number of attributes to set, and for each attribute, how many entries
5560 * are on the stack before the final attribute, in order to correctly
5561 * calculate the topn value to use to get the receiver of the attribute
5562 * setter method.
5563 *
5564 * A brief description of the VM stack for simple multiple assignment
5565 * with no splat (rhs_array will not be present if the return value of
5566 * the multiple assignment is not needed):
5567 *
5568 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5569 *
5570 * For multiple assignment with splats, while processing the part before
5571 * the splat (splat+post here is an array of the splat and the post arguments):
5572 *
5573 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5574 *
5575 * When processing the splat and post arguments:
5576 *
5577 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5578 *
5579 * When processing nested multiple assignment, existing values on the stack
5580 * are kept. So for:
5581 *
5582 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5583 *
5584 * The stack layout would be the following before processing the nested
5585 * multiple assignment:
5586 *
5587 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5588 *
5589 * In order to handle this correctly, we need to keep track of the nesting
5590 * level for each attribute assignment, as well as the attribute number
5591 * (left hand side attributes are processed left to right) and number of
5592 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5593 * this information.
5594 *
5595 * We also need to track information for the entire multiple assignment, such
5596 * as the total number of arguments, and the current nesting level, to
5597 * handle both nested multiple assignment as well as cases where the
5598 * rhs is not needed. We also need to keep track of all attribute
5599 * assignments in this, which we do using a linked listed. struct masgn_state
5600 * tracks this information.
5601 */
5602
5604 INSN *before_insn;
5605 struct masgn_lhs_node *next;
5606 const NODE *line_node;
5607 int argn;
5608 int num_args;
5609 int lhs_pos;
5610};
5611
5613 struct masgn_lhs_node *first_memo;
5614 struct masgn_lhs_node *last_memo;
5615 int lhs_level;
5616 int num_args;
5617 bool nested;
5618};
5619
5620static int
5621add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5622{
5623 if (!state) {
5624 rb_bug("no masgn_state");
5625 }
5626
5627 struct masgn_lhs_node *memo;
5628 memo = malloc(sizeof(struct masgn_lhs_node));
5629 if (!memo) {
5630 return COMPILE_NG;
5631 }
5632
5633 memo->before_insn = before_insn;
5634 memo->line_node = line_node;
5635 memo->argn = state->num_args + 1;
5636 memo->num_args = argc;
5637 state->num_args += argc;
5638 memo->lhs_pos = lhs_pos;
5639 memo->next = NULL;
5640 if (!state->first_memo) {
5641 state->first_memo = memo;
5642 }
5643 else {
5644 state->last_memo->next = memo;
5645 }
5646 state->last_memo = memo;
5647
5648 return COMPILE_OK;
5649}
5650
5651static int compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped);
5652
5653static int
5654compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int lhs_pos)
5655{
5656 switch (nd_type(node)) {
5657 case NODE_ATTRASGN: {
5658 INSN *iobj;
5659 const NODE *line_node = node;
5660
5661 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5662
5663 bool safenav_call = false;
5664 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5665 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5666 ASSUME(iobj);
5667 ELEM_REMOVE(insn_element);
5668 if (!IS_INSN_ID(iobj, send)) {
5669 safenav_call = true;
5670 iobj = (INSN *)get_prev_insn(iobj);
5671 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5672 }
5673 (pre->last = iobj->link.prev)->next = 0;
5674
5675 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5676 int argc = vm_ci_argc(ci) + 1;
5677 ci = ci_argc_set(iseq, ci, argc);
5678 OPERAND_AT(iobj, 0) = (VALUE)ci;
5679 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5680
5681 if (argc == 1) {
5682 ADD_INSN(lhs, line_node, swap);
5683 }
5684 else {
5685 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5686 }
5687
5688 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5689 return COMPILE_NG;
5690 }
5691
5692 iobj->link.prev = lhs->last;
5693 lhs->last->next = &iobj->link;
5694 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5695 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5696 int argc = vm_ci_argc(ci);
5697 bool dupsplat = false;
5698 ci = ci_argc_set(iseq, ci, argc - 1);
5699 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5700 /* Given h[*a], _ = ary
5701 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5702 * `a` must be dupped, because it will be appended with ary[0]
5703 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5704 */
5705 dupsplat = true;
5706 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5707 }
5708 OPERAND_AT(iobj, 0) = (VALUE)ci;
5709 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5710
5711 /* Given: h[*a], h[*b, 1] = ary
5712 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5713 * so this uses splatarray true on a to dup it before using pushtoarray
5714 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5715 * so you can use pushtoarray directly
5716 */
5717 int line_no = nd_line(line_node);
5718 int node_id = nd_node_id(line_node);
5719
5720 if (dupsplat) {
5721 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5722 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5723 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5724 }
5725 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5726 }
5727 if (!safenav_call) {
5728 ADD_INSN(lhs, line_node, pop);
5729 if (argc != 1) {
5730 ADD_INSN(lhs, line_node, pop);
5731 }
5732 }
5733 for (int i=0; i < argc; i++) {
5734 ADD_INSN(post, line_node, pop);
5735 }
5736 break;
5737 }
5738 case NODE_MASGN: {
5739 DECL_ANCHOR(nest_rhs);
5740 INIT_ANCHOR(nest_rhs);
5741 DECL_ANCHOR(nest_lhs);
5742 INIT_ANCHOR(nest_lhs);
5743
5744 int prev_level = state->lhs_level;
5745 bool prev_nested = state->nested;
5746 state->nested = 1;
5747 state->lhs_level = lhs_pos - 1;
5748 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5749 state->lhs_level = prev_level;
5750 state->nested = prev_nested;
5751
5752 ADD_SEQ(lhs, nest_rhs);
5753 ADD_SEQ(lhs, nest_lhs);
5754 break;
5755 }
5756 case NODE_CDECL:
5757 if (!RNODE_CDECL(node)->nd_vid) {
5758 /* Special handling only needed for expr::C, not for C */
5759 INSN *iobj;
5760
5761 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5762
5763 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5764 iobj = (INSN *)insn_element; /* setconstant insn */
5765 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5766 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5767 ELEM_REMOVE(insn_element);
5768 pre->last = iobj->link.prev;
5769 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5770
5771 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5772 return COMPILE_NG;
5773 }
5774
5775 ADD_INSN(post, node, pop);
5776 break;
5777 }
5778 /* Fallthrough */
5779 default: {
5780 DECL_ANCHOR(anchor);
5781 INIT_ANCHOR(anchor);
5782 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5783 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5784 ADD_SEQ(lhs, anchor);
5785 }
5786 }
5787
5788 return COMPILE_OK;
5789}
5790
5791static int
5792compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5793{
5794 if (lhsn) {
5795 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5796 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5797 }
5798 return COMPILE_OK;
5799}
5800
5801static int
5802compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5803 const NODE *rhsn, const NODE *orig_lhsn)
5804{
5805 VALUE mem[64];
5806 const int memsize = numberof(mem);
5807 int memindex = 0;
5808 int llen = 0, rlen = 0;
5809 int i;
5810 const NODE *lhsn = orig_lhsn;
5811
5812#define MEMORY(v) { \
5813 int i; \
5814 if (memindex == memsize) return 0; \
5815 for (i=0; i<memindex; i++) { \
5816 if (mem[i] == (v)) return 0; \
5817 } \
5818 mem[memindex++] = (v); \
5819}
5820
5821 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5822 return 0;
5823 }
5824
5825 while (lhsn) {
5826 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5827 switch (nd_type(ln)) {
5828 case NODE_LASGN:
5829 case NODE_DASGN:
5830 case NODE_IASGN:
5831 case NODE_CVASGN:
5832 MEMORY(get_nd_vid(ln));
5833 break;
5834 default:
5835 return 0;
5836 }
5837 lhsn = RNODE_LIST(lhsn)->nd_next;
5838 llen++;
5839 }
5840
5841 while (rhsn) {
5842 if (llen <= rlen) {
5843 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5844 }
5845 else {
5846 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5847 }
5848 rhsn = RNODE_LIST(rhsn)->nd_next;
5849 rlen++;
5850 }
5851
5852 if (llen > rlen) {
5853 for (i=0; i<llen-rlen; i++) {
5854 ADD_INSN(ret, orig_lhsn, putnil);
5855 }
5856 }
5857
5858 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5859 return 1;
5860}
5861
5862static int
5863compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped)
5864{
5865 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5866 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5867 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5868 const NODE *lhsn_count = lhsn;
5869 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5870
5871 int llen = 0;
5872 int lpos = 0;
5873
5874 while (lhsn_count) {
5875 llen++;
5876 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5877 }
5878 while (lhsn) {
5879 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5880 lpos++;
5881 lhsn = RNODE_LIST(lhsn)->nd_next;
5882 }
5883
5884 if (lhs_splat) {
5885 if (nd_type_p(splatn, NODE_POSTARG)) {
5886 /*a, b, *r, p1, p2 */
5887 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5888 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5889 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5890 int ppos = 0;
5891 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5892
5893 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5894
5895 if (NODE_NAMED_REST_P(restn)) {
5896 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5897 }
5898 while (postn) {
5899 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5900 ppos++;
5901 postn = RNODE_LIST(postn)->nd_next;
5902 }
5903 }
5904 else {
5905 /* a, b, *r */
5906 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5907 }
5908 }
5909
5910 if (!state->nested) {
5911 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5912 }
5913
5914 if (!popped) {
5915 ADD_INSN(rhs, node, dup);
5916 }
5917 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5918 return COMPILE_OK;
5919}
5920
5921static int
5922compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5923{
5924 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5925 struct masgn_state state;
5926 state.lhs_level = popped ? 0 : 1;
5927 state.nested = 0;
5928 state.num_args = 0;
5929 state.first_memo = NULL;
5930 state.last_memo = NULL;
5931
5932 DECL_ANCHOR(pre);
5933 INIT_ANCHOR(pre);
5934 DECL_ANCHOR(rhs);
5935 INIT_ANCHOR(rhs);
5936 DECL_ANCHOR(lhs);
5937 INIT_ANCHOR(lhs);
5938 DECL_ANCHOR(post);
5939 INIT_ANCHOR(post);
5940 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5941
5942 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5943 while (memo) {
5944 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5945 for (int i = 0; i < memo->num_args; i++) {
5946 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5947 }
5948 tmp_memo = memo->next;
5949 free(memo);
5950 memo = tmp_memo;
5951 }
5952 CHECK(ok);
5953
5954 ADD_SEQ(ret, pre);
5955 ADD_SEQ(ret, rhs);
5956 ADD_SEQ(ret, lhs);
5957 if (!popped && state.num_args >= 1) {
5958 /* make sure rhs array is returned before popping */
5959 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5960 }
5961 ADD_SEQ(ret, post);
5962 }
5963 return COMPILE_OK;
5964}
5965
5966static VALUE
5967collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5968{
5969 VALUE arr = rb_ary_new();
5970 for (;;) {
5971 switch (nd_type(node)) {
5972 case NODE_CONST:
5973 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5974 return arr;
5975 case NODE_COLON3:
5976 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5977 rb_ary_unshift(arr, ID2SYM(idNULL));
5978 return arr;
5979 case NODE_COLON2:
5980 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5981 node = RNODE_COLON2(node)->nd_head;
5982 break;
5983 default:
5984 return Qfalse;
5985 }
5986 }
5987}
5988
5989static int
5990compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5991 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5992{
5993 switch (nd_type(node)) {
5994 case NODE_CONST:
5995 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5996 ADD_INSN1(body, node, putobject, Qtrue);
5997 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5998 break;
5999 case NODE_COLON3:
6000 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6001 ADD_INSN(body, node, pop);
6002 ADD_INSN1(body, node, putobject, rb_cObject);
6003 ADD_INSN1(body, node, putobject, Qtrue);
6004 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6005 break;
6006 case NODE_COLON2:
6007 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6008 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6009 ADD_INSN1(body, node, putobject, Qfalse);
6010 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6011 break;
6012 default:
6013 CHECK(COMPILE(pref, "const colon2 prefix", node));
6014 break;
6015 }
6016 return COMPILE_OK;
6017}
6018
6019static int
6020compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6021{
6022 if (nd_type_p(cpath, NODE_COLON3)) {
6023 /* toplevel class ::Foo */
6024 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6025 return VM_DEFINECLASS_FLAG_SCOPED;
6026 }
6027 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6028 /* Bar::Foo */
6029 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6030 return VM_DEFINECLASS_FLAG_SCOPED;
6031 }
6032 else {
6033 /* class at cbase Foo */
6034 ADD_INSN1(ret, cpath, putspecialobject,
6035 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6036 return 0;
6037 }
6038}
6039
6040static inline int
6041private_recv_p(const NODE *node)
6042{
6043 NODE *recv = get_nd_recv(node);
6044 if (recv && nd_type_p(recv, NODE_SELF)) {
6045 return RNODE_SELF(recv)->nd_state != 0;
6046 }
6047 return 0;
6048}
6049
6050static void
6051defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6052 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6053
6054static int
6055compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver);
6056
6057static void
6058defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6059 const NODE *const node, LABEL **lfinish, VALUE needstr,
6060 bool keep_result)
6061{
6062 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6063 enum node_type type;
6064 const int line = nd_line(node);
6065 const NODE *line_node = node;
6066
6067 switch (type = nd_type(node)) {
6068
6069 /* easy literals */
6070 case NODE_NIL:
6071 expr_type = DEFINED_NIL;
6072 break;
6073 case NODE_SELF:
6074 expr_type = DEFINED_SELF;
6075 break;
6076 case NODE_TRUE:
6077 expr_type = DEFINED_TRUE;
6078 break;
6079 case NODE_FALSE:
6080 expr_type = DEFINED_FALSE;
6081 break;
6082
6083 case NODE_HASH:
6084 case NODE_LIST:{
6085 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6086
6087 if (vals) {
6088 do {
6089 if (RNODE_LIST(vals)->nd_head) {
6090 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6091
6092 if (!lfinish[1]) {
6093 lfinish[1] = NEW_LABEL(line);
6094 }
6095 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6096 }
6097 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6098 }
6099 }
6100 /* fall through */
6101 case NODE_STR:
6102 case NODE_SYM:
6103 case NODE_REGX:
6104 case NODE_LINE:
6105 case NODE_FILE:
6106 case NODE_ENCODING:
6107 case NODE_INTEGER:
6108 case NODE_FLOAT:
6109 case NODE_RATIONAL:
6110 case NODE_IMAGINARY:
6111 case NODE_ZLIST:
6112 case NODE_AND:
6113 case NODE_OR:
6114 default:
6115 expr_type = DEFINED_EXPR;
6116 break;
6117
6118 case NODE_SPLAT:
6119 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6120 if (!lfinish[1]) {
6121 lfinish[1] = NEW_LABEL(line);
6122 }
6123 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6124 expr_type = DEFINED_EXPR;
6125 break;
6126
6127 /* variables */
6128 case NODE_LVAR:
6129 case NODE_DVAR:
6130 expr_type = DEFINED_LVAR;
6131 break;
6132
6133#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6134 case NODE_IVAR:
6135 ADD_INSN3(ret, line_node, definedivar,
6136 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6137 return;
6138
6139 case NODE_GVAR:
6140 ADD_INSN(ret, line_node, putnil);
6141 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6142 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6143 return;
6144
6145 case NODE_CVAR:
6146 ADD_INSN(ret, line_node, putnil);
6147 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6148 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6149 return;
6150
6151 case NODE_CONST:
6152 ADD_INSN(ret, line_node, putnil);
6153 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6154 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6155 return;
6156 case NODE_COLON2:
6157 if (!lfinish[1]) {
6158 lfinish[1] = NEW_LABEL(line);
6159 }
6160 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6161 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6162 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6163
6164 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6165 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6166 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6167 }
6168 else {
6169 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6170 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6171 }
6172 return;
6173 case NODE_COLON3:
6174 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6175 ADD_INSN3(ret, line_node, defined,
6176 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6177 return;
6178
6179 /* method dispatch */
6180 case NODE_CALL:
6181 case NODE_OPCALL:
6182 case NODE_VCALL:
6183 case NODE_FCALL:
6184 case NODE_ATTRASGN:{
6185 const int explicit_receiver =
6186 (type == NODE_CALL || type == NODE_OPCALL ||
6187 (type == NODE_ATTRASGN && !private_recv_p(node)));
6188
6189 if (get_nd_args(node) || explicit_receiver) {
6190 if (!lfinish[1]) {
6191 lfinish[1] = NEW_LABEL(line);
6192 }
6193 if (!lfinish[2]) {
6194 lfinish[2] = NEW_LABEL(line);
6195 }
6196 }
6197 if (get_nd_args(node)) {
6198 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6199 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6200 }
6201 if (explicit_receiver) {
6202 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6203 switch (nd_type(get_nd_recv(node))) {
6204 case NODE_CALL:
6205 case NODE_OPCALL:
6206 case NODE_VCALL:
6207 case NODE_FCALL:
6208 case NODE_ATTRASGN:
6209 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6210 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6211 break;
6212 default:
6213 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6214 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6215 break;
6216 }
6217 if (keep_result) {
6218 ADD_INSN(ret, line_node, dup);
6219 }
6220 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6221 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6222 }
6223 else {
6224 ADD_INSN(ret, line_node, putself);
6225 if (keep_result) {
6226 ADD_INSN(ret, line_node, dup);
6227 }
6228 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6229 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6230 }
6231 return;
6232 }
6233
6234 case NODE_YIELD:
6235 ADD_INSN(ret, line_node, putnil);
6236 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6237 PUSH_VAL(DEFINED_YIELD));
6238 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6239 return;
6240
6241 case NODE_BACK_REF:
6242 case NODE_NTH_REF:
6243 ADD_INSN(ret, line_node, putnil);
6244 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6245 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6246 PUSH_VAL(DEFINED_GVAR));
6247 return;
6248
6249 case NODE_SUPER:
6250 case NODE_ZSUPER:
6251 ADD_INSN(ret, line_node, putnil);
6252 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6253 PUSH_VAL(DEFINED_ZSUPER));
6254 return;
6255
6256#undef PUSH_VAL
6257 case NODE_OP_ASGN1:
6258 case NODE_OP_ASGN2:
6259 case NODE_OP_ASGN_OR:
6260 case NODE_OP_ASGN_AND:
6261 case NODE_MASGN:
6262 case NODE_LASGN:
6263 case NODE_DASGN:
6264 case NODE_GASGN:
6265 case NODE_IASGN:
6266 case NODE_CDECL:
6267 case NODE_CVASGN:
6268 case NODE_OP_CDECL:
6269 expr_type = DEFINED_ASGN;
6270 break;
6271 }
6272
6273 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6274
6275 if (needstr != Qfalse) {
6276 VALUE str = rb_iseq_defined_string(expr_type);
6277 ADD_INSN1(ret, line_node, putobject, str);
6278 }
6279 else {
6280 ADD_INSN1(ret, line_node, putobject, Qtrue);
6281 }
6282}
6283
6284static void
6285build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6286{
6287 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6288 iseq_set_exception_local_table(iseq);
6289}
6290
6291static void
6292defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6293 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6294{
6295 LINK_ELEMENT *lcur = ret->last;
6296 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6297 if (lfinish[1]) {
6298 int line = nd_line(node);
6299 LABEL *lstart = NEW_LABEL(line);
6300 LABEL *lend = NEW_LABEL(line);
6301 const rb_iseq_t *rescue;
6303 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6304 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6305 rb_str_concat(rb_str_new2("defined guard in "),
6306 ISEQ_BODY(iseq)->location.label),
6307 ISEQ_TYPE_RESCUE, 0);
6308 lstart->rescued = LABEL_RESCUE_BEG;
6309 lend->rescued = LABEL_RESCUE_END;
6310 APPEND_LABEL(ret, lcur, lstart);
6311 ADD_LABEL(ret, lend);
6312 if (!ignore) {
6313 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6314 }
6315 }
6316}
6317
6318static int
6319compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6320{
6321 const int line = nd_line(node);
6322 const NODE *line_node = node;
6323 if (!RNODE_DEFINED(node)->nd_head) {
6324 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6325 ADD_INSN1(ret, line_node, putobject, str);
6326 }
6327 else {
6328 LABEL *lfinish[3];
6329 LINK_ELEMENT *last = ret->last;
6330 lfinish[0] = NEW_LABEL(line);
6331 lfinish[1] = 0;
6332 lfinish[2] = 0;
6333 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6334 if (lfinish[1]) {
6335 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6336 ADD_INSN(ret, line_node, swap);
6337 if (lfinish[2]) {
6338 ADD_LABEL(ret, lfinish[2]);
6339 }
6340 ADD_INSN(ret, line_node, pop);
6341 ADD_LABEL(ret, lfinish[1]);
6342 }
6343 ADD_LABEL(ret, lfinish[0]);
6344 }
6345 return COMPILE_OK;
6346}
6347
6348static VALUE
6349make_name_for_block(const rb_iseq_t *orig_iseq)
6350{
6351 int level = 1;
6352 const rb_iseq_t *iseq = orig_iseq;
6353
6354 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6355 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6356 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6357 level++;
6358 }
6359 iseq = ISEQ_BODY(iseq)->parent_iseq;
6360 }
6361 }
6362
6363 if (level == 1) {
6364 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6365 }
6366 else {
6367 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6368 }
6369}
6370
6371static void
6372push_ensure_entry(rb_iseq_t *iseq,
6374 struct ensure_range *er, const void *const node)
6375{
6376 enl->ensure_node = node;
6377 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6378 enl->erange = er;
6379 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6380}
6381
6382static void
6383add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6384 LABEL *lstart, LABEL *lend)
6385{
6386 struct ensure_range *ne =
6387 compile_data_alloc(iseq, sizeof(struct ensure_range));
6388
6389 while (erange->next != 0) {
6390 erange = erange->next;
6391 }
6392 ne->next = 0;
6393 ne->begin = lend;
6394 ne->end = erange->end;
6395 erange->end = lstart;
6396
6397 erange->next = ne;
6398}
6399
6400static bool
6401can_add_ensure_iseq(const rb_iseq_t *iseq)
6402{
6404 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6405 while (e) {
6406 if (e->ensure_node) return false;
6407 e = e->prev;
6408 }
6409 }
6410 return true;
6411}
6412
6413static void
6414add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6415{
6416 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6417
6419 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6420 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6421 DECL_ANCHOR(ensure);
6422
6423 INIT_ANCHOR(ensure);
6424 while (enlp) {
6425 if (enlp->erange != NULL) {
6426 DECL_ANCHOR(ensure_part);
6427 LABEL *lstart = NEW_LABEL(0);
6428 LABEL *lend = NEW_LABEL(0);
6429 INIT_ANCHOR(ensure_part);
6430
6431 add_ensure_range(iseq, enlp->erange, lstart, lend);
6432
6433 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6434 ADD_LABEL(ensure_part, lstart);
6435 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6436 ADD_LABEL(ensure_part, lend);
6437 ADD_SEQ(ensure, ensure_part);
6438 }
6439 else {
6440 if (!is_return) {
6441 break;
6442 }
6443 }
6444 enlp = enlp->prev;
6445 }
6446 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6447 ADD_SEQ(ret, ensure);
6448}
6449
6450#if RUBY_DEBUG
6451static int
6452check_keyword(const NODE *node)
6453{
6454 /* This check is essentially a code clone of compile_keyword_arg. */
6455
6456 if (nd_type_p(node, NODE_LIST)) {
6457 while (RNODE_LIST(node)->nd_next) {
6458 node = RNODE_LIST(node)->nd_next;
6459 }
6460 node = RNODE_LIST(node)->nd_head;
6461 }
6462
6463 return keyword_node_p(node);
6464}
6465#endif
6466
6467static bool
6468keyword_node_single_splat_p(NODE *kwnode)
6469{
6470 RUBY_ASSERT(keyword_node_p(kwnode));
6471
6472 NODE *node = RNODE_HASH(kwnode)->nd_head;
6473 return RNODE_LIST(node)->nd_head == NULL &&
6474 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6475}
6476
6477static void
6478compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6479 NODE *kwnode, unsigned int *flag_ptr)
6480{
6481 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6482 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6483 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6484 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6485 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6486}
6487
6488#define SPLATARRAY_FALSE 0
6489#define SPLATARRAY_TRUE 1
6490#define DUP_SINGLE_KW_SPLAT 2
6491
6492static int
6493setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6494 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6495{
6496 if (!argn) return 0;
6497
6498 NODE *kwnode = NULL;
6499
6500 switch (nd_type(argn)) {
6501 case NODE_LIST: {
6502 // f(x, y, z)
6503 int len = compile_args(iseq, args, argn, &kwnode);
6504 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6505
6506 if (kwnode) {
6507 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6508 len -= 1;
6509 }
6510 else {
6511 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6512 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6513 }
6514 else {
6515 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6516 }
6517 }
6518 }
6519
6520 return len;
6521 }
6522 case NODE_SPLAT: {
6523 // f(*a)
6524 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6525 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6526 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6527 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6528 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6529 return 1;
6530 }
6531 case NODE_ARGSCAT: {
6532 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6533 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6534 bool args_pushed = false;
6535
6536 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6537 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6538 if (kwnode) rest_len--;
6539 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6540 args_pushed = true;
6541 }
6542 else {
6543 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6544 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6545 }
6546
6547 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6548 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6549 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6550 argc += 1;
6551 }
6552 else if (!args_pushed) {
6553 ADD_INSN(args, argn, concattoarray);
6554 }
6555
6556 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6557 if (kwnode) {
6558 // kwsplat
6559 *flag_ptr |= VM_CALL_KW_SPLAT;
6560 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6561 argc += 1;
6562 }
6563
6564 return argc;
6565 }
6566 case NODE_ARGSPUSH: {
6567 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6568 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6569
6570 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6571 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6572 if (kwnode) rest_len--;
6573 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6574 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6575 }
6576 else {
6577 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6578 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6579 }
6580 else {
6581 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6582 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6583 }
6584 }
6585
6586 if (kwnode) {
6587 // f(*a, k:1)
6588 *flag_ptr |= VM_CALL_KW_SPLAT;
6589 if (!keyword_node_single_splat_p(kwnode)) {
6590 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6591 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6592 }
6593 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6594 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6595 }
6596 else {
6597 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6598 }
6599 argc += 1;
6600 }
6601
6602 return argc;
6603 }
6604 default: {
6605 UNKNOWN_NODE("setup_arg", argn, Qnil);
6606 }
6607 }
6608}
6609
6610static void
6611setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6612{
6613 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6614 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6615 }
6616}
6617
6618static bool
6619setup_args_dup_rest_p(const NODE *argn)
6620{
6621 switch(nd_type(argn)) {
6622 case NODE_LVAR:
6623 case NODE_DVAR:
6624 case NODE_GVAR:
6625 case NODE_IVAR:
6626 case NODE_CVAR:
6627 case NODE_CONST:
6628 case NODE_COLON3:
6629 case NODE_INTEGER:
6630 case NODE_FLOAT:
6631 case NODE_RATIONAL:
6632 case NODE_IMAGINARY:
6633 case NODE_STR:
6634 case NODE_SYM:
6635 case NODE_REGX:
6636 case NODE_SELF:
6637 case NODE_NIL:
6638 case NODE_TRUE:
6639 case NODE_FALSE:
6640 case NODE_LAMBDA:
6641 case NODE_NTH_REF:
6642 case NODE_BACK_REF:
6643 return false;
6644 case NODE_COLON2:
6645 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6646 case NODE_LIST:
6647 while (argn) {
6648 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6649 return true;
6650 }
6651 argn = RNODE_LIST(argn)->nd_next;
6652 }
6653 return false;
6654 default:
6655 return true;
6656 }
6657}
6658
6659static VALUE
6660setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6661 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6662{
6663 VALUE ret;
6664 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6665
6666 if (argn) {
6667 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6668 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6669
6670 if (check_arg) {
6671 switch(nd_type(check_arg)) {
6672 case(NODE_SPLAT):
6673 // avoid caller side array allocation for f(*arg)
6674 dup_rest = SPLATARRAY_FALSE;
6675 break;
6676 case(NODE_ARGSCAT):
6677 // avoid caller side array allocation for f(1, *arg)
6678 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6679 break;
6680 case(NODE_ARGSPUSH):
6681 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6682 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6683 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6684 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6685 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6686 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6687
6688 if (dup_rest == SPLATARRAY_FALSE) {
6689 // require allocation for keyword key/value/splat that may modify splatted argument
6690 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6691 while (node) {
6692 NODE *key_node = RNODE_LIST(node)->nd_head;
6693 if (key_node && setup_args_dup_rest_p(key_node)) {
6694 dup_rest = SPLATARRAY_TRUE;
6695 break;
6696 }
6697
6698 node = RNODE_LIST(node)->nd_next;
6699 NODE *value_node = RNODE_LIST(node)->nd_head;
6700 if (setup_args_dup_rest_p(value_node)) {
6701 dup_rest = SPLATARRAY_TRUE;
6702 break;
6703 }
6704
6705 node = RNODE_LIST(node)->nd_next;
6706 }
6707 }
6708 break;
6709 default:
6710 break;
6711 }
6712 }
6713
6714 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6715 // for block pass that may modify splatted argument, dup rest and kwrest if given
6716 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6717 }
6718 }
6719 initial_dup_rest = dup_rest;
6720
6721 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6722 DECL_ANCHOR(arg_block);
6723 INIT_ANCHOR(arg_block);
6724
6725 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6726 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6727
6728 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6729 const NODE * arg_node =
6730 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6731
6732 int argc = 0;
6733
6734 // Only compile leading args:
6735 // foo(x, y, ...)
6736 // ^^^^
6737 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6738 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6739 }
6740
6741 *flag |= VM_CALL_FORWARDING;
6742
6743 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6744 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6745 return INT2FIX(argc);
6746 }
6747 else {
6748 *flag |= VM_CALL_ARGS_BLOCKARG;
6749
6750 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6751 }
6752
6753 if (LIST_INSN_SIZE_ONE(arg_block)) {
6754 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6755 if (IS_INSN(elem)) {
6756 INSN *iobj = (INSN *)elem;
6757 if (iobj->insn_id == BIN(getblockparam)) {
6758 iobj->insn_id = BIN(getblockparamproxy);
6759 }
6760 }
6761 }
6762 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6763 ADD_SEQ(args, arg_block);
6764 }
6765 else {
6766 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6767 }
6768 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6769 return ret;
6770}
6771
6772static void
6773build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6774{
6775 const NODE *body = ptr;
6776 int line = nd_line(body);
6777 VALUE argc = INT2FIX(0);
6778 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6779
6780 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6781 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6782 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6783 iseq_set_local_table(iseq, 0, 0);
6784}
6785
6786static void
6787compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6788{
6789 const NODE *vars;
6790 LINK_ELEMENT *last;
6791 int line = nd_line(node);
6792 const NODE *line_node = node;
6793 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6794
6795#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6796 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6797#else
6798 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6799#endif
6800 ADD_INSN(ret, line_node, dup);
6801 ADD_INSNL(ret, line_node, branchunless, fail_label);
6802
6803 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6804 INSN *cap;
6805 if (RNODE_BLOCK(vars)->nd_next) {
6806 ADD_INSN(ret, line_node, dup);
6807 }
6808 last = ret->last;
6809 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6810 last = last->next; /* putobject :var */
6811 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6812 NULL, INT2FIX(0), NULL);
6813 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6814#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6815 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6816 /* only one name */
6817 DECL_ANCHOR(nom);
6818
6819 INIT_ANCHOR(nom);
6820 ADD_INSNL(nom, line_node, jump, end_label);
6821 ADD_LABEL(nom, fail_label);
6822# if 0 /* $~ must be MatchData or nil */
6823 ADD_INSN(nom, line_node, pop);
6824 ADD_INSN(nom, line_node, putnil);
6825# endif
6826 ADD_LABEL(nom, end_label);
6827 (nom->last->next = cap->link.next)->prev = nom->last;
6828 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6829 return;
6830 }
6831#endif
6832 }
6833 ADD_INSNL(ret, line_node, jump, end_label);
6834 ADD_LABEL(ret, fail_label);
6835 ADD_INSN(ret, line_node, pop);
6836 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6837 last = ret->last;
6838 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6839 last = last->next; /* putobject :var */
6840 ((INSN*)last)->insn_id = BIN(putnil);
6841 ((INSN*)last)->operand_size = 0;
6842 }
6843 ADD_LABEL(ret, end_label);
6844}
6845
6846static int
6847optimizable_range_item_p(const NODE *n)
6848{
6849 if (!n) return FALSE;
6850 switch (nd_type(n)) {
6851 case NODE_LINE:
6852 return TRUE;
6853 case NODE_INTEGER:
6854 return TRUE;
6855 case NODE_NIL:
6856 return TRUE;
6857 default:
6858 return FALSE;
6859 }
6860}
6861
6862static VALUE
6863optimized_range_item(const NODE *n)
6864{
6865 switch (nd_type(n)) {
6866 case NODE_LINE:
6867 return rb_node_line_lineno_val(n);
6868 case NODE_INTEGER:
6869 return rb_node_integer_literal_val(n);
6870 case NODE_FLOAT:
6871 return rb_node_float_literal_val(n);
6872 case NODE_RATIONAL:
6873 return rb_node_rational_literal_val(n);
6874 case NODE_IMAGINARY:
6875 return rb_node_imaginary_literal_val(n);
6876 case NODE_NIL:
6877 return Qnil;
6878 default:
6879 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6880 }
6881}
6882
6883static int
6884compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6885{
6886 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6887 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6888
6889 const int line = nd_line(node);
6890 const NODE *line_node = node;
6891 DECL_ANCHOR(cond_seq);
6892 LABEL *then_label, *else_label, *end_label;
6893 VALUE branches = Qfalse;
6894
6895 INIT_ANCHOR(cond_seq);
6896 then_label = NEW_LABEL(line);
6897 else_label = NEW_LABEL(line);
6898 end_label = 0;
6899
6900 NODE *cond = RNODE_IF(node)->nd_cond;
6901 if (nd_type(cond) == NODE_BLOCK) {
6902 cond = RNODE_BLOCK(cond)->nd_head;
6903 }
6904
6905 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6906 ADD_SEQ(ret, cond_seq);
6907
6908 if (then_label->refcnt && else_label->refcnt) {
6909 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6910 }
6911
6912 if (then_label->refcnt) {
6913 ADD_LABEL(ret, then_label);
6914
6915 DECL_ANCHOR(then_seq);
6916 INIT_ANCHOR(then_seq);
6917 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6918
6919 if (else_label->refcnt) {
6920 const NODE *const coverage_node = node_body ? node_body : node;
6921 add_trace_branch_coverage(
6922 iseq,
6923 ret,
6924 nd_code_loc(coverage_node),
6925 nd_node_id(coverage_node),
6926 0,
6927 type == NODE_IF ? "then" : "else",
6928 branches);
6929 end_label = NEW_LABEL(line);
6930 ADD_INSNL(then_seq, line_node, jump, end_label);
6931 if (!popped) {
6932 ADD_INSN(then_seq, line_node, pop);
6933 }
6934 }
6935 ADD_SEQ(ret, then_seq);
6936 }
6937
6938 if (else_label->refcnt) {
6939 ADD_LABEL(ret, else_label);
6940
6941 DECL_ANCHOR(else_seq);
6942 INIT_ANCHOR(else_seq);
6943 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6944
6945 if (then_label->refcnt) {
6946 const NODE *const coverage_node = node_else ? node_else : node;
6947 add_trace_branch_coverage(
6948 iseq,
6949 ret,
6950 nd_code_loc(coverage_node),
6951 nd_node_id(coverage_node),
6952 1,
6953 type == NODE_IF ? "else" : "then",
6954 branches);
6955 }
6956 ADD_SEQ(ret, else_seq);
6957 }
6958
6959 if (end_label) {
6960 ADD_LABEL(ret, end_label);
6961 }
6962
6963 return COMPILE_OK;
6964}
6965
6966static int
6967compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6968{
6969 const NODE *vals;
6970 const NODE *node = orig_node;
6971 LABEL *endlabel, *elselabel;
6972 DECL_ANCHOR(head);
6973 DECL_ANCHOR(body_seq);
6974 DECL_ANCHOR(cond_seq);
6975 int only_special_literals = 1;
6976 VALUE literals = rb_hash_new();
6977 int line;
6978 enum node_type type;
6979 const NODE *line_node;
6980 VALUE branches = Qfalse;
6981 int branch_id = 0;
6982
6983 INIT_ANCHOR(head);
6984 INIT_ANCHOR(body_seq);
6985 INIT_ANCHOR(cond_seq);
6986
6987 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6988
6989 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6990
6991 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6992
6993 node = RNODE_CASE(node)->nd_body;
6994 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6995 type = nd_type(node);
6996 line = nd_line(node);
6997 line_node = node;
6998
6999 endlabel = NEW_LABEL(line);
7000 elselabel = NEW_LABEL(line);
7001
7002 ADD_SEQ(ret, head); /* case VAL */
7003
7004 while (type == NODE_WHEN) {
7005 LABEL *l1;
7006
7007 l1 = NEW_LABEL(line);
7008 ADD_LABEL(body_seq, l1);
7009 ADD_INSN(body_seq, line_node, pop);
7010
7011 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7012 add_trace_branch_coverage(
7013 iseq,
7014 body_seq,
7015 nd_code_loc(coverage_node),
7016 nd_node_id(coverage_node),
7017 branch_id++,
7018 "when",
7019 branches);
7020
7021 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7022 ADD_INSNL(body_seq, line_node, jump, endlabel);
7023
7024 vals = RNODE_WHEN(node)->nd_head;
7025 if (vals) {
7026 switch (nd_type(vals)) {
7027 case NODE_LIST:
7028 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7029 if (only_special_literals < 0) return COMPILE_NG;
7030 break;
7031 case NODE_SPLAT:
7032 case NODE_ARGSCAT:
7033 case NODE_ARGSPUSH:
7034 only_special_literals = 0;
7035 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7036 break;
7037 default:
7038 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7039 }
7040 }
7041 else {
7042 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7043 }
7044
7045 node = RNODE_WHEN(node)->nd_next;
7046 if (!node) {
7047 break;
7048 }
7049 type = nd_type(node);
7050 line = nd_line(node);
7051 line_node = node;
7052 }
7053 /* else */
7054 if (node) {
7055 ADD_LABEL(cond_seq, elselabel);
7056 ADD_INSN(cond_seq, line_node, pop);
7057 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7058 CHECK(COMPILE_(cond_seq, "else", node, popped));
7059 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7060 }
7061 else {
7062 debugs("== else (implicit)\n");
7063 ADD_LABEL(cond_seq, elselabel);
7064 ADD_INSN(cond_seq, orig_node, pop);
7065 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7066 if (!popped) {
7067 ADD_INSN(cond_seq, orig_node, putnil);
7068 }
7069 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7070 }
7071
7072 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7073 ADD_INSN(ret, orig_node, dup);
7074 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7075 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7076 LABEL_REF(elselabel);
7077 }
7078
7079 ADD_SEQ(ret, cond_seq);
7080 ADD_SEQ(ret, body_seq);
7081 ADD_LABEL(ret, endlabel);
7082 return COMPILE_OK;
7083}
7084
7085static int
7086compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7087{
7088 const NODE *vals;
7089 const NODE *val;
7090 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7091 LABEL *endlabel;
7092 DECL_ANCHOR(body_seq);
7093 VALUE branches = Qfalse;
7094 int branch_id = 0;
7095
7096 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7097
7098 INIT_ANCHOR(body_seq);
7099 endlabel = NEW_LABEL(nd_line(node));
7100
7101 while (node && nd_type_p(node, NODE_WHEN)) {
7102 const int line = nd_line(node);
7103 LABEL *l1 = NEW_LABEL(line);
7104 ADD_LABEL(body_seq, l1);
7105
7106 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7107 add_trace_branch_coverage(
7108 iseq,
7109 body_seq,
7110 nd_code_loc(coverage_node),
7111 nd_node_id(coverage_node),
7112 branch_id++,
7113 "when",
7114 branches);
7115
7116 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7117 ADD_INSNL(body_seq, node, jump, endlabel);
7118
7119 vals = RNODE_WHEN(node)->nd_head;
7120 if (!vals) {
7121 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7122 }
7123 switch (nd_type(vals)) {
7124 case NODE_LIST:
7125 while (vals) {
7126 LABEL *lnext;
7127 val = RNODE_LIST(vals)->nd_head;
7128 lnext = NEW_LABEL(nd_line(val));
7129 debug_compile("== when2\n", (void)0);
7130 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7131 ADD_LABEL(ret, lnext);
7132 vals = RNODE_LIST(vals)->nd_next;
7133 }
7134 break;
7135 case NODE_SPLAT:
7136 case NODE_ARGSCAT:
7137 case NODE_ARGSPUSH:
7138 ADD_INSN(ret, vals, putnil);
7139 CHECK(COMPILE(ret, "when2/cond splat", vals));
7140 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7141 ADD_INSNL(ret, vals, branchif, l1);
7142 break;
7143 default:
7144 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7145 }
7146 node = RNODE_WHEN(node)->nd_next;
7147 }
7148 /* else */
7149 const NODE *const coverage_node = node ? node : orig_node;
7150 add_trace_branch_coverage(
7151 iseq,
7152 ret,
7153 nd_code_loc(coverage_node),
7154 nd_node_id(coverage_node),
7155 branch_id,
7156 "else",
7157 branches);
7158 CHECK(COMPILE_(ret, "else", node, popped));
7159 ADD_INSNL(ret, orig_node, jump, endlabel);
7160
7161 ADD_SEQ(ret, body_seq);
7162 ADD_LABEL(ret, endlabel);
7163 return COMPILE_OK;
7164}
7165
7166static 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);
7167
7168static 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);
7169static 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);
7170static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7171static 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);
7172static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7173
7174#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7175#define CASE3_BI_OFFSET_ERROR_STRING 1
7176#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7177#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7178#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7179
7180static int
7181iseq_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)
7182{
7183 const int line = nd_line(node);
7184 const NODE *line_node = node;
7185
7186 switch (nd_type(node)) {
7187 case NODE_ARYPTN: {
7188 /*
7189 * if pattern.use_rest_num?
7190 * rest_num = 0
7191 * end
7192 * if pattern.has_constant_node?
7193 * unless pattern.constant === obj
7194 * goto match_failed
7195 * end
7196 * end
7197 * unless obj.respond_to?(:deconstruct)
7198 * goto match_failed
7199 * end
7200 * d = obj.deconstruct
7201 * unless Array === d
7202 * goto type_error
7203 * end
7204 * min_argc = pattern.pre_args_num + pattern.post_args_num
7205 * if pattern.has_rest_arg?
7206 * unless d.length >= min_argc
7207 * goto match_failed
7208 * end
7209 * else
7210 * unless d.length == min_argc
7211 * goto match_failed
7212 * end
7213 * end
7214 * pattern.pre_args_num.each do |i|
7215 * unless pattern.pre_args[i].match?(d[i])
7216 * goto match_failed
7217 * end
7218 * end
7219 * if pattern.use_rest_num?
7220 * rest_num = d.length - min_argc
7221 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7222 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7223 * goto match_failed
7224 * end
7225 * end
7226 * end
7227 * pattern.post_args_num.each do |i|
7228 * j = pattern.pre_args_num + i
7229 * j += rest_num
7230 * unless pattern.post_args[i].match?(d[j])
7231 * goto match_failed
7232 * end
7233 * end
7234 * goto matched
7235 * type_error:
7236 * FrozenCore.raise TypeError
7237 * match_failed:
7238 * goto unmatched
7239 */
7240 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7241 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7242 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7243
7244 const int min_argc = pre_args_num + post_args_num;
7245 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7246 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7247
7248 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7249 int i;
7250 match_failed = NEW_LABEL(line);
7251 type_error = NEW_LABEL(line);
7252 deconstruct = NEW_LABEL(line);
7253 deconstructed = NEW_LABEL(line);
7254
7255 if (use_rest_num) {
7256 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7257 ADD_INSN(ret, line_node, swap);
7258 if (base_index) {
7259 base_index++;
7260 }
7261 }
7262
7263 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7264
7265 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7266
7267 ADD_INSN(ret, line_node, dup);
7268 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7269 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7270 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7271 if (in_single_pattern) {
7272 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7273 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7274 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7275 INT2FIX(min_argc), base_index + 1 /* (1) */));
7276 }
7277 ADD_INSNL(ret, line_node, branchunless, match_failed);
7278
7279 for (i = 0; i < pre_args_num; i++) {
7280 ADD_INSN(ret, line_node, dup);
7281 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7282 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7283 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));
7284 args = RNODE_LIST(args)->nd_next;
7285 }
7286
7287 if (RNODE_ARYPTN(node)->rest_arg) {
7288 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7289 ADD_INSN(ret, line_node, dup);
7290 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7291 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
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(4));
7296 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7297
7298 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));
7299 }
7300 else {
7301 if (post_args_num > 0) {
7302 ADD_INSN(ret, line_node, dup);
7303 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7304 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7305 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7306 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7307 ADD_INSN(ret, line_node, pop);
7308 }
7309 }
7310 }
7311
7312 args = RNODE_ARYPTN(node)->post_args;
7313 for (i = 0; i < post_args_num; i++) {
7314 ADD_INSN(ret, line_node, dup);
7315
7316 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7317 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7318 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7319
7320 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7321 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));
7322 args = RNODE_LIST(args)->nd_next;
7323 }
7324
7325 ADD_INSN(ret, line_node, pop);
7326 if (use_rest_num) {
7327 ADD_INSN(ret, line_node, pop);
7328 }
7329 ADD_INSNL(ret, line_node, jump, matched);
7330 ADD_INSN(ret, line_node, putnil);
7331 if (use_rest_num) {
7332 ADD_INSN(ret, line_node, putnil);
7333 }
7334
7335 ADD_LABEL(ret, type_error);
7336 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7337 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7338 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7339 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7340 ADD_INSN(ret, line_node, pop);
7341
7342 ADD_LABEL(ret, match_failed);
7343 ADD_INSN(ret, line_node, pop);
7344 if (use_rest_num) {
7345 ADD_INSN(ret, line_node, pop);
7346 }
7347 ADD_INSNL(ret, line_node, jump, unmatched);
7348
7349 break;
7350 }
7351 case NODE_FNDPTN: {
7352 /*
7353 * if pattern.has_constant_node?
7354 * unless pattern.constant === obj
7355 * goto match_failed
7356 * end
7357 * end
7358 * unless obj.respond_to?(:deconstruct)
7359 * goto match_failed
7360 * end
7361 * d = obj.deconstruct
7362 * unless Array === d
7363 * goto type_error
7364 * end
7365 * unless d.length >= pattern.args_num
7366 * goto match_failed
7367 * end
7368 *
7369 * begin
7370 * len = d.length
7371 * limit = d.length - pattern.args_num
7372 * i = 0
7373 * while i <= limit
7374 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7375 * if pattern.has_pre_rest_arg_id
7376 * unless pattern.pre_rest_arg.match?(d[0, i])
7377 * goto find_failed
7378 * end
7379 * end
7380 * if pattern.has_post_rest_arg_id
7381 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7382 * goto find_failed
7383 * end
7384 * end
7385 * goto find_succeeded
7386 * end
7387 * i+=1
7388 * end
7389 * find_failed:
7390 * goto match_failed
7391 * find_succeeded:
7392 * end
7393 *
7394 * goto matched
7395 * type_error:
7396 * FrozenCore.raise TypeError
7397 * match_failed:
7398 * goto unmatched
7399 */
7400 const NODE *args = RNODE_FNDPTN(node)->args;
7401 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7402
7403 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7404 match_failed = NEW_LABEL(line);
7405 type_error = NEW_LABEL(line);
7406 deconstruct = NEW_LABEL(line);
7407 deconstructed = NEW_LABEL(line);
7408
7409 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7410
7411 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7412
7413 ADD_INSN(ret, line_node, dup);
7414 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7415 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7416 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7417 if (in_single_pattern) {
7418 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) */));
7419 }
7420 ADD_INSNL(ret, line_node, branchunless, match_failed);
7421
7422 {
7423 LABEL *while_begin = NEW_LABEL(nd_line(node));
7424 LABEL *next_loop = NEW_LABEL(nd_line(node));
7425 LABEL *find_succeeded = NEW_LABEL(line);
7426 LABEL *find_failed = NEW_LABEL(nd_line(node));
7427 int j;
7428
7429 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7430 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7431
7432 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7433 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7434 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7435
7436 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7437
7438 ADD_LABEL(ret, while_begin);
7439
7440 ADD_INSN(ret, line_node, dup);
7441 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7442 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7443 ADD_INSNL(ret, line_node, branchunless, find_failed);
7444
7445 for (j = 0; j < args_num; j++) {
7446 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7447 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7448 if (j != 0) {
7449 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7450 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7451 }
7452 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7453
7454 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));
7455 args = RNODE_LIST(args)->nd_next;
7456 }
7457
7458 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7459 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7460 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7461 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7462 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7463 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));
7464 }
7465 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7466 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7467 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7468 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7469 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7470 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7471 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7472 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));
7473 }
7474 ADD_INSNL(ret, line_node, jump, find_succeeded);
7475
7476 ADD_LABEL(ret, next_loop);
7477 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7478 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7479 ADD_INSNL(ret, line_node, jump, while_begin);
7480
7481 ADD_LABEL(ret, find_failed);
7482 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7483 if (in_single_pattern) {
7484 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7485 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7486 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7487 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7488 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7489
7490 ADD_INSN1(ret, line_node, putobject, Qfalse);
7491 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7492
7493 ADD_INSN(ret, line_node, pop);
7494 ADD_INSN(ret, line_node, pop);
7495 }
7496 ADD_INSNL(ret, line_node, jump, match_failed);
7497 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7498
7499 ADD_LABEL(ret, find_succeeded);
7500 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7501 }
7502
7503 ADD_INSN(ret, line_node, pop);
7504 ADD_INSNL(ret, line_node, jump, matched);
7505 ADD_INSN(ret, line_node, putnil);
7506
7507 ADD_LABEL(ret, type_error);
7508 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7509 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7510 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7511 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7512 ADD_INSN(ret, line_node, pop);
7513
7514 ADD_LABEL(ret, match_failed);
7515 ADD_INSN(ret, line_node, pop);
7516 ADD_INSNL(ret, line_node, jump, unmatched);
7517
7518 break;
7519 }
7520 case NODE_HSHPTN: {
7521 /*
7522 * keys = nil
7523 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7524 * keys = pattern.kw_args_node.keys
7525 * end
7526 * if pattern.has_constant_node?
7527 * unless pattern.constant === obj
7528 * goto match_failed
7529 * end
7530 * end
7531 * unless obj.respond_to?(:deconstruct_keys)
7532 * goto match_failed
7533 * end
7534 * d = obj.deconstruct_keys(keys)
7535 * unless Hash === d
7536 * goto type_error
7537 * end
7538 * if pattern.has_kw_rest_arg_node?
7539 * d = d.dup
7540 * end
7541 * if pattern.has_kw_args_node?
7542 * pattern.kw_args_node.each |k,|
7543 * unless d.key?(k)
7544 * goto match_failed
7545 * end
7546 * end
7547 * pattern.kw_args_node.each |k, pat|
7548 * if pattern.has_kw_rest_arg_node?
7549 * unless pat.match?(d.delete(k))
7550 * goto match_failed
7551 * end
7552 * else
7553 * unless pat.match?(d[k])
7554 * goto match_failed
7555 * end
7556 * end
7557 * end
7558 * else
7559 * unless d.empty?
7560 * goto match_failed
7561 * end
7562 * end
7563 * if pattern.has_kw_rest_arg_node?
7564 * if pattern.no_rest_keyword?
7565 * unless d.empty?
7566 * goto match_failed
7567 * end
7568 * else
7569 * unless pattern.kw_rest_arg_node.match?(d)
7570 * goto match_failed
7571 * end
7572 * end
7573 * end
7574 * goto matched
7575 * type_error:
7576 * FrozenCore.raise TypeError
7577 * match_failed:
7578 * goto unmatched
7579 */
7580 LABEL *match_failed, *type_error;
7581 VALUE keys = Qnil;
7582
7583 match_failed = NEW_LABEL(line);
7584 type_error = NEW_LABEL(line);
7585
7586 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7587 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7588 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7589 while (kw_args) {
7590 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7591 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7592 }
7593 }
7594
7595 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7596
7597 ADD_INSN(ret, line_node, dup);
7598 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7599 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7600 if (in_single_pattern) {
7601 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7602 }
7603 ADD_INSNL(ret, line_node, branchunless, match_failed);
7604
7605 if (NIL_P(keys)) {
7606 ADD_INSN(ret, line_node, putnil);
7607 }
7608 else {
7609 ADD_INSN1(ret, line_node, duparray, keys);
7610 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7611 }
7612 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7613
7614 ADD_INSN(ret, line_node, dup);
7615 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7616 ADD_INSNL(ret, line_node, branchunless, type_error);
7617
7618 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7619 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7620 }
7621
7622 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7623 int i;
7624 int keys_num;
7625 const NODE *args;
7626 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7627 if (args) {
7628 DECL_ANCHOR(match_values);
7629 INIT_ANCHOR(match_values);
7630 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7631 for (i = 0; i < keys_num; i++) {
7632 NODE *key_node = RNODE_LIST(args)->nd_head;
7633 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7634 VALUE key = get_symbol_value(iseq, key_node);
7635
7636 ADD_INSN(ret, line_node, dup);
7637 ADD_INSN1(ret, line_node, putobject, key);
7638 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7639 if (in_single_pattern) {
7640 LABEL *match_succeeded;
7641 match_succeeded = NEW_LABEL(line);
7642
7643 ADD_INSN(ret, line_node, dup);
7644 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7645
7646 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7647 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7648 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7649 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7650 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7651 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7652 ADD_INSN1(ret, line_node, putobject, key); // (7)
7653 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7654
7655 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7656
7657 ADD_LABEL(ret, match_succeeded);
7658 }
7659 ADD_INSNL(ret, line_node, branchunless, match_failed);
7660
7661 ADD_INSN(match_values, line_node, dup);
7662 ADD_INSN1(match_values, line_node, putobject, key);
7663 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7664 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7665 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7666 }
7667 ADD_SEQ(ret, match_values);
7668 }
7669 }
7670 else {
7671 ADD_INSN(ret, line_node, dup);
7672 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7673 if (in_single_pattern) {
7674 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7675 }
7676 ADD_INSNL(ret, line_node, branchunless, match_failed);
7677 }
7678
7679 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7680 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7681 ADD_INSN(ret, line_node, dup);
7682 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7683 if (in_single_pattern) {
7684 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7685 }
7686 ADD_INSNL(ret, line_node, branchunless, match_failed);
7687 }
7688 else {
7689 ADD_INSN(ret, line_node, dup); // (11)
7690 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));
7691 }
7692 }
7693
7694 ADD_INSN(ret, line_node, pop);
7695 ADD_INSNL(ret, line_node, jump, matched);
7696 ADD_INSN(ret, line_node, putnil);
7697
7698 ADD_LABEL(ret, type_error);
7699 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7700 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7701 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7702 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7703 ADD_INSN(ret, line_node, pop);
7704
7705 ADD_LABEL(ret, match_failed);
7706 ADD_INSN(ret, line_node, pop);
7707 ADD_INSNL(ret, line_node, jump, unmatched);
7708 break;
7709 }
7710 case NODE_SYM:
7711 case NODE_REGX:
7712 case NODE_LINE:
7713 case NODE_INTEGER:
7714 case NODE_FLOAT:
7715 case NODE_RATIONAL:
7716 case NODE_IMAGINARY:
7717 case NODE_FILE:
7718 case NODE_ENCODING:
7719 case NODE_STR:
7720 case NODE_XSTR:
7721 case NODE_DSTR:
7722 case NODE_DSYM:
7723 case NODE_DREGX:
7724 case NODE_LIST:
7725 case NODE_ZLIST:
7726 case NODE_LAMBDA:
7727 case NODE_DOT2:
7728 case NODE_DOT3:
7729 case NODE_CONST:
7730 case NODE_LVAR:
7731 case NODE_DVAR:
7732 case NODE_IVAR:
7733 case NODE_CVAR:
7734 case NODE_GVAR:
7735 case NODE_TRUE:
7736 case NODE_FALSE:
7737 case NODE_SELF:
7738 case NODE_NIL:
7739 case NODE_COLON2:
7740 case NODE_COLON3:
7741 case NODE_BEGIN:
7742 case NODE_BLOCK:
7743 case NODE_ONCE:
7744 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7745 if (in_single_pattern) {
7746 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7747 }
7748 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7749 if (in_single_pattern) {
7750 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7751 }
7752 ADD_INSNL(ret, line_node, branchif, matched);
7753 ADD_INSNL(ret, line_node, jump, unmatched);
7754 break;
7755 case NODE_LASGN: {
7756 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7757 ID id = RNODE_LASGN(node)->nd_vid;
7758 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7759
7760 if (in_alt_pattern) {
7761 const char *name = rb_id2name(id);
7762 if (name && strlen(name) > 0 && name[0] != '_') {
7763 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7764 rb_id2str(id));
7765 return COMPILE_NG;
7766 }
7767 }
7768
7769 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7770 ADD_INSNL(ret, line_node, jump, matched);
7771 break;
7772 }
7773 case NODE_DASGN: {
7774 int idx, lv, ls;
7775 ID id = RNODE_DASGN(node)->nd_vid;
7776
7777 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7778
7779 if (in_alt_pattern) {
7780 const char *name = rb_id2name(id);
7781 if (name && strlen(name) > 0 && name[0] != '_') {
7782 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7783 rb_id2str(id));
7784 return COMPILE_NG;
7785 }
7786 }
7787
7788 if (idx < 0) {
7789 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7790 rb_id2str(id));
7791 return COMPILE_NG;
7792 }
7793 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7794 ADD_INSNL(ret, line_node, jump, matched);
7795 break;
7796 }
7797 case NODE_IF:
7798 case NODE_UNLESS: {
7799 LABEL *match_failed;
7800 match_failed = unmatched;
7801 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7802 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7803 if (in_single_pattern) {
7804 LABEL *match_succeeded;
7805 match_succeeded = NEW_LABEL(line);
7806
7807 ADD_INSN(ret, line_node, dup);
7808 if (nd_type_p(node, NODE_IF)) {
7809 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7810 }
7811 else {
7812 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7813 }
7814
7815 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7816 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7817 ADD_INSN1(ret, line_node, putobject, Qfalse);
7818 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7819
7820 ADD_INSN(ret, line_node, pop);
7821 ADD_INSN(ret, line_node, pop);
7822
7823 ADD_LABEL(ret, match_succeeded);
7824 }
7825 if (nd_type_p(node, NODE_IF)) {
7826 ADD_INSNL(ret, line_node, branchunless, match_failed);
7827 }
7828 else {
7829 ADD_INSNL(ret, line_node, branchif, match_failed);
7830 }
7831 ADD_INSNL(ret, line_node, jump, matched);
7832 break;
7833 }
7834 case NODE_HASH: {
7835 NODE *n;
7836 LABEL *match_failed;
7837 match_failed = NEW_LABEL(line);
7838
7839 n = RNODE_HASH(node)->nd_head;
7840 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7841 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7842 return COMPILE_NG;
7843 }
7844
7845 ADD_INSN(ret, line_node, dup); // (1)
7846 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));
7847 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));
7848 ADD_INSN(ret, line_node, putnil);
7849
7850 ADD_LABEL(ret, match_failed);
7851 ADD_INSN(ret, line_node, pop);
7852 ADD_INSNL(ret, line_node, jump, unmatched);
7853 break;
7854 }
7855 case NODE_OR: {
7856 LABEL *match_succeeded, *fin;
7857 match_succeeded = NEW_LABEL(line);
7858 fin = NEW_LABEL(line);
7859
7860 ADD_INSN(ret, line_node, dup); // (1)
7861 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));
7862 ADD_LABEL(ret, match_succeeded);
7863 ADD_INSN(ret, line_node, pop);
7864 ADD_INSNL(ret, line_node, jump, matched);
7865 ADD_INSN(ret, line_node, putnil);
7866 ADD_LABEL(ret, fin);
7867 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7868 break;
7869 }
7870 default:
7871 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7872 }
7873 return COMPILE_OK;
7874}
7875
7876static int
7877iseq_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)
7878{
7879 LABEL *fin = NEW_LABEL(nd_line(node));
7880 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7881 ADD_LABEL(ret, fin);
7882 return COMPILE_OK;
7883}
7884
7885static int
7886iseq_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)
7887{
7888 const NODE *line_node = node;
7889
7890 if (RNODE_ARYPTN(node)->nd_pconst) {
7891 ADD_INSN(ret, line_node, dup); // (1)
7892 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7893 if (in_single_pattern) {
7894 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7895 }
7896 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7897 if (in_single_pattern) {
7898 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7899 }
7900 ADD_INSNL(ret, line_node, branchunless, match_failed);
7901 }
7902 return COMPILE_OK;
7903}
7904
7905
7906static int
7907iseq_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)
7908{
7909 const NODE *line_node = node;
7910
7911 // NOTE: this optimization allows us to re-use the #deconstruct value
7912 // (or its absence).
7913 if (use_deconstructed_cache) {
7914 // If value is nil then we haven't tried to deconstruct
7915 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7916 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7917
7918 // If false then the value is not deconstructable
7919 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7920 ADD_INSNL(ret, line_node, branchunless, match_failed);
7921
7922 // Drop value, add deconstructed to the stack and jump
7923 ADD_INSN(ret, line_node, pop); // (1)
7924 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7925 ADD_INSNL(ret, line_node, jump, deconstructed);
7926 }
7927 else {
7928 ADD_INSNL(ret, line_node, jump, deconstruct);
7929 }
7930
7931 ADD_LABEL(ret, deconstruct);
7932 ADD_INSN(ret, line_node, dup);
7933 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7934 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7935
7936 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7937 if (use_deconstructed_cache) {
7938 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7939 }
7940
7941 if (in_single_pattern) {
7942 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7943 }
7944
7945 ADD_INSNL(ret, line_node, branchunless, match_failed);
7946
7947 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7948
7949 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7950 if (use_deconstructed_cache) {
7951 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7952 }
7953
7954 ADD_INSN(ret, line_node, dup);
7955 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7956 ADD_INSNL(ret, line_node, branchunless, type_error);
7957
7958 ADD_LABEL(ret, deconstructed);
7959
7960 return COMPILE_OK;
7961}
7962
7963static int
7964iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7965{
7966 /*
7967 * if match_succeeded?
7968 * goto match_succeeded
7969 * end
7970 * error_string = FrozenCore.sprintf(errmsg, matchee)
7971 * key_error_p = false
7972 * match_succeeded:
7973 */
7974 const int line = nd_line(node);
7975 const NODE *line_node = node;
7976 LABEL *match_succeeded = NEW_LABEL(line);
7977
7978 ADD_INSN(ret, line_node, dup);
7979 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7980
7981 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7982 ADD_INSN1(ret, line_node, putobject, errmsg);
7983 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7984 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7985 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7986
7987 ADD_INSN1(ret, line_node, putobject, Qfalse);
7988 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7989
7990 ADD_INSN(ret, line_node, pop);
7991 ADD_INSN(ret, line_node, pop);
7992 ADD_LABEL(ret, match_succeeded);
7993
7994 return COMPILE_OK;
7995}
7996
7997static int
7998iseq_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)
7999{
8000 /*
8001 * if match_succeeded?
8002 * goto match_succeeded
8003 * end
8004 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8005 * key_error_p = false
8006 * match_succeeded:
8007 */
8008 const int line = nd_line(node);
8009 const NODE *line_node = node;
8010 LABEL *match_succeeded = NEW_LABEL(line);
8011
8012 ADD_INSN(ret, line_node, dup);
8013 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8014
8015 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8016 ADD_INSN1(ret, line_node, putobject, errmsg);
8017 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8018 ADD_INSN(ret, line_node, dup);
8019 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8020 ADD_INSN1(ret, line_node, putobject, pattern_length);
8021 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8022 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8023
8024 ADD_INSN1(ret, line_node, putobject, Qfalse);
8025 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8026
8027 ADD_INSN(ret, line_node, pop);
8028 ADD_INSN(ret, line_node, pop);
8029 ADD_LABEL(ret, match_succeeded);
8030
8031 return COMPILE_OK;
8032}
8033
8034static int
8035iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8036{
8037 /*
8038 * if match_succeeded?
8039 * goto match_succeeded
8040 * end
8041 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8042 * key_error_p = false
8043 * match_succeeded:
8044 */
8045 const int line = nd_line(node);
8046 const NODE *line_node = node;
8047 LABEL *match_succeeded = NEW_LABEL(line);
8048
8049 ADD_INSN(ret, line_node, dup);
8050 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8051
8052 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8053 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8054 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8055 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8056 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8057 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8058
8059 ADD_INSN1(ret, line_node, putobject, Qfalse);
8060 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8061
8062 ADD_INSN(ret, line_node, pop);
8063 ADD_INSN(ret, line_node, pop);
8064
8065 ADD_LABEL(ret, match_succeeded);
8066 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8067 ADD_INSN(ret, line_node, pop);
8068 ADD_INSN(ret, line_node, pop);
8069
8070 return COMPILE_OK;
8071}
8072
8073static int
8074compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8075{
8076 const NODE *pattern;
8077 const NODE *node = orig_node;
8078 LABEL *endlabel, *elselabel;
8079 DECL_ANCHOR(head);
8080 DECL_ANCHOR(body_seq);
8081 DECL_ANCHOR(cond_seq);
8082 int line;
8083 enum node_type type;
8084 const NODE *line_node;
8085 VALUE branches = 0;
8086 int branch_id = 0;
8087 bool single_pattern;
8088
8089 INIT_ANCHOR(head);
8090 INIT_ANCHOR(body_seq);
8091 INIT_ANCHOR(cond_seq);
8092
8093 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8094
8095 node = RNODE_CASE3(node)->nd_body;
8096 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8097 type = nd_type(node);
8098 line = nd_line(node);
8099 line_node = node;
8100 single_pattern = !RNODE_IN(node)->nd_next;
8101
8102 endlabel = NEW_LABEL(line);
8103 elselabel = NEW_LABEL(line);
8104
8105 if (single_pattern) {
8106 /* allocate stack for ... */
8107 ADD_INSN(head, line_node, putnil); /* key_error_key */
8108 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8109 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8110 ADD_INSN(head, line_node, putnil); /* error_string */
8111 }
8112 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8113
8114 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8115
8116 ADD_SEQ(ret, head); /* case VAL */
8117
8118 while (type == NODE_IN) {
8119 LABEL *l1;
8120
8121 if (branch_id) {
8122 ADD_INSN(body_seq, line_node, putnil);
8123 }
8124 l1 = NEW_LABEL(line);
8125 ADD_LABEL(body_seq, l1);
8126 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8127
8128 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8129 add_trace_branch_coverage(
8130 iseq,
8131 body_seq,
8132 nd_code_loc(coverage_node),
8133 nd_node_id(coverage_node),
8134 branch_id++,
8135 "in",
8136 branches);
8137
8138 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8139 ADD_INSNL(body_seq, line_node, jump, endlabel);
8140
8141 pattern = RNODE_IN(node)->nd_head;
8142 if (pattern) {
8143 int pat_line = nd_line(pattern);
8144 LABEL *next_pat = NEW_LABEL(pat_line);
8145 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8146 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8147 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8148 ADD_LABEL(cond_seq, next_pat);
8149 LABEL_UNREMOVABLE(next_pat);
8150 }
8151 else {
8152 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8153 return COMPILE_NG;
8154 }
8155
8156 node = RNODE_IN(node)->nd_next;
8157 if (!node) {
8158 break;
8159 }
8160 type = nd_type(node);
8161 line = nd_line(node);
8162 line_node = node;
8163 }
8164 /* else */
8165 if (node) {
8166 ADD_LABEL(cond_seq, elselabel);
8167 ADD_INSN(cond_seq, line_node, pop);
8168 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8169 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8170 CHECK(COMPILE_(cond_seq, "else", node, popped));
8171 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8172 ADD_INSN(cond_seq, line_node, putnil);
8173 if (popped) {
8174 ADD_INSN(cond_seq, line_node, putnil);
8175 }
8176 }
8177 else {
8178 debugs("== else (implicit)\n");
8179 ADD_LABEL(cond_seq, elselabel);
8180 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8181 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8182
8183 if (single_pattern) {
8184 /*
8185 * if key_error_p
8186 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8187 * else
8188 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8189 * end
8190 */
8191 LABEL *key_error, *fin;
8192 struct rb_callinfo_kwarg *kw_arg;
8193
8194 key_error = NEW_LABEL(line);
8195 fin = NEW_LABEL(line);
8196
8197 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8198 kw_arg->references = 0;
8199 kw_arg->keyword_len = 2;
8200 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8201 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8202
8203 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8204 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8205 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8206 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8207 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8208 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8209 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8210 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8211 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8212 ADD_INSNL(cond_seq, orig_node, jump, fin);
8213
8214 ADD_LABEL(cond_seq, key_error);
8215 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8216 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8217 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8218 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8219 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8220 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8221 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8222 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8223 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8224 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8225
8226 ADD_LABEL(cond_seq, fin);
8227 }
8228 else {
8229 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8230 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8231 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8232 }
8233 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8234 if (!popped) {
8235 ADD_INSN(cond_seq, orig_node, putnil);
8236 }
8237 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8238 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8239 if (popped) {
8240 ADD_INSN(cond_seq, line_node, putnil);
8241 }
8242 }
8243
8244 ADD_SEQ(ret, cond_seq);
8245 ADD_SEQ(ret, body_seq);
8246 ADD_LABEL(ret, endlabel);
8247 return COMPILE_OK;
8248}
8249
8250#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8251#undef CASE3_BI_OFFSET_ERROR_STRING
8252#undef CASE3_BI_OFFSET_KEY_ERROR_P
8253#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8254#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8255
8256static int
8257compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8258{
8259 const int line = (int)nd_line(node);
8260 const NODE *line_node = node;
8261
8262 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8263 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8264 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8265 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8266 VALUE branches = Qfalse;
8267
8269
8270 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8271 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8272 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8273 LABEL *end_label = NEW_LABEL(line);
8274 LABEL *adjust_label = NEW_LABEL(line);
8275
8276 LABEL *next_catch_label = NEW_LABEL(line);
8277 LABEL *tmp_label = NULL;
8278
8279 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8280 push_ensure_entry(iseq, &enl, NULL, NULL);
8281
8282 if (RNODE_WHILE(node)->nd_state == 1) {
8283 ADD_INSNL(ret, line_node, jump, next_label);
8284 }
8285 else {
8286 tmp_label = NEW_LABEL(line);
8287 ADD_INSNL(ret, line_node, jump, tmp_label);
8288 }
8289 ADD_LABEL(ret, adjust_label);
8290 ADD_INSN(ret, line_node, putnil);
8291 ADD_LABEL(ret, next_catch_label);
8292 ADD_INSN(ret, line_node, pop);
8293 ADD_INSNL(ret, line_node, jump, next_label);
8294 if (tmp_label) ADD_LABEL(ret, tmp_label);
8295
8296 ADD_LABEL(ret, redo_label);
8297 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8298
8299 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8300 add_trace_branch_coverage(
8301 iseq,
8302 ret,
8303 nd_code_loc(coverage_node),
8304 nd_node_id(coverage_node),
8305 0,
8306 "body",
8307 branches);
8308
8309 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8310 ADD_LABEL(ret, next_label); /* next */
8311
8312 if (type == NODE_WHILE) {
8313 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8314 redo_label, end_label));
8315 }
8316 else {
8317 /* until */
8318 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8319 end_label, redo_label));
8320 }
8321
8322 ADD_LABEL(ret, end_label);
8323 ADD_ADJUST_RESTORE(ret, adjust_label);
8324
8325 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8326 /* ADD_INSN(ret, line_node, putundef); */
8327 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8328 return COMPILE_NG;
8329 }
8330 else {
8331 ADD_INSN(ret, line_node, putnil);
8332 }
8333
8334 ADD_LABEL(ret, break_label); /* break */
8335
8336 if (popped) {
8337 ADD_INSN(ret, line_node, pop);
8338 }
8339
8340 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8341 break_label);
8342 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8343 next_catch_label);
8344 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8345 ISEQ_COMPILE_DATA(iseq)->redo_label);
8346
8347 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8348 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8349 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8350 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8351 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8352 return COMPILE_OK;
8353}
8354
8355static int
8356compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8357{
8358 const int line = nd_line(node);
8359 const NODE *line_node = node;
8360 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8361 LABEL *retry_label = NEW_LABEL(line);
8362 LABEL *retry_end_l = NEW_LABEL(line);
8363 const rb_iseq_t *child_iseq;
8364
8365 ADD_LABEL(ret, retry_label);
8366 if (nd_type_p(node, NODE_FOR)) {
8367 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8368
8369 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8370 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8371 ISEQ_TYPE_BLOCK, line);
8372 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8373 }
8374 else {
8375 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8376 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8377 ISEQ_TYPE_BLOCK, line);
8378 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8379 }
8380
8381 {
8382 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8383 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8384 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8385 //
8386 // Normally, "send" instruction is at the last.
8387 // However, qcall under branch coverage measurement adds some instructions after the "send".
8388 //
8389 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8390 INSN *iobj;
8391 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8392 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8393 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8394 iobj = (INSN*) get_prev_insn(iobj);
8395 }
8396 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8397
8398 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8399 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8400 if (&iobj->link == LAST_ELEMENT(ret)) {
8401 ret->last = (LINK_ELEMENT*) retry_end_l;
8402 }
8403 }
8404
8405 if (popped) {
8406 ADD_INSN(ret, line_node, pop);
8407 }
8408
8409 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8410
8411 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8412 return COMPILE_OK;
8413}
8414
8415static int
8416compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8417{
8418 /* massign to var in "for"
8419 * (args.length == 1 && Array.try_convert(args[0])) || args
8420 */
8421 const NODE *line_node = node;
8422 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8423 LABEL *not_single = NEW_LABEL(nd_line(var));
8424 LABEL *not_ary = NEW_LABEL(nd_line(var));
8425 CHECK(COMPILE(ret, "for var", var));
8426 ADD_INSN(ret, line_node, dup);
8427 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8428 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8429 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8430 ADD_INSNL(ret, line_node, branchunless, not_single);
8431 ADD_INSN(ret, line_node, dup);
8432 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8433 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8434 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8435 ADD_INSN(ret, line_node, swap);
8436 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8437 ADD_INSN(ret, line_node, dup);
8438 ADD_INSNL(ret, line_node, branchunless, not_ary);
8439 ADD_INSN(ret, line_node, swap);
8440 ADD_LABEL(ret, not_ary);
8441 ADD_INSN(ret, line_node, pop);
8442 ADD_LABEL(ret, not_single);
8443 return COMPILE_OK;
8444}
8445
8446static int
8447compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8448{
8449 const NODE *line_node = node;
8450 unsigned long throw_flag = 0;
8451
8452 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8453 /* while/until */
8454 LABEL *splabel = NEW_LABEL(0);
8455 ADD_LABEL(ret, splabel);
8456 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8457 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8458 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8459 add_ensure_iseq(ret, iseq, 0);
8460 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8461 ADD_ADJUST_RESTORE(ret, splabel);
8462
8463 if (!popped) {
8464 ADD_INSN(ret, line_node, putnil);
8465 }
8466 }
8467 else {
8468 const rb_iseq_t *ip = iseq;
8469
8470 while (ip) {
8471 if (!ISEQ_COMPILE_DATA(ip)) {
8472 ip = 0;
8473 break;
8474 }
8475
8476 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8477 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8478 }
8479 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8480 throw_flag = 0;
8481 }
8482 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8483 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8484 return COMPILE_NG;
8485 }
8486 else {
8487 ip = ISEQ_BODY(ip)->parent_iseq;
8488 continue;
8489 }
8490
8491 /* escape from block */
8492 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8493 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8494 if (popped) {
8495 ADD_INSN(ret, line_node, pop);
8496 }
8497 return COMPILE_OK;
8498 }
8499 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8500 return COMPILE_NG;
8501 }
8502 return COMPILE_OK;
8503}
8504
8505static int
8506compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8507{
8508 const NODE *line_node = node;
8509 unsigned long throw_flag = 0;
8510
8511 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8512 LABEL *splabel = NEW_LABEL(0);
8513 debugs("next in while loop\n");
8514 ADD_LABEL(ret, splabel);
8515 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8516 add_ensure_iseq(ret, iseq, 0);
8517 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8518 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8519 ADD_ADJUST_RESTORE(ret, splabel);
8520 if (!popped) {
8521 ADD_INSN(ret, line_node, putnil);
8522 }
8523 }
8524 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8525 LABEL *splabel = NEW_LABEL(0);
8526 debugs("next in block\n");
8527 ADD_LABEL(ret, splabel);
8528 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8529 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8530 add_ensure_iseq(ret, iseq, 0);
8531 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8532 ADD_ADJUST_RESTORE(ret, splabel);
8533
8534 if (!popped) {
8535 ADD_INSN(ret, line_node, putnil);
8536 }
8537 }
8538 else {
8539 const rb_iseq_t *ip = iseq;
8540
8541 while (ip) {
8542 if (!ISEQ_COMPILE_DATA(ip)) {
8543 ip = 0;
8544 break;
8545 }
8546
8547 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8548 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8549 /* while loop */
8550 break;
8551 }
8552 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8553 break;
8554 }
8555 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8556 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8557 return COMPILE_NG;
8558 }
8559
8560 ip = ISEQ_BODY(ip)->parent_iseq;
8561 }
8562 if (ip != 0) {
8563 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8564 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8565
8566 if (popped) {
8567 ADD_INSN(ret, line_node, pop);
8568 }
8569 }
8570 else {
8571 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8572 return COMPILE_NG;
8573 }
8574 }
8575 return COMPILE_OK;
8576}
8577
8578static int
8579compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8580{
8581 const NODE *line_node = node;
8582
8583 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8584 LABEL *splabel = NEW_LABEL(0);
8585 debugs("redo in while");
8586 ADD_LABEL(ret, splabel);
8587 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8588 add_ensure_iseq(ret, iseq, 0);
8589 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8590 ADD_ADJUST_RESTORE(ret, splabel);
8591 if (!popped) {
8592 ADD_INSN(ret, line_node, putnil);
8593 }
8594 }
8595 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8596 LABEL *splabel = NEW_LABEL(0);
8597
8598 debugs("redo in block");
8599 ADD_LABEL(ret, splabel);
8600 add_ensure_iseq(ret, iseq, 0);
8601 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8602 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8603 ADD_ADJUST_RESTORE(ret, splabel);
8604
8605 if (!popped) {
8606 ADD_INSN(ret, line_node, putnil);
8607 }
8608 }
8609 else {
8610 const rb_iseq_t *ip = iseq;
8611
8612 while (ip) {
8613 if (!ISEQ_COMPILE_DATA(ip)) {
8614 ip = 0;
8615 break;
8616 }
8617
8618 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8619 break;
8620 }
8621 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8622 break;
8623 }
8624 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8625 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8626 return COMPILE_NG;
8627 }
8628
8629 ip = ISEQ_BODY(ip)->parent_iseq;
8630 }
8631 if (ip != 0) {
8632 ADD_INSN(ret, line_node, putnil);
8633 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8634
8635 if (popped) {
8636 ADD_INSN(ret, line_node, pop);
8637 }
8638 }
8639 else {
8640 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8641 return COMPILE_NG;
8642 }
8643 }
8644 return COMPILE_OK;
8645}
8646
8647static int
8648compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8649{
8650 const NODE *line_node = node;
8651
8652 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8653 ADD_INSN(ret, line_node, putnil);
8654 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8655
8656 if (popped) {
8657 ADD_INSN(ret, line_node, pop);
8658 }
8659 }
8660 else {
8661 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8662 return COMPILE_NG;
8663 }
8664 return COMPILE_OK;
8665}
8666
8667static int
8668compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8669{
8670 const int line = nd_line(node);
8671 const NODE *line_node = node;
8672 LABEL *lstart = NEW_LABEL(line);
8673 LABEL *lend = NEW_LABEL(line);
8674 LABEL *lcont = NEW_LABEL(line);
8675 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8676 rb_str_concat(rb_str_new2("rescue in "),
8677 ISEQ_BODY(iseq)->location.label),
8678 ISEQ_TYPE_RESCUE, line);
8679
8680 lstart->rescued = LABEL_RESCUE_BEG;
8681 lend->rescued = LABEL_RESCUE_END;
8682 ADD_LABEL(ret, lstart);
8683
8684 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8685 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8686 {
8687 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8688 }
8689 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8690
8691 ADD_LABEL(ret, lend);
8692 if (RNODE_RESCUE(node)->nd_else) {
8693 ADD_INSN(ret, line_node, pop);
8694 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8695 }
8696 ADD_INSN(ret, line_node, nop);
8697 ADD_LABEL(ret, lcont);
8698
8699 if (popped) {
8700 ADD_INSN(ret, line_node, pop);
8701 }
8702
8703 /* register catch entry */
8704 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8705 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8706 return COMPILE_OK;
8707}
8708
8709static int
8710compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8711{
8712 const int line = nd_line(node);
8713 const NODE *line_node = node;
8714 const NODE *resq = node;
8715 const NODE *narg;
8716 LABEL *label_miss, *label_hit;
8717
8718 while (resq) {
8719 label_miss = NEW_LABEL(line);
8720 label_hit = NEW_LABEL(line);
8721
8722 narg = RNODE_RESBODY(resq)->nd_args;
8723 if (narg) {
8724 switch (nd_type(narg)) {
8725 case NODE_LIST:
8726 while (narg) {
8727 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8728 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8729 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8730 ADD_INSNL(ret, line_node, branchif, label_hit);
8731 narg = RNODE_LIST(narg)->nd_next;
8732 }
8733 break;
8734 case NODE_SPLAT:
8735 case NODE_ARGSCAT:
8736 case NODE_ARGSPUSH:
8737 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8738 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8739 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8740 ADD_INSNL(ret, line_node, branchif, label_hit);
8741 break;
8742 default:
8743 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8744 }
8745 }
8746 else {
8747 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8748 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8749 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8750 ADD_INSNL(ret, line_node, branchif, label_hit);
8751 }
8752 ADD_INSNL(ret, line_node, jump, label_miss);
8753 ADD_LABEL(ret, label_hit);
8754 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8755
8756 if (RNODE_RESBODY(resq)->nd_exc_var) {
8757 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8758 }
8759
8760 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) {
8761 // empty body
8762 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8763 }
8764 else {
8765 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8766 }
8767
8768 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8769 ADD_INSN(ret, line_node, nop);
8770 }
8771 ADD_INSN(ret, line_node, leave);
8772 ADD_LABEL(ret, label_miss);
8773 resq = RNODE_RESBODY(resq)->nd_next;
8774 }
8775 return COMPILE_OK;
8776}
8777
8778static int
8779compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8780{
8781 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8782 const NODE *line_node = node;
8783 DECL_ANCHOR(ensr);
8784 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8785 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8786 ISEQ_TYPE_ENSURE, line);
8787 LABEL *lstart = NEW_LABEL(line);
8788 LABEL *lend = NEW_LABEL(line);
8789 LABEL *lcont = NEW_LABEL(line);
8790 LINK_ELEMENT *last;
8791 int last_leave = 0;
8792 struct ensure_range er;
8794 struct ensure_range *erange;
8795
8796 INIT_ANCHOR(ensr);
8797 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8798 last = ensr->last;
8799 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8800
8801 er.begin = lstart;
8802 er.end = lend;
8803 er.next = 0;
8804 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8805
8806 ADD_LABEL(ret, lstart);
8807 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8808 ADD_LABEL(ret, lend);
8809 ADD_SEQ(ret, ensr);
8810 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8811 ADD_LABEL(ret, lcont);
8812 if (last_leave) ADD_INSN(ret, line_node, pop);
8813
8814 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8815 if (lstart->link.next != &lend->link) {
8816 while (erange) {
8817 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8818 ensure, lcont);
8819 erange = erange->next;
8820 }
8821 }
8822
8823 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8824 return COMPILE_OK;
8825}
8826
8827static int
8828compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8829{
8830 const NODE *line_node = node;
8831
8832 if (iseq) {
8833 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8834 const rb_iseq_t *is = iseq;
8835 enum rb_iseq_type t = type;
8836 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8837 LABEL *splabel = 0;
8838
8839 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8840 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8841 t = ISEQ_BODY(is)->type;
8842 }
8843 switch (t) {
8844 case ISEQ_TYPE_TOP:
8845 case ISEQ_TYPE_MAIN:
8846 if (retval) {
8847 rb_warn("argument of top-level return is ignored");
8848 }
8849 if (is == iseq) {
8850 /* plain top-level, leave directly */
8851 type = ISEQ_TYPE_METHOD;
8852 }
8853 break;
8854 default:
8855 break;
8856 }
8857
8858 if (type == ISEQ_TYPE_METHOD) {
8859 splabel = NEW_LABEL(0);
8860 ADD_LABEL(ret, splabel);
8861 ADD_ADJUST(ret, line_node, 0);
8862 }
8863
8864 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8865
8866 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8867 add_ensure_iseq(ret, iseq, 1);
8868 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8869 ADD_INSN(ret, line_node, leave);
8870 ADD_ADJUST_RESTORE(ret, splabel);
8871
8872 if (!popped) {
8873 ADD_INSN(ret, line_node, putnil);
8874 }
8875 }
8876 else {
8877 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8878 if (popped) {
8879 ADD_INSN(ret, line_node, pop);
8880 }
8881 }
8882 }
8883 return COMPILE_OK;
8884}
8885
8886static bool
8887drop_unreachable_return(LINK_ANCHOR *ret)
8888{
8889 LINK_ELEMENT *i = ret->last, *last;
8890 if (!i) return false;
8891 if (IS_TRACE(i)) i = i->prev;
8892 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8893 last = i = i->prev;
8894 if (IS_ADJUST(i)) i = i->prev;
8895 if (!IS_INSN(i)) return false;
8896 switch (INSN_OF(i)) {
8897 case BIN(leave):
8898 case BIN(jump):
8899 break;
8900 default:
8901 return false;
8902 }
8903 (ret->last = last->prev)->next = NULL;
8904 return true;
8905}
8906
8907static int
8908compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8909{
8910 CHECK(COMPILE_(ret, "nd_body", node, popped));
8911
8912 if (!popped && !all_string_result_p(node)) {
8913 const NODE *line_node = node;
8914 const unsigned int flag = VM_CALL_FCALL;
8915
8916 // Note, this dup could be removed if we are willing to change anytostring. It pops
8917 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8918 ADD_INSN(ret, line_node, dup);
8919 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8920 ADD_INSN(ret, line_node, anytostring);
8921 }
8922 return COMPILE_OK;
8923}
8924
8925static void
8926compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8927{
8928 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8929
8930 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8931 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8932}
8933
8934static LABEL *
8935qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8936{
8937 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8938 VALUE br = 0;
8939
8940 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8941 *branches = br;
8942 ADD_INSN(recv, line_node, dup);
8943 ADD_INSNL(recv, line_node, branchnil, else_label);
8944 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8945 return else_label;
8946}
8947
8948static void
8949qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8950{
8951 LABEL *end_label;
8952 if (!else_label) return;
8953 end_label = NEW_LABEL(nd_line(line_node));
8954 ADD_INSNL(ret, line_node, jump, end_label);
8955 ADD_LABEL(ret, else_label);
8956 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8957 ADD_LABEL(ret, end_label);
8958}
8959
8960static int
8961compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8962{
8963 /* optimization shortcut
8964 * "literal".freeze -> opt_str_freeze("literal")
8965 */
8966 if (get_nd_recv(node) &&
8967 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8968 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8969 get_nd_args(node) == NULL &&
8970 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8971 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8972 VALUE str = get_string_value(get_nd_recv(node));
8973 if (get_node_call_nd_mid(node) == idUMinus) {
8974 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8975 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8976 }
8977 else {
8978 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8979 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8980 }
8981 RB_OBJ_WRITTEN(iseq, Qundef, str);
8982 if (popped) {
8983 ADD_INSN(ret, line_node, pop);
8984 }
8985 return TRUE;
8986 }
8987 /* optimization shortcut
8988 * obj["literal"] -> opt_aref_with(obj, "literal")
8989 */
8990 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8991 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8992 (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)) &&
8993 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8994 !frozen_string_literal_p(iseq) &&
8995 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8996 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8997 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8998 ADD_INSN2(ret, line_node, opt_aref_with, str,
8999 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
9000 RB_OBJ_WRITTEN(iseq, Qundef, str);
9001 if (popped) {
9002 ADD_INSN(ret, line_node, pop);
9003 }
9004 return TRUE;
9005 }
9006 return FALSE;
9007}
9008
9009static int
9010iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9011{
9012 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9013}
9014
9015static const struct rb_builtin_function *
9016iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9017{
9018 int i;
9019 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9020 for (i=0; table[i].index != -1; i++) {
9021 if (strcmp(table[i].name, name) == 0) {
9022 return &table[i];
9023 }
9024 }
9025 return NULL;
9026}
9027
9028static const char *
9029iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9030{
9031 const char *name = rb_id2name(mid);
9032 static const char prefix[] = "__builtin_";
9033 const size_t prefix_len = sizeof(prefix) - 1;
9034
9035 switch (type) {
9036 case NODE_CALL:
9037 if (recv) {
9038 switch (nd_type(recv)) {
9039 case NODE_VCALL:
9040 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9041 return name;
9042 }
9043 break;
9044 case NODE_CONST:
9045 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9046 return name;
9047 }
9048 break;
9049 default: break;
9050 }
9051 }
9052 break;
9053 case NODE_VCALL:
9054 case NODE_FCALL:
9055 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9056 return &name[prefix_len];
9057 }
9058 break;
9059 default: break;
9060 }
9061 return NULL;
9062}
9063
9064static int
9065delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9066{
9067
9068 if (argc == 0) {
9069 *pstart_index = 0;
9070 return TRUE;
9071 }
9072 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9073 unsigned int start=0;
9074
9075 // local_table: [p1, p2, p3, l1, l2, l3]
9076 // arguments: [p3, l1, l2] -> 2
9077 for (start = 0;
9078 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9079 start++) {
9080 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9081
9082 for (unsigned int i=start; i-start<argc; i++) {
9083 if (IS_INSN(elem) &&
9084 INSN_OF(elem) == BIN(getlocal)) {
9085 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9086 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9087
9088 if (local_level == 0) {
9089 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9090 if (0) { // for debug
9091 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9092 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9093 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9094 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9095 }
9096 if (i == index) {
9097 elem = elem->next;
9098 continue; /* for */
9099 }
9100 else {
9101 goto next;
9102 }
9103 }
9104 else {
9105 goto fail; // level != 0 is unsupported
9106 }
9107 }
9108 else {
9109 goto fail; // insn is not a getlocal
9110 }
9111 }
9112 goto success;
9113 next:;
9114 }
9115 fail:
9116 return FALSE;
9117 success:
9118 *pstart_index = start;
9119 return TRUE;
9120 }
9121 else {
9122 return FALSE;
9123 }
9124}
9125
9126// Compile Primitive.attr! :leaf, ...
9127static int
9128compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9129{
9130 VALUE symbol;
9131 VALUE string;
9132 if (!node) goto no_arg;
9133 while (node) {
9134 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9135 const NODE *next = RNODE_LIST(node)->nd_next;
9136
9137 node = RNODE_LIST(node)->nd_head;
9138 if (!node) goto no_arg;
9139 switch (nd_type(node)) {
9140 case NODE_SYM:
9141 symbol = rb_node_sym_string_val(node);
9142 break;
9143 default:
9144 goto bad_arg;
9145 }
9146
9147 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9148
9149 string = rb_sym2str(symbol);
9150 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9151 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9152 }
9153 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9154 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9155 }
9156 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9157 iseq_set_use_block(iseq);
9158 }
9159 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9160 // Let the iseq act like a C method in backtraces
9161 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9162 }
9163 else {
9164 goto unknown_arg;
9165 }
9166 node = next;
9167 }
9168 return COMPILE_OK;
9169 no_arg:
9170 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9171 return COMPILE_NG;
9172 non_symbol_arg:
9173 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9174 return COMPILE_NG;
9175 unknown_arg:
9176 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9177 return COMPILE_NG;
9178 bad_arg:
9179 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9180}
9181
9182static int
9183compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9184{
9185 VALUE name;
9186
9187 if (!node) goto no_arg;
9188 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9189 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9190 node = RNODE_LIST(node)->nd_head;
9191 if (!node) goto no_arg;
9192 switch (nd_type(node)) {
9193 case NODE_SYM:
9194 name = rb_node_sym_string_val(node);
9195 break;
9196 default:
9197 goto bad_arg;
9198 }
9199 if (!SYMBOL_P(name)) goto non_symbol_arg;
9200 if (!popped) {
9201 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9202 }
9203 return COMPILE_OK;
9204 no_arg:
9205 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9206 return COMPILE_NG;
9207 too_many_arg:
9208 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9209 return COMPILE_NG;
9210 non_symbol_arg:
9211 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9212 rb_builtin_class_name(name));
9213 return COMPILE_NG;
9214 bad_arg:
9215 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9216}
9217
9218static NODE *
9219mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9220{
9221 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9222 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9223 return RNODE_IF(node)->nd_body;
9224 }
9225 else {
9226 rb_bug("mandatory_node: can't find mandatory node");
9227 }
9228}
9229
9230static int
9231compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9232{
9233 // arguments
9234 struct rb_args_info args = {
9235 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9236 };
9237 rb_node_args_t args_node;
9238 rb_node_init(RNODE(&args_node), NODE_ARGS);
9239 args_node.nd_ainfo = args;
9240
9241 // local table without non-mandatory parameters
9242 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9243 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9244
9245 VALUE idtmp = 0;
9246 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9247 tbl->size = table_size;
9248
9249 int i;
9250
9251 // lead parameters
9252 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9253 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9254 }
9255 // local variables
9256 for (; i<table_size; i++) {
9257 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9258 }
9259
9260 rb_node_scope_t scope_node;
9261 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9262 scope_node.nd_tbl = tbl;
9263 scope_node.nd_body = mandatory_node(iseq, node);
9264 scope_node.nd_args = &args_node;
9265
9266 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9267
9268 const rb_iseq_t *mandatory_only_iseq =
9269 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9270 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9271 nd_line(line_node), NULL, 0,
9272 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9273 ISEQ_BODY(iseq)->variable.script_lines);
9274 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9275
9276 ALLOCV_END(idtmp);
9277 return COMPILE_OK;
9278}
9279
9280static int
9281compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9282 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9283{
9284 NODE *args_node = get_nd_args(node);
9285
9286 if (parent_block != NULL) {
9287 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9288 return COMPILE_NG;
9289 }
9290 else {
9291# define BUILTIN_INLINE_PREFIX "_bi"
9292 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9293 bool cconst = false;
9294 retry:;
9295 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9296
9297 if (bf == NULL) {
9298 if (strcmp("cstmt!", builtin_func) == 0 ||
9299 strcmp("cexpr!", builtin_func) == 0) {
9300 // ok
9301 }
9302 else if (strcmp("cconst!", builtin_func) == 0) {
9303 cconst = true;
9304 }
9305 else if (strcmp("cinit!", builtin_func) == 0) {
9306 // ignore
9307 return COMPILE_OK;
9308 }
9309 else if (strcmp("attr!", builtin_func) == 0) {
9310 return compile_builtin_attr(iseq, args_node);
9311 }
9312 else if (strcmp("arg!", builtin_func) == 0) {
9313 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9314 }
9315 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9316 if (popped) {
9317 rb_bug("mandatory_only? should be in if condition");
9318 }
9319 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9320 rb_bug("mandatory_only? should be put on top");
9321 }
9322
9323 ADD_INSN1(ret, line_node, putobject, Qfalse);
9324 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9325 }
9326 else if (1) {
9327 rb_bug("can't find builtin function:%s", builtin_func);
9328 }
9329 else {
9330 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9331 return COMPILE_NG;
9332 }
9333
9334 int inline_index = nd_line(node);
9335 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9336 builtin_func = inline_func;
9337 args_node = NULL;
9338 goto retry;
9339 }
9340
9341 if (cconst) {
9342 typedef VALUE(*builtin_func0)(void *, VALUE);
9343 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9344 ADD_INSN1(ret, line_node, putobject, const_val);
9345 return COMPILE_OK;
9346 }
9347
9348 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9349
9350 unsigned int flag = 0;
9351 struct rb_callinfo_kwarg *keywords = NULL;
9352 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9353
9354 if (FIX2INT(argc) != bf->argc) {
9355 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9356 builtin_func, bf->argc, FIX2INT(argc));
9357 return COMPILE_NG;
9358 }
9359
9360 unsigned int start_index;
9361 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9362 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9363 }
9364 else {
9365 ADD_SEQ(ret, args);
9366 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9367 }
9368
9369 if (popped) ADD_INSN(ret, line_node, pop);
9370 return COMPILE_OK;
9371 }
9372}
9373
9374static int
9375compile_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)
9376{
9377 /* call: obj.method(...)
9378 * fcall: func(...)
9379 * vcall: func
9380 */
9381 DECL_ANCHOR(recv);
9382 DECL_ANCHOR(args);
9383 ID mid = get_node_call_nd_mid(node);
9384 VALUE argc;
9385 unsigned int flag = 0;
9386 struct rb_callinfo_kwarg *keywords = NULL;
9387 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9388 LABEL *else_label = NULL;
9389 VALUE branches = Qfalse;
9390
9391 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9392
9393 INIT_ANCHOR(recv);
9394 INIT_ANCHOR(args);
9395
9396#if OPT_SUPPORT_JOKE
9397 if (nd_type_p(node, NODE_VCALL)) {
9398 ID id_bitblt;
9399 ID id_answer;
9400
9401 CONST_ID(id_bitblt, "bitblt");
9402 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9403
9404 if (mid == id_bitblt) {
9405 ADD_INSN(ret, line_node, bitblt);
9406 return COMPILE_OK;
9407 }
9408 else if (mid == id_answer) {
9409 ADD_INSN(ret, line_node, answer);
9410 return COMPILE_OK;
9411 }
9412 }
9413 /* only joke */
9414 {
9415 ID goto_id;
9416 ID label_id;
9417
9418 CONST_ID(goto_id, "__goto__");
9419 CONST_ID(label_id, "__label__");
9420
9421 if (nd_type_p(node, NODE_FCALL) &&
9422 (mid == goto_id || mid == label_id)) {
9423 LABEL *label;
9424 st_data_t data;
9425 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9426 VALUE label_name;
9427
9428 if (!labels_table) {
9429 labels_table = st_init_numtable();
9430 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9431 }
9432 {
9433 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9434 return COMPILE_NG;
9435 }
9436
9437 if (mid == goto_id) {
9438 ADD_INSNL(ret, line_node, jump, label);
9439 }
9440 else {
9441 ADD_LABEL(ret, label);
9442 }
9443 return COMPILE_OK;
9444 }
9445 }
9446#endif
9447
9448 const char *builtin_func;
9449 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9450 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9451 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9452 }
9453
9454 /* receiver */
9455 if (!assume_receiver) {
9456 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9457 int idx, level;
9458
9459 if (mid == idCall &&
9460 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9461 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9462 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9463 }
9464 else if (private_recv_p(node)) {
9465 ADD_INSN(recv, node, putself);
9466 flag |= VM_CALL_FCALL;
9467 }
9468 else {
9469 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9470 }
9471
9472 if (type == NODE_QCALL) {
9473 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9474 }
9475 }
9476 else if (type == NODE_FCALL || type == NODE_VCALL) {
9477 ADD_CALL_RECEIVER(recv, line_node);
9478 }
9479 }
9480
9481 /* args */
9482 if (type != NODE_VCALL) {
9483 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9484 CHECK(!NIL_P(argc));
9485 }
9486 else {
9487 argc = INT2FIX(0);
9488 }
9489
9490 ADD_SEQ(ret, recv);
9491
9492 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9493 mid == rb_intern("new") &&
9494 parent_block == NULL &&
9495 !(flag & VM_CALL_ARGS_BLOCKARG);
9496
9497 if (inline_new) {
9498 ADD_INSN(ret, node, putnil);
9499 ADD_INSN(ret, node, swap);
9500 }
9501
9502 ADD_SEQ(ret, args);
9503
9504 debugp_param("call args argc", argc);
9505 debugp_param("call method", ID2SYM(mid));
9506
9507 switch ((int)type) {
9508 case NODE_VCALL:
9509 flag |= VM_CALL_VCALL;
9510 /* VCALL is funcall, so fall through */
9511 case NODE_FCALL:
9512 flag |= VM_CALL_FCALL;
9513 }
9514
9515 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9516 ADD_INSN(ret, line_node, splatkw);
9517 }
9518
9519 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9520 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9521
9522 if (inline_new) {
9523 // Jump unless the receiver uses the "basic" implementation of "new"
9524 VALUE ci;
9525 if (flag & VM_CALL_FORWARDING) {
9526 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9527 }
9528 else {
9529 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9530 }
9531 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9532 LABEL_REF(not_basic_new);
9533
9534 // optimized path
9535 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9536 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9537
9538 ADD_LABEL(ret, not_basic_new);
9539 // Fall back to normal send
9540 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9541 ADD_INSN(ret, line_node, swap);
9542
9543 ADD_LABEL(ret, not_basic_new_finish);
9544 ADD_INSN(ret, line_node, pop);
9545 }
9546 else {
9547 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9548 }
9549
9550 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9551 if (popped) {
9552 ADD_INSN(ret, line_node, pop);
9553 }
9554 return COMPILE_OK;
9555}
9556
9557static int
9558compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9559{
9560 const int line = nd_line(node);
9561 VALUE argc;
9562 unsigned int flag = 0;
9563 int asgnflag = 0;
9564 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9565
9566 /*
9567 * a[x] (op)= y
9568 *
9569 * nil # nil
9570 * eval a # nil a
9571 * eval x # nil a x
9572 * dupn 2 # nil a x a x
9573 * send :[] # nil a x a[x]
9574 * eval y # nil a x a[x] y
9575 * send op # nil a x ret
9576 * setn 3 # ret a x ret
9577 * send []= # ret ?
9578 * pop # ret
9579 */
9580
9581 /*
9582 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9583 * NODE_OP_ASGN nd_recv
9584 * nd_args->nd_head
9585 * nd_args->nd_body
9586 * nd_mid
9587 */
9588
9589 if (!popped) {
9590 ADD_INSN(ret, node, putnil);
9591 }
9592 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9593 CHECK(asgnflag != -1);
9594 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9595 case NODE_ZLIST:
9596 argc = INT2FIX(0);
9597 break;
9598 default:
9599 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9600 CHECK(!NIL_P(argc));
9601 }
9602 int dup_argn = FIX2INT(argc) + 1;
9603 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9604 flag |= asgnflag;
9605 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9606
9607 if (id == idOROP || id == idANDOP) {
9608 /* a[x] ||= y or a[x] &&= y
9609
9610 unless/if a[x]
9611 a[x]= y
9612 else
9613 nil
9614 end
9615 */
9616 LABEL *label = NEW_LABEL(line);
9617 LABEL *lfin = NEW_LABEL(line);
9618
9619 ADD_INSN(ret, node, dup);
9620 if (id == idOROP) {
9621 ADD_INSNL(ret, node, branchif, label);
9622 }
9623 else { /* idANDOP */
9624 ADD_INSNL(ret, node, branchunless, label);
9625 }
9626 ADD_INSN(ret, node, pop);
9627
9628 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9629 if (!popped) {
9630 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9631 }
9632 if (flag & VM_CALL_ARGS_SPLAT) {
9633 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9634 ADD_INSN(ret, node, swap);
9635 ADD_INSN1(ret, node, splatarray, Qtrue);
9636 ADD_INSN(ret, node, swap);
9637 flag |= VM_CALL_ARGS_SPLAT_MUT;
9638 }
9639 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9640 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9641 }
9642 else {
9643 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9644 }
9645 ADD_INSN(ret, node, pop);
9646 ADD_INSNL(ret, node, jump, lfin);
9647 ADD_LABEL(ret, label);
9648 if (!popped) {
9649 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9650 }
9651 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9652 ADD_LABEL(ret, lfin);
9653 }
9654 else {
9655 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9656 ADD_SEND(ret, node, id, INT2FIX(1));
9657 if (!popped) {
9658 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9659 }
9660 if (flag & VM_CALL_ARGS_SPLAT) {
9661 if (flag & VM_CALL_KW_SPLAT) {
9662 ADD_INSN1(ret, node, topn, INT2FIX(2));
9663 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9664 ADD_INSN1(ret, node, splatarray, Qtrue);
9665 flag |= VM_CALL_ARGS_SPLAT_MUT;
9666 }
9667 ADD_INSN(ret, node, swap);
9668 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9669 ADD_INSN1(ret, node, setn, INT2FIX(2));
9670 ADD_INSN(ret, node, pop);
9671 }
9672 else {
9673 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9674 ADD_INSN(ret, node, swap);
9675 ADD_INSN1(ret, node, splatarray, Qtrue);
9676 ADD_INSN(ret, node, swap);
9677 flag |= VM_CALL_ARGS_SPLAT_MUT;
9678 }
9679 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9680 }
9681 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9682 }
9683 else {
9684 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9685 }
9686 ADD_INSN(ret, node, pop);
9687 }
9688 return COMPILE_OK;
9689}
9690
9691static int
9692compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9693{
9694 const int line = nd_line(node);
9695 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9696 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9697 int asgnflag;
9698 LABEL *lfin = NEW_LABEL(line);
9699 LABEL *lcfin = NEW_LABEL(line);
9700 LABEL *lskip = 0;
9701 /*
9702 class C; attr_accessor :c; end
9703 r = C.new
9704 r.a &&= v # asgn2
9705
9706 eval r # r
9707 dup # r r
9708 eval r.a # r o
9709
9710 # or
9711 dup # r o o
9712 if lcfin # r o
9713 pop # r
9714 eval v # r v
9715 swap # v r
9716 topn 1 # v r v
9717 send a= # v ?
9718 jump lfin # v ?
9719
9720 lcfin: # r o
9721 swap # o r
9722
9723 lfin: # o ?
9724 pop # o
9725
9726 # or (popped)
9727 if lcfin # r
9728 eval v # r v
9729 send a= # ?
9730 jump lfin # ?
9731
9732 lcfin: # r
9733
9734 lfin: # ?
9735 pop #
9736
9737 # and
9738 dup # r o o
9739 unless lcfin
9740 pop # r
9741 eval v # r v
9742 swap # v r
9743 topn 1 # v r v
9744 send a= # v ?
9745 jump lfin # v ?
9746
9747 # others
9748 eval v # r o v
9749 send ?? # r w
9750 send a= # w
9751
9752 */
9753
9754 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9755 CHECK(asgnflag != -1);
9756 if (RNODE_OP_ASGN2(node)->nd_aid) {
9757 lskip = NEW_LABEL(line);
9758 ADD_INSN(ret, node, dup);
9759 ADD_INSNL(ret, node, branchnil, lskip);
9760 }
9761 ADD_INSN(ret, node, dup);
9762 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9763
9764 if (atype == idOROP || atype == idANDOP) {
9765 if (!popped) {
9766 ADD_INSN(ret, node, dup);
9767 }
9768 if (atype == idOROP) {
9769 ADD_INSNL(ret, node, branchif, lcfin);
9770 }
9771 else { /* idANDOP */
9772 ADD_INSNL(ret, node, branchunless, lcfin);
9773 }
9774 if (!popped) {
9775 ADD_INSN(ret, node, pop);
9776 }
9777 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9778 if (!popped) {
9779 ADD_INSN(ret, node, swap);
9780 ADD_INSN1(ret, node, topn, INT2FIX(1));
9781 }
9782 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9783 ADD_INSNL(ret, node, jump, lfin);
9784
9785 ADD_LABEL(ret, lcfin);
9786 if (!popped) {
9787 ADD_INSN(ret, node, swap);
9788 }
9789
9790 ADD_LABEL(ret, lfin);
9791 }
9792 else {
9793 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9794 ADD_SEND(ret, node, atype, INT2FIX(1));
9795 if (!popped) {
9796 ADD_INSN(ret, node, swap);
9797 ADD_INSN1(ret, node, topn, INT2FIX(1));
9798 }
9799 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9800 }
9801 if (lskip && popped) {
9802 ADD_LABEL(ret, lskip);
9803 }
9804 ADD_INSN(ret, node, pop);
9805 if (lskip && !popped) {
9806 ADD_LABEL(ret, lskip);
9807 }
9808 return COMPILE_OK;
9809}
9810
9811static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9812
9813static int
9814compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9815{
9816 const int line = nd_line(node);
9817 LABEL *lfin = 0;
9818 LABEL *lassign = 0;
9819 ID mid;
9820
9821 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9822 case NODE_COLON3:
9823 ADD_INSN1(ret, node, putobject, rb_cObject);
9824 break;
9825 case NODE_COLON2:
9826 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9827 break;
9828 default:
9829 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9830 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9831 return COMPILE_NG;
9832 }
9833 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9834 /* cref */
9835 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9836 lassign = NEW_LABEL(line);
9837 ADD_INSN(ret, node, dup); /* cref cref */
9838 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9839 ID2SYM(mid), Qtrue); /* cref bool */
9840 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9841 }
9842 ADD_INSN(ret, node, dup); /* cref cref */
9843 ADD_INSN1(ret, node, putobject, Qtrue);
9844 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9845
9846 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9847 lfin = NEW_LABEL(line);
9848 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9849 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9850 ADD_INSNL(ret, node, branchif, lfin);
9851 else /* idANDOP */
9852 ADD_INSNL(ret, node, branchunless, lfin);
9853 /* cref [obj] */
9854 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9855 if (lassign) ADD_LABEL(ret, lassign);
9856 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9857 /* cref value */
9858 if (popped)
9859 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9860 else {
9861 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9862 ADD_INSN(ret, node, swap); /* cref value value cref */
9863 }
9864 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9865 ADD_LABEL(ret, lfin); /* cref [value] */
9866 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9867 ADD_INSN(ret, node, pop); /* [value] */
9868 }
9869 else {
9870 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9871 /* cref obj value */
9872 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9873 /* cref value */
9874 ADD_INSN(ret, node, swap); /* value cref */
9875 if (!popped) {
9876 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9877 ADD_INSN(ret, node, swap); /* value value cref */
9878 }
9879 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9880 }
9881 return COMPILE_OK;
9882}
9883
9884static int
9885compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9886{
9887 const int line = nd_line(node);
9888 LABEL *lfin = NEW_LABEL(line);
9889 LABEL *lassign;
9890
9891 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9892 LABEL *lfinish[2];
9893 lfinish[0] = lfin;
9894 lfinish[1] = 0;
9895 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9896 lassign = lfinish[1];
9897 if (!lassign) {
9898 lassign = NEW_LABEL(line);
9899 }
9900 ADD_INSNL(ret, node, branchunless, lassign);
9901 }
9902 else {
9903 lassign = NEW_LABEL(line);
9904 }
9905
9906 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9907
9908 if (!popped) {
9909 ADD_INSN(ret, node, dup);
9910 }
9911
9912 if (type == NODE_OP_ASGN_AND) {
9913 ADD_INSNL(ret, node, branchunless, lfin);
9914 }
9915 else {
9916 ADD_INSNL(ret, node, branchif, lfin);
9917 }
9918
9919 if (!popped) {
9920 ADD_INSN(ret, node, pop);
9921 }
9922
9923 ADD_LABEL(ret, lassign);
9924 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9925 ADD_LABEL(ret, lfin);
9926 return COMPILE_OK;
9927}
9928
9929static int
9930compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9931{
9932 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9933 DECL_ANCHOR(args);
9934 int argc;
9935 unsigned int flag = 0;
9936 struct rb_callinfo_kwarg *keywords = NULL;
9937 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9938 int use_block = 1;
9939
9940 INIT_ANCHOR(args);
9941 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9942
9943 if (type == NODE_SUPER) {
9944 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9945 CHECK(!NIL_P(vargc));
9946 argc = FIX2INT(vargc);
9947 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9948 ADD_INSN(args, node, splatkw);
9949 }
9950
9951 if (flag & VM_CALL_ARGS_BLOCKARG) {
9952 use_block = 0;
9953 }
9954 }
9955 else {
9956 /* NODE_ZSUPER */
9957 int i;
9958 const rb_iseq_t *liseq = body->local_iseq;
9959 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9960 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9961 int lvar_level = get_lvar_level(iseq);
9962
9963 argc = local_body->param.lead_num;
9964
9965 /* normal arguments */
9966 for (i = 0; i < local_body->param.lead_num; i++) {
9967 int idx = local_body->local_table_size - i;
9968 ADD_GETLOCAL(args, node, idx, lvar_level);
9969 }
9970
9971 /* forward ... */
9972 if (local_body->param.flags.forwardable) {
9973 flag |= VM_CALL_FORWARDING;
9974 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9975 ADD_GETLOCAL(args, node, idx, lvar_level);
9976 }
9977
9978 if (local_body->param.flags.has_opt) {
9979 /* optional arguments */
9980 int j;
9981 for (j = 0; j < local_body->param.opt_num; j++) {
9982 int idx = local_body->local_table_size - (i + j);
9983 ADD_GETLOCAL(args, node, idx, lvar_level);
9984 }
9985 i += j;
9986 argc = i;
9987 }
9988 if (local_body->param.flags.has_rest) {
9989 /* rest argument */
9990 int idx = local_body->local_table_size - local_body->param.rest_start;
9991 ADD_GETLOCAL(args, node, idx, lvar_level);
9992 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9993
9994 argc = local_body->param.rest_start + 1;
9995 flag |= VM_CALL_ARGS_SPLAT;
9996 }
9997 if (local_body->param.flags.has_post) {
9998 /* post arguments */
9999 int post_len = local_body->param.post_num;
10000 int post_start = local_body->param.post_start;
10001
10002 if (local_body->param.flags.has_rest) {
10003 int j;
10004 for (j=0; j<post_len; j++) {
10005 int idx = local_body->local_table_size - (post_start + j);
10006 ADD_GETLOCAL(args, node, idx, lvar_level);
10007 }
10008 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10009 flag |= VM_CALL_ARGS_SPLAT_MUT;
10010 /* argc is settled at above */
10011 }
10012 else {
10013 int j;
10014 for (j=0; j<post_len; j++) {
10015 int idx = local_body->local_table_size - (post_start + j);
10016 ADD_GETLOCAL(args, node, idx, lvar_level);
10017 }
10018 argc = post_len + post_start;
10019 }
10020 }
10021
10022 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10023 int local_size = local_body->local_table_size;
10024 argc++;
10025
10026 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10027
10028 if (local_body->param.flags.has_kwrest) {
10029 int idx = local_body->local_table_size - local_kwd->rest_start;
10030 ADD_GETLOCAL(args, node, idx, lvar_level);
10031 RUBY_ASSERT(local_kwd->num > 0);
10032 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10033 }
10034 else {
10035 ADD_INSN1(args, node, newhash, INT2FIX(0));
10036 }
10037 for (i = 0; i < local_kwd->num; ++i) {
10038 ID id = local_kwd->table[i];
10039 int idx = local_size - get_local_var_idx(liseq, id);
10040 ADD_INSN1(args, node, putobject, ID2SYM(id));
10041 ADD_GETLOCAL(args, node, idx, lvar_level);
10042 }
10043 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10044 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10045 }
10046 else if (local_body->param.flags.has_kwrest) {
10047 int idx = local_body->local_table_size - local_kwd->rest_start;
10048 ADD_GETLOCAL(args, node, idx, lvar_level);
10049 argc++;
10050 flag |= VM_CALL_KW_SPLAT;
10051 }
10052 }
10053
10054 if (use_block && parent_block == NULL) {
10055 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10056 }
10057
10058 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10059 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10060 ADD_INSN(ret, node, putself);
10061 ADD_SEQ(ret, args);
10062
10063 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10064
10065 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10066 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10067 }
10068 else {
10069 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10070 }
10071
10072 if (popped) {
10073 ADD_INSN(ret, node, pop);
10074 }
10075 return COMPILE_OK;
10076}
10077
10078static int
10079compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10080{
10081 DECL_ANCHOR(args);
10082 VALUE argc;
10083 unsigned int flag = 0;
10084 struct rb_callinfo_kwarg *keywords = NULL;
10085
10086 INIT_ANCHOR(args);
10087
10088 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10089 case ISEQ_TYPE_TOP:
10090 case ISEQ_TYPE_MAIN:
10091 case ISEQ_TYPE_CLASS:
10092 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10093 return COMPILE_NG;
10094 default: /* valid */;
10095 }
10096
10097 if (RNODE_YIELD(node)->nd_head) {
10098 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10099 CHECK(!NIL_P(argc));
10100 }
10101 else {
10102 argc = INT2FIX(0);
10103 }
10104
10105 ADD_SEQ(ret, args);
10106 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10107 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10108
10109 if (popped) {
10110 ADD_INSN(ret, node, pop);
10111 }
10112
10113 int level = 0;
10114 const rb_iseq_t *tmp_iseq = iseq;
10115 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10116 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10117 }
10118 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10119
10120 return COMPILE_OK;
10121}
10122
10123static int
10124compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10125{
10126 DECL_ANCHOR(recv);
10127 DECL_ANCHOR(val);
10128
10129 INIT_ANCHOR(recv);
10130 INIT_ANCHOR(val);
10131 switch ((int)type) {
10132 case NODE_MATCH:
10133 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10134 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10135 INT2FIX(0));
10136 break;
10137 case NODE_MATCH2:
10138 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10139 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10140 break;
10141 case NODE_MATCH3:
10142 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10143 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10144 break;
10145 }
10146
10147 ADD_SEQ(ret, recv);
10148 ADD_SEQ(ret, val);
10149 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10150
10151 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10152 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10153 }
10154
10155 if (popped) {
10156 ADD_INSN(ret, node, pop);
10157 }
10158 return COMPILE_OK;
10159}
10160
10161static int
10162compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10163{
10164 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10165 /* constant */
10166 VALUE segments;
10167 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10168 (segments = collect_const_segments(iseq, node))) {
10169 ISEQ_BODY(iseq)->ic_size++;
10170 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10171 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10172 }
10173 else {
10174 /* constant */
10175 DECL_ANCHOR(pref);
10176 DECL_ANCHOR(body);
10177
10178 INIT_ANCHOR(pref);
10179 INIT_ANCHOR(body);
10180 CHECK(compile_const_prefix(iseq, node, pref, body));
10181 if (LIST_INSN_SIZE_ZERO(pref)) {
10182 ADD_INSN(ret, node, putnil);
10183 ADD_SEQ(ret, body);
10184 }
10185 else {
10186 ADD_SEQ(ret, pref);
10187 ADD_SEQ(ret, body);
10188 }
10189 }
10190 }
10191 else {
10192 /* function call */
10193 ADD_CALL_RECEIVER(ret, node);
10194 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10195 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10196 }
10197 if (popped) {
10198 ADD_INSN(ret, node, pop);
10199 }
10200 return COMPILE_OK;
10201}
10202
10203static int
10204compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10205{
10206 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10207
10208 /* add cache insn */
10209 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10210 ISEQ_BODY(iseq)->ic_size++;
10211 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10212 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10213 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10214 }
10215 else {
10216 ADD_INSN1(ret, node, putobject, rb_cObject);
10217 ADD_INSN1(ret, node, putobject, Qtrue);
10218 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10219 }
10220
10221 if (popped) {
10222 ADD_INSN(ret, node, pop);
10223 }
10224 return COMPILE_OK;
10225}
10226
10227static int
10228compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10229{
10230 VALUE flag = INT2FIX(excl);
10231 const NODE *b = RNODE_DOT2(node)->nd_beg;
10232 const NODE *e = RNODE_DOT2(node)->nd_end;
10233
10234 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10235 if (!popped) {
10236 VALUE bv = optimized_range_item(b);
10237 VALUE ev = optimized_range_item(e);
10238 VALUE val = rb_range_new(bv, ev, excl);
10239 ADD_INSN1(ret, node, putobject, val);
10240 RB_OBJ_WRITTEN(iseq, Qundef, val);
10241 }
10242 }
10243 else {
10244 CHECK(COMPILE_(ret, "min", b, popped));
10245 CHECK(COMPILE_(ret, "max", e, popped));
10246 if (!popped) {
10247 ADD_INSN1(ret, node, newrange, flag);
10248 }
10249 }
10250 return COMPILE_OK;
10251}
10252
10253static int
10254compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10255{
10256 if (!popped) {
10257 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10258 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10259 }
10260 else {
10261 const rb_iseq_t *ip = iseq;
10262 int level = 0;
10263 while (ip) {
10264 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10265 break;
10266 }
10267 ip = ISEQ_BODY(ip)->parent_iseq;
10268 level++;
10269 }
10270 if (ip) {
10271 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10272 }
10273 else {
10274 ADD_INSN(ret, node, putnil);
10275 }
10276 }
10277 }
10278 return COMPILE_OK;
10279}
10280
10281static int
10282compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10283{
10284 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10285 LABEL *end_label = NEW_LABEL(nd_line(node));
10286 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10287
10288 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10289 /* required argument. do nothing */
10290 COMPILE_ERROR(ERROR_ARGS "unreachable");
10291 return COMPILE_NG;
10292 }
10293 else if (nd_type_p(default_value, NODE_SYM) ||
10294 nd_type_p(default_value, NODE_REGX) ||
10295 nd_type_p(default_value, NODE_LINE) ||
10296 nd_type_p(default_value, NODE_INTEGER) ||
10297 nd_type_p(default_value, NODE_FLOAT) ||
10298 nd_type_p(default_value, NODE_RATIONAL) ||
10299 nd_type_p(default_value, NODE_IMAGINARY) ||
10300 nd_type_p(default_value, NODE_NIL) ||
10301 nd_type_p(default_value, NODE_TRUE) ||
10302 nd_type_p(default_value, NODE_FALSE)) {
10303 COMPILE_ERROR(ERROR_ARGS "unreachable");
10304 return COMPILE_NG;
10305 }
10306 else {
10307 /* if keywordcheck(_kw_bits, nth_keyword)
10308 * kw = default_value
10309 * end
10310 */
10311 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10312 int keyword_idx = body->param.keyword->num;
10313
10314 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10315 ADD_INSNL(ret, node, branchif, end_label);
10316 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10317 ADD_LABEL(ret, end_label);
10318 }
10319 return COMPILE_OK;
10320}
10321
10322static int
10323compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10324{
10325 DECL_ANCHOR(recv);
10326 DECL_ANCHOR(args);
10327 unsigned int flag = 0;
10328 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10329 VALUE argc;
10330 LABEL *else_label = NULL;
10331 VALUE branches = Qfalse;
10332
10333 /* optimization shortcut
10334 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10335 */
10336 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10337 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10338 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10339 (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)) &&
10340 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10341 !frozen_string_literal_p(iseq) &&
10342 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10343 {
10344 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10345 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10346 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10347 if (!popped) {
10348 ADD_INSN(ret, node, swap);
10349 ADD_INSN1(ret, node, topn, INT2FIX(1));
10350 }
10351 ADD_INSN2(ret, node, opt_aset_with, str,
10352 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10353 RB_OBJ_WRITTEN(iseq, Qundef, str);
10354 ADD_INSN(ret, node, pop);
10355 return COMPILE_OK;
10356 }
10357
10358 INIT_ANCHOR(recv);
10359 INIT_ANCHOR(args);
10360 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10361 CHECK(!NIL_P(argc));
10362
10363 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10364 CHECK(asgnflag != -1);
10365 flag |= (unsigned int)asgnflag;
10366
10367 debugp_param("argc", argc);
10368 debugp_param("nd_mid", ID2SYM(mid));
10369
10370 if (!rb_is_attrset_id(mid)) {
10371 /* safe nav attr */
10372 mid = rb_id_attrset(mid);
10373 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10374 }
10375 if (!popped) {
10376 ADD_INSN(ret, node, putnil);
10377 ADD_SEQ(ret, recv);
10378 ADD_SEQ(ret, args);
10379
10380 if (flag & VM_CALL_ARGS_SPLAT) {
10381 ADD_INSN(ret, node, dup);
10382 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10383 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10384 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10385 ADD_INSN (ret, node, pop);
10386 }
10387 else {
10388 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10389 }
10390 }
10391 else {
10392 ADD_SEQ(ret, recv);
10393 ADD_SEQ(ret, args);
10394 }
10395 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10396 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10397 ADD_INSN(ret, node, pop);
10398 return COMPILE_OK;
10399}
10400
10401static int
10402compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10403{
10404 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10405 ADD_SEQ(ret, sub);
10406
10407 if (copy) {
10408 /*
10409 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10410 * NEW_LIST(value, loc), loc);
10411 */
10412 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10413 }
10414 else {
10415 /*
10416 * NEW_CALL(fcore, rb_intern("make_shareable"),
10417 * NEW_LIST(value, loc), loc);
10418 */
10419 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10420 }
10421
10422 return COMPILE_OK;
10423}
10424
10425static VALUE
10426node_const_decl_val(const NODE *node)
10427{
10428 VALUE path;
10429 switch (nd_type(node)) {
10430 case NODE_CDECL:
10431 if (RNODE_CDECL(node)->nd_vid) {
10432 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10433 goto end;
10434 }
10435 else {
10436 node = RNODE_CDECL(node)->nd_else;
10437 }
10438 break;
10439 case NODE_COLON2:
10440 break;
10441 case NODE_COLON3:
10442 // ::Const
10443 path = rb_str_new_cstr("::");
10444 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10445 goto end;
10446 default:
10447 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10449 }
10450
10451 path = rb_ary_new();
10452 if (node) {
10453 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10454 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10455 }
10456 if (node && nd_type_p(node, NODE_CONST)) {
10457 // Const::Name
10458 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10459 }
10460 else if (node && nd_type_p(node, NODE_COLON3)) {
10461 // ::Const::Name
10462 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10463 rb_ary_push(path, rb_str_new(0, 0));
10464 }
10465 else {
10466 // expression::Name
10467 rb_ary_push(path, rb_str_new_cstr("..."));
10468 }
10469 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10470 }
10471 end:
10472 path = rb_fstring(path);
10473 return path;
10474}
10475
10476static VALUE
10477const_decl_path(NODE *dest)
10478{
10479 VALUE path = Qnil;
10480 if (!nd_type_p(dest, NODE_CALL)) {
10481 path = node_const_decl_val(dest);
10482 }
10483 return path;
10484}
10485
10486static int
10487compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10488{
10489 /*
10490 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10491 */
10492 VALUE path = const_decl_path(dest);
10493 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10494 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10495 ADD_INSN1(ret, value, putobject, path);
10496 RB_OBJ_WRITTEN(iseq, Qundef, path);
10497 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10498
10499 return COMPILE_OK;
10500}
10501
10502#ifndef SHAREABLE_BARE_EXPRESSION
10503#define SHAREABLE_BARE_EXPRESSION 1
10504#endif
10505
10506static int
10507compile_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)
10508{
10509# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10510 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10511 VALUE lit = Qnil;
10512 DECL_ANCHOR(anchor);
10513
10514 enum node_type type = node ? nd_type(node) : NODE_NIL;
10515 switch (type) {
10516 case NODE_TRUE:
10517 *value_p = Qtrue;
10518 goto compile;
10519 case NODE_FALSE:
10520 *value_p = Qfalse;
10521 goto compile;
10522 case NODE_NIL:
10523 *value_p = Qnil;
10524 goto compile;
10525 case NODE_SYM:
10526 *value_p = rb_node_sym_string_val(node);
10527 goto compile;
10528 case NODE_REGX:
10529 *value_p = rb_node_regx_string_val(node);
10530 goto compile;
10531 case NODE_LINE:
10532 *value_p = rb_node_line_lineno_val(node);
10533 goto compile;
10534 case NODE_INTEGER:
10535 *value_p = rb_node_integer_literal_val(node);
10536 goto compile;
10537 case NODE_FLOAT:
10538 *value_p = rb_node_float_literal_val(node);
10539 goto compile;
10540 case NODE_RATIONAL:
10541 *value_p = rb_node_rational_literal_val(node);
10542 goto compile;
10543 case NODE_IMAGINARY:
10544 *value_p = rb_node_imaginary_literal_val(node);
10545 goto compile;
10546 case NODE_ENCODING:
10547 *value_p = rb_node_encoding_val(node);
10548
10549 compile:
10550 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10551 *shareable_literal_p = 1;
10552 return COMPILE_OK;
10553
10554 case NODE_DSTR:
10555 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10556 if (shareable == rb_parser_shareable_literal) {
10557 /*
10558 * NEW_CALL(node, idUMinus, 0, loc);
10559 *
10560 * -"#{var}"
10561 */
10562 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10563 }
10564 *value_p = Qundef;
10565 *shareable_literal_p = 1;
10566 return COMPILE_OK;
10567
10568 case NODE_STR:{
10569 VALUE lit = rb_node_str_string_val(node);
10570 ADD_INSN1(ret, node, putobject, lit);
10571 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10572 *value_p = lit;
10573 *shareable_literal_p = 1;
10574
10575 return COMPILE_OK;
10576 }
10577
10578 case NODE_FILE:{
10579 VALUE lit = rb_node_file_path_val(node);
10580 ADD_INSN1(ret, node, putobject, lit);
10581 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10582 *value_p = lit;
10583 *shareable_literal_p = 1;
10584
10585 return COMPILE_OK;
10586 }
10587
10588 case NODE_ZLIST:{
10589 VALUE lit = rb_ary_new();
10590 OBJ_FREEZE(lit);
10591 ADD_INSN1(ret, node, putobject, lit);
10592 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10593 *value_p = lit;
10594 *shareable_literal_p = 1;
10595
10596 return COMPILE_OK;
10597 }
10598
10599 case NODE_LIST:{
10600 INIT_ANCHOR(anchor);
10601 lit = rb_ary_new();
10602 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10603 VALUE val;
10604 int shareable_literal_p2;
10605 NODE *elt = RNODE_LIST(n)->nd_head;
10606 if (elt) {
10607 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10608 if (shareable_literal_p2) {
10609 /* noop */
10610 }
10611 else if (RTEST(lit)) {
10612 rb_ary_clear(lit);
10613 lit = Qfalse;
10614 }
10615 }
10616 if (RTEST(lit)) {
10617 if (!UNDEF_P(val)) {
10618 rb_ary_push(lit, val);
10619 }
10620 else {
10621 rb_ary_clear(lit);
10622 lit = Qnil; /* make shareable at runtime */
10623 }
10624 }
10625 }
10626 break;
10627 }
10628 case NODE_HASH:{
10629 if (!RNODE_HASH(node)->nd_brace) {
10630 *value_p = Qundef;
10631 *shareable_literal_p = 0;
10632 return COMPILE_OK;
10633 }
10634 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10635 if (!RNODE_LIST(n)->nd_head) {
10636 // If the hash node have a keyword splat, fall back to the default case.
10637 goto compile_shareable;
10638 }
10639 }
10640
10641 INIT_ANCHOR(anchor);
10642 lit = rb_hash_new();
10643 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10644 VALUE key_val = 0;
10645 VALUE value_val = 0;
10646 int shareable_literal_p2;
10647 NODE *key = RNODE_LIST(n)->nd_head;
10648 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10649 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10650 if (shareable_literal_p2) {
10651 /* noop */
10652 }
10653 else if (RTEST(lit)) {
10654 rb_hash_clear(lit);
10655 lit = Qfalse;
10656 }
10657 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10658 if (shareable_literal_p2) {
10659 /* noop */
10660 }
10661 else if (RTEST(lit)) {
10662 rb_hash_clear(lit);
10663 lit = Qfalse;
10664 }
10665 if (RTEST(lit)) {
10666 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10667 rb_hash_aset(lit, key_val, value_val);
10668 }
10669 else {
10670 rb_hash_clear(lit);
10671 lit = Qnil; /* make shareable at runtime */
10672 }
10673 }
10674 }
10675 break;
10676 }
10677
10678 default:
10679
10680 compile_shareable:
10681 if (shareable == rb_parser_shareable_literal &&
10682 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10683 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10684 *value_p = Qundef;
10685 *shareable_literal_p = 1;
10686 return COMPILE_OK;
10687 }
10688 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10689 *value_p = Qundef;
10690 *shareable_literal_p = 0;
10691 return COMPILE_OK;
10692 }
10693
10694 /* Array or Hash that does not have keyword splat */
10695 if (!lit) {
10696 if (nd_type(node) == NODE_LIST) {
10697 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10698 }
10699 else if (nd_type(node) == NODE_HASH) {
10700 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10701 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10702 }
10703 *value_p = Qundef;
10704 *shareable_literal_p = 0;
10705 ADD_SEQ(ret, anchor);
10706 return COMPILE_OK;
10707 }
10708 if (NIL_P(lit)) {
10709 // if shareable_literal, all elements should have been ensured
10710 // as shareable
10711 if (nd_type(node) == NODE_LIST) {
10712 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10713 }
10714 else if (nd_type(node) == NODE_HASH) {
10715 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10716 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10717 }
10718 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10719 *value_p = Qundef;
10720 *shareable_literal_p = 1;
10721 }
10722 else {
10724 ADD_INSN1(ret, node, putobject, val);
10725 RB_OBJ_WRITTEN(iseq, Qundef, val);
10726 *value_p = val;
10727 *shareable_literal_p = 1;
10728 }
10729
10730 return COMPILE_OK;
10731}
10732
10733static int
10734compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10735{
10736 int literal_p = 0;
10737 VALUE val;
10738 DECL_ANCHOR(anchor);
10739 INIT_ANCHOR(anchor);
10740
10741 switch (shareable) {
10742 case rb_parser_shareable_none:
10743 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10744 return COMPILE_OK;
10745
10746 case rb_parser_shareable_literal:
10747 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10748 ADD_SEQ(ret, anchor);
10749 return COMPILE_OK;
10750
10751 case rb_parser_shareable_copy:
10752 case rb_parser_shareable_everything:
10753 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10754 if (!literal_p) {
10755 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10756 }
10757 else {
10758 ADD_SEQ(ret, anchor);
10759 }
10760 return COMPILE_OK;
10761 default:
10762 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10763 }
10764}
10765
10766static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10774static int
10775iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10776{
10777 if (node == 0) {
10778 if (!popped) {
10779 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10780 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10781 debugs("node: NODE_NIL(implicit)\n");
10782 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10783 }
10784 return COMPILE_OK;
10785 }
10786 return iseq_compile_each0(iseq, ret, node, popped);
10787}
10788
10789static int
10790iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10791{
10792 const int line = (int)nd_line(node);
10793 const enum node_type type = nd_type(node);
10794 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10795
10796 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10797 /* ignore */
10798 }
10799 else {
10800 if (nd_fl_newline(node)) {
10801 int event = RUBY_EVENT_LINE;
10802 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10803 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10804 event |= RUBY_EVENT_COVERAGE_LINE;
10805 }
10806 ADD_TRACE(ret, event);
10807 }
10808 }
10809
10810 debug_node_start(node);
10811#undef BEFORE_RETURN
10812#define BEFORE_RETURN debug_node_end()
10813
10814 switch (type) {
10815 case NODE_BLOCK:
10816 CHECK(compile_block(iseq, ret, node, popped));
10817 break;
10818 case NODE_IF:
10819 case NODE_UNLESS:
10820 CHECK(compile_if(iseq, ret, node, popped, type));
10821 break;
10822 case NODE_CASE:
10823 CHECK(compile_case(iseq, ret, node, popped));
10824 break;
10825 case NODE_CASE2:
10826 CHECK(compile_case2(iseq, ret, node, popped));
10827 break;
10828 case NODE_CASE3:
10829 CHECK(compile_case3(iseq, ret, node, popped));
10830 break;
10831 case NODE_WHILE:
10832 case NODE_UNTIL:
10833 CHECK(compile_loop(iseq, ret, node, popped, type));
10834 break;
10835 case NODE_FOR:
10836 case NODE_ITER:
10837 CHECK(compile_iter(iseq, ret, node, popped));
10838 break;
10839 case NODE_FOR_MASGN:
10840 CHECK(compile_for_masgn(iseq, ret, node, popped));
10841 break;
10842 case NODE_BREAK:
10843 CHECK(compile_break(iseq, ret, node, popped));
10844 break;
10845 case NODE_NEXT:
10846 CHECK(compile_next(iseq, ret, node, popped));
10847 break;
10848 case NODE_REDO:
10849 CHECK(compile_redo(iseq, ret, node, popped));
10850 break;
10851 case NODE_RETRY:
10852 CHECK(compile_retry(iseq, ret, node, popped));
10853 break;
10854 case NODE_BEGIN:{
10855 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10856 break;
10857 }
10858 case NODE_RESCUE:
10859 CHECK(compile_rescue(iseq, ret, node, popped));
10860 break;
10861 case NODE_RESBODY:
10862 CHECK(compile_resbody(iseq, ret, node, popped));
10863 break;
10864 case NODE_ENSURE:
10865 CHECK(compile_ensure(iseq, ret, node, popped));
10866 break;
10867
10868 case NODE_AND:
10869 case NODE_OR:{
10870 LABEL *end_label = NEW_LABEL(line);
10871 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10872 if (!popped) {
10873 ADD_INSN(ret, node, dup);
10874 }
10875 if (type == NODE_AND) {
10876 ADD_INSNL(ret, node, branchunless, end_label);
10877 }
10878 else {
10879 ADD_INSNL(ret, node, branchif, end_label);
10880 }
10881 if (!popped) {
10882 ADD_INSN(ret, node, pop);
10883 }
10884 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10885 ADD_LABEL(ret, end_label);
10886 break;
10887 }
10888
10889 case NODE_MASGN:{
10890 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10891 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10892 compile_massign(iseq, ret, node, popped);
10893 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10894 break;
10895 }
10896
10897 case NODE_LASGN:{
10898 ID id = RNODE_LASGN(node)->nd_vid;
10899 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10900
10901 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10902 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10903
10904 if (!popped) {
10905 ADD_INSN(ret, node, dup);
10906 }
10907 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10908 break;
10909 }
10910 case NODE_DASGN: {
10911 int idx, lv, ls;
10912 ID id = RNODE_DASGN(node)->nd_vid;
10913 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10914 debugi("dassn id", rb_id2str(id) ? id : '*');
10915
10916 if (!popped) {
10917 ADD_INSN(ret, node, dup);
10918 }
10919
10920 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10921
10922 if (idx < 0) {
10923 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10924 rb_id2str(id));
10925 goto ng;
10926 }
10927 ADD_SETLOCAL(ret, node, ls - idx, lv);
10928 break;
10929 }
10930 case NODE_GASGN:{
10931 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10932
10933 if (!popped) {
10934 ADD_INSN(ret, node, dup);
10935 }
10936 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10937 break;
10938 }
10939 case NODE_IASGN:{
10940 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10941 if (!popped) {
10942 ADD_INSN(ret, node, dup);
10943 }
10944 ADD_INSN2(ret, node, setinstancevariable,
10945 ID2SYM(RNODE_IASGN(node)->nd_vid),
10946 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10947 break;
10948 }
10949 case NODE_CDECL:{
10950 if (RNODE_CDECL(node)->nd_vid) {
10951 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10952
10953 if (!popped) {
10954 ADD_INSN(ret, node, dup);
10955 }
10956
10957 ADD_INSN1(ret, node, putspecialobject,
10958 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10959 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10960 }
10961 else {
10962 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10963 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10964 ADD_INSN(ret, node, swap);
10965
10966 if (!popped) {
10967 ADD_INSN1(ret, node, topn, INT2FIX(1));
10968 ADD_INSN(ret, node, swap);
10969 }
10970
10971 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10972 }
10973 break;
10974 }
10975 case NODE_CVASGN:{
10976 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10977 if (!popped) {
10978 ADD_INSN(ret, node, dup);
10979 }
10980 ADD_INSN2(ret, node, setclassvariable,
10981 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10982 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10983 break;
10984 }
10985 case NODE_OP_ASGN1:
10986 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10987 break;
10988 case NODE_OP_ASGN2:
10989 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10990 break;
10991 case NODE_OP_CDECL:
10992 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10993 break;
10994 case NODE_OP_ASGN_AND:
10995 case NODE_OP_ASGN_OR:
10996 CHECK(compile_op_log(iseq, ret, node, popped, type));
10997 break;
10998 case NODE_CALL: /* obj.foo */
10999 case NODE_OPCALL: /* foo[] */
11000 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11001 break;
11002 }
11003 case NODE_QCALL: /* obj&.foo */
11004 case NODE_FCALL: /* foo() */
11005 case NODE_VCALL: /* foo (variable or call) */
11006 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11007 goto ng;
11008 }
11009 break;
11010 case NODE_SUPER:
11011 case NODE_ZSUPER:
11012 CHECK(compile_super(iseq, ret, node, popped, type));
11013 break;
11014 case NODE_LIST:{
11015 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11016 break;
11017 }
11018 case NODE_ZLIST:{
11019 if (!popped) {
11020 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11021 }
11022 break;
11023 }
11024 case NODE_HASH:
11025 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11026 break;
11027 case NODE_RETURN:
11028 CHECK(compile_return(iseq, ret, node, popped));
11029 break;
11030 case NODE_YIELD:
11031 CHECK(compile_yield(iseq, ret, node, popped));
11032 break;
11033 case NODE_LVAR:{
11034 if (!popped) {
11035 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11036 }
11037 break;
11038 }
11039 case NODE_DVAR:{
11040 int lv, idx, ls;
11041 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11042 if (!popped) {
11043 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11044 if (idx < 0) {
11045 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11046 rb_id2str(RNODE_DVAR(node)->nd_vid));
11047 goto ng;
11048 }
11049 ADD_GETLOCAL(ret, node, ls - idx, lv);
11050 }
11051 break;
11052 }
11053 case NODE_GVAR:{
11054 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11055 if (popped) {
11056 ADD_INSN(ret, node, pop);
11057 }
11058 break;
11059 }
11060 case NODE_IVAR:{
11061 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11062 if (!popped) {
11063 ADD_INSN2(ret, node, getinstancevariable,
11064 ID2SYM(RNODE_IVAR(node)->nd_vid),
11065 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11066 }
11067 break;
11068 }
11069 case NODE_CONST:{
11070 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11071
11072 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11073 body->ic_size++;
11074 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11075 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11076 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11077 }
11078 else {
11079 ADD_INSN(ret, node, putnil);
11080 ADD_INSN1(ret, node, putobject, Qtrue);
11081 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11082 }
11083
11084 if (popped) {
11085 ADD_INSN(ret, node, pop);
11086 }
11087 break;
11088 }
11089 case NODE_CVAR:{
11090 if (!popped) {
11091 ADD_INSN2(ret, node, getclassvariable,
11092 ID2SYM(RNODE_CVAR(node)->nd_vid),
11093 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11094 }
11095 break;
11096 }
11097 case NODE_NTH_REF:{
11098 if (!popped) {
11099 if (!RNODE_NTH_REF(node)->nd_nth) {
11100 ADD_INSN(ret, node, putnil);
11101 break;
11102 }
11103 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11104 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11105 }
11106 break;
11107 }
11108 case NODE_BACK_REF:{
11109 if (!popped) {
11110 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11111 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11112 }
11113 break;
11114 }
11115 case NODE_MATCH:
11116 case NODE_MATCH2:
11117 case NODE_MATCH3:
11118 CHECK(compile_match(iseq, ret, node, popped, type));
11119 break;
11120 case NODE_SYM:{
11121 if (!popped) {
11122 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11123 }
11124 break;
11125 }
11126 case NODE_LINE:{
11127 if (!popped) {
11128 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11129 }
11130 break;
11131 }
11132 case NODE_ENCODING:{
11133 if (!popped) {
11134 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11135 }
11136 break;
11137 }
11138 case NODE_INTEGER:{
11139 VALUE lit = rb_node_integer_literal_val(node);
11140 debugp_param("integer", lit);
11141 if (!popped) {
11142 ADD_INSN1(ret, node, putobject, lit);
11143 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11144 }
11145 break;
11146 }
11147 case NODE_FLOAT:{
11148 VALUE lit = rb_node_float_literal_val(node);
11149 debugp_param("float", lit);
11150 if (!popped) {
11151 ADD_INSN1(ret, node, putobject, lit);
11152 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11153 }
11154 break;
11155 }
11156 case NODE_RATIONAL:{
11157 VALUE lit = rb_node_rational_literal_val(node);
11158 debugp_param("rational", lit);
11159 if (!popped) {
11160 ADD_INSN1(ret, node, putobject, lit);
11161 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11162 }
11163 break;
11164 }
11165 case NODE_IMAGINARY:{
11166 VALUE lit = rb_node_imaginary_literal_val(node);
11167 debugp_param("imaginary", lit);
11168 if (!popped) {
11169 ADD_INSN1(ret, node, putobject, lit);
11170 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11171 }
11172 break;
11173 }
11174 case NODE_FILE:
11175 case NODE_STR:{
11176 debugp_param("nd_lit", get_string_value(node));
11177 if (!popped) {
11178 VALUE lit = get_string_value(node);
11179 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11180 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11181 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11182 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11183 }
11184 switch (option->frozen_string_literal) {
11185 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11186 ADD_INSN1(ret, node, putchilledstring, lit);
11187 break;
11188 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11189 ADD_INSN1(ret, node, putstring, lit);
11190 break;
11191 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11192 ADD_INSN1(ret, node, putobject, lit);
11193 break;
11194 default:
11195 rb_bug("invalid frozen_string_literal");
11196 }
11197 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11198 }
11199 break;
11200 }
11201 case NODE_DSTR:{
11202 compile_dstr(iseq, ret, node);
11203
11204 if (popped) {
11205 ADD_INSN(ret, node, pop);
11206 }
11207 break;
11208 }
11209 case NODE_XSTR:{
11210 ADD_CALL_RECEIVER(ret, node);
11211 VALUE str = rb_node_str_string_val(node);
11212 ADD_INSN1(ret, node, putobject, str);
11213 RB_OBJ_WRITTEN(iseq, Qundef, str);
11214 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11215
11216 if (popped) {
11217 ADD_INSN(ret, node, pop);
11218 }
11219 break;
11220 }
11221 case NODE_DXSTR:{
11222 ADD_CALL_RECEIVER(ret, node);
11223 compile_dstr(iseq, ret, node);
11224 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11225
11226 if (popped) {
11227 ADD_INSN(ret, node, pop);
11228 }
11229 break;
11230 }
11231 case NODE_EVSTR:
11232 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11233 break;
11234 case NODE_REGX:{
11235 if (!popped) {
11236 VALUE lit = rb_node_regx_string_val(node);
11237 ADD_INSN1(ret, node, putobject, lit);
11238 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11239 }
11240 break;
11241 }
11242 case NODE_DREGX:
11243 compile_dregx(iseq, ret, node, popped);
11244 break;
11245 case NODE_ONCE:{
11246 int ic_index = body->ise_size++;
11247 const rb_iseq_t *block_iseq;
11248 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11249
11250 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11251 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11252
11253 if (popped) {
11254 ADD_INSN(ret, node, pop);
11255 }
11256 break;
11257 }
11258 case NODE_ARGSCAT:{
11259 if (popped) {
11260 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11261 ADD_INSN1(ret, node, splatarray, Qfalse);
11262 ADD_INSN(ret, node, pop);
11263 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11264 ADD_INSN1(ret, node, splatarray, Qfalse);
11265 ADD_INSN(ret, node, pop);
11266 }
11267 else {
11268 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11269 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11270 if (nd_type_p(body_node, NODE_LIST)) {
11271 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11272 }
11273 else {
11274 CHECK(COMPILE(ret, "argscat body", body_node));
11275 ADD_INSN(ret, node, concattoarray);
11276 }
11277 }
11278 break;
11279 }
11280 case NODE_ARGSPUSH:{
11281 if (popped) {
11282 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11283 ADD_INSN1(ret, node, splatarray, Qfalse);
11284 ADD_INSN(ret, node, pop);
11285 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11286 }
11287 else {
11288 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11289 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11290 if (keyword_node_p(body_node)) {
11291 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11292 ADD_INSN(ret, node, pushtoarraykwsplat);
11293 }
11294 else if (static_literal_node_p(body_node, iseq, false)) {
11295 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11296 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11297 }
11298 else {
11299 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11300 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11301 }
11302 }
11303 break;
11304 }
11305 case NODE_SPLAT:{
11306 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11307 ADD_INSN1(ret, node, splatarray, Qtrue);
11308
11309 if (popped) {
11310 ADD_INSN(ret, node, pop);
11311 }
11312 break;
11313 }
11314 case NODE_DEFN:{
11315 ID mid = RNODE_DEFN(node)->nd_mid;
11316 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11317 rb_id2str(mid),
11318 ISEQ_TYPE_METHOD, line);
11319
11320 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11321 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11322 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11323
11324 if (!popped) {
11325 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11326 }
11327
11328 break;
11329 }
11330 case NODE_DEFS:{
11331 ID mid = RNODE_DEFS(node)->nd_mid;
11332 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11333 rb_id2str(mid),
11334 ISEQ_TYPE_METHOD, line);
11335
11336 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11337 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11338 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11339 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11340
11341 if (!popped) {
11342 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11343 }
11344 break;
11345 }
11346 case NODE_ALIAS:{
11347 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11348 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11349 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11350 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11351 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11352
11353 if (popped) {
11354 ADD_INSN(ret, node, pop);
11355 }
11356 break;
11357 }
11358 case NODE_VALIAS:{
11359 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11360 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11361 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11362 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11363
11364 if (popped) {
11365 ADD_INSN(ret, node, pop);
11366 }
11367 break;
11368 }
11369 case NODE_UNDEF:{
11370 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11371
11372 for (long i = 0; i < ary->len; i++) {
11373 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11374 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11375 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11376 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11377
11378 if (i < ary->len - 1) {
11379 ADD_INSN(ret, node, pop);
11380 }
11381 }
11382
11383 if (popped) {
11384 ADD_INSN(ret, node, pop);
11385 }
11386 break;
11387 }
11388 case NODE_CLASS:{
11389 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11390 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11391 ISEQ_TYPE_CLASS, line);
11392 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11393 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11394 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11395
11396 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11397 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11398 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11399
11400 if (popped) {
11401 ADD_INSN(ret, node, pop);
11402 }
11403 break;
11404 }
11405 case NODE_MODULE:{
11406 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11407 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11408 ISEQ_TYPE_CLASS, line);
11409 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11410 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11411
11412 ADD_INSN (ret, node, putnil); /* dummy */
11413 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11414 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11415
11416 if (popped) {
11417 ADD_INSN(ret, node, pop);
11418 }
11419 break;
11420 }
11421 case NODE_SCLASS:{
11422 ID singletonclass;
11423 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11424 ISEQ_TYPE_CLASS, line);
11425
11426 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11427 ADD_INSN (ret, node, putnil);
11428 CONST_ID(singletonclass, "singletonclass");
11429 ADD_INSN3(ret, node, defineclass,
11430 ID2SYM(singletonclass), singleton_class,
11431 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11432 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11433
11434 if (popped) {
11435 ADD_INSN(ret, node, pop);
11436 }
11437 break;
11438 }
11439 case NODE_COLON2:
11440 CHECK(compile_colon2(iseq, ret, node, popped));
11441 break;
11442 case NODE_COLON3:
11443 CHECK(compile_colon3(iseq, ret, node, popped));
11444 break;
11445 case NODE_DOT2:
11446 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11447 break;
11448 case NODE_DOT3:
11449 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11450 break;
11451 case NODE_FLIP2:
11452 case NODE_FLIP3:{
11453 LABEL *lend = NEW_LABEL(line);
11454 LABEL *ltrue = NEW_LABEL(line);
11455 LABEL *lfalse = NEW_LABEL(line);
11456 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11457 ltrue, lfalse));
11458 ADD_LABEL(ret, ltrue);
11459 ADD_INSN1(ret, node, putobject, Qtrue);
11460 ADD_INSNL(ret, node, jump, lend);
11461 ADD_LABEL(ret, lfalse);
11462 ADD_INSN1(ret, node, putobject, Qfalse);
11463 ADD_LABEL(ret, lend);
11464 break;
11465 }
11466 case NODE_SELF:{
11467 if (!popped) {
11468 ADD_INSN(ret, node, putself);
11469 }
11470 break;
11471 }
11472 case NODE_NIL:{
11473 if (!popped) {
11474 ADD_INSN(ret, node, putnil);
11475 }
11476 break;
11477 }
11478 case NODE_TRUE:{
11479 if (!popped) {
11480 ADD_INSN1(ret, node, putobject, Qtrue);
11481 }
11482 break;
11483 }
11484 case NODE_FALSE:{
11485 if (!popped) {
11486 ADD_INSN1(ret, node, putobject, Qfalse);
11487 }
11488 break;
11489 }
11490 case NODE_ERRINFO:
11491 CHECK(compile_errinfo(iseq, ret, node, popped));
11492 break;
11493 case NODE_DEFINED:
11494 if (!popped) {
11495 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11496 }
11497 break;
11498 case NODE_POSTEXE:{
11499 /* compiled to:
11500 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11501 */
11502 int is_index = body->ise_size++;
11504 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11505 const rb_iseq_t *once_iseq =
11506 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11507
11508 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11509 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11510
11511 if (popped) {
11512 ADD_INSN(ret, node, pop);
11513 }
11514 break;
11515 }
11516 case NODE_KW_ARG:
11517 CHECK(compile_kw_arg(iseq, ret, node, popped));
11518 break;
11519 case NODE_DSYM:{
11520 compile_dstr(iseq, ret, node);
11521 if (!popped) {
11522 ADD_INSN(ret, node, intern);
11523 }
11524 else {
11525 ADD_INSN(ret, node, pop);
11526 }
11527 break;
11528 }
11529 case NODE_ATTRASGN:
11530 CHECK(compile_attrasgn(iseq, ret, node, popped));
11531 break;
11532 case NODE_LAMBDA:{
11533 /* compile same as lambda{...} */
11534 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11535 VALUE argc = INT2FIX(0);
11536
11537 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11538 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11539 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11540
11541 if (popped) {
11542 ADD_INSN(ret, node, pop);
11543 }
11544 break;
11545 }
11546 default:
11547 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11548 ng:
11549 debug_node_end();
11550 return COMPILE_NG;
11551 }
11552
11553 debug_node_end();
11554 return COMPILE_OK;
11555}
11556
11557/***************************/
11558/* instruction information */
11559/***************************/
11560
11561static int
11562insn_data_length(INSN *iobj)
11563{
11564 return insn_len(iobj->insn_id);
11565}
11566
11567static int
11568calc_sp_depth(int depth, INSN *insn)
11569{
11570 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11571}
11572
11573static VALUE
11574opobj_inspect(VALUE obj)
11575{
11576 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11577 switch (BUILTIN_TYPE(obj)) {
11578 case T_STRING:
11579 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11580 break;
11581 case T_ARRAY:
11582 obj = rb_ary_dup(obj);
11583 break;
11584 default:
11585 break;
11586 }
11587 }
11588 return rb_inspect(obj);
11589}
11590
11591
11592
11593static VALUE
11594insn_data_to_s_detail(INSN *iobj)
11595{
11596 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11597
11598 if (iobj->operands) {
11599 const char *types = insn_op_types(iobj->insn_id);
11600 int j;
11601
11602 for (j = 0; types[j]; j++) {
11603 char type = types[j];
11604
11605 switch (type) {
11606 case TS_OFFSET: /* label(destination position) */
11607 {
11608 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11609 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11610 break;
11611 }
11612 break;
11613 case TS_ISEQ: /* iseq */
11614 {
11615 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11616 VALUE val = Qnil;
11617 if (0 && iseq) { /* TODO: invalidate now */
11618 val = (VALUE)iseq;
11619 }
11620 rb_str_concat(str, opobj_inspect(val));
11621 }
11622 break;
11623 case TS_LINDEX:
11624 case TS_NUM: /* ulong */
11625 case TS_VALUE: /* VALUE */
11626 {
11627 VALUE v = OPERAND_AT(iobj, j);
11628 if (!CLASS_OF(v))
11629 rb_str_cat2(str, "<hidden>");
11630 else {
11631 rb_str_concat(str, opobj_inspect(v));
11632 }
11633 break;
11634 }
11635 case TS_ID: /* ID */
11636 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11637 break;
11638 case TS_IC: /* inline cache */
11639 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11640 break;
11641 case TS_IVC: /* inline ivar cache */
11642 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11643 break;
11644 case TS_ICVARC: /* inline cvar cache */
11645 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11646 break;
11647 case TS_ISE: /* inline storage entry */
11648 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11649 break;
11650 case TS_CALLDATA: /* we store these as call infos at compile time */
11651 {
11652 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11653 rb_str_cat2(str, "<calldata:");
11654 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11655 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11656 break;
11657 }
11658 case TS_CDHASH: /* case/when condition cache */
11659 rb_str_cat2(str, "<ch>");
11660 break;
11661 case TS_FUNCPTR:
11662 {
11663 void *func = (void *)OPERAND_AT(iobj, j);
11664#ifdef HAVE_DLADDR
11665 Dl_info info;
11666 if (dladdr(func, &info) && info.dli_sname) {
11667 rb_str_cat2(str, info.dli_sname);
11668 break;
11669 }
11670#endif
11671 rb_str_catf(str, "<%p>", func);
11672 }
11673 break;
11674 case TS_BUILTIN:
11675 rb_str_cat2(str, "<TS_BUILTIN>");
11676 break;
11677 default:{
11678 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11679 }
11680 }
11681 if (types[j + 1]) {
11682 rb_str_cat2(str, ", ");
11683 }
11684 }
11685 }
11686 return str;
11687}
11688
11689static void
11690dump_disasm_list(const LINK_ELEMENT *link)
11691{
11692 dump_disasm_list_with_cursor(link, NULL, NULL);
11693}
11694
11695static void
11696dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11697{
11698 int pos = 0;
11699 INSN *iobj;
11700 LABEL *lobj;
11701 VALUE str;
11702
11703 printf("-- raw disasm--------\n");
11704
11705 while (link) {
11706 if (curr) printf(curr == link ? "*" : " ");
11707 switch (link->type) {
11708 case ISEQ_ELEMENT_INSN:
11709 {
11710 iobj = (INSN *)link;
11711 str = insn_data_to_s_detail(iobj);
11712 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11713 pos += insn_data_length(iobj);
11714 break;
11715 }
11716 case ISEQ_ELEMENT_LABEL:
11717 {
11718 lobj = (LABEL *)link;
11719 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11720 dest == lobj ? " <---" : "");
11721 break;
11722 }
11723 case ISEQ_ELEMENT_TRACE:
11724 {
11725 TRACE *trace = (TRACE *)link;
11726 printf(" trace: %0x\n", trace->event);
11727 break;
11728 }
11729 case ISEQ_ELEMENT_ADJUST:
11730 {
11731 ADJUST *adjust = (ADJUST *)link;
11732 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11733 break;
11734 }
11735 default:
11736 /* ignore */
11737 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11738 }
11739 link = link->next;
11740 }
11741 printf("---------------------\n");
11742 fflush(stdout);
11743}
11744
11745int
11746rb_insn_len(VALUE insn)
11747{
11748 return insn_len(insn);
11749}
11750
11751const char *
11752rb_insns_name(int i)
11753{
11754 return insn_name(i);
11755}
11756
11757VALUE
11758rb_insns_name_array(void)
11759{
11760 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11761 int i;
11762 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11763 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11764 }
11765 return rb_ary_freeze(ary);
11766}
11767
11768static LABEL *
11769register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11770{
11771 LABEL *label = 0;
11772 st_data_t tmp;
11773 obj = rb_to_symbol_type(obj);
11774
11775 if (st_lookup(labels_table, obj, &tmp) == 0) {
11776 label = NEW_LABEL(0);
11777 st_insert(labels_table, obj, (st_data_t)label);
11778 }
11779 else {
11780 label = (LABEL *)tmp;
11781 }
11782 LABEL_REF(label);
11783 return label;
11784}
11785
11786static VALUE
11787get_exception_sym2type(VALUE sym)
11788{
11789 static VALUE symRescue, symEnsure, symRetry;
11790 static VALUE symBreak, symRedo, symNext;
11791
11792 if (symRescue == 0) {
11793 symRescue = ID2SYM(rb_intern_const("rescue"));
11794 symEnsure = ID2SYM(rb_intern_const("ensure"));
11795 symRetry = ID2SYM(rb_intern_const("retry"));
11796 symBreak = ID2SYM(rb_intern_const("break"));
11797 symRedo = ID2SYM(rb_intern_const("redo"));
11798 symNext = ID2SYM(rb_intern_const("next"));
11799 }
11800
11801 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11802 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11803 if (sym == symRetry) return CATCH_TYPE_RETRY;
11804 if (sym == symBreak) return CATCH_TYPE_BREAK;
11805 if (sym == symRedo) return CATCH_TYPE_REDO;
11806 if (sym == symNext) return CATCH_TYPE_NEXT;
11807 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11808 return 0;
11809}
11810
11811static int
11812iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11813 VALUE exception)
11814{
11815 int i;
11816
11817 for (i=0; i<RARRAY_LEN(exception); i++) {
11818 const rb_iseq_t *eiseq;
11819 VALUE v, type;
11820 LABEL *lstart, *lend, *lcont;
11821 unsigned int sp;
11822
11823 v = rb_to_array_type(RARRAY_AREF(exception, i));
11824 if (RARRAY_LEN(v) != 6) {
11825 rb_raise(rb_eSyntaxError, "wrong exception entry");
11826 }
11827 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11828 if (NIL_P(RARRAY_AREF(v, 1))) {
11829 eiseq = NULL;
11830 }
11831 else {
11832 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11833 }
11834
11835 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11836 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11837 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11838 sp = NUM2UINT(RARRAY_AREF(v, 5));
11839
11840 /* TODO: Dirty Hack! Fix me */
11841 if (type == CATCH_TYPE_RESCUE ||
11842 type == CATCH_TYPE_BREAK ||
11843 type == CATCH_TYPE_NEXT) {
11844 ++sp;
11845 }
11846
11847 lcont->sp = sp;
11848
11849 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11850
11851 RB_GC_GUARD(v);
11852 }
11853 return COMPILE_OK;
11854}
11855
11856static struct st_table *
11857insn_make_insn_table(void)
11858{
11859 struct st_table *table;
11860 int i;
11861 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11862
11863 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11864 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11865 }
11866
11867 return table;
11868}
11869
11870static const rb_iseq_t *
11871iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11872{
11873 VALUE iseqw;
11874 const rb_iseq_t *loaded_iseq;
11875
11876 if (RB_TYPE_P(op, T_ARRAY)) {
11877 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11878 }
11879 else if (CLASS_OF(op) == rb_cISeq) {
11880 iseqw = op;
11881 }
11882 else {
11883 rb_raise(rb_eSyntaxError, "ISEQ is required");
11884 }
11885
11886 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11887 return loaded_iseq;
11888}
11889
11890static VALUE
11891iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11892{
11893 ID mid = 0;
11894 int orig_argc = 0;
11895 unsigned int flag = 0;
11896 struct rb_callinfo_kwarg *kw_arg = 0;
11897
11898 if (!NIL_P(op)) {
11899 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11900 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11901 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11902 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11903
11904 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11905 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11906 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11907
11908 if (!NIL_P(vkw_arg)) {
11909 int i;
11910 int len = RARRAY_LENINT(vkw_arg);
11911 size_t n = rb_callinfo_kwarg_bytes(len);
11912
11913 kw_arg = xmalloc(n);
11914 kw_arg->references = 0;
11915 kw_arg->keyword_len = len;
11916 for (i = 0; i < len; i++) {
11917 VALUE kw = RARRAY_AREF(vkw_arg, i);
11918 SYM2ID(kw); /* make immortal */
11919 kw_arg->keywords[i] = kw;
11920 }
11921 }
11922 }
11923
11924 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11925 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11926 return (VALUE)ci;
11927}
11928
11929static rb_event_flag_t
11930event_name_to_flag(VALUE sym)
11931{
11932#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11933 CHECK_EVENT(RUBY_EVENT_LINE);
11934 CHECK_EVENT(RUBY_EVENT_CLASS);
11935 CHECK_EVENT(RUBY_EVENT_END);
11936 CHECK_EVENT(RUBY_EVENT_CALL);
11937 CHECK_EVENT(RUBY_EVENT_RETURN);
11938 CHECK_EVENT(RUBY_EVENT_B_CALL);
11939 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11940 CHECK_EVENT(RUBY_EVENT_RESCUE);
11941#undef CHECK_EVENT
11942 return RUBY_EVENT_NONE;
11943}
11944
11945static int
11946iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11947 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11948{
11949 /* TODO: body should be frozen */
11950 long i, len = RARRAY_LEN(body);
11951 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11952 int j;
11953 int line_no = 0, node_id = -1, insn_idx = 0;
11954 int ret = COMPILE_OK;
11955
11956 /*
11957 * index -> LABEL *label
11958 */
11959 static struct st_table *insn_table;
11960
11961 if (insn_table == 0) {
11962 insn_table = insn_make_insn_table();
11963 }
11964
11965 for (i=0; i<len; i++) {
11966 VALUE obj = RARRAY_AREF(body, i);
11967
11968 if (SYMBOL_P(obj)) {
11969 rb_event_flag_t event;
11970 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11971 ADD_TRACE(anchor, event);
11972 }
11973 else {
11974 LABEL *label = register_label(iseq, labels_table, obj);
11975 ADD_LABEL(anchor, label);
11976 }
11977 }
11978 else if (FIXNUM_P(obj)) {
11979 line_no = NUM2INT(obj);
11980 }
11981 else if (RB_TYPE_P(obj, T_ARRAY)) {
11982 VALUE *argv = 0;
11983 int argc = RARRAY_LENINT(obj) - 1;
11984 st_data_t insn_id;
11985 VALUE insn;
11986
11987 if (node_ids) {
11988 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11989 }
11990
11991 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11992 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11993 /* TODO: exception */
11994 COMPILE_ERROR(iseq, line_no,
11995 "unknown instruction: %+"PRIsVALUE, insn);
11996 ret = COMPILE_NG;
11997 break;
11998 }
11999
12000 if (argc != insn_len((VALUE)insn_id)-1) {
12001 COMPILE_ERROR(iseq, line_no,
12002 "operand size mismatch");
12003 ret = COMPILE_NG;
12004 break;
12005 }
12006
12007 if (argc > 0) {
12008 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
12009
12010 // add element before operand setup to make GC root
12011 ADD_ELEM(anchor,
12012 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12013 (enum ruby_vminsn_type)insn_id, argc, argv));
12014
12015 for (j=0; j<argc; j++) {
12016 VALUE op = rb_ary_entry(obj, j+1);
12017 switch (insn_op_type((VALUE)insn_id, j)) {
12018 case TS_OFFSET: {
12019 LABEL *label = register_label(iseq, labels_table, op);
12020 argv[j] = (VALUE)label;
12021 break;
12022 }
12023 case TS_LINDEX:
12024 case TS_NUM:
12025 (void)NUM2INT(op);
12026 argv[j] = op;
12027 break;
12028 case TS_VALUE:
12029 argv[j] = op;
12030 RB_OBJ_WRITTEN(iseq, Qundef, op);
12031 break;
12032 case TS_ISEQ:
12033 {
12034 if (op != Qnil) {
12035 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12036 argv[j] = v;
12037 RB_OBJ_WRITTEN(iseq, Qundef, v);
12038 }
12039 else {
12040 argv[j] = 0;
12041 }
12042 }
12043 break;
12044 case TS_ISE:
12045 argv[j] = op;
12046 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12047 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12048 }
12049 break;
12050 case TS_IC:
12051 {
12052 VALUE segments = rb_ary_new();
12053 op = rb_to_array_type(op);
12054
12055 for (int i = 0; i < RARRAY_LEN(op); i++) {
12056 VALUE sym = RARRAY_AREF(op, i);
12057 sym = rb_to_symbol_type(sym);
12058 rb_ary_push(segments, sym);
12059 }
12060
12061 RB_GC_GUARD(op);
12062 argv[j] = segments;
12063 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12064 ISEQ_BODY(iseq)->ic_size++;
12065 }
12066 break;
12067 case TS_IVC: /* inline ivar cache */
12068 argv[j] = op;
12069 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12070 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12071 }
12072 break;
12073 case TS_ICVARC: /* inline cvar cache */
12074 argv[j] = op;
12075 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12076 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12077 }
12078 break;
12079 case TS_CALLDATA:
12080 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12081 break;
12082 case TS_ID:
12083 argv[j] = rb_to_symbol_type(op);
12084 break;
12085 case TS_CDHASH:
12086 {
12087 int i;
12088 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12089
12090 RHASH_TBL_RAW(map)->type = &cdhash_type;
12091 op = rb_to_array_type(op);
12092 for (i=0; i<RARRAY_LEN(op); i+=2) {
12093 VALUE key = RARRAY_AREF(op, i);
12094 VALUE sym = RARRAY_AREF(op, i+1);
12095 LABEL *label =
12096 register_label(iseq, labels_table, sym);
12097 rb_hash_aset(map, key, (VALUE)label | 1);
12098 }
12099 RB_GC_GUARD(op);
12100 argv[j] = map;
12101 RB_OBJ_WRITTEN(iseq, Qundef, map);
12102 }
12103 break;
12104 case TS_FUNCPTR:
12105 {
12106#if SIZEOF_VALUE <= SIZEOF_LONG
12107 long funcptr = NUM2LONG(op);
12108#else
12109 LONG_LONG funcptr = NUM2LL(op);
12110#endif
12111 argv[j] = (VALUE)funcptr;
12112 }
12113 break;
12114 default:
12115 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12116 }
12117 }
12118 }
12119 else {
12120 ADD_ELEM(anchor,
12121 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12122 (enum ruby_vminsn_type)insn_id, argc, NULL));
12123 }
12124 }
12125 else {
12126 rb_raise(rb_eTypeError, "unexpected object for instruction");
12127 }
12128 }
12129 RTYPEDDATA_DATA(labels_wrapper) = 0;
12130 RB_GC_GUARD(labels_wrapper);
12131 validate_labels(iseq, labels_table);
12132 if (!ret) return ret;
12133 return iseq_setup(iseq, anchor);
12134}
12135
12136#define CHECK_ARRAY(v) rb_to_array_type(v)
12137#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12138
12139static int
12140int_param(int *dst, VALUE param, VALUE sym)
12141{
12142 VALUE val = rb_hash_aref(param, sym);
12143 if (FIXNUM_P(val)) {
12144 *dst = FIX2INT(val);
12145 return TRUE;
12146 }
12147 else if (!NIL_P(val)) {
12148 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12149 sym, val);
12150 }
12151 return FALSE;
12152}
12153
12154static const struct rb_iseq_param_keyword *
12155iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12156{
12157 int i, j;
12158 int len = RARRAY_LENINT(keywords);
12159 int default_len;
12160 VALUE key, sym, default_val;
12161 VALUE *dvs;
12162 ID *ids;
12163 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12164
12165 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12166
12167 keyword->num = len;
12168#define SYM(s) ID2SYM(rb_intern_const(#s))
12169 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12170 i = keyword->bits_start - keyword->num;
12171 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12172#undef SYM
12173
12174 /* required args */
12175 for (i = 0; i < len; i++) {
12176 VALUE val = RARRAY_AREF(keywords, i);
12177
12178 if (!SYMBOL_P(val)) {
12179 goto default_values;
12180 }
12181 ids[i] = SYM2ID(val);
12182 keyword->required_num++;
12183 }
12184
12185 default_values: /* note: we intentionally preserve `i' from previous loop */
12186 default_len = len - i;
12187 if (default_len == 0) {
12188 keyword->table = ids;
12189 return keyword;
12190 }
12191 else if (default_len < 0) {
12193 }
12194
12195 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12196
12197 for (j = 0; i < len; i++, j++) {
12198 key = RARRAY_AREF(keywords, i);
12199 CHECK_ARRAY(key);
12200
12201 switch (RARRAY_LEN(key)) {
12202 case 1:
12203 sym = RARRAY_AREF(key, 0);
12204 default_val = Qundef;
12205 break;
12206 case 2:
12207 sym = RARRAY_AREF(key, 0);
12208 default_val = RARRAY_AREF(key, 1);
12209 break;
12210 default:
12211 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12212 }
12213 ids[i] = SYM2ID(sym);
12214 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12215 }
12216
12217 keyword->table = ids;
12218 keyword->default_values = dvs;
12219
12220 return keyword;
12221}
12222
12223static void
12224iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12225{
12226 rb_gc_mark_and_move(obj);
12227}
12228
12229void
12230rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12231{
12232 INSN *iobj = 0;
12233 size_t size = sizeof(INSN);
12234 unsigned int pos = 0;
12235
12236 while (storage) {
12237#ifdef STRICT_ALIGNMENT
12238 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12239#else
12240 const size_t padding = 0; /* expected to be optimized by compiler */
12241#endif /* STRICT_ALIGNMENT */
12242 size_t offset = pos + size + padding;
12243 if (offset > storage->size || offset > storage->pos) {
12244 pos = 0;
12245 storage = storage->next;
12246 }
12247 else {
12248#ifdef STRICT_ALIGNMENT
12249 pos += (int)padding;
12250#endif /* STRICT_ALIGNMENT */
12251
12252 iobj = (INSN *)&storage->buff[pos];
12253
12254 if (iobj->operands) {
12255 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12256 }
12257 pos += (int)size;
12258 }
12259 }
12260}
12261
12262static const rb_data_type_t labels_wrapper_type = {
12263 .wrap_struct_name = "compiler/labels_wrapper",
12264 .function = {
12265 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12266 .dfree = (RUBY_DATA_FUNC)st_free_table,
12267 },
12268 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12269};
12270
12271void
12272rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12273 VALUE exception, VALUE body)
12274{
12275#define SYM(s) ID2SYM(rb_intern_const(#s))
12276 int i, len;
12277 unsigned int arg_size, local_size, stack_max;
12278 ID *tbl;
12279 struct st_table *labels_table = st_init_numtable();
12280 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12281 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12282 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12283 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12284 DECL_ANCHOR(anchor);
12285 INIT_ANCHOR(anchor);
12286
12287 len = RARRAY_LENINT(locals);
12288 ISEQ_BODY(iseq)->local_table_size = len;
12289 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12290
12291 for (i = 0; i < len; i++) {
12292 VALUE lv = RARRAY_AREF(locals, i);
12293
12294 if (sym_arg_rest == lv) {
12295 tbl[i] = 0;
12296 }
12297 else {
12298 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12299 }
12300 }
12301
12302#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12303 if (INT_PARAM(lead_num)) {
12304 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12305 }
12306 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12307 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12308 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12309 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12310#undef INT_PARAM
12311 {
12312#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12313 int x;
12314 INT_PARAM(arg_size);
12315 INT_PARAM(local_size);
12316 INT_PARAM(stack_max);
12317#undef INT_PARAM
12318 }
12319
12320 VALUE node_ids = Qfalse;
12321#ifdef USE_ISEQ_NODE_ID
12322 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12323 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12324 rb_raise(rb_eTypeError, "node_ids is not an array");
12325 }
12326#endif
12327
12328 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12329 len = RARRAY_LENINT(arg_opt_labels);
12330 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12331
12332 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12333 VALUE *opt_table = ALLOC_N(VALUE, len);
12334
12335 for (i = 0; i < len; i++) {
12336 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12337 LABEL *label = register_label(iseq, labels_table, ent);
12338 opt_table[i] = (VALUE)label;
12339 }
12340
12341 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12342 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12343 }
12344 }
12345 else if (!NIL_P(arg_opt_labels)) {
12346 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12347 arg_opt_labels);
12348 }
12349
12350 if (RB_TYPE_P(keywords, T_ARRAY)) {
12351 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12352 }
12353 else if (!NIL_P(keywords)) {
12354 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12355 keywords);
12356 }
12357
12358 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12359 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12360 }
12361
12362 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12363 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12364 }
12365
12366 if (int_param(&i, params, SYM(kwrest))) {
12367 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12368 if (keyword == NULL) {
12369 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12370 }
12371 keyword->rest_start = i;
12372 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12373 }
12374#undef SYM
12375 iseq_calc_param_size(iseq);
12376
12377 /* exception */
12378 iseq_build_from_ary_exception(iseq, labels_table, exception);
12379
12380 /* body */
12381 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12382
12383 ISEQ_BODY(iseq)->param.size = arg_size;
12384 ISEQ_BODY(iseq)->local_table_size = local_size;
12385 ISEQ_BODY(iseq)->stack_max = stack_max;
12386}
12387
12388/* for parser */
12389
12390int
12391rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12392{
12393 if (iseq) {
12394 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12395 while (body->type == ISEQ_TYPE_BLOCK ||
12396 body->type == ISEQ_TYPE_RESCUE ||
12397 body->type == ISEQ_TYPE_ENSURE ||
12398 body->type == ISEQ_TYPE_EVAL ||
12399 body->type == ISEQ_TYPE_MAIN
12400 ) {
12401 unsigned int i;
12402
12403 for (i = 0; i < body->local_table_size; i++) {
12404 if (body->local_table[i] == id) {
12405 return 1;
12406 }
12407 }
12408 iseq = body->parent_iseq;
12409 body = ISEQ_BODY(iseq);
12410 }
12411 }
12412 return 0;
12413}
12414
12415int
12416rb_local_defined(ID id, const rb_iseq_t *iseq)
12417{
12418 if (iseq) {
12419 unsigned int i;
12420 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12421
12422 for (i=0; i<body->local_table_size; i++) {
12423 if (body->local_table[i] == id) {
12424 return 1;
12425 }
12426 }
12427 }
12428 return 0;
12429}
12430
12431/* ISeq binary format */
12432
12433#ifndef IBF_ISEQ_DEBUG
12434#define IBF_ISEQ_DEBUG 0
12435#endif
12436
12437#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12438#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12439#endif
12440
12441typedef uint32_t ibf_offset_t;
12442#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12443
12444#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12445#ifdef RUBY_DEVEL
12446#define IBF_DEVEL_VERSION 4
12447#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12448#else
12449#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12450#endif
12451
12452static const char IBF_ENDIAN_MARK =
12453#ifdef WORDS_BIGENDIAN
12454 'b'
12455#else
12456 'l'
12457#endif
12458 ;
12459
12461 char magic[4]; /* YARB */
12462 uint32_t major_version;
12463 uint32_t minor_version;
12464 uint32_t size;
12465 uint32_t extra_size;
12466
12467 uint32_t iseq_list_size;
12468 uint32_t global_object_list_size;
12469 ibf_offset_t iseq_list_offset;
12470 ibf_offset_t global_object_list_offset;
12471 uint8_t endian;
12472 uint8_t wordsize; /* assume no 2048-bit CPU */
12473};
12474
12476 VALUE str;
12477 st_table *obj_table; /* obj -> obj number */
12478};
12479
12480struct ibf_dump {
12481 st_table *iseq_table; /* iseq -> iseq number */
12482 struct ibf_dump_buffer global_buffer;
12483 struct ibf_dump_buffer *current_buffer;
12484};
12485
12487 const char *buff;
12488 ibf_offset_t size;
12489
12490 VALUE obj_list; /* [obj0, ...] */
12491 unsigned int obj_list_size;
12492 ibf_offset_t obj_list_offset;
12493};
12494
12495struct ibf_load {
12496 const struct ibf_header *header;
12497 VALUE iseq_list; /* [iseq0, ...] */
12498 struct ibf_load_buffer global_buffer;
12499 VALUE loader_obj;
12500 rb_iseq_t *iseq;
12501 VALUE str;
12502 struct ibf_load_buffer *current_buffer;
12503};
12504
12506 long size;
12507 VALUE buffer[1];
12508};
12509
12510static void
12511pinned_list_mark(void *ptr)
12512{
12513 long i;
12514 struct pinned_list *list = (struct pinned_list *)ptr;
12515 for (i = 0; i < list->size; i++) {
12516 if (list->buffer[i]) {
12517 rb_gc_mark(list->buffer[i]);
12518 }
12519 }
12520}
12521
12522static const rb_data_type_t pinned_list_type = {
12523 "pinned_list",
12524 {
12525 pinned_list_mark,
12527 NULL, // No external memory to report,
12528 },
12529 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12530};
12531
12532static VALUE
12533pinned_list_fetch(VALUE list, long offset)
12534{
12535 struct pinned_list * ptr;
12536
12537 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12538
12539 if (offset >= ptr->size) {
12540 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12541 }
12542
12543 return ptr->buffer[offset];
12544}
12545
12546static void
12547pinned_list_store(VALUE list, long offset, VALUE object)
12548{
12549 struct pinned_list * ptr;
12550
12551 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12552
12553 if (offset >= ptr->size) {
12554 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12555 }
12556
12557 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12558}
12559
12560static VALUE
12561pinned_list_new(long size)
12562{
12563 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12564 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12565 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12566 ptr->size = size;
12567 return obj_list;
12568}
12569
12570static ibf_offset_t
12571ibf_dump_pos(struct ibf_dump *dump)
12572{
12573 long pos = RSTRING_LEN(dump->current_buffer->str);
12574#if SIZEOF_LONG > SIZEOF_INT
12575 if (pos >= UINT_MAX) {
12576 rb_raise(rb_eRuntimeError, "dump size exceeds");
12577 }
12578#endif
12579 return (unsigned int)pos;
12580}
12581
12582static void
12583ibf_dump_align(struct ibf_dump *dump, size_t align)
12584{
12585 ibf_offset_t pos = ibf_dump_pos(dump);
12586 if (pos % align) {
12587 static const char padding[sizeof(VALUE)];
12588 size_t size = align - ((size_t)pos % align);
12589#if SIZEOF_LONG > SIZEOF_INT
12590 if (pos + size >= UINT_MAX) {
12591 rb_raise(rb_eRuntimeError, "dump size exceeds");
12592 }
12593#endif
12594 for (; size > sizeof(padding); size -= sizeof(padding)) {
12595 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12596 }
12597 rb_str_cat(dump->current_buffer->str, padding, size);
12598 }
12599}
12600
12601static ibf_offset_t
12602ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12603{
12604 ibf_offset_t pos = ibf_dump_pos(dump);
12605 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12606 /* TODO: overflow check */
12607 return pos;
12608}
12609
12610static ibf_offset_t
12611ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12612{
12613 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12614}
12615
12616static void
12617ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12618{
12619 VALUE str = dump->current_buffer->str;
12620 char *ptr = RSTRING_PTR(str);
12621 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12622 rb_bug("ibf_dump_overwrite: overflow");
12623 memcpy(ptr + offset, buff, size);
12624}
12625
12626static const void *
12627ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12628{
12629 ibf_offset_t beg = *offset;
12630 *offset += size;
12631 return load->current_buffer->buff + beg;
12632}
12633
12634static void *
12635ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12636{
12637 void *buff = ruby_xmalloc2(x, y);
12638 size_t size = x * y;
12639 memcpy(buff, load->current_buffer->buff + offset, size);
12640 return buff;
12641}
12642
12643#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12644
12645#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12646#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12647#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12648#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12649#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12650
12651static int
12652ibf_table_lookup(struct st_table *table, st_data_t key)
12653{
12654 st_data_t val;
12655
12656 if (st_lookup(table, key, &val)) {
12657 return (int)val;
12658 }
12659 else {
12660 return -1;
12661 }
12662}
12663
12664static int
12665ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12666{
12667 int index = ibf_table_lookup(table, key);
12668
12669 if (index < 0) { /* not found */
12670 index = (int)table->num_entries;
12671 st_insert(table, key, (st_data_t)index);
12672 }
12673
12674 return index;
12675}
12676
12677/* dump/load generic */
12678
12679static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12680
12681static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12682static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12683
12684static st_table *
12685ibf_dump_object_table_new(void)
12686{
12687 st_table *obj_table = st_init_numtable(); /* need free */
12688 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12689
12690 return obj_table;
12691}
12692
12693static VALUE
12694ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12695{
12696 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12697}
12698
12699static VALUE
12700ibf_dump_id(struct ibf_dump *dump, ID id)
12701{
12702 if (id == 0 || rb_id2name(id) == NULL) {
12703 return 0;
12704 }
12705 return ibf_dump_object(dump, rb_id2sym(id));
12706}
12707
12708static ID
12709ibf_load_id(const struct ibf_load *load, const ID id_index)
12710{
12711 if (id_index == 0) {
12712 return 0;
12713 }
12714 VALUE sym = ibf_load_object(load, id_index);
12715 if (rb_integer_type_p(sym)) {
12716 /* Load hidden local variables as indexes */
12717 return NUM2ULONG(sym);
12718 }
12719 return rb_sym2id(sym);
12720}
12721
12722/* dump/load: code */
12723
12724static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12725
12726static int
12727ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12728{
12729 if (iseq == NULL) {
12730 return -1;
12731 }
12732 else {
12733 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12734 }
12735}
12736
12737static unsigned char
12738ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12739{
12740 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12741 return (unsigned char)load->current_buffer->buff[(*offset)++];
12742}
12743
12744/*
12745 * Small uint serialization
12746 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12747 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12748 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12749 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12750 * ...
12751 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12752 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12753 */
12754static void
12755ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12756{
12757 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12758 ibf_dump_write(dump, &x, sizeof(VALUE));
12759 return;
12760 }
12761
12762 enum { max_byte_length = sizeof(VALUE) + 1 };
12763
12764 unsigned char bytes[max_byte_length];
12765 ibf_offset_t n;
12766
12767 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12768 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12769 }
12770
12771 x <<= 1;
12772 x |= 1;
12773 x <<= n;
12774 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12775 n++;
12776
12777 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12778}
12779
12780static VALUE
12781ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12782{
12783 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12784 union { char s[sizeof(VALUE)]; VALUE v; } x;
12785
12786 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12787 *offset += sizeof(VALUE);
12788
12789 return x.v;
12790 }
12791
12792 enum { max_byte_length = sizeof(VALUE) + 1 };
12793
12794 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12795 const unsigned char c = buffer[*offset];
12796
12797 ibf_offset_t n =
12798 c & 1 ? 1 :
12799 c == 0 ? 9 : ntz_int32(c) + 1;
12800 VALUE x = (VALUE)c >> n;
12801
12802 if (*offset + n > load->current_buffer->size) {
12803 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12804 }
12805
12806 ibf_offset_t i;
12807 for (i = 1; i < n; i++) {
12808 x <<= 8;
12809 x |= (VALUE)buffer[*offset + i];
12810 }
12811
12812 *offset += n;
12813 return x;
12814}
12815
12816static void
12817ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12818{
12819 // short: index
12820 // short: name.length
12821 // bytes: name
12822 // // omit argc (only verify with name)
12823 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12824
12825 size_t len = strlen(bf->name);
12826 ibf_dump_write_small_value(dump, (VALUE)len);
12827 ibf_dump_write(dump, bf->name, len);
12828}
12829
12830static const struct rb_builtin_function *
12831ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12832{
12833 int i = (int)ibf_load_small_value(load, offset);
12834 int len = (int)ibf_load_small_value(load, offset);
12835 const char *name = (char *)ibf_load_ptr(load, offset, len);
12836
12837 if (0) {
12838 fprintf(stderr, "%.*s!!\n", len, name);
12839 }
12840
12841 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12842 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12843 if (strncmp(table[i].name, name, len) != 0) {
12844 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12845 }
12846 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12847
12848 return &table[i];
12849}
12850
12851static ibf_offset_t
12852ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12853{
12854 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12855 const int iseq_size = body->iseq_size;
12856 int code_index;
12857 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12858
12859 ibf_offset_t offset = ibf_dump_pos(dump);
12860
12861 for (code_index=0; code_index<iseq_size;) {
12862 const VALUE insn = orig_code[code_index++];
12863 const char *types = insn_op_types(insn);
12864 int op_index;
12865
12866 /* opcode */
12867 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12868 ibf_dump_write_small_value(dump, insn);
12869
12870 /* operands */
12871 for (op_index=0; types[op_index]; op_index++, code_index++) {
12872 VALUE op = orig_code[code_index];
12873 VALUE wv;
12874
12875 switch (types[op_index]) {
12876 case TS_CDHASH:
12877 case TS_VALUE:
12878 wv = ibf_dump_object(dump, op);
12879 break;
12880 case TS_ISEQ:
12881 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12882 break;
12883 case TS_IC:
12884 {
12885 IC ic = (IC)op;
12886 VALUE arr = idlist_to_array(ic->segments);
12887 wv = ibf_dump_object(dump, arr);
12888 }
12889 break;
12890 case TS_ISE:
12891 case TS_IVC:
12892 case TS_ICVARC:
12893 {
12895 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12896 }
12897 break;
12898 case TS_CALLDATA:
12899 {
12900 goto skip_wv;
12901 }
12902 case TS_ID:
12903 wv = ibf_dump_id(dump, (ID)op);
12904 break;
12905 case TS_FUNCPTR:
12906 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12907 goto skip_wv;
12908 case TS_BUILTIN:
12909 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12910 goto skip_wv;
12911 default:
12912 wv = op;
12913 break;
12914 }
12915 ibf_dump_write_small_value(dump, wv);
12916 skip_wv:;
12917 }
12918 RUBY_ASSERT(insn_len(insn) == op_index+1);
12919 }
12920
12921 return offset;
12922}
12923
12924static VALUE *
12925ibf_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)
12926{
12927 VALUE iseqv = (VALUE)iseq;
12928 unsigned int code_index;
12929 ibf_offset_t reading_pos = bytecode_offset;
12930 VALUE *code = ALLOC_N(VALUE, iseq_size);
12931
12932 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12933 struct rb_call_data *cd_entries = load_body->call_data;
12934 int ic_index = 0;
12935
12936 iseq_bits_t * mark_offset_bits;
12937
12938 iseq_bits_t tmp[1] = {0};
12939
12940 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12941 mark_offset_bits = tmp;
12942 }
12943 else {
12944 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12945 }
12946 bool needs_bitmap = false;
12947
12948 for (code_index=0; code_index<iseq_size;) {
12949 /* opcode */
12950 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12951 const char *types = insn_op_types(insn);
12952 int op_index;
12953
12954 code_index++;
12955
12956 /* operands */
12957 for (op_index=0; types[op_index]; op_index++, code_index++) {
12958 const char operand_type = types[op_index];
12959 switch (operand_type) {
12960 case TS_VALUE:
12961 {
12962 VALUE op = ibf_load_small_value(load, &reading_pos);
12963 VALUE v = ibf_load_object(load, op);
12964 code[code_index] = v;
12965 if (!SPECIAL_CONST_P(v)) {
12966 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12967 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12968 needs_bitmap = true;
12969 }
12970 break;
12971 }
12972 case TS_CDHASH:
12973 {
12974 VALUE op = ibf_load_small_value(load, &reading_pos);
12975 VALUE v = ibf_load_object(load, op);
12976 v = rb_hash_dup(v); // hash dumped as frozen
12977 RHASH_TBL_RAW(v)->type = &cdhash_type;
12978 rb_hash_rehash(v); // hash function changed
12979 freeze_hide_obj(v);
12980
12981 // Overwrite the existing hash in the object list. This
12982 // is to keep the object alive during load time.
12983 // [Bug #17984] [ruby-core:104259]
12984 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12985
12986 code[code_index] = v;
12987 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12988 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12989 needs_bitmap = true;
12990 break;
12991 }
12992 case TS_ISEQ:
12993 {
12994 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12995 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12996 code[code_index] = v;
12997 if (!SPECIAL_CONST_P(v)) {
12998 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12999 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13000 needs_bitmap = true;
13001 }
13002 break;
13003 }
13004 case TS_IC:
13005 {
13006 VALUE op = ibf_load_small_value(load, &reading_pos);
13007 VALUE arr = ibf_load_object(load, op);
13008
13009 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13010 ic->segments = array_to_idlist(arr);
13011
13012 code[code_index] = (VALUE)ic;
13013 }
13014 break;
13015 case TS_ISE:
13016 case TS_ICVARC:
13017 case TS_IVC:
13018 {
13019 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13020
13021 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13022 code[code_index] = (VALUE)ic;
13023
13024 if (operand_type == TS_IVC) {
13025 IVC cache = (IVC)ic;
13026
13027 if (insn == BIN(setinstancevariable)) {
13028 ID iv_name = (ID)code[code_index - 1];
13029 cache->iv_set_name = iv_name;
13030 }
13031 else {
13032 cache->iv_set_name = 0;
13033 }
13034
13035 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13036 }
13037
13038 }
13039 break;
13040 case TS_CALLDATA:
13041 {
13042 code[code_index] = (VALUE)cd_entries++;
13043 }
13044 break;
13045 case TS_ID:
13046 {
13047 VALUE op = ibf_load_small_value(load, &reading_pos);
13048 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13049 }
13050 break;
13051 case TS_FUNCPTR:
13052 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13053 break;
13054 case TS_BUILTIN:
13055 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13056 break;
13057 default:
13058 code[code_index] = ibf_load_small_value(load, &reading_pos);
13059 continue;
13060 }
13061 }
13062 if (insn_len(insn) != op_index+1) {
13063 rb_raise(rb_eRuntimeError, "operand size mismatch");
13064 }
13065 }
13066
13067 load_body->iseq_encoded = code;
13068 load_body->iseq_size = code_index;
13069
13070 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13071 load_body->mark_bits.single = mark_offset_bits[0];
13072 }
13073 else {
13074 if (needs_bitmap) {
13075 load_body->mark_bits.list = mark_offset_bits;
13076 }
13077 else {
13078 load_body->mark_bits.list = 0;
13079 ruby_xfree(mark_offset_bits);
13080 }
13081 }
13082
13083 RUBY_ASSERT(code_index == iseq_size);
13084 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13085 return code;
13086}
13087
13088static ibf_offset_t
13089ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13090{
13091 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13092
13093 if (opt_num > 0) {
13094 IBF_W_ALIGN(VALUE);
13095 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13096 }
13097 else {
13098 return ibf_dump_pos(dump);
13099 }
13100}
13101
13102static VALUE *
13103ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13104{
13105 if (opt_num > 0) {
13106 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13107 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13108 return table;
13109 }
13110 else {
13111 return NULL;
13112 }
13113}
13114
13115static ibf_offset_t
13116ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13117{
13118 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13119
13120 if (kw) {
13121 struct rb_iseq_param_keyword dump_kw = *kw;
13122 int dv_num = kw->num - kw->required_num;
13123 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13124 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13125 int i;
13126
13127 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13128 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13129
13130 dump_kw.table = IBF_W(ids, ID, kw->num);
13131 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13132 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13133 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13134 }
13135 else {
13136 return 0;
13137 }
13138}
13139
13140static const struct rb_iseq_param_keyword *
13141ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13142{
13143 if (param_keyword_offset) {
13144 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13145 int dv_num = kw->num - kw->required_num;
13146 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13147
13148 int i;
13149 for (i=0; i<dv_num; i++) {
13150 dvs[i] = ibf_load_object(load, dvs[i]);
13151 }
13152
13153 // Will be set once the local table is loaded.
13154 kw->table = NULL;
13155
13156 kw->default_values = dvs;
13157 return kw;
13158 }
13159 else {
13160 return NULL;
13161 }
13162}
13163
13164static ibf_offset_t
13165ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13166{
13167 ibf_offset_t offset = ibf_dump_pos(dump);
13168 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13169
13170 unsigned int i;
13171 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13172 ibf_dump_write_small_value(dump, entries[i].line_no);
13173#ifdef USE_ISEQ_NODE_ID
13174 ibf_dump_write_small_value(dump, entries[i].node_id);
13175#endif
13176 ibf_dump_write_small_value(dump, entries[i].events);
13177 }
13178
13179 return offset;
13180}
13181
13182static struct iseq_insn_info_entry *
13183ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13184{
13185 ibf_offset_t reading_pos = body_offset;
13186 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13187
13188 unsigned int i;
13189 for (i = 0; i < size; i++) {
13190 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13191#ifdef USE_ISEQ_NODE_ID
13192 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13193#endif
13194 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13195 }
13196
13197 return entries;
13198}
13199
13200static ibf_offset_t
13201ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13202{
13203 ibf_offset_t offset = ibf_dump_pos(dump);
13204
13205 unsigned int last = 0;
13206 unsigned int i;
13207 for (i = 0; i < size; i++) {
13208 ibf_dump_write_small_value(dump, positions[i] - last);
13209 last = positions[i];
13210 }
13211
13212 return offset;
13213}
13214
13215static unsigned int *
13216ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13217{
13218 ibf_offset_t reading_pos = positions_offset;
13219 unsigned int *positions = ALLOC_N(unsigned int, size);
13220
13221 unsigned int last = 0;
13222 unsigned int i;
13223 for (i = 0; i < size; i++) {
13224 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13225 last = positions[i];
13226 }
13227
13228 return positions;
13229}
13230
13231static ibf_offset_t
13232ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13233{
13234 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13235 const int size = body->local_table_size;
13236 ID *table = ALLOCA_N(ID, size);
13237 int i;
13238
13239 for (i=0; i<size; i++) {
13240 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13241 if (v == 0) {
13242 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13243 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13244 }
13245 table[i] = v;
13246 }
13247
13248 IBF_W_ALIGN(ID);
13249 return ibf_dump_write(dump, table, sizeof(ID) * size);
13250}
13251
13252static ID *
13253ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13254{
13255 if (size > 0) {
13256 ID *table = IBF_R(local_table_offset, ID, size);
13257 int i;
13258
13259 for (i=0; i<size; i++) {
13260 table[i] = ibf_load_id(load, table[i]);
13261 }
13262 return table;
13263 }
13264 else {
13265 return NULL;
13266 }
13267}
13268
13269static ibf_offset_t
13270ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13271{
13272 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13273
13274 if (table) {
13275 int *iseq_indices = ALLOCA_N(int, table->size);
13276 unsigned int i;
13277
13278 for (i=0; i<table->size; i++) {
13279 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13280 }
13281
13282 const ibf_offset_t offset = ibf_dump_pos(dump);
13283
13284 for (i=0; i<table->size; i++) {
13285 ibf_dump_write_small_value(dump, iseq_indices[i]);
13286 ibf_dump_write_small_value(dump, table->entries[i].type);
13287 ibf_dump_write_small_value(dump, table->entries[i].start);
13288 ibf_dump_write_small_value(dump, table->entries[i].end);
13289 ibf_dump_write_small_value(dump, table->entries[i].cont);
13290 ibf_dump_write_small_value(dump, table->entries[i].sp);
13291 }
13292 return offset;
13293 }
13294 else {
13295 return ibf_dump_pos(dump);
13296 }
13297}
13298
13299static void
13300ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13301{
13302 if (size) {
13303 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13304 table->size = size;
13305 ISEQ_BODY(parent_iseq)->catch_table = table;
13306
13307 ibf_offset_t reading_pos = catch_table_offset;
13308
13309 unsigned int i;
13310 for (i=0; i<table->size; i++) {
13311 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13312 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13313 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13314 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13315 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13316 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13317
13318 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13319 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13320 }
13321 }
13322 else {
13323 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13324 }
13325}
13326
13327static ibf_offset_t
13328ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13329{
13330 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13331 const unsigned int ci_size = body->ci_size;
13332 const struct rb_call_data *cds = body->call_data;
13333
13334 ibf_offset_t offset = ibf_dump_pos(dump);
13335
13336 unsigned int i;
13337
13338 for (i = 0; i < ci_size; i++) {
13339 const struct rb_callinfo *ci = cds[i].ci;
13340 if (ci != NULL) {
13341 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13342 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13343 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13344
13345 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13346 if (kwarg) {
13347 int len = kwarg->keyword_len;
13348 ibf_dump_write_small_value(dump, len);
13349 for (int j=0; j<len; j++) {
13350 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13351 ibf_dump_write_small_value(dump, keyword);
13352 }
13353 }
13354 else {
13355 ibf_dump_write_small_value(dump, 0);
13356 }
13357 }
13358 else {
13359 // TODO: truncate NULL ci from call_data.
13360 ibf_dump_write_small_value(dump, (VALUE)-1);
13361 }
13362 }
13363
13364 return offset;
13365}
13366
13368 ID id;
13369 VALUE name;
13370 VALUE val;
13371};
13372
13374 size_t num;
13375 struct outer_variable_pair pairs[1];
13376};
13377
13378static enum rb_id_table_iterator_result
13379store_outer_variable(ID id, VALUE val, void *dump)
13380{
13381 struct outer_variable_list *ovlist = dump;
13382 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13383 pair->id = id;
13384 pair->name = rb_id2str(id);
13385 pair->val = val;
13386 return ID_TABLE_CONTINUE;
13387}
13388
13389static int
13390outer_variable_cmp(const void *a, const void *b, void *arg)
13391{
13392 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13393 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13394
13395 if (!ap->name) {
13396 return -1;
13397 }
13398 else if (!bp->name) {
13399 return 1;
13400 }
13401
13402 return rb_str_cmp(ap->name, bp->name);
13403}
13404
13405static ibf_offset_t
13406ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13407{
13408 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13409
13410 ibf_offset_t offset = ibf_dump_pos(dump);
13411
13412 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13413 ibf_dump_write_small_value(dump, (VALUE)size);
13414 if (size > 0) {
13415 VALUE buff;
13416 size_t buffsize =
13417 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13418 offsetof(struct outer_variable_list, pairs),
13419 rb_eArgError);
13420 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13421 ovlist->num = 0;
13422 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13423 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13424 for (size_t i = 0; i < size; ++i) {
13425 ID id = ovlist->pairs[i].id;
13426 ID val = ovlist->pairs[i].val;
13427 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13428 ibf_dump_write_small_value(dump, val);
13429 }
13430 }
13431
13432 return offset;
13433}
13434
13435/* note that we dump out rb_call_info but load back rb_call_data */
13436static void
13437ibf_load_ci_entries(const struct ibf_load *load,
13438 ibf_offset_t ci_entries_offset,
13439 unsigned int ci_size,
13440 struct rb_call_data **cd_ptr)
13441{
13442 if (!ci_size) {
13443 *cd_ptr = NULL;
13444 return;
13445 }
13446
13447 ibf_offset_t reading_pos = ci_entries_offset;
13448
13449 unsigned int i;
13450
13451 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13452 *cd_ptr = cds;
13453
13454 for (i = 0; i < ci_size; i++) {
13455 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13456 if (mid_index != (VALUE)-1) {
13457 ID mid = ibf_load_id(load, mid_index);
13458 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13459 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13460
13461 struct rb_callinfo_kwarg *kwarg = NULL;
13462 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13463 if (kwlen > 0) {
13464 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13465 kwarg->references = 0;
13466 kwarg->keyword_len = kwlen;
13467 for (int j=0; j<kwlen; j++) {
13468 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13469 kwarg->keywords[j] = ibf_load_object(load, keyword);
13470 }
13471 }
13472
13473 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13474 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13475 cds[i].cc = vm_cc_empty();
13476 }
13477 else {
13478 // NULL ci
13479 cds[i].ci = NULL;
13480 cds[i].cc = NULL;
13481 }
13482 }
13483}
13484
13485static struct rb_id_table *
13486ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13487{
13488 ibf_offset_t reading_pos = outer_variables_offset;
13489
13490 struct rb_id_table *tbl = NULL;
13491
13492 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13493
13494 if (table_size > 0) {
13495 tbl = rb_id_table_create(table_size);
13496 }
13497
13498 for (size_t i = 0; i < table_size; i++) {
13499 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13500 VALUE value = ibf_load_small_value(load, &reading_pos);
13501 if (!key) key = rb_make_temporary_id(i);
13502 rb_id_table_insert(tbl, key, value);
13503 }
13504
13505 return tbl;
13506}
13507
13508static ibf_offset_t
13509ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13510{
13511 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13512
13513 unsigned int *positions;
13514
13515 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13516
13517 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13518 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13519 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13520
13521#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13522 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13523
13524 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13525 struct ibf_dump_buffer buffer;
13526 buffer.str = rb_str_new(0, 0);
13527 buffer.obj_table = ibf_dump_object_table_new();
13528 dump->current_buffer = &buffer;
13529#endif
13530
13531 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13532 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13533 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13534 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13535 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13536
13537 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13538 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13539 ruby_xfree(positions);
13540
13541 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13542 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13543 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13544 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13545 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13546 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13547 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13548 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13549
13550#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13551 ibf_offset_t local_obj_list_offset;
13552 unsigned int local_obj_list_size;
13553
13554 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13555#endif
13556
13557 ibf_offset_t body_offset = ibf_dump_pos(dump);
13558
13559 /* dump the constant body */
13560 unsigned int param_flags =
13561 (body->param.flags.has_lead << 0) |
13562 (body->param.flags.has_opt << 1) |
13563 (body->param.flags.has_rest << 2) |
13564 (body->param.flags.has_post << 3) |
13565 (body->param.flags.has_kw << 4) |
13566 (body->param.flags.has_kwrest << 5) |
13567 (body->param.flags.has_block << 6) |
13568 (body->param.flags.ambiguous_param0 << 7) |
13569 (body->param.flags.accepts_no_kwarg << 8) |
13570 (body->param.flags.ruby2_keywords << 9) |
13571 (body->param.flags.anon_rest << 10) |
13572 (body->param.flags.anon_kwrest << 11) |
13573 (body->param.flags.use_block << 12) |
13574 (body->param.flags.forwardable << 13) ;
13575
13576#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13577# define IBF_BODY_OFFSET(x) (x)
13578#else
13579# define IBF_BODY_OFFSET(x) (body_offset - (x))
13580#endif
13581
13582 ibf_dump_write_small_value(dump, body->type);
13583 ibf_dump_write_small_value(dump, body->iseq_size);
13584 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13585 ibf_dump_write_small_value(dump, bytecode_size);
13586 ibf_dump_write_small_value(dump, param_flags);
13587 ibf_dump_write_small_value(dump, body->param.size);
13588 ibf_dump_write_small_value(dump, body->param.lead_num);
13589 ibf_dump_write_small_value(dump, body->param.opt_num);
13590 ibf_dump_write_small_value(dump, body->param.rest_start);
13591 ibf_dump_write_small_value(dump, body->param.post_start);
13592 ibf_dump_write_small_value(dump, body->param.post_num);
13593 ibf_dump_write_small_value(dump, body->param.block_start);
13594 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13595 ibf_dump_write_small_value(dump, param_keyword_offset);
13596 ibf_dump_write_small_value(dump, location_pathobj_index);
13597 ibf_dump_write_small_value(dump, location_base_label_index);
13598 ibf_dump_write_small_value(dump, location_label_index);
13599 ibf_dump_write_small_value(dump, body->location.first_lineno);
13600 ibf_dump_write_small_value(dump, body->location.node_id);
13601 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13602 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13603 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13604 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13605 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13606 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13607 ibf_dump_write_small_value(dump, body->insns_info.size);
13608 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13609 ibf_dump_write_small_value(dump, catch_table_size);
13610 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13611 ibf_dump_write_small_value(dump, parent_iseq_index);
13612 ibf_dump_write_small_value(dump, local_iseq_index);
13613 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13614 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13615 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13616 ibf_dump_write_small_value(dump, body->variable.flip_count);
13617 ibf_dump_write_small_value(dump, body->local_table_size);
13618 ibf_dump_write_small_value(dump, body->ivc_size);
13619 ibf_dump_write_small_value(dump, body->icvarc_size);
13620 ibf_dump_write_small_value(dump, body->ise_size);
13621 ibf_dump_write_small_value(dump, body->ic_size);
13622 ibf_dump_write_small_value(dump, body->ci_size);
13623 ibf_dump_write_small_value(dump, body->stack_max);
13624 ibf_dump_write_small_value(dump, body->builtin_attrs);
13625 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13626
13627#undef IBF_BODY_OFFSET
13628
13629#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13630 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13631
13632 dump->current_buffer = saved_buffer;
13633 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13634
13635 ibf_offset_t offset = ibf_dump_pos(dump);
13636 ibf_dump_write_small_value(dump, iseq_start);
13637 ibf_dump_write_small_value(dump, iseq_length_bytes);
13638 ibf_dump_write_small_value(dump, body_offset);
13639
13640 ibf_dump_write_small_value(dump, local_obj_list_offset);
13641 ibf_dump_write_small_value(dump, local_obj_list_size);
13642
13643 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13644
13645 return offset;
13646#else
13647 return body_offset;
13648#endif
13649}
13650
13651static VALUE
13652ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13653{
13654 VALUE str = ibf_load_object(load, str_index);
13655 if (str != Qnil) {
13656 str = rb_fstring(str);
13657 }
13658 return str;
13659}
13660
13661static void
13662ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13663{
13664 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13665
13666 ibf_offset_t reading_pos = offset;
13667
13668#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13669 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13670 load->current_buffer = &load->global_buffer;
13671
13672 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13673 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13674 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13675
13676 struct ibf_load_buffer buffer;
13677 buffer.buff = load->global_buffer.buff + iseq_start;
13678 buffer.size = iseq_length_bytes;
13679 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13680 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13681 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13682
13683 load->current_buffer = &buffer;
13684 reading_pos = body_offset;
13685#endif
13686
13687#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13688# define IBF_BODY_OFFSET(x) (x)
13689#else
13690# define IBF_BODY_OFFSET(x) (offset - (x))
13691#endif
13692
13693 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13694 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13695 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13696 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13697 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13698 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13699 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13700 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13701 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13702 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13703 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13704 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13705 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13706 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13707 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13708 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13709 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13710 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13711 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13712 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13713 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13714 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13715 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13716 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13717 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13718 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13719 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13720 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13721 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13722 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13723 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13724 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13725 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13726 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13727 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13728 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13729
13730 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13731 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13732 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13733 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13734
13735 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13736 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13737 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13738 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13739
13740 // setup fname and dummy frame
13741 VALUE path = ibf_load_object(load, location_pathobj_index);
13742 {
13743 VALUE realpath = Qnil;
13744
13745 if (RB_TYPE_P(path, T_STRING)) {
13746 realpath = path = rb_fstring(path);
13747 }
13748 else if (RB_TYPE_P(path, T_ARRAY)) {
13749 VALUE pathobj = path;
13750 if (RARRAY_LEN(pathobj) != 2) {
13751 rb_raise(rb_eRuntimeError, "path object size mismatch");
13752 }
13753 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13754 realpath = RARRAY_AREF(pathobj, 1);
13755 if (!NIL_P(realpath)) {
13756 if (!RB_TYPE_P(realpath, T_STRING)) {
13757 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13758 "(%x), path=%+"PRIsVALUE,
13759 realpath, TYPE(realpath), path);
13760 }
13761 realpath = rb_fstring(realpath);
13762 }
13763 }
13764 else {
13765 rb_raise(rb_eRuntimeError, "unexpected path object");
13766 }
13767 rb_iseq_pathobj_set(iseq, path, realpath);
13768 }
13769
13770 // push dummy frame
13771 rb_execution_context_t *ec = GET_EC();
13772 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13773
13774#undef IBF_BODY_OFFSET
13775
13776 load_body->type = type;
13777 load_body->stack_max = stack_max;
13778 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13779 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13780 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13781 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13782 load_body->param.flags.has_kw = FALSE;
13783 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13784 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13785 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13786 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13787 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13788 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13789 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13790 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13791 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13792 load_body->param.size = param_size;
13793 load_body->param.lead_num = param_lead_num;
13794 load_body->param.opt_num = param_opt_num;
13795 load_body->param.rest_start = param_rest_start;
13796 load_body->param.post_start = param_post_start;
13797 load_body->param.post_num = param_post_num;
13798 load_body->param.block_start = param_block_start;
13799 load_body->local_table_size = local_table_size;
13800 load_body->ci_size = ci_size;
13801 load_body->insns_info.size = insns_info_size;
13802
13803 ISEQ_COVERAGE_SET(iseq, Qnil);
13804 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13805 load_body->variable.flip_count = variable_flip_count;
13806 load_body->variable.script_lines = Qnil;
13807
13808 load_body->location.first_lineno = location_first_lineno;
13809 load_body->location.node_id = location_node_id;
13810 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13811 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13812 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13813 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13814 load_body->builtin_attrs = builtin_attrs;
13815 load_body->prism = prism;
13816
13817 load_body->ivc_size = ivc_size;
13818 load_body->icvarc_size = icvarc_size;
13819 load_body->ise_size = ise_size;
13820 load_body->ic_size = ic_size;
13821
13822 if (ISEQ_IS_SIZE(load_body)) {
13823 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13824 }
13825 else {
13826 load_body->is_entries = NULL;
13827 }
13828 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13829 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13830 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13831 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13832 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13833 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13834 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13835 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13836 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13837
13838 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13839 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13840 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13841
13842 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13843 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13844 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13845
13846 // This must be done after the local table is loaded.
13847 if (load_body->param.keyword != NULL) {
13848 RUBY_ASSERT(load_body->local_table);
13849 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13850 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13851 }
13852
13853 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13854#if VM_INSN_INFO_TABLE_IMPL == 2
13855 rb_iseq_insns_info_encode_positions(iseq);
13856#endif
13857
13858 rb_iseq_translate_threaded_code(iseq);
13859
13860#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13861 load->current_buffer = &load->global_buffer;
13862#endif
13863
13864 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13865 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13866
13867#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13868 load->current_buffer = saved_buffer;
13869#endif
13870 verify_call_cache(iseq);
13871
13872 RB_GC_GUARD(dummy_frame);
13873 rb_vm_pop_frame_no_int(ec);
13874}
13875
13877{
13878 struct ibf_dump *dump;
13879 VALUE offset_list;
13880};
13881
13882static int
13883ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13884{
13885 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13886 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13887
13888 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13889 rb_ary_push(args->offset_list, UINT2NUM(offset));
13890
13891 return ST_CONTINUE;
13892}
13893
13894static void
13895ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13896{
13897 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13898
13899 struct ibf_dump_iseq_list_arg args;
13900 args.dump = dump;
13901 args.offset_list = offset_list;
13902
13903 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13904
13905 st_index_t i;
13906 st_index_t size = dump->iseq_table->num_entries;
13907 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13908
13909 for (i = 0; i < size; i++) {
13910 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13911 }
13912
13913 ibf_dump_align(dump, sizeof(ibf_offset_t));
13914 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13915 header->iseq_list_size = (unsigned int)size;
13916}
13917
13918#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13919
13920/*
13921 * Binary format
13922 * - ibf_object_header
13923 * - ibf_object_xxx (xxx is type)
13924 */
13925
13927 unsigned int type: 5;
13928 unsigned int special_const: 1;
13929 unsigned int frozen: 1;
13930 unsigned int internal: 1;
13931};
13932
13933enum ibf_object_class_index {
13934 IBF_OBJECT_CLASS_OBJECT,
13935 IBF_OBJECT_CLASS_ARRAY,
13936 IBF_OBJECT_CLASS_STANDARD_ERROR,
13937 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13938 IBF_OBJECT_CLASS_TYPE_ERROR,
13939 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13940};
13941
13943 long srcstr;
13944 char option;
13945};
13946
13948 long len;
13949 long keyval[FLEX_ARY_LEN];
13950};
13951
13953 long class_index;
13954 long len;
13955 long beg;
13956 long end;
13957 int excl;
13958};
13959
13961 ssize_t slen;
13962 BDIGIT digits[FLEX_ARY_LEN];
13963};
13964
13965enum ibf_object_data_type {
13966 IBF_OBJECT_DATA_ENCODING,
13967};
13968
13970 long a, b;
13971};
13972
13974 long str;
13975};
13976
13977#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13978 ((((offset) - 1) / (align) + 1) * (align))
13979#define IBF_OBJBODY(type, offset) (const type *)\
13980 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13981
13982static const void *
13983ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13984{
13985 if (offset >= load->current_buffer->size) {
13986 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13987 }
13988 return load->current_buffer->buff + offset;
13989}
13990
13991NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13992
13993static void
13994ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13995{
13996 char buff[0x100];
13997 rb_raw_obj_info(buff, sizeof(buff), obj);
13998 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13999}
14000
14001NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14002
14003static VALUE
14004ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14005{
14006 rb_raise(rb_eArgError, "unsupported");
14008}
14009
14010static void
14011ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14012{
14013 enum ibf_object_class_index cindex;
14014 if (obj == rb_cObject) {
14015 cindex = IBF_OBJECT_CLASS_OBJECT;
14016 }
14017 else if (obj == rb_cArray) {
14018 cindex = IBF_OBJECT_CLASS_ARRAY;
14019 }
14020 else if (obj == rb_eStandardError) {
14021 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14022 }
14023 else if (obj == rb_eNoMatchingPatternError) {
14024 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14025 }
14026 else if (obj == rb_eTypeError) {
14027 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14028 }
14029 else if (obj == rb_eNoMatchingPatternKeyError) {
14030 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14031 }
14032 else {
14033 rb_obj_info_dump(obj);
14034 rb_p(obj);
14035 rb_bug("unsupported class");
14036 }
14037 ibf_dump_write_small_value(dump, (VALUE)cindex);
14038}
14039
14040static VALUE
14041ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14042{
14043 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14044
14045 switch (cindex) {
14046 case IBF_OBJECT_CLASS_OBJECT:
14047 return rb_cObject;
14048 case IBF_OBJECT_CLASS_ARRAY:
14049 return rb_cArray;
14050 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14051 return rb_eStandardError;
14052 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14054 case IBF_OBJECT_CLASS_TYPE_ERROR:
14055 return rb_eTypeError;
14056 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14058 }
14059
14060 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14061}
14062
14063
14064static void
14065ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14066{
14067 double dbl = RFLOAT_VALUE(obj);
14068 (void)IBF_W(&dbl, double, 1);
14069}
14070
14071static VALUE
14072ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14073{
14074 const double *dblp = IBF_OBJBODY(double, offset);
14075 return DBL2NUM(*dblp);
14076}
14077
14078static void
14079ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14080{
14081 long encindex = (long)rb_enc_get_index(obj);
14082 long len = RSTRING_LEN(obj);
14083 const char *ptr = RSTRING_PTR(obj);
14084
14085 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14086 rb_encoding *enc = rb_enc_from_index((int)encindex);
14087 const char *enc_name = rb_enc_name(enc);
14088 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14089 }
14090
14091 ibf_dump_write_small_value(dump, encindex);
14092 ibf_dump_write_small_value(dump, len);
14093 IBF_WP(ptr, char, len);
14094}
14095
14096static VALUE
14097ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14098{
14099 ibf_offset_t reading_pos = offset;
14100
14101 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14102 const long len = (long)ibf_load_small_value(load, &reading_pos);
14103 const char *ptr = load->current_buffer->buff + reading_pos;
14104
14105 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14106 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14107 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14108 }
14109
14110 VALUE str;
14111 if (header->frozen && !header->internal) {
14112 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14113 }
14114 else {
14115 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14116
14117 if (header->internal) rb_obj_hide(str);
14118 if (header->frozen) str = rb_fstring(str);
14119 }
14120 return str;
14121}
14122
14123static void
14124ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14125{
14126 VALUE srcstr = RREGEXP_SRC(obj);
14127 struct ibf_object_regexp regexp;
14128 regexp.option = (char)rb_reg_options(obj);
14129 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14130
14131 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14132 ibf_dump_write_small_value(dump, regexp.srcstr);
14133}
14134
14135static VALUE
14136ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14137{
14138 struct ibf_object_regexp regexp;
14139 regexp.option = ibf_load_byte(load, &offset);
14140 regexp.srcstr = ibf_load_small_value(load, &offset);
14141
14142 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14143 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14144
14145 if (header->internal) rb_obj_hide(reg);
14146 if (header->frozen) rb_obj_freeze(reg);
14147
14148 return reg;
14149}
14150
14151static void
14152ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14153{
14154 long i, len = RARRAY_LEN(obj);
14155 ibf_dump_write_small_value(dump, len);
14156 for (i=0; i<len; i++) {
14157 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14158 ibf_dump_write_small_value(dump, index);
14159 }
14160}
14161
14162static VALUE
14163ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14164{
14165 ibf_offset_t reading_pos = offset;
14166
14167 const long len = (long)ibf_load_small_value(load, &reading_pos);
14168
14169 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14170 int i;
14171
14172 for (i=0; i<len; i++) {
14173 const VALUE index = ibf_load_small_value(load, &reading_pos);
14174 rb_ary_push(ary, ibf_load_object(load, index));
14175 }
14176
14177 if (header->frozen) rb_ary_freeze(ary);
14178
14179 return ary;
14180}
14181
14182static int
14183ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14184{
14185 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14186
14187 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14188 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14189
14190 ibf_dump_write_small_value(dump, key_index);
14191 ibf_dump_write_small_value(dump, val_index);
14192 return ST_CONTINUE;
14193}
14194
14195static void
14196ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14197{
14198 long len = RHASH_SIZE(obj);
14199 ibf_dump_write_small_value(dump, (VALUE)len);
14200
14201 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14202}
14203
14204static VALUE
14205ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14206{
14207 long len = (long)ibf_load_small_value(load, &offset);
14208 VALUE obj = rb_hash_new_with_size(len);
14209 int i;
14210
14211 for (i = 0; i < len; i++) {
14212 VALUE key_index = ibf_load_small_value(load, &offset);
14213 VALUE val_index = ibf_load_small_value(load, &offset);
14214
14215 VALUE key = ibf_load_object(load, key_index);
14216 VALUE val = ibf_load_object(load, val_index);
14217 rb_hash_aset(obj, key, val);
14218 }
14219 rb_hash_rehash(obj);
14220
14221 if (header->internal) rb_obj_hide(obj);
14222 if (header->frozen) rb_obj_freeze(obj);
14223
14224 return obj;
14225}
14226
14227static void
14228ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14229{
14230 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14231 struct ibf_object_struct_range range;
14232 VALUE beg, end;
14233 IBF_ZERO(range);
14234 range.len = 3;
14235 range.class_index = 0;
14236
14237 rb_range_values(obj, &beg, &end, &range.excl);
14238 range.beg = (long)ibf_dump_object(dump, beg);
14239 range.end = (long)ibf_dump_object(dump, end);
14240
14241 IBF_W_ALIGN(struct ibf_object_struct_range);
14242 IBF_WV(range);
14243 }
14244 else {
14245 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14246 rb_class_name(CLASS_OF(obj)));
14247 }
14248}
14249
14250static VALUE
14251ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14252{
14253 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14254 VALUE beg = ibf_load_object(load, range->beg);
14255 VALUE end = ibf_load_object(load, range->end);
14256 VALUE obj = rb_range_new(beg, end, range->excl);
14257 if (header->internal) rb_obj_hide(obj);
14258 if (header->frozen) rb_obj_freeze(obj);
14259 return obj;
14260}
14261
14262static void
14263ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14264{
14265 ssize_t len = BIGNUM_LEN(obj);
14266 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14267 BDIGIT *d = BIGNUM_DIGITS(obj);
14268
14269 (void)IBF_W(&slen, ssize_t, 1);
14270 IBF_WP(d, BDIGIT, len);
14271}
14272
14273static VALUE
14274ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14275{
14276 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14277 int sign = bignum->slen > 0;
14278 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14279 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14282 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14283 big_unpack_flags |
14284 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14285 if (header->internal) rb_obj_hide(obj);
14286 if (header->frozen) rb_obj_freeze(obj);
14287 return obj;
14288}
14289
14290static void
14291ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14292{
14293 if (rb_data_is_encoding(obj)) {
14294 rb_encoding *enc = rb_to_encoding(obj);
14295 const char *name = rb_enc_name(enc);
14296 long len = strlen(name) + 1;
14297 long data[2];
14298 data[0] = IBF_OBJECT_DATA_ENCODING;
14299 data[1] = len;
14300 (void)IBF_W(data, long, 2);
14301 IBF_WP(name, char, len);
14302 }
14303 else {
14304 ibf_dump_object_unsupported(dump, obj);
14305 }
14306}
14307
14308static VALUE
14309ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14310{
14311 const long *body = IBF_OBJBODY(long, offset);
14312 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14313 /* const long len = body[1]; */
14314 const char *data = (const char *)&body[2];
14315
14316 switch (type) {
14317 case IBF_OBJECT_DATA_ENCODING:
14318 {
14319 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14320 return encobj;
14321 }
14322 }
14323
14324 return ibf_load_object_unsupported(load, header, offset);
14325}
14326
14327static void
14328ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14329{
14330 long data[2];
14331 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14332 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14333
14334 (void)IBF_W(data, long, 2);
14335}
14336
14337static VALUE
14338ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14339{
14340 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14341 VALUE a = ibf_load_object(load, nums->a);
14342 VALUE b = ibf_load_object(load, nums->b);
14343 VALUE obj = header->type == T_COMPLEX ?
14344 rb_complex_new(a, b) : rb_rational_new(a, b);
14345
14346 if (header->internal) rb_obj_hide(obj);
14347 if (header->frozen) rb_obj_freeze(obj);
14348 return obj;
14349}
14350
14351static void
14352ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14353{
14354 ibf_dump_object_string(dump, rb_sym2str(obj));
14355}
14356
14357static VALUE
14358ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14359{
14360 ibf_offset_t reading_pos = offset;
14361
14362 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14363 const long len = (long)ibf_load_small_value(load, &reading_pos);
14364 const char *ptr = load->current_buffer->buff + reading_pos;
14365
14366 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14367 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14368 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14369 }
14370
14371 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14372 return ID2SYM(id);
14373}
14374
14375typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14376static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14377 ibf_dump_object_unsupported, /* T_NONE */
14378 ibf_dump_object_unsupported, /* T_OBJECT */
14379 ibf_dump_object_class, /* T_CLASS */
14380 ibf_dump_object_unsupported, /* T_MODULE */
14381 ibf_dump_object_float, /* T_FLOAT */
14382 ibf_dump_object_string, /* T_STRING */
14383 ibf_dump_object_regexp, /* T_REGEXP */
14384 ibf_dump_object_array, /* T_ARRAY */
14385 ibf_dump_object_hash, /* T_HASH */
14386 ibf_dump_object_struct, /* T_STRUCT */
14387 ibf_dump_object_bignum, /* T_BIGNUM */
14388 ibf_dump_object_unsupported, /* T_FILE */
14389 ibf_dump_object_data, /* T_DATA */
14390 ibf_dump_object_unsupported, /* T_MATCH */
14391 ibf_dump_object_complex_rational, /* T_COMPLEX */
14392 ibf_dump_object_complex_rational, /* T_RATIONAL */
14393 ibf_dump_object_unsupported, /* 0x10 */
14394 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14395 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14396 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14397 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14398 ibf_dump_object_unsupported, /* T_FIXNUM */
14399 ibf_dump_object_unsupported, /* T_UNDEF */
14400 ibf_dump_object_unsupported, /* 0x17 */
14401 ibf_dump_object_unsupported, /* 0x18 */
14402 ibf_dump_object_unsupported, /* 0x19 */
14403 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14404 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14405 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14406 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14407 ibf_dump_object_unsupported, /* 0x1e */
14408 ibf_dump_object_unsupported, /* 0x1f */
14409};
14410
14411static void
14412ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14413{
14414 unsigned char byte =
14415 (header.type << 0) |
14416 (header.special_const << 5) |
14417 (header.frozen << 6) |
14418 (header.internal << 7);
14419
14420 IBF_WV(byte);
14421}
14422
14423static struct ibf_object_header
14424ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14425{
14426 unsigned char byte = ibf_load_byte(load, offset);
14427
14428 struct ibf_object_header header;
14429 header.type = (byte >> 0) & 0x1f;
14430 header.special_const = (byte >> 5) & 0x01;
14431 header.frozen = (byte >> 6) & 0x01;
14432 header.internal = (byte >> 7) & 0x01;
14433
14434 return header;
14435}
14436
14437static ibf_offset_t
14438ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14439{
14440 struct ibf_object_header obj_header;
14441 ibf_offset_t current_offset;
14442 IBF_ZERO(obj_header);
14443 obj_header.type = TYPE(obj);
14444
14445 IBF_W_ALIGN(ibf_offset_t);
14446 current_offset = ibf_dump_pos(dump);
14447
14448 if (SPECIAL_CONST_P(obj) &&
14449 ! (SYMBOL_P(obj) ||
14450 RB_FLOAT_TYPE_P(obj))) {
14451 obj_header.special_const = TRUE;
14452 obj_header.frozen = TRUE;
14453 obj_header.internal = TRUE;
14454 ibf_dump_object_object_header(dump, obj_header);
14455 ibf_dump_write_small_value(dump, obj);
14456 }
14457 else {
14458 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14459 obj_header.special_const = FALSE;
14460 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14461 ibf_dump_object_object_header(dump, obj_header);
14462 (*dump_object_functions[obj_header.type])(dump, obj);
14463 }
14464
14465 return current_offset;
14466}
14467
14468typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14469static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14470 ibf_load_object_unsupported, /* T_NONE */
14471 ibf_load_object_unsupported, /* T_OBJECT */
14472 ibf_load_object_class, /* T_CLASS */
14473 ibf_load_object_unsupported, /* T_MODULE */
14474 ibf_load_object_float, /* T_FLOAT */
14475 ibf_load_object_string, /* T_STRING */
14476 ibf_load_object_regexp, /* T_REGEXP */
14477 ibf_load_object_array, /* T_ARRAY */
14478 ibf_load_object_hash, /* T_HASH */
14479 ibf_load_object_struct, /* T_STRUCT */
14480 ibf_load_object_bignum, /* T_BIGNUM */
14481 ibf_load_object_unsupported, /* T_FILE */
14482 ibf_load_object_data, /* T_DATA */
14483 ibf_load_object_unsupported, /* T_MATCH */
14484 ibf_load_object_complex_rational, /* T_COMPLEX */
14485 ibf_load_object_complex_rational, /* T_RATIONAL */
14486 ibf_load_object_unsupported, /* 0x10 */
14487 ibf_load_object_unsupported, /* T_NIL */
14488 ibf_load_object_unsupported, /* T_TRUE */
14489 ibf_load_object_unsupported, /* T_FALSE */
14490 ibf_load_object_symbol,
14491 ibf_load_object_unsupported, /* T_FIXNUM */
14492 ibf_load_object_unsupported, /* T_UNDEF */
14493 ibf_load_object_unsupported, /* 0x17 */
14494 ibf_load_object_unsupported, /* 0x18 */
14495 ibf_load_object_unsupported, /* 0x19 */
14496 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14497 ibf_load_object_unsupported, /* T_NODE 0x1b */
14498 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14499 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14500 ibf_load_object_unsupported, /* 0x1e */
14501 ibf_load_object_unsupported, /* 0x1f */
14502};
14503
14504static VALUE
14505ibf_load_object(const struct ibf_load *load, VALUE object_index)
14506{
14507 if (object_index == 0) {
14508 return Qnil;
14509 }
14510 else {
14511 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14512 if (!obj) {
14513 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14514 ibf_offset_t offset = offsets[object_index];
14515 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14516
14517#if IBF_ISEQ_DEBUG
14518 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14519 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14520 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14521 header.type, header.special_const, header.frozen, header.internal);
14522#endif
14523 if (offset >= load->current_buffer->size) {
14524 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14525 }
14526
14527 if (header.special_const) {
14528 ibf_offset_t reading_pos = offset;
14529
14530 obj = ibf_load_small_value(load, &reading_pos);
14531 }
14532 else {
14533 obj = (*load_object_functions[header.type])(load, &header, offset);
14534 }
14535
14536 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14537 }
14538#if IBF_ISEQ_DEBUG
14539 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14540 object_index, obj);
14541#endif
14542 return obj;
14543 }
14544}
14545
14547{
14548 struct ibf_dump *dump;
14549 VALUE offset_list;
14550};
14551
14552static int
14553ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14554{
14555 VALUE obj = (VALUE)key;
14556 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14557
14558 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14559 rb_ary_push(args->offset_list, UINT2NUM(offset));
14560
14561 return ST_CONTINUE;
14562}
14563
14564static void
14565ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14566{
14567 st_table *obj_table = dump->current_buffer->obj_table;
14568 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14569
14570 struct ibf_dump_object_list_arg args;
14571 args.dump = dump;
14572 args.offset_list = offset_list;
14573
14574 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14575
14576 IBF_W_ALIGN(ibf_offset_t);
14577 *obj_list_offset = ibf_dump_pos(dump);
14578
14579 st_index_t size = obj_table->num_entries;
14580 st_index_t i;
14581
14582 for (i=0; i<size; i++) {
14583 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14584 IBF_WV(offset);
14585 }
14586
14587 *obj_list_size = (unsigned int)size;
14588}
14589
14590static void
14591ibf_dump_mark(void *ptr)
14592{
14593 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14594 rb_gc_mark(dump->global_buffer.str);
14595
14596 rb_mark_set(dump->global_buffer.obj_table);
14597 rb_mark_set(dump->iseq_table);
14598}
14599
14600static void
14601ibf_dump_free(void *ptr)
14602{
14603 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14604 if (dump->global_buffer.obj_table) {
14605 st_free_table(dump->global_buffer.obj_table);
14606 dump->global_buffer.obj_table = 0;
14607 }
14608 if (dump->iseq_table) {
14609 st_free_table(dump->iseq_table);
14610 dump->iseq_table = 0;
14611 }
14612}
14613
14614static size_t
14615ibf_dump_memsize(const void *ptr)
14616{
14617 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14618 size_t size = 0;
14619 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14620 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14621 return size;
14622}
14623
14624static const rb_data_type_t ibf_dump_type = {
14625 "ibf_dump",
14626 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14627 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14628};
14629
14630static void
14631ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14632{
14633 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14634 dump->iseq_table = NULL;
14635
14636 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14637 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14638 dump->iseq_table = st_init_numtable(); /* need free */
14639
14640 dump->current_buffer = &dump->global_buffer;
14641}
14642
14643VALUE
14644rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14645{
14646 struct ibf_dump *dump;
14647 struct ibf_header header = {{0}};
14648 VALUE dump_obj;
14649 VALUE str;
14650
14651 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14652 ISEQ_BODY(iseq)->local_iseq != iseq) {
14653 rb_raise(rb_eRuntimeError, "should be top of iseq");
14654 }
14655 if (RTEST(ISEQ_COVERAGE(iseq))) {
14656 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14657 }
14658
14659 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14660 ibf_dump_setup(dump, dump_obj);
14661
14662 ibf_dump_write(dump, &header, sizeof(header));
14663 ibf_dump_iseq(dump, iseq);
14664
14665 header.magic[0] = 'Y'; /* YARB */
14666 header.magic[1] = 'A';
14667 header.magic[2] = 'R';
14668 header.magic[3] = 'B';
14669 header.major_version = IBF_MAJOR_VERSION;
14670 header.minor_version = IBF_MINOR_VERSION;
14671 header.endian = IBF_ENDIAN_MARK;
14672 header.wordsize = (uint8_t)SIZEOF_VALUE;
14673 ibf_dump_iseq_list(dump, &header);
14674 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14675 header.size = ibf_dump_pos(dump);
14676
14677 if (RTEST(opt)) {
14678 VALUE opt_str = opt;
14679 const char *ptr = StringValuePtr(opt_str);
14680 header.extra_size = RSTRING_LENINT(opt_str);
14681 ibf_dump_write(dump, ptr, header.extra_size);
14682 }
14683 else {
14684 header.extra_size = 0;
14685 }
14686
14687 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14688
14689 str = dump->global_buffer.str;
14690 RB_GC_GUARD(dump_obj);
14691 return str;
14692}
14693
14694static const ibf_offset_t *
14695ibf_iseq_list(const struct ibf_load *load)
14696{
14697 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14698}
14699
14700void
14701rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14702{
14703 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14704 rb_iseq_t *prev_src_iseq = load->iseq;
14705 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14706 load->iseq = iseq;
14707#if IBF_ISEQ_DEBUG
14708 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14709 iseq->aux.loader.index, offset,
14710 load->header->size);
14711#endif
14712 ibf_load_iseq_each(load, iseq, offset);
14713 ISEQ_COMPILE_DATA_CLEAR(iseq);
14714 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14715 rb_iseq_init_trace(iseq);
14716 load->iseq = prev_src_iseq;
14717}
14718
14719#if USE_LAZY_LOAD
14720const rb_iseq_t *
14721rb_iseq_complete(const rb_iseq_t *iseq)
14722{
14723 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14724 return iseq;
14725}
14726#endif
14727
14728static rb_iseq_t *
14729ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14730{
14731 int iseq_index = (int)(VALUE)index_iseq;
14732
14733#if IBF_ISEQ_DEBUG
14734 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14735 (void *)index_iseq, (void *)load->iseq_list);
14736#endif
14737 if (iseq_index == -1) {
14738 return NULL;
14739 }
14740 else {
14741 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14742
14743#if IBF_ISEQ_DEBUG
14744 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14745#endif
14746 if (iseqv) {
14747 return (rb_iseq_t *)iseqv;
14748 }
14749 else {
14750 rb_iseq_t *iseq = iseq_imemo_alloc();
14751#if IBF_ISEQ_DEBUG
14752 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14753#endif
14754 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14755 iseq->aux.loader.obj = load->loader_obj;
14756 iseq->aux.loader.index = iseq_index;
14757#if IBF_ISEQ_DEBUG
14758 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14759 (void *)iseq, (void *)load->loader_obj, iseq_index);
14760#endif
14761 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14762
14763 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14764#if IBF_ISEQ_DEBUG
14765 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14766#endif
14767 rb_ibf_load_iseq_complete(iseq);
14768 }
14769
14770#if IBF_ISEQ_DEBUG
14771 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14772 (void *)iseq, (void *)load->iseq);
14773#endif
14774 return iseq;
14775 }
14776 }
14777}
14778
14779static void
14780ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14781{
14782 struct ibf_header *header = (struct ibf_header *)bytes;
14783 load->loader_obj = loader_obj;
14784 load->global_buffer.buff = bytes;
14785 load->header = header;
14786 load->global_buffer.size = header->size;
14787 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14788 load->global_buffer.obj_list_size = header->global_object_list_size;
14789 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14790 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14791 load->iseq = NULL;
14792
14793 load->current_buffer = &load->global_buffer;
14794
14795 if (size < header->size) {
14796 rb_raise(rb_eRuntimeError, "broken binary format");
14797 }
14798 if (strncmp(header->magic, "YARB", 4) != 0) {
14799 rb_raise(rb_eRuntimeError, "unknown binary format");
14800 }
14801 if (header->major_version != IBF_MAJOR_VERSION ||
14802 header->minor_version != IBF_MINOR_VERSION) {
14803 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14804 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14805 }
14806 if (header->endian != IBF_ENDIAN_MARK) {
14807 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14808 }
14809 if (header->wordsize != SIZEOF_VALUE) {
14810 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14811 }
14812 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14813 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14814 header->iseq_list_offset);
14815 }
14816 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14817 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14818 load->global_buffer.obj_list_offset);
14819 }
14820}
14821
14822static void
14823ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14824{
14825 StringValue(str);
14826
14827 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14828 rb_raise(rb_eRuntimeError, "broken binary format");
14829 }
14830
14831 if (USE_LAZY_LOAD) {
14832 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14833 }
14834
14835 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14836 RB_OBJ_WRITE(loader_obj, &load->str, str);
14837}
14838
14839static void
14840ibf_loader_mark(void *ptr)
14841{
14842 struct ibf_load *load = (struct ibf_load *)ptr;
14843 rb_gc_mark(load->str);
14844 rb_gc_mark(load->iseq_list);
14845 rb_gc_mark(load->global_buffer.obj_list);
14846}
14847
14848static void
14849ibf_loader_free(void *ptr)
14850{
14851 struct ibf_load *load = (struct ibf_load *)ptr;
14852 ruby_xfree(load);
14853}
14854
14855static size_t
14856ibf_loader_memsize(const void *ptr)
14857{
14858 return sizeof(struct ibf_load);
14859}
14860
14861static const rb_data_type_t ibf_load_type = {
14862 "ibf_loader",
14863 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14864 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14865};
14866
14867const rb_iseq_t *
14868rb_iseq_ibf_load(VALUE str)
14869{
14870 struct ibf_load *load;
14871 rb_iseq_t *iseq;
14872 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14873
14874 ibf_load_setup(load, loader_obj, str);
14875 iseq = ibf_load_iseq(load, 0);
14876
14877 RB_GC_GUARD(loader_obj);
14878 return iseq;
14879}
14880
14881const rb_iseq_t *
14882rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14883{
14884 struct ibf_load *load;
14885 rb_iseq_t *iseq;
14886 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14887
14888 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14889 iseq = ibf_load_iseq(load, 0);
14890
14891 RB_GC_GUARD(loader_obj);
14892 return iseq;
14893}
14894
14895VALUE
14896rb_iseq_ibf_load_extra_data(VALUE str)
14897{
14898 struct ibf_load *load;
14899 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14900 VALUE extra_str;
14901
14902 ibf_load_setup(load, loader_obj, str);
14903 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14904 RB_GC_GUARD(loader_obj);
14905 return extra_str;
14906}
14907
14908#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:695
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:110
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:101
VALUE rb_cHash
Hash class.
Definition hash.c:113
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:657
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:880
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1299
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1063
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1087
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1838
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:68
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4225
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:4102
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:2057
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4478
#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:4464
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3870
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:4068
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4534
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:4351
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3583
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:493
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:953
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:972
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:921
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1405
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:163
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:450
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9067
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:30
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:280
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:287
Definition vm_core.h:290
Definition iseq.h:251
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:203
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:210
struct rb_iseq_constant_body::@154 param
parameter information
Definition st.h:79
Definition vm_core.h:299
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145