Ruby 3.5.0dev (2025-02-19 revision 27ba268b75bbe461460b31426e377b42d4935f70)
compile.c (27ba268b75bbe461460b31426e377b42d4935f70)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497
498static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
499static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
500
501/*
502 * To make Array to LinkedList, use link_anchor
503 */
504
505static void
506verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
507{
508#if CPDEBUG
509 int flag = 0;
510 LINK_ELEMENT *list, *plist;
511
512 if (!compile_debug) return;
513
514 list = anchor->anchor.next;
515 plist = &anchor->anchor;
516 while (list) {
517 if (plist != list->prev) {
518 flag += 1;
519 }
520 plist = list;
521 list = list->next;
522 }
523
524 if (anchor->last != plist && anchor->last != 0) {
525 flag |= 0x70000;
526 }
527
528 if (flag != 0) {
529 rb_bug("list verify error: %08x (%s)", flag, info);
530 }
531#endif
532}
533#if CPDEBUG < 0
534#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
535#endif
536
537static void
538verify_call_cache(rb_iseq_t *iseq)
539{
540#if CPDEBUG
541 VALUE *original = rb_iseq_original_iseq(iseq);
542 size_t i = 0;
543 while (i < ISEQ_BODY(iseq)->iseq_size) {
544 VALUE insn = original[i];
545 const char *types = insn_op_types(insn);
546
547 for (int j=0; types[j]; j++) {
548 if (types[j] == TS_CALLDATA) {
549 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
550 const struct rb_callinfo *ci = cd->ci;
551 const struct rb_callcache *cc = cd->cc;
552 if (cc != vm_cc_empty()) {
553 vm_ci_dump(ci);
554 rb_bug("call cache is not initialized by vm_cc_empty()");
555 }
556 }
557 }
558 i += insn_len(insn);
559 }
560
561 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
562 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
563 const struct rb_callinfo *ci = cd->ci;
564 const struct rb_callcache *cc = cd->cc;
565 if (cc != NULL && cc != vm_cc_empty()) {
566 vm_ci_dump(ci);
567 rb_bug("call cache is not initialized by vm_cc_empty()");
568 }
569 }
570#endif
571}
572
573/*
574 * elem1, elem2 => elem1, elem2, elem
575 */
576static void
577ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
578{
579 elem->prev = anchor->last;
580 anchor->last->next = elem;
581 anchor->last = elem;
582 verify_list("add", anchor);
583}
584
585/*
586 * elem1, before, elem2 => elem1, before, elem, elem2
587 */
588static void
589APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
590{
591 elem->prev = before;
592 elem->next = before->next;
593 elem->next->prev = elem;
594 before->next = elem;
595 if (before == anchor->last) anchor->last = elem;
596 verify_list("add", anchor);
597}
598#if CPDEBUG < 0
599#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
600#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
601#endif
602
603static int
604branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
605{
606 if (!ISEQ_COVERAGE(iseq)) return 0;
607 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
608 if (first_line <= 0) return 0;
609 return 1;
610}
611
612#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
613
614static VALUE
615setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
616{
617 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
618 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
619 VALUE branch = rb_ary_hidden_new(6);
620
621 rb_hash_aset(structure, key, branch);
622 rb_ary_push(branch, ID2SYM(rb_intern(type)));
623 rb_ary_push(branch, INT2FIX(first_lineno));
624 rb_ary_push(branch, INT2FIX(first_column));
625 rb_ary_push(branch, INT2FIX(last_lineno));
626 rb_ary_push(branch, INT2FIX(last_column));
627 return branch;
628}
629
630static VALUE
631decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
632{
633 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
634
635 /*
636 * if !structure[node]
637 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
638 * else
639 * branches = structure[node][5]
640 * end
641 */
642
643 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
644 VALUE branch_base = rb_hash_aref(structure, key);
645 VALUE branches;
646
647 if (NIL_P(branch_base)) {
648 branch_base = setup_branch(loc, type, structure, key);
649 branches = rb_hash_new();
650 rb_obj_hide(branches);
651 rb_ary_push(branch_base, branches);
652 }
653 else {
654 branches = RARRAY_AREF(branch_base, 5);
655 }
656
657 return branches;
658}
659
660static NODE
661generate_dummy_line_node(int lineno, int node_id)
662{
663 NODE dummy = { 0 };
664 nd_set_line(&dummy, lineno);
665 nd_set_node_id(&dummy, node_id);
666 return dummy;
667}
668
669static void
670add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
671{
672 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
673
674 /*
675 * if !branches[branch_id]
676 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
677 * else
678 * counter_idx= branches[branch_id][5]
679 * end
680 */
681
682 VALUE key = INT2FIX(branch_id);
683 VALUE branch = rb_hash_aref(branches, key);
684 long counter_idx;
685
686 if (NIL_P(branch)) {
687 branch = setup_branch(loc, type, branches, key);
688 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
689 counter_idx = RARRAY_LEN(counters);
690 rb_ary_push(branch, LONG2FIX(counter_idx));
691 rb_ary_push(counters, INT2FIX(0));
692 }
693 else {
694 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
695 }
696
697 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
698 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
699}
700
701#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
702
703static int
704validate_label(st_data_t name, st_data_t label, st_data_t arg)
705{
706 rb_iseq_t *iseq = (rb_iseq_t *)arg;
707 LABEL *lobj = (LABEL *)label;
708 if (!lobj->link.next) {
709 do {
710 COMPILE_ERROR(iseq, lobj->position,
711 "%"PRIsVALUE": undefined label",
712 rb_sym2str((VALUE)name));
713 } while (0);
714 }
715 return ST_CONTINUE;
716}
717
718static void
719validate_labels(rb_iseq_t *iseq, st_table *labels_table)
720{
721 st_foreach(labels_table, validate_label, (st_data_t)iseq);
722 st_free_table(labels_table);
723}
724
725static NODE *
726get_nd_recv(const NODE *node)
727{
728 switch (nd_type(node)) {
729 case NODE_CALL:
730 return RNODE_CALL(node)->nd_recv;
731 case NODE_OPCALL:
732 return RNODE_OPCALL(node)->nd_recv;
733 case NODE_FCALL:
734 return 0;
735 case NODE_QCALL:
736 return RNODE_QCALL(node)->nd_recv;
737 case NODE_VCALL:
738 return 0;
739 case NODE_ATTRASGN:
740 return RNODE_ATTRASGN(node)->nd_recv;
741 case NODE_OP_ASGN1:
742 return RNODE_OP_ASGN1(node)->nd_recv;
743 case NODE_OP_ASGN2:
744 return RNODE_OP_ASGN2(node)->nd_recv;
745 default:
746 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
747 }
748}
749
750static ID
751get_node_call_nd_mid(const NODE *node)
752{
753 switch (nd_type(node)) {
754 case NODE_CALL:
755 return RNODE_CALL(node)->nd_mid;
756 case NODE_OPCALL:
757 return RNODE_OPCALL(node)->nd_mid;
758 case NODE_FCALL:
759 return RNODE_FCALL(node)->nd_mid;
760 case NODE_QCALL:
761 return RNODE_QCALL(node)->nd_mid;
762 case NODE_VCALL:
763 return RNODE_VCALL(node)->nd_mid;
764 case NODE_ATTRASGN:
765 return RNODE_ATTRASGN(node)->nd_mid;
766 default:
767 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
768 }
769}
770
771static NODE *
772get_nd_args(const NODE *node)
773{
774 switch (nd_type(node)) {
775 case NODE_CALL:
776 return RNODE_CALL(node)->nd_args;
777 case NODE_OPCALL:
778 return RNODE_OPCALL(node)->nd_args;
779 case NODE_FCALL:
780 return RNODE_FCALL(node)->nd_args;
781 case NODE_QCALL:
782 return RNODE_QCALL(node)->nd_args;
783 case NODE_VCALL:
784 return 0;
785 case NODE_ATTRASGN:
786 return RNODE_ATTRASGN(node)->nd_args;
787 default:
788 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
789 }
790}
791
792static ID
793get_node_colon_nd_mid(const NODE *node)
794{
795 switch (nd_type(node)) {
796 case NODE_COLON2:
797 return RNODE_COLON2(node)->nd_mid;
798 case NODE_COLON3:
799 return RNODE_COLON3(node)->nd_mid;
800 default:
801 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
802 }
803}
804
805static ID
806get_nd_vid(const NODE *node)
807{
808 switch (nd_type(node)) {
809 case NODE_LASGN:
810 return RNODE_LASGN(node)->nd_vid;
811 case NODE_DASGN:
812 return RNODE_DASGN(node)->nd_vid;
813 case NODE_IASGN:
814 return RNODE_IASGN(node)->nd_vid;
815 case NODE_CVASGN:
816 return RNODE_CVASGN(node)->nd_vid;
817 default:
818 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
819 }
820}
821
822static NODE *
823get_nd_value(const NODE *node)
824{
825 switch (nd_type(node)) {
826 case NODE_LASGN:
827 return RNODE_LASGN(node)->nd_value;
828 case NODE_DASGN:
829 return RNODE_DASGN(node)->nd_value;
830 default:
831 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
832 }
833}
834
835static VALUE
836get_string_value(const NODE *node)
837{
838 switch (nd_type(node)) {
839 case NODE_STR:
840 return rb_node_str_string_val(node);
841 case NODE_FILE:
842 return rb_node_file_path_val(node);
843 default:
844 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
845 }
846}
847
848VALUE
849rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
850{
851 DECL_ANCHOR(ret);
852 INIT_ANCHOR(ret);
853
854 (*ifunc->func)(iseq, ret, ifunc->data);
855
856 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
857
858 CHECK(iseq_setup_insn(iseq, ret));
859 return iseq_setup(iseq, ret);
860}
861
862static bool drop_unreachable_return(LINK_ANCHOR *ret);
863
864VALUE
865rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
866{
867 DECL_ANCHOR(ret);
868 INIT_ANCHOR(ret);
869
870 if (node == 0) {
871 NO_CHECK(COMPILE(ret, "nil", node));
872 iseq_set_local_table(iseq, 0, 0);
873 }
874 /* assume node is T_NODE */
875 else if (nd_type_p(node, NODE_SCOPE)) {
876 /* iseq type of top, method, class, block */
877 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, obj);
1401}
1402
1403static INSN *
1404new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1405{
1406 INSN *iobj = compile_data_alloc_insn(iseq);
1407
1408 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1409
1410 iobj->link.type = ISEQ_ELEMENT_INSN;
1411 iobj->link.next = 0;
1412 iobj->insn_id = insn_id;
1413 iobj->insn_info.line_no = line_no;
1414 iobj->insn_info.node_id = node_id;
1415 iobj->insn_info.events = 0;
1416 iobj->operands = argv;
1417 iobj->operand_size = argc;
1418 iobj->sc_state = 0;
1419
1420 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1421
1422 return iobj;
1423}
1424
1425static INSN *
1426new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1427{
1428 VALUE *operands = 0;
1429 va_list argv;
1430 if (argc > 0) {
1431 int i;
1432 va_start(argv, argc);
1433 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1434 for (i = 0; i < argc; i++) {
1435 VALUE v = va_arg(argv, VALUE);
1436 operands[i] = v;
1437 }
1438 va_end(argv);
1439 }
1440 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1441}
1442
1443static const struct rb_callinfo *
1444new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1445{
1446 VM_ASSERT(argc >= 0);
1447
1448 if (kw_arg) {
1449 flag |= VM_CALL_KWARG;
1450 argc += kw_arg->keyword_len;
1451 }
1452
1453 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1454 && !has_blockiseq) {
1455 flag |= VM_CALL_ARGS_SIMPLE;
1456 }
1457
1458 ISEQ_BODY(iseq)->ci_size++;
1459 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1460 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1461 return ci;
1462}
1463
1464static INSN *
1465new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1466{
1467 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1468 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1469 operands[0] = ci;
1470 operands[1] = (VALUE)blockiseq;
1471 if (blockiseq) {
1472 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1473 }
1474
1475 INSN *insn;
1476
1477 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1478 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1479 }
1480 else {
1481 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1482 }
1483
1484 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1485 RB_GC_GUARD(ci);
1486 return insn;
1487}
1488
1489static rb_iseq_t *
1490new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1491 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1492{
1493 rb_iseq_t *ret_iseq;
1494 VALUE ast_value = rb_ruby_ast_new(node);
1495
1496 debugs("[new_child_iseq]> ---------------------------------------\n");
1497 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1498 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1499 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1500 line_no, parent,
1501 isolated_depth ? isolated_depth + 1 : 0,
1502 type, ISEQ_COMPILE_DATA(iseq)->option,
1503 ISEQ_BODY(iseq)->variable.script_lines);
1504 debugs("[new_child_iseq]< ---------------------------------------\n");
1505 return ret_iseq;
1506}
1507
1508static rb_iseq_t *
1509new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1510 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1511{
1512 rb_iseq_t *ret_iseq;
1513
1514 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1515 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1516 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1517 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1518 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1519 return ret_iseq;
1520}
1521
1522static void
1523set_catch_except_p(rb_iseq_t *iseq)
1524{
1525 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1526 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1527 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1528 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1529 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1530 }
1531 }
1532}
1533
1534/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1535 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1536 if catch table exists. But we want to optimize while loop, which always has catch
1537 table entries for break/next/redo.
1538
1539 So this function sets true for limited ISeqs with break/next/redo catch table entries
1540 whose child ISeq would really raise an exception. */
1541static void
1542update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1543{
1544 unsigned int pos;
1545 size_t i;
1546 int insn;
1547 const struct iseq_catch_table *ct = body->catch_table;
1548
1549 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1550 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1551 pos = 0;
1552 while (pos < body->iseq_size) {
1553 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1554 if (insn == BIN(throw)) {
1555 set_catch_except_p(iseq);
1556 break;
1557 }
1558 pos += insn_len(insn);
1559 }
1560
1561 if (ct == NULL)
1562 return;
1563
1564 for (i = 0; i < ct->size; i++) {
1565 const struct iseq_catch_table_entry *entry =
1566 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1567 if (entry->type != CATCH_TYPE_BREAK
1568 && entry->type != CATCH_TYPE_NEXT
1569 && entry->type != CATCH_TYPE_REDO) {
1570 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1571 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1572 break;
1573 }
1574 }
1575}
1576
1577static void
1578iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1579{
1580 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1581 if (NIL_P(catch_table_ary)) return;
1582 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1583 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1584 for (i = 0; i < tlen; i++) {
1585 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1586 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1587 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1588 LINK_ELEMENT *e;
1589
1590 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1591
1592 if (ct != CATCH_TYPE_BREAK
1593 && ct != CATCH_TYPE_NEXT
1594 && ct != CATCH_TYPE_REDO) {
1595
1596 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1597 if (e == cont) {
1598 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1599 ELEM_INSERT_NEXT(end, &nop->link);
1600 break;
1601 }
1602 }
1603 }
1604 }
1605
1606 RB_GC_GUARD(catch_table_ary);
1607}
1608
1609static int
1610iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1611{
1612 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1613 return COMPILE_NG;
1614
1615 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1616
1617 if (compile_debug > 5)
1618 dump_disasm_list(FIRST_ELEMENT(anchor));
1619
1620 debugs("[compile step 3.1 (iseq_optimize)]\n");
1621 iseq_optimize(iseq, anchor);
1622
1623 if (compile_debug > 5)
1624 dump_disasm_list(FIRST_ELEMENT(anchor));
1625
1626 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1627 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1628 iseq_insns_unification(iseq, anchor);
1629 if (compile_debug > 5)
1630 dump_disasm_list(FIRST_ELEMENT(anchor));
1631 }
1632
1633 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1634 iseq_insert_nop_between_end_and_cont(iseq);
1635 if (compile_debug > 5)
1636 dump_disasm_list(FIRST_ELEMENT(anchor));
1637
1638 return COMPILE_OK;
1639}
1640
1641static int
1642iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1643{
1644 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1645 return COMPILE_NG;
1646
1647 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1648 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1649 if (compile_debug > 5)
1650 dump_disasm_list(FIRST_ELEMENT(anchor));
1651
1652 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1653 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1654
1655 debugs("[compile step 4.3 (set_optargs_table)] \n");
1656 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1657
1658 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1659 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1660
1661 debugs("[compile step 6 (update_catch_except_flags)] \n");
1662 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1663 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1664
1665 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1666 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1667 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1668 xfree(ISEQ_BODY(iseq)->catch_table);
1669 ISEQ_BODY(iseq)->catch_table = NULL;
1670 }
1671
1672#if VM_INSN_INFO_TABLE_IMPL == 2
1673 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1674 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1675 rb_iseq_insns_info_encode_positions(iseq);
1676 }
1677#endif
1678
1679 if (compile_debug > 1) {
1680 VALUE str = rb_iseq_disasm(iseq);
1681 printf("%s\n", StringValueCStr(str));
1682 }
1683 verify_call_cache(iseq);
1684 debugs("[compile step: finish]\n");
1685
1686 return COMPILE_OK;
1687}
1688
1689static int
1690iseq_set_exception_local_table(rb_iseq_t *iseq)
1691{
1692 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1693 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1694 return COMPILE_OK;
1695}
1696
1697static int
1698get_lvar_level(const rb_iseq_t *iseq)
1699{
1700 int lev = 0;
1701 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1702 lev++;
1703 iseq = ISEQ_BODY(iseq)->parent_iseq;
1704 }
1705 return lev;
1706}
1707
1708static int
1709get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1710{
1711 unsigned int i;
1712
1713 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1714 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1715 return (int)i;
1716 }
1717 }
1718 return -1;
1719}
1720
1721static int
1722get_local_var_idx(const rb_iseq_t *iseq, ID id)
1723{
1724 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1725
1726 if (idx < 0) {
1727 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1728 "get_local_var_idx: %d", idx);
1729 }
1730
1731 return idx;
1732}
1733
1734static int
1735get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1736{
1737 int lv = 0, idx = -1;
1738 const rb_iseq_t *const topmost_iseq = iseq;
1739
1740 while (iseq) {
1741 idx = get_dyna_var_idx_at_raw(iseq, id);
1742 if (idx >= 0) {
1743 break;
1744 }
1745 iseq = ISEQ_BODY(iseq)->parent_iseq;
1746 lv++;
1747 }
1748
1749 if (idx < 0) {
1750 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1751 "get_dyna_var_idx: -1");
1752 }
1753
1754 *level = lv;
1755 *ls = ISEQ_BODY(iseq)->local_table_size;
1756 return idx;
1757}
1758
1759static int
1760iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1761{
1762 const struct rb_iseq_constant_body *body;
1763 while (level > 0) {
1764 iseq = ISEQ_BODY(iseq)->parent_iseq;
1765 level--;
1766 }
1767 body = ISEQ_BODY(iseq);
1768 if (body->local_iseq == iseq && /* local variables */
1769 body->param.flags.has_block &&
1770 body->local_table_size - body->param.block_start == idx) {
1771 return TRUE;
1772 }
1773 else {
1774 return FALSE;
1775 }
1776}
1777
1778static int
1779iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1780{
1781 int level, ls;
1782 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1783 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1784 *pidx = ls - idx;
1785 *plevel = level;
1786 return TRUE;
1787 }
1788 else {
1789 return FALSE;
1790 }
1791}
1792
1793static void
1794access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1795{
1796 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1797
1798 if (isolated_depth && level >= isolated_depth) {
1799 if (id == rb_intern("yield")) {
1800 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1801 }
1802 else {
1803 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1804 }
1805 }
1806
1807 for (int i=0; i<level; i++) {
1808 VALUE val;
1809 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1810
1811 if (!ovs) {
1812 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1813 }
1814
1815 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1816 if (write && !val) {
1817 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1818 }
1819 }
1820 else {
1821 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1822 }
1823
1824 iseq = ISEQ_BODY(iseq)->parent_iseq;
1825 }
1826}
1827
1828static ID
1829iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1830{
1831 for (int i=0; i<level; i++) {
1832 iseq = ISEQ_BODY(iseq)->parent_iseq;
1833 }
1834
1835 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1836 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1837 return id;
1838}
1839
1840static void
1841iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1842{
1843 if (iseq_local_block_param_p(iseq, idx, level)) {
1844 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1845 }
1846 else {
1847 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1848 }
1849 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1850}
1851
1852static void
1853iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1854{
1855 if (iseq_local_block_param_p(iseq, idx, level)) {
1856 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1857 }
1858 else {
1859 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1860 }
1861 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1862}
1863
1864
1865
1866static void
1867iseq_calc_param_size(rb_iseq_t *iseq)
1868{
1869 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1870 if (body->param.flags.has_opt ||
1871 body->param.flags.has_post ||
1872 body->param.flags.has_rest ||
1873 body->param.flags.has_block ||
1874 body->param.flags.has_kw ||
1875 body->param.flags.has_kwrest) {
1876
1877 if (body->param.flags.has_block) {
1878 body->param.size = body->param.block_start + 1;
1879 }
1880 else if (body->param.flags.has_kwrest) {
1881 body->param.size = body->param.keyword->rest_start + 1;
1882 }
1883 else if (body->param.flags.has_kw) {
1884 body->param.size = body->param.keyword->bits_start + 1;
1885 }
1886 else if (body->param.flags.has_post) {
1887 body->param.size = body->param.post_start + body->param.post_num;
1888 }
1889 else if (body->param.flags.has_rest) {
1890 body->param.size = body->param.rest_start + 1;
1891 }
1892 else if (body->param.flags.has_opt) {
1893 body->param.size = body->param.lead_num + body->param.opt_num;
1894 }
1895 else {
1897 }
1898 }
1899 else {
1900 body->param.size = body->param.lead_num;
1901 }
1902}
1903
1904static int
1905iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1906 const struct rb_args_info *args, int arg_size)
1907{
1908 const rb_node_kw_arg_t *node = args->kw_args;
1909 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1910 struct rb_iseq_param_keyword *keyword;
1911 const VALUE default_values = rb_ary_hidden_new(1);
1912 const VALUE complex_mark = rb_str_tmp_new(0);
1913 int kw = 0, rkw = 0, di = 0, i;
1914
1915 body->param.flags.has_kw = TRUE;
1916 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1917
1918 while (node) {
1919 kw++;
1920 node = node->nd_next;
1921 }
1922 arg_size += kw;
1923 keyword->bits_start = arg_size++;
1924
1925 node = args->kw_args;
1926 while (node) {
1927 const NODE *val_node = get_nd_value(node->nd_body);
1928 VALUE dv;
1929
1930 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1931 ++rkw;
1932 }
1933 else {
1934 switch (nd_type(val_node)) {
1935 case NODE_SYM:
1936 dv = rb_node_sym_string_val(val_node);
1937 break;
1938 case NODE_REGX:
1939 dv = rb_node_regx_string_val(val_node);
1940 break;
1941 case NODE_LINE:
1942 dv = rb_node_line_lineno_val(val_node);
1943 break;
1944 case NODE_INTEGER:
1945 dv = rb_node_integer_literal_val(val_node);
1946 break;
1947 case NODE_FLOAT:
1948 dv = rb_node_float_literal_val(val_node);
1949 break;
1950 case NODE_RATIONAL:
1951 dv = rb_node_rational_literal_val(val_node);
1952 break;
1953 case NODE_IMAGINARY:
1954 dv = rb_node_imaginary_literal_val(val_node);
1955 break;
1956 case NODE_ENCODING:
1957 dv = rb_node_encoding_val(val_node);
1958 break;
1959 case NODE_NIL:
1960 dv = Qnil;
1961 break;
1962 case NODE_TRUE:
1963 dv = Qtrue;
1964 break;
1965 case NODE_FALSE:
1966 dv = Qfalse;
1967 break;
1968 default:
1969 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1970 dv = complex_mark;
1971 }
1972
1973 keyword->num = ++di;
1974 rb_ary_push(default_values, dv);
1975 }
1976
1977 node = node->nd_next;
1978 }
1979
1980 keyword->num = kw;
1981
1982 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1983 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
1984 keyword->rest_start = arg_size++;
1985 body->param.flags.has_kwrest = TRUE;
1986
1987 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
1988 }
1989 keyword->required_num = rkw;
1990 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1991
1992 if (RARRAY_LEN(default_values)) {
1993 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1994
1995 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1996 VALUE dv = RARRAY_AREF(default_values, i);
1997 if (dv == complex_mark) dv = Qundef;
1998 RB_OBJ_WRITE(iseq, &dvs[i], dv);
1999 }
2000
2001 keyword->default_values = dvs;
2002 }
2003 return arg_size;
2004}
2005
2006static void
2007iseq_set_use_block(rb_iseq_t *iseq)
2008{
2009 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2010 if (!body->param.flags.use_block) {
2011 body->param.flags.use_block = 1;
2012
2013 rb_vm_t *vm = GET_VM();
2014
2015 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2016 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2017 st_insert(vm->unused_block_warning_table, key, 1);
2018 }
2019 }
2020}
2021
2022static int
2023iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2024{
2025 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2026
2027 if (node_args) {
2028 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2029 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2030 ID rest_id = 0;
2031 int last_comma = 0;
2032 ID block_id = 0;
2033 int arg_size;
2034
2035 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2036
2037 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2038 body->param.lead_num = arg_size = (int)args->pre_args_num;
2039 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2040 debugs(" - argc: %d\n", body->param.lead_num);
2041
2042 rest_id = args->rest_arg;
2043 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2044 last_comma = 1;
2045 rest_id = 0;
2046 }
2047 block_id = args->block_arg;
2048
2049 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2050
2051 if (optimized_forward) {
2052 rest_id = 0;
2053 block_id = 0;
2054 }
2055
2056 if (args->opt_args) {
2057 const rb_node_opt_arg_t *node = args->opt_args;
2058 LABEL *label;
2059 VALUE labels = rb_ary_hidden_new(1);
2060 VALUE *opt_table;
2061 int i = 0, j;
2062
2063 while (node) {
2064 label = NEW_LABEL(nd_line(RNODE(node)));
2065 rb_ary_push(labels, (VALUE)label | 1);
2066 ADD_LABEL(optargs, label);
2067 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2068 node = node->nd_next;
2069 i += 1;
2070 }
2071
2072 /* last label */
2073 label = NEW_LABEL(nd_line(node_args));
2074 rb_ary_push(labels, (VALUE)label | 1);
2075 ADD_LABEL(optargs, label);
2076
2077 opt_table = ALLOC_N(VALUE, i+1);
2078
2079 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2080 for (j = 0; j < i+1; j++) {
2081 opt_table[j] &= ~1;
2082 }
2083 rb_ary_clear(labels);
2084
2085 body->param.flags.has_opt = TRUE;
2086 body->param.opt_num = i;
2087 body->param.opt_table = opt_table;
2088 arg_size += i;
2089 }
2090
2091 if (rest_id) {
2092 body->param.rest_start = arg_size++;
2093 body->param.flags.has_rest = TRUE;
2094 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2095 RUBY_ASSERT(body->param.rest_start != -1);
2096 }
2097
2098 if (args->first_post_arg) {
2099 body->param.post_start = arg_size;
2100 body->param.post_num = args->post_args_num;
2101 body->param.flags.has_post = TRUE;
2102 arg_size += args->post_args_num;
2103
2104 if (body->param.flags.has_rest) { /* TODO: why that? */
2105 body->param.post_start = body->param.rest_start + 1;
2106 }
2107 }
2108
2109 if (args->kw_args) {
2110 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2111 }
2112 else if (args->kw_rest_arg && !optimized_forward) {
2113 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2114 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2115 keyword->rest_start = arg_size++;
2116 body->param.keyword = keyword;
2117 body->param.flags.has_kwrest = TRUE;
2118
2119 static ID anon_kwrest = 0;
2120 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2121 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2122 }
2123 else if (args->no_kwarg) {
2124 body->param.flags.accepts_no_kwarg = TRUE;
2125 }
2126
2127 if (block_id) {
2128 body->param.block_start = arg_size++;
2129 body->param.flags.has_block = TRUE;
2130 iseq_set_use_block(iseq);
2131 }
2132
2133 // Only optimize specifically methods like this: `foo(...)`
2134 if (optimized_forward) {
2135 body->param.flags.use_block = 1;
2136 body->param.flags.forwardable = TRUE;
2137 arg_size = 1;
2138 }
2139
2140 iseq_calc_param_size(iseq);
2141 body->param.size = arg_size;
2142
2143 if (args->pre_init) { /* m_init */
2144 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2145 }
2146 if (args->post_init) { /* p_init */
2147 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2148 }
2149
2150 if (body->type == ISEQ_TYPE_BLOCK) {
2151 if (body->param.flags.has_opt == FALSE &&
2152 body->param.flags.has_post == FALSE &&
2153 body->param.flags.has_rest == FALSE &&
2154 body->param.flags.has_kw == FALSE &&
2155 body->param.flags.has_kwrest == FALSE) {
2156
2157 if (body->param.lead_num == 1 && last_comma == 0) {
2158 /* {|a|} */
2159 body->param.flags.ambiguous_param0 = TRUE;
2160 }
2161 }
2162 }
2163 }
2164
2165 return COMPILE_OK;
2166}
2167
2168static int
2169iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2170{
2171 unsigned int size = tbl ? tbl->size : 0;
2172 unsigned int offset = 0;
2173
2174 if (node_args) {
2175 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2176
2177 // If we have a function that only has `...` as the parameter,
2178 // then its local table should only be `...`
2179 // FIXME: I think this should be fixed in the AST rather than special case here.
2180 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2181 size -= 3;
2182 offset += 3;
2183 }
2184 }
2185
2186 if (size > 0) {
2187 ID *ids = (ID *)ALLOC_N(ID, size);
2188 MEMCPY(ids, tbl->ids + offset, ID, size);
2189 ISEQ_BODY(iseq)->local_table = ids;
2190 }
2191 ISEQ_BODY(iseq)->local_table_size = size;
2192
2193 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2194 return COMPILE_OK;
2195}
2196
2197int
2198rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2199{
2200 int tval, tlit;
2201
2202 if (val == lit) {
2203 return 0;
2204 }
2205 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2206 return val != lit;
2207 }
2208 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2209 return -1;
2210 }
2211 else if (tlit != tval) {
2212 return -1;
2213 }
2214 else if (tlit == T_SYMBOL) {
2215 return val != lit;
2216 }
2217 else if (tlit == T_STRING) {
2218 return rb_str_hash_cmp(lit, val);
2219 }
2220 else if (tlit == T_BIGNUM) {
2221 long x = FIX2LONG(rb_big_cmp(lit, val));
2222
2223 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2224 * There is no need to call rb_fix2int here. */
2225 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2226 return (int)x;
2227 }
2228 else if (tlit == T_FLOAT) {
2229 return rb_float_cmp(lit, val);
2230 }
2231 else if (tlit == T_RATIONAL) {
2232 const struct RRational *rat1 = RRATIONAL(val);
2233 const struct RRational *rat2 = RRATIONAL(lit);
2234 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2235 }
2236 else if (tlit == T_COMPLEX) {
2237 const struct RComplex *comp1 = RCOMPLEX(val);
2238 const struct RComplex *comp2 = RCOMPLEX(lit);
2239 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2240 }
2241 else if (tlit == T_REGEXP) {
2242 return rb_reg_equal(val, lit) ? 0 : -1;
2243 }
2244 else {
2246 }
2247}
2248
2249st_index_t
2250rb_iseq_cdhash_hash(VALUE a)
2251{
2252 switch (OBJ_BUILTIN_TYPE(a)) {
2253 case -1:
2254 case T_SYMBOL:
2255 return (st_index_t)a;
2256 case T_STRING:
2257 return rb_str_hash(a);
2258 case T_BIGNUM:
2259 return FIX2LONG(rb_big_hash(a));
2260 case T_FLOAT:
2261 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2262 case T_RATIONAL:
2263 return rb_rational_hash(a);
2264 case T_COMPLEX:
2265 return rb_complex_hash(a);
2266 case T_REGEXP:
2267 return NUM2LONG(rb_reg_hash(a));
2268 default:
2270 }
2271}
2272
2273static const struct st_hash_type cdhash_type = {
2274 rb_iseq_cdhash_cmp,
2275 rb_iseq_cdhash_hash,
2276};
2277
2279 VALUE hash;
2280 int pos;
2281 int len;
2282};
2283
2284static int
2285cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2286{
2287 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2288 LABEL *lobj = (LABEL *)(val & ~1);
2289 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2290 return ST_CONTINUE;
2291}
2292
2293
2294static inline VALUE
2295get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2296{
2297 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2298}
2299
2300static inline VALUE
2301get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2302{
2303 VALUE val;
2304 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2305 if (tbl) {
2306 if (rb_id_table_lookup(tbl,id,&val)) {
2307 return val;
2308 }
2309 }
2310 else {
2311 tbl = rb_id_table_create(1);
2312 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2313 }
2314 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2315 rb_id_table_insert(tbl,id,val);
2316 return val;
2317}
2318
2319#define BADINSN_DUMP(anchor, list, dest) \
2320 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2321
2322#define BADINSN_ERROR \
2323 (xfree(generated_iseq), \
2324 xfree(insns_info), \
2325 BADINSN_DUMP(anchor, list, NULL), \
2326 COMPILE_ERROR)
2327
2328static int
2329fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2330{
2331 int stack_max = 0, sp = 0, line = 0;
2332 LINK_ELEMENT *list;
2333
2334 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2335 if (IS_LABEL(list)) {
2336 LABEL *lobj = (LABEL *)list;
2337 lobj->set = TRUE;
2338 }
2339 }
2340
2341 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2342 switch (list->type) {
2343 case ISEQ_ELEMENT_INSN:
2344 {
2345 int j, len, insn;
2346 const char *types;
2347 VALUE *operands;
2348 INSN *iobj = (INSN *)list;
2349
2350 /* update sp */
2351 sp = calc_sp_depth(sp, iobj);
2352 if (sp < 0) {
2353 BADINSN_DUMP(anchor, list, NULL);
2354 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2355 "argument stack underflow (%d)", sp);
2356 return -1;
2357 }
2358 if (sp > stack_max) {
2359 stack_max = sp;
2360 }
2361
2362 line = iobj->insn_info.line_no;
2363 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2364 operands = iobj->operands;
2365 insn = iobj->insn_id;
2366 types = insn_op_types(insn);
2367 len = insn_len(insn);
2368
2369 /* operand check */
2370 if (iobj->operand_size != len - 1) {
2371 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2372 BADINSN_DUMP(anchor, list, NULL);
2373 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2374 "operand size miss! (%d for %d)",
2375 iobj->operand_size, len - 1);
2376 return -1;
2377 }
2378
2379 for (j = 0; types[j]; j++) {
2380 if (types[j] == TS_OFFSET) {
2381 /* label(destination position) */
2382 LABEL *lobj = (LABEL *)operands[j];
2383 if (!lobj->set) {
2384 BADINSN_DUMP(anchor, list, NULL);
2385 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2386 "unknown label: "LABEL_FORMAT, lobj->label_no);
2387 return -1;
2388 }
2389 if (lobj->sp == -1) {
2390 lobj->sp = sp;
2391 }
2392 else if (lobj->sp != sp) {
2393 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2394 RSTRING_PTR(rb_iseq_path(iseq)), line,
2395 lobj->label_no, lobj->sp, sp);
2396 }
2397 }
2398 }
2399 break;
2400 }
2401 case ISEQ_ELEMENT_LABEL:
2402 {
2403 LABEL *lobj = (LABEL *)list;
2404 if (lobj->sp == -1) {
2405 lobj->sp = sp;
2406 }
2407 else {
2408 if (lobj->sp != sp) {
2409 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2410 RSTRING_PTR(rb_iseq_path(iseq)), line,
2411 lobj->label_no, lobj->sp, sp);
2412 }
2413 sp = lobj->sp;
2414 }
2415 break;
2416 }
2417 case ISEQ_ELEMENT_TRACE:
2418 {
2419 /* ignore */
2420 break;
2421 }
2422 case ISEQ_ELEMENT_ADJUST:
2423 {
2424 ADJUST *adjust = (ADJUST *)list;
2425 int orig_sp = sp;
2426
2427 sp = adjust->label ? adjust->label->sp : 0;
2428 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2429 BADINSN_DUMP(anchor, list, NULL);
2430 COMPILE_ERROR(iseq, adjust->line_no,
2431 "iseq_set_sequence: adjust bug %d < %d",
2432 orig_sp, sp);
2433 return -1;
2434 }
2435 break;
2436 }
2437 default:
2438 BADINSN_DUMP(anchor, list, NULL);
2439 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2440 return -1;
2441 }
2442 }
2443 return stack_max;
2444}
2445
2446static int
2447add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2448 int insns_info_index, int code_index, const INSN *iobj)
2449{
2450 if (insns_info_index == 0 ||
2451 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2452#ifdef USE_ISEQ_NODE_ID
2453 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2454#endif
2455 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2456 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2457#ifdef USE_ISEQ_NODE_ID
2458 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2459#endif
2460 insns_info[insns_info_index].events = iobj->insn_info.events;
2461 positions[insns_info_index] = code_index;
2462 return TRUE;
2463 }
2464 return FALSE;
2465}
2466
2467static int
2468add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2469 int insns_info_index, int code_index, const ADJUST *adjust)
2470{
2471 insns_info[insns_info_index].line_no = adjust->line_no;
2472 insns_info[insns_info_index].node_id = -1;
2473 insns_info[insns_info_index].events = 0;
2474 positions[insns_info_index] = code_index;
2475 return TRUE;
2476}
2477
2478static ID *
2479array_to_idlist(VALUE arr)
2480{
2482 long size = RARRAY_LEN(arr);
2483 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2484 for (int i = 0; i < size; i++) {
2485 VALUE sym = RARRAY_AREF(arr, i);
2486 ids[i] = SYM2ID(sym);
2487 }
2488 ids[size] = 0;
2489 return ids;
2490}
2491
2492static VALUE
2493idlist_to_array(const ID *ids)
2494{
2495 VALUE arr = rb_ary_new();
2496 while (*ids) {
2497 rb_ary_push(arr, ID2SYM(*ids++));
2498 }
2499 return arr;
2500}
2501
2505static int
2506iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2507{
2508 struct iseq_insn_info_entry *insns_info;
2509 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2510 unsigned int *positions;
2511 LINK_ELEMENT *list;
2512 VALUE *generated_iseq;
2513 rb_event_flag_t events = 0;
2514 long data = 0;
2515
2516 int insn_num, code_index, insns_info_index, sp = 0;
2517 int stack_max = fix_sp_depth(iseq, anchor);
2518
2519 if (stack_max < 0) return COMPILE_NG;
2520
2521 /* fix label position */
2522 insn_num = code_index = 0;
2523 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2524 switch (list->type) {
2525 case ISEQ_ELEMENT_INSN:
2526 {
2527 INSN *iobj = (INSN *)list;
2528 /* update sp */
2529 sp = calc_sp_depth(sp, iobj);
2530 insn_num++;
2531 events = iobj->insn_info.events |= events;
2532 if (ISEQ_COVERAGE(iseq)) {
2533 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2534 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2535 int line = iobj->insn_info.line_no - 1;
2536 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2537 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2538 }
2539 }
2540 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2541 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2542 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2543 }
2544 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2545 }
2546 }
2547 code_index += insn_data_length(iobj);
2548 events = 0;
2549 data = 0;
2550 break;
2551 }
2552 case ISEQ_ELEMENT_LABEL:
2553 {
2554 LABEL *lobj = (LABEL *)list;
2555 lobj->position = code_index;
2556 if (lobj->sp != sp) {
2557 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2558 RSTRING_PTR(rb_iseq_path(iseq)),
2559 lobj->label_no, lobj->sp, sp);
2560 }
2561 sp = lobj->sp;
2562 break;
2563 }
2564 case ISEQ_ELEMENT_TRACE:
2565 {
2566 TRACE *trace = (TRACE *)list;
2567 events |= trace->event;
2568 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2569 break;
2570 }
2571 case ISEQ_ELEMENT_ADJUST:
2572 {
2573 ADJUST *adjust = (ADJUST *)list;
2574 if (adjust->line_no != -1) {
2575 int orig_sp = sp;
2576 sp = adjust->label ? adjust->label->sp : 0;
2577 if (orig_sp - sp > 0) {
2578 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2579 code_index++; /* insn */
2580 insn_num++;
2581 }
2582 }
2583 break;
2584 }
2585 default: break;
2586 }
2587 }
2588
2589 /* make instruction sequence */
2590 generated_iseq = ALLOC_N(VALUE, code_index);
2591 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2592 positions = ALLOC_N(unsigned int, insn_num);
2593 if (ISEQ_IS_SIZE(body)) {
2594 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2595 }
2596 else {
2597 body->is_entries = NULL;
2598 }
2599 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2600 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2601
2602 // Calculate the bitmask buffer size.
2603 // Round the generated_iseq size up to the nearest multiple
2604 // of the number of bits in an unsigned long.
2605
2606 // Allocate enough room for the bitmask list
2607 iseq_bits_t * mark_offset_bits;
2608 int code_size = code_index;
2609
2610 iseq_bits_t tmp[1] = {0};
2611 bool needs_bitmap = false;
2612
2613 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2614 mark_offset_bits = tmp;
2615 }
2616 else {
2617 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2618 }
2619
2620 list = FIRST_ELEMENT(anchor);
2621 insns_info_index = code_index = sp = 0;
2622
2623 while (list) {
2624 switch (list->type) {
2625 case ISEQ_ELEMENT_INSN:
2626 {
2627 int j, len, insn;
2628 const char *types;
2629 VALUE *operands;
2630 INSN *iobj = (INSN *)list;
2631
2632 /* update sp */
2633 sp = calc_sp_depth(sp, iobj);
2634 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2635 operands = iobj->operands;
2636 insn = iobj->insn_id;
2637 generated_iseq[code_index] = insn;
2638 types = insn_op_types(insn);
2639 len = insn_len(insn);
2640
2641 for (j = 0; types[j]; j++) {
2642 char type = types[j];
2643
2644 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2645 switch (type) {
2646 case TS_OFFSET:
2647 {
2648 /* label(destination position) */
2649 LABEL *lobj = (LABEL *)operands[j];
2650 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2651 break;
2652 }
2653 case TS_CDHASH:
2654 {
2655 VALUE map = operands[j];
2656 struct cdhash_set_label_struct data;
2657 data.hash = map;
2658 data.pos = code_index;
2659 data.len = len;
2660 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2661
2662 rb_hash_rehash(map);
2663 freeze_hide_obj(map);
2664 generated_iseq[code_index + 1 + j] = map;
2665 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2666 RB_OBJ_WRITTEN(iseq, Qundef, map);
2667 needs_bitmap = true;
2668 break;
2669 }
2670 case TS_LINDEX:
2671 case TS_NUM: /* ulong */
2672 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2673 break;
2674 case TS_ISEQ: /* iseq */
2675 case TS_VALUE: /* VALUE */
2676 {
2677 VALUE v = operands[j];
2678 generated_iseq[code_index + 1 + j] = v;
2679 /* to mark ruby object */
2680 if (!SPECIAL_CONST_P(v)) {
2681 RB_OBJ_WRITTEN(iseq, Qundef, v);
2682 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2683 needs_bitmap = true;
2684 }
2685 break;
2686 }
2687 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2688 case TS_IC: /* inline cache: constants */
2689 {
2690 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2691 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2692 if (UNLIKELY(ic_index >= body->ic_size)) {
2693 BADINSN_DUMP(anchor, &iobj->link, 0);
2694 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2695 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2696 ic_index, ISEQ_IS_SIZE(body));
2697 }
2698
2699 ic->segments = array_to_idlist(operands[j]);
2700
2701 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2702 }
2703 break;
2704 case TS_IVC: /* inline ivar cache */
2705 {
2706 unsigned int ic_index = FIX2UINT(operands[j]);
2707
2708 IVC cache = ((IVC)&body->is_entries[ic_index]);
2709
2710 if (insn == BIN(setinstancevariable)) {
2711 cache->iv_set_name = SYM2ID(operands[j - 1]);
2712 }
2713 else {
2714 cache->iv_set_name = 0;
2715 }
2716
2717 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2718 }
2719 case TS_ISE: /* inline storage entry: `once` insn */
2720 case TS_ICVARC: /* inline cvar cache */
2721 {
2722 unsigned int ic_index = FIX2UINT(operands[j]);
2723 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2724 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2725 BADINSN_DUMP(anchor, &iobj->link, 0);
2726 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2727 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2728 ic_index, ISEQ_IS_SIZE(body));
2729 }
2730 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2731
2732 break;
2733 }
2734 case TS_CALLDATA:
2735 {
2736 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2737 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2738 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2739 cd->ci = source_ci;
2740 cd->cc = vm_cc_empty();
2741 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2742 break;
2743 }
2744 case TS_ID: /* ID */
2745 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2746 break;
2747 case TS_FUNCPTR:
2748 generated_iseq[code_index + 1 + j] = operands[j];
2749 break;
2750 case TS_BUILTIN:
2751 generated_iseq[code_index + 1 + j] = operands[j];
2752 break;
2753 default:
2754 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2755 "unknown operand type: %c", type);
2756 return COMPILE_NG;
2757 }
2758 }
2759 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2760 code_index += len;
2761 break;
2762 }
2763 case ISEQ_ELEMENT_LABEL:
2764 {
2765 LABEL *lobj = (LABEL *)list;
2766 if (lobj->sp != sp) {
2767 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2768 RSTRING_PTR(rb_iseq_path(iseq)),
2769 lobj->label_no, lobj->sp, sp);
2770 }
2771 sp = lobj->sp;
2772 break;
2773 }
2774 case ISEQ_ELEMENT_ADJUST:
2775 {
2776 ADJUST *adjust = (ADJUST *)list;
2777 int orig_sp = sp;
2778
2779 if (adjust->label) {
2780 sp = adjust->label->sp;
2781 }
2782 else {
2783 sp = 0;
2784 }
2785
2786 if (adjust->line_no != -1) {
2787 const int diff = orig_sp - sp;
2788 if (diff > 0) {
2789 if (insns_info_index == 0) {
2790 COMPILE_ERROR(iseq, adjust->line_no,
2791 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2792 }
2793 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2794 }
2795 if (diff > 1) {
2796 generated_iseq[code_index++] = BIN(adjuststack);
2797 generated_iseq[code_index++] = orig_sp - sp;
2798 }
2799 else if (diff == 1) {
2800 generated_iseq[code_index++] = BIN(pop);
2801 }
2802 else if (diff < 0) {
2803 int label_no = adjust->label ? adjust->label->label_no : -1;
2804 xfree(generated_iseq);
2805 xfree(insns_info);
2806 xfree(positions);
2807 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2808 xfree(mark_offset_bits);
2809 }
2810 debug_list(anchor, list);
2811 COMPILE_ERROR(iseq, adjust->line_no,
2812 "iseq_set_sequence: adjust bug to %d %d < %d",
2813 label_no, orig_sp, sp);
2814 return COMPILE_NG;
2815 }
2816 }
2817 break;
2818 }
2819 default:
2820 /* ignore */
2821 break;
2822 }
2823 list = list->next;
2824 }
2825
2826 body->iseq_encoded = (void *)generated_iseq;
2827 body->iseq_size = code_index;
2828 body->stack_max = stack_max;
2829
2830 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2831 body->mark_bits.single = mark_offset_bits[0];
2832 }
2833 else {
2834 if (needs_bitmap) {
2835 body->mark_bits.list = mark_offset_bits;
2836 }
2837 else {
2838 body->mark_bits.list = 0;
2839 ruby_xfree(mark_offset_bits);
2840 }
2841 }
2842
2843 /* get rid of memory leak when REALLOC failed */
2844 body->insns_info.body = insns_info;
2845 body->insns_info.positions = positions;
2846
2847 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2848 body->insns_info.body = insns_info;
2849 REALLOC_N(positions, unsigned int, insns_info_index);
2850 body->insns_info.positions = positions;
2851 body->insns_info.size = insns_info_index;
2852
2853 return COMPILE_OK;
2854}
2855
2856static int
2857label_get_position(LABEL *lobj)
2858{
2859 return lobj->position;
2860}
2861
2862static int
2863label_get_sp(LABEL *lobj)
2864{
2865 return lobj->sp;
2866}
2867
2868static int
2869iseq_set_exception_table(rb_iseq_t *iseq)
2870{
2871 const VALUE *tptr, *ptr;
2872 unsigned int tlen, i;
2873 struct iseq_catch_table_entry *entry;
2874
2875 ISEQ_BODY(iseq)->catch_table = NULL;
2876
2877 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2878 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2879 tlen = (int)RARRAY_LEN(catch_table_ary);
2880 tptr = RARRAY_CONST_PTR(catch_table_ary);
2881
2882 if (tlen > 0) {
2883 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2884 table->size = tlen;
2885
2886 for (i = 0; i < table->size; i++) {
2887 int pos;
2888 ptr = RARRAY_CONST_PTR(tptr[i]);
2889 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2890 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2891 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2892 RUBY_ASSERT(pos >= 0);
2893 entry->start = (unsigned int)pos;
2894 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2895 RUBY_ASSERT(pos >= 0);
2896 entry->end = (unsigned int)pos;
2897 entry->iseq = (rb_iseq_t *)ptr[3];
2898 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2899
2900 /* stack depth */
2901 if (ptr[4]) {
2902 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2903 entry->cont = label_get_position(lobj);
2904 entry->sp = label_get_sp(lobj);
2905
2906 /* TODO: Dirty Hack! Fix me */
2907 if (entry->type == CATCH_TYPE_RESCUE ||
2908 entry->type == CATCH_TYPE_BREAK ||
2909 entry->type == CATCH_TYPE_NEXT) {
2910 RUBY_ASSERT(entry->sp > 0);
2911 entry->sp--;
2912 }
2913 }
2914 else {
2915 entry->cont = 0;
2916 }
2917 }
2918 ISEQ_BODY(iseq)->catch_table = table;
2919 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2920 }
2921
2922 RB_GC_GUARD(catch_table_ary);
2923
2924 return COMPILE_OK;
2925}
2926
2927/*
2928 * set optional argument table
2929 * def foo(a, b=expr1, c=expr2)
2930 * =>
2931 * b:
2932 * expr1
2933 * c:
2934 * expr2
2935 */
2936static int
2937iseq_set_optargs_table(rb_iseq_t *iseq)
2938{
2939 int i;
2940 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2941
2942 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2943 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2944 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2945 }
2946 }
2947 return COMPILE_OK;
2948}
2949
2950static LINK_ELEMENT *
2951get_destination_insn(INSN *iobj)
2952{
2953 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2954 LINK_ELEMENT *list;
2955 rb_event_flag_t events = 0;
2956
2957 list = lobj->link.next;
2958 while (list) {
2959 switch (list->type) {
2960 case ISEQ_ELEMENT_INSN:
2961 case ISEQ_ELEMENT_ADJUST:
2962 goto found;
2963 case ISEQ_ELEMENT_LABEL:
2964 /* ignore */
2965 break;
2966 case ISEQ_ELEMENT_TRACE:
2967 {
2968 TRACE *trace = (TRACE *)list;
2969 events |= trace->event;
2970 }
2971 break;
2972 default: break;
2973 }
2974 list = list->next;
2975 }
2976 found:
2977 if (list && IS_INSN(list)) {
2978 INSN *iobj = (INSN *)list;
2979 iobj->insn_info.events |= events;
2980 }
2981 return list;
2982}
2983
2984static LINK_ELEMENT *
2985get_next_insn(INSN *iobj)
2986{
2987 LINK_ELEMENT *list = iobj->link.next;
2988
2989 while (list) {
2990 if (IS_INSN(list) || IS_ADJUST(list)) {
2991 return list;
2992 }
2993 list = list->next;
2994 }
2995 return 0;
2996}
2997
2998static LINK_ELEMENT *
2999get_prev_insn(INSN *iobj)
3000{
3001 LINK_ELEMENT *list = iobj->link.prev;
3002
3003 while (list) {
3004 if (IS_INSN(list) || IS_ADJUST(list)) {
3005 return list;
3006 }
3007 list = list->prev;
3008 }
3009 return 0;
3010}
3011
3012static void
3013unref_destination(INSN *iobj, int pos)
3014{
3015 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3016 --lobj->refcnt;
3017 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3018}
3019
3020static bool
3021replace_destination(INSN *dobj, INSN *nobj)
3022{
3023 VALUE n = OPERAND_AT(nobj, 0);
3024 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3025 LABEL *nl = (LABEL *)n;
3026 if (dl == nl) return false;
3027 --dl->refcnt;
3028 ++nl->refcnt;
3029 OPERAND_AT(dobj, 0) = n;
3030 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3031 return true;
3032}
3033
3034static LABEL*
3035find_destination(INSN *i)
3036{
3037 int pos, len = insn_len(i->insn_id);
3038 for (pos = 0; pos < len; ++pos) {
3039 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3040 return (LABEL *)OPERAND_AT(i, pos);
3041 }
3042 }
3043 return 0;
3044}
3045
3046static int
3047remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3048{
3049 LINK_ELEMENT *first = i, *end;
3050 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3051
3052 if (!i) return 0;
3053 unref_counts = ALLOCA_N(int, nlabels);
3054 MEMZERO(unref_counts, int, nlabels);
3055 end = i;
3056 do {
3057 LABEL *lab;
3058 if (IS_INSN(i)) {
3059 if (IS_INSN_ID(i, leave)) {
3060 end = i;
3061 break;
3062 }
3063 else if ((lab = find_destination((INSN *)i)) != 0) {
3064 unref_counts[lab->label_no]++;
3065 }
3066 }
3067 else if (IS_LABEL(i)) {
3068 lab = (LABEL *)i;
3069 if (lab->unremovable) return 0;
3070 if (lab->refcnt > unref_counts[lab->label_no]) {
3071 if (i == first) return 0;
3072 break;
3073 }
3074 continue;
3075 }
3076 else if (IS_TRACE(i)) {
3077 /* do nothing */
3078 }
3079 else if (IS_ADJUST(i)) {
3080 return 0;
3081 }
3082 end = i;
3083 } while ((i = i->next) != 0);
3084 i = first;
3085 do {
3086 if (IS_INSN(i)) {
3087 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3088 VALUE insn = INSN_OF(i);
3089 int pos, len = insn_len(insn);
3090 for (pos = 0; pos < len; ++pos) {
3091 switch (insn_op_types(insn)[pos]) {
3092 case TS_OFFSET:
3093 unref_destination((INSN *)i, pos);
3094 break;
3095 case TS_CALLDATA:
3096 --(body->ci_size);
3097 break;
3098 }
3099 }
3100 }
3101 ELEM_REMOVE(i);
3102 } while ((i != end) && (i = i->next) != 0);
3103 return 1;
3104}
3105
3106static int
3107iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3108{
3109 switch (OPERAND_AT(iobj, 0)) {
3110 case INT2FIX(0): /* empty array */
3111 ELEM_REMOVE(&iobj->link);
3112 return TRUE;
3113 case INT2FIX(1): /* single element array */
3114 ELEM_REMOVE(&iobj->link);
3115 return FALSE;
3116 default:
3117 iobj->insn_id = BIN(adjuststack);
3118 return TRUE;
3119 }
3120}
3121
3122static int
3123is_frozen_putstring(INSN *insn, VALUE *op)
3124{
3125 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3126 *op = OPERAND_AT(insn, 0);
3127 return 1;
3128 }
3129 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3130 *op = OPERAND_AT(insn, 0);
3131 return RB_TYPE_P(*op, T_STRING);
3132 }
3133 return 0;
3134}
3135
3136static int
3137optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3138{
3139 /*
3140 * putobject obj
3141 * dup
3142 * checktype T_XXX
3143 * branchif l1
3144 * l2:
3145 * ...
3146 * l1:
3147 *
3148 * => obj is a T_XXX
3149 *
3150 * putobject obj (T_XXX)
3151 * jump L1
3152 * L1:
3153 *
3154 * => obj is not a T_XXX
3155 *
3156 * putobject obj (T_XXX)
3157 * jump L2
3158 * L2:
3159 */
3160 int line, node_id;
3161 INSN *niobj, *ciobj, *dup = 0;
3162 LABEL *dest = 0;
3163 VALUE type;
3164
3165 switch (INSN_OF(iobj)) {
3166 case BIN(putstring):
3167 case BIN(putchilledstring):
3169 break;
3170 case BIN(putnil):
3171 type = INT2FIX(T_NIL);
3172 break;
3173 case BIN(putobject):
3174 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3175 break;
3176 default: return FALSE;
3177 }
3178
3179 ciobj = (INSN *)get_next_insn(iobj);
3180 if (IS_INSN_ID(ciobj, jump)) {
3181 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3182 }
3183 if (IS_INSN_ID(ciobj, dup)) {
3184 ciobj = (INSN *)get_next_insn(dup = ciobj);
3185 }
3186 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3187 niobj = (INSN *)get_next_insn(ciobj);
3188 if (!niobj) {
3189 /* TODO: putobject true/false */
3190 return FALSE;
3191 }
3192 switch (INSN_OF(niobj)) {
3193 case BIN(branchif):
3194 if (OPERAND_AT(ciobj, 0) == type) {
3195 dest = (LABEL *)OPERAND_AT(niobj, 0);
3196 }
3197 break;
3198 case BIN(branchunless):
3199 if (OPERAND_AT(ciobj, 0) != type) {
3200 dest = (LABEL *)OPERAND_AT(niobj, 0);
3201 }
3202 break;
3203 default:
3204 return FALSE;
3205 }
3206 line = ciobj->insn_info.line_no;
3207 node_id = ciobj->insn_info.node_id;
3208 if (!dest) {
3209 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3210 dest = (LABEL *)niobj->link.next; /* reuse label */
3211 }
3212 else {
3213 dest = NEW_LABEL(line);
3214 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3215 }
3216 }
3217 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3218 LABEL_REF(dest);
3219 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3220 return TRUE;
3221}
3222
3223static const struct rb_callinfo *
3224ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3225{
3226 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3227 vm_ci_flag(ci) | add,
3228 vm_ci_argc(ci),
3229 vm_ci_kwarg(ci));
3230 RB_OBJ_WRITTEN(iseq, ci, nci);
3231 return nci;
3232}
3233
3234static const struct rb_callinfo *
3235ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3236{
3237 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3238 vm_ci_flag(ci),
3239 argc,
3240 vm_ci_kwarg(ci));
3241 RB_OBJ_WRITTEN(iseq, ci, nci);
3242 return nci;
3243}
3244
3245#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3246
3247static int
3248iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3249{
3250 INSN *const iobj = (INSN *)list;
3251
3252 again:
3253 optimize_checktype(iseq, iobj);
3254
3255 if (IS_INSN_ID(iobj, jump)) {
3256 INSN *niobj, *diobj, *piobj;
3257 diobj = (INSN *)get_destination_insn(iobj);
3258 niobj = (INSN *)get_next_insn(iobj);
3259
3260 if (diobj == niobj) {
3261 /*
3262 * jump LABEL
3263 * LABEL:
3264 * =>
3265 * LABEL:
3266 */
3267 unref_destination(iobj, 0);
3268 ELEM_REMOVE(&iobj->link);
3269 return COMPILE_OK;
3270 }
3271 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3272 IS_INSN_ID(diobj, jump) &&
3273 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3274 diobj->insn_info.events == 0) {
3275 /*
3276 * useless jump elimination:
3277 * jump LABEL1
3278 * ...
3279 * LABEL1:
3280 * jump LABEL2
3281 *
3282 * => in this case, first jump instruction should jump to
3283 * LABEL2 directly
3284 */
3285 if (replace_destination(iobj, diobj)) {
3286 remove_unreachable_chunk(iseq, iobj->link.next);
3287 goto again;
3288 }
3289 }
3290 else if (IS_INSN_ID(diobj, leave)) {
3291 /*
3292 * jump LABEL
3293 * ...
3294 * LABEL:
3295 * leave
3296 * =>
3297 * leave
3298 * ...
3299 * LABEL:
3300 * leave
3301 */
3302 /* replace */
3303 unref_destination(iobj, 0);
3304 iobj->insn_id = BIN(leave);
3305 iobj->operand_size = 0;
3306 iobj->insn_info = diobj->insn_info;
3307 goto again;
3308 }
3309 else if (IS_INSN(iobj->link.prev) &&
3310 (piobj = (INSN *)iobj->link.prev) &&
3311 (IS_INSN_ID(piobj, branchif) ||
3312 IS_INSN_ID(piobj, branchunless))) {
3313 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3314 if (niobj == pdiobj) {
3315 int refcnt = IS_LABEL(piobj->link.next) ?
3316 ((LABEL *)piobj->link.next)->refcnt : 0;
3317 /*
3318 * useless jump elimination (if/unless destination):
3319 * if L1
3320 * jump L2
3321 * L1:
3322 * ...
3323 * L2:
3324 *
3325 * ==>
3326 * unless L2
3327 * L1:
3328 * ...
3329 * L2:
3330 */
3331 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3332 ? BIN(branchunless) : BIN(branchif);
3333 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3334 ELEM_REMOVE(&iobj->link);
3335 }
3336 else {
3337 /* TODO: replace other branch destinations too */
3338 }
3339 return COMPILE_OK;
3340 }
3341 else if (diobj == pdiobj) {
3342 /*
3343 * useless jump elimination (if/unless before jump):
3344 * L1:
3345 * ...
3346 * if L1
3347 * jump L1
3348 *
3349 * ==>
3350 * L1:
3351 * ...
3352 * pop
3353 * jump L1
3354 */
3355 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3356 ELEM_REPLACE(&piobj->link, &popiobj->link);
3357 }
3358 }
3359 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3360 goto again;
3361 }
3362 }
3363
3364 /*
3365 * putstring "beg"
3366 * putstring "end"
3367 * newrange excl
3368 *
3369 * ==>
3370 *
3371 * putobject "beg".."end"
3372 */
3373 if (IS_INSN_ID(iobj, newrange)) {
3374 INSN *const range = iobj;
3375 INSN *beg, *end;
3376 VALUE str_beg, str_end;
3377
3378 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3379 is_frozen_putstring(end, &str_end) &&
3380 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3381 is_frozen_putstring(beg, &str_beg)) {
3382 int excl = FIX2INT(OPERAND_AT(range, 0));
3383 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3384
3385 ELEM_REMOVE(&beg->link);
3386 ELEM_REMOVE(&end->link);
3387 range->insn_id = BIN(putobject);
3388 OPERAND_AT(range, 0) = lit_range;
3389 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3390 }
3391 }
3392
3393 if (IS_INSN_ID(iobj, leave)) {
3394 remove_unreachable_chunk(iseq, iobj->link.next);
3395 }
3396
3397 /*
3398 * ...
3399 * duparray [...]
3400 * concatarray | concattoarray
3401 * =>
3402 * ...
3403 * putobject [...]
3404 * concatarray | concattoarray
3405 */
3406 if (IS_INSN_ID(iobj, duparray)) {
3407 LINK_ELEMENT *next = iobj->link.next;
3408 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3409 iobj->insn_id = BIN(putobject);
3410 }
3411 }
3412
3413 /*
3414 * duparray [...]
3415 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3416 * =>
3417 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3418 */
3419 if (IS_INSN_ID(iobj, duparray)) {
3420 LINK_ELEMENT *next = iobj->link.next;
3421 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3422 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3423 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3424
3425 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3426 VALUE ary = iobj->operands[0];
3428
3429 iobj->insn_id = BIN(opt_ary_freeze);
3430 iobj->operand_size = 2;
3431 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3432 iobj->operands[0] = ary;
3433 iobj->operands[1] = (VALUE)ci;
3434 ELEM_REMOVE(next);
3435 }
3436 }
3437 }
3438
3439 /*
3440 * duphash {...}
3441 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3442 * =>
3443 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3444 */
3445 if (IS_INSN_ID(iobj, duphash)) {
3446 LINK_ELEMENT *next = iobj->link.next;
3447 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3448 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3449 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3450
3451 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3452 VALUE hash = iobj->operands[0];
3453 rb_obj_reveal(hash, rb_cHash);
3454
3455 iobj->insn_id = BIN(opt_hash_freeze);
3456 iobj->operand_size = 2;
3457 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3458 iobj->operands[0] = hash;
3459 iobj->operands[1] = (VALUE)ci;
3460 ELEM_REMOVE(next);
3461 }
3462 }
3463 }
3464
3465 /*
3466 * newarray 0
3467 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3468 * =>
3469 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3470 */
3471 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3472 LINK_ELEMENT *next = iobj->link.next;
3473 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3474 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3475 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3476
3477 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3478 iobj->insn_id = BIN(opt_ary_freeze);
3479 iobj->operand_size = 2;
3480 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3481 iobj->operands[0] = rb_cArray_empty_frozen;
3482 iobj->operands[1] = (VALUE)ci;
3483 ELEM_REMOVE(next);
3484 }
3485 }
3486 }
3487
3488 /*
3489 * newhash 0
3490 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3491 * =>
3492 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3493 */
3494 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3495 LINK_ELEMENT *next = iobj->link.next;
3496 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3497 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3498 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3499
3500 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3501 iobj->insn_id = BIN(opt_hash_freeze);
3502 iobj->operand_size = 2;
3503 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3504 iobj->operands[0] = rb_cHash_empty_frozen;
3505 iobj->operands[1] = (VALUE)ci;
3506 ELEM_REMOVE(next);
3507 }
3508 }
3509 }
3510
3511 if (IS_INSN_ID(iobj, branchif) ||
3512 IS_INSN_ID(iobj, branchnil) ||
3513 IS_INSN_ID(iobj, branchunless)) {
3514 /*
3515 * if L1
3516 * ...
3517 * L1:
3518 * jump L2
3519 * =>
3520 * if L2
3521 */
3522 INSN *nobj = (INSN *)get_destination_insn(iobj);
3523
3524 /* This is super nasty hack!!!
3525 *
3526 * This jump-jump optimization may ignore event flags of the jump
3527 * instruction being skipped. Actually, Line 2 TracePoint event
3528 * is never fired in the following code:
3529 *
3530 * 1: raise if 1 == 2
3531 * 2: while true
3532 * 3: break
3533 * 4: end
3534 *
3535 * This is critical for coverage measurement. [Bug #15980]
3536 *
3537 * This is a stopgap measure: stop the jump-jump optimization if
3538 * coverage measurement is enabled and if the skipped instruction
3539 * has any event flag.
3540 *
3541 * Note that, still, TracePoint Line event does not occur on Line 2.
3542 * This should be fixed in future.
3543 */
3544 int stop_optimization =
3545 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3546 nobj->link.type == ISEQ_ELEMENT_INSN &&
3547 nobj->insn_info.events;
3548 if (!stop_optimization) {
3549 INSN *pobj = (INSN *)iobj->link.prev;
3550 int prev_dup = 0;
3551 if (pobj) {
3552 if (!IS_INSN(&pobj->link))
3553 pobj = 0;
3554 else if (IS_INSN_ID(pobj, dup))
3555 prev_dup = 1;
3556 }
3557
3558 for (;;) {
3559 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3560 if (!replace_destination(iobj, nobj)) break;
3561 }
3562 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3563 !!(nobj = (INSN *)nobj->link.next) &&
3564 /* basic blocks, with no labels in the middle */
3565 nobj->insn_id == iobj->insn_id) {
3566 /*
3567 * dup
3568 * if L1
3569 * ...
3570 * L1:
3571 * dup
3572 * if L2
3573 * =>
3574 * dup
3575 * if L2
3576 * ...
3577 * L1:
3578 * dup
3579 * if L2
3580 */
3581 if (!replace_destination(iobj, nobj)) break;
3582 }
3583 else if (pobj) {
3584 /*
3585 * putnil
3586 * if L1
3587 * =>
3588 * # nothing
3589 *
3590 * putobject true
3591 * if L1
3592 * =>
3593 * jump L1
3594 *
3595 * putstring ".."
3596 * if L1
3597 * =>
3598 * jump L1
3599 *
3600 * putstring ".."
3601 * dup
3602 * if L1
3603 * =>
3604 * putstring ".."
3605 * jump L1
3606 *
3607 */
3608 int cond;
3609 if (prev_dup && IS_INSN(pobj->link.prev)) {
3610 pobj = (INSN *)pobj->link.prev;
3611 }
3612 if (IS_INSN_ID(pobj, putobject)) {
3613 cond = (IS_INSN_ID(iobj, branchif) ?
3614 OPERAND_AT(pobj, 0) != Qfalse :
3615 IS_INSN_ID(iobj, branchunless) ?
3616 OPERAND_AT(pobj, 0) == Qfalse :
3617 FALSE);
3618 }
3619 else if (IS_INSN_ID(pobj, putstring) ||
3620 IS_INSN_ID(pobj, duparray) ||
3621 IS_INSN_ID(pobj, newarray)) {
3622 cond = IS_INSN_ID(iobj, branchif);
3623 }
3624 else if (IS_INSN_ID(pobj, putnil)) {
3625 cond = !IS_INSN_ID(iobj, branchif);
3626 }
3627 else break;
3628 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3629 ELEM_REMOVE(iobj->link.prev);
3630 }
3631 else if (!iseq_pop_newarray(iseq, pobj)) {
3632 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3633 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3634 }
3635 if (cond) {
3636 if (prev_dup) {
3637 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3638 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3639 }
3640 iobj->insn_id = BIN(jump);
3641 goto again;
3642 }
3643 else {
3644 unref_destination(iobj, 0);
3645 ELEM_REMOVE(&iobj->link);
3646 }
3647 break;
3648 }
3649 else break;
3650 nobj = (INSN *)get_destination_insn(nobj);
3651 }
3652 }
3653 }
3654
3655 if (IS_INSN_ID(iobj, pop)) {
3656 /*
3657 * putself / putnil / putobject obj / putstring "..."
3658 * pop
3659 * =>
3660 * # do nothing
3661 */
3662 LINK_ELEMENT *prev = iobj->link.prev;
3663 if (IS_INSN(prev)) {
3664 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3665 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3666 previ == BIN(putself) || previ == BIN(putstring) ||
3667 previ == BIN(putchilledstring) ||
3668 previ == BIN(dup) ||
3669 previ == BIN(getlocal) ||
3670 previ == BIN(getblockparam) ||
3671 previ == BIN(getblockparamproxy) ||
3672 previ == BIN(getinstancevariable) ||
3673 previ == BIN(duparray)) {
3674 /* just push operand or static value and pop soon, no
3675 * side effects */
3676 ELEM_REMOVE(prev);
3677 ELEM_REMOVE(&iobj->link);
3678 }
3679 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3680 ELEM_REMOVE(&iobj->link);
3681 }
3682 else if (previ == BIN(concatarray)) {
3683 INSN *piobj = (INSN *)prev;
3684 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3685 INSN_OF(piobj) = BIN(pop);
3686 }
3687 else if (previ == BIN(concatstrings)) {
3688 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3689 ELEM_REMOVE(prev);
3690 }
3691 else {
3692 ELEM_REMOVE(&iobj->link);
3693 INSN_OF(prev) = BIN(adjuststack);
3694 }
3695 }
3696 }
3697 }
3698
3699 if (IS_INSN_ID(iobj, newarray) ||
3700 IS_INSN_ID(iobj, duparray) ||
3701 IS_INSN_ID(iobj, concatarray) ||
3702 IS_INSN_ID(iobj, splatarray) ||
3703 0) {
3704 /*
3705 * newarray N
3706 * splatarray
3707 * =>
3708 * newarray N
3709 * newarray always puts an array
3710 */
3711 LINK_ELEMENT *next = iobj->link.next;
3712 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3713 /* remove splatarray following always-array insn */
3714 ELEM_REMOVE(next);
3715 }
3716 }
3717
3718 if (IS_INSN_ID(iobj, newarray)) {
3719 LINK_ELEMENT *next = iobj->link.next;
3720 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3721 OPERAND_AT(next, 1) == INT2FIX(0)) {
3722 VALUE op1, op2;
3723 op1 = OPERAND_AT(iobj, 0);
3724 op2 = OPERAND_AT(next, 0);
3725 ELEM_REMOVE(next);
3726
3727 if (op1 == op2) {
3728 /*
3729 * newarray 2
3730 * expandarray 2, 0
3731 * =>
3732 * swap
3733 */
3734 if (op1 == INT2FIX(2)) {
3735 INSN_OF(iobj) = BIN(swap);
3736 iobj->operand_size = 0;
3737 }
3738 /*
3739 * newarray X
3740 * expandarray X, 0
3741 * =>
3742 * opt_reverse X
3743 */
3744 else {
3745 INSN_OF(iobj) = BIN(opt_reverse);
3746 }
3747 }
3748 else {
3749 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3750 INSN_OF(iobj) = BIN(opt_reverse);
3751 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3752
3753 if (op1 > op2) {
3754 /* X > Y
3755 * newarray X
3756 * expandarray Y, 0
3757 * =>
3758 * pop * (Y-X)
3759 * opt_reverse Y
3760 */
3761 for (; diff > 0; diff--) {
3762 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3763 }
3764 }
3765 else { /* (op1 < op2) */
3766 /* X < Y
3767 * newarray X
3768 * expandarray Y, 0
3769 * =>
3770 * putnil * (Y-X)
3771 * opt_reverse Y
3772 */
3773 for (; diff < 0; diff++) {
3774 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3775 }
3776 }
3777 }
3778 }
3779 }
3780
3781 if (IS_INSN_ID(iobj, duparray)) {
3782 LINK_ELEMENT *next = iobj->link.next;
3783 /*
3784 * duparray obj
3785 * expandarray X, 0
3786 * =>
3787 * putobject obj
3788 * expandarray X, 0
3789 */
3790 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3791 INSN_OF(iobj) = BIN(putobject);
3792 }
3793 }
3794
3795 if (IS_INSN_ID(iobj, anytostring)) {
3796 LINK_ELEMENT *next = iobj->link.next;
3797 /*
3798 * anytostring
3799 * concatstrings 1
3800 * =>
3801 * anytostring
3802 */
3803 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3804 OPERAND_AT(next, 0) == INT2FIX(1)) {
3805 ELEM_REMOVE(next);
3806 }
3807 }
3808
3809 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3810 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3811 /*
3812 * putstring ""
3813 * concatstrings N
3814 * =>
3815 * concatstrings N-1
3816 */
3817 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3818 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3819 INSN *next = (INSN *)iobj->link.next;
3820 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3821 ELEM_REMOVE(&next->link);
3822 }
3823 ELEM_REMOVE(&iobj->link);
3824 }
3825 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3826 INSN *next = (INSN *)iobj->link.next;
3827 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3828 VALUE src = OPERAND_AT(iobj, 0);
3829 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3830 VALUE path = rb_iseq_path(iseq);
3831 int line = iobj->insn_info.line_no;
3832 VALUE errinfo = rb_errinfo();
3833 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3834 if (NIL_P(re)) {
3835 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3836 rb_set_errinfo(errinfo);
3837 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3838 }
3839 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3840 ELEM_REMOVE(iobj->link.next);
3841 }
3842 }
3843 }
3844
3845 if (IS_INSN_ID(iobj, concatstrings)) {
3846 /*
3847 * concatstrings N
3848 * concatstrings M
3849 * =>
3850 * concatstrings N+M-1
3851 */
3852 LINK_ELEMENT *next = iobj->link.next;
3853 INSN *jump = 0;
3854 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3855 next = get_destination_insn(jump = (INSN *)next);
3856 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3857 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3858 OPERAND_AT(iobj, 0) = INT2FIX(n);
3859 if (jump) {
3860 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3861 if (!--label->refcnt) {
3862 ELEM_REMOVE(&label->link);
3863 }
3864 else {
3865 label = NEW_LABEL(0);
3866 OPERAND_AT(jump, 0) = (VALUE)label;
3867 }
3868 label->refcnt++;
3869 ELEM_INSERT_NEXT(next, &label->link);
3870 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3871 }
3872 else {
3873 ELEM_REMOVE(next);
3874 }
3875 }
3876 }
3877
3878 if (do_tailcallopt &&
3879 (IS_INSN_ID(iobj, send) ||
3880 IS_INSN_ID(iobj, opt_aref_with) ||
3881 IS_INSN_ID(iobj, opt_aset_with) ||
3882 IS_INSN_ID(iobj, invokesuper))) {
3883 /*
3884 * send ...
3885 * leave
3886 * =>
3887 * send ..., ... | VM_CALL_TAILCALL, ...
3888 * leave # unreachable
3889 */
3890 INSN *piobj = NULL;
3891 if (iobj->link.next) {
3892 LINK_ELEMENT *next = iobj->link.next;
3893 do {
3894 if (!IS_INSN(next)) {
3895 next = next->next;
3896 continue;
3897 }
3898 switch (INSN_OF(next)) {
3899 case BIN(nop):
3900 next = next->next;
3901 break;
3902 case BIN(jump):
3903 /* if cond
3904 * return tailcall
3905 * end
3906 */
3907 next = get_destination_insn((INSN *)next);
3908 break;
3909 case BIN(leave):
3910 piobj = iobj;
3911 /* fall through */
3912 default:
3913 next = NULL;
3914 break;
3915 }
3916 } while (next);
3917 }
3918
3919 if (piobj) {
3920 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3921 if (IS_INSN_ID(piobj, send) ||
3922 IS_INSN_ID(piobj, invokesuper)) {
3923 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3924 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3925 OPERAND_AT(piobj, 0) = (VALUE)ci;
3926 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3927 }
3928 }
3929 else {
3930 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3931 OPERAND_AT(piobj, 0) = (VALUE)ci;
3932 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3933 }
3934 }
3935 }
3936
3937 if (IS_INSN_ID(iobj, dup)) {
3938 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3939 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3940
3941 /*
3942 * dup
3943 * setlocal x, y
3944 * setlocal x, y
3945 * =>
3946 * dup
3947 * setlocal x, y
3948 */
3949 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3950 set2 = set1->next;
3951 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3952 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3953 ELEM_REMOVE(set1);
3954 ELEM_REMOVE(&iobj->link);
3955 }
3956 }
3957
3958 /*
3959 * dup
3960 * setlocal x, y
3961 * dup
3962 * setlocal x, y
3963 * =>
3964 * dup
3965 * setlocal x, y
3966 */
3967 else if (IS_NEXT_INSN_ID(set1, dup) &&
3968 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3969 set2 = set1->next->next;
3970 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3971 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3972 ELEM_REMOVE(set1->next);
3973 ELEM_REMOVE(set2);
3974 }
3975 }
3976 }
3977 }
3978
3979 /*
3980 * getlocal x, y
3981 * dup
3982 * setlocal x, y
3983 * =>
3984 * dup
3985 */
3986 if (IS_INSN_ID(iobj, getlocal)) {
3987 LINK_ELEMENT *niobj = &iobj->link;
3988 if (IS_NEXT_INSN_ID(niobj, dup)) {
3989 niobj = niobj->next;
3990 }
3991 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3992 LINK_ELEMENT *set1 = niobj->next;
3993 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3994 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3995 ELEM_REMOVE(set1);
3996 ELEM_REMOVE(niobj);
3997 }
3998 }
3999 }
4000
4001 /*
4002 * opt_invokebuiltin_delegate
4003 * trace
4004 * leave
4005 * =>
4006 * opt_invokebuiltin_delegate_leave
4007 * trace
4008 * leave
4009 */
4010 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4011 if (IS_TRACE(iobj->link.next)) {
4012 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4013 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4014 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4015 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4016 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4017 }
4018 }
4019 }
4020 }
4021
4022 /*
4023 * getblockparam
4024 * branchif / branchunless
4025 * =>
4026 * getblockparamproxy
4027 * branchif / branchunless
4028 */
4029 if (IS_INSN_ID(iobj, getblockparam)) {
4030 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4031 iobj->insn_id = BIN(getblockparamproxy);
4032 }
4033 }
4034
4035 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4036 LINK_ELEMENT *niobj = &iobj->link;
4037 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4038 niobj = niobj->next;
4039 LINK_ELEMENT *siobj;
4040 unsigned int set_flags = 0, unset_flags = 0;
4041
4042 /*
4043 * Eliminate hash allocation for f(*a, kw: 1)
4044 *
4045 * splatarray false
4046 * duphash
4047 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4048 * =>
4049 * splatarray false
4050 * putobject
4051 * send ARGS_SPLAT|KW_SPLAT
4052 */
4053 if (IS_NEXT_INSN_ID(niobj, send)) {
4054 siobj = niobj->next;
4055 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4056 unset_flags = VM_CALL_ARGS_BLOCKARG;
4057 }
4058 /*
4059 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4060 *
4061 * splatarray false
4062 * duphash
4063 * getlocal / getinstancevariable / getblockparamproxy
4064 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4065 * =>
4066 * splatarray false
4067 * putobject
4068 * getlocal / getinstancevariable / getblockparamproxy
4069 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4070 */
4071 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4072 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4073 siobj = niobj->next->next;
4074 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4075 }
4076
4077 if (set_flags) {
4078 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4079 unsigned int flags = vm_ci_flag(ci);
4080 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4081 ((INSN*)niobj)->insn_id = BIN(putobject);
4082 OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
4083
4084 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4085 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4086 RB_OBJ_WRITTEN(iseq, ci, nci);
4087 OPERAND_AT(siobj, 0) = (VALUE)nci;
4088 }
4089 }
4090 }
4091 }
4092
4093 return COMPILE_OK;
4094}
4095
4096static int
4097insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4098{
4099 iobj->insn_id = insn_id;
4100 iobj->operand_size = insn_len(insn_id) - 1;
4101 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4102
4103 if (insn_id == BIN(opt_neq)) {
4104 VALUE original_ci = iobj->operands[0];
4105 iobj->operand_size = 2;
4106 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
4107 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4108 iobj->operands[1] = original_ci;
4109 }
4110
4111 return COMPILE_OK;
4112}
4113
4114static int
4115iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4116{
4117 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4118 IS_INSN(iobj->link.next)) {
4119 /*
4120 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4121 */
4122 INSN *niobj = (INSN *)iobj->link.next;
4123 if (IS_INSN_ID(niobj, send)) {
4124 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4125 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4126 VALUE method = INT2FIX(0);
4127 switch (vm_ci_mid(ci)) {
4128 case idMax:
4129 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4130 break;
4131 case idMin:
4132 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4133 break;
4134 case idHash:
4135 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4136 break;
4137 }
4138
4139 if (method != INT2FIX(0)) {
4140 VALUE num = iobj->operands[0];
4141 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4142 iobj->insn_id = BIN(opt_newarray_send);
4143 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4144 iobj->operands[0] = num;
4145 iobj->operands[1] = method;
4146 iobj->operand_size = operand_len;
4147 ELEM_REMOVE(&niobj->link);
4148 return COMPILE_OK;
4149 }
4150 }
4151 }
4152 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4153 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4154 IS_NEXT_INSN_ID(&niobj->link, send)) {
4155 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4156 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4157 VALUE num = iobj->operands[0];
4158 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4159 iobj->insn_id = BIN(opt_newarray_send);
4160 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4161 iobj->operands[0] = FIXNUM_INC(num, 1);
4162 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4163 iobj->operand_size = operand_len;
4164 ELEM_REMOVE(&iobj->link);
4165 ELEM_REMOVE(niobj->link.next);
4166 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4167 return COMPILE_OK;
4168 }
4169 }
4170 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4171 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4172 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4173 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4174 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4175 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4176 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4177 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4178 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4179 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4180 VALUE num = iobj->operands[0];
4181 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4182 iobj->insn_id = BIN(opt_newarray_send);
4183 iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
4184 iobj->operands[0] = FIXNUM_INC(num, 2);
4185 iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4186 iobj->operand_size = operand_len;
4187 // Remove the "send" insn.
4188 ELEM_REMOVE((niobj->link.next)->next);
4189 // Remove the modified insn from its original "newarray" position...
4190 ELEM_REMOVE(&iobj->link);
4191 // and insert it after the buffer insn.
4192 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4193 return COMPILE_OK;
4194 }
4195 }
4196
4197 // Break the "else if" chain since some prior checks abort after sub-ifs.
4198 // We already found "newarray". To match `[...].include?(arg)` we look for
4199 // the instruction(s) representing the argument followed by a "send".
4200 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4201 IS_INSN_ID(niobj, putobject) ||
4202 IS_INSN_ID(niobj, putself) ||
4203 IS_INSN_ID(niobj, getlocal) ||
4204 IS_INSN_ID(niobj, getinstancevariable)) &&
4205 IS_NEXT_INSN_ID(&niobj->link, send)) {
4206
4207 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4208 const struct rb_callinfo *ci;
4209 // Allow any number (0 or more) of simple method calls on the argument
4210 // (as in `[...].include?(arg.method1.method2)`.
4211 do {
4212 sendobj = sendobj->next;
4213 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4214 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4215
4216 // If this send is for .include? with one arg we can do our opt.
4217 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4218 VALUE num = iobj->operands[0];
4219 INSN *sendins = (INSN *)sendobj;
4220 sendins->insn_id = BIN(opt_newarray_send);
4221 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4222 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4223 sendins->operands[0] = FIXNUM_INC(num, 1);
4224 sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4225 // Remove the original "newarray" insn.
4226 ELEM_REMOVE(&iobj->link);
4227 return COMPILE_OK;
4228 }
4229 }
4230 }
4231
4232 /*
4233 * duparray [...]
4234 * some insn for the arg...
4235 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4236 * =>
4237 * arg insn...
4238 * opt_duparray_send [...], :include?, 1
4239 */
4240 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4241 INSN *niobj = (INSN *)iobj->link.next;
4242 if ((IS_INSN_ID(niobj, getlocal) ||
4243 IS_INSN_ID(niobj, getinstancevariable) ||
4244 IS_INSN_ID(niobj, putself)) &&
4245 IS_NEXT_INSN_ID(&niobj->link, send)) {
4246
4247 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4248 const struct rb_callinfo *ci;
4249 // Allow any number (0 or more) of simple method calls on the argument
4250 // (as in `[...].include?(arg.method1.method2)`.
4251 do {
4252 sendobj = sendobj->next;
4253 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4254 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4255
4256 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4257 // Move the array arg from duparray to opt_duparray_send.
4258 VALUE ary = iobj->operands[0];
4260
4261 INSN *sendins = (INSN *)sendobj;
4262 sendins->insn_id = BIN(opt_duparray_send);
4263 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4264 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
4265 sendins->operands[0] = ary;
4266 sendins->operands[1] = rb_id2sym(idIncludeP);
4267 sendins->operands[2] = INT2FIX(1);
4268
4269 // Remove the duparray insn.
4270 ELEM_REMOVE(&iobj->link);
4271 return COMPILE_OK;
4272 }
4273 }
4274 }
4275
4276
4277 if (IS_INSN_ID(iobj, send)) {
4278 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4279 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4280
4281#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4282 if (vm_ci_simple(ci)) {
4283 switch (vm_ci_argc(ci)) {
4284 case 0:
4285 switch (vm_ci_mid(ci)) {
4286 case idLength: SP_INSN(length); return COMPILE_OK;
4287 case idSize: SP_INSN(size); return COMPILE_OK;
4288 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4289 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4290 case idSucc: SP_INSN(succ); return COMPILE_OK;
4291 case idNot: SP_INSN(not); return COMPILE_OK;
4292 }
4293 break;
4294 case 1:
4295 switch (vm_ci_mid(ci)) {
4296 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4297 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4298 case idMULT: SP_INSN(mult); return COMPILE_OK;
4299 case idDIV: SP_INSN(div); return COMPILE_OK;
4300 case idMOD: SP_INSN(mod); return COMPILE_OK;
4301 case idEq: SP_INSN(eq); return COMPILE_OK;
4302 case idNeq: SP_INSN(neq); return COMPILE_OK;
4303 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4304 case idLT: SP_INSN(lt); return COMPILE_OK;
4305 case idLE: SP_INSN(le); return COMPILE_OK;
4306 case idGT: SP_INSN(gt); return COMPILE_OK;
4307 case idGE: SP_INSN(ge); return COMPILE_OK;
4308 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4309 case idAREF: SP_INSN(aref); return COMPILE_OK;
4310 case idAnd: SP_INSN(and); return COMPILE_OK;
4311 case idOr: SP_INSN(or); return COMPILE_OK;
4312 }
4313 break;
4314 case 2:
4315 switch (vm_ci_mid(ci)) {
4316 case idASET: SP_INSN(aset); return COMPILE_OK;
4317 }
4318 break;
4319 }
4320 }
4321
4322 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4323 iobj->insn_id = BIN(opt_send_without_block);
4324 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4325 }
4326 }
4327#undef SP_INSN
4328
4329 return COMPILE_OK;
4330}
4331
4332static inline int
4333tailcallable_p(rb_iseq_t *iseq)
4334{
4335 switch (ISEQ_BODY(iseq)->type) {
4336 case ISEQ_TYPE_TOP:
4337 case ISEQ_TYPE_EVAL:
4338 case ISEQ_TYPE_MAIN:
4339 /* not tail callable because cfp will be over popped */
4340 case ISEQ_TYPE_RESCUE:
4341 case ISEQ_TYPE_ENSURE:
4342 /* rescue block can't tail call because of errinfo */
4343 return FALSE;
4344 default:
4345 return TRUE;
4346 }
4347}
4348
4349static int
4350iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4351{
4352 LINK_ELEMENT *list;
4353 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4354 const int do_tailcallopt = tailcallable_p(iseq) &&
4355 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4356 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4357 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4358 int rescue_level = 0;
4359 int tailcallopt = do_tailcallopt;
4360
4361 list = FIRST_ELEMENT(anchor);
4362
4363 int do_block_optimization = 0;
4364
4365 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4366 do_block_optimization = 1;
4367 }
4368
4369 while (list) {
4370 if (IS_INSN(list)) {
4371 if (do_peepholeopt) {
4372 iseq_peephole_optimize(iseq, list, tailcallopt);
4373 }
4374 if (do_si) {
4375 iseq_specialized_instruction(iseq, (INSN *)list);
4376 }
4377 if (do_ou) {
4378 insn_operands_unification((INSN *)list);
4379 }
4380
4381 if (do_block_optimization) {
4382 INSN * item = (INSN *)list;
4383 if (IS_INSN_ID(item, jump)) {
4384 do_block_optimization = 0;
4385 }
4386 }
4387 }
4388 if (IS_LABEL(list)) {
4389 switch (((LABEL *)list)->rescued) {
4390 case LABEL_RESCUE_BEG:
4391 rescue_level++;
4392 tailcallopt = FALSE;
4393 break;
4394 case LABEL_RESCUE_END:
4395 if (!--rescue_level) tailcallopt = do_tailcallopt;
4396 break;
4397 }
4398 }
4399 list = list->next;
4400 }
4401
4402 if (do_block_optimization) {
4403 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4404 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4405 ELEM_REMOVE(le);
4406 }
4407 }
4408 return COMPILE_OK;
4409}
4410
4411#if OPT_INSTRUCTIONS_UNIFICATION
4412static INSN *
4413new_unified_insn(rb_iseq_t *iseq,
4414 int insn_id, int size, LINK_ELEMENT *seq_list)
4415{
4416 INSN *iobj = 0;
4417 LINK_ELEMENT *list = seq_list;
4418 int i, argc = 0;
4419 VALUE *operands = 0, *ptr = 0;
4420
4421
4422 /* count argc */
4423 for (i = 0; i < size; i++) {
4424 iobj = (INSN *)list;
4425 argc += iobj->operand_size;
4426 list = list->next;
4427 }
4428
4429 if (argc > 0) {
4430 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4431 }
4432
4433 /* copy operands */
4434 list = seq_list;
4435 for (i = 0; i < size; i++) {
4436 iobj = (INSN *)list;
4437 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4438 ptr += iobj->operand_size;
4439 list = list->next;
4440 }
4441
4442 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4443}
4444#endif
4445
4446/*
4447 * This scheme can get more performance if do this optimize with
4448 * label address resolving.
4449 * It's future work (if compile time was bottle neck).
4450 */
4451static int
4452iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4453{
4454#if OPT_INSTRUCTIONS_UNIFICATION
4455 LINK_ELEMENT *list;
4456 INSN *iobj, *niobj;
4457 int id, k;
4458 intptr_t j;
4459
4460 list = FIRST_ELEMENT(anchor);
4461 while (list) {
4462 if (IS_INSN(list)) {
4463 iobj = (INSN *)list;
4464 id = iobj->insn_id;
4465 if (unified_insns_data[id] != 0) {
4466 const int *const *entry = unified_insns_data[id];
4467 for (j = 1; j < (intptr_t)entry[0]; j++) {
4468 const int *unified = entry[j];
4469 LINK_ELEMENT *li = list->next;
4470 for (k = 2; k < unified[1]; k++) {
4471 if (!IS_INSN(li) ||
4472 ((INSN *)li)->insn_id != unified[k]) {
4473 goto miss;
4474 }
4475 li = li->next;
4476 }
4477 /* matched */
4478 niobj =
4479 new_unified_insn(iseq, unified[0], unified[1] - 1,
4480 list);
4481
4482 /* insert to list */
4483 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4484 niobj->link.next = li;
4485 if (li) {
4486 li->prev = (LINK_ELEMENT *)niobj;
4487 }
4488
4489 list->prev->next = (LINK_ELEMENT *)niobj;
4490 list = (LINK_ELEMENT *)niobj;
4491 break;
4492 miss:;
4493 }
4494 }
4495 }
4496 list = list->next;
4497 }
4498#endif
4499 return COMPILE_OK;
4500}
4501
4502static int
4503all_string_result_p(const NODE *node)
4504{
4505 if (!node) return FALSE;
4506 switch (nd_type(node)) {
4507 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4508 return TRUE;
4509 case NODE_IF: case NODE_UNLESS:
4510 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4511 if (all_string_result_p(RNODE_IF(node)->nd_body))
4512 return all_string_result_p(RNODE_IF(node)->nd_else);
4513 return FALSE;
4514 case NODE_AND: case NODE_OR:
4515 if (!RNODE_AND(node)->nd_2nd)
4516 return all_string_result_p(RNODE_AND(node)->nd_1st);
4517 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4518 return FALSE;
4519 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4520 default:
4521 return FALSE;
4522 }
4523}
4524
4526 rb_iseq_t *const iseq;
4527 LINK_ANCHOR *const ret;
4528 VALUE lit;
4529 const NODE *lit_node;
4530 int cnt;
4531 int dregx;
4532};
4533
4534static int
4535append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4536{
4537 VALUE s = rb_str_new_mutable_parser_string(str);
4538 if (args->dregx) {
4539 VALUE error = rb_reg_check_preprocess(s);
4540 if (!NIL_P(error)) {
4541 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4542 return COMPILE_NG;
4543 }
4544 }
4545 if (NIL_P(args->lit)) {
4546 args->lit = s;
4547 args->lit_node = node;
4548 }
4549 else {
4550 rb_str_buf_append(args->lit, s);
4551 }
4552 return COMPILE_OK;
4553}
4554
4555static void
4556flush_dstr_fragment(struct dstr_ctxt *args)
4557{
4558 if (!NIL_P(args->lit)) {
4559 rb_iseq_t *iseq = args->iseq;
4560 VALUE lit = args->lit;
4561 args->lit = Qnil;
4562 lit = rb_fstring(lit);
4563 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4564 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4565 args->cnt++;
4566 }
4567}
4568
4569static int
4570compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4571{
4572 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4573 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4574
4575 if (str) {
4576 CHECK(append_dstr_fragment(args, node, str));
4577 }
4578
4579 while (list) {
4580 const NODE *const head = list->nd_head;
4581 if (nd_type_p(head, NODE_STR)) {
4582 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4583 }
4584 else if (nd_type_p(head, NODE_DSTR)) {
4585 CHECK(compile_dstr_fragments_0(args, head));
4586 }
4587 else {
4588 flush_dstr_fragment(args);
4589 rb_iseq_t *iseq = args->iseq;
4590 CHECK(COMPILE(args->ret, "each string", head));
4591 args->cnt++;
4592 }
4593 list = (struct RNode_LIST *)list->nd_next;
4594 }
4595 return COMPILE_OK;
4596}
4597
4598static int
4599compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4600{
4601 struct dstr_ctxt args = {
4602 .iseq = iseq, .ret = ret,
4603 .lit = Qnil, .lit_node = NULL,
4604 .cnt = 0, .dregx = dregx,
4605 };
4606 CHECK(compile_dstr_fragments_0(&args, node));
4607 flush_dstr_fragment(&args);
4608
4609 *cntp = args.cnt;
4610
4611 return COMPILE_OK;
4612}
4613
4614static int
4615compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4616{
4617 while (node && nd_type_p(node, NODE_BLOCK)) {
4618 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4619 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4620 node = RNODE_BLOCK(node)->nd_next;
4621 }
4622 if (node) {
4623 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4624 }
4625 return COMPILE_OK;
4626}
4627
4628static int
4629compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4630{
4631 int cnt;
4632 if (!RNODE_DSTR(node)->nd_next) {
4633 VALUE lit = rb_node_dstr_string_val(node);
4634 ADD_INSN1(ret, node, putstring, lit);
4635 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4636 }
4637 else {
4638 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4639 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4640 }
4641 return COMPILE_OK;
4642}
4643
4644static int
4645compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4646{
4647 int cnt;
4648 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4649
4650 if (!RNODE_DREGX(node)->nd_next) {
4651 if (!popped) {
4652 VALUE src = rb_node_dregx_string_val(node);
4653 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4654 ADD_INSN1(ret, node, putobject, match);
4655 RB_OBJ_WRITTEN(iseq, Qundef, match);
4656 }
4657 return COMPILE_OK;
4658 }
4659
4660 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4661 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4662
4663 if (popped) {
4664 ADD_INSN(ret, node, pop);
4665 }
4666
4667 return COMPILE_OK;
4668}
4669
4670static int
4671compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4672 LABEL *then_label, LABEL *else_label)
4673{
4674 const int line = nd_line(node);
4675 LABEL *lend = NEW_LABEL(line);
4676 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4677 + VM_SVAR_FLIPFLOP_START;
4678 VALUE key = INT2FIX(cnt);
4679
4680 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4681 ADD_INSNL(ret, node, branchif, lend);
4682
4683 /* *flip == 0 */
4684 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4685 ADD_INSNL(ret, node, branchunless, else_label);
4686 ADD_INSN1(ret, node, putobject, Qtrue);
4687 ADD_INSN1(ret, node, setspecial, key);
4688 if (!again) {
4689 ADD_INSNL(ret, node, jump, then_label);
4690 }
4691
4692 /* *flip == 1 */
4693 ADD_LABEL(ret, lend);
4694 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4695 ADD_INSNL(ret, node, branchunless, then_label);
4696 ADD_INSN1(ret, node, putobject, Qfalse);
4697 ADD_INSN1(ret, node, setspecial, key);
4698 ADD_INSNL(ret, node, jump, then_label);
4699
4700 return COMPILE_OK;
4701}
4702
4703static int
4704compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4705 LABEL *then_label, LABEL *else_label);
4706
4707#define COMPILE_SINGLE 2
4708static int
4709compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4710 LABEL *then_label, LABEL *else_label)
4711{
4712 DECL_ANCHOR(seq);
4713 INIT_ANCHOR(seq);
4714 LABEL *label = NEW_LABEL(nd_line(cond));
4715 if (!then_label) then_label = label;
4716 else if (!else_label) else_label = label;
4717
4718 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4719
4720 if (LIST_INSN_SIZE_ONE(seq)) {
4721 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4722 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4723 return COMPILE_OK;
4724 }
4725 if (!label->refcnt) {
4726 return COMPILE_SINGLE;
4727 }
4728 ADD_LABEL(seq, label);
4729 ADD_SEQ(ret, seq);
4730 return COMPILE_OK;
4731}
4732
4733static int
4734compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4735 LABEL *then_label, LABEL *else_label)
4736{
4737 int ok;
4738 DECL_ANCHOR(ignore);
4739
4740 again:
4741 switch (nd_type(cond)) {
4742 case NODE_AND:
4743 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4744 cond = RNODE_AND(cond)->nd_2nd;
4745 if (ok == COMPILE_SINGLE) {
4746 INIT_ANCHOR(ignore);
4747 ret = ignore;
4748 then_label = NEW_LABEL(nd_line(cond));
4749 }
4750 goto again;
4751 case NODE_OR:
4752 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4753 cond = RNODE_OR(cond)->nd_2nd;
4754 if (ok == COMPILE_SINGLE) {
4755 INIT_ANCHOR(ignore);
4756 ret = ignore;
4757 else_label = NEW_LABEL(nd_line(cond));
4758 }
4759 goto again;
4760 case NODE_SYM:
4761 case NODE_LINE:
4762 case NODE_FILE:
4763 case NODE_ENCODING:
4764 case NODE_INTEGER: /* NODE_INTEGER is always true */
4765 case NODE_FLOAT: /* NODE_FLOAT is always true */
4766 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4767 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4768 case NODE_TRUE:
4769 case NODE_STR:
4770 case NODE_REGX:
4771 case NODE_ZLIST:
4772 case NODE_LAMBDA:
4773 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4774 ADD_INSNL(ret, cond, jump, then_label);
4775 return COMPILE_OK;
4776 case NODE_FALSE:
4777 case NODE_NIL:
4778 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4779 ADD_INSNL(ret, cond, jump, else_label);
4780 return COMPILE_OK;
4781 case NODE_LIST:
4782 case NODE_ARGSCAT:
4783 case NODE_DREGX:
4784 case NODE_DSTR:
4785 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4786 ADD_INSNL(ret, cond, jump, then_label);
4787 return COMPILE_OK;
4788 case NODE_FLIP2:
4789 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4790 return COMPILE_OK;
4791 case NODE_FLIP3:
4792 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4793 return COMPILE_OK;
4794 case NODE_DEFINED:
4795 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4796 break;
4797 default:
4798 {
4799 DECL_ANCHOR(cond_seq);
4800 INIT_ANCHOR(cond_seq);
4801
4802 CHECK(COMPILE(cond_seq, "branch condition", cond));
4803
4804 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4805 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4806 if (insn->insn_id == BIN(putobject)) {
4807 if (RTEST(insn->operands[0])) {
4808 ADD_INSNL(ret, cond, jump, then_label);
4809 // maybe unreachable
4810 return COMPILE_OK;
4811 }
4812 else {
4813 ADD_INSNL(ret, cond, jump, else_label);
4814 return COMPILE_OK;
4815 }
4816 }
4817 }
4818 ADD_SEQ(ret, cond_seq);
4819 }
4820 break;
4821 }
4822
4823 ADD_INSNL(ret, cond, branchunless, else_label);
4824 ADD_INSNL(ret, cond, jump, then_label);
4825 return COMPILE_OK;
4826}
4827
4828#define HASH_BRACE 1
4829
4830static int
4831keyword_node_p(const NODE *const node)
4832{
4833 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4834}
4835
4836static VALUE
4837get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4838{
4839 switch (nd_type(node)) {
4840 case NODE_SYM:
4841 return rb_node_sym_string_val(node);
4842 default:
4843 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4844 }
4845}
4846
4847static VALUE
4848node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4849{
4850 NODE *node = node_hash->nd_head;
4851 VALUE hash = rb_hash_new();
4852 VALUE ary = rb_ary_new();
4853
4854 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4855 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4856 VALUE idx = rb_hash_aref(hash, key);
4857 if (!NIL_P(idx)) {
4858 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4859 (*count_ptr)--;
4860 }
4861 rb_hash_aset(hash, key, INT2FIX(i));
4862 rb_ary_store(ary, i, Qtrue);
4863 (*count_ptr)++;
4864 }
4865
4866 return ary;
4867}
4868
4869static int
4870compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4871 const NODE *const root_node,
4872 struct rb_callinfo_kwarg **const kw_arg_ptr,
4873 unsigned int *flag)
4874{
4875 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4876 RUBY_ASSERT(kw_arg_ptr != NULL);
4877 RUBY_ASSERT(flag != NULL);
4878
4879 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4880 const NODE *node = RNODE_HASH(root_node)->nd_head;
4881 int seen_nodes = 0;
4882
4883 while (node) {
4884 const NODE *key_node = RNODE_LIST(node)->nd_head;
4885 seen_nodes++;
4886
4887 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4888 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4889 /* can be keywords */
4890 }
4891 else {
4892 if (flag) {
4893 *flag |= VM_CALL_KW_SPLAT;
4894 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4895 /* A new hash will be created for the keyword arguments
4896 * in this case, so mark the method as passing mutable
4897 * keyword splat.
4898 */
4899 *flag |= VM_CALL_KW_SPLAT_MUT;
4900 }
4901 }
4902 return FALSE;
4903 }
4904 node = RNODE_LIST(node)->nd_next; /* skip value node */
4905 node = RNODE_LIST(node)->nd_next;
4906 }
4907
4908 /* may be keywords */
4909 node = RNODE_HASH(root_node)->nd_head;
4910 {
4911 int len = 0;
4912 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4913 struct rb_callinfo_kwarg *kw_arg =
4914 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4915 VALUE *keywords = kw_arg->keywords;
4916 int i = 0;
4917 int j = 0;
4918 kw_arg->references = 0;
4919 kw_arg->keyword_len = len;
4920
4921 *kw_arg_ptr = kw_arg;
4922
4923 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4924 const NODE *key_node = RNODE_LIST(node)->nd_head;
4925 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4926 int popped = TRUE;
4927 if (rb_ary_entry(key_index, i)) {
4928 keywords[j] = get_symbol_value(iseq, key_node);
4929 j++;
4930 popped = FALSE;
4931 }
4932 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4933 }
4934 RUBY_ASSERT(j == len);
4935 return TRUE;
4936 }
4937 }
4938 return FALSE;
4939}
4940
4941static int
4942compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4943{
4944 int len = 0;
4945
4946 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4947 if (CPDEBUG > 0) {
4948 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4949 }
4950
4951 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4952 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4953 }
4954 else {
4955 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4956 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4957 }
4958 }
4959
4960 return len;
4961}
4962
4963static inline bool
4964frozen_string_literal_p(const rb_iseq_t *iseq)
4965{
4966 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4967}
4968
4969static inline bool
4970static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
4971{
4972 switch (nd_type(node)) {
4973 case NODE_SYM:
4974 case NODE_REGX:
4975 case NODE_LINE:
4976 case NODE_ENCODING:
4977 case NODE_INTEGER:
4978 case NODE_FLOAT:
4979 case NODE_RATIONAL:
4980 case NODE_IMAGINARY:
4981 case NODE_NIL:
4982 case NODE_TRUE:
4983 case NODE_FALSE:
4984 return TRUE;
4985 case NODE_STR:
4986 case NODE_FILE:
4987 return hash_key || frozen_string_literal_p(iseq);
4988 default:
4989 return FALSE;
4990 }
4991}
4992
4993static inline VALUE
4994static_literal_value(const NODE *node, rb_iseq_t *iseq)
4995{
4996 switch (nd_type(node)) {
4997 case NODE_INTEGER:
4998 return rb_node_integer_literal_val(node);
4999 case NODE_FLOAT:
5000 return rb_node_float_literal_val(node);
5001 case NODE_RATIONAL:
5002 return rb_node_rational_literal_val(node);
5003 case NODE_IMAGINARY:
5004 return rb_node_imaginary_literal_val(node);
5005 case NODE_NIL:
5006 return Qnil;
5007 case NODE_TRUE:
5008 return Qtrue;
5009 case NODE_FALSE:
5010 return Qfalse;
5011 case NODE_SYM:
5012 return rb_node_sym_string_val(node);
5013 case NODE_REGX:
5014 return rb_node_regx_string_val(node);
5015 case NODE_LINE:
5016 return rb_node_line_lineno_val(node);
5017 case NODE_ENCODING:
5018 return rb_node_encoding_val(node);
5019 case NODE_FILE:
5020 case NODE_STR:
5021 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5022 VALUE lit = get_string_value(node);
5023 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5024 }
5025 else {
5026 return get_string_value(node);
5027 }
5028 default:
5029 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5030 }
5031}
5032
5033static int
5034compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5035{
5036 const NODE *line_node = node;
5037
5038 if (nd_type_p(node, NODE_ZLIST)) {
5039 if (!popped) {
5040 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5041 }
5042 return 0;
5043 }
5044
5045 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5046
5047 if (popped) {
5048 for (; node; node = RNODE_LIST(node)->nd_next) {
5049 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5050 }
5051 return 1;
5052 }
5053
5054 /* Compilation of an array literal.
5055 * The following code is essentially the same as:
5056 *
5057 * for (int count = 0; node; count++; node->nd_next) {
5058 * compile(node->nd_head);
5059 * }
5060 * ADD_INSN(newarray, count);
5061 *
5062 * However, there are three points.
5063 *
5064 * - The code above causes stack overflow for a big string literal.
5065 * The following limits the stack length up to max_stack_len.
5066 *
5067 * [x1,x2,...,x10000] =>
5068 * push x1 ; push x2 ; ...; push x256; newarray 256;
5069 * push x257; push x258; ...; push x512; pushtoarray 256;
5070 * push x513; push x514; ...; push x768; pushtoarray 256;
5071 * ...
5072 *
5073 * - Long subarray can be optimized by pre-allocating a hidden array.
5074 *
5075 * [1,2,3,...,100] =>
5076 * duparray [1,2,3,...,100]
5077 *
5078 * [x, 1,2,3,...,100, z] =>
5079 * push x; newarray 1;
5080 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5081 * push z; pushtoarray 1;
5082 *
5083 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5084 * to only push it onto the array if it is not empty
5085 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5086 *
5087 * [1,2,3,**kw] =>
5088 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5089 */
5090
5091 const int max_stack_len = 0x100;
5092 const int min_tmp_ary_len = 0x40;
5093 int stack_len = 0;
5094
5095 /* Either create a new array, or push to the existing array */
5096#define FLUSH_CHUNK \
5097 if (stack_len) { \
5098 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5099 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5100 first_chunk = FALSE; \
5101 stack_len = 0; \
5102 }
5103
5104 while (node) {
5105 int count = 1;
5106
5107 /* pre-allocation check (this branch can be omittable) */
5108 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5109 /* count the elements that are optimizable */
5110 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5111 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5112 count++;
5113
5114 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5115 /* The literal contains only optimizable elements, or the subarray is long enough */
5116 VALUE ary = rb_ary_hidden_new(count);
5117
5118 /* Create a hidden array */
5119 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5120 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5121 OBJ_FREEZE(ary);
5122
5123 /* Emit optimized code */
5124 FLUSH_CHUNK;
5125 if (first_chunk) {
5126 ADD_INSN1(ret, line_node, duparray, ary);
5127 first_chunk = FALSE;
5128 }
5129 else {
5130 ADD_INSN1(ret, line_node, putobject, ary);
5131 ADD_INSN(ret, line_node, concattoarray);
5132 }
5133 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5134 }
5135 }
5136
5137 /* Base case: Compile "count" elements */
5138 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5139 if (CPDEBUG > 0) {
5140 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5141 }
5142
5143 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5144 /* Create array or push existing non-keyword elements onto array */
5145 if (stack_len == 0 && first_chunk) {
5146 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5147 }
5148 else {
5149 FLUSH_CHUNK;
5150 }
5151 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5152 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5153 return 1;
5154 }
5155 else {
5156 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5157 stack_len++;
5158 }
5159
5160 /* If there are many pushed elements, flush them to avoid stack overflow */
5161 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5162 }
5163 }
5164
5165 FLUSH_CHUNK;
5166#undef FLUSH_CHUNK
5167 return 1;
5168}
5169
5170static inline int
5171static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5172{
5173 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);
5174}
5175
5176static int
5177compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5178{
5179 const NODE *line_node = node;
5180
5181 node = RNODE_HASH(node)->nd_head;
5182
5183 if (!node || nd_type_p(node, NODE_ZLIST)) {
5184 if (!popped) {
5185 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5186 }
5187 return 0;
5188 }
5189
5190 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5191
5192 if (popped) {
5193 for (; node; node = RNODE_LIST(node)->nd_next) {
5194 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5195 }
5196 return 1;
5197 }
5198
5199 /* Compilation of a hash literal (or keyword arguments).
5200 * This is very similar to compile_array, but there are some differences:
5201 *
5202 * - It contains key-value pairs. So we need to take every two elements.
5203 * We can assume that the length is always even.
5204 *
5205 * - Merging is done by a method call (id_core_hash_merge_ptr).
5206 * Sometimes we need to insert the receiver, so "anchor" is needed.
5207 * In addition, a method call is much slower than concatarray.
5208 * So it pays only when the subsequence is really long.
5209 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5210 *
5211 * - We need to handle keyword splat: **kw.
5212 * For **kw, the key part (node->nd_head) is NULL, and the value part
5213 * (node->nd_next->nd_head) is "kw".
5214 * The code is a bit difficult to avoid hash allocation for **{}.
5215 */
5216
5217 const int max_stack_len = 0x100;
5218 const int min_tmp_hash_len = 0x800;
5219 int stack_len = 0;
5220 int first_chunk = 1;
5221 DECL_ANCHOR(anchor);
5222 INIT_ANCHOR(anchor);
5223
5224 /* Convert pushed elements to a hash, and merge if needed */
5225#define FLUSH_CHUNK() \
5226 if (stack_len) { \
5227 if (first_chunk) { \
5228 APPEND_LIST(ret, anchor); \
5229 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5230 } \
5231 else { \
5232 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5233 ADD_INSN(ret, line_node, swap); \
5234 APPEND_LIST(ret, anchor); \
5235 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5236 } \
5237 INIT_ANCHOR(anchor); \
5238 first_chunk = stack_len = 0; \
5239 }
5240
5241 while (node) {
5242 int count = 1;
5243
5244 /* pre-allocation check (this branch can be omittable) */
5245 if (static_literal_node_pair_p(node, iseq)) {
5246 /* count the elements that are optimizable */
5247 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5248 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5249 count++;
5250
5251 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5252 /* The literal contains only optimizable elements, or the subsequence is long enough */
5253 VALUE ary = rb_ary_hidden_new(count);
5254
5255 /* Create a hidden hash */
5256 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5257 VALUE elem[2];
5258 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5259 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5260 rb_ary_cat(ary, elem, 2);
5261 }
5262 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5263 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5264 hash = rb_obj_hide(hash);
5265 OBJ_FREEZE(hash);
5266
5267 /* Emit optimized code */
5268 FLUSH_CHUNK();
5269 if (first_chunk) {
5270 ADD_INSN1(ret, line_node, duphash, hash);
5271 first_chunk = 0;
5272 }
5273 else {
5274 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5275 ADD_INSN(ret, line_node, swap);
5276
5277 ADD_INSN1(ret, line_node, putobject, hash);
5278
5279 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5280 }
5281 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5282 }
5283 }
5284
5285 /* Base case: Compile "count" elements */
5286 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5287
5288 if (CPDEBUG > 0) {
5289 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5290 }
5291
5292 if (RNODE_LIST(node)->nd_head) {
5293 /* Normal key-value pair */
5294 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5295 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5296 stack_len += 2;
5297
5298 /* If there are many pushed elements, flush them to avoid stack overflow */
5299 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5300 }
5301 else {
5302 /* kwsplat case: foo(..., **kw, ...) */
5303 FLUSH_CHUNK();
5304
5305 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5306 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5307 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5308 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5309 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5310
5311 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5312 if (empty_kw) {
5313 if (only_kw && method_call_keywords) {
5314 /* **{} appears at the only keyword argument in method call,
5315 * so it won't be modified.
5316 * kw is a special NODE_LIT that contains a special empty hash,
5317 * so this emits: putobject {}.
5318 * This is only done for method calls and not for literal hashes,
5319 * because literal hashes should always result in a new hash.
5320 */
5321 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5322 }
5323 else if (first_kw) {
5324 /* **{} appears as the first keyword argument, so it may be modified.
5325 * We need to create a fresh hash object.
5326 */
5327 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5328 }
5329 /* Any empty keyword splats that are not the first can be ignored.
5330 * since merging an empty hash into the existing hash is the same
5331 * as not merging it. */
5332 }
5333 else {
5334 if (only_kw && method_call_keywords) {
5335 /* **kw is only keyword argument in method call.
5336 * Use directly. This will be not be flagged as mutable.
5337 * This is only done for method calls and not for literal hashes,
5338 * because literal hashes should always result in a new hash.
5339 */
5340 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5341 }
5342 else {
5343 /* There is more than one keyword argument, or this is not a method
5344 * call. In that case, we need to add an empty hash (if first keyword),
5345 * or merge the hash to the accumulated hash (if not the first keyword).
5346 */
5347 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5348 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5349 else ADD_INSN(ret, line_node, swap);
5350
5351 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5352
5353 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5354 }
5355 }
5356
5357 first_chunk = 0;
5358 }
5359 }
5360 }
5361
5362 FLUSH_CHUNK();
5363#undef FLUSH_CHUNK
5364 return 1;
5365}
5366
5367VALUE
5368rb_node_case_when_optimizable_literal(const NODE *const node)
5369{
5370 switch (nd_type(node)) {
5371 case NODE_INTEGER:
5372 return rb_node_integer_literal_val(node);
5373 case NODE_FLOAT: {
5374 VALUE v = rb_node_float_literal_val(node);
5375 double ival;
5376
5377 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5378 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5379 }
5380 return v;
5381 }
5382 case NODE_RATIONAL:
5383 case NODE_IMAGINARY:
5384 return Qundef;
5385 case NODE_NIL:
5386 return Qnil;
5387 case NODE_TRUE:
5388 return Qtrue;
5389 case NODE_FALSE:
5390 return Qfalse;
5391 case NODE_SYM:
5392 return rb_node_sym_string_val(node);
5393 case NODE_LINE:
5394 return rb_node_line_lineno_val(node);
5395 case NODE_STR:
5396 return rb_node_str_string_val(node);
5397 case NODE_FILE:
5398 return rb_node_file_path_val(node);
5399 }
5400 return Qundef;
5401}
5402
5403static int
5404when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5405 LABEL *l1, int only_special_literals, VALUE literals)
5406{
5407 while (vals) {
5408 const NODE *val = RNODE_LIST(vals)->nd_head;
5409 VALUE lit = rb_node_case_when_optimizable_literal(val);
5410
5411 if (UNDEF_P(lit)) {
5412 only_special_literals = 0;
5413 }
5414 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5415 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5416 }
5417
5418 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5419 debugp_param("nd_lit", get_string_value(val));
5420 lit = get_string_value(val);
5421 ADD_INSN1(cond_seq, val, putobject, lit);
5422 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5423 }
5424 else {
5425 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5426 }
5427
5428 // Emit pattern === target
5429 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5430 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5431 ADD_INSNL(cond_seq, val, branchif, l1);
5432 vals = RNODE_LIST(vals)->nd_next;
5433 }
5434 return only_special_literals;
5435}
5436
5437static int
5438when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5439 LABEL *l1, int only_special_literals, VALUE literals)
5440{
5441 const NODE *line_node = vals;
5442
5443 switch (nd_type(vals)) {
5444 case NODE_LIST:
5445 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5446 return COMPILE_NG;
5447 break;
5448 case NODE_SPLAT:
5449 ADD_INSN (cond_seq, line_node, dup);
5450 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5451 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5452 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5453 ADD_INSNL(cond_seq, line_node, branchif, l1);
5454 break;
5455 case NODE_ARGSCAT:
5456 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5457 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5458 break;
5459 case NODE_ARGSPUSH:
5460 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5461 ADD_INSN (cond_seq, line_node, dup);
5462 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5463 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5464 ADD_INSNL(cond_seq, line_node, branchif, l1);
5465 break;
5466 default:
5467 ADD_INSN (cond_seq, line_node, dup);
5468 CHECK(COMPILE(cond_seq, "when val", vals));
5469 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5470 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5471 ADD_INSNL(cond_seq, line_node, branchif, l1);
5472 break;
5473 }
5474 return COMPILE_OK;
5475}
5476
5477/* Multiple Assignment Handling
5478 *
5479 * In order to handle evaluation of multiple assignment such that the left hand side
5480 * is evaluated before the right hand side, we need to process the left hand side
5481 * and see if there are any attributes that need to be assigned, or constants set
5482 * on explicit objects. If so, we add instructions to evaluate the receiver of
5483 * any assigned attributes or constants before we process the right hand side.
5484 *
5485 * For a multiple assignment such as:
5486 *
5487 * l1.m1, l2[0] = r3, r4
5488 *
5489 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5490 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5491 * On the VM stack, this looks like:
5492 *
5493 * self # putself
5494 * l1 # send
5495 * l1, self # putself
5496 * l1, l2 # send
5497 * l1, l2, 0 # putobject 0
5498 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5499 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5500 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5501 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5502 * l1, l2, 0, [r3, r4], r4, m1= # send
5503 * l1, l2, 0, [r3, r4], r4 # pop
5504 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5505 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5506 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5507 * l1, l2, 0, [r3, r4], r4, []= # send
5508 * l1, l2, 0, [r3, r4], r4 # pop
5509 * l1, l2, 0, [r3, r4] # pop
5510 * [r3, r4], l2, 0, [r3, r4] # setn 3
5511 * [r3, r4], l2, 0 # pop
5512 * [r3, r4], l2 # pop
5513 * [r3, r4] # pop
5514 *
5515 * This is made more complex when you have to handle splats, post args,
5516 * and arbitrary levels of nesting. You need to keep track of the total
5517 * number of attributes to set, and for each attribute, how many entries
5518 * are on the stack before the final attribute, in order to correctly
5519 * calculate the topn value to use to get the receiver of the attribute
5520 * setter method.
5521 *
5522 * A brief description of the VM stack for simple multiple assignment
5523 * with no splat (rhs_array will not be present if the return value of
5524 * the multiple assignment is not needed):
5525 *
5526 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5527 *
5528 * For multiple assignment with splats, while processing the part before
5529 * the splat (splat+post here is an array of the splat and the post arguments):
5530 *
5531 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5532 *
5533 * When processing the splat and post arguments:
5534 *
5535 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5536 *
5537 * When processing nested multiple assignment, existing values on the stack
5538 * are kept. So for:
5539 *
5540 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5541 *
5542 * The stack layout would be the following before processing the nested
5543 * multiple assignment:
5544 *
5545 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5546 *
5547 * In order to handle this correctly, we need to keep track of the nesting
5548 * level for each attribute assignment, as well as the attribute number
5549 * (left hand side attributes are processed left to right) and number of
5550 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5551 * this information.
5552 *
5553 * We also need to track information for the entire multiple assignment, such
5554 * as the total number of arguments, and the current nesting level, to
5555 * handle both nested multiple assignment as well as cases where the
5556 * rhs is not needed. We also need to keep track of all attribute
5557 * assignments in this, which we do using a linked listed. struct masgn_state
5558 * tracks this information.
5559 */
5560
5562 INSN *before_insn;
5563 struct masgn_lhs_node *next;
5564 const NODE *line_node;
5565 int argn;
5566 int num_args;
5567 int lhs_pos;
5568};
5569
5571 struct masgn_lhs_node *first_memo;
5572 struct masgn_lhs_node *last_memo;
5573 int lhs_level;
5574 int num_args;
5575 bool nested;
5576};
5577
5578static int
5579add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5580{
5581 if (!state) {
5582 rb_bug("no masgn_state");
5583 }
5584
5585 struct masgn_lhs_node *memo;
5586 memo = malloc(sizeof(struct masgn_lhs_node));
5587 if (!memo) {
5588 return COMPILE_NG;
5589 }
5590
5591 memo->before_insn = before_insn;
5592 memo->line_node = line_node;
5593 memo->argn = state->num_args + 1;
5594 memo->num_args = argc;
5595 state->num_args += argc;
5596 memo->lhs_pos = lhs_pos;
5597 memo->next = NULL;
5598 if (!state->first_memo) {
5599 state->first_memo = memo;
5600 }
5601 else {
5602 state->last_memo->next = memo;
5603 }
5604 state->last_memo = memo;
5605
5606 return COMPILE_OK;
5607}
5608
5609static 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);
5610
5611static int
5612compile_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)
5613{
5614 switch (nd_type(node)) {
5615 case NODE_ATTRASGN: {
5616 INSN *iobj;
5617 const NODE *line_node = node;
5618
5619 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5620
5621 bool safenav_call = false;
5622 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5623 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5624 ASSUME(iobj);
5625 ELEM_REMOVE(insn_element);
5626 if (!IS_INSN_ID(iobj, send)) {
5627 safenav_call = true;
5628 iobj = (INSN *)get_prev_insn(iobj);
5629 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5630 }
5631 (pre->last = iobj->link.prev)->next = 0;
5632
5633 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5634 int argc = vm_ci_argc(ci) + 1;
5635 ci = ci_argc_set(iseq, ci, argc);
5636 OPERAND_AT(iobj, 0) = (VALUE)ci;
5637 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5638
5639 if (argc == 1) {
5640 ADD_INSN(lhs, line_node, swap);
5641 }
5642 else {
5643 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5644 }
5645
5646 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5647 return COMPILE_NG;
5648 }
5649
5650 iobj->link.prev = lhs->last;
5651 lhs->last->next = &iobj->link;
5652 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5653 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5654 int argc = vm_ci_argc(ci);
5655 bool dupsplat = false;
5656 ci = ci_argc_set(iseq, ci, argc - 1);
5657 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5658 /* Given h[*a], _ = ary
5659 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5660 * `a` must be dupped, because it will be appended with ary[0]
5661 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5662 */
5663 dupsplat = true;
5664 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5665 }
5666 OPERAND_AT(iobj, 0) = (VALUE)ci;
5667 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5668
5669 /* Given: h[*a], h[*b, 1] = ary
5670 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5671 * so this uses splatarray true on a to dup it before using pushtoarray
5672 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5673 * so you can use pushtoarray directly
5674 */
5675 int line_no = nd_line(line_node);
5676 int node_id = nd_node_id(line_node);
5677
5678 if (dupsplat) {
5679 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5680 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5681 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5682 }
5683 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5684 }
5685 if (!safenav_call) {
5686 ADD_INSN(lhs, line_node, pop);
5687 if (argc != 1) {
5688 ADD_INSN(lhs, line_node, pop);
5689 }
5690 }
5691 for (int i=0; i < argc; i++) {
5692 ADD_INSN(post, line_node, pop);
5693 }
5694 break;
5695 }
5696 case NODE_MASGN: {
5697 DECL_ANCHOR(nest_rhs);
5698 INIT_ANCHOR(nest_rhs);
5699 DECL_ANCHOR(nest_lhs);
5700 INIT_ANCHOR(nest_lhs);
5701
5702 int prev_level = state->lhs_level;
5703 bool prev_nested = state->nested;
5704 state->nested = 1;
5705 state->lhs_level = lhs_pos - 1;
5706 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5707 state->lhs_level = prev_level;
5708 state->nested = prev_nested;
5709
5710 ADD_SEQ(lhs, nest_rhs);
5711 ADD_SEQ(lhs, nest_lhs);
5712 break;
5713 }
5714 case NODE_CDECL:
5715 if (!RNODE_CDECL(node)->nd_vid) {
5716 /* Special handling only needed for expr::C, not for C */
5717 INSN *iobj;
5718
5719 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5720
5721 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5722 iobj = (INSN *)insn_element; /* setconstant insn */
5723 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5724 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5725 ELEM_REMOVE(insn_element);
5726 pre->last = iobj->link.prev;
5727 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5728
5729 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5730 return COMPILE_NG;
5731 }
5732
5733 ADD_INSN(post, node, pop);
5734 break;
5735 }
5736 /* Fallthrough */
5737 default: {
5738 DECL_ANCHOR(anchor);
5739 INIT_ANCHOR(anchor);
5740 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5741 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5742 ADD_SEQ(lhs, anchor);
5743 }
5744 }
5745
5746 return COMPILE_OK;
5747}
5748
5749static int
5750compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5751{
5752 if (lhsn) {
5753 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5754 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5755 }
5756 return COMPILE_OK;
5757}
5758
5759static int
5760compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5761 const NODE *rhsn, const NODE *orig_lhsn)
5762{
5763 VALUE mem[64];
5764 const int memsize = numberof(mem);
5765 int memindex = 0;
5766 int llen = 0, rlen = 0;
5767 int i;
5768 const NODE *lhsn = orig_lhsn;
5769
5770#define MEMORY(v) { \
5771 int i; \
5772 if (memindex == memsize) return 0; \
5773 for (i=0; i<memindex; i++) { \
5774 if (mem[i] == (v)) return 0; \
5775 } \
5776 mem[memindex++] = (v); \
5777}
5778
5779 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5780 return 0;
5781 }
5782
5783 while (lhsn) {
5784 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5785 switch (nd_type(ln)) {
5786 case NODE_LASGN:
5787 case NODE_DASGN:
5788 case NODE_IASGN:
5789 case NODE_CVASGN:
5790 MEMORY(get_nd_vid(ln));
5791 break;
5792 default:
5793 return 0;
5794 }
5795 lhsn = RNODE_LIST(lhsn)->nd_next;
5796 llen++;
5797 }
5798
5799 while (rhsn) {
5800 if (llen <= rlen) {
5801 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5802 }
5803 else {
5804 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5805 }
5806 rhsn = RNODE_LIST(rhsn)->nd_next;
5807 rlen++;
5808 }
5809
5810 if (llen > rlen) {
5811 for (i=0; i<llen-rlen; i++) {
5812 ADD_INSN(ret, orig_lhsn, putnil);
5813 }
5814 }
5815
5816 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5817 return 1;
5818}
5819
5820static int
5821compile_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)
5822{
5823 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5824 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5825 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5826 const NODE *lhsn_count = lhsn;
5827 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5828
5829 int llen = 0;
5830 int lpos = 0;
5831
5832 while (lhsn_count) {
5833 llen++;
5834 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5835 }
5836 while (lhsn) {
5837 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5838 lpos++;
5839 lhsn = RNODE_LIST(lhsn)->nd_next;
5840 }
5841
5842 if (lhs_splat) {
5843 if (nd_type_p(splatn, NODE_POSTARG)) {
5844 /*a, b, *r, p1, p2 */
5845 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5846 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5847 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5848 int ppos = 0;
5849 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5850
5851 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5852
5853 if (NODE_NAMED_REST_P(restn)) {
5854 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5855 }
5856 while (postn) {
5857 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5858 ppos++;
5859 postn = RNODE_LIST(postn)->nd_next;
5860 }
5861 }
5862 else {
5863 /* a, b, *r */
5864 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5865 }
5866 }
5867
5868 if (!state->nested) {
5869 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5870 }
5871
5872 if (!popped) {
5873 ADD_INSN(rhs, node, dup);
5874 }
5875 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5876 return COMPILE_OK;
5877}
5878
5879static int
5880compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5881{
5882 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5883 struct masgn_state state;
5884 state.lhs_level = popped ? 0 : 1;
5885 state.nested = 0;
5886 state.num_args = 0;
5887 state.first_memo = NULL;
5888 state.last_memo = NULL;
5889
5890 DECL_ANCHOR(pre);
5891 INIT_ANCHOR(pre);
5892 DECL_ANCHOR(rhs);
5893 INIT_ANCHOR(rhs);
5894 DECL_ANCHOR(lhs);
5895 INIT_ANCHOR(lhs);
5896 DECL_ANCHOR(post);
5897 INIT_ANCHOR(post);
5898 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5899
5900 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5901 while (memo) {
5902 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5903 for (int i = 0; i < memo->num_args; i++) {
5904 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5905 }
5906 tmp_memo = memo->next;
5907 free(memo);
5908 memo = tmp_memo;
5909 }
5910 CHECK(ok);
5911
5912 ADD_SEQ(ret, pre);
5913 ADD_SEQ(ret, rhs);
5914 ADD_SEQ(ret, lhs);
5915 if (!popped && state.num_args >= 1) {
5916 /* make sure rhs array is returned before popping */
5917 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5918 }
5919 ADD_SEQ(ret, post);
5920 }
5921 return COMPILE_OK;
5922}
5923
5924static VALUE
5925collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5926{
5927 VALUE arr = rb_ary_new();
5928 for (;;) {
5929 switch (nd_type(node)) {
5930 case NODE_CONST:
5931 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5932 return arr;
5933 case NODE_COLON3:
5934 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5935 rb_ary_unshift(arr, ID2SYM(idNULL));
5936 return arr;
5937 case NODE_COLON2:
5938 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5939 node = RNODE_COLON2(node)->nd_head;
5940 break;
5941 default:
5942 return Qfalse;
5943 }
5944 }
5945}
5946
5947static int
5948compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5949 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5950{
5951 switch (nd_type(node)) {
5952 case NODE_CONST:
5953 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5954 ADD_INSN1(body, node, putobject, Qtrue);
5955 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5956 break;
5957 case NODE_COLON3:
5958 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5959 ADD_INSN(body, node, pop);
5960 ADD_INSN1(body, node, putobject, rb_cObject);
5961 ADD_INSN1(body, node, putobject, Qtrue);
5962 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5963 break;
5964 case NODE_COLON2:
5965 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5966 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5967 ADD_INSN1(body, node, putobject, Qfalse);
5968 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5969 break;
5970 default:
5971 CHECK(COMPILE(pref, "const colon2 prefix", node));
5972 break;
5973 }
5974 return COMPILE_OK;
5975}
5976
5977static int
5978compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5979{
5980 if (nd_type_p(cpath, NODE_COLON3)) {
5981 /* toplevel class ::Foo */
5982 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5983 return VM_DEFINECLASS_FLAG_SCOPED;
5984 }
5985 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5986 /* Bar::Foo */
5987 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5988 return VM_DEFINECLASS_FLAG_SCOPED;
5989 }
5990 else {
5991 /* class at cbase Foo */
5992 ADD_INSN1(ret, cpath, putspecialobject,
5993 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5994 return 0;
5995 }
5996}
5997
5998static inline int
5999private_recv_p(const NODE *node)
6000{
6001 NODE *recv = get_nd_recv(node);
6002 if (recv && nd_type_p(recv, NODE_SELF)) {
6003 return RNODE_SELF(recv)->nd_state != 0;
6004 }
6005 return 0;
6006}
6007
6008static void
6009defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6010 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6011
6012static int
6013compile_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);
6014
6015static void
6016defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6017 const NODE *const node, LABEL **lfinish, VALUE needstr,
6018 bool keep_result)
6019{
6020 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6021 enum node_type type;
6022 const int line = nd_line(node);
6023 const NODE *line_node = node;
6024
6025 switch (type = nd_type(node)) {
6026
6027 /* easy literals */
6028 case NODE_NIL:
6029 expr_type = DEFINED_NIL;
6030 break;
6031 case NODE_SELF:
6032 expr_type = DEFINED_SELF;
6033 break;
6034 case NODE_TRUE:
6035 expr_type = DEFINED_TRUE;
6036 break;
6037 case NODE_FALSE:
6038 expr_type = DEFINED_FALSE;
6039 break;
6040
6041 case NODE_HASH:
6042 case NODE_LIST:{
6043 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6044
6045 if (vals) {
6046 do {
6047 if (RNODE_LIST(vals)->nd_head) {
6048 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6049
6050 if (!lfinish[1]) {
6051 lfinish[1] = NEW_LABEL(line);
6052 }
6053 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6054 }
6055 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6056 }
6057 }
6058 /* fall through */
6059 case NODE_STR:
6060 case NODE_SYM:
6061 case NODE_REGX:
6062 case NODE_LINE:
6063 case NODE_FILE:
6064 case NODE_ENCODING:
6065 case NODE_INTEGER:
6066 case NODE_FLOAT:
6067 case NODE_RATIONAL:
6068 case NODE_IMAGINARY:
6069 case NODE_ZLIST:
6070 case NODE_AND:
6071 case NODE_OR:
6072 default:
6073 expr_type = DEFINED_EXPR;
6074 break;
6075
6076 case NODE_SPLAT:
6077 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6078 if (!lfinish[1]) {
6079 lfinish[1] = NEW_LABEL(line);
6080 }
6081 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6082 expr_type = DEFINED_EXPR;
6083 break;
6084
6085 /* variables */
6086 case NODE_LVAR:
6087 case NODE_DVAR:
6088 expr_type = DEFINED_LVAR;
6089 break;
6090
6091#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6092 case NODE_IVAR:
6093 ADD_INSN3(ret, line_node, definedivar,
6094 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6095 return;
6096
6097 case NODE_GVAR:
6098 ADD_INSN(ret, line_node, putnil);
6099 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6100 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6101 return;
6102
6103 case NODE_CVAR:
6104 ADD_INSN(ret, line_node, putnil);
6105 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6106 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6107 return;
6108
6109 case NODE_CONST:
6110 ADD_INSN(ret, line_node, putnil);
6111 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6112 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6113 return;
6114 case NODE_COLON2:
6115 if (!lfinish[1]) {
6116 lfinish[1] = NEW_LABEL(line);
6117 }
6118 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6119 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6120 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6121
6122 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6123 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6124 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6125 }
6126 else {
6127 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6128 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6129 }
6130 return;
6131 case NODE_COLON3:
6132 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6133 ADD_INSN3(ret, line_node, defined,
6134 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6135 return;
6136
6137 /* method dispatch */
6138 case NODE_CALL:
6139 case NODE_OPCALL:
6140 case NODE_VCALL:
6141 case NODE_FCALL:
6142 case NODE_ATTRASGN:{
6143 const int explicit_receiver =
6144 (type == NODE_CALL || type == NODE_OPCALL ||
6145 (type == NODE_ATTRASGN && !private_recv_p(node)));
6146
6147 if (get_nd_args(node) || explicit_receiver) {
6148 if (!lfinish[1]) {
6149 lfinish[1] = NEW_LABEL(line);
6150 }
6151 if (!lfinish[2]) {
6152 lfinish[2] = NEW_LABEL(line);
6153 }
6154 }
6155 if (get_nd_args(node)) {
6156 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6157 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6158 }
6159 if (explicit_receiver) {
6160 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6161 switch (nd_type(get_nd_recv(node))) {
6162 case NODE_CALL:
6163 case NODE_OPCALL:
6164 case NODE_VCALL:
6165 case NODE_FCALL:
6166 case NODE_ATTRASGN:
6167 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6168 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6169 break;
6170 default:
6171 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6172 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6173 break;
6174 }
6175 if (keep_result) {
6176 ADD_INSN(ret, line_node, dup);
6177 }
6178 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6179 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6180 }
6181 else {
6182 ADD_INSN(ret, line_node, putself);
6183 if (keep_result) {
6184 ADD_INSN(ret, line_node, dup);
6185 }
6186 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6187 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6188 }
6189 return;
6190 }
6191
6192 case NODE_YIELD:
6193 ADD_INSN(ret, line_node, putnil);
6194 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6195 PUSH_VAL(DEFINED_YIELD));
6196 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6197 return;
6198
6199 case NODE_BACK_REF:
6200 case NODE_NTH_REF:
6201 ADD_INSN(ret, line_node, putnil);
6202 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6203 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6204 PUSH_VAL(DEFINED_GVAR));
6205 return;
6206
6207 case NODE_SUPER:
6208 case NODE_ZSUPER:
6209 ADD_INSN(ret, line_node, putnil);
6210 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6211 PUSH_VAL(DEFINED_ZSUPER));
6212 return;
6213
6214#undef PUSH_VAL
6215 case NODE_OP_ASGN1:
6216 case NODE_OP_ASGN2:
6217 case NODE_OP_ASGN_OR:
6218 case NODE_OP_ASGN_AND:
6219 case NODE_MASGN:
6220 case NODE_LASGN:
6221 case NODE_DASGN:
6222 case NODE_GASGN:
6223 case NODE_IASGN:
6224 case NODE_CDECL:
6225 case NODE_CVASGN:
6226 case NODE_OP_CDECL:
6227 expr_type = DEFINED_ASGN;
6228 break;
6229 }
6230
6231 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6232
6233 if (needstr != Qfalse) {
6234 VALUE str = rb_iseq_defined_string(expr_type);
6235 ADD_INSN1(ret, line_node, putobject, str);
6236 }
6237 else {
6238 ADD_INSN1(ret, line_node, putobject, Qtrue);
6239 }
6240}
6241
6242static void
6243build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6244{
6245 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6246 iseq_set_exception_local_table(iseq);
6247}
6248
6249static void
6250defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6251 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6252{
6253 LINK_ELEMENT *lcur = ret->last;
6254 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6255 if (lfinish[1]) {
6256 int line = nd_line(node);
6257 LABEL *lstart = NEW_LABEL(line);
6258 LABEL *lend = NEW_LABEL(line);
6259 const rb_iseq_t *rescue;
6261 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6262 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6263 rb_str_concat(rb_str_new2("defined guard in "),
6264 ISEQ_BODY(iseq)->location.label),
6265 ISEQ_TYPE_RESCUE, 0);
6266 lstart->rescued = LABEL_RESCUE_BEG;
6267 lend->rescued = LABEL_RESCUE_END;
6268 APPEND_LABEL(ret, lcur, lstart);
6269 ADD_LABEL(ret, lend);
6270 if (!ignore) {
6271 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6272 }
6273 }
6274}
6275
6276static int
6277compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6278{
6279 const int line = nd_line(node);
6280 const NODE *line_node = node;
6281 if (!RNODE_DEFINED(node)->nd_head) {
6282 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6283 ADD_INSN1(ret, line_node, putobject, str);
6284 }
6285 else {
6286 LABEL *lfinish[3];
6287 LINK_ELEMENT *last = ret->last;
6288 lfinish[0] = NEW_LABEL(line);
6289 lfinish[1] = 0;
6290 lfinish[2] = 0;
6291 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6292 if (lfinish[1]) {
6293 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6294 ADD_INSN(ret, line_node, swap);
6295 if (lfinish[2]) {
6296 ADD_LABEL(ret, lfinish[2]);
6297 }
6298 ADD_INSN(ret, line_node, pop);
6299 ADD_LABEL(ret, lfinish[1]);
6300 }
6301 ADD_LABEL(ret, lfinish[0]);
6302 }
6303 return COMPILE_OK;
6304}
6305
6306static VALUE
6307make_name_for_block(const rb_iseq_t *orig_iseq)
6308{
6309 int level = 1;
6310 const rb_iseq_t *iseq = orig_iseq;
6311
6312 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6313 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6314 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6315 level++;
6316 }
6317 iseq = ISEQ_BODY(iseq)->parent_iseq;
6318 }
6319 }
6320
6321 if (level == 1) {
6322 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6323 }
6324 else {
6325 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6326 }
6327}
6328
6329static void
6330push_ensure_entry(rb_iseq_t *iseq,
6332 struct ensure_range *er, const void *const node)
6333{
6334 enl->ensure_node = node;
6335 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6336 enl->erange = er;
6337 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6338}
6339
6340static void
6341add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6342 LABEL *lstart, LABEL *lend)
6343{
6344 struct ensure_range *ne =
6345 compile_data_alloc(iseq, sizeof(struct ensure_range));
6346
6347 while (erange->next != 0) {
6348 erange = erange->next;
6349 }
6350 ne->next = 0;
6351 ne->begin = lend;
6352 ne->end = erange->end;
6353 erange->end = lstart;
6354
6355 erange->next = ne;
6356}
6357
6358static bool
6359can_add_ensure_iseq(const rb_iseq_t *iseq)
6360{
6362 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6363 while (e) {
6364 if (e->ensure_node) return false;
6365 e = e->prev;
6366 }
6367 }
6368 return true;
6369}
6370
6371static void
6372add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6373{
6374 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6375
6377 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6378 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6379 DECL_ANCHOR(ensure);
6380
6381 INIT_ANCHOR(ensure);
6382 while (enlp) {
6383 if (enlp->erange != NULL) {
6384 DECL_ANCHOR(ensure_part);
6385 LABEL *lstart = NEW_LABEL(0);
6386 LABEL *lend = NEW_LABEL(0);
6387 INIT_ANCHOR(ensure_part);
6388
6389 add_ensure_range(iseq, enlp->erange, lstart, lend);
6390
6391 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6392 ADD_LABEL(ensure_part, lstart);
6393 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6394 ADD_LABEL(ensure_part, lend);
6395 ADD_SEQ(ensure, ensure_part);
6396 }
6397 else {
6398 if (!is_return) {
6399 break;
6400 }
6401 }
6402 enlp = enlp->prev;
6403 }
6404 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6405 ADD_SEQ(ret, ensure);
6406}
6407
6408#if RUBY_DEBUG
6409static int
6410check_keyword(const NODE *node)
6411{
6412 /* This check is essentially a code clone of compile_keyword_arg. */
6413
6414 if (nd_type_p(node, NODE_LIST)) {
6415 while (RNODE_LIST(node)->nd_next) {
6416 node = RNODE_LIST(node)->nd_next;
6417 }
6418 node = RNODE_LIST(node)->nd_head;
6419 }
6420
6421 return keyword_node_p(node);
6422}
6423#endif
6424
6425static bool
6426keyword_node_single_splat_p(NODE *kwnode)
6427{
6428 RUBY_ASSERT(keyword_node_p(kwnode));
6429
6430 NODE *node = RNODE_HASH(kwnode)->nd_head;
6431 return RNODE_LIST(node)->nd_head == NULL &&
6432 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6433}
6434
6435static void
6436compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6437 NODE *kwnode, unsigned int *flag_ptr)
6438{
6439 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6440 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6441 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6442 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6443 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6444}
6445
6446#define SPLATARRAY_FALSE 0
6447#define SPLATARRAY_TRUE 1
6448#define DUP_SINGLE_KW_SPLAT 2
6449
6450static int
6451setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6452 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6453{
6454 if (!argn) return 0;
6455
6456 NODE *kwnode = NULL;
6457
6458 switch (nd_type(argn)) {
6459 case NODE_LIST: {
6460 // f(x, y, z)
6461 int len = compile_args(iseq, args, argn, &kwnode);
6462 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6463
6464 if (kwnode) {
6465 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6466 len -= 1;
6467 }
6468 else {
6469 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6470 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6471 }
6472 else {
6473 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6474 }
6475 }
6476 }
6477
6478 return len;
6479 }
6480 case NODE_SPLAT: {
6481 // f(*a)
6482 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6483 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6484 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6485 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6486 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6487 return 1;
6488 }
6489 case NODE_ARGSCAT: {
6490 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6491 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6492 bool args_pushed = false;
6493
6494 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6495 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6496 if (kwnode) rest_len--;
6497 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6498 args_pushed = true;
6499 }
6500 else {
6501 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6502 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6503 }
6504
6505 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6506 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6507 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6508 argc += 1;
6509 }
6510 else if (!args_pushed) {
6511 ADD_INSN(args, argn, concattoarray);
6512 }
6513
6514 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6515 if (kwnode) {
6516 // kwsplat
6517 *flag_ptr |= VM_CALL_KW_SPLAT;
6518 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6519 argc += 1;
6520 }
6521
6522 return argc;
6523 }
6524 case NODE_ARGSPUSH: {
6525 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6526 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6527
6528 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6529 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6530 if (kwnode) rest_len--;
6531 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6532 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6533 }
6534 else {
6535 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6536 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6537 }
6538 else {
6539 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6540 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6541 }
6542 }
6543
6544 if (kwnode) {
6545 // f(*a, k:1)
6546 *flag_ptr |= VM_CALL_KW_SPLAT;
6547 if (!keyword_node_single_splat_p(kwnode)) {
6548 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6549 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6550 }
6551 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6552 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6553 }
6554 else {
6555 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6556 }
6557 argc += 1;
6558 }
6559
6560 return argc;
6561 }
6562 default: {
6563 UNKNOWN_NODE("setup_arg", argn, Qnil);
6564 }
6565 }
6566}
6567
6568static void
6569setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6570{
6571 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6572 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6573 }
6574}
6575
6576static bool
6577setup_args_dup_rest_p(const NODE *argn)
6578{
6579 switch(nd_type(argn)) {
6580 case NODE_LVAR:
6581 case NODE_DVAR:
6582 case NODE_GVAR:
6583 case NODE_IVAR:
6584 case NODE_CVAR:
6585 case NODE_CONST:
6586 case NODE_COLON3:
6587 case NODE_INTEGER:
6588 case NODE_FLOAT:
6589 case NODE_RATIONAL:
6590 case NODE_IMAGINARY:
6591 case NODE_STR:
6592 case NODE_SYM:
6593 case NODE_REGX:
6594 case NODE_SELF:
6595 case NODE_NIL:
6596 case NODE_TRUE:
6597 case NODE_FALSE:
6598 case NODE_LAMBDA:
6599 case NODE_NTH_REF:
6600 case NODE_BACK_REF:
6601 return false;
6602 case NODE_COLON2:
6603 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6604 default:
6605 return true;
6606 }
6607}
6608
6609static VALUE
6610setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6611 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6612{
6613 VALUE ret;
6614 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6615
6616 if (argn) {
6617 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6618 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6619
6620 if (check_arg) {
6621 switch(nd_type(check_arg)) {
6622 case(NODE_SPLAT):
6623 // avoid caller side array allocation for f(*arg)
6624 dup_rest = SPLATARRAY_FALSE;
6625 break;
6626 case(NODE_ARGSCAT):
6627 // avoid caller side array allocation for f(1, *arg)
6628 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6629 break;
6630 case(NODE_ARGSPUSH):
6631 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6632 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6633 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6634 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6635 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6636 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6637
6638 if (dup_rest == SPLATARRAY_FALSE) {
6639 // require allocation for keyword key/value/splat that may modify splatted argument
6640 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6641 while (node) {
6642 NODE *key_node = RNODE_LIST(node)->nd_head;
6643 if (key_node && setup_args_dup_rest_p(key_node)) {
6644 dup_rest = SPLATARRAY_TRUE;
6645 break;
6646 }
6647
6648 node = RNODE_LIST(node)->nd_next;
6649 NODE *value_node = RNODE_LIST(node)->nd_head;
6650 if (setup_args_dup_rest_p(value_node)) {
6651 dup_rest = SPLATARRAY_TRUE;
6652 break;
6653 }
6654
6655 node = RNODE_LIST(node)->nd_next;
6656 }
6657 }
6658 break;
6659 default:
6660 break;
6661 }
6662 }
6663
6664 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6665 // for block pass that may modify splatted argument, dup rest and kwrest if given
6666 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6667 }
6668 }
6669 initial_dup_rest = dup_rest;
6670
6671 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6672 DECL_ANCHOR(arg_block);
6673 INIT_ANCHOR(arg_block);
6674
6675 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6676 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6677
6678 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6679 const NODE * arg_node =
6680 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6681
6682 int argc = 0;
6683
6684 // Only compile leading args:
6685 // foo(x, y, ...)
6686 // ^^^^
6687 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6688 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6689 }
6690
6691 *flag |= VM_CALL_FORWARDING;
6692
6693 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6694 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6695 return INT2FIX(argc);
6696 }
6697 else {
6698 *flag |= VM_CALL_ARGS_BLOCKARG;
6699
6700 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6701 }
6702
6703 if (LIST_INSN_SIZE_ONE(arg_block)) {
6704 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6705 if (IS_INSN(elem)) {
6706 INSN *iobj = (INSN *)elem;
6707 if (iobj->insn_id == BIN(getblockparam)) {
6708 iobj->insn_id = BIN(getblockparamproxy);
6709 }
6710 }
6711 }
6712 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6713 ADD_SEQ(args, arg_block);
6714 }
6715 else {
6716 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6717 }
6718 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6719 return ret;
6720}
6721
6722static void
6723build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6724{
6725 const NODE *body = ptr;
6726 int line = nd_line(body);
6727 VALUE argc = INT2FIX(0);
6728 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6729
6730 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6731 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6732 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6733 iseq_set_local_table(iseq, 0, 0);
6734}
6735
6736static void
6737compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6738{
6739 const NODE *vars;
6740 LINK_ELEMENT *last;
6741 int line = nd_line(node);
6742 const NODE *line_node = node;
6743 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6744
6745#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6746 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6747#else
6748 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6749#endif
6750 ADD_INSN(ret, line_node, dup);
6751 ADD_INSNL(ret, line_node, branchunless, fail_label);
6752
6753 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6754 INSN *cap;
6755 if (RNODE_BLOCK(vars)->nd_next) {
6756 ADD_INSN(ret, line_node, dup);
6757 }
6758 last = ret->last;
6759 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6760 last = last->next; /* putobject :var */
6761 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6762 NULL, INT2FIX(0), NULL);
6763 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6764#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6765 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6766 /* only one name */
6767 DECL_ANCHOR(nom);
6768
6769 INIT_ANCHOR(nom);
6770 ADD_INSNL(nom, line_node, jump, end_label);
6771 ADD_LABEL(nom, fail_label);
6772# if 0 /* $~ must be MatchData or nil */
6773 ADD_INSN(nom, line_node, pop);
6774 ADD_INSN(nom, line_node, putnil);
6775# endif
6776 ADD_LABEL(nom, end_label);
6777 (nom->last->next = cap->link.next)->prev = nom->last;
6778 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6779 return;
6780 }
6781#endif
6782 }
6783 ADD_INSNL(ret, line_node, jump, end_label);
6784 ADD_LABEL(ret, fail_label);
6785 ADD_INSN(ret, line_node, pop);
6786 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6787 last = ret->last;
6788 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6789 last = last->next; /* putobject :var */
6790 ((INSN*)last)->insn_id = BIN(putnil);
6791 ((INSN*)last)->operand_size = 0;
6792 }
6793 ADD_LABEL(ret, end_label);
6794}
6795
6796static int
6797optimizable_range_item_p(const NODE *n)
6798{
6799 if (!n) return FALSE;
6800 switch (nd_type(n)) {
6801 case NODE_LINE:
6802 return TRUE;
6803 case NODE_INTEGER:
6804 return TRUE;
6805 case NODE_NIL:
6806 return TRUE;
6807 default:
6808 return FALSE;
6809 }
6810}
6811
6812static VALUE
6813optimized_range_item(const NODE *n)
6814{
6815 switch (nd_type(n)) {
6816 case NODE_LINE:
6817 return rb_node_line_lineno_val(n);
6818 case NODE_INTEGER:
6819 return rb_node_integer_literal_val(n);
6820 case NODE_FLOAT:
6821 return rb_node_float_literal_val(n);
6822 case NODE_RATIONAL:
6823 return rb_node_rational_literal_val(n);
6824 case NODE_IMAGINARY:
6825 return rb_node_imaginary_literal_val(n);
6826 case NODE_NIL:
6827 return Qnil;
6828 default:
6829 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6830 }
6831}
6832
6833static int
6834compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6835{
6836 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6837 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6838
6839 const int line = nd_line(node);
6840 const NODE *line_node = node;
6841 DECL_ANCHOR(cond_seq);
6842 LABEL *then_label, *else_label, *end_label;
6843 VALUE branches = Qfalse;
6844
6845 INIT_ANCHOR(cond_seq);
6846 then_label = NEW_LABEL(line);
6847 else_label = NEW_LABEL(line);
6848 end_label = 0;
6849
6850 NODE *cond = RNODE_IF(node)->nd_cond;
6851 if (nd_type(cond) == NODE_BLOCK) {
6852 cond = RNODE_BLOCK(cond)->nd_head;
6853 }
6854
6855 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6856 ADD_SEQ(ret, cond_seq);
6857
6858 if (then_label->refcnt && else_label->refcnt) {
6859 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6860 }
6861
6862 if (then_label->refcnt) {
6863 ADD_LABEL(ret, then_label);
6864
6865 DECL_ANCHOR(then_seq);
6866 INIT_ANCHOR(then_seq);
6867 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6868
6869 if (else_label->refcnt) {
6870 const NODE *const coverage_node = node_body ? node_body : node;
6871 add_trace_branch_coverage(
6872 iseq,
6873 ret,
6874 nd_code_loc(coverage_node),
6875 nd_node_id(coverage_node),
6876 0,
6877 type == NODE_IF ? "then" : "else",
6878 branches);
6879 end_label = NEW_LABEL(line);
6880 ADD_INSNL(then_seq, line_node, jump, end_label);
6881 if (!popped) {
6882 ADD_INSN(then_seq, line_node, pop);
6883 }
6884 }
6885 ADD_SEQ(ret, then_seq);
6886 }
6887
6888 if (else_label->refcnt) {
6889 ADD_LABEL(ret, else_label);
6890
6891 DECL_ANCHOR(else_seq);
6892 INIT_ANCHOR(else_seq);
6893 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6894
6895 if (then_label->refcnt) {
6896 const NODE *const coverage_node = node_else ? node_else : node;
6897 add_trace_branch_coverage(
6898 iseq,
6899 ret,
6900 nd_code_loc(coverage_node),
6901 nd_node_id(coverage_node),
6902 1,
6903 type == NODE_IF ? "else" : "then",
6904 branches);
6905 }
6906 ADD_SEQ(ret, else_seq);
6907 }
6908
6909 if (end_label) {
6910 ADD_LABEL(ret, end_label);
6911 }
6912
6913 return COMPILE_OK;
6914}
6915
6916static int
6917compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6918{
6919 const NODE *vals;
6920 const NODE *node = orig_node;
6921 LABEL *endlabel, *elselabel;
6922 DECL_ANCHOR(head);
6923 DECL_ANCHOR(body_seq);
6924 DECL_ANCHOR(cond_seq);
6925 int only_special_literals = 1;
6926 VALUE literals = rb_hash_new();
6927 int line;
6928 enum node_type type;
6929 const NODE *line_node;
6930 VALUE branches = Qfalse;
6931 int branch_id = 0;
6932
6933 INIT_ANCHOR(head);
6934 INIT_ANCHOR(body_seq);
6935 INIT_ANCHOR(cond_seq);
6936
6937 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6938
6939 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6940
6941 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6942
6943 node = RNODE_CASE(node)->nd_body;
6944 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6945 type = nd_type(node);
6946 line = nd_line(node);
6947 line_node = node;
6948
6949 endlabel = NEW_LABEL(line);
6950 elselabel = NEW_LABEL(line);
6951
6952 ADD_SEQ(ret, head); /* case VAL */
6953
6954 while (type == NODE_WHEN) {
6955 LABEL *l1;
6956
6957 l1 = NEW_LABEL(line);
6958 ADD_LABEL(body_seq, l1);
6959 ADD_INSN(body_seq, line_node, pop);
6960
6961 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6962 add_trace_branch_coverage(
6963 iseq,
6964 body_seq,
6965 nd_code_loc(coverage_node),
6966 nd_node_id(coverage_node),
6967 branch_id++,
6968 "when",
6969 branches);
6970
6971 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
6972 ADD_INSNL(body_seq, line_node, jump, endlabel);
6973
6974 vals = RNODE_WHEN(node)->nd_head;
6975 if (vals) {
6976 switch (nd_type(vals)) {
6977 case NODE_LIST:
6978 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6979 if (only_special_literals < 0) return COMPILE_NG;
6980 break;
6981 case NODE_SPLAT:
6982 case NODE_ARGSCAT:
6983 case NODE_ARGSPUSH:
6984 only_special_literals = 0;
6985 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6986 break;
6987 default:
6988 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6989 }
6990 }
6991 else {
6992 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6993 }
6994
6995 node = RNODE_WHEN(node)->nd_next;
6996 if (!node) {
6997 break;
6998 }
6999 type = nd_type(node);
7000 line = nd_line(node);
7001 line_node = node;
7002 }
7003 /* else */
7004 if (node) {
7005 ADD_LABEL(cond_seq, elselabel);
7006 ADD_INSN(cond_seq, line_node, pop);
7007 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7008 CHECK(COMPILE_(cond_seq, "else", node, popped));
7009 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7010 }
7011 else {
7012 debugs("== else (implicit)\n");
7013 ADD_LABEL(cond_seq, elselabel);
7014 ADD_INSN(cond_seq, orig_node, pop);
7015 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7016 if (!popped) {
7017 ADD_INSN(cond_seq, orig_node, putnil);
7018 }
7019 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7020 }
7021
7022 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7023 ADD_INSN(ret, orig_node, dup);
7024 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7025 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7026 LABEL_REF(elselabel);
7027 }
7028
7029 ADD_SEQ(ret, cond_seq);
7030 ADD_SEQ(ret, body_seq);
7031 ADD_LABEL(ret, endlabel);
7032 return COMPILE_OK;
7033}
7034
7035static int
7036compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7037{
7038 const NODE *vals;
7039 const NODE *val;
7040 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7041 LABEL *endlabel;
7042 DECL_ANCHOR(body_seq);
7043 VALUE branches = Qfalse;
7044 int branch_id = 0;
7045
7046 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7047
7048 INIT_ANCHOR(body_seq);
7049 endlabel = NEW_LABEL(nd_line(node));
7050
7051 while (node && nd_type_p(node, NODE_WHEN)) {
7052 const int line = nd_line(node);
7053 LABEL *l1 = NEW_LABEL(line);
7054 ADD_LABEL(body_seq, l1);
7055
7056 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7057 add_trace_branch_coverage(
7058 iseq,
7059 body_seq,
7060 nd_code_loc(coverage_node),
7061 nd_node_id(coverage_node),
7062 branch_id++,
7063 "when",
7064 branches);
7065
7066 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7067 ADD_INSNL(body_seq, node, jump, endlabel);
7068
7069 vals = RNODE_WHEN(node)->nd_head;
7070 if (!vals) {
7071 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7072 }
7073 switch (nd_type(vals)) {
7074 case NODE_LIST:
7075 while (vals) {
7076 LABEL *lnext;
7077 val = RNODE_LIST(vals)->nd_head;
7078 lnext = NEW_LABEL(nd_line(val));
7079 debug_compile("== when2\n", (void)0);
7080 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7081 ADD_LABEL(ret, lnext);
7082 vals = RNODE_LIST(vals)->nd_next;
7083 }
7084 break;
7085 case NODE_SPLAT:
7086 case NODE_ARGSCAT:
7087 case NODE_ARGSPUSH:
7088 ADD_INSN(ret, vals, putnil);
7089 CHECK(COMPILE(ret, "when2/cond splat", vals));
7090 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7091 ADD_INSNL(ret, vals, branchif, l1);
7092 break;
7093 default:
7094 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7095 }
7096 node = RNODE_WHEN(node)->nd_next;
7097 }
7098 /* else */
7099 const NODE *const coverage_node = node ? node : orig_node;
7100 add_trace_branch_coverage(
7101 iseq,
7102 ret,
7103 nd_code_loc(coverage_node),
7104 nd_node_id(coverage_node),
7105 branch_id,
7106 "else",
7107 branches);
7108 CHECK(COMPILE_(ret, "else", node, popped));
7109 ADD_INSNL(ret, orig_node, jump, endlabel);
7110
7111 ADD_SEQ(ret, body_seq);
7112 ADD_LABEL(ret, endlabel);
7113 return COMPILE_OK;
7114}
7115
7116static 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);
7117
7118static 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);
7119static 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);
7120static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7121static 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);
7122static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7123
7124#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7125#define CASE3_BI_OFFSET_ERROR_STRING 1
7126#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7127#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7128#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7129
7130static int
7131iseq_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)
7132{
7133 const int line = nd_line(node);
7134 const NODE *line_node = node;
7135
7136 switch (nd_type(node)) {
7137 case NODE_ARYPTN: {
7138 /*
7139 * if pattern.use_rest_num?
7140 * rest_num = 0
7141 * end
7142 * if pattern.has_constant_node?
7143 * unless pattern.constant === obj
7144 * goto match_failed
7145 * end
7146 * end
7147 * unless obj.respond_to?(:deconstruct)
7148 * goto match_failed
7149 * end
7150 * d = obj.deconstruct
7151 * unless Array === d
7152 * goto type_error
7153 * end
7154 * min_argc = pattern.pre_args_num + pattern.post_args_num
7155 * if pattern.has_rest_arg?
7156 * unless d.length >= min_argc
7157 * goto match_failed
7158 * end
7159 * else
7160 * unless d.length == min_argc
7161 * goto match_failed
7162 * end
7163 * end
7164 * pattern.pre_args_num.each do |i|
7165 * unless pattern.pre_args[i].match?(d[i])
7166 * goto match_failed
7167 * end
7168 * end
7169 * if pattern.use_rest_num?
7170 * rest_num = d.length - min_argc
7171 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7172 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7173 * goto match_failed
7174 * end
7175 * end
7176 * end
7177 * pattern.post_args_num.each do |i|
7178 * j = pattern.pre_args_num + i
7179 * j += rest_num
7180 * unless pattern.post_args[i].match?(d[j])
7181 * goto match_failed
7182 * end
7183 * end
7184 * goto matched
7185 * type_error:
7186 * FrozenCore.raise TypeError
7187 * match_failed:
7188 * goto unmatched
7189 */
7190 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7191 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7192 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7193
7194 const int min_argc = pre_args_num + post_args_num;
7195 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7196 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7197
7198 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7199 int i;
7200 match_failed = NEW_LABEL(line);
7201 type_error = NEW_LABEL(line);
7202 deconstruct = NEW_LABEL(line);
7203 deconstructed = NEW_LABEL(line);
7204
7205 if (use_rest_num) {
7206 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7207 ADD_INSN(ret, line_node, swap);
7208 if (base_index) {
7209 base_index++;
7210 }
7211 }
7212
7213 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7214
7215 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7216
7217 ADD_INSN(ret, line_node, dup);
7218 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7219 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7220 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7221 if (in_single_pattern) {
7222 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7223 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7224 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7225 INT2FIX(min_argc), base_index + 1 /* (1) */));
7226 }
7227 ADD_INSNL(ret, line_node, branchunless, match_failed);
7228
7229 for (i = 0; i < pre_args_num; i++) {
7230 ADD_INSN(ret, line_node, dup);
7231 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7232 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7233 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));
7234 args = RNODE_LIST(args)->nd_next;
7235 }
7236
7237 if (RNODE_ARYPTN(node)->rest_arg) {
7238 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7239 ADD_INSN(ret, line_node, dup);
7240 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7241 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7242 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7243 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7244 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7245 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7246 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7247
7248 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));
7249 }
7250 else {
7251 if (post_args_num > 0) {
7252 ADD_INSN(ret, line_node, dup);
7253 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7254 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7255 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7256 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7257 ADD_INSN(ret, line_node, pop);
7258 }
7259 }
7260 }
7261
7262 args = RNODE_ARYPTN(node)->post_args;
7263 for (i = 0; i < post_args_num; i++) {
7264 ADD_INSN(ret, line_node, dup);
7265
7266 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7267 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7268 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7269
7270 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7271 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));
7272 args = RNODE_LIST(args)->nd_next;
7273 }
7274
7275 ADD_INSN(ret, line_node, pop);
7276 if (use_rest_num) {
7277 ADD_INSN(ret, line_node, pop);
7278 }
7279 ADD_INSNL(ret, line_node, jump, matched);
7280 ADD_INSN(ret, line_node, putnil);
7281 if (use_rest_num) {
7282 ADD_INSN(ret, line_node, putnil);
7283 }
7284
7285 ADD_LABEL(ret, type_error);
7286 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7287 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7288 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7289 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7290 ADD_INSN(ret, line_node, pop);
7291
7292 ADD_LABEL(ret, match_failed);
7293 ADD_INSN(ret, line_node, pop);
7294 if (use_rest_num) {
7295 ADD_INSN(ret, line_node, pop);
7296 }
7297 ADD_INSNL(ret, line_node, jump, unmatched);
7298
7299 break;
7300 }
7301 case NODE_FNDPTN: {
7302 /*
7303 * if pattern.has_constant_node?
7304 * unless pattern.constant === obj
7305 * goto match_failed
7306 * end
7307 * end
7308 * unless obj.respond_to?(:deconstruct)
7309 * goto match_failed
7310 * end
7311 * d = obj.deconstruct
7312 * unless Array === d
7313 * goto type_error
7314 * end
7315 * unless d.length >= pattern.args_num
7316 * goto match_failed
7317 * end
7318 *
7319 * begin
7320 * len = d.length
7321 * limit = d.length - pattern.args_num
7322 * i = 0
7323 * while i <= limit
7324 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7325 * if pattern.has_pre_rest_arg_id
7326 * unless pattern.pre_rest_arg.match?(d[0, i])
7327 * goto find_failed
7328 * end
7329 * end
7330 * if pattern.has_post_rest_arg_id
7331 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7332 * goto find_failed
7333 * end
7334 * end
7335 * goto find_succeeded
7336 * end
7337 * i+=1
7338 * end
7339 * find_failed:
7340 * goto match_failed
7341 * find_succeeded:
7342 * end
7343 *
7344 * goto matched
7345 * type_error:
7346 * FrozenCore.raise TypeError
7347 * match_failed:
7348 * goto unmatched
7349 */
7350 const NODE *args = RNODE_FNDPTN(node)->args;
7351 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7352
7353 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7354 match_failed = NEW_LABEL(line);
7355 type_error = NEW_LABEL(line);
7356 deconstruct = NEW_LABEL(line);
7357 deconstructed = NEW_LABEL(line);
7358
7359 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7360
7361 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7362
7363 ADD_INSN(ret, line_node, dup);
7364 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7365 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7366 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7367 if (in_single_pattern) {
7368 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) */));
7369 }
7370 ADD_INSNL(ret, line_node, branchunless, match_failed);
7371
7372 {
7373 LABEL *while_begin = NEW_LABEL(nd_line(node));
7374 LABEL *next_loop = NEW_LABEL(nd_line(node));
7375 LABEL *find_succeeded = NEW_LABEL(line);
7376 LABEL *find_failed = NEW_LABEL(nd_line(node));
7377 int j;
7378
7379 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7380 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7381
7382 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7383 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7384 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7385
7386 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7387
7388 ADD_LABEL(ret, while_begin);
7389
7390 ADD_INSN(ret, line_node, dup);
7391 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7392 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7393 ADD_INSNL(ret, line_node, branchunless, find_failed);
7394
7395 for (j = 0; j < args_num; j++) {
7396 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7397 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7398 if (j != 0) {
7399 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7400 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7401 }
7402 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7403
7404 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));
7405 args = RNODE_LIST(args)->nd_next;
7406 }
7407
7408 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7409 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7410 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7411 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7412 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7413 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));
7414 }
7415 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7416 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7417 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7418 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7419 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7420 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7421 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7422 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));
7423 }
7424 ADD_INSNL(ret, line_node, jump, find_succeeded);
7425
7426 ADD_LABEL(ret, next_loop);
7427 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7428 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7429 ADD_INSNL(ret, line_node, jump, while_begin);
7430
7431 ADD_LABEL(ret, find_failed);
7432 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7433 if (in_single_pattern) {
7434 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7435 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7436 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7437 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7438 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7439
7440 ADD_INSN1(ret, line_node, putobject, Qfalse);
7441 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7442
7443 ADD_INSN(ret, line_node, pop);
7444 ADD_INSN(ret, line_node, pop);
7445 }
7446 ADD_INSNL(ret, line_node, jump, match_failed);
7447 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7448
7449 ADD_LABEL(ret, find_succeeded);
7450 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7451 }
7452
7453 ADD_INSN(ret, line_node, pop);
7454 ADD_INSNL(ret, line_node, jump, matched);
7455 ADD_INSN(ret, line_node, putnil);
7456
7457 ADD_LABEL(ret, type_error);
7458 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7459 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7460 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7461 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7462 ADD_INSN(ret, line_node, pop);
7463
7464 ADD_LABEL(ret, match_failed);
7465 ADD_INSN(ret, line_node, pop);
7466 ADD_INSNL(ret, line_node, jump, unmatched);
7467
7468 break;
7469 }
7470 case NODE_HSHPTN: {
7471 /*
7472 * keys = nil
7473 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7474 * keys = pattern.kw_args_node.keys
7475 * end
7476 * if pattern.has_constant_node?
7477 * unless pattern.constant === obj
7478 * goto match_failed
7479 * end
7480 * end
7481 * unless obj.respond_to?(:deconstruct_keys)
7482 * goto match_failed
7483 * end
7484 * d = obj.deconstruct_keys(keys)
7485 * unless Hash === d
7486 * goto type_error
7487 * end
7488 * if pattern.has_kw_rest_arg_node?
7489 * d = d.dup
7490 * end
7491 * if pattern.has_kw_args_node?
7492 * pattern.kw_args_node.each |k,|
7493 * unless d.key?(k)
7494 * goto match_failed
7495 * end
7496 * end
7497 * pattern.kw_args_node.each |k, pat|
7498 * if pattern.has_kw_rest_arg_node?
7499 * unless pat.match?(d.delete(k))
7500 * goto match_failed
7501 * end
7502 * else
7503 * unless pat.match?(d[k])
7504 * goto match_failed
7505 * end
7506 * end
7507 * end
7508 * else
7509 * unless d.empty?
7510 * goto match_failed
7511 * end
7512 * end
7513 * if pattern.has_kw_rest_arg_node?
7514 * if pattern.no_rest_keyword?
7515 * unless d.empty?
7516 * goto match_failed
7517 * end
7518 * else
7519 * unless pattern.kw_rest_arg_node.match?(d)
7520 * goto match_failed
7521 * end
7522 * end
7523 * end
7524 * goto matched
7525 * type_error:
7526 * FrozenCore.raise TypeError
7527 * match_failed:
7528 * goto unmatched
7529 */
7530 LABEL *match_failed, *type_error;
7531 VALUE keys = Qnil;
7532
7533 match_failed = NEW_LABEL(line);
7534 type_error = NEW_LABEL(line);
7535
7536 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7537 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7538 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7539 while (kw_args) {
7540 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7541 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7542 }
7543 }
7544
7545 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7546
7547 ADD_INSN(ret, line_node, dup);
7548 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7549 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7550 if (in_single_pattern) {
7551 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7552 }
7553 ADD_INSNL(ret, line_node, branchunless, match_failed);
7554
7555 if (NIL_P(keys)) {
7556 ADD_INSN(ret, line_node, putnil);
7557 }
7558 else {
7559 ADD_INSN1(ret, line_node, duparray, keys);
7560 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7561 }
7562 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7563
7564 ADD_INSN(ret, line_node, dup);
7565 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7566 ADD_INSNL(ret, line_node, branchunless, type_error);
7567
7568 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7569 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7570 }
7571
7572 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7573 int i;
7574 int keys_num;
7575 const NODE *args;
7576 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7577 if (args) {
7578 DECL_ANCHOR(match_values);
7579 INIT_ANCHOR(match_values);
7580 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7581 for (i = 0; i < keys_num; i++) {
7582 NODE *key_node = RNODE_LIST(args)->nd_head;
7583 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7584 VALUE key = get_symbol_value(iseq, key_node);
7585
7586 ADD_INSN(ret, line_node, dup);
7587 ADD_INSN1(ret, line_node, putobject, key);
7588 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7589 if (in_single_pattern) {
7590 LABEL *match_succeeded;
7591 match_succeeded = NEW_LABEL(line);
7592
7593 ADD_INSN(ret, line_node, dup);
7594 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7595
7596 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7597 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7598 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7599 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7600 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7601 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7602 ADD_INSN1(ret, line_node, putobject, key); // (7)
7603 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7604
7605 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7606
7607 ADD_LABEL(ret, match_succeeded);
7608 }
7609 ADD_INSNL(ret, line_node, branchunless, match_failed);
7610
7611 ADD_INSN(match_values, line_node, dup);
7612 ADD_INSN1(match_values, line_node, putobject, key);
7613 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7614 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7615 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7616 }
7617 ADD_SEQ(ret, match_values);
7618 }
7619 }
7620 else {
7621 ADD_INSN(ret, line_node, dup);
7622 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7623 if (in_single_pattern) {
7624 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7625 }
7626 ADD_INSNL(ret, line_node, branchunless, match_failed);
7627 }
7628
7629 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7630 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7631 ADD_INSN(ret, line_node, dup);
7632 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7633 if (in_single_pattern) {
7634 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7635 }
7636 ADD_INSNL(ret, line_node, branchunless, match_failed);
7637 }
7638 else {
7639 ADD_INSN(ret, line_node, dup); // (11)
7640 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));
7641 }
7642 }
7643
7644 ADD_INSN(ret, line_node, pop);
7645 ADD_INSNL(ret, line_node, jump, matched);
7646 ADD_INSN(ret, line_node, putnil);
7647
7648 ADD_LABEL(ret, type_error);
7649 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7650 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7651 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7652 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7653 ADD_INSN(ret, line_node, pop);
7654
7655 ADD_LABEL(ret, match_failed);
7656 ADD_INSN(ret, line_node, pop);
7657 ADD_INSNL(ret, line_node, jump, unmatched);
7658 break;
7659 }
7660 case NODE_SYM:
7661 case NODE_REGX:
7662 case NODE_LINE:
7663 case NODE_INTEGER:
7664 case NODE_FLOAT:
7665 case NODE_RATIONAL:
7666 case NODE_IMAGINARY:
7667 case NODE_FILE:
7668 case NODE_ENCODING:
7669 case NODE_STR:
7670 case NODE_XSTR:
7671 case NODE_DSTR:
7672 case NODE_DSYM:
7673 case NODE_DREGX:
7674 case NODE_LIST:
7675 case NODE_ZLIST:
7676 case NODE_LAMBDA:
7677 case NODE_DOT2:
7678 case NODE_DOT3:
7679 case NODE_CONST:
7680 case NODE_LVAR:
7681 case NODE_DVAR:
7682 case NODE_IVAR:
7683 case NODE_CVAR:
7684 case NODE_GVAR:
7685 case NODE_TRUE:
7686 case NODE_FALSE:
7687 case NODE_SELF:
7688 case NODE_NIL:
7689 case NODE_COLON2:
7690 case NODE_COLON3:
7691 case NODE_BEGIN:
7692 case NODE_BLOCK:
7693 case NODE_ONCE:
7694 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7695 if (in_single_pattern) {
7696 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7697 }
7698 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7699 if (in_single_pattern) {
7700 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7701 }
7702 ADD_INSNL(ret, line_node, branchif, matched);
7703 ADD_INSNL(ret, line_node, jump, unmatched);
7704 break;
7705 case NODE_LASGN: {
7706 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7707 ID id = RNODE_LASGN(node)->nd_vid;
7708 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7709
7710 if (in_alt_pattern) {
7711 const char *name = rb_id2name(id);
7712 if (name && strlen(name) > 0 && name[0] != '_') {
7713 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7714 rb_id2str(id));
7715 return COMPILE_NG;
7716 }
7717 }
7718
7719 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7720 ADD_INSNL(ret, line_node, jump, matched);
7721 break;
7722 }
7723 case NODE_DASGN: {
7724 int idx, lv, ls;
7725 ID id = RNODE_DASGN(node)->nd_vid;
7726
7727 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7728
7729 if (in_alt_pattern) {
7730 const char *name = rb_id2name(id);
7731 if (name && strlen(name) > 0 && name[0] != '_') {
7732 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7733 rb_id2str(id));
7734 return COMPILE_NG;
7735 }
7736 }
7737
7738 if (idx < 0) {
7739 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7740 rb_id2str(id));
7741 return COMPILE_NG;
7742 }
7743 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7744 ADD_INSNL(ret, line_node, jump, matched);
7745 break;
7746 }
7747 case NODE_IF:
7748 case NODE_UNLESS: {
7749 LABEL *match_failed;
7750 match_failed = unmatched;
7751 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7752 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7753 if (in_single_pattern) {
7754 LABEL *match_succeeded;
7755 match_succeeded = NEW_LABEL(line);
7756
7757 ADD_INSN(ret, line_node, dup);
7758 if (nd_type_p(node, NODE_IF)) {
7759 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7760 }
7761 else {
7762 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7763 }
7764
7765 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7766 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7767 ADD_INSN1(ret, line_node, putobject, Qfalse);
7768 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7769
7770 ADD_INSN(ret, line_node, pop);
7771 ADD_INSN(ret, line_node, pop);
7772
7773 ADD_LABEL(ret, match_succeeded);
7774 }
7775 if (nd_type_p(node, NODE_IF)) {
7776 ADD_INSNL(ret, line_node, branchunless, match_failed);
7777 }
7778 else {
7779 ADD_INSNL(ret, line_node, branchif, match_failed);
7780 }
7781 ADD_INSNL(ret, line_node, jump, matched);
7782 break;
7783 }
7784 case NODE_HASH: {
7785 NODE *n;
7786 LABEL *match_failed;
7787 match_failed = NEW_LABEL(line);
7788
7789 n = RNODE_HASH(node)->nd_head;
7790 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7791 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7792 return COMPILE_NG;
7793 }
7794
7795 ADD_INSN(ret, line_node, dup); // (1)
7796 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));
7797 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));
7798 ADD_INSN(ret, line_node, putnil);
7799
7800 ADD_LABEL(ret, match_failed);
7801 ADD_INSN(ret, line_node, pop);
7802 ADD_INSNL(ret, line_node, jump, unmatched);
7803 break;
7804 }
7805 case NODE_OR: {
7806 LABEL *match_succeeded, *fin;
7807 match_succeeded = NEW_LABEL(line);
7808 fin = NEW_LABEL(line);
7809
7810 ADD_INSN(ret, line_node, dup); // (1)
7811 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));
7812 ADD_LABEL(ret, match_succeeded);
7813 ADD_INSN(ret, line_node, pop);
7814 ADD_INSNL(ret, line_node, jump, matched);
7815 ADD_INSN(ret, line_node, putnil);
7816 ADD_LABEL(ret, fin);
7817 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7818 break;
7819 }
7820 default:
7821 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7822 }
7823 return COMPILE_OK;
7824}
7825
7826static int
7827iseq_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)
7828{
7829 LABEL *fin = NEW_LABEL(nd_line(node));
7830 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7831 ADD_LABEL(ret, fin);
7832 return COMPILE_OK;
7833}
7834
7835static int
7836iseq_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)
7837{
7838 const NODE *line_node = node;
7839
7840 if (RNODE_ARYPTN(node)->nd_pconst) {
7841 ADD_INSN(ret, line_node, dup); // (1)
7842 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7843 if (in_single_pattern) {
7844 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7845 }
7846 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7847 if (in_single_pattern) {
7848 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7849 }
7850 ADD_INSNL(ret, line_node, branchunless, match_failed);
7851 }
7852 return COMPILE_OK;
7853}
7854
7855
7856static int
7857iseq_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)
7858{
7859 const NODE *line_node = node;
7860
7861 // NOTE: this optimization allows us to re-use the #deconstruct value
7862 // (or its absence).
7863 if (use_deconstructed_cache) {
7864 // If value is nil then we haven't tried to deconstruct
7865 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7866 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7867
7868 // If false then the value is not deconstructable
7869 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7870 ADD_INSNL(ret, line_node, branchunless, match_failed);
7871
7872 // Drop value, add deconstructed to the stack and jump
7873 ADD_INSN(ret, line_node, pop); // (1)
7874 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7875 ADD_INSNL(ret, line_node, jump, deconstructed);
7876 }
7877 else {
7878 ADD_INSNL(ret, line_node, jump, deconstruct);
7879 }
7880
7881 ADD_LABEL(ret, deconstruct);
7882 ADD_INSN(ret, line_node, dup);
7883 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7884 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7885
7886 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7887 if (use_deconstructed_cache) {
7888 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7889 }
7890
7891 if (in_single_pattern) {
7892 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7893 }
7894
7895 ADD_INSNL(ret, line_node, branchunless, match_failed);
7896
7897 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7898
7899 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7900 if (use_deconstructed_cache) {
7901 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7902 }
7903
7904 ADD_INSN(ret, line_node, dup);
7905 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7906 ADD_INSNL(ret, line_node, branchunless, type_error);
7907
7908 ADD_LABEL(ret, deconstructed);
7909
7910 return COMPILE_OK;
7911}
7912
7913static int
7914iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7915{
7916 /*
7917 * if match_succeeded?
7918 * goto match_succeeded
7919 * end
7920 * error_string = FrozenCore.sprintf(errmsg, matchee)
7921 * key_error_p = false
7922 * match_succeeded:
7923 */
7924 const int line = nd_line(node);
7925 const NODE *line_node = node;
7926 LABEL *match_succeeded = NEW_LABEL(line);
7927
7928 ADD_INSN(ret, line_node, dup);
7929 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7930
7931 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7932 ADD_INSN1(ret, line_node, putobject, errmsg);
7933 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7934 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7935 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7936
7937 ADD_INSN1(ret, line_node, putobject, Qfalse);
7938 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7939
7940 ADD_INSN(ret, line_node, pop);
7941 ADD_INSN(ret, line_node, pop);
7942 ADD_LABEL(ret, match_succeeded);
7943
7944 return COMPILE_OK;
7945}
7946
7947static int
7948iseq_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)
7949{
7950 /*
7951 * if match_succeeded?
7952 * goto match_succeeded
7953 * end
7954 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7955 * key_error_p = false
7956 * match_succeeded:
7957 */
7958 const int line = nd_line(node);
7959 const NODE *line_node = node;
7960 LABEL *match_succeeded = NEW_LABEL(line);
7961
7962 ADD_INSN(ret, line_node, dup);
7963 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7964
7965 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7966 ADD_INSN1(ret, line_node, putobject, errmsg);
7967 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7968 ADD_INSN(ret, line_node, dup);
7969 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7970 ADD_INSN1(ret, line_node, putobject, pattern_length);
7971 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7972 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7973
7974 ADD_INSN1(ret, line_node, putobject, Qfalse);
7975 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7976
7977 ADD_INSN(ret, line_node, pop);
7978 ADD_INSN(ret, line_node, pop);
7979 ADD_LABEL(ret, match_succeeded);
7980
7981 return COMPILE_OK;
7982}
7983
7984static int
7985iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7986{
7987 /*
7988 * if match_succeeded?
7989 * goto match_succeeded
7990 * end
7991 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7992 * key_error_p = false
7993 * match_succeeded:
7994 */
7995 const int line = nd_line(node);
7996 const NODE *line_node = node;
7997 LABEL *match_succeeded = NEW_LABEL(line);
7998
7999 ADD_INSN(ret, line_node, dup);
8000 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8001
8002 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8003 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8004 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8005 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8006 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8007 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8008
8009 ADD_INSN1(ret, line_node, putobject, Qfalse);
8010 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8011
8012 ADD_INSN(ret, line_node, pop);
8013 ADD_INSN(ret, line_node, pop);
8014
8015 ADD_LABEL(ret, match_succeeded);
8016 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8017 ADD_INSN(ret, line_node, pop);
8018 ADD_INSN(ret, line_node, pop);
8019
8020 return COMPILE_OK;
8021}
8022
8023static int
8024compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8025{
8026 const NODE *pattern;
8027 const NODE *node = orig_node;
8028 LABEL *endlabel, *elselabel;
8029 DECL_ANCHOR(head);
8030 DECL_ANCHOR(body_seq);
8031 DECL_ANCHOR(cond_seq);
8032 int line;
8033 enum node_type type;
8034 const NODE *line_node;
8035 VALUE branches = 0;
8036 int branch_id = 0;
8037 bool single_pattern;
8038
8039 INIT_ANCHOR(head);
8040 INIT_ANCHOR(body_seq);
8041 INIT_ANCHOR(cond_seq);
8042
8043 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8044
8045 node = RNODE_CASE3(node)->nd_body;
8046 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8047 type = nd_type(node);
8048 line = nd_line(node);
8049 line_node = node;
8050 single_pattern = !RNODE_IN(node)->nd_next;
8051
8052 endlabel = NEW_LABEL(line);
8053 elselabel = NEW_LABEL(line);
8054
8055 if (single_pattern) {
8056 /* allocate stack for ... */
8057 ADD_INSN(head, line_node, putnil); /* key_error_key */
8058 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8059 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8060 ADD_INSN(head, line_node, putnil); /* error_string */
8061 }
8062 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8063
8064 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8065
8066 ADD_SEQ(ret, head); /* case VAL */
8067
8068 while (type == NODE_IN) {
8069 LABEL *l1;
8070
8071 if (branch_id) {
8072 ADD_INSN(body_seq, line_node, putnil);
8073 }
8074 l1 = NEW_LABEL(line);
8075 ADD_LABEL(body_seq, l1);
8076 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8077
8078 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8079 add_trace_branch_coverage(
8080 iseq,
8081 body_seq,
8082 nd_code_loc(coverage_node),
8083 nd_node_id(coverage_node),
8084 branch_id++,
8085 "in",
8086 branches);
8087
8088 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8089 ADD_INSNL(body_seq, line_node, jump, endlabel);
8090
8091 pattern = RNODE_IN(node)->nd_head;
8092 if (pattern) {
8093 int pat_line = nd_line(pattern);
8094 LABEL *next_pat = NEW_LABEL(pat_line);
8095 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8096 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8097 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8098 ADD_LABEL(cond_seq, next_pat);
8099 LABEL_UNREMOVABLE(next_pat);
8100 }
8101 else {
8102 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8103 return COMPILE_NG;
8104 }
8105
8106 node = RNODE_IN(node)->nd_next;
8107 if (!node) {
8108 break;
8109 }
8110 type = nd_type(node);
8111 line = nd_line(node);
8112 line_node = node;
8113 }
8114 /* else */
8115 if (node) {
8116 ADD_LABEL(cond_seq, elselabel);
8117 ADD_INSN(cond_seq, line_node, pop);
8118 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8119 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8120 CHECK(COMPILE_(cond_seq, "else", node, popped));
8121 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8122 ADD_INSN(cond_seq, line_node, putnil);
8123 if (popped) {
8124 ADD_INSN(cond_seq, line_node, putnil);
8125 }
8126 }
8127 else {
8128 debugs("== else (implicit)\n");
8129 ADD_LABEL(cond_seq, elselabel);
8130 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8131 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8132
8133 if (single_pattern) {
8134 /*
8135 * if key_error_p
8136 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8137 * else
8138 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8139 * end
8140 */
8141 LABEL *key_error, *fin;
8142 struct rb_callinfo_kwarg *kw_arg;
8143
8144 key_error = NEW_LABEL(line);
8145 fin = NEW_LABEL(line);
8146
8147 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8148 kw_arg->references = 0;
8149 kw_arg->keyword_len = 2;
8150 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8151 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8152
8153 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8154 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8155 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8156 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8157 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8158 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8159 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8160 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8161 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8162 ADD_INSNL(cond_seq, orig_node, jump, fin);
8163
8164 ADD_LABEL(cond_seq, key_error);
8165 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8166 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8167 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8168 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8169 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8170 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8171 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8172 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8173 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8174 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8175
8176 ADD_LABEL(cond_seq, fin);
8177 }
8178 else {
8179 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8180 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8181 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8182 }
8183 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8184 if (!popped) {
8185 ADD_INSN(cond_seq, orig_node, putnil);
8186 }
8187 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8188 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8189 if (popped) {
8190 ADD_INSN(cond_seq, line_node, putnil);
8191 }
8192 }
8193
8194 ADD_SEQ(ret, cond_seq);
8195 ADD_SEQ(ret, body_seq);
8196 ADD_LABEL(ret, endlabel);
8197 return COMPILE_OK;
8198}
8199
8200#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8201#undef CASE3_BI_OFFSET_ERROR_STRING
8202#undef CASE3_BI_OFFSET_KEY_ERROR_P
8203#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8204#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8205
8206static int
8207compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8208{
8209 const int line = (int)nd_line(node);
8210 const NODE *line_node = node;
8211
8212 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8213 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8214 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8215 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8216 VALUE branches = Qfalse;
8217
8219
8220 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8221 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8222 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8223 LABEL *end_label = NEW_LABEL(line);
8224 LABEL *adjust_label = NEW_LABEL(line);
8225
8226 LABEL *next_catch_label = NEW_LABEL(line);
8227 LABEL *tmp_label = NULL;
8228
8229 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8230 push_ensure_entry(iseq, &enl, NULL, NULL);
8231
8232 if (RNODE_WHILE(node)->nd_state == 1) {
8233 ADD_INSNL(ret, line_node, jump, next_label);
8234 }
8235 else {
8236 tmp_label = NEW_LABEL(line);
8237 ADD_INSNL(ret, line_node, jump, tmp_label);
8238 }
8239 ADD_LABEL(ret, adjust_label);
8240 ADD_INSN(ret, line_node, putnil);
8241 ADD_LABEL(ret, next_catch_label);
8242 ADD_INSN(ret, line_node, pop);
8243 ADD_INSNL(ret, line_node, jump, next_label);
8244 if (tmp_label) ADD_LABEL(ret, tmp_label);
8245
8246 ADD_LABEL(ret, redo_label);
8247 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8248
8249 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8250 add_trace_branch_coverage(
8251 iseq,
8252 ret,
8253 nd_code_loc(coverage_node),
8254 nd_node_id(coverage_node),
8255 0,
8256 "body",
8257 branches);
8258
8259 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8260 ADD_LABEL(ret, next_label); /* next */
8261
8262 if (type == NODE_WHILE) {
8263 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8264 redo_label, end_label));
8265 }
8266 else {
8267 /* until */
8268 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8269 end_label, redo_label));
8270 }
8271
8272 ADD_LABEL(ret, end_label);
8273 ADD_ADJUST_RESTORE(ret, adjust_label);
8274
8275 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8276 /* ADD_INSN(ret, line_node, putundef); */
8277 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8278 return COMPILE_NG;
8279 }
8280 else {
8281 ADD_INSN(ret, line_node, putnil);
8282 }
8283
8284 ADD_LABEL(ret, break_label); /* break */
8285
8286 if (popped) {
8287 ADD_INSN(ret, line_node, pop);
8288 }
8289
8290 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8291 break_label);
8292 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8293 next_catch_label);
8294 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8295 ISEQ_COMPILE_DATA(iseq)->redo_label);
8296
8297 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8298 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8299 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8300 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8301 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8302 return COMPILE_OK;
8303}
8304
8305static int
8306compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8307{
8308 const int line = nd_line(node);
8309 const NODE *line_node = node;
8310 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8311 LABEL *retry_label = NEW_LABEL(line);
8312 LABEL *retry_end_l = NEW_LABEL(line);
8313 const rb_iseq_t *child_iseq;
8314
8315 ADD_LABEL(ret, retry_label);
8316 if (nd_type_p(node, NODE_FOR)) {
8317 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8318
8319 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8320 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8321 ISEQ_TYPE_BLOCK, line);
8322 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8323 }
8324 else {
8325 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8326 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8327 ISEQ_TYPE_BLOCK, line);
8328 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8329 }
8330
8331 {
8332 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8333 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8334 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8335 //
8336 // Normally, "send" instruction is at the last.
8337 // However, qcall under branch coverage measurement adds some instructions after the "send".
8338 //
8339 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8340 INSN *iobj;
8341 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8342 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8343 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8344 iobj = (INSN*) get_prev_insn(iobj);
8345 }
8346 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8347
8348 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8349 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8350 if (&iobj->link == LAST_ELEMENT(ret)) {
8351 ret->last = (LINK_ELEMENT*) retry_end_l;
8352 }
8353 }
8354
8355 if (popped) {
8356 ADD_INSN(ret, line_node, pop);
8357 }
8358
8359 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8360
8361 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8362 return COMPILE_OK;
8363}
8364
8365static int
8366compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8367{
8368 /* massign to var in "for"
8369 * (args.length == 1 && Array.try_convert(args[0])) || args
8370 */
8371 const NODE *line_node = node;
8372 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8373 LABEL *not_single = NEW_LABEL(nd_line(var));
8374 LABEL *not_ary = NEW_LABEL(nd_line(var));
8375 CHECK(COMPILE(ret, "for var", var));
8376 ADD_INSN(ret, line_node, dup);
8377 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8378 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8379 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8380 ADD_INSNL(ret, line_node, branchunless, not_single);
8381 ADD_INSN(ret, line_node, dup);
8382 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8383 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8384 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8385 ADD_INSN(ret, line_node, swap);
8386 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8387 ADD_INSN(ret, line_node, dup);
8388 ADD_INSNL(ret, line_node, branchunless, not_ary);
8389 ADD_INSN(ret, line_node, swap);
8390 ADD_LABEL(ret, not_ary);
8391 ADD_INSN(ret, line_node, pop);
8392 ADD_LABEL(ret, not_single);
8393 return COMPILE_OK;
8394}
8395
8396static int
8397compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8398{
8399 const NODE *line_node = node;
8400 unsigned long throw_flag = 0;
8401
8402 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8403 /* while/until */
8404 LABEL *splabel = NEW_LABEL(0);
8405 ADD_LABEL(ret, splabel);
8406 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8407 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8408 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8409 add_ensure_iseq(ret, iseq, 0);
8410 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8411 ADD_ADJUST_RESTORE(ret, splabel);
8412
8413 if (!popped) {
8414 ADD_INSN(ret, line_node, putnil);
8415 }
8416 }
8417 else {
8418 const rb_iseq_t *ip = iseq;
8419
8420 while (ip) {
8421 if (!ISEQ_COMPILE_DATA(ip)) {
8422 ip = 0;
8423 break;
8424 }
8425
8426 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8427 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8428 }
8429 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8430 throw_flag = 0;
8431 }
8432 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8433 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8434 return COMPILE_NG;
8435 }
8436 else {
8437 ip = ISEQ_BODY(ip)->parent_iseq;
8438 continue;
8439 }
8440
8441 /* escape from block */
8442 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8443 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8444 if (popped) {
8445 ADD_INSN(ret, line_node, pop);
8446 }
8447 return COMPILE_OK;
8448 }
8449 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8450 return COMPILE_NG;
8451 }
8452 return COMPILE_OK;
8453}
8454
8455static int
8456compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8457{
8458 const NODE *line_node = node;
8459 unsigned long throw_flag = 0;
8460
8461 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8462 LABEL *splabel = NEW_LABEL(0);
8463 debugs("next in while loop\n");
8464 ADD_LABEL(ret, splabel);
8465 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8466 add_ensure_iseq(ret, iseq, 0);
8467 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8468 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8469 ADD_ADJUST_RESTORE(ret, splabel);
8470 if (!popped) {
8471 ADD_INSN(ret, line_node, putnil);
8472 }
8473 }
8474 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8475 LABEL *splabel = NEW_LABEL(0);
8476 debugs("next in block\n");
8477 ADD_LABEL(ret, splabel);
8478 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8479 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8480 add_ensure_iseq(ret, iseq, 0);
8481 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8482 ADD_ADJUST_RESTORE(ret, splabel);
8483
8484 if (!popped) {
8485 ADD_INSN(ret, line_node, putnil);
8486 }
8487 }
8488 else {
8489 const rb_iseq_t *ip = iseq;
8490
8491 while (ip) {
8492 if (!ISEQ_COMPILE_DATA(ip)) {
8493 ip = 0;
8494 break;
8495 }
8496
8497 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8498 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8499 /* while loop */
8500 break;
8501 }
8502 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8503 break;
8504 }
8505 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8506 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8507 return COMPILE_NG;
8508 }
8509
8510 ip = ISEQ_BODY(ip)->parent_iseq;
8511 }
8512 if (ip != 0) {
8513 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8514 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8515
8516 if (popped) {
8517 ADD_INSN(ret, line_node, pop);
8518 }
8519 }
8520 else {
8521 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8522 return COMPILE_NG;
8523 }
8524 }
8525 return COMPILE_OK;
8526}
8527
8528static int
8529compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8530{
8531 const NODE *line_node = node;
8532
8533 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8534 LABEL *splabel = NEW_LABEL(0);
8535 debugs("redo in while");
8536 ADD_LABEL(ret, splabel);
8537 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8538 add_ensure_iseq(ret, iseq, 0);
8539 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8540 ADD_ADJUST_RESTORE(ret, splabel);
8541 if (!popped) {
8542 ADD_INSN(ret, line_node, putnil);
8543 }
8544 }
8545 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8546 LABEL *splabel = NEW_LABEL(0);
8547
8548 debugs("redo in block");
8549 ADD_LABEL(ret, splabel);
8550 add_ensure_iseq(ret, iseq, 0);
8551 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8552 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8553 ADD_ADJUST_RESTORE(ret, splabel);
8554
8555 if (!popped) {
8556 ADD_INSN(ret, line_node, putnil);
8557 }
8558 }
8559 else {
8560 const rb_iseq_t *ip = iseq;
8561
8562 while (ip) {
8563 if (!ISEQ_COMPILE_DATA(ip)) {
8564 ip = 0;
8565 break;
8566 }
8567
8568 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8569 break;
8570 }
8571 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8572 break;
8573 }
8574 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8575 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8576 return COMPILE_NG;
8577 }
8578
8579 ip = ISEQ_BODY(ip)->parent_iseq;
8580 }
8581 if (ip != 0) {
8582 ADD_INSN(ret, line_node, putnil);
8583 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8584
8585 if (popped) {
8586 ADD_INSN(ret, line_node, pop);
8587 }
8588 }
8589 else {
8590 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8591 return COMPILE_NG;
8592 }
8593 }
8594 return COMPILE_OK;
8595}
8596
8597static int
8598compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8599{
8600 const NODE *line_node = node;
8601
8602 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8603 ADD_INSN(ret, line_node, putnil);
8604 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8605
8606 if (popped) {
8607 ADD_INSN(ret, line_node, pop);
8608 }
8609 }
8610 else {
8611 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8612 return COMPILE_NG;
8613 }
8614 return COMPILE_OK;
8615}
8616
8617static int
8618compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8619{
8620 const int line = nd_line(node);
8621 const NODE *line_node = node;
8622 LABEL *lstart = NEW_LABEL(line);
8623 LABEL *lend = NEW_LABEL(line);
8624 LABEL *lcont = NEW_LABEL(line);
8625 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8626 rb_str_concat(rb_str_new2("rescue in "),
8627 ISEQ_BODY(iseq)->location.label),
8628 ISEQ_TYPE_RESCUE, line);
8629
8630 lstart->rescued = LABEL_RESCUE_BEG;
8631 lend->rescued = LABEL_RESCUE_END;
8632 ADD_LABEL(ret, lstart);
8633
8634 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8635 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8636 {
8637 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8638 }
8639 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8640
8641 ADD_LABEL(ret, lend);
8642 if (RNODE_RESCUE(node)->nd_else) {
8643 ADD_INSN(ret, line_node, pop);
8644 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8645 }
8646 ADD_INSN(ret, line_node, nop);
8647 ADD_LABEL(ret, lcont);
8648
8649 if (popped) {
8650 ADD_INSN(ret, line_node, pop);
8651 }
8652
8653 /* register catch entry */
8654 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8655 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8656 return COMPILE_OK;
8657}
8658
8659static int
8660compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8661{
8662 const int line = nd_line(node);
8663 const NODE *line_node = node;
8664 const NODE *resq = node;
8665 const NODE *narg;
8666 LABEL *label_miss, *label_hit;
8667
8668 while (resq) {
8669 label_miss = NEW_LABEL(line);
8670 label_hit = NEW_LABEL(line);
8671
8672 narg = RNODE_RESBODY(resq)->nd_args;
8673 if (narg) {
8674 switch (nd_type(narg)) {
8675 case NODE_LIST:
8676 while (narg) {
8677 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8678 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8679 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8680 ADD_INSNL(ret, line_node, branchif, label_hit);
8681 narg = RNODE_LIST(narg)->nd_next;
8682 }
8683 break;
8684 case NODE_SPLAT:
8685 case NODE_ARGSCAT:
8686 case NODE_ARGSPUSH:
8687 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8688 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8689 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8690 ADD_INSNL(ret, line_node, branchif, label_hit);
8691 break;
8692 default:
8693 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8694 }
8695 }
8696 else {
8697 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8698 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8699 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8700 ADD_INSNL(ret, line_node, branchif, label_hit);
8701 }
8702 ADD_INSNL(ret, line_node, jump, label_miss);
8703 ADD_LABEL(ret, label_hit);
8704 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8705
8706 if (RNODE_RESBODY(resq)->nd_exc_var) {
8707 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8708 }
8709
8710 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) {
8711 // empty body
8712 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8713 }
8714 else {
8715 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8716 }
8717
8718 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8719 ADD_INSN(ret, line_node, nop);
8720 }
8721 ADD_INSN(ret, line_node, leave);
8722 ADD_LABEL(ret, label_miss);
8723 resq = RNODE_RESBODY(resq)->nd_next;
8724 }
8725 return COMPILE_OK;
8726}
8727
8728static int
8729compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8730{
8731 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8732 const NODE *line_node = node;
8733 DECL_ANCHOR(ensr);
8734 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8735 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8736 ISEQ_TYPE_ENSURE, line);
8737 LABEL *lstart = NEW_LABEL(line);
8738 LABEL *lend = NEW_LABEL(line);
8739 LABEL *lcont = NEW_LABEL(line);
8740 LINK_ELEMENT *last;
8741 int last_leave = 0;
8742 struct ensure_range er;
8744 struct ensure_range *erange;
8745
8746 INIT_ANCHOR(ensr);
8747 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8748 last = ensr->last;
8749 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8750
8751 er.begin = lstart;
8752 er.end = lend;
8753 er.next = 0;
8754 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8755
8756 ADD_LABEL(ret, lstart);
8757 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8758 ADD_LABEL(ret, lend);
8759 ADD_SEQ(ret, ensr);
8760 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8761 ADD_LABEL(ret, lcont);
8762 if (last_leave) ADD_INSN(ret, line_node, pop);
8763
8764 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8765 if (lstart->link.next != &lend->link) {
8766 while (erange) {
8767 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8768 ensure, lcont);
8769 erange = erange->next;
8770 }
8771 }
8772
8773 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8774 return COMPILE_OK;
8775}
8776
8777static int
8778compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8779{
8780 const NODE *line_node = node;
8781
8782 if (iseq) {
8783 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8784 const rb_iseq_t *is = iseq;
8785 enum rb_iseq_type t = type;
8786 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8787 LABEL *splabel = 0;
8788
8789 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8790 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8791 t = ISEQ_BODY(is)->type;
8792 }
8793 switch (t) {
8794 case ISEQ_TYPE_TOP:
8795 case ISEQ_TYPE_MAIN:
8796 if (retval) {
8797 rb_warn("argument of top-level return is ignored");
8798 }
8799 if (is == iseq) {
8800 /* plain top-level, leave directly */
8801 type = ISEQ_TYPE_METHOD;
8802 }
8803 break;
8804 default:
8805 break;
8806 }
8807
8808 if (type == ISEQ_TYPE_METHOD) {
8809 splabel = NEW_LABEL(0);
8810 ADD_LABEL(ret, splabel);
8811 ADD_ADJUST(ret, line_node, 0);
8812 }
8813
8814 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8815
8816 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8817 add_ensure_iseq(ret, iseq, 1);
8818 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8819 ADD_INSN(ret, line_node, leave);
8820 ADD_ADJUST_RESTORE(ret, splabel);
8821
8822 if (!popped) {
8823 ADD_INSN(ret, line_node, putnil);
8824 }
8825 }
8826 else {
8827 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8828 if (popped) {
8829 ADD_INSN(ret, line_node, pop);
8830 }
8831 }
8832 }
8833 return COMPILE_OK;
8834}
8835
8836static bool
8837drop_unreachable_return(LINK_ANCHOR *ret)
8838{
8839 LINK_ELEMENT *i = ret->last, *last;
8840 if (!i) return false;
8841 if (IS_TRACE(i)) i = i->prev;
8842 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8843 last = i = i->prev;
8844 if (IS_ADJUST(i)) i = i->prev;
8845 if (!IS_INSN(i)) return false;
8846 switch (INSN_OF(i)) {
8847 case BIN(leave):
8848 case BIN(jump):
8849 break;
8850 default:
8851 return false;
8852 }
8853 (ret->last = last->prev)->next = NULL;
8854 return true;
8855}
8856
8857static int
8858compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8859{
8860 CHECK(COMPILE_(ret, "nd_body", node, popped));
8861
8862 if (!popped && !all_string_result_p(node)) {
8863 const NODE *line_node = node;
8864 const unsigned int flag = VM_CALL_FCALL;
8865
8866 // Note, this dup could be removed if we are willing to change anytostring. It pops
8867 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8868 ADD_INSN(ret, line_node, dup);
8869 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8870 ADD_INSN(ret, line_node, anytostring);
8871 }
8872 return COMPILE_OK;
8873}
8874
8875static void
8876compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8877{
8878 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8879
8880 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8881 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8882}
8883
8884static LABEL *
8885qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8886{
8887 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8888 VALUE br = 0;
8889
8890 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8891 *branches = br;
8892 ADD_INSN(recv, line_node, dup);
8893 ADD_INSNL(recv, line_node, branchnil, else_label);
8894 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8895 return else_label;
8896}
8897
8898static void
8899qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8900{
8901 LABEL *end_label;
8902 if (!else_label) return;
8903 end_label = NEW_LABEL(nd_line(line_node));
8904 ADD_INSNL(ret, line_node, jump, end_label);
8905 ADD_LABEL(ret, else_label);
8906 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8907 ADD_LABEL(ret, end_label);
8908}
8909
8910static int
8911compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8912{
8913 /* optimization shortcut
8914 * "literal".freeze -> opt_str_freeze("literal")
8915 */
8916 if (get_nd_recv(node) &&
8917 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8918 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8919 get_nd_args(node) == NULL &&
8920 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8921 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8922 VALUE str = get_string_value(get_nd_recv(node));
8923 if (get_node_call_nd_mid(node) == idUMinus) {
8924 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8925 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8926 }
8927 else {
8928 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8929 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8930 }
8931 RB_OBJ_WRITTEN(iseq, Qundef, str);
8932 if (popped) {
8933 ADD_INSN(ret, line_node, pop);
8934 }
8935 return TRUE;
8936 }
8937 /* optimization shortcut
8938 * obj["literal"] -> opt_aref_with(obj, "literal")
8939 */
8940 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8941 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8942 (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)) &&
8943 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8944 !frozen_string_literal_p(iseq) &&
8945 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8946 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8947 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8948 ADD_INSN2(ret, line_node, opt_aref_with, str,
8949 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8950 RB_OBJ_WRITTEN(iseq, Qundef, str);
8951 if (popped) {
8952 ADD_INSN(ret, line_node, pop);
8953 }
8954 return TRUE;
8955 }
8956 return FALSE;
8957}
8958
8959static int
8960iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8961{
8962 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8963}
8964
8965static const struct rb_builtin_function *
8966iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8967{
8968 int i;
8969 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8970 for (i=0; table[i].index != -1; i++) {
8971 if (strcmp(table[i].name, name) == 0) {
8972 return &table[i];
8973 }
8974 }
8975 return NULL;
8976}
8977
8978static const char *
8979iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8980{
8981 const char *name = rb_id2name(mid);
8982 static const char prefix[] = "__builtin_";
8983 const size_t prefix_len = sizeof(prefix) - 1;
8984
8985 switch (type) {
8986 case NODE_CALL:
8987 if (recv) {
8988 switch (nd_type(recv)) {
8989 case NODE_VCALL:
8990 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
8991 return name;
8992 }
8993 break;
8994 case NODE_CONST:
8995 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
8996 return name;
8997 }
8998 break;
8999 default: break;
9000 }
9001 }
9002 break;
9003 case NODE_VCALL:
9004 case NODE_FCALL:
9005 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9006 return &name[prefix_len];
9007 }
9008 break;
9009 default: break;
9010 }
9011 return NULL;
9012}
9013
9014static int
9015delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9016{
9017
9018 if (argc == 0) {
9019 *pstart_index = 0;
9020 return TRUE;
9021 }
9022 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9023 unsigned int start=0;
9024
9025 // local_table: [p1, p2, p3, l1, l2, l3]
9026 // arguments: [p3, l1, l2] -> 2
9027 for (start = 0;
9028 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9029 start++) {
9030 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9031
9032 for (unsigned int i=start; i-start<argc; i++) {
9033 if (IS_INSN(elem) &&
9034 INSN_OF(elem) == BIN(getlocal)) {
9035 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9036 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9037
9038 if (local_level == 0) {
9039 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9040 if (0) { // for debug
9041 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9042 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9043 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9044 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9045 }
9046 if (i == index) {
9047 elem = elem->next;
9048 continue; /* for */
9049 }
9050 else {
9051 goto next;
9052 }
9053 }
9054 else {
9055 goto fail; // level != 0 is unsupported
9056 }
9057 }
9058 else {
9059 goto fail; // insn is not a getlocal
9060 }
9061 }
9062 goto success;
9063 next:;
9064 }
9065 fail:
9066 return FALSE;
9067 success:
9068 *pstart_index = start;
9069 return TRUE;
9070 }
9071 else {
9072 return FALSE;
9073 }
9074}
9075
9076// Compile Primitive.attr! :leaf, ...
9077static int
9078compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9079{
9080 VALUE symbol;
9081 VALUE string;
9082 if (!node) goto no_arg;
9083 while (node) {
9084 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9085 const NODE *next = RNODE_LIST(node)->nd_next;
9086
9087 node = RNODE_LIST(node)->nd_head;
9088 if (!node) goto no_arg;
9089 switch (nd_type(node)) {
9090 case NODE_SYM:
9091 symbol = rb_node_sym_string_val(node);
9092 break;
9093 default:
9094 goto bad_arg;
9095 }
9096
9097 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9098
9099 string = rb_sym2str(symbol);
9100 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9101 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9102 }
9103 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9104 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9105 }
9106 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9107 iseq_set_use_block(iseq);
9108 }
9109 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9110 // Let the iseq act like a C method in backtraces
9111 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9112 }
9113 else {
9114 goto unknown_arg;
9115 }
9116 node = next;
9117 }
9118 return COMPILE_OK;
9119 no_arg:
9120 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9121 return COMPILE_NG;
9122 non_symbol_arg:
9123 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9124 return COMPILE_NG;
9125 unknown_arg:
9126 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9127 return COMPILE_NG;
9128 bad_arg:
9129 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9130}
9131
9132static int
9133compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9134{
9135 VALUE name;
9136
9137 if (!node) goto no_arg;
9138 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9139 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9140 node = RNODE_LIST(node)->nd_head;
9141 if (!node) goto no_arg;
9142 switch (nd_type(node)) {
9143 case NODE_SYM:
9144 name = rb_node_sym_string_val(node);
9145 break;
9146 default:
9147 goto bad_arg;
9148 }
9149 if (!SYMBOL_P(name)) goto non_symbol_arg;
9150 if (!popped) {
9151 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9152 }
9153 return COMPILE_OK;
9154 no_arg:
9155 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9156 return COMPILE_NG;
9157 too_many_arg:
9158 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9159 return COMPILE_NG;
9160 non_symbol_arg:
9161 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9162 rb_builtin_class_name(name));
9163 return COMPILE_NG;
9164 bad_arg:
9165 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9166}
9167
9168static NODE *
9169mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9170{
9171 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9172 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9173 return RNODE_IF(node)->nd_body;
9174 }
9175 else {
9176 rb_bug("mandatory_node: can't find mandatory node");
9177 }
9178}
9179
9180static int
9181compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9182{
9183 // arguments
9184 struct rb_args_info args = {
9185 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9186 };
9187 rb_node_args_t args_node;
9188 rb_node_init(RNODE(&args_node), NODE_ARGS);
9189 args_node.nd_ainfo = args;
9190
9191 // local table without non-mandatory parameters
9192 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9193 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9194
9195 VALUE idtmp = 0;
9196 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9197 tbl->size = table_size;
9198
9199 int i;
9200
9201 // lead parameters
9202 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9203 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9204 }
9205 // local variables
9206 for (; i<table_size; i++) {
9207 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9208 }
9209
9210 rb_node_scope_t scope_node;
9211 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9212 scope_node.nd_tbl = tbl;
9213 scope_node.nd_body = mandatory_node(iseq, node);
9214 scope_node.nd_args = &args_node;
9215
9216 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9217
9218 ISEQ_BODY(iseq)->mandatory_only_iseq =
9219 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9220 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9221 nd_line(line_node), NULL, 0,
9222 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9223 ISEQ_BODY(iseq)->variable.script_lines);
9224
9225 ALLOCV_END(idtmp);
9226 return COMPILE_OK;
9227}
9228
9229static int
9230compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9231 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9232{
9233 NODE *args_node = get_nd_args(node);
9234
9235 if (parent_block != NULL) {
9236 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9237 return COMPILE_NG;
9238 }
9239 else {
9240# define BUILTIN_INLINE_PREFIX "_bi"
9241 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9242 bool cconst = false;
9243 retry:;
9244 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9245
9246 if (bf == NULL) {
9247 if (strcmp("cstmt!", builtin_func) == 0 ||
9248 strcmp("cexpr!", builtin_func) == 0) {
9249 // ok
9250 }
9251 else if (strcmp("cconst!", builtin_func) == 0) {
9252 cconst = true;
9253 }
9254 else if (strcmp("cinit!", builtin_func) == 0) {
9255 // ignore
9256 return COMPILE_OK;
9257 }
9258 else if (strcmp("attr!", builtin_func) == 0) {
9259 return compile_builtin_attr(iseq, args_node);
9260 }
9261 else if (strcmp("arg!", builtin_func) == 0) {
9262 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9263 }
9264 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9265 if (popped) {
9266 rb_bug("mandatory_only? should be in if condition");
9267 }
9268 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9269 rb_bug("mandatory_only? should be put on top");
9270 }
9271
9272 ADD_INSN1(ret, line_node, putobject, Qfalse);
9273 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9274 }
9275 else if (1) {
9276 rb_bug("can't find builtin function:%s", builtin_func);
9277 }
9278 else {
9279 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9280 return COMPILE_NG;
9281 }
9282
9283 int inline_index = nd_line(node);
9284 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9285 builtin_func = inline_func;
9286 args_node = NULL;
9287 goto retry;
9288 }
9289
9290 if (cconst) {
9291 typedef VALUE(*builtin_func0)(void *, VALUE);
9292 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9293 ADD_INSN1(ret, line_node, putobject, const_val);
9294 return COMPILE_OK;
9295 }
9296
9297 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9298
9299 unsigned int flag = 0;
9300 struct rb_callinfo_kwarg *keywords = NULL;
9301 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9302
9303 if (FIX2INT(argc) != bf->argc) {
9304 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9305 builtin_func, bf->argc, FIX2INT(argc));
9306 return COMPILE_NG;
9307 }
9308
9309 unsigned int start_index;
9310 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9311 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9312 }
9313 else {
9314 ADD_SEQ(ret, args);
9315 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9316 }
9317
9318 if (popped) ADD_INSN(ret, line_node, pop);
9319 return COMPILE_OK;
9320 }
9321}
9322
9323static int
9324compile_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)
9325{
9326 /* call: obj.method(...)
9327 * fcall: func(...)
9328 * vcall: func
9329 */
9330 DECL_ANCHOR(recv);
9331 DECL_ANCHOR(args);
9332 ID mid = get_node_call_nd_mid(node);
9333 VALUE argc;
9334 unsigned int flag = 0;
9335 struct rb_callinfo_kwarg *keywords = NULL;
9336 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9337 LABEL *else_label = NULL;
9338 VALUE branches = Qfalse;
9339
9340 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9341
9342 INIT_ANCHOR(recv);
9343 INIT_ANCHOR(args);
9344#if OPT_SUPPORT_JOKE
9345 if (nd_type_p(node, NODE_VCALL)) {
9346 ID id_bitblt;
9347 ID id_answer;
9348
9349 CONST_ID(id_bitblt, "bitblt");
9350 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9351
9352 if (mid == id_bitblt) {
9353 ADD_INSN(ret, line_node, bitblt);
9354 return COMPILE_OK;
9355 }
9356 else if (mid == id_answer) {
9357 ADD_INSN(ret, line_node, answer);
9358 return COMPILE_OK;
9359 }
9360 }
9361 /* only joke */
9362 {
9363 ID goto_id;
9364 ID label_id;
9365
9366 CONST_ID(goto_id, "__goto__");
9367 CONST_ID(label_id, "__label__");
9368
9369 if (nd_type_p(node, NODE_FCALL) &&
9370 (mid == goto_id || mid == label_id)) {
9371 LABEL *label;
9372 st_data_t data;
9373 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9374 VALUE label_name;
9375
9376 if (!labels_table) {
9377 labels_table = st_init_numtable();
9378 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9379 }
9380 {
9381 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9382 return COMPILE_NG;
9383 }
9384
9385 if (mid == goto_id) {
9386 ADD_INSNL(ret, line_node, jump, label);
9387 }
9388 else {
9389 ADD_LABEL(ret, label);
9390 }
9391 return COMPILE_OK;
9392 }
9393 }
9394#endif
9395
9396 const char *builtin_func;
9397 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9398 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9399 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9400 }
9401
9402 /* receiver */
9403 if (!assume_receiver) {
9404 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9405 int idx, level;
9406
9407 if (mid == idCall &&
9408 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9409 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9410 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9411 }
9412 else if (private_recv_p(node)) {
9413 ADD_INSN(recv, node, putself);
9414 flag |= VM_CALL_FCALL;
9415 }
9416 else {
9417 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9418 }
9419
9420 if (type == NODE_QCALL) {
9421 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9422 }
9423 }
9424 else if (type == NODE_FCALL || type == NODE_VCALL) {
9425 ADD_CALL_RECEIVER(recv, line_node);
9426 }
9427 }
9428
9429 /* args */
9430 if (type != NODE_VCALL) {
9431 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9432 CHECK(!NIL_P(argc));
9433 }
9434 else {
9435 argc = INT2FIX(0);
9436 }
9437
9438 ADD_SEQ(ret, recv);
9439 ADD_SEQ(ret, args);
9440
9441 debugp_param("call args argc", argc);
9442 debugp_param("call method", ID2SYM(mid));
9443
9444 switch ((int)type) {
9445 case NODE_VCALL:
9446 flag |= VM_CALL_VCALL;
9447 /* VCALL is funcall, so fall through */
9448 case NODE_FCALL:
9449 flag |= VM_CALL_FCALL;
9450 }
9451
9452 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9453 ADD_INSN(ret, line_node, splatkw);
9454 }
9455 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9456
9457 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9458 if (popped) {
9459 ADD_INSN(ret, line_node, pop);
9460 }
9461 return COMPILE_OK;
9462}
9463
9464static int
9465compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9466{
9467 const int line = nd_line(node);
9468 VALUE argc;
9469 unsigned int flag = 0;
9470 int asgnflag = 0;
9471 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9472
9473 /*
9474 * a[x] (op)= y
9475 *
9476 * nil # nil
9477 * eval a # nil a
9478 * eval x # nil a x
9479 * dupn 2 # nil a x a x
9480 * send :[] # nil a x a[x]
9481 * eval y # nil a x a[x] y
9482 * send op # nil a x ret
9483 * setn 3 # ret a x ret
9484 * send []= # ret ?
9485 * pop # ret
9486 */
9487
9488 /*
9489 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9490 * NODE_OP_ASGN nd_recv
9491 * nd_args->nd_head
9492 * nd_args->nd_body
9493 * nd_mid
9494 */
9495
9496 if (!popped) {
9497 ADD_INSN(ret, node, putnil);
9498 }
9499 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9500 CHECK(asgnflag != -1);
9501 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9502 case NODE_ZLIST:
9503 argc = INT2FIX(0);
9504 break;
9505 default:
9506 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9507 CHECK(!NIL_P(argc));
9508 }
9509 int dup_argn = FIX2INT(argc) + 1;
9510 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9511 flag |= asgnflag;
9512 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9513
9514 if (id == idOROP || id == idANDOP) {
9515 /* a[x] ||= y or a[x] &&= y
9516
9517 unless/if a[x]
9518 a[x]= y
9519 else
9520 nil
9521 end
9522 */
9523 LABEL *label = NEW_LABEL(line);
9524 LABEL *lfin = NEW_LABEL(line);
9525
9526 ADD_INSN(ret, node, dup);
9527 if (id == idOROP) {
9528 ADD_INSNL(ret, node, branchif, label);
9529 }
9530 else { /* idANDOP */
9531 ADD_INSNL(ret, node, branchunless, label);
9532 }
9533 ADD_INSN(ret, node, pop);
9534
9535 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9536 if (!popped) {
9537 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9538 }
9539 if (flag & VM_CALL_ARGS_SPLAT) {
9540 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9541 ADD_INSN(ret, node, swap);
9542 ADD_INSN1(ret, node, splatarray, Qtrue);
9543 ADD_INSN(ret, node, swap);
9544 flag |= VM_CALL_ARGS_SPLAT_MUT;
9545 }
9546 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9547 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9548 }
9549 else {
9550 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9551 }
9552 ADD_INSN(ret, node, pop);
9553 ADD_INSNL(ret, node, jump, lfin);
9554 ADD_LABEL(ret, label);
9555 if (!popped) {
9556 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9557 }
9558 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9559 ADD_LABEL(ret, lfin);
9560 }
9561 else {
9562 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9563 ADD_SEND(ret, node, id, INT2FIX(1));
9564 if (!popped) {
9565 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9566 }
9567 if (flag & VM_CALL_ARGS_SPLAT) {
9568 if (flag & VM_CALL_KW_SPLAT) {
9569 ADD_INSN1(ret, node, topn, INT2FIX(2));
9570 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9571 ADD_INSN1(ret, node, splatarray, Qtrue);
9572 flag |= VM_CALL_ARGS_SPLAT_MUT;
9573 }
9574 ADD_INSN(ret, node, swap);
9575 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9576 ADD_INSN1(ret, node, setn, INT2FIX(2));
9577 ADD_INSN(ret, node, pop);
9578 }
9579 else {
9580 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9581 ADD_INSN(ret, node, swap);
9582 ADD_INSN1(ret, node, splatarray, Qtrue);
9583 ADD_INSN(ret, node, swap);
9584 flag |= VM_CALL_ARGS_SPLAT_MUT;
9585 }
9586 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9587 }
9588 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9589 }
9590 else {
9591 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9592 }
9593 ADD_INSN(ret, node, pop);
9594 }
9595 return COMPILE_OK;
9596}
9597
9598static int
9599compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9600{
9601 const int line = nd_line(node);
9602 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9603 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9604 int asgnflag;
9605 LABEL *lfin = NEW_LABEL(line);
9606 LABEL *lcfin = NEW_LABEL(line);
9607 LABEL *lskip = 0;
9608 /*
9609 class C; attr_accessor :c; end
9610 r = C.new
9611 r.a &&= v # asgn2
9612
9613 eval r # r
9614 dup # r r
9615 eval r.a # r o
9616
9617 # or
9618 dup # r o o
9619 if lcfin # r o
9620 pop # r
9621 eval v # r v
9622 swap # v r
9623 topn 1 # v r v
9624 send a= # v ?
9625 jump lfin # v ?
9626
9627 lcfin: # r o
9628 swap # o r
9629
9630 lfin: # o ?
9631 pop # o
9632
9633 # or (popped)
9634 if lcfin # r
9635 eval v # r v
9636 send a= # ?
9637 jump lfin # ?
9638
9639 lcfin: # r
9640
9641 lfin: # ?
9642 pop #
9643
9644 # and
9645 dup # r o o
9646 unless lcfin
9647 pop # r
9648 eval v # r v
9649 swap # v r
9650 topn 1 # v r v
9651 send a= # v ?
9652 jump lfin # v ?
9653
9654 # others
9655 eval v # r o v
9656 send ?? # r w
9657 send a= # w
9658
9659 */
9660
9661 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9662 CHECK(asgnflag != -1);
9663 if (RNODE_OP_ASGN2(node)->nd_aid) {
9664 lskip = NEW_LABEL(line);
9665 ADD_INSN(ret, node, dup);
9666 ADD_INSNL(ret, node, branchnil, lskip);
9667 }
9668 ADD_INSN(ret, node, dup);
9669 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9670
9671 if (atype == idOROP || atype == idANDOP) {
9672 if (!popped) {
9673 ADD_INSN(ret, node, dup);
9674 }
9675 if (atype == idOROP) {
9676 ADD_INSNL(ret, node, branchif, lcfin);
9677 }
9678 else { /* idANDOP */
9679 ADD_INSNL(ret, node, branchunless, lcfin);
9680 }
9681 if (!popped) {
9682 ADD_INSN(ret, node, pop);
9683 }
9684 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9685 if (!popped) {
9686 ADD_INSN(ret, node, swap);
9687 ADD_INSN1(ret, node, topn, INT2FIX(1));
9688 }
9689 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9690 ADD_INSNL(ret, node, jump, lfin);
9691
9692 ADD_LABEL(ret, lcfin);
9693 if (!popped) {
9694 ADD_INSN(ret, node, swap);
9695 }
9696
9697 ADD_LABEL(ret, lfin);
9698 }
9699 else {
9700 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9701 ADD_SEND(ret, node, atype, INT2FIX(1));
9702 if (!popped) {
9703 ADD_INSN(ret, node, swap);
9704 ADD_INSN1(ret, node, topn, INT2FIX(1));
9705 }
9706 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9707 }
9708 if (lskip && popped) {
9709 ADD_LABEL(ret, lskip);
9710 }
9711 ADD_INSN(ret, node, pop);
9712 if (lskip && !popped) {
9713 ADD_LABEL(ret, lskip);
9714 }
9715 return COMPILE_OK;
9716}
9717
9718static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9719
9720static int
9721compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9722{
9723 const int line = nd_line(node);
9724 LABEL *lfin = 0;
9725 LABEL *lassign = 0;
9726 ID mid;
9727
9728 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9729 case NODE_COLON3:
9730 ADD_INSN1(ret, node, putobject, rb_cObject);
9731 break;
9732 case NODE_COLON2:
9733 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9734 break;
9735 default:
9736 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9737 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9738 return COMPILE_NG;
9739 }
9740 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9741 /* cref */
9742 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9743 lassign = NEW_LABEL(line);
9744 ADD_INSN(ret, node, dup); /* cref cref */
9745 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9746 ID2SYM(mid), Qtrue); /* cref bool */
9747 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9748 }
9749 ADD_INSN(ret, node, dup); /* cref cref */
9750 ADD_INSN1(ret, node, putobject, Qtrue);
9751 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9752
9753 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9754 lfin = NEW_LABEL(line);
9755 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9756 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9757 ADD_INSNL(ret, node, branchif, lfin);
9758 else /* idANDOP */
9759 ADD_INSNL(ret, node, branchunless, lfin);
9760 /* cref [obj] */
9761 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9762 if (lassign) ADD_LABEL(ret, lassign);
9763 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9764 /* cref value */
9765 if (popped)
9766 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9767 else {
9768 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9769 ADD_INSN(ret, node, swap); /* cref value value cref */
9770 }
9771 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9772 ADD_LABEL(ret, lfin); /* cref [value] */
9773 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9774 ADD_INSN(ret, node, pop); /* [value] */
9775 }
9776 else {
9777 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9778 /* cref obj value */
9779 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9780 /* cref value */
9781 ADD_INSN(ret, node, swap); /* value cref */
9782 if (!popped) {
9783 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9784 ADD_INSN(ret, node, swap); /* value value cref */
9785 }
9786 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9787 }
9788 return COMPILE_OK;
9789}
9790
9791static int
9792compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9793{
9794 const int line = nd_line(node);
9795 LABEL *lfin = NEW_LABEL(line);
9796 LABEL *lassign;
9797
9798 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9799 LABEL *lfinish[2];
9800 lfinish[0] = lfin;
9801 lfinish[1] = 0;
9802 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9803 lassign = lfinish[1];
9804 if (!lassign) {
9805 lassign = NEW_LABEL(line);
9806 }
9807 ADD_INSNL(ret, node, branchunless, lassign);
9808 }
9809 else {
9810 lassign = NEW_LABEL(line);
9811 }
9812
9813 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9814
9815 if (!popped) {
9816 ADD_INSN(ret, node, dup);
9817 }
9818
9819 if (type == NODE_OP_ASGN_AND) {
9820 ADD_INSNL(ret, node, branchunless, lfin);
9821 }
9822 else {
9823 ADD_INSNL(ret, node, branchif, lfin);
9824 }
9825
9826 if (!popped) {
9827 ADD_INSN(ret, node, pop);
9828 }
9829
9830 ADD_LABEL(ret, lassign);
9831 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9832 ADD_LABEL(ret, lfin);
9833 return COMPILE_OK;
9834}
9835
9836static int
9837compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9838{
9839 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9840 DECL_ANCHOR(args);
9841 int argc;
9842 unsigned int flag = 0;
9843 struct rb_callinfo_kwarg *keywords = NULL;
9844 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9845 int use_block = 1;
9846
9847 INIT_ANCHOR(args);
9848 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9849
9850 if (type == NODE_SUPER) {
9851 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9852 CHECK(!NIL_P(vargc));
9853 argc = FIX2INT(vargc);
9854 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9855 ADD_INSN(args, node, splatkw);
9856 }
9857
9858 if (flag & VM_CALL_ARGS_BLOCKARG) {
9859 use_block = 0;
9860 }
9861 }
9862 else {
9863 /* NODE_ZSUPER */
9864 int i;
9865 const rb_iseq_t *liseq = body->local_iseq;
9866 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9867 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9868 int lvar_level = get_lvar_level(iseq);
9869
9870 argc = local_body->param.lead_num;
9871
9872 /* normal arguments */
9873 for (i = 0; i < local_body->param.lead_num; i++) {
9874 int idx = local_body->local_table_size - i;
9875 ADD_GETLOCAL(args, node, idx, lvar_level);
9876 }
9877
9878 /* forward ... */
9879 if (local_body->param.flags.forwardable) {
9880 flag |= VM_CALL_FORWARDING;
9881 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9882 ADD_GETLOCAL(args, node, idx, lvar_level);
9883 }
9884
9885 if (local_body->param.flags.has_opt) {
9886 /* optional arguments */
9887 int j;
9888 for (j = 0; j < local_body->param.opt_num; j++) {
9889 int idx = local_body->local_table_size - (i + j);
9890 ADD_GETLOCAL(args, node, idx, lvar_level);
9891 }
9892 i += j;
9893 argc = i;
9894 }
9895 if (local_body->param.flags.has_rest) {
9896 /* rest argument */
9897 int idx = local_body->local_table_size - local_body->param.rest_start;
9898 ADD_GETLOCAL(args, node, idx, lvar_level);
9899 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9900
9901 argc = local_body->param.rest_start + 1;
9902 flag |= VM_CALL_ARGS_SPLAT;
9903 }
9904 if (local_body->param.flags.has_post) {
9905 /* post arguments */
9906 int post_len = local_body->param.post_num;
9907 int post_start = local_body->param.post_start;
9908
9909 if (local_body->param.flags.has_rest) {
9910 int j;
9911 for (j=0; j<post_len; j++) {
9912 int idx = local_body->local_table_size - (post_start + j);
9913 ADD_GETLOCAL(args, node, idx, lvar_level);
9914 }
9915 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9916 flag |= VM_CALL_ARGS_SPLAT_MUT;
9917 /* argc is settled at above */
9918 }
9919 else {
9920 int j;
9921 for (j=0; j<post_len; j++) {
9922 int idx = local_body->local_table_size - (post_start + j);
9923 ADD_GETLOCAL(args, node, idx, lvar_level);
9924 }
9925 argc = post_len + post_start;
9926 }
9927 }
9928
9929 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9930 int local_size = local_body->local_table_size;
9931 argc++;
9932
9933 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9934
9935 if (local_body->param.flags.has_kwrest) {
9936 int idx = local_body->local_table_size - local_kwd->rest_start;
9937 ADD_GETLOCAL(args, node, idx, lvar_level);
9938 RUBY_ASSERT(local_kwd->num > 0);
9939 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9940 }
9941 else {
9942 ADD_INSN1(args, node, newhash, INT2FIX(0));
9943 }
9944 for (i = 0; i < local_kwd->num; ++i) {
9945 ID id = local_kwd->table[i];
9946 int idx = local_size - get_local_var_idx(liseq, id);
9947 ADD_INSN1(args, node, putobject, ID2SYM(id));
9948 ADD_GETLOCAL(args, node, idx, lvar_level);
9949 }
9950 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9951 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9952 }
9953 else if (local_body->param.flags.has_kwrest) {
9954 int idx = local_body->local_table_size - local_kwd->rest_start;
9955 ADD_GETLOCAL(args, node, idx, lvar_level);
9956 argc++;
9957 flag |= VM_CALL_KW_SPLAT;
9958 }
9959 }
9960
9961 if (use_block && parent_block == NULL) {
9962 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9963 }
9964
9965 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9966 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9967 ADD_INSN(ret, node, putself);
9968 ADD_SEQ(ret, args);
9969
9970 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
9971
9972 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
9973 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
9974 }
9975 else {
9976 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
9977 }
9978
9979 if (popped) {
9980 ADD_INSN(ret, node, pop);
9981 }
9982 return COMPILE_OK;
9983}
9984
9985static int
9986compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9987{
9988 DECL_ANCHOR(args);
9989 VALUE argc;
9990 unsigned int flag = 0;
9991 struct rb_callinfo_kwarg *keywords = NULL;
9992
9993 INIT_ANCHOR(args);
9994
9995 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9996 case ISEQ_TYPE_TOP:
9997 case ISEQ_TYPE_MAIN:
9998 case ISEQ_TYPE_CLASS:
9999 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10000 return COMPILE_NG;
10001 default: /* valid */;
10002 }
10003
10004 if (RNODE_YIELD(node)->nd_head) {
10005 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10006 CHECK(!NIL_P(argc));
10007 }
10008 else {
10009 argc = INT2FIX(0);
10010 }
10011
10012 ADD_SEQ(ret, args);
10013 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10014 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10015
10016 if (popped) {
10017 ADD_INSN(ret, node, pop);
10018 }
10019
10020 int level = 0;
10021 const rb_iseq_t *tmp_iseq = iseq;
10022 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10023 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10024 }
10025 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10026
10027 return COMPILE_OK;
10028}
10029
10030static int
10031compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10032{
10033 DECL_ANCHOR(recv);
10034 DECL_ANCHOR(val);
10035
10036 INIT_ANCHOR(recv);
10037 INIT_ANCHOR(val);
10038 switch ((int)type) {
10039 case NODE_MATCH:
10040 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10041 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10042 INT2FIX(0));
10043 break;
10044 case NODE_MATCH2:
10045 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10046 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10047 break;
10048 case NODE_MATCH3:
10049 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10050 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10051 break;
10052 }
10053
10054 ADD_SEQ(ret, recv);
10055 ADD_SEQ(ret, val);
10056 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10057
10058 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10059 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10060 }
10061
10062 if (popped) {
10063 ADD_INSN(ret, node, pop);
10064 }
10065 return COMPILE_OK;
10066}
10067
10068static int
10069compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10070{
10071 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10072 /* constant */
10073 VALUE segments;
10074 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10075 (segments = collect_const_segments(iseq, node))) {
10076 ISEQ_BODY(iseq)->ic_size++;
10077 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10078 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10079 }
10080 else {
10081 /* constant */
10082 DECL_ANCHOR(pref);
10083 DECL_ANCHOR(body);
10084
10085 INIT_ANCHOR(pref);
10086 INIT_ANCHOR(body);
10087 CHECK(compile_const_prefix(iseq, node, pref, body));
10088 if (LIST_INSN_SIZE_ZERO(pref)) {
10089 ADD_INSN(ret, node, putnil);
10090 ADD_SEQ(ret, body);
10091 }
10092 else {
10093 ADD_SEQ(ret, pref);
10094 ADD_SEQ(ret, body);
10095 }
10096 }
10097 }
10098 else {
10099 /* function call */
10100 ADD_CALL_RECEIVER(ret, node);
10101 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10102 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10103 }
10104 if (popped) {
10105 ADD_INSN(ret, node, pop);
10106 }
10107 return COMPILE_OK;
10108}
10109
10110static int
10111compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10112{
10113 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10114
10115 /* add cache insn */
10116 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10117 ISEQ_BODY(iseq)->ic_size++;
10118 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10119 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10120 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10121 }
10122 else {
10123 ADD_INSN1(ret, node, putobject, rb_cObject);
10124 ADD_INSN1(ret, node, putobject, Qtrue);
10125 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10126 }
10127
10128 if (popped) {
10129 ADD_INSN(ret, node, pop);
10130 }
10131 return COMPILE_OK;
10132}
10133
10134static int
10135compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10136{
10137 VALUE flag = INT2FIX(excl);
10138 const NODE *b = RNODE_DOT2(node)->nd_beg;
10139 const NODE *e = RNODE_DOT2(node)->nd_end;
10140
10141 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10142 if (!popped) {
10143 VALUE bv = optimized_range_item(b);
10144 VALUE ev = optimized_range_item(e);
10145 VALUE val = rb_range_new(bv, ev, excl);
10146 ADD_INSN1(ret, node, putobject, val);
10147 RB_OBJ_WRITTEN(iseq, Qundef, val);
10148 }
10149 }
10150 else {
10151 CHECK(COMPILE_(ret, "min", b, popped));
10152 CHECK(COMPILE_(ret, "max", e, popped));
10153 if (!popped) {
10154 ADD_INSN1(ret, node, newrange, flag);
10155 }
10156 }
10157 return COMPILE_OK;
10158}
10159
10160static int
10161compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10162{
10163 if (!popped) {
10164 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10165 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10166 }
10167 else {
10168 const rb_iseq_t *ip = iseq;
10169 int level = 0;
10170 while (ip) {
10171 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10172 break;
10173 }
10174 ip = ISEQ_BODY(ip)->parent_iseq;
10175 level++;
10176 }
10177 if (ip) {
10178 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10179 }
10180 else {
10181 ADD_INSN(ret, node, putnil);
10182 }
10183 }
10184 }
10185 return COMPILE_OK;
10186}
10187
10188static int
10189compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10190{
10191 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10192 LABEL *end_label = NEW_LABEL(nd_line(node));
10193 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10194
10195 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10196 /* required argument. do nothing */
10197 COMPILE_ERROR(ERROR_ARGS "unreachable");
10198 return COMPILE_NG;
10199 }
10200 else if (nd_type_p(default_value, NODE_SYM) ||
10201 nd_type_p(default_value, NODE_REGX) ||
10202 nd_type_p(default_value, NODE_LINE) ||
10203 nd_type_p(default_value, NODE_INTEGER) ||
10204 nd_type_p(default_value, NODE_FLOAT) ||
10205 nd_type_p(default_value, NODE_RATIONAL) ||
10206 nd_type_p(default_value, NODE_IMAGINARY) ||
10207 nd_type_p(default_value, NODE_NIL) ||
10208 nd_type_p(default_value, NODE_TRUE) ||
10209 nd_type_p(default_value, NODE_FALSE)) {
10210 COMPILE_ERROR(ERROR_ARGS "unreachable");
10211 return COMPILE_NG;
10212 }
10213 else {
10214 /* if keywordcheck(_kw_bits, nth_keyword)
10215 * kw = default_value
10216 * end
10217 */
10218 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10219 int keyword_idx = body->param.keyword->num;
10220
10221 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10222 ADD_INSNL(ret, node, branchif, end_label);
10223 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10224 ADD_LABEL(ret, end_label);
10225 }
10226 return COMPILE_OK;
10227}
10228
10229static int
10230compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10231{
10232 DECL_ANCHOR(recv);
10233 DECL_ANCHOR(args);
10234 unsigned int flag = 0;
10235 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10236 VALUE argc;
10237 LABEL *else_label = NULL;
10238 VALUE branches = Qfalse;
10239
10240 /* optimization shortcut
10241 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10242 */
10243 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10244 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10245 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10246 (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)) &&
10247 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10248 !frozen_string_literal_p(iseq) &&
10249 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10250 {
10251 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10252 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10253 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10254 if (!popped) {
10255 ADD_INSN(ret, node, swap);
10256 ADD_INSN1(ret, node, topn, INT2FIX(1));
10257 }
10258 ADD_INSN2(ret, node, opt_aset_with, str,
10259 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10260 RB_OBJ_WRITTEN(iseq, Qundef, str);
10261 ADD_INSN(ret, node, pop);
10262 return COMPILE_OK;
10263 }
10264
10265 INIT_ANCHOR(recv);
10266 INIT_ANCHOR(args);
10267 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10268 CHECK(!NIL_P(argc));
10269
10270 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10271 CHECK(asgnflag != -1);
10272 flag |= (unsigned int)asgnflag;
10273
10274 debugp_param("argc", argc);
10275 debugp_param("nd_mid", ID2SYM(mid));
10276
10277 if (!rb_is_attrset_id(mid)) {
10278 /* safe nav attr */
10279 mid = rb_id_attrset(mid);
10280 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10281 }
10282 if (!popped) {
10283 ADD_INSN(ret, node, putnil);
10284 ADD_SEQ(ret, recv);
10285 ADD_SEQ(ret, args);
10286
10287 if (flag & VM_CALL_ARGS_SPLAT) {
10288 ADD_INSN(ret, node, dup);
10289 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10290 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10291 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10292 ADD_INSN (ret, node, pop);
10293 }
10294 else {
10295 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10296 }
10297 }
10298 else {
10299 ADD_SEQ(ret, recv);
10300 ADD_SEQ(ret, args);
10301 }
10302 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10303 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10304 ADD_INSN(ret, node, pop);
10305 return COMPILE_OK;
10306}
10307
10308static int
10309compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10310{
10311 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10312 ADD_SEQ(ret, sub);
10313
10314 if (copy) {
10315 /*
10316 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10317 * NEW_LIST(value, loc), loc);
10318 */
10319 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10320 }
10321 else {
10322 /*
10323 * NEW_CALL(fcore, rb_intern("make_shareable"),
10324 * NEW_LIST(value, loc), loc);
10325 */
10326 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10327 }
10328
10329 return COMPILE_OK;
10330}
10331
10332static VALUE
10333node_const_decl_val(const NODE *node)
10334{
10335 VALUE path;
10336 switch (nd_type(node)) {
10337 case NODE_CDECL:
10338 if (RNODE_CDECL(node)->nd_vid) {
10339 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10340 goto end;
10341 }
10342 else {
10343 node = RNODE_CDECL(node)->nd_else;
10344 }
10345 break;
10346 case NODE_COLON2:
10347 break;
10348 case NODE_COLON3:
10349 // ::Const
10350 path = rb_str_new_cstr("::");
10351 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10352 goto end;
10353 default:
10354 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10356 }
10357
10358 path = rb_ary_new();
10359 if (node) {
10360 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10361 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10362 }
10363 if (node && nd_type_p(node, NODE_CONST)) {
10364 // Const::Name
10365 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10366 }
10367 else if (node && nd_type_p(node, NODE_COLON3)) {
10368 // ::Const::Name
10369 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10370 rb_ary_push(path, rb_str_new(0, 0));
10371 }
10372 else {
10373 // expression::Name
10374 rb_ary_push(path, rb_str_new_cstr("..."));
10375 }
10376 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10377 }
10378 end:
10379 path = rb_fstring(path);
10380 return path;
10381}
10382
10383static VALUE
10384const_decl_path(NODE *dest)
10385{
10386 VALUE path = Qnil;
10387 if (!nd_type_p(dest, NODE_CALL)) {
10388 path = node_const_decl_val(dest);
10389 }
10390 return path;
10391}
10392
10393static int
10394compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10395{
10396 /*
10397 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10398 */
10399 VALUE path = const_decl_path(dest);
10400 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10401 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10402 ADD_INSN1(ret, value, putobject, path);
10403 RB_OBJ_WRITTEN(iseq, Qundef, path);
10404 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10405
10406 return COMPILE_OK;
10407}
10408
10409#ifndef SHAREABLE_BARE_EXPRESSION
10410#define SHAREABLE_BARE_EXPRESSION 1
10411#endif
10412
10413static int
10414compile_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)
10415{
10416# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10417 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10418 VALUE lit = Qnil;
10419 DECL_ANCHOR(anchor);
10420
10421 enum node_type type = node ? nd_type(node) : NODE_NIL;
10422 switch (type) {
10423 case NODE_TRUE:
10424 *value_p = Qtrue;
10425 goto compile;
10426 case NODE_FALSE:
10427 *value_p = Qfalse;
10428 goto compile;
10429 case NODE_NIL:
10430 *value_p = Qnil;
10431 goto compile;
10432 case NODE_SYM:
10433 *value_p = rb_node_sym_string_val(node);
10434 goto compile;
10435 case NODE_REGX:
10436 *value_p = rb_node_regx_string_val(node);
10437 goto compile;
10438 case NODE_LINE:
10439 *value_p = rb_node_line_lineno_val(node);
10440 goto compile;
10441 case NODE_INTEGER:
10442 *value_p = rb_node_integer_literal_val(node);
10443 goto compile;
10444 case NODE_FLOAT:
10445 *value_p = rb_node_float_literal_val(node);
10446 goto compile;
10447 case NODE_RATIONAL:
10448 *value_p = rb_node_rational_literal_val(node);
10449 goto compile;
10450 case NODE_IMAGINARY:
10451 *value_p = rb_node_imaginary_literal_val(node);
10452 goto compile;
10453 case NODE_ENCODING:
10454 *value_p = rb_node_encoding_val(node);
10455
10456 compile:
10457 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10458 *shareable_literal_p = 1;
10459 return COMPILE_OK;
10460
10461 case NODE_DSTR:
10462 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10463 if (shareable == rb_parser_shareable_literal) {
10464 /*
10465 * NEW_CALL(node, idUMinus, 0, loc);
10466 *
10467 * -"#{var}"
10468 */
10469 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10470 }
10471 *value_p = Qundef;
10472 *shareable_literal_p = 1;
10473 return COMPILE_OK;
10474
10475 case NODE_STR:{
10476 VALUE lit = rb_node_str_string_val(node);
10477 ADD_INSN1(ret, node, putobject, lit);
10478 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10479 *value_p = lit;
10480 *shareable_literal_p = 1;
10481
10482 return COMPILE_OK;
10483 }
10484
10485 case NODE_FILE:{
10486 VALUE lit = rb_node_file_path_val(node);
10487 ADD_INSN1(ret, node, putobject, lit);
10488 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10489 *value_p = lit;
10490 *shareable_literal_p = 1;
10491
10492 return COMPILE_OK;
10493 }
10494
10495 case NODE_ZLIST:{
10496 VALUE lit = rb_ary_new();
10497 OBJ_FREEZE(lit);
10498 ADD_INSN1(ret, node, putobject, lit);
10499 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10500 *value_p = lit;
10501 *shareable_literal_p = 1;
10502
10503 return COMPILE_OK;
10504 }
10505
10506 case NODE_LIST:{
10507 INIT_ANCHOR(anchor);
10508 lit = rb_ary_new();
10509 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10510 VALUE val;
10511 int shareable_literal_p2;
10512 NODE *elt = RNODE_LIST(n)->nd_head;
10513 if (elt) {
10514 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10515 if (shareable_literal_p2) {
10516 /* noop */
10517 }
10518 else if (RTEST(lit)) {
10519 rb_ary_clear(lit);
10520 lit = Qfalse;
10521 }
10522 }
10523 if (RTEST(lit)) {
10524 if (!UNDEF_P(val)) {
10525 rb_ary_push(lit, val);
10526 }
10527 else {
10528 rb_ary_clear(lit);
10529 lit = Qnil; /* make shareable at runtime */
10530 }
10531 }
10532 }
10533 break;
10534 }
10535 case NODE_HASH:{
10536 if (!RNODE_HASH(node)->nd_brace) {
10537 *value_p = Qundef;
10538 *shareable_literal_p = 0;
10539 return COMPILE_OK;
10540 }
10541 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10542 if (!RNODE_LIST(n)->nd_head) {
10543 // If the hash node have a keyword splat, fall back to the default case.
10544 goto compile_shareable;
10545 }
10546 }
10547
10548 INIT_ANCHOR(anchor);
10549 lit = rb_hash_new();
10550 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10551 VALUE key_val = 0;
10552 VALUE value_val = 0;
10553 int shareable_literal_p2;
10554 NODE *key = RNODE_LIST(n)->nd_head;
10555 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10556 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10557 if (shareable_literal_p2) {
10558 /* noop */
10559 }
10560 else if (RTEST(lit)) {
10561 rb_hash_clear(lit);
10562 lit = Qfalse;
10563 }
10564 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10565 if (shareable_literal_p2) {
10566 /* noop */
10567 }
10568 else if (RTEST(lit)) {
10569 rb_hash_clear(lit);
10570 lit = Qfalse;
10571 }
10572 if (RTEST(lit)) {
10573 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10574 rb_hash_aset(lit, key_val, value_val);
10575 }
10576 else {
10577 rb_hash_clear(lit);
10578 lit = Qnil; /* make shareable at runtime */
10579 }
10580 }
10581 }
10582 break;
10583 }
10584
10585 default:
10586
10587 compile_shareable:
10588 if (shareable == rb_parser_shareable_literal &&
10589 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10590 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10591 *value_p = Qundef;
10592 *shareable_literal_p = 1;
10593 return COMPILE_OK;
10594 }
10595 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10596 *value_p = Qundef;
10597 *shareable_literal_p = 0;
10598 return COMPILE_OK;
10599 }
10600
10601 /* Array or Hash that does not have keyword splat */
10602 if (!lit) {
10603 if (nd_type(node) == NODE_LIST) {
10604 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10605 }
10606 else if (nd_type(node) == NODE_HASH) {
10607 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10608 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10609 }
10610 *value_p = Qundef;
10611 *shareable_literal_p = 0;
10612 ADD_SEQ(ret, anchor);
10613 return COMPILE_OK;
10614 }
10615 if (NIL_P(lit)) {
10616 // if shareable_literal, all elements should have been ensured
10617 // as shareable
10618 if (nd_type(node) == NODE_LIST) {
10619 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10620 }
10621 else if (nd_type(node) == NODE_HASH) {
10622 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10623 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10624 }
10625 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10626 *value_p = Qundef;
10627 *shareable_literal_p = 1;
10628 }
10629 else {
10631 ADD_INSN1(ret, node, putobject, val);
10632 RB_OBJ_WRITTEN(iseq, Qundef, val);
10633 *value_p = val;
10634 *shareable_literal_p = 1;
10635 }
10636
10637 return COMPILE_OK;
10638}
10639
10640static int
10641compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10642{
10643 int literal_p = 0;
10644 VALUE val;
10645 DECL_ANCHOR(anchor);
10646 INIT_ANCHOR(anchor);
10647
10648 switch (shareable) {
10649 case rb_parser_shareable_none:
10650 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10651 return COMPILE_OK;
10652
10653 case rb_parser_shareable_literal:
10654 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10655 ADD_SEQ(ret, anchor);
10656 return COMPILE_OK;
10657
10658 case rb_parser_shareable_copy:
10659 case rb_parser_shareable_everything:
10660 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10661 if (!literal_p) {
10662 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10663 }
10664 else {
10665 ADD_SEQ(ret, anchor);
10666 }
10667 return COMPILE_OK;
10668 default:
10669 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10670 }
10671}
10672
10673static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10681static int
10682iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10683{
10684 if (node == 0) {
10685 if (!popped) {
10686 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10687 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10688 debugs("node: NODE_NIL(implicit)\n");
10689 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10690 }
10691 return COMPILE_OK;
10692 }
10693 return iseq_compile_each0(iseq, ret, node, popped);
10694}
10695
10696static int
10697iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10698{
10699 const int line = (int)nd_line(node);
10700 const enum node_type type = nd_type(node);
10701 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10702
10703 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10704 /* ignore */
10705 }
10706 else {
10707 if (nd_fl_newline(node)) {
10708 int event = RUBY_EVENT_LINE;
10709 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10710 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10711 event |= RUBY_EVENT_COVERAGE_LINE;
10712 }
10713 ADD_TRACE(ret, event);
10714 }
10715 }
10716
10717 debug_node_start(node);
10718#undef BEFORE_RETURN
10719#define BEFORE_RETURN debug_node_end()
10720
10721 switch (type) {
10722 case NODE_BLOCK:
10723 CHECK(compile_block(iseq, ret, node, popped));
10724 break;
10725 case NODE_IF:
10726 case NODE_UNLESS:
10727 CHECK(compile_if(iseq, ret, node, popped, type));
10728 break;
10729 case NODE_CASE:
10730 CHECK(compile_case(iseq, ret, node, popped));
10731 break;
10732 case NODE_CASE2:
10733 CHECK(compile_case2(iseq, ret, node, popped));
10734 break;
10735 case NODE_CASE3:
10736 CHECK(compile_case3(iseq, ret, node, popped));
10737 break;
10738 case NODE_WHILE:
10739 case NODE_UNTIL:
10740 CHECK(compile_loop(iseq, ret, node, popped, type));
10741 break;
10742 case NODE_FOR:
10743 case NODE_ITER:
10744 CHECK(compile_iter(iseq, ret, node, popped));
10745 break;
10746 case NODE_FOR_MASGN:
10747 CHECK(compile_for_masgn(iseq, ret, node, popped));
10748 break;
10749 case NODE_BREAK:
10750 CHECK(compile_break(iseq, ret, node, popped));
10751 break;
10752 case NODE_NEXT:
10753 CHECK(compile_next(iseq, ret, node, popped));
10754 break;
10755 case NODE_REDO:
10756 CHECK(compile_redo(iseq, ret, node, popped));
10757 break;
10758 case NODE_RETRY:
10759 CHECK(compile_retry(iseq, ret, node, popped));
10760 break;
10761 case NODE_BEGIN:{
10762 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10763 break;
10764 }
10765 case NODE_RESCUE:
10766 CHECK(compile_rescue(iseq, ret, node, popped));
10767 break;
10768 case NODE_RESBODY:
10769 CHECK(compile_resbody(iseq, ret, node, popped));
10770 break;
10771 case NODE_ENSURE:
10772 CHECK(compile_ensure(iseq, ret, node, popped));
10773 break;
10774
10775 case NODE_AND:
10776 case NODE_OR:{
10777 LABEL *end_label = NEW_LABEL(line);
10778 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10779 if (!popped) {
10780 ADD_INSN(ret, node, dup);
10781 }
10782 if (type == NODE_AND) {
10783 ADD_INSNL(ret, node, branchunless, end_label);
10784 }
10785 else {
10786 ADD_INSNL(ret, node, branchif, end_label);
10787 }
10788 if (!popped) {
10789 ADD_INSN(ret, node, pop);
10790 }
10791 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10792 ADD_LABEL(ret, end_label);
10793 break;
10794 }
10795
10796 case NODE_MASGN:{
10797 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10798 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10799 compile_massign(iseq, ret, node, popped);
10800 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10801 break;
10802 }
10803
10804 case NODE_LASGN:{
10805 ID id = RNODE_LASGN(node)->nd_vid;
10806 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10807
10808 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10809 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10810
10811 if (!popped) {
10812 ADD_INSN(ret, node, dup);
10813 }
10814 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10815 break;
10816 }
10817 case NODE_DASGN: {
10818 int idx, lv, ls;
10819 ID id = RNODE_DASGN(node)->nd_vid;
10820 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10821 debugi("dassn id", rb_id2str(id) ? id : '*');
10822
10823 if (!popped) {
10824 ADD_INSN(ret, node, dup);
10825 }
10826
10827 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10828
10829 if (idx < 0) {
10830 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10831 rb_id2str(id));
10832 goto ng;
10833 }
10834 ADD_SETLOCAL(ret, node, ls - idx, lv);
10835 break;
10836 }
10837 case NODE_GASGN:{
10838 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10839
10840 if (!popped) {
10841 ADD_INSN(ret, node, dup);
10842 }
10843 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10844 break;
10845 }
10846 case NODE_IASGN:{
10847 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10848 if (!popped) {
10849 ADD_INSN(ret, node, dup);
10850 }
10851 ADD_INSN2(ret, node, setinstancevariable,
10852 ID2SYM(RNODE_IASGN(node)->nd_vid),
10853 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10854 break;
10855 }
10856 case NODE_CDECL:{
10857 if (RNODE_CDECL(node)->nd_vid) {
10858 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10859
10860 if (!popped) {
10861 ADD_INSN(ret, node, dup);
10862 }
10863
10864 ADD_INSN1(ret, node, putspecialobject,
10865 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10866 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10867 }
10868 else {
10869 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10870 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10871 ADD_INSN(ret, node, swap);
10872
10873 if (!popped) {
10874 ADD_INSN1(ret, node, topn, INT2FIX(1));
10875 ADD_INSN(ret, node, swap);
10876 }
10877
10878 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10879 }
10880 break;
10881 }
10882 case NODE_CVASGN:{
10883 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10884 if (!popped) {
10885 ADD_INSN(ret, node, dup);
10886 }
10887 ADD_INSN2(ret, node, setclassvariable,
10888 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10889 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10890 break;
10891 }
10892 case NODE_OP_ASGN1:
10893 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10894 break;
10895 case NODE_OP_ASGN2:
10896 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10897 break;
10898 case NODE_OP_CDECL:
10899 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10900 break;
10901 case NODE_OP_ASGN_AND:
10902 case NODE_OP_ASGN_OR:
10903 CHECK(compile_op_log(iseq, ret, node, popped, type));
10904 break;
10905 case NODE_CALL: /* obj.foo */
10906 case NODE_OPCALL: /* foo[] */
10907 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10908 break;
10909 }
10910 case NODE_QCALL: /* obj&.foo */
10911 case NODE_FCALL: /* foo() */
10912 case NODE_VCALL: /* foo (variable or call) */
10913 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10914 goto ng;
10915 }
10916 break;
10917 case NODE_SUPER:
10918 case NODE_ZSUPER:
10919 CHECK(compile_super(iseq, ret, node, popped, type));
10920 break;
10921 case NODE_LIST:{
10922 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10923 break;
10924 }
10925 case NODE_ZLIST:{
10926 if (!popped) {
10927 ADD_INSN1(ret, node, newarray, INT2FIX(0));
10928 }
10929 break;
10930 }
10931 case NODE_HASH:
10932 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10933 break;
10934 case NODE_RETURN:
10935 CHECK(compile_return(iseq, ret, node, popped));
10936 break;
10937 case NODE_YIELD:
10938 CHECK(compile_yield(iseq, ret, node, popped));
10939 break;
10940 case NODE_LVAR:{
10941 if (!popped) {
10942 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10943 }
10944 break;
10945 }
10946 case NODE_DVAR:{
10947 int lv, idx, ls;
10948 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10949 if (!popped) {
10950 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10951 if (idx < 0) {
10952 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10953 rb_id2str(RNODE_DVAR(node)->nd_vid));
10954 goto ng;
10955 }
10956 ADD_GETLOCAL(ret, node, ls - idx, lv);
10957 }
10958 break;
10959 }
10960 case NODE_GVAR:{
10961 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10962 if (popped) {
10963 ADD_INSN(ret, node, pop);
10964 }
10965 break;
10966 }
10967 case NODE_IVAR:{
10968 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10969 if (!popped) {
10970 ADD_INSN2(ret, node, getinstancevariable,
10971 ID2SYM(RNODE_IVAR(node)->nd_vid),
10972 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10973 }
10974 break;
10975 }
10976 case NODE_CONST:{
10977 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
10978
10979 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10980 body->ic_size++;
10981 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
10982 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10983 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10984 }
10985 else {
10986 ADD_INSN(ret, node, putnil);
10987 ADD_INSN1(ret, node, putobject, Qtrue);
10988 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
10989 }
10990
10991 if (popped) {
10992 ADD_INSN(ret, node, pop);
10993 }
10994 break;
10995 }
10996 case NODE_CVAR:{
10997 if (!popped) {
10998 ADD_INSN2(ret, node, getclassvariable,
10999 ID2SYM(RNODE_CVAR(node)->nd_vid),
11000 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11001 }
11002 break;
11003 }
11004 case NODE_NTH_REF:{
11005 if (!popped) {
11006 if (!RNODE_NTH_REF(node)->nd_nth) {
11007 ADD_INSN(ret, node, putnil);
11008 break;
11009 }
11010 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11011 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11012 }
11013 break;
11014 }
11015 case NODE_BACK_REF:{
11016 if (!popped) {
11017 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11018 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11019 }
11020 break;
11021 }
11022 case NODE_MATCH:
11023 case NODE_MATCH2:
11024 case NODE_MATCH3:
11025 CHECK(compile_match(iseq, ret, node, popped, type));
11026 break;
11027 case NODE_SYM:{
11028 if (!popped) {
11029 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11030 }
11031 break;
11032 }
11033 case NODE_LINE:{
11034 if (!popped) {
11035 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11036 }
11037 break;
11038 }
11039 case NODE_ENCODING:{
11040 if (!popped) {
11041 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11042 }
11043 break;
11044 }
11045 case NODE_INTEGER:{
11046 VALUE lit = rb_node_integer_literal_val(node);
11047 debugp_param("integer", lit);
11048 if (!popped) {
11049 ADD_INSN1(ret, node, putobject, lit);
11050 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11051 }
11052 break;
11053 }
11054 case NODE_FLOAT:{
11055 VALUE lit = rb_node_float_literal_val(node);
11056 debugp_param("float", lit);
11057 if (!popped) {
11058 ADD_INSN1(ret, node, putobject, lit);
11059 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11060 }
11061 break;
11062 }
11063 case NODE_RATIONAL:{
11064 VALUE lit = rb_node_rational_literal_val(node);
11065 debugp_param("rational", lit);
11066 if (!popped) {
11067 ADD_INSN1(ret, node, putobject, lit);
11068 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11069 }
11070 break;
11071 }
11072 case NODE_IMAGINARY:{
11073 VALUE lit = rb_node_imaginary_literal_val(node);
11074 debugp_param("imaginary", lit);
11075 if (!popped) {
11076 ADD_INSN1(ret, node, putobject, lit);
11077 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11078 }
11079 break;
11080 }
11081 case NODE_FILE:
11082 case NODE_STR:{
11083 debugp_param("nd_lit", get_string_value(node));
11084 if (!popped) {
11085 VALUE lit = get_string_value(node);
11086 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11087 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11088 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11089 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11090 }
11091 switch (option->frozen_string_literal) {
11092 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11093 ADD_INSN1(ret, node, putchilledstring, lit);
11094 break;
11095 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11096 ADD_INSN1(ret, node, putstring, lit);
11097 break;
11098 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11099 ADD_INSN1(ret, node, putobject, lit);
11100 break;
11101 default:
11102 rb_bug("invalid frozen_string_literal");
11103 }
11104 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11105 }
11106 break;
11107 }
11108 case NODE_DSTR:{
11109 compile_dstr(iseq, ret, node);
11110
11111 if (popped) {
11112 ADD_INSN(ret, node, pop);
11113 }
11114 break;
11115 }
11116 case NODE_XSTR:{
11117 ADD_CALL_RECEIVER(ret, node);
11118 VALUE str = rb_node_str_string_val(node);
11119 ADD_INSN1(ret, node, putobject, str);
11120 RB_OBJ_WRITTEN(iseq, Qundef, str);
11121 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11122
11123 if (popped) {
11124 ADD_INSN(ret, node, pop);
11125 }
11126 break;
11127 }
11128 case NODE_DXSTR:{
11129 ADD_CALL_RECEIVER(ret, node);
11130 compile_dstr(iseq, ret, node);
11131 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11132
11133 if (popped) {
11134 ADD_INSN(ret, node, pop);
11135 }
11136 break;
11137 }
11138 case NODE_EVSTR:
11139 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11140 break;
11141 case NODE_REGX:{
11142 if (!popped) {
11143 VALUE lit = rb_node_regx_string_val(node);
11144 ADD_INSN1(ret, node, putobject, lit);
11145 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11146 }
11147 break;
11148 }
11149 case NODE_DREGX:
11150 compile_dregx(iseq, ret, node, popped);
11151 break;
11152 case NODE_ONCE:{
11153 int ic_index = body->ise_size++;
11154 const rb_iseq_t *block_iseq;
11155 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11156
11157 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11158 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11159
11160 if (popped) {
11161 ADD_INSN(ret, node, pop);
11162 }
11163 break;
11164 }
11165 case NODE_ARGSCAT:{
11166 if (popped) {
11167 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11168 ADD_INSN1(ret, node, splatarray, Qfalse);
11169 ADD_INSN(ret, node, pop);
11170 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11171 ADD_INSN1(ret, node, splatarray, Qfalse);
11172 ADD_INSN(ret, node, pop);
11173 }
11174 else {
11175 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11176 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11177 if (nd_type_p(body_node, NODE_LIST)) {
11178 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11179 }
11180 else {
11181 CHECK(COMPILE(ret, "argscat body", body_node));
11182 ADD_INSN(ret, node, concattoarray);
11183 }
11184 }
11185 break;
11186 }
11187 case NODE_ARGSPUSH:{
11188 if (popped) {
11189 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11190 ADD_INSN1(ret, node, splatarray, Qfalse);
11191 ADD_INSN(ret, node, pop);
11192 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11193 }
11194 else {
11195 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11196 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11197 if (keyword_node_p(body_node)) {
11198 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11199 ADD_INSN(ret, node, pushtoarraykwsplat);
11200 }
11201 else if (static_literal_node_p(body_node, iseq, false)) {
11202 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11203 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11204 }
11205 else {
11206 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11207 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11208 }
11209 }
11210 break;
11211 }
11212 case NODE_SPLAT:{
11213 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11214 ADD_INSN1(ret, node, splatarray, Qtrue);
11215
11216 if (popped) {
11217 ADD_INSN(ret, node, pop);
11218 }
11219 break;
11220 }
11221 case NODE_DEFN:{
11222 ID mid = RNODE_DEFN(node)->nd_mid;
11223 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11224 rb_id2str(mid),
11225 ISEQ_TYPE_METHOD, line);
11226
11227 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11228 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11229 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11230
11231 if (!popped) {
11232 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11233 }
11234
11235 break;
11236 }
11237 case NODE_DEFS:{
11238 ID mid = RNODE_DEFS(node)->nd_mid;
11239 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11240 rb_id2str(mid),
11241 ISEQ_TYPE_METHOD, line);
11242
11243 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11244 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11245 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11246 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11247
11248 if (!popped) {
11249 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11250 }
11251 break;
11252 }
11253 case NODE_ALIAS:{
11254 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11255 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11256 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11257 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11258 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11259
11260 if (popped) {
11261 ADD_INSN(ret, node, pop);
11262 }
11263 break;
11264 }
11265 case NODE_VALIAS:{
11266 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11267 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11268 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11269 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11270
11271 if (popped) {
11272 ADD_INSN(ret, node, pop);
11273 }
11274 break;
11275 }
11276 case NODE_UNDEF:{
11277 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11278
11279 for (long i = 0; i < ary->len; i++) {
11280 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11281 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11282 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11283 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11284
11285 if (i < ary->len - 1) {
11286 ADD_INSN(ret, node, pop);
11287 }
11288 }
11289
11290 if (popped) {
11291 ADD_INSN(ret, node, pop);
11292 }
11293 break;
11294 }
11295 case NODE_CLASS:{
11296 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11297 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11298 ISEQ_TYPE_CLASS, line);
11299 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11300 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11301 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11302
11303 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11304 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11305 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11306
11307 if (popped) {
11308 ADD_INSN(ret, node, pop);
11309 }
11310 break;
11311 }
11312 case NODE_MODULE:{
11313 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11314 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11315 ISEQ_TYPE_CLASS, line);
11316 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11317 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11318
11319 ADD_INSN (ret, node, putnil); /* dummy */
11320 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11321 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11322
11323 if (popped) {
11324 ADD_INSN(ret, node, pop);
11325 }
11326 break;
11327 }
11328 case NODE_SCLASS:{
11329 ID singletonclass;
11330 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11331 ISEQ_TYPE_CLASS, line);
11332
11333 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11334 ADD_INSN (ret, node, putnil);
11335 CONST_ID(singletonclass, "singletonclass");
11336 ADD_INSN3(ret, node, defineclass,
11337 ID2SYM(singletonclass), singleton_class,
11338 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11339 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11340
11341 if (popped) {
11342 ADD_INSN(ret, node, pop);
11343 }
11344 break;
11345 }
11346 case NODE_COLON2:
11347 CHECK(compile_colon2(iseq, ret, node, popped));
11348 break;
11349 case NODE_COLON3:
11350 CHECK(compile_colon3(iseq, ret, node, popped));
11351 break;
11352 case NODE_DOT2:
11353 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11354 break;
11355 case NODE_DOT3:
11356 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11357 break;
11358 case NODE_FLIP2:
11359 case NODE_FLIP3:{
11360 LABEL *lend = NEW_LABEL(line);
11361 LABEL *ltrue = NEW_LABEL(line);
11362 LABEL *lfalse = NEW_LABEL(line);
11363 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11364 ltrue, lfalse));
11365 ADD_LABEL(ret, ltrue);
11366 ADD_INSN1(ret, node, putobject, Qtrue);
11367 ADD_INSNL(ret, node, jump, lend);
11368 ADD_LABEL(ret, lfalse);
11369 ADD_INSN1(ret, node, putobject, Qfalse);
11370 ADD_LABEL(ret, lend);
11371 break;
11372 }
11373 case NODE_SELF:{
11374 if (!popped) {
11375 ADD_INSN(ret, node, putself);
11376 }
11377 break;
11378 }
11379 case NODE_NIL:{
11380 if (!popped) {
11381 ADD_INSN(ret, node, putnil);
11382 }
11383 break;
11384 }
11385 case NODE_TRUE:{
11386 if (!popped) {
11387 ADD_INSN1(ret, node, putobject, Qtrue);
11388 }
11389 break;
11390 }
11391 case NODE_FALSE:{
11392 if (!popped) {
11393 ADD_INSN1(ret, node, putobject, Qfalse);
11394 }
11395 break;
11396 }
11397 case NODE_ERRINFO:
11398 CHECK(compile_errinfo(iseq, ret, node, popped));
11399 break;
11400 case NODE_DEFINED:
11401 if (!popped) {
11402 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11403 }
11404 break;
11405 case NODE_POSTEXE:{
11406 /* compiled to:
11407 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11408 */
11409 int is_index = body->ise_size++;
11411 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11412 const rb_iseq_t *once_iseq =
11413 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11414
11415 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11416 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11417
11418 if (popped) {
11419 ADD_INSN(ret, node, pop);
11420 }
11421 break;
11422 }
11423 case NODE_KW_ARG:
11424 CHECK(compile_kw_arg(iseq, ret, node, popped));
11425 break;
11426 case NODE_DSYM:{
11427 compile_dstr(iseq, ret, node);
11428 if (!popped) {
11429 ADD_INSN(ret, node, intern);
11430 }
11431 else {
11432 ADD_INSN(ret, node, pop);
11433 }
11434 break;
11435 }
11436 case NODE_ATTRASGN:
11437 CHECK(compile_attrasgn(iseq, ret, node, popped));
11438 break;
11439 case NODE_LAMBDA:{
11440 /* compile same as lambda{...} */
11441 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11442 VALUE argc = INT2FIX(0);
11443
11444 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11445 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11446 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11447
11448 if (popped) {
11449 ADD_INSN(ret, node, pop);
11450 }
11451 break;
11452 }
11453 default:
11454 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11455 ng:
11456 debug_node_end();
11457 return COMPILE_NG;
11458 }
11459
11460 debug_node_end();
11461 return COMPILE_OK;
11462}
11463
11464/***************************/
11465/* instruction information */
11466/***************************/
11467
11468static int
11469insn_data_length(INSN *iobj)
11470{
11471 return insn_len(iobj->insn_id);
11472}
11473
11474static int
11475calc_sp_depth(int depth, INSN *insn)
11476{
11477 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11478}
11479
11480static VALUE
11481opobj_inspect(VALUE obj)
11482{
11483 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11484 switch (BUILTIN_TYPE(obj)) {
11485 case T_STRING:
11486 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11487 break;
11488 case T_ARRAY:
11489 obj = rb_ary_dup(obj);
11490 break;
11491 default:
11492 break;
11493 }
11494 }
11495 return rb_inspect(obj);
11496}
11497
11498
11499
11500static VALUE
11501insn_data_to_s_detail(INSN *iobj)
11502{
11503 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11504
11505 if (iobj->operands) {
11506 const char *types = insn_op_types(iobj->insn_id);
11507 int j;
11508
11509 for (j = 0; types[j]; j++) {
11510 char type = types[j];
11511
11512 switch (type) {
11513 case TS_OFFSET: /* label(destination position) */
11514 {
11515 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11516 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11517 break;
11518 }
11519 break;
11520 case TS_ISEQ: /* iseq */
11521 {
11522 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11523 VALUE val = Qnil;
11524 if (0 && iseq) { /* TODO: invalidate now */
11525 val = (VALUE)iseq;
11526 }
11527 rb_str_concat(str, opobj_inspect(val));
11528 }
11529 break;
11530 case TS_LINDEX:
11531 case TS_NUM: /* ulong */
11532 case TS_VALUE: /* VALUE */
11533 {
11534 VALUE v = OPERAND_AT(iobj, j);
11535 if (!CLASS_OF(v))
11536 rb_str_cat2(str, "<hidden>");
11537 else {
11538 rb_str_concat(str, opobj_inspect(v));
11539 }
11540 break;
11541 }
11542 case TS_ID: /* ID */
11543 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11544 break;
11545 case TS_IC: /* inline cache */
11546 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11547 break;
11548 case TS_IVC: /* inline ivar cache */
11549 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11550 break;
11551 case TS_ICVARC: /* inline cvar cache */
11552 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11553 break;
11554 case TS_ISE: /* inline storage entry */
11555 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11556 break;
11557 case TS_CALLDATA: /* we store these as call infos at compile time */
11558 {
11559 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11560 rb_str_cat2(str, "<calldata:");
11561 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11562 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11563 break;
11564 }
11565 case TS_CDHASH: /* case/when condition cache */
11566 rb_str_cat2(str, "<ch>");
11567 break;
11568 case TS_FUNCPTR:
11569 {
11570 void *func = (void *)OPERAND_AT(iobj, j);
11571#ifdef HAVE_DLADDR
11572 Dl_info info;
11573 if (dladdr(func, &info) && info.dli_sname) {
11574 rb_str_cat2(str, info.dli_sname);
11575 break;
11576 }
11577#endif
11578 rb_str_catf(str, "<%p>", func);
11579 }
11580 break;
11581 case TS_BUILTIN:
11582 rb_str_cat2(str, "<TS_BUILTIN>");
11583 break;
11584 default:{
11585 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11586 }
11587 }
11588 if (types[j + 1]) {
11589 rb_str_cat2(str, ", ");
11590 }
11591 }
11592 }
11593 return str;
11594}
11595
11596static void
11597dump_disasm_list(const LINK_ELEMENT *link)
11598{
11599 dump_disasm_list_with_cursor(link, NULL, NULL);
11600}
11601
11602static void
11603dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11604{
11605 int pos = 0;
11606 INSN *iobj;
11607 LABEL *lobj;
11608 VALUE str;
11609
11610 printf("-- raw disasm--------\n");
11611
11612 while (link) {
11613 if (curr) printf(curr == link ? "*" : " ");
11614 switch (link->type) {
11615 case ISEQ_ELEMENT_INSN:
11616 {
11617 iobj = (INSN *)link;
11618 str = insn_data_to_s_detail(iobj);
11619 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11620 pos += insn_data_length(iobj);
11621 break;
11622 }
11623 case ISEQ_ELEMENT_LABEL:
11624 {
11625 lobj = (LABEL *)link;
11626 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11627 dest == lobj ? " <---" : "");
11628 break;
11629 }
11630 case ISEQ_ELEMENT_TRACE:
11631 {
11632 TRACE *trace = (TRACE *)link;
11633 printf(" trace: %0x\n", trace->event);
11634 break;
11635 }
11636 case ISEQ_ELEMENT_ADJUST:
11637 {
11638 ADJUST *adjust = (ADJUST *)link;
11639 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11640 break;
11641 }
11642 default:
11643 /* ignore */
11644 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11645 }
11646 link = link->next;
11647 }
11648 printf("---------------------\n");
11649 fflush(stdout);
11650}
11651
11652int
11653rb_insn_len(VALUE insn)
11654{
11655 return insn_len(insn);
11656}
11657
11658const char *
11659rb_insns_name(int i)
11660{
11661 return insn_name(i);
11662}
11663
11664VALUE
11665rb_insns_name_array(void)
11666{
11667 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11668 int i;
11669 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11670 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11671 }
11672 return rb_ary_freeze(ary);
11673}
11674
11675static LABEL *
11676register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11677{
11678 LABEL *label = 0;
11679 st_data_t tmp;
11680 obj = rb_to_symbol_type(obj);
11681
11682 if (st_lookup(labels_table, obj, &tmp) == 0) {
11683 label = NEW_LABEL(0);
11684 st_insert(labels_table, obj, (st_data_t)label);
11685 }
11686 else {
11687 label = (LABEL *)tmp;
11688 }
11689 LABEL_REF(label);
11690 return label;
11691}
11692
11693static VALUE
11694get_exception_sym2type(VALUE sym)
11695{
11696 static VALUE symRescue, symEnsure, symRetry;
11697 static VALUE symBreak, symRedo, symNext;
11698
11699 if (symRescue == 0) {
11700 symRescue = ID2SYM(rb_intern_const("rescue"));
11701 symEnsure = ID2SYM(rb_intern_const("ensure"));
11702 symRetry = ID2SYM(rb_intern_const("retry"));
11703 symBreak = ID2SYM(rb_intern_const("break"));
11704 symRedo = ID2SYM(rb_intern_const("redo"));
11705 symNext = ID2SYM(rb_intern_const("next"));
11706 }
11707
11708 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11709 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11710 if (sym == symRetry) return CATCH_TYPE_RETRY;
11711 if (sym == symBreak) return CATCH_TYPE_BREAK;
11712 if (sym == symRedo) return CATCH_TYPE_REDO;
11713 if (sym == symNext) return CATCH_TYPE_NEXT;
11714 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11715 return 0;
11716}
11717
11718static int
11719iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11720 VALUE exception)
11721{
11722 int i;
11723
11724 for (i=0; i<RARRAY_LEN(exception); i++) {
11725 const rb_iseq_t *eiseq;
11726 VALUE v, type;
11727 LABEL *lstart, *lend, *lcont;
11728 unsigned int sp;
11729
11730 v = rb_to_array_type(RARRAY_AREF(exception, i));
11731 if (RARRAY_LEN(v) != 6) {
11732 rb_raise(rb_eSyntaxError, "wrong exception entry");
11733 }
11734 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11735 if (NIL_P(RARRAY_AREF(v, 1))) {
11736 eiseq = NULL;
11737 }
11738 else {
11739 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11740 }
11741
11742 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11743 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11744 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11745 sp = NUM2UINT(RARRAY_AREF(v, 5));
11746
11747 /* TODO: Dirty Hack! Fix me */
11748 if (type == CATCH_TYPE_RESCUE ||
11749 type == CATCH_TYPE_BREAK ||
11750 type == CATCH_TYPE_NEXT) {
11751 ++sp;
11752 }
11753
11754 lcont->sp = sp;
11755
11756 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11757
11758 RB_GC_GUARD(v);
11759 }
11760 return COMPILE_OK;
11761}
11762
11763static struct st_table *
11764insn_make_insn_table(void)
11765{
11766 struct st_table *table;
11767 int i;
11768 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11769
11770 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11771 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11772 }
11773
11774 return table;
11775}
11776
11777static const rb_iseq_t *
11778iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11779{
11780 VALUE iseqw;
11781 const rb_iseq_t *loaded_iseq;
11782
11783 if (RB_TYPE_P(op, T_ARRAY)) {
11784 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11785 }
11786 else if (CLASS_OF(op) == rb_cISeq) {
11787 iseqw = op;
11788 }
11789 else {
11790 rb_raise(rb_eSyntaxError, "ISEQ is required");
11791 }
11792
11793 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11794 return loaded_iseq;
11795}
11796
11797static VALUE
11798iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11799{
11800 ID mid = 0;
11801 int orig_argc = 0;
11802 unsigned int flag = 0;
11803 struct rb_callinfo_kwarg *kw_arg = 0;
11804
11805 if (!NIL_P(op)) {
11806 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11807 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11808 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11809 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11810
11811 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11812 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11813 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11814
11815 if (!NIL_P(vkw_arg)) {
11816 int i;
11817 int len = RARRAY_LENINT(vkw_arg);
11818 size_t n = rb_callinfo_kwarg_bytes(len);
11819
11820 kw_arg = xmalloc(n);
11821 kw_arg->references = 0;
11822 kw_arg->keyword_len = len;
11823 for (i = 0; i < len; i++) {
11824 VALUE kw = RARRAY_AREF(vkw_arg, i);
11825 SYM2ID(kw); /* make immortal */
11826 kw_arg->keywords[i] = kw;
11827 }
11828 }
11829 }
11830
11831 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11832 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11833 return (VALUE)ci;
11834}
11835
11836static rb_event_flag_t
11837event_name_to_flag(VALUE sym)
11838{
11839#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11840 CHECK_EVENT(RUBY_EVENT_LINE);
11841 CHECK_EVENT(RUBY_EVENT_CLASS);
11842 CHECK_EVENT(RUBY_EVENT_END);
11843 CHECK_EVENT(RUBY_EVENT_CALL);
11844 CHECK_EVENT(RUBY_EVENT_RETURN);
11845 CHECK_EVENT(RUBY_EVENT_B_CALL);
11846 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11847 CHECK_EVENT(RUBY_EVENT_RESCUE);
11848#undef CHECK_EVENT
11849 return RUBY_EVENT_NONE;
11850}
11851
11852static int
11853iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11854 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11855{
11856 /* TODO: body should be frozen */
11857 long i, len = RARRAY_LEN(body);
11858 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11859 int j;
11860 int line_no = 0, node_id = -1, insn_idx = 0;
11861 int ret = COMPILE_OK;
11862
11863 /*
11864 * index -> LABEL *label
11865 */
11866 static struct st_table *insn_table;
11867
11868 if (insn_table == 0) {
11869 insn_table = insn_make_insn_table();
11870 }
11871
11872 for (i=0; i<len; i++) {
11873 VALUE obj = RARRAY_AREF(body, i);
11874
11875 if (SYMBOL_P(obj)) {
11876 rb_event_flag_t event;
11877 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11878 ADD_TRACE(anchor, event);
11879 }
11880 else {
11881 LABEL *label = register_label(iseq, labels_table, obj);
11882 ADD_LABEL(anchor, label);
11883 }
11884 }
11885 else if (FIXNUM_P(obj)) {
11886 line_no = NUM2INT(obj);
11887 }
11888 else if (RB_TYPE_P(obj, T_ARRAY)) {
11889 VALUE *argv = 0;
11890 int argc = RARRAY_LENINT(obj) - 1;
11891 st_data_t insn_id;
11892 VALUE insn;
11893
11894 if (node_ids) {
11895 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11896 }
11897
11898 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11899 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11900 /* TODO: exception */
11901 COMPILE_ERROR(iseq, line_no,
11902 "unknown instruction: %+"PRIsVALUE, insn);
11903 ret = COMPILE_NG;
11904 break;
11905 }
11906
11907 if (argc != insn_len((VALUE)insn_id)-1) {
11908 COMPILE_ERROR(iseq, line_no,
11909 "operand size mismatch");
11910 ret = COMPILE_NG;
11911 break;
11912 }
11913
11914 if (argc > 0) {
11915 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11916
11917 // add element before operand setup to make GC root
11918 ADD_ELEM(anchor,
11919 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11920 (enum ruby_vminsn_type)insn_id, argc, argv));
11921
11922 for (j=0; j<argc; j++) {
11923 VALUE op = rb_ary_entry(obj, j+1);
11924 switch (insn_op_type((VALUE)insn_id, j)) {
11925 case TS_OFFSET: {
11926 LABEL *label = register_label(iseq, labels_table, op);
11927 argv[j] = (VALUE)label;
11928 break;
11929 }
11930 case TS_LINDEX:
11931 case TS_NUM:
11932 (void)NUM2INT(op);
11933 argv[j] = op;
11934 break;
11935 case TS_VALUE:
11936 argv[j] = op;
11937 RB_OBJ_WRITTEN(iseq, Qundef, op);
11938 break;
11939 case TS_ISEQ:
11940 {
11941 if (op != Qnil) {
11942 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
11943 argv[j] = v;
11944 RB_OBJ_WRITTEN(iseq, Qundef, v);
11945 }
11946 else {
11947 argv[j] = 0;
11948 }
11949 }
11950 break;
11951 case TS_ISE:
11952 argv[j] = op;
11953 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11954 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
11955 }
11956 break;
11957 case TS_IC:
11958 {
11959 VALUE segments = rb_ary_new();
11960 op = rb_to_array_type(op);
11961
11962 for (int i = 0; i < RARRAY_LEN(op); i++) {
11963 VALUE sym = RARRAY_AREF(op, i);
11964 sym = rb_to_symbol_type(sym);
11965 rb_ary_push(segments, sym);
11966 }
11967
11968 RB_GC_GUARD(op);
11969 argv[j] = segments;
11970 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11971 ISEQ_BODY(iseq)->ic_size++;
11972 }
11973 break;
11974 case TS_IVC: /* inline ivar cache */
11975 argv[j] = op;
11976 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
11977 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
11978 }
11979 break;
11980 case TS_ICVARC: /* inline cvar cache */
11981 argv[j] = op;
11982 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
11983 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
11984 }
11985 break;
11986 case TS_CALLDATA:
11987 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
11988 break;
11989 case TS_ID:
11990 argv[j] = rb_to_symbol_type(op);
11991 break;
11992 case TS_CDHASH:
11993 {
11994 int i;
11995 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
11996
11997 RHASH_TBL_RAW(map)->type = &cdhash_type;
11998 op = rb_to_array_type(op);
11999 for (i=0; i<RARRAY_LEN(op); i+=2) {
12000 VALUE key = RARRAY_AREF(op, i);
12001 VALUE sym = RARRAY_AREF(op, i+1);
12002 LABEL *label =
12003 register_label(iseq, labels_table, sym);
12004 rb_hash_aset(map, key, (VALUE)label | 1);
12005 }
12006 RB_GC_GUARD(op);
12007 argv[j] = map;
12008 RB_OBJ_WRITTEN(iseq, Qundef, map);
12009 }
12010 break;
12011 case TS_FUNCPTR:
12012 {
12013#if SIZEOF_VALUE <= SIZEOF_LONG
12014 long funcptr = NUM2LONG(op);
12015#else
12016 LONG_LONG funcptr = NUM2LL(op);
12017#endif
12018 argv[j] = (VALUE)funcptr;
12019 }
12020 break;
12021 default:
12022 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12023 }
12024 }
12025 }
12026 else {
12027 ADD_ELEM(anchor,
12028 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12029 (enum ruby_vminsn_type)insn_id, argc, NULL));
12030 }
12031 }
12032 else {
12033 rb_raise(rb_eTypeError, "unexpected object for instruction");
12034 }
12035 }
12036 RTYPEDDATA_DATA(labels_wrapper) = 0;
12037 RB_GC_GUARD(labels_wrapper);
12038 validate_labels(iseq, labels_table);
12039 if (!ret) return ret;
12040 return iseq_setup(iseq, anchor);
12041}
12042
12043#define CHECK_ARRAY(v) rb_to_array_type(v)
12044#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12045
12046static int
12047int_param(int *dst, VALUE param, VALUE sym)
12048{
12049 VALUE val = rb_hash_aref(param, sym);
12050 if (FIXNUM_P(val)) {
12051 *dst = FIX2INT(val);
12052 return TRUE;
12053 }
12054 else if (!NIL_P(val)) {
12055 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12056 sym, val);
12057 }
12058 return FALSE;
12059}
12060
12061static const struct rb_iseq_param_keyword *
12062iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12063{
12064 int i, j;
12065 int len = RARRAY_LENINT(keywords);
12066 int default_len;
12067 VALUE key, sym, default_val;
12068 VALUE *dvs;
12069 ID *ids;
12070 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12071
12072 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12073
12074 keyword->num = len;
12075#define SYM(s) ID2SYM(rb_intern_const(#s))
12076 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12077 i = keyword->bits_start - keyword->num;
12078 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12079#undef SYM
12080
12081 /* required args */
12082 for (i = 0; i < len; i++) {
12083 VALUE val = RARRAY_AREF(keywords, i);
12084
12085 if (!SYMBOL_P(val)) {
12086 goto default_values;
12087 }
12088 ids[i] = SYM2ID(val);
12089 keyword->required_num++;
12090 }
12091
12092 default_values: /* note: we intentionally preserve `i' from previous loop */
12093 default_len = len - i;
12094 if (default_len == 0) {
12095 keyword->table = ids;
12096 return keyword;
12097 }
12098 else if (default_len < 0) {
12100 }
12101
12102 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12103
12104 for (j = 0; i < len; i++, j++) {
12105 key = RARRAY_AREF(keywords, i);
12106 CHECK_ARRAY(key);
12107
12108 switch (RARRAY_LEN(key)) {
12109 case 1:
12110 sym = RARRAY_AREF(key, 0);
12111 default_val = Qundef;
12112 break;
12113 case 2:
12114 sym = RARRAY_AREF(key, 0);
12115 default_val = RARRAY_AREF(key, 1);
12116 break;
12117 default:
12118 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12119 }
12120 ids[i] = SYM2ID(sym);
12121 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12122 }
12123
12124 keyword->table = ids;
12125 keyword->default_values = dvs;
12126
12127 return keyword;
12128}
12129
12130static void
12131iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
12132{
12133 rb_gc_mark(obj);
12134}
12135
12136void
12137rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
12138{
12139 INSN *iobj = 0;
12140 size_t size = sizeof(INSN);
12141 unsigned int pos = 0;
12142
12143 while (storage) {
12144#ifdef STRICT_ALIGNMENT
12145 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12146#else
12147 const size_t padding = 0; /* expected to be optimized by compiler */
12148#endif /* STRICT_ALIGNMENT */
12149 size_t offset = pos + size + padding;
12150 if (offset > storage->size || offset > storage->pos) {
12151 pos = 0;
12152 storage = storage->next;
12153 }
12154 else {
12155#ifdef STRICT_ALIGNMENT
12156 pos += (int)padding;
12157#endif /* STRICT_ALIGNMENT */
12158
12159 iobj = (INSN *)&storage->buff[pos];
12160
12161 if (iobj->operands) {
12162 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
12163 }
12164 pos += (int)size;
12165 }
12166 }
12167}
12168
12169static const rb_data_type_t labels_wrapper_type = {
12170 .wrap_struct_name = "compiler/labels_wrapper",
12171 .function = {
12172 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12173 .dfree = (RUBY_DATA_FUNC)st_free_table,
12174 },
12175 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12176};
12177
12178void
12179rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12180 VALUE exception, VALUE body)
12181{
12182#define SYM(s) ID2SYM(rb_intern_const(#s))
12183 int i, len;
12184 unsigned int arg_size, local_size, stack_max;
12185 ID *tbl;
12186 struct st_table *labels_table = st_init_numtable();
12187 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12188 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12189 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12190 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12191 DECL_ANCHOR(anchor);
12192 INIT_ANCHOR(anchor);
12193
12194 len = RARRAY_LENINT(locals);
12195 ISEQ_BODY(iseq)->local_table_size = len;
12196 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12197
12198 for (i = 0; i < len; i++) {
12199 VALUE lv = RARRAY_AREF(locals, i);
12200
12201 if (sym_arg_rest == lv) {
12202 tbl[i] = 0;
12203 }
12204 else {
12205 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12206 }
12207 }
12208
12209#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12210 if (INT_PARAM(lead_num)) {
12211 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12212 }
12213 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12214 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12215 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12216 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12217#undef INT_PARAM
12218 {
12219#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12220 int x;
12221 INT_PARAM(arg_size);
12222 INT_PARAM(local_size);
12223 INT_PARAM(stack_max);
12224#undef INT_PARAM
12225 }
12226
12227 VALUE node_ids = Qfalse;
12228#ifdef USE_ISEQ_NODE_ID
12229 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12230 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12231 rb_raise(rb_eTypeError, "node_ids is not an array");
12232 }
12233#endif
12234
12235 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12236 len = RARRAY_LENINT(arg_opt_labels);
12237 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12238
12239 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12240 VALUE *opt_table = ALLOC_N(VALUE, len);
12241
12242 for (i = 0; i < len; i++) {
12243 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12244 LABEL *label = register_label(iseq, labels_table, ent);
12245 opt_table[i] = (VALUE)label;
12246 }
12247
12248 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12249 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12250 }
12251 }
12252 else if (!NIL_P(arg_opt_labels)) {
12253 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12254 arg_opt_labels);
12255 }
12256
12257 if (RB_TYPE_P(keywords, T_ARRAY)) {
12258 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12259 }
12260 else if (!NIL_P(keywords)) {
12261 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12262 keywords);
12263 }
12264
12265 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12266 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12267 }
12268
12269 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12270 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12271 }
12272
12273 if (int_param(&i, params, SYM(kwrest))) {
12274 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12275 if (keyword == NULL) {
12276 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12277 }
12278 keyword->rest_start = i;
12279 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12280 }
12281#undef SYM
12282 iseq_calc_param_size(iseq);
12283
12284 /* exception */
12285 iseq_build_from_ary_exception(iseq, labels_table, exception);
12286
12287 /* body */
12288 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12289
12290 ISEQ_BODY(iseq)->param.size = arg_size;
12291 ISEQ_BODY(iseq)->local_table_size = local_size;
12292 ISEQ_BODY(iseq)->stack_max = stack_max;
12293}
12294
12295/* for parser */
12296
12297int
12298rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12299{
12300 if (iseq) {
12301 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12302 while (body->type == ISEQ_TYPE_BLOCK ||
12303 body->type == ISEQ_TYPE_RESCUE ||
12304 body->type == ISEQ_TYPE_ENSURE ||
12305 body->type == ISEQ_TYPE_EVAL ||
12306 body->type == ISEQ_TYPE_MAIN
12307 ) {
12308 unsigned int i;
12309
12310 for (i = 0; i < body->local_table_size; i++) {
12311 if (body->local_table[i] == id) {
12312 return 1;
12313 }
12314 }
12315 iseq = body->parent_iseq;
12316 body = ISEQ_BODY(iseq);
12317 }
12318 }
12319 return 0;
12320}
12321
12322int
12323rb_local_defined(ID id, const rb_iseq_t *iseq)
12324{
12325 if (iseq) {
12326 unsigned int i;
12327 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12328
12329 for (i=0; i<body->local_table_size; i++) {
12330 if (body->local_table[i] == id) {
12331 return 1;
12332 }
12333 }
12334 }
12335 return 0;
12336}
12337
12338/* ISeq binary format */
12339
12340#ifndef IBF_ISEQ_DEBUG
12341#define IBF_ISEQ_DEBUG 0
12342#endif
12343
12344#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12345#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12346#endif
12347
12348typedef uint32_t ibf_offset_t;
12349#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12350
12351#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12352#ifdef RUBY_DEVEL
12353#define IBF_DEVEL_VERSION 4
12354#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12355#else
12356#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12357#endif
12358
12359static const char IBF_ENDIAN_MARK =
12360#ifdef WORDS_BIGENDIAN
12361 'b'
12362#else
12363 'l'
12364#endif
12365 ;
12366
12368 char magic[4]; /* YARB */
12369 uint32_t major_version;
12370 uint32_t minor_version;
12371 uint32_t size;
12372 uint32_t extra_size;
12373
12374 uint32_t iseq_list_size;
12375 uint32_t global_object_list_size;
12376 ibf_offset_t iseq_list_offset;
12377 ibf_offset_t global_object_list_offset;
12378 uint8_t endian;
12379 uint8_t wordsize; /* assume no 2048-bit CPU */
12380};
12381
12383 VALUE str;
12384 st_table *obj_table; /* obj -> obj number */
12385};
12386
12387struct ibf_dump {
12388 st_table *iseq_table; /* iseq -> iseq number */
12389 struct ibf_dump_buffer global_buffer;
12390 struct ibf_dump_buffer *current_buffer;
12391};
12392
12394 const char *buff;
12395 ibf_offset_t size;
12396
12397 VALUE obj_list; /* [obj0, ...] */
12398 unsigned int obj_list_size;
12399 ibf_offset_t obj_list_offset;
12400};
12401
12402struct ibf_load {
12403 const struct ibf_header *header;
12404 VALUE iseq_list; /* [iseq0, ...] */
12405 struct ibf_load_buffer global_buffer;
12406 VALUE loader_obj;
12407 rb_iseq_t *iseq;
12408 VALUE str;
12409 struct ibf_load_buffer *current_buffer;
12410};
12411
12413 long size;
12414 VALUE buffer[1];
12415};
12416
12417static void
12418pinned_list_mark(void *ptr)
12419{
12420 long i;
12421 struct pinned_list *list = (struct pinned_list *)ptr;
12422 for (i = 0; i < list->size; i++) {
12423 if (list->buffer[i]) {
12424 rb_gc_mark(list->buffer[i]);
12425 }
12426 }
12427}
12428
12429static const rb_data_type_t pinned_list_type = {
12430 "pinned_list",
12431 {
12432 pinned_list_mark,
12434 NULL, // No external memory to report,
12435 },
12436 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12437};
12438
12439static VALUE
12440pinned_list_fetch(VALUE list, long offset)
12441{
12442 struct pinned_list * ptr;
12443
12444 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12445
12446 if (offset >= ptr->size) {
12447 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12448 }
12449
12450 return ptr->buffer[offset];
12451}
12452
12453static void
12454pinned_list_store(VALUE list, long offset, VALUE object)
12455{
12456 struct pinned_list * ptr;
12457
12458 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12459
12460 if (offset >= ptr->size) {
12461 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12462 }
12463
12464 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12465}
12466
12467static VALUE
12468pinned_list_new(long size)
12469{
12470 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12471 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12472 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12473 ptr->size = size;
12474 return obj_list;
12475}
12476
12477static ibf_offset_t
12478ibf_dump_pos(struct ibf_dump *dump)
12479{
12480 long pos = RSTRING_LEN(dump->current_buffer->str);
12481#if SIZEOF_LONG > SIZEOF_INT
12482 if (pos >= UINT_MAX) {
12483 rb_raise(rb_eRuntimeError, "dump size exceeds");
12484 }
12485#endif
12486 return (unsigned int)pos;
12487}
12488
12489static void
12490ibf_dump_align(struct ibf_dump *dump, size_t align)
12491{
12492 ibf_offset_t pos = ibf_dump_pos(dump);
12493 if (pos % align) {
12494 static const char padding[sizeof(VALUE)];
12495 size_t size = align - ((size_t)pos % align);
12496#if SIZEOF_LONG > SIZEOF_INT
12497 if (pos + size >= UINT_MAX) {
12498 rb_raise(rb_eRuntimeError, "dump size exceeds");
12499 }
12500#endif
12501 for (; size > sizeof(padding); size -= sizeof(padding)) {
12502 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12503 }
12504 rb_str_cat(dump->current_buffer->str, padding, size);
12505 }
12506}
12507
12508static ibf_offset_t
12509ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12510{
12511 ibf_offset_t pos = ibf_dump_pos(dump);
12512 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12513 /* TODO: overflow check */
12514 return pos;
12515}
12516
12517static ibf_offset_t
12518ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12519{
12520 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12521}
12522
12523static void
12524ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12525{
12526 VALUE str = dump->current_buffer->str;
12527 char *ptr = RSTRING_PTR(str);
12528 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12529 rb_bug("ibf_dump_overwrite: overflow");
12530 memcpy(ptr + offset, buff, size);
12531}
12532
12533static const void *
12534ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12535{
12536 ibf_offset_t beg = *offset;
12537 *offset += size;
12538 return load->current_buffer->buff + beg;
12539}
12540
12541static void *
12542ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12543{
12544 void *buff = ruby_xmalloc2(x, y);
12545 size_t size = x * y;
12546 memcpy(buff, load->current_buffer->buff + offset, size);
12547 return buff;
12548}
12549
12550#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12551
12552#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12553#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12554#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12555#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12556#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12557
12558static int
12559ibf_table_lookup(struct st_table *table, st_data_t key)
12560{
12561 st_data_t val;
12562
12563 if (st_lookup(table, key, &val)) {
12564 return (int)val;
12565 }
12566 else {
12567 return -1;
12568 }
12569}
12570
12571static int
12572ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12573{
12574 int index = ibf_table_lookup(table, key);
12575
12576 if (index < 0) { /* not found */
12577 index = (int)table->num_entries;
12578 st_insert(table, key, (st_data_t)index);
12579 }
12580
12581 return index;
12582}
12583
12584/* dump/load generic */
12585
12586static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12587
12588static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12589static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12590
12591static st_table *
12592ibf_dump_object_table_new(void)
12593{
12594 st_table *obj_table = st_init_numtable(); /* need free */
12595 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12596
12597 return obj_table;
12598}
12599
12600static VALUE
12601ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12602{
12603 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12604}
12605
12606static VALUE
12607ibf_dump_id(struct ibf_dump *dump, ID id)
12608{
12609 if (id == 0 || rb_id2name(id) == NULL) {
12610 return 0;
12611 }
12612 return ibf_dump_object(dump, rb_id2sym(id));
12613}
12614
12615static ID
12616ibf_load_id(const struct ibf_load *load, const ID id_index)
12617{
12618 if (id_index == 0) {
12619 return 0;
12620 }
12621 VALUE sym = ibf_load_object(load, id_index);
12622 if (rb_integer_type_p(sym)) {
12623 /* Load hidden local variables as indexes */
12624 return NUM2ULONG(sym);
12625 }
12626 return rb_sym2id(sym);
12627}
12628
12629/* dump/load: code */
12630
12631static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12632
12633static int
12634ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12635{
12636 if (iseq == NULL) {
12637 return -1;
12638 }
12639 else {
12640 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12641 }
12642}
12643
12644static unsigned char
12645ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12646{
12647 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12648 return (unsigned char)load->current_buffer->buff[(*offset)++];
12649}
12650
12651/*
12652 * Small uint serialization
12653 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12654 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12655 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12656 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12657 * ...
12658 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12659 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12660 */
12661static void
12662ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12663{
12664 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12665 ibf_dump_write(dump, &x, sizeof(VALUE));
12666 return;
12667 }
12668
12669 enum { max_byte_length = sizeof(VALUE) + 1 };
12670
12671 unsigned char bytes[max_byte_length];
12672 ibf_offset_t n;
12673
12674 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12675 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12676 }
12677
12678 x <<= 1;
12679 x |= 1;
12680 x <<= n;
12681 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12682 n++;
12683
12684 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12685}
12686
12687static VALUE
12688ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12689{
12690 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12691 union { char s[sizeof(VALUE)]; VALUE v; } x;
12692
12693 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12694 *offset += sizeof(VALUE);
12695
12696 return x.v;
12697 }
12698
12699 enum { max_byte_length = sizeof(VALUE) + 1 };
12700
12701 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12702 const unsigned char c = buffer[*offset];
12703
12704 ibf_offset_t n =
12705 c & 1 ? 1 :
12706 c == 0 ? 9 : ntz_int32(c) + 1;
12707 VALUE x = (VALUE)c >> n;
12708
12709 if (*offset + n > load->current_buffer->size) {
12710 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12711 }
12712
12713 ibf_offset_t i;
12714 for (i = 1; i < n; i++) {
12715 x <<= 8;
12716 x |= (VALUE)buffer[*offset + i];
12717 }
12718
12719 *offset += n;
12720 return x;
12721}
12722
12723static void
12724ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12725{
12726 // short: index
12727 // short: name.length
12728 // bytes: name
12729 // // omit argc (only verify with name)
12730 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12731
12732 size_t len = strlen(bf->name);
12733 ibf_dump_write_small_value(dump, (VALUE)len);
12734 ibf_dump_write(dump, bf->name, len);
12735}
12736
12737static const struct rb_builtin_function *
12738ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12739{
12740 int i = (int)ibf_load_small_value(load, offset);
12741 int len = (int)ibf_load_small_value(load, offset);
12742 const char *name = (char *)ibf_load_ptr(load, offset, len);
12743
12744 if (0) {
12745 fprintf(stderr, "%.*s!!\n", len, name);
12746 }
12747
12748 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12749 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12750 if (strncmp(table[i].name, name, len) != 0) {
12751 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12752 }
12753 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12754
12755 return &table[i];
12756}
12757
12758static ibf_offset_t
12759ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12760{
12761 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12762 const int iseq_size = body->iseq_size;
12763 int code_index;
12764 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12765
12766 ibf_offset_t offset = ibf_dump_pos(dump);
12767
12768 for (code_index=0; code_index<iseq_size;) {
12769 const VALUE insn = orig_code[code_index++];
12770 const char *types = insn_op_types(insn);
12771 int op_index;
12772
12773 /* opcode */
12774 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12775 ibf_dump_write_small_value(dump, insn);
12776
12777 /* operands */
12778 for (op_index=0; types[op_index]; op_index++, code_index++) {
12779 VALUE op = orig_code[code_index];
12780 VALUE wv;
12781
12782 switch (types[op_index]) {
12783 case TS_CDHASH:
12784 case TS_VALUE:
12785 wv = ibf_dump_object(dump, op);
12786 break;
12787 case TS_ISEQ:
12788 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12789 break;
12790 case TS_IC:
12791 {
12792 IC ic = (IC)op;
12793 VALUE arr = idlist_to_array(ic->segments);
12794 wv = ibf_dump_object(dump, arr);
12795 }
12796 break;
12797 case TS_ISE:
12798 case TS_IVC:
12799 case TS_ICVARC:
12800 {
12802 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12803 }
12804 break;
12805 case TS_CALLDATA:
12806 {
12807 goto skip_wv;
12808 }
12809 case TS_ID:
12810 wv = ibf_dump_id(dump, (ID)op);
12811 break;
12812 case TS_FUNCPTR:
12813 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12814 goto skip_wv;
12815 case TS_BUILTIN:
12816 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12817 goto skip_wv;
12818 default:
12819 wv = op;
12820 break;
12821 }
12822 ibf_dump_write_small_value(dump, wv);
12823 skip_wv:;
12824 }
12825 RUBY_ASSERT(insn_len(insn) == op_index+1);
12826 }
12827
12828 return offset;
12829}
12830
12831static VALUE *
12832ibf_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)
12833{
12834 VALUE iseqv = (VALUE)iseq;
12835 unsigned int code_index;
12836 ibf_offset_t reading_pos = bytecode_offset;
12837 VALUE *code = ALLOC_N(VALUE, iseq_size);
12838
12839 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12840 struct rb_call_data *cd_entries = load_body->call_data;
12841 int ic_index = 0;
12842
12843 iseq_bits_t * mark_offset_bits;
12844
12845 iseq_bits_t tmp[1] = {0};
12846
12847 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12848 mark_offset_bits = tmp;
12849 }
12850 else {
12851 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12852 }
12853 bool needs_bitmap = false;
12854
12855 for (code_index=0; code_index<iseq_size;) {
12856 /* opcode */
12857 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12858 const char *types = insn_op_types(insn);
12859 int op_index;
12860
12861 code_index++;
12862
12863 /* operands */
12864 for (op_index=0; types[op_index]; op_index++, code_index++) {
12865 const char operand_type = types[op_index];
12866 switch (operand_type) {
12867 case TS_VALUE:
12868 {
12869 VALUE op = ibf_load_small_value(load, &reading_pos);
12870 VALUE v = ibf_load_object(load, op);
12871 code[code_index] = v;
12872 if (!SPECIAL_CONST_P(v)) {
12873 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12874 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12875 needs_bitmap = true;
12876 }
12877 break;
12878 }
12879 case TS_CDHASH:
12880 {
12881 VALUE op = ibf_load_small_value(load, &reading_pos);
12882 VALUE v = ibf_load_object(load, op);
12883 v = rb_hash_dup(v); // hash dumped as frozen
12884 RHASH_TBL_RAW(v)->type = &cdhash_type;
12885 rb_hash_rehash(v); // hash function changed
12886 freeze_hide_obj(v);
12887
12888 // Overwrite the existing hash in the object list. This
12889 // is to keep the object alive during load time.
12890 // [Bug #17984] [ruby-core:104259]
12891 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12892
12893 code[code_index] = v;
12894 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12895 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12896 needs_bitmap = true;
12897 break;
12898 }
12899 case TS_ISEQ:
12900 {
12901 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12902 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12903 code[code_index] = v;
12904 if (!SPECIAL_CONST_P(v)) {
12905 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12906 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12907 needs_bitmap = true;
12908 }
12909 break;
12910 }
12911 case TS_IC:
12912 {
12913 VALUE op = ibf_load_small_value(load, &reading_pos);
12914 VALUE arr = ibf_load_object(load, op);
12915
12916 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12917 ic->segments = array_to_idlist(arr);
12918
12919 code[code_index] = (VALUE)ic;
12920 }
12921 break;
12922 case TS_ISE:
12923 case TS_ICVARC:
12924 case TS_IVC:
12925 {
12926 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
12927
12928 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12929 code[code_index] = (VALUE)ic;
12930
12931 if (operand_type == TS_IVC) {
12932 IVC cache = (IVC)ic;
12933
12934 if (insn == BIN(setinstancevariable)) {
12935 ID iv_name = (ID)code[code_index - 1];
12936 cache->iv_set_name = iv_name;
12937 }
12938 else {
12939 cache->iv_set_name = 0;
12940 }
12941
12942 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12943 }
12944
12945 }
12946 break;
12947 case TS_CALLDATA:
12948 {
12949 code[code_index] = (VALUE)cd_entries++;
12950 }
12951 break;
12952 case TS_ID:
12953 {
12954 VALUE op = ibf_load_small_value(load, &reading_pos);
12955 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
12956 }
12957 break;
12958 case TS_FUNCPTR:
12959 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12960 break;
12961 case TS_BUILTIN:
12962 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
12963 break;
12964 default:
12965 code[code_index] = ibf_load_small_value(load, &reading_pos);
12966 continue;
12967 }
12968 }
12969 if (insn_len(insn) != op_index+1) {
12970 rb_raise(rb_eRuntimeError, "operand size mismatch");
12971 }
12972 }
12973
12974 load_body->iseq_encoded = code;
12975 load_body->iseq_size = code_index;
12976
12977 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
12978 load_body->mark_bits.single = mark_offset_bits[0];
12979 }
12980 else {
12981 if (needs_bitmap) {
12982 load_body->mark_bits.list = mark_offset_bits;
12983 }
12984 else {
12985 load_body->mark_bits.list = 0;
12986 ruby_xfree(mark_offset_bits);
12987 }
12988 }
12989
12990 RUBY_ASSERT(code_index == iseq_size);
12991 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
12992 return code;
12993}
12994
12995static ibf_offset_t
12996ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
12997{
12998 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
12999
13000 if (opt_num > 0) {
13001 IBF_W_ALIGN(VALUE);
13002 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13003 }
13004 else {
13005 return ibf_dump_pos(dump);
13006 }
13007}
13008
13009static VALUE *
13010ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13011{
13012 if (opt_num > 0) {
13013 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13014 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13015 return table;
13016 }
13017 else {
13018 return NULL;
13019 }
13020}
13021
13022static ibf_offset_t
13023ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13024{
13025 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13026
13027 if (kw) {
13028 struct rb_iseq_param_keyword dump_kw = *kw;
13029 int dv_num = kw->num - kw->required_num;
13030 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13031 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13032 int i;
13033
13034 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13035 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13036
13037 dump_kw.table = IBF_W(ids, ID, kw->num);
13038 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13039 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13040 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13041 }
13042 else {
13043 return 0;
13044 }
13045}
13046
13047static const struct rb_iseq_param_keyword *
13048ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13049{
13050 if (param_keyword_offset) {
13051 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13052 int dv_num = kw->num - kw->required_num;
13053 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13054
13055 int i;
13056 for (i=0; i<dv_num; i++) {
13057 dvs[i] = ibf_load_object(load, dvs[i]);
13058 }
13059
13060 // Will be set once the local table is loaded.
13061 kw->table = NULL;
13062
13063 kw->default_values = dvs;
13064 return kw;
13065 }
13066 else {
13067 return NULL;
13068 }
13069}
13070
13071static ibf_offset_t
13072ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13073{
13074 ibf_offset_t offset = ibf_dump_pos(dump);
13075 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13076
13077 unsigned int i;
13078 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13079 ibf_dump_write_small_value(dump, entries[i].line_no);
13080#ifdef USE_ISEQ_NODE_ID
13081 ibf_dump_write_small_value(dump, entries[i].node_id);
13082#endif
13083 ibf_dump_write_small_value(dump, entries[i].events);
13084 }
13085
13086 return offset;
13087}
13088
13089static struct iseq_insn_info_entry *
13090ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13091{
13092 ibf_offset_t reading_pos = body_offset;
13093 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13094
13095 unsigned int i;
13096 for (i = 0; i < size; i++) {
13097 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13098#ifdef USE_ISEQ_NODE_ID
13099 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13100#endif
13101 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13102 }
13103
13104 return entries;
13105}
13106
13107static ibf_offset_t
13108ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13109{
13110 ibf_offset_t offset = ibf_dump_pos(dump);
13111
13112 unsigned int last = 0;
13113 unsigned int i;
13114 for (i = 0; i < size; i++) {
13115 ibf_dump_write_small_value(dump, positions[i] - last);
13116 last = positions[i];
13117 }
13118
13119 return offset;
13120}
13121
13122static unsigned int *
13123ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13124{
13125 ibf_offset_t reading_pos = positions_offset;
13126 unsigned int *positions = ALLOC_N(unsigned int, size);
13127
13128 unsigned int last = 0;
13129 unsigned int i;
13130 for (i = 0; i < size; i++) {
13131 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13132 last = positions[i];
13133 }
13134
13135 return positions;
13136}
13137
13138static ibf_offset_t
13139ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13140{
13141 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13142 const int size = body->local_table_size;
13143 ID *table = ALLOCA_N(ID, size);
13144 int i;
13145
13146 for (i=0; i<size; i++) {
13147 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13148 if (v == 0) {
13149 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13150 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13151 }
13152 table[i] = v;
13153 }
13154
13155 IBF_W_ALIGN(ID);
13156 return ibf_dump_write(dump, table, sizeof(ID) * size);
13157}
13158
13159static ID *
13160ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13161{
13162 if (size > 0) {
13163 ID *table = IBF_R(local_table_offset, ID, size);
13164 int i;
13165
13166 for (i=0; i<size; i++) {
13167 table[i] = ibf_load_id(load, table[i]);
13168 }
13169 return table;
13170 }
13171 else {
13172 return NULL;
13173 }
13174}
13175
13176static ibf_offset_t
13177ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13178{
13179 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13180
13181 if (table) {
13182 int *iseq_indices = ALLOCA_N(int, table->size);
13183 unsigned int i;
13184
13185 for (i=0; i<table->size; i++) {
13186 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13187 }
13188
13189 const ibf_offset_t offset = ibf_dump_pos(dump);
13190
13191 for (i=0; i<table->size; i++) {
13192 ibf_dump_write_small_value(dump, iseq_indices[i]);
13193 ibf_dump_write_small_value(dump, table->entries[i].type);
13194 ibf_dump_write_small_value(dump, table->entries[i].start);
13195 ibf_dump_write_small_value(dump, table->entries[i].end);
13196 ibf_dump_write_small_value(dump, table->entries[i].cont);
13197 ibf_dump_write_small_value(dump, table->entries[i].sp);
13198 }
13199 return offset;
13200 }
13201 else {
13202 return ibf_dump_pos(dump);
13203 }
13204}
13205
13206static struct iseq_catch_table *
13207ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
13208{
13209 if (size) {
13210 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13211 table->size = size;
13212
13213 ibf_offset_t reading_pos = catch_table_offset;
13214
13215 unsigned int i;
13216 for (i=0; i<table->size; i++) {
13217 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13218 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13219 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13220 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13221 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13222 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13223
13224 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13225 }
13226 return table;
13227 }
13228 else {
13229 return NULL;
13230 }
13231}
13232
13233static ibf_offset_t
13234ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13235{
13236 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13237 const unsigned int ci_size = body->ci_size;
13238 const struct rb_call_data *cds = body->call_data;
13239
13240 ibf_offset_t offset = ibf_dump_pos(dump);
13241
13242 unsigned int i;
13243
13244 for (i = 0; i < ci_size; i++) {
13245 const struct rb_callinfo *ci = cds[i].ci;
13246 if (ci != NULL) {
13247 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13248 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13249 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13250
13251 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13252 if (kwarg) {
13253 int len = kwarg->keyword_len;
13254 ibf_dump_write_small_value(dump, len);
13255 for (int j=0; j<len; j++) {
13256 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13257 ibf_dump_write_small_value(dump, keyword);
13258 }
13259 }
13260 else {
13261 ibf_dump_write_small_value(dump, 0);
13262 }
13263 }
13264 else {
13265 // TODO: truncate NULL ci from call_data.
13266 ibf_dump_write_small_value(dump, (VALUE)-1);
13267 }
13268 }
13269
13270 return offset;
13271}
13272
13274 ID id;
13275 VALUE name;
13276 VALUE val;
13277};
13278
13280 size_t num;
13281 struct outer_variable_pair pairs[1];
13282};
13283
13284static enum rb_id_table_iterator_result
13285store_outer_variable(ID id, VALUE val, void *dump)
13286{
13287 struct outer_variable_list *ovlist = dump;
13288 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13289 pair->id = id;
13290 pair->name = rb_id2str(id);
13291 pair->val = val;
13292 return ID_TABLE_CONTINUE;
13293}
13294
13295static int
13296outer_variable_cmp(const void *a, const void *b, void *arg)
13297{
13298 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13299 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13300 return rb_str_cmp(ap->name, bp->name);
13301}
13302
13303static ibf_offset_t
13304ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13305{
13306 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13307
13308 ibf_offset_t offset = ibf_dump_pos(dump);
13309
13310 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13311 ibf_dump_write_small_value(dump, (VALUE)size);
13312 if (size > 0) {
13313 VALUE buff;
13314 size_t buffsize =
13315 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13316 offsetof(struct outer_variable_list, pairs),
13317 rb_eArgError);
13318 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13319 ovlist->num = 0;
13320 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13321 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13322 for (size_t i = 0; i < size; ++i) {
13323 ID id = ovlist->pairs[i].id;
13324 ID val = ovlist->pairs[i].val;
13325 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13326 ibf_dump_write_small_value(dump, val);
13327 }
13328 }
13329
13330 return offset;
13331}
13332
13333/* note that we dump out rb_call_info but load back rb_call_data */
13334static void
13335ibf_load_ci_entries(const struct ibf_load *load,
13336 ibf_offset_t ci_entries_offset,
13337 unsigned int ci_size,
13338 struct rb_call_data **cd_ptr)
13339{
13340 ibf_offset_t reading_pos = ci_entries_offset;
13341
13342 unsigned int i;
13343
13344 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13345 *cd_ptr = cds;
13346
13347 for (i = 0; i < ci_size; i++) {
13348 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13349 if (mid_index != (VALUE)-1) {
13350 ID mid = ibf_load_id(load, mid_index);
13351 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13352 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13353
13354 struct rb_callinfo_kwarg *kwarg = NULL;
13355 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13356 if (kwlen > 0) {
13357 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13358 kwarg->references = 0;
13359 kwarg->keyword_len = kwlen;
13360 for (int j=0; j<kwlen; j++) {
13361 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13362 kwarg->keywords[j] = ibf_load_object(load, keyword);
13363 }
13364 }
13365
13366 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13367 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13368 cds[i].cc = vm_cc_empty();
13369 }
13370 else {
13371 // NULL ci
13372 cds[i].ci = NULL;
13373 cds[i].cc = NULL;
13374 }
13375 }
13376}
13377
13378static struct rb_id_table *
13379ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13380{
13381 ibf_offset_t reading_pos = outer_variables_offset;
13382
13383 struct rb_id_table *tbl = NULL;
13384
13385 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13386
13387 if (table_size > 0) {
13388 tbl = rb_id_table_create(table_size);
13389 }
13390
13391 for (size_t i = 0; i < table_size; i++) {
13392 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13393 VALUE value = ibf_load_small_value(load, &reading_pos);
13394 if (!key) key = rb_make_temporary_id(i);
13395 rb_id_table_insert(tbl, key, value);
13396 }
13397
13398 return tbl;
13399}
13400
13401static ibf_offset_t
13402ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13403{
13404 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13405
13406 unsigned int *positions;
13407
13408 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13409
13410 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13411 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13412 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13413
13414#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13415 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13416
13417 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13418 struct ibf_dump_buffer buffer;
13419 buffer.str = rb_str_new(0, 0);
13420 buffer.obj_table = ibf_dump_object_table_new();
13421 dump->current_buffer = &buffer;
13422#endif
13423
13424 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13425 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13426 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13427 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13428 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13429
13430 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13431 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13432 ruby_xfree(positions);
13433
13434 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13435 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13436 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13437 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13438 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13439 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13440 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13441 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13442
13443#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13444 ibf_offset_t local_obj_list_offset;
13445 unsigned int local_obj_list_size;
13446
13447 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13448#endif
13449
13450 ibf_offset_t body_offset = ibf_dump_pos(dump);
13451
13452 /* dump the constant body */
13453 unsigned int param_flags =
13454 (body->param.flags.has_lead << 0) |
13455 (body->param.flags.has_opt << 1) |
13456 (body->param.flags.has_rest << 2) |
13457 (body->param.flags.has_post << 3) |
13458 (body->param.flags.has_kw << 4) |
13459 (body->param.flags.has_kwrest << 5) |
13460 (body->param.flags.has_block << 6) |
13461 (body->param.flags.ambiguous_param0 << 7) |
13462 (body->param.flags.accepts_no_kwarg << 8) |
13463 (body->param.flags.ruby2_keywords << 9) |
13464 (body->param.flags.anon_rest << 10) |
13465 (body->param.flags.anon_kwrest << 11) |
13466 (body->param.flags.use_block << 12) |
13467 (body->param.flags.forwardable << 13) ;
13468
13469#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13470# define IBF_BODY_OFFSET(x) (x)
13471#else
13472# define IBF_BODY_OFFSET(x) (body_offset - (x))
13473#endif
13474
13475 ibf_dump_write_small_value(dump, body->type);
13476 ibf_dump_write_small_value(dump, body->iseq_size);
13477 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13478 ibf_dump_write_small_value(dump, bytecode_size);
13479 ibf_dump_write_small_value(dump, param_flags);
13480 ibf_dump_write_small_value(dump, body->param.size);
13481 ibf_dump_write_small_value(dump, body->param.lead_num);
13482 ibf_dump_write_small_value(dump, body->param.opt_num);
13483 ibf_dump_write_small_value(dump, body->param.rest_start);
13484 ibf_dump_write_small_value(dump, body->param.post_start);
13485 ibf_dump_write_small_value(dump, body->param.post_num);
13486 ibf_dump_write_small_value(dump, body->param.block_start);
13487 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13488 ibf_dump_write_small_value(dump, param_keyword_offset);
13489 ibf_dump_write_small_value(dump, location_pathobj_index);
13490 ibf_dump_write_small_value(dump, location_base_label_index);
13491 ibf_dump_write_small_value(dump, location_label_index);
13492 ibf_dump_write_small_value(dump, body->location.first_lineno);
13493 ibf_dump_write_small_value(dump, body->location.node_id);
13494 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13495 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13496 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13497 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13498 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13499 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13500 ibf_dump_write_small_value(dump, body->insns_info.size);
13501 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13502 ibf_dump_write_small_value(dump, catch_table_size);
13503 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13504 ibf_dump_write_small_value(dump, parent_iseq_index);
13505 ibf_dump_write_small_value(dump, local_iseq_index);
13506 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13507 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13508 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13509 ibf_dump_write_small_value(dump, body->variable.flip_count);
13510 ibf_dump_write_small_value(dump, body->local_table_size);
13511 ibf_dump_write_small_value(dump, body->ivc_size);
13512 ibf_dump_write_small_value(dump, body->icvarc_size);
13513 ibf_dump_write_small_value(dump, body->ise_size);
13514 ibf_dump_write_small_value(dump, body->ic_size);
13515 ibf_dump_write_small_value(dump, body->ci_size);
13516 ibf_dump_write_small_value(dump, body->stack_max);
13517 ibf_dump_write_small_value(dump, body->builtin_attrs);
13518 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13519
13520#undef IBF_BODY_OFFSET
13521
13522#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13523 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13524
13525 dump->current_buffer = saved_buffer;
13526 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13527
13528 ibf_offset_t offset = ibf_dump_pos(dump);
13529 ibf_dump_write_small_value(dump, iseq_start);
13530 ibf_dump_write_small_value(dump, iseq_length_bytes);
13531 ibf_dump_write_small_value(dump, body_offset);
13532
13533 ibf_dump_write_small_value(dump, local_obj_list_offset);
13534 ibf_dump_write_small_value(dump, local_obj_list_size);
13535
13536 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13537
13538 return offset;
13539#else
13540 return body_offset;
13541#endif
13542}
13543
13544static VALUE
13545ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13546{
13547 VALUE str = ibf_load_object(load, str_index);
13548 if (str != Qnil) {
13549 str = rb_fstring(str);
13550 }
13551 return str;
13552}
13553
13554static void
13555ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13556{
13557 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13558
13559 ibf_offset_t reading_pos = offset;
13560
13561#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13562 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13563 load->current_buffer = &load->global_buffer;
13564
13565 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13566 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13567 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13568
13569 struct ibf_load_buffer buffer;
13570 buffer.buff = load->global_buffer.buff + iseq_start;
13571 buffer.size = iseq_length_bytes;
13572 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13573 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13574 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13575
13576 load->current_buffer = &buffer;
13577 reading_pos = body_offset;
13578#endif
13579
13580#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13581# define IBF_BODY_OFFSET(x) (x)
13582#else
13583# define IBF_BODY_OFFSET(x) (offset - (x))
13584#endif
13585
13586 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13587 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13588 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13589 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13590 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13591 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13592 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13593 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13594 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13595 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13596 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13597 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13598 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13599 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13600 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13601 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13602 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13603 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13604 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13605 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13606 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13607 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13608 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13609 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13610 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13611 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13612 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13613 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13614 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13615 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13616 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13617 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13618 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13619 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13620 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13621 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13622
13623 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13624 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13625 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13626 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13627
13628 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13629 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13630 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13631 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13632
13633 // setup fname and dummy frame
13634 VALUE path = ibf_load_object(load, location_pathobj_index);
13635 {
13636 VALUE realpath = Qnil;
13637
13638 if (RB_TYPE_P(path, T_STRING)) {
13639 realpath = path = rb_fstring(path);
13640 }
13641 else if (RB_TYPE_P(path, T_ARRAY)) {
13642 VALUE pathobj = path;
13643 if (RARRAY_LEN(pathobj) != 2) {
13644 rb_raise(rb_eRuntimeError, "path object size mismatch");
13645 }
13646 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13647 realpath = RARRAY_AREF(pathobj, 1);
13648 if (!NIL_P(realpath)) {
13649 if (!RB_TYPE_P(realpath, T_STRING)) {
13650 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13651 "(%x), path=%+"PRIsVALUE,
13652 realpath, TYPE(realpath), path);
13653 }
13654 realpath = rb_fstring(realpath);
13655 }
13656 }
13657 else {
13658 rb_raise(rb_eRuntimeError, "unexpected path object");
13659 }
13660 rb_iseq_pathobj_set(iseq, path, realpath);
13661 }
13662
13663 // push dummy frame
13664 rb_execution_context_t *ec = GET_EC();
13665 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13666
13667#undef IBF_BODY_OFFSET
13668
13669 load_body->type = type;
13670 load_body->stack_max = stack_max;
13671 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13672 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13673 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13674 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13675 load_body->param.flags.has_kw = FALSE;
13676 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13677 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13678 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13679 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13680 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13681 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13682 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13683 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13684 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13685 load_body->param.size = param_size;
13686 load_body->param.lead_num = param_lead_num;
13687 load_body->param.opt_num = param_opt_num;
13688 load_body->param.rest_start = param_rest_start;
13689 load_body->param.post_start = param_post_start;
13690 load_body->param.post_num = param_post_num;
13691 load_body->param.block_start = param_block_start;
13692 load_body->local_table_size = local_table_size;
13693 load_body->ci_size = ci_size;
13694 load_body->insns_info.size = insns_info_size;
13695
13696 ISEQ_COVERAGE_SET(iseq, Qnil);
13697 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13698 load_body->variable.flip_count = variable_flip_count;
13699 load_body->variable.script_lines = Qnil;
13700
13701 load_body->location.first_lineno = location_first_lineno;
13702 load_body->location.node_id = location_node_id;
13703 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13704 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13705 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13706 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13707 load_body->builtin_attrs = builtin_attrs;
13708 load_body->prism = prism;
13709
13710 load_body->ivc_size = ivc_size;
13711 load_body->icvarc_size = icvarc_size;
13712 load_body->ise_size = ise_size;
13713 load_body->ic_size = ic_size;
13714
13715 if (ISEQ_IS_SIZE(load_body)) {
13716 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13717 }
13718 else {
13719 load_body->is_entries = NULL;
13720 }
13721 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13722 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13723 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13724 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13725 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13726 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13727 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13728 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13729 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
13730 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13731 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13732 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13733
13734 // This must be done after the local table is loaded.
13735 if (load_body->param.keyword != NULL) {
13736 RUBY_ASSERT(load_body->local_table);
13737 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13738 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13739 }
13740
13741 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13742#if VM_INSN_INFO_TABLE_IMPL == 2
13743 rb_iseq_insns_info_encode_positions(iseq);
13744#endif
13745
13746 rb_iseq_translate_threaded_code(iseq);
13747
13748#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13749 load->current_buffer = &load->global_buffer;
13750#endif
13751
13752 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13753 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13754
13755#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13756 load->current_buffer = saved_buffer;
13757#endif
13758 verify_call_cache(iseq);
13759
13760 RB_GC_GUARD(dummy_frame);
13761 rb_vm_pop_frame_no_int(ec);
13762}
13763
13765{
13766 struct ibf_dump *dump;
13767 VALUE offset_list;
13768};
13769
13770static int
13771ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13772{
13773 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13774 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13775
13776 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13777 rb_ary_push(args->offset_list, UINT2NUM(offset));
13778
13779 return ST_CONTINUE;
13780}
13781
13782static void
13783ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13784{
13785 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13786
13787 struct ibf_dump_iseq_list_arg args;
13788 args.dump = dump;
13789 args.offset_list = offset_list;
13790
13791 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13792
13793 st_index_t i;
13794 st_index_t size = dump->iseq_table->num_entries;
13795 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13796
13797 for (i = 0; i < size; i++) {
13798 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13799 }
13800
13801 ibf_dump_align(dump, sizeof(ibf_offset_t));
13802 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13803 header->iseq_list_size = (unsigned int)size;
13804}
13805
13806#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13807
13808/*
13809 * Binary format
13810 * - ibf_object_header
13811 * - ibf_object_xxx (xxx is type)
13812 */
13813
13815 unsigned int type: 5;
13816 unsigned int special_const: 1;
13817 unsigned int frozen: 1;
13818 unsigned int internal: 1;
13819};
13820
13821enum ibf_object_class_index {
13822 IBF_OBJECT_CLASS_OBJECT,
13823 IBF_OBJECT_CLASS_ARRAY,
13824 IBF_OBJECT_CLASS_STANDARD_ERROR,
13825 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13826 IBF_OBJECT_CLASS_TYPE_ERROR,
13827 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13828};
13829
13831 long srcstr;
13832 char option;
13833};
13834
13836 long len;
13837 long keyval[FLEX_ARY_LEN];
13838};
13839
13841 long class_index;
13842 long len;
13843 long beg;
13844 long end;
13845 int excl;
13846};
13847
13849 ssize_t slen;
13850 BDIGIT digits[FLEX_ARY_LEN];
13851};
13852
13853enum ibf_object_data_type {
13854 IBF_OBJECT_DATA_ENCODING,
13855};
13856
13858 long a, b;
13859};
13860
13862 long str;
13863};
13864
13865#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13866 ((((offset) - 1) / (align) + 1) * (align))
13867#define IBF_OBJBODY(type, offset) (const type *)\
13868 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13869
13870static const void *
13871ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13872{
13873 if (offset >= load->current_buffer->size) {
13874 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13875 }
13876 return load->current_buffer->buff + offset;
13877}
13878
13879NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13880
13881static void
13882ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13883{
13884 char buff[0x100];
13885 rb_raw_obj_info(buff, sizeof(buff), obj);
13886 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13887}
13888
13889NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13890
13891static VALUE
13892ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13893{
13894 rb_raise(rb_eArgError, "unsupported");
13896}
13897
13898static void
13899ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13900{
13901 enum ibf_object_class_index cindex;
13902 if (obj == rb_cObject) {
13903 cindex = IBF_OBJECT_CLASS_OBJECT;
13904 }
13905 else if (obj == rb_cArray) {
13906 cindex = IBF_OBJECT_CLASS_ARRAY;
13907 }
13908 else if (obj == rb_eStandardError) {
13909 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13910 }
13911 else if (obj == rb_eNoMatchingPatternError) {
13912 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13913 }
13914 else if (obj == rb_eTypeError) {
13915 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13916 }
13917 else if (obj == rb_eNoMatchingPatternKeyError) {
13918 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13919 }
13920 else {
13921 rb_obj_info_dump(obj);
13922 rb_p(obj);
13923 rb_bug("unsupported class");
13924 }
13925 ibf_dump_write_small_value(dump, (VALUE)cindex);
13926}
13927
13928static VALUE
13929ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13930{
13931 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13932
13933 switch (cindex) {
13934 case IBF_OBJECT_CLASS_OBJECT:
13935 return rb_cObject;
13936 case IBF_OBJECT_CLASS_ARRAY:
13937 return rb_cArray;
13938 case IBF_OBJECT_CLASS_STANDARD_ERROR:
13939 return rb_eStandardError;
13940 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13942 case IBF_OBJECT_CLASS_TYPE_ERROR:
13943 return rb_eTypeError;
13944 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13946 }
13947
13948 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
13949}
13950
13951
13952static void
13953ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
13954{
13955 double dbl = RFLOAT_VALUE(obj);
13956 (void)IBF_W(&dbl, double, 1);
13957}
13958
13959static VALUE
13960ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13961{
13962 const double *dblp = IBF_OBJBODY(double, offset);
13963 return DBL2NUM(*dblp);
13964}
13965
13966static void
13967ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
13968{
13969 long encindex = (long)rb_enc_get_index(obj);
13970 long len = RSTRING_LEN(obj);
13971 const char *ptr = RSTRING_PTR(obj);
13972
13973 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13974 rb_encoding *enc = rb_enc_from_index((int)encindex);
13975 const char *enc_name = rb_enc_name(enc);
13976 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
13977 }
13978
13979 ibf_dump_write_small_value(dump, encindex);
13980 ibf_dump_write_small_value(dump, len);
13981 IBF_WP(ptr, char, len);
13982}
13983
13984static VALUE
13985ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13986{
13987 ibf_offset_t reading_pos = offset;
13988
13989 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13990 const long len = (long)ibf_load_small_value(load, &reading_pos);
13991 const char *ptr = load->current_buffer->buff + reading_pos;
13992
13993 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13994 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13995 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13996 }
13997
13998 VALUE str;
13999 if (header->frozen && !header->internal) {
14000 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14001 }
14002 else {
14003 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14004
14005 if (header->internal) rb_obj_hide(str);
14006 if (header->frozen) str = rb_fstring(str);
14007 }
14008 return str;
14009}
14010
14011static void
14012ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14013{
14014 VALUE srcstr = RREGEXP_SRC(obj);
14015 struct ibf_object_regexp regexp;
14016 regexp.option = (char)rb_reg_options(obj);
14017 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14018
14019 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14020 ibf_dump_write_small_value(dump, regexp.srcstr);
14021}
14022
14023static VALUE
14024ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14025{
14026 struct ibf_object_regexp regexp;
14027 regexp.option = ibf_load_byte(load, &offset);
14028 regexp.srcstr = ibf_load_small_value(load, &offset);
14029
14030 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14031 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14032
14033 if (header->internal) rb_obj_hide(reg);
14034 if (header->frozen) rb_obj_freeze(reg);
14035
14036 return reg;
14037}
14038
14039static void
14040ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14041{
14042 long i, len = RARRAY_LEN(obj);
14043 ibf_dump_write_small_value(dump, len);
14044 for (i=0; i<len; i++) {
14045 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14046 ibf_dump_write_small_value(dump, index);
14047 }
14048}
14049
14050static VALUE
14051ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14052{
14053 ibf_offset_t reading_pos = offset;
14054
14055 const long len = (long)ibf_load_small_value(load, &reading_pos);
14056
14057 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14058 int i;
14059
14060 for (i=0; i<len; i++) {
14061 const VALUE index = ibf_load_small_value(load, &reading_pos);
14062 rb_ary_push(ary, ibf_load_object(load, index));
14063 }
14064
14065 if (header->frozen) rb_ary_freeze(ary);
14066
14067 return ary;
14068}
14069
14070static int
14071ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14072{
14073 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14074
14075 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14076 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14077
14078 ibf_dump_write_small_value(dump, key_index);
14079 ibf_dump_write_small_value(dump, val_index);
14080 return ST_CONTINUE;
14081}
14082
14083static void
14084ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14085{
14086 long len = RHASH_SIZE(obj);
14087 ibf_dump_write_small_value(dump, (VALUE)len);
14088
14089 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14090}
14091
14092static VALUE
14093ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14094{
14095 long len = (long)ibf_load_small_value(load, &offset);
14096 VALUE obj = rb_hash_new_with_size(len);
14097 int i;
14098
14099 for (i = 0; i < len; i++) {
14100 VALUE key_index = ibf_load_small_value(load, &offset);
14101 VALUE val_index = ibf_load_small_value(load, &offset);
14102
14103 VALUE key = ibf_load_object(load, key_index);
14104 VALUE val = ibf_load_object(load, val_index);
14105 rb_hash_aset(obj, key, val);
14106 }
14107 rb_hash_rehash(obj);
14108
14109 if (header->internal) rb_obj_hide(obj);
14110 if (header->frozen) rb_obj_freeze(obj);
14111
14112 return obj;
14113}
14114
14115static void
14116ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14117{
14118 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14119 struct ibf_object_struct_range range;
14120 VALUE beg, end;
14121 IBF_ZERO(range);
14122 range.len = 3;
14123 range.class_index = 0;
14124
14125 rb_range_values(obj, &beg, &end, &range.excl);
14126 range.beg = (long)ibf_dump_object(dump, beg);
14127 range.end = (long)ibf_dump_object(dump, end);
14128
14129 IBF_W_ALIGN(struct ibf_object_struct_range);
14130 IBF_WV(range);
14131 }
14132 else {
14133 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14134 rb_class_name(CLASS_OF(obj)));
14135 }
14136}
14137
14138static VALUE
14139ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14140{
14141 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14142 VALUE beg = ibf_load_object(load, range->beg);
14143 VALUE end = ibf_load_object(load, range->end);
14144 VALUE obj = rb_range_new(beg, end, range->excl);
14145 if (header->internal) rb_obj_hide(obj);
14146 if (header->frozen) rb_obj_freeze(obj);
14147 return obj;
14148}
14149
14150static void
14151ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14152{
14153 ssize_t len = BIGNUM_LEN(obj);
14154 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14155 BDIGIT *d = BIGNUM_DIGITS(obj);
14156
14157 (void)IBF_W(&slen, ssize_t, 1);
14158 IBF_WP(d, BDIGIT, len);
14159}
14160
14161static VALUE
14162ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14163{
14164 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14165 int sign = bignum->slen > 0;
14166 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14167 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14170 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14171 big_unpack_flags |
14172 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14173 if (header->internal) rb_obj_hide(obj);
14174 if (header->frozen) rb_obj_freeze(obj);
14175 return obj;
14176}
14177
14178static void
14179ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14180{
14181 if (rb_data_is_encoding(obj)) {
14182 rb_encoding *enc = rb_to_encoding(obj);
14183 const char *name = rb_enc_name(enc);
14184 long len = strlen(name) + 1;
14185 long data[2];
14186 data[0] = IBF_OBJECT_DATA_ENCODING;
14187 data[1] = len;
14188 (void)IBF_W(data, long, 2);
14189 IBF_WP(name, char, len);
14190 }
14191 else {
14192 ibf_dump_object_unsupported(dump, obj);
14193 }
14194}
14195
14196static VALUE
14197ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14198{
14199 const long *body = IBF_OBJBODY(long, offset);
14200 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14201 /* const long len = body[1]; */
14202 const char *data = (const char *)&body[2];
14203
14204 switch (type) {
14205 case IBF_OBJECT_DATA_ENCODING:
14206 {
14207 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14208 return encobj;
14209 }
14210 }
14211
14212 return ibf_load_object_unsupported(load, header, offset);
14213}
14214
14215static void
14216ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14217{
14218 long data[2];
14219 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14220 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14221
14222 (void)IBF_W(data, long, 2);
14223}
14224
14225static VALUE
14226ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14227{
14228 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14229 VALUE a = ibf_load_object(load, nums->a);
14230 VALUE b = ibf_load_object(load, nums->b);
14231 VALUE obj = header->type == T_COMPLEX ?
14232 rb_complex_new(a, b) : rb_rational_new(a, b);
14233
14234 if (header->internal) rb_obj_hide(obj);
14235 if (header->frozen) rb_obj_freeze(obj);
14236 return obj;
14237}
14238
14239static void
14240ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14241{
14242 ibf_dump_object_string(dump, rb_sym2str(obj));
14243}
14244
14245static VALUE
14246ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14247{
14248 ibf_offset_t reading_pos = offset;
14249
14250 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14251 const long len = (long)ibf_load_small_value(load, &reading_pos);
14252 const char *ptr = load->current_buffer->buff + reading_pos;
14253
14254 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14255 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14256 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14257 }
14258
14259 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14260 return ID2SYM(id);
14261}
14262
14263typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14264static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14265 ibf_dump_object_unsupported, /* T_NONE */
14266 ibf_dump_object_unsupported, /* T_OBJECT */
14267 ibf_dump_object_class, /* T_CLASS */
14268 ibf_dump_object_unsupported, /* T_MODULE */
14269 ibf_dump_object_float, /* T_FLOAT */
14270 ibf_dump_object_string, /* T_STRING */
14271 ibf_dump_object_regexp, /* T_REGEXP */
14272 ibf_dump_object_array, /* T_ARRAY */
14273 ibf_dump_object_hash, /* T_HASH */
14274 ibf_dump_object_struct, /* T_STRUCT */
14275 ibf_dump_object_bignum, /* T_BIGNUM */
14276 ibf_dump_object_unsupported, /* T_FILE */
14277 ibf_dump_object_data, /* T_DATA */
14278 ibf_dump_object_unsupported, /* T_MATCH */
14279 ibf_dump_object_complex_rational, /* T_COMPLEX */
14280 ibf_dump_object_complex_rational, /* T_RATIONAL */
14281 ibf_dump_object_unsupported, /* 0x10 */
14282 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14283 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14284 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14285 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14286 ibf_dump_object_unsupported, /* T_FIXNUM */
14287 ibf_dump_object_unsupported, /* T_UNDEF */
14288 ibf_dump_object_unsupported, /* 0x17 */
14289 ibf_dump_object_unsupported, /* 0x18 */
14290 ibf_dump_object_unsupported, /* 0x19 */
14291 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14292 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14293 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14294 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14295 ibf_dump_object_unsupported, /* 0x1e */
14296 ibf_dump_object_unsupported, /* 0x1f */
14297};
14298
14299static void
14300ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14301{
14302 unsigned char byte =
14303 (header.type << 0) |
14304 (header.special_const << 5) |
14305 (header.frozen << 6) |
14306 (header.internal << 7);
14307
14308 IBF_WV(byte);
14309}
14310
14311static struct ibf_object_header
14312ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14313{
14314 unsigned char byte = ibf_load_byte(load, offset);
14315
14316 struct ibf_object_header header;
14317 header.type = (byte >> 0) & 0x1f;
14318 header.special_const = (byte >> 5) & 0x01;
14319 header.frozen = (byte >> 6) & 0x01;
14320 header.internal = (byte >> 7) & 0x01;
14321
14322 return header;
14323}
14324
14325static ibf_offset_t
14326ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14327{
14328 struct ibf_object_header obj_header;
14329 ibf_offset_t current_offset;
14330 IBF_ZERO(obj_header);
14331 obj_header.type = TYPE(obj);
14332
14333 IBF_W_ALIGN(ibf_offset_t);
14334 current_offset = ibf_dump_pos(dump);
14335
14336 if (SPECIAL_CONST_P(obj) &&
14337 ! (SYMBOL_P(obj) ||
14338 RB_FLOAT_TYPE_P(obj))) {
14339 obj_header.special_const = TRUE;
14340 obj_header.frozen = TRUE;
14341 obj_header.internal = TRUE;
14342 ibf_dump_object_object_header(dump, obj_header);
14343 ibf_dump_write_small_value(dump, obj);
14344 }
14345 else {
14346 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14347 obj_header.special_const = FALSE;
14348 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
14349 ibf_dump_object_object_header(dump, obj_header);
14350 (*dump_object_functions[obj_header.type])(dump, obj);
14351 }
14352
14353 return current_offset;
14354}
14355
14356typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14357static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14358 ibf_load_object_unsupported, /* T_NONE */
14359 ibf_load_object_unsupported, /* T_OBJECT */
14360 ibf_load_object_class, /* T_CLASS */
14361 ibf_load_object_unsupported, /* T_MODULE */
14362 ibf_load_object_float, /* T_FLOAT */
14363 ibf_load_object_string, /* T_STRING */
14364 ibf_load_object_regexp, /* T_REGEXP */
14365 ibf_load_object_array, /* T_ARRAY */
14366 ibf_load_object_hash, /* T_HASH */
14367 ibf_load_object_struct, /* T_STRUCT */
14368 ibf_load_object_bignum, /* T_BIGNUM */
14369 ibf_load_object_unsupported, /* T_FILE */
14370 ibf_load_object_data, /* T_DATA */
14371 ibf_load_object_unsupported, /* T_MATCH */
14372 ibf_load_object_complex_rational, /* T_COMPLEX */
14373 ibf_load_object_complex_rational, /* T_RATIONAL */
14374 ibf_load_object_unsupported, /* 0x10 */
14375 ibf_load_object_unsupported, /* T_NIL */
14376 ibf_load_object_unsupported, /* T_TRUE */
14377 ibf_load_object_unsupported, /* T_FALSE */
14378 ibf_load_object_symbol,
14379 ibf_load_object_unsupported, /* T_FIXNUM */
14380 ibf_load_object_unsupported, /* T_UNDEF */
14381 ibf_load_object_unsupported, /* 0x17 */
14382 ibf_load_object_unsupported, /* 0x18 */
14383 ibf_load_object_unsupported, /* 0x19 */
14384 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14385 ibf_load_object_unsupported, /* T_NODE 0x1b */
14386 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14387 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14388 ibf_load_object_unsupported, /* 0x1e */
14389 ibf_load_object_unsupported, /* 0x1f */
14390};
14391
14392static VALUE
14393ibf_load_object(const struct ibf_load *load, VALUE object_index)
14394{
14395 if (object_index == 0) {
14396 return Qnil;
14397 }
14398 else {
14399 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14400 if (!obj) {
14401 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14402 ibf_offset_t offset = offsets[object_index];
14403 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14404
14405#if IBF_ISEQ_DEBUG
14406 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14407 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14408 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14409 header.type, header.special_const, header.frozen, header.internal);
14410#endif
14411 if (offset >= load->current_buffer->size) {
14412 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14413 }
14414
14415 if (header.special_const) {
14416 ibf_offset_t reading_pos = offset;
14417
14418 obj = ibf_load_small_value(load, &reading_pos);
14419 }
14420 else {
14421 obj = (*load_object_functions[header.type])(load, &header, offset);
14422 }
14423
14424 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14425 }
14426#if IBF_ISEQ_DEBUG
14427 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14428 object_index, obj);
14429#endif
14430 return obj;
14431 }
14432}
14433
14435{
14436 struct ibf_dump *dump;
14437 VALUE offset_list;
14438};
14439
14440static int
14441ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14442{
14443 VALUE obj = (VALUE)key;
14444 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14445
14446 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14447 rb_ary_push(args->offset_list, UINT2NUM(offset));
14448
14449 return ST_CONTINUE;
14450}
14451
14452static void
14453ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14454{
14455 st_table *obj_table = dump->current_buffer->obj_table;
14456 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14457
14458 struct ibf_dump_object_list_arg args;
14459 args.dump = dump;
14460 args.offset_list = offset_list;
14461
14462 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14463
14464 IBF_W_ALIGN(ibf_offset_t);
14465 *obj_list_offset = ibf_dump_pos(dump);
14466
14467 st_index_t size = obj_table->num_entries;
14468 st_index_t i;
14469
14470 for (i=0; i<size; i++) {
14471 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14472 IBF_WV(offset);
14473 }
14474
14475 *obj_list_size = (unsigned int)size;
14476}
14477
14478static void
14479ibf_dump_mark(void *ptr)
14480{
14481 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14482 rb_gc_mark(dump->global_buffer.str);
14483
14484 rb_mark_set(dump->global_buffer.obj_table);
14485 rb_mark_set(dump->iseq_table);
14486}
14487
14488static void
14489ibf_dump_free(void *ptr)
14490{
14491 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14492 if (dump->global_buffer.obj_table) {
14493 st_free_table(dump->global_buffer.obj_table);
14494 dump->global_buffer.obj_table = 0;
14495 }
14496 if (dump->iseq_table) {
14497 st_free_table(dump->iseq_table);
14498 dump->iseq_table = 0;
14499 }
14500}
14501
14502static size_t
14503ibf_dump_memsize(const void *ptr)
14504{
14505 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14506 size_t size = 0;
14507 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14508 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14509 return size;
14510}
14511
14512static const rb_data_type_t ibf_dump_type = {
14513 "ibf_dump",
14514 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14515 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14516};
14517
14518static void
14519ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14520{
14521 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14522 dump->iseq_table = NULL;
14523
14524 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14525 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14526 dump->iseq_table = st_init_numtable(); /* need free */
14527
14528 dump->current_buffer = &dump->global_buffer;
14529}
14530
14531VALUE
14532rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14533{
14534 struct ibf_dump *dump;
14535 struct ibf_header header = {{0}};
14536 VALUE dump_obj;
14537 VALUE str;
14538
14539 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14540 ISEQ_BODY(iseq)->local_iseq != iseq) {
14541 rb_raise(rb_eRuntimeError, "should be top of iseq");
14542 }
14543 if (RTEST(ISEQ_COVERAGE(iseq))) {
14544 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14545 }
14546
14547 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14548 ibf_dump_setup(dump, dump_obj);
14549
14550 ibf_dump_write(dump, &header, sizeof(header));
14551 ibf_dump_iseq(dump, iseq);
14552
14553 header.magic[0] = 'Y'; /* YARB */
14554 header.magic[1] = 'A';
14555 header.magic[2] = 'R';
14556 header.magic[3] = 'B';
14557 header.major_version = IBF_MAJOR_VERSION;
14558 header.minor_version = IBF_MINOR_VERSION;
14559 header.endian = IBF_ENDIAN_MARK;
14560 header.wordsize = (uint8_t)SIZEOF_VALUE;
14561 ibf_dump_iseq_list(dump, &header);
14562 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14563 header.size = ibf_dump_pos(dump);
14564
14565 if (RTEST(opt)) {
14566 VALUE opt_str = opt;
14567 const char *ptr = StringValuePtr(opt_str);
14568 header.extra_size = RSTRING_LENINT(opt_str);
14569 ibf_dump_write(dump, ptr, header.extra_size);
14570 }
14571 else {
14572 header.extra_size = 0;
14573 }
14574
14575 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14576
14577 str = dump->global_buffer.str;
14578 RB_GC_GUARD(dump_obj);
14579 return str;
14580}
14581
14582static const ibf_offset_t *
14583ibf_iseq_list(const struct ibf_load *load)
14584{
14585 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14586}
14587
14588void
14589rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14590{
14591 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14592 rb_iseq_t *prev_src_iseq = load->iseq;
14593 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14594 load->iseq = iseq;
14595#if IBF_ISEQ_DEBUG
14596 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14597 iseq->aux.loader.index, offset,
14598 load->header->size);
14599#endif
14600 ibf_load_iseq_each(load, iseq, offset);
14601 ISEQ_COMPILE_DATA_CLEAR(iseq);
14602 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14603 rb_iseq_init_trace(iseq);
14604 load->iseq = prev_src_iseq;
14605}
14606
14607#if USE_LAZY_LOAD
14608const rb_iseq_t *
14609rb_iseq_complete(const rb_iseq_t *iseq)
14610{
14611 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14612 return iseq;
14613}
14614#endif
14615
14616static rb_iseq_t *
14617ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14618{
14619 int iseq_index = (int)(VALUE)index_iseq;
14620
14621#if IBF_ISEQ_DEBUG
14622 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14623 (void *)index_iseq, (void *)load->iseq_list);
14624#endif
14625 if (iseq_index == -1) {
14626 return NULL;
14627 }
14628 else {
14629 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14630
14631#if IBF_ISEQ_DEBUG
14632 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14633#endif
14634 if (iseqv) {
14635 return (rb_iseq_t *)iseqv;
14636 }
14637 else {
14638 rb_iseq_t *iseq = iseq_imemo_alloc();
14639#if IBF_ISEQ_DEBUG
14640 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14641#endif
14642 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14643 iseq->aux.loader.obj = load->loader_obj;
14644 iseq->aux.loader.index = iseq_index;
14645#if IBF_ISEQ_DEBUG
14646 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14647 (void *)iseq, (void *)load->loader_obj, iseq_index);
14648#endif
14649 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14650
14651 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14652#if IBF_ISEQ_DEBUG
14653 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14654#endif
14655 rb_ibf_load_iseq_complete(iseq);
14656 }
14657
14658#if IBF_ISEQ_DEBUG
14659 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14660 (void *)iseq, (void *)load->iseq);
14661#endif
14662 return iseq;
14663 }
14664 }
14665}
14666
14667static void
14668ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14669{
14670 struct ibf_header *header = (struct ibf_header *)bytes;
14671 load->loader_obj = loader_obj;
14672 load->global_buffer.buff = bytes;
14673 load->header = header;
14674 load->global_buffer.size = header->size;
14675 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14676 load->global_buffer.obj_list_size = header->global_object_list_size;
14677 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14678 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14679 load->iseq = NULL;
14680
14681 load->current_buffer = &load->global_buffer;
14682
14683 if (size < header->size) {
14684 rb_raise(rb_eRuntimeError, "broken binary format");
14685 }
14686 if (strncmp(header->magic, "YARB", 4) != 0) {
14687 rb_raise(rb_eRuntimeError, "unknown binary format");
14688 }
14689 if (header->major_version != IBF_MAJOR_VERSION ||
14690 header->minor_version != IBF_MINOR_VERSION) {
14691 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14692 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14693 }
14694 if (header->endian != IBF_ENDIAN_MARK) {
14695 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14696 }
14697 if (header->wordsize != SIZEOF_VALUE) {
14698 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14699 }
14700 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14701 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14702 header->iseq_list_offset);
14703 }
14704 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14705 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14706 load->global_buffer.obj_list_offset);
14707 }
14708}
14709
14710static void
14711ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14712{
14713 StringValue(str);
14714
14715 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14716 rb_raise(rb_eRuntimeError, "broken binary format");
14717 }
14718
14719 if (USE_LAZY_LOAD) {
14720 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14721 }
14722
14723 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14724 RB_OBJ_WRITE(loader_obj, &load->str, str);
14725}
14726
14727static void
14728ibf_loader_mark(void *ptr)
14729{
14730 struct ibf_load *load = (struct ibf_load *)ptr;
14731 rb_gc_mark(load->str);
14732 rb_gc_mark(load->iseq_list);
14733 rb_gc_mark(load->global_buffer.obj_list);
14734}
14735
14736static void
14737ibf_loader_free(void *ptr)
14738{
14739 struct ibf_load *load = (struct ibf_load *)ptr;
14740 ruby_xfree(load);
14741}
14742
14743static size_t
14744ibf_loader_memsize(const void *ptr)
14745{
14746 return sizeof(struct ibf_load);
14747}
14748
14749static const rb_data_type_t ibf_load_type = {
14750 "ibf_loader",
14751 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14752 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14753};
14754
14755const rb_iseq_t *
14756rb_iseq_ibf_load(VALUE str)
14757{
14758 struct ibf_load *load;
14759 rb_iseq_t *iseq;
14760 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14761
14762 ibf_load_setup(load, loader_obj, str);
14763 iseq = ibf_load_iseq(load, 0);
14764
14765 RB_GC_GUARD(loader_obj);
14766 return iseq;
14767}
14768
14769const rb_iseq_t *
14770rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14771{
14772 struct ibf_load *load;
14773 rb_iseq_t *iseq;
14774 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14775
14776 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14777 iseq = ibf_load_iseq(load, 0);
14778
14779 RB_GC_GUARD(loader_obj);
14780 return iseq;
14781}
14782
14783VALUE
14784rb_iseq_ibf_load_extra_data(VALUE str)
14785{
14786 struct ibf_load *load;
14787 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14788 VALUE extra_str;
14789
14790 ibf_load_setup(load, loader_obj, str);
14791 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14792 RB_GC_GUARD(loader_obj);
14793 return extra_str;
14794}
14795
14796#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:129
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:131
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:67
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:133
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:688
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:113
VALUE rb_cArray
Array class.
Definition array.c:40
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:104
VALUE rb_cHash
Hash class.
Definition hash.c:113
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:865
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1260
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1079
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1103
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1804
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:4198
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:3677
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1672
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4046
#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:4032
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3445
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:3643
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4102
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:3919
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3177
#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:412
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:967
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:986
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:933
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:3111
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:150
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:449
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:497
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9035
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:29
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:270
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:241
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:207
struct rb_iseq_constant_body::@154 param
parameter information
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145