Ruby 3.5.0dev (2025-09-03 revision de6df7508de397138e3a4d16469e7f35a8fe1b1e)
compile.c (de6df7508de397138e3a4d16469e7f35a8fe1b1e)
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 INSN *
1444insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1445{
1446 VALUE *operands = 0;
1447 va_list argv;
1448 if (argc > 0) {
1449 int i;
1450 va_start(argv, argc);
1451 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1452 for (i = 0; i < argc; i++) {
1453 VALUE v = va_arg(argv, VALUE);
1454 operands[i] = v;
1455 }
1456 va_end(argv);
1457 }
1458
1459 iobj->insn_id = insn_id;
1460 iobj->operand_size = argc;
1461 iobj->operands = operands;
1462 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1463
1464 return iobj;
1465}
1466
1467static const struct rb_callinfo *
1468new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1469{
1470 VM_ASSERT(argc >= 0);
1471
1472 if (kw_arg) {
1473 flag |= VM_CALL_KWARG;
1474 argc += kw_arg->keyword_len;
1475 }
1476
1477 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1478 && !has_blockiseq) {
1479 flag |= VM_CALL_ARGS_SIMPLE;
1480 }
1481
1482 ISEQ_BODY(iseq)->ci_size++;
1483 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1484 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1485 return ci;
1486}
1487
1488static INSN *
1489new_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)
1490{
1491 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1492 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1493 operands[0] = ci;
1494 operands[1] = (VALUE)blockiseq;
1495 if (blockiseq) {
1496 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1497 }
1498
1499 INSN *insn;
1500
1501 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1502 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1503 }
1504 else {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1506 }
1507
1508 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1509 RB_GC_GUARD(ci);
1510 return insn;
1511}
1512
1513static rb_iseq_t *
1514new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1515 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1516{
1517 rb_iseq_t *ret_iseq;
1518 VALUE ast_value = rb_ruby_ast_new(node);
1519
1520 debugs("[new_child_iseq]> ---------------------------------------\n");
1521 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1522 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1523 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1524 line_no, parent,
1525 isolated_depth ? isolated_depth + 1 : 0,
1526 type, ISEQ_COMPILE_DATA(iseq)->option,
1527 ISEQ_BODY(iseq)->variable.script_lines);
1528 debugs("[new_child_iseq]< ---------------------------------------\n");
1529 return ret_iseq;
1530}
1531
1532static rb_iseq_t *
1533new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1534 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1535{
1536 rb_iseq_t *ret_iseq;
1537
1538 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1539 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1540 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1541 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1542 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1543 return ret_iseq;
1544}
1545
1546static void
1547set_catch_except_p(rb_iseq_t *iseq)
1548{
1549 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1550 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1551 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1552 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1553 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1554 }
1555 }
1556}
1557
1558/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1559 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1560 if catch table exists. But we want to optimize while loop, which always has catch
1561 table entries for break/next/redo.
1562
1563 So this function sets true for limited ISeqs with break/next/redo catch table entries
1564 whose child ISeq would really raise an exception. */
1565static void
1566update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1567{
1568 unsigned int pos;
1569 size_t i;
1570 int insn;
1571 const struct iseq_catch_table *ct = body->catch_table;
1572
1573 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1574 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1575 pos = 0;
1576 while (pos < body->iseq_size) {
1577 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1578 if (insn == BIN(throw)) {
1579 set_catch_except_p(iseq);
1580 break;
1581 }
1582 pos += insn_len(insn);
1583 }
1584
1585 if (ct == NULL)
1586 return;
1587
1588 for (i = 0; i < ct->size; i++) {
1589 const struct iseq_catch_table_entry *entry =
1590 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1591 if (entry->type != CATCH_TYPE_BREAK
1592 && entry->type != CATCH_TYPE_NEXT
1593 && entry->type != CATCH_TYPE_REDO) {
1594 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1595 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1596 break;
1597 }
1598 }
1599}
1600
1601static void
1602iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1603{
1604 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1605 if (NIL_P(catch_table_ary)) return;
1606 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1607 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1608 for (i = 0; i < tlen; i++) {
1609 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1610 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1611 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1612 LINK_ELEMENT *e;
1613
1614 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1615
1616 if (ct != CATCH_TYPE_BREAK
1617 && ct != CATCH_TYPE_NEXT
1618 && ct != CATCH_TYPE_REDO) {
1619
1620 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1621 if (e == cont) {
1622 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1623 ELEM_INSERT_NEXT(end, &nop->link);
1624 break;
1625 }
1626 }
1627 }
1628 }
1629
1630 RB_GC_GUARD(catch_table_ary);
1631}
1632
1633static int
1634iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1635{
1636 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1637 return COMPILE_NG;
1638
1639 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1640
1641 if (compile_debug > 5)
1642 dump_disasm_list(FIRST_ELEMENT(anchor));
1643
1644 debugs("[compile step 3.1 (iseq_optimize)]\n");
1645 iseq_optimize(iseq, anchor);
1646
1647 if (compile_debug > 5)
1648 dump_disasm_list(FIRST_ELEMENT(anchor));
1649
1650 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1651 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1652 iseq_insns_unification(iseq, anchor);
1653 if (compile_debug > 5)
1654 dump_disasm_list(FIRST_ELEMENT(anchor));
1655 }
1656
1657 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1658 iseq_insert_nop_between_end_and_cont(iseq);
1659 if (compile_debug > 5)
1660 dump_disasm_list(FIRST_ELEMENT(anchor));
1661
1662 return COMPILE_OK;
1663}
1664
1665static int
1666iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1667{
1668 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1669 return COMPILE_NG;
1670
1671 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1672 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1673 if (compile_debug > 5)
1674 dump_disasm_list(FIRST_ELEMENT(anchor));
1675
1676 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1677 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1678
1679 debugs("[compile step 4.3 (set_optargs_table)] \n");
1680 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1681
1682 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1683 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1684
1685 debugs("[compile step 6 (update_catch_except_flags)] \n");
1686 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1687 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1688
1689 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1690 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1691 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1692 xfree(ISEQ_BODY(iseq)->catch_table);
1693 ISEQ_BODY(iseq)->catch_table = NULL;
1694 }
1695
1696#if VM_INSN_INFO_TABLE_IMPL == 2
1697 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1698 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1699 rb_iseq_insns_info_encode_positions(iseq);
1700 }
1701#endif
1702
1703 if (compile_debug > 1) {
1704 VALUE str = rb_iseq_disasm(iseq);
1705 printf("%s\n", StringValueCStr(str));
1706 }
1707 verify_call_cache(iseq);
1708 debugs("[compile step: finish]\n");
1709
1710 return COMPILE_OK;
1711}
1712
1713static int
1714iseq_set_exception_local_table(rb_iseq_t *iseq)
1715{
1716 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1717 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1718 return COMPILE_OK;
1719}
1720
1721static int
1722get_lvar_level(const rb_iseq_t *iseq)
1723{
1724 int lev = 0;
1725 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1726 lev++;
1727 iseq = ISEQ_BODY(iseq)->parent_iseq;
1728 }
1729 return lev;
1730}
1731
1732static int
1733get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1734{
1735 unsigned int i;
1736
1737 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1738 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1739 return (int)i;
1740 }
1741 }
1742 return -1;
1743}
1744
1745static int
1746get_local_var_idx(const rb_iseq_t *iseq, ID id)
1747{
1748 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1749
1750 if (idx < 0) {
1751 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1752 "get_local_var_idx: %d", idx);
1753 }
1754
1755 return idx;
1756}
1757
1758static int
1759get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1760{
1761 int lv = 0, idx = -1;
1762 const rb_iseq_t *const topmost_iseq = iseq;
1763
1764 while (iseq) {
1765 idx = get_dyna_var_idx_at_raw(iseq, id);
1766 if (idx >= 0) {
1767 break;
1768 }
1769 iseq = ISEQ_BODY(iseq)->parent_iseq;
1770 lv++;
1771 }
1772
1773 if (idx < 0) {
1774 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1775 "get_dyna_var_idx: -1");
1776 }
1777
1778 *level = lv;
1779 *ls = ISEQ_BODY(iseq)->local_table_size;
1780 return idx;
1781}
1782
1783static int
1784iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1785{
1786 const struct rb_iseq_constant_body *body;
1787 while (level > 0) {
1788 iseq = ISEQ_BODY(iseq)->parent_iseq;
1789 level--;
1790 }
1791 body = ISEQ_BODY(iseq);
1792 if (body->local_iseq == iseq && /* local variables */
1793 body->param.flags.has_block &&
1794 body->local_table_size - body->param.block_start == idx) {
1795 return TRUE;
1796 }
1797 else {
1798 return FALSE;
1799 }
1800}
1801
1802static int
1803iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1804{
1805 int level, ls;
1806 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1807 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1808 *pidx = ls - idx;
1809 *plevel = level;
1810 return TRUE;
1811 }
1812 else {
1813 return FALSE;
1814 }
1815}
1816
1817static void
1818access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1819{
1820 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1821
1822 if (isolated_depth && level >= isolated_depth) {
1823 if (id == rb_intern("yield")) {
1824 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1825 }
1826 else {
1827 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1828 }
1829 }
1830
1831 for (int i=0; i<level; i++) {
1832 VALUE val;
1833 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1834
1835 if (!ovs) {
1836 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1837 }
1838
1839 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1840 if (write && !val) {
1841 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1842 }
1843 }
1844 else {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1846 }
1847
1848 iseq = ISEQ_BODY(iseq)->parent_iseq;
1849 }
1850}
1851
1852static ID
1853iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1854{
1855 for (int i=0; i<level; i++) {
1856 iseq = ISEQ_BODY(iseq)->parent_iseq;
1857 }
1858
1859 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1860 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1861 return id;
1862}
1863
1864static void
1865iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1866{
1867 if (iseq_local_block_param_p(iseq, idx, level)) {
1868 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1869 }
1870 else {
1871 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1872 }
1873 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1874}
1875
1876static void
1877iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1878{
1879 if (iseq_local_block_param_p(iseq, idx, level)) {
1880 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1881 }
1882 else {
1883 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1884 }
1885 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1886}
1887
1888
1889
1890static void
1891iseq_calc_param_size(rb_iseq_t *iseq)
1892{
1893 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1894 if (body->param.flags.has_opt ||
1895 body->param.flags.has_post ||
1896 body->param.flags.has_rest ||
1897 body->param.flags.has_block ||
1898 body->param.flags.has_kw ||
1899 body->param.flags.has_kwrest) {
1900
1901 if (body->param.flags.has_block) {
1902 body->param.size = body->param.block_start + 1;
1903 }
1904 else if (body->param.flags.has_kwrest) {
1905 body->param.size = body->param.keyword->rest_start + 1;
1906 }
1907 else if (body->param.flags.has_kw) {
1908 body->param.size = body->param.keyword->bits_start + 1;
1909 }
1910 else if (body->param.flags.has_post) {
1911 body->param.size = body->param.post_start + body->param.post_num;
1912 }
1913 else if (body->param.flags.has_rest) {
1914 body->param.size = body->param.rest_start + 1;
1915 }
1916 else if (body->param.flags.has_opt) {
1917 body->param.size = body->param.lead_num + body->param.opt_num;
1918 }
1919 else {
1921 }
1922 }
1923 else {
1924 body->param.size = body->param.lead_num;
1925 }
1926}
1927
1928static int
1929iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1930 const struct rb_args_info *args, int arg_size)
1931{
1932 const rb_node_kw_arg_t *node = args->kw_args;
1933 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1934 struct rb_iseq_param_keyword *keyword;
1935 const VALUE default_values = rb_ary_hidden_new(1);
1936 const VALUE complex_mark = rb_str_tmp_new(0);
1937 int kw = 0, rkw = 0, di = 0, i;
1938
1939 body->param.flags.has_kw = TRUE;
1940 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1941
1942 while (node) {
1943 kw++;
1944 node = node->nd_next;
1945 }
1946 arg_size += kw;
1947 keyword->bits_start = arg_size++;
1948
1949 node = args->kw_args;
1950 while (node) {
1951 const NODE *val_node = get_nd_value(node->nd_body);
1952 VALUE dv;
1953
1954 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1955 ++rkw;
1956 }
1957 else {
1958 switch (nd_type(val_node)) {
1959 case NODE_SYM:
1960 dv = rb_node_sym_string_val(val_node);
1961 break;
1962 case NODE_REGX:
1963 dv = rb_node_regx_string_val(val_node);
1964 break;
1965 case NODE_LINE:
1966 dv = rb_node_line_lineno_val(val_node);
1967 break;
1968 case NODE_INTEGER:
1969 dv = rb_node_integer_literal_val(val_node);
1970 break;
1971 case NODE_FLOAT:
1972 dv = rb_node_float_literal_val(val_node);
1973 break;
1974 case NODE_RATIONAL:
1975 dv = rb_node_rational_literal_val(val_node);
1976 break;
1977 case NODE_IMAGINARY:
1978 dv = rb_node_imaginary_literal_val(val_node);
1979 break;
1980 case NODE_ENCODING:
1981 dv = rb_node_encoding_val(val_node);
1982 break;
1983 case NODE_NIL:
1984 dv = Qnil;
1985 break;
1986 case NODE_TRUE:
1987 dv = Qtrue;
1988 break;
1989 case NODE_FALSE:
1990 dv = Qfalse;
1991 break;
1992 default:
1993 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1994 dv = complex_mark;
1995 }
1996
1997 keyword->num = ++di;
1998 rb_ary_push(default_values, dv);
1999 }
2000
2001 node = node->nd_next;
2002 }
2003
2004 keyword->num = kw;
2005
2006 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2007 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2008 keyword->rest_start = arg_size++;
2009 body->param.flags.has_kwrest = TRUE;
2010
2011 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2012 }
2013 keyword->required_num = rkw;
2014 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2015
2016 if (RARRAY_LEN(default_values)) {
2017 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2018
2019 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2020 VALUE dv = RARRAY_AREF(default_values, i);
2021 if (dv == complex_mark) dv = Qundef;
2022 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2023 }
2024
2025 keyword->default_values = dvs;
2026 }
2027 return arg_size;
2028}
2029
2030static void
2031iseq_set_use_block(rb_iseq_t *iseq)
2032{
2033 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2034 if (!body->param.flags.use_block) {
2035 body->param.flags.use_block = 1;
2036
2037 rb_vm_t *vm = GET_VM();
2038
2039 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2040 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2041 set_insert(vm->unused_block_warning_table, key);
2042 }
2043 }
2044}
2045
2046static int
2047iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2048{
2049 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2050
2051 if (node_args) {
2052 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2053 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2054 ID rest_id = 0;
2055 int last_comma = 0;
2056 ID block_id = 0;
2057 int arg_size;
2058
2059 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2060
2061 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2062 body->param.lead_num = arg_size = (int)args->pre_args_num;
2063 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2064 debugs(" - argc: %d\n", body->param.lead_num);
2065
2066 rest_id = args->rest_arg;
2067 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2068 last_comma = 1;
2069 rest_id = 0;
2070 }
2071 block_id = args->block_arg;
2072
2073 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2074
2075 if (optimized_forward) {
2076 rest_id = 0;
2077 block_id = 0;
2078 }
2079
2080 if (args->opt_args) {
2081 const rb_node_opt_arg_t *node = args->opt_args;
2082 LABEL *label;
2083 VALUE labels = rb_ary_hidden_new(1);
2084 VALUE *opt_table;
2085 int i = 0, j;
2086
2087 while (node) {
2088 label = NEW_LABEL(nd_line(RNODE(node)));
2089 rb_ary_push(labels, (VALUE)label | 1);
2090 ADD_LABEL(optargs, label);
2091 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2092 node = node->nd_next;
2093 i += 1;
2094 }
2095
2096 /* last label */
2097 label = NEW_LABEL(nd_line(node_args));
2098 rb_ary_push(labels, (VALUE)label | 1);
2099 ADD_LABEL(optargs, label);
2100
2101 opt_table = ALLOC_N(VALUE, i+1);
2102
2103 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2104 for (j = 0; j < i+1; j++) {
2105 opt_table[j] &= ~1;
2106 }
2107 rb_ary_clear(labels);
2108
2109 body->param.flags.has_opt = TRUE;
2110 body->param.opt_num = i;
2111 body->param.opt_table = opt_table;
2112 arg_size += i;
2113 }
2114
2115 if (rest_id) {
2116 body->param.rest_start = arg_size++;
2117 body->param.flags.has_rest = TRUE;
2118 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2119 RUBY_ASSERT(body->param.rest_start != -1);
2120 }
2121
2122 if (args->first_post_arg) {
2123 body->param.post_start = arg_size;
2124 body->param.post_num = args->post_args_num;
2125 body->param.flags.has_post = TRUE;
2126 arg_size += args->post_args_num;
2127
2128 if (body->param.flags.has_rest) { /* TODO: why that? */
2129 body->param.post_start = body->param.rest_start + 1;
2130 }
2131 }
2132
2133 if (args->kw_args) {
2134 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2135 }
2136 else if (args->kw_rest_arg && !optimized_forward) {
2137 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2138 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2139 keyword->rest_start = arg_size++;
2140 body->param.keyword = keyword;
2141 body->param.flags.has_kwrest = TRUE;
2142
2143 static ID anon_kwrest = 0;
2144 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2145 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2146 }
2147 else if (args->no_kwarg) {
2148 body->param.flags.accepts_no_kwarg = TRUE;
2149 }
2150
2151 if (block_id) {
2152 body->param.block_start = arg_size++;
2153 body->param.flags.has_block = TRUE;
2154 iseq_set_use_block(iseq);
2155 }
2156
2157 // Only optimize specifically methods like this: `foo(...)`
2158 if (optimized_forward) {
2159 body->param.flags.use_block = 1;
2160 body->param.flags.forwardable = TRUE;
2161 arg_size = 1;
2162 }
2163
2164 iseq_calc_param_size(iseq);
2165 body->param.size = arg_size;
2166
2167 if (args->pre_init) { /* m_init */
2168 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2169 }
2170 if (args->post_init) { /* p_init */
2171 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2172 }
2173
2174 if (body->type == ISEQ_TYPE_BLOCK) {
2175 if (body->param.flags.has_opt == FALSE &&
2176 body->param.flags.has_post == FALSE &&
2177 body->param.flags.has_rest == FALSE &&
2178 body->param.flags.has_kw == FALSE &&
2179 body->param.flags.has_kwrest == FALSE) {
2180
2181 if (body->param.lead_num == 1 && last_comma == 0) {
2182 /* {|a|} */
2183 body->param.flags.ambiguous_param0 = TRUE;
2184 }
2185 }
2186 }
2187 }
2188
2189 return COMPILE_OK;
2190}
2191
2192static int
2193iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2194{
2195 unsigned int size = tbl ? tbl->size : 0;
2196 unsigned int offset = 0;
2197
2198 if (node_args) {
2199 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2200
2201 // If we have a function that only has `...` as the parameter,
2202 // then its local table should only be `...`
2203 // FIXME: I think this should be fixed in the AST rather than special case here.
2204 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2205 CHECK(size >= 3);
2206 size -= 3;
2207 offset += 3;
2208 }
2209 }
2210
2211 if (size > 0) {
2212 ID *ids = ALLOC_N(ID, size);
2213 MEMCPY(ids, tbl->ids + offset, ID, size);
2214 ISEQ_BODY(iseq)->local_table = ids;
2215 }
2216 ISEQ_BODY(iseq)->local_table_size = size;
2217
2218 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2219 return COMPILE_OK;
2220}
2221
2222int
2223rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2224{
2225 int tval, tlit;
2226
2227 if (val == lit) {
2228 return 0;
2229 }
2230 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2231 return val != lit;
2232 }
2233 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2234 return -1;
2235 }
2236 else if (tlit != tval) {
2237 return -1;
2238 }
2239 else if (tlit == T_SYMBOL) {
2240 return val != lit;
2241 }
2242 else if (tlit == T_STRING) {
2243 return rb_str_hash_cmp(lit, val);
2244 }
2245 else if (tlit == T_BIGNUM) {
2246 long x = FIX2LONG(rb_big_cmp(lit, val));
2247
2248 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2249 * There is no need to call rb_fix2int here. */
2250 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2251 return (int)x;
2252 }
2253 else if (tlit == T_FLOAT) {
2254 return rb_float_cmp(lit, val);
2255 }
2256 else if (tlit == T_RATIONAL) {
2257 const struct RRational *rat1 = RRATIONAL(val);
2258 const struct RRational *rat2 = RRATIONAL(lit);
2259 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2260 }
2261 else if (tlit == T_COMPLEX) {
2262 const struct RComplex *comp1 = RCOMPLEX(val);
2263 const struct RComplex *comp2 = RCOMPLEX(lit);
2264 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2265 }
2266 else if (tlit == T_REGEXP) {
2267 return rb_reg_equal(val, lit) ? 0 : -1;
2268 }
2269 else {
2271 }
2272}
2273
2274st_index_t
2275rb_iseq_cdhash_hash(VALUE a)
2276{
2277 switch (OBJ_BUILTIN_TYPE(a)) {
2278 case -1:
2279 case T_SYMBOL:
2280 return (st_index_t)a;
2281 case T_STRING:
2282 return rb_str_hash(a);
2283 case T_BIGNUM:
2284 return FIX2LONG(rb_big_hash(a));
2285 case T_FLOAT:
2286 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2287 case T_RATIONAL:
2288 return rb_rational_hash(a);
2289 case T_COMPLEX:
2290 return rb_complex_hash(a);
2291 case T_REGEXP:
2292 return NUM2LONG(rb_reg_hash(a));
2293 default:
2295 }
2296}
2297
2298static const struct st_hash_type cdhash_type = {
2299 rb_iseq_cdhash_cmp,
2300 rb_iseq_cdhash_hash,
2301};
2302
2304 VALUE hash;
2305 int pos;
2306 int len;
2307};
2308
2309static int
2310cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2311{
2312 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2313 LABEL *lobj = (LABEL *)(val & ~1);
2314 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2315 return ST_CONTINUE;
2316}
2317
2318
2319static inline VALUE
2320get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2321{
2322 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2323}
2324
2325static inline VALUE
2326get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2327{
2328 VALUE val;
2329 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2330 if (tbl) {
2331 if (rb_id_table_lookup(tbl,id,&val)) {
2332 return val;
2333 }
2334 }
2335 else {
2336 tbl = rb_id_table_create(1);
2337 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2338 }
2339 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2340 rb_id_table_insert(tbl,id,val);
2341 return val;
2342}
2343
2344#define BADINSN_DUMP(anchor, list, dest) \
2345 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2346
2347#define BADINSN_ERROR \
2348 (xfree(generated_iseq), \
2349 xfree(insns_info), \
2350 BADINSN_DUMP(anchor, list, NULL), \
2351 COMPILE_ERROR)
2352
2353static int
2354fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2355{
2356 int stack_max = 0, sp = 0, line = 0;
2357 LINK_ELEMENT *list;
2358
2359 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2360 if (IS_LABEL(list)) {
2361 LABEL *lobj = (LABEL *)list;
2362 lobj->set = TRUE;
2363 }
2364 }
2365
2366 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2367 switch (list->type) {
2368 case ISEQ_ELEMENT_INSN:
2369 {
2370 int j, len, insn;
2371 const char *types;
2372 VALUE *operands;
2373 INSN *iobj = (INSN *)list;
2374
2375 /* update sp */
2376 sp = calc_sp_depth(sp, iobj);
2377 if (sp < 0) {
2378 BADINSN_DUMP(anchor, list, NULL);
2379 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2380 "argument stack underflow (%d)", sp);
2381 return -1;
2382 }
2383 if (sp > stack_max) {
2384 stack_max = sp;
2385 }
2386
2387 line = iobj->insn_info.line_no;
2388 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2389 operands = iobj->operands;
2390 insn = iobj->insn_id;
2391 types = insn_op_types(insn);
2392 len = insn_len(insn);
2393
2394 /* operand check */
2395 if (iobj->operand_size != len - 1) {
2396 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2397 BADINSN_DUMP(anchor, list, NULL);
2398 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2399 "operand size miss! (%d for %d)",
2400 iobj->operand_size, len - 1);
2401 return -1;
2402 }
2403
2404 for (j = 0; types[j]; j++) {
2405 if (types[j] == TS_OFFSET) {
2406 /* label(destination position) */
2407 LABEL *lobj = (LABEL *)operands[j];
2408 if (!lobj->set) {
2409 BADINSN_DUMP(anchor, list, NULL);
2410 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2411 "unknown label: "LABEL_FORMAT, lobj->label_no);
2412 return -1;
2413 }
2414 if (lobj->sp == -1) {
2415 lobj->sp = sp;
2416 }
2417 else if (lobj->sp != sp) {
2418 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2419 RSTRING_PTR(rb_iseq_path(iseq)), line,
2420 lobj->label_no, lobj->sp, sp);
2421 }
2422 }
2423 }
2424 break;
2425 }
2426 case ISEQ_ELEMENT_LABEL:
2427 {
2428 LABEL *lobj = (LABEL *)list;
2429 if (lobj->sp == -1) {
2430 lobj->sp = sp;
2431 }
2432 else {
2433 if (lobj->sp != sp) {
2434 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2435 RSTRING_PTR(rb_iseq_path(iseq)), line,
2436 lobj->label_no, lobj->sp, sp);
2437 }
2438 sp = lobj->sp;
2439 }
2440 break;
2441 }
2442 case ISEQ_ELEMENT_TRACE:
2443 {
2444 /* ignore */
2445 break;
2446 }
2447 case ISEQ_ELEMENT_ADJUST:
2448 {
2449 ADJUST *adjust = (ADJUST *)list;
2450 int orig_sp = sp;
2451
2452 sp = adjust->label ? adjust->label->sp : 0;
2453 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2454 BADINSN_DUMP(anchor, list, NULL);
2455 COMPILE_ERROR(iseq, adjust->line_no,
2456 "iseq_set_sequence: adjust bug %d < %d",
2457 orig_sp, sp);
2458 return -1;
2459 }
2460 break;
2461 }
2462 default:
2463 BADINSN_DUMP(anchor, list, NULL);
2464 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2465 return -1;
2466 }
2467 }
2468 return stack_max;
2469}
2470
2471static int
2472add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2473 int insns_info_index, int code_index, const INSN *iobj)
2474{
2475 if (insns_info_index == 0 ||
2476 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2477#ifdef USE_ISEQ_NODE_ID
2478 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2479#endif
2480 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2481 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2482#ifdef USE_ISEQ_NODE_ID
2483 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2484#endif
2485 insns_info[insns_info_index].events = iobj->insn_info.events;
2486 positions[insns_info_index] = code_index;
2487 return TRUE;
2488 }
2489 return FALSE;
2490}
2491
2492static int
2493add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2494 int insns_info_index, int code_index, const ADJUST *adjust)
2495{
2496 insns_info[insns_info_index].line_no = adjust->line_no;
2497 insns_info[insns_info_index].node_id = -1;
2498 insns_info[insns_info_index].events = 0;
2499 positions[insns_info_index] = code_index;
2500 return TRUE;
2501}
2502
2503static ID *
2504array_to_idlist(VALUE arr)
2505{
2507 long size = RARRAY_LEN(arr);
2508 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2509 for (long i = 0; i < size; i++) {
2510 VALUE sym = RARRAY_AREF(arr, i);
2511 ids[i] = SYM2ID(sym);
2512 }
2513 ids[size] = 0;
2514 return ids;
2515}
2516
2517static VALUE
2518idlist_to_array(const ID *ids)
2519{
2520 VALUE arr = rb_ary_new();
2521 while (*ids) {
2522 rb_ary_push(arr, ID2SYM(*ids++));
2523 }
2524 return arr;
2525}
2526
2530static int
2531iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2532{
2533 struct iseq_insn_info_entry *insns_info;
2534 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2535 unsigned int *positions;
2536 LINK_ELEMENT *list;
2537 VALUE *generated_iseq;
2538 rb_event_flag_t events = 0;
2539 long data = 0;
2540
2541 int insn_num, code_index, insns_info_index, sp = 0;
2542 int stack_max = fix_sp_depth(iseq, anchor);
2543
2544 if (stack_max < 0) return COMPILE_NG;
2545
2546 /* fix label position */
2547 insn_num = code_index = 0;
2548 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2549 switch (list->type) {
2550 case ISEQ_ELEMENT_INSN:
2551 {
2552 INSN *iobj = (INSN *)list;
2553 /* update sp */
2554 sp = calc_sp_depth(sp, iobj);
2555 insn_num++;
2556 events = iobj->insn_info.events |= events;
2557 if (ISEQ_COVERAGE(iseq)) {
2558 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2559 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2560 int line = iobj->insn_info.line_no - 1;
2561 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2562 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2563 }
2564 }
2565 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2566 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2567 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2568 }
2569 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2570 }
2571 }
2572 code_index += insn_data_length(iobj);
2573 events = 0;
2574 data = 0;
2575 break;
2576 }
2577 case ISEQ_ELEMENT_LABEL:
2578 {
2579 LABEL *lobj = (LABEL *)list;
2580 lobj->position = code_index;
2581 if (lobj->sp != sp) {
2582 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2583 RSTRING_PTR(rb_iseq_path(iseq)),
2584 lobj->label_no, lobj->sp, sp);
2585 }
2586 sp = lobj->sp;
2587 break;
2588 }
2589 case ISEQ_ELEMENT_TRACE:
2590 {
2591 TRACE *trace = (TRACE *)list;
2592 events |= trace->event;
2593 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2594 break;
2595 }
2596 case ISEQ_ELEMENT_ADJUST:
2597 {
2598 ADJUST *adjust = (ADJUST *)list;
2599 if (adjust->line_no != -1) {
2600 int orig_sp = sp;
2601 sp = adjust->label ? adjust->label->sp : 0;
2602 if (orig_sp - sp > 0) {
2603 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2604 code_index++; /* insn */
2605 insn_num++;
2606 }
2607 }
2608 break;
2609 }
2610 default: break;
2611 }
2612 }
2613
2614 /* make instruction sequence */
2615 generated_iseq = ALLOC_N(VALUE, code_index);
2616 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2617 positions = ALLOC_N(unsigned int, insn_num);
2618 if (ISEQ_IS_SIZE(body)) {
2619 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2620 }
2621 else {
2622 body->is_entries = NULL;
2623 }
2624
2625 if (body->ci_size) {
2626 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2627 }
2628 else {
2629 body->call_data = NULL;
2630 }
2631 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2632
2633 // Calculate the bitmask buffer size.
2634 // Round the generated_iseq size up to the nearest multiple
2635 // of the number of bits in an unsigned long.
2636
2637 // Allocate enough room for the bitmask list
2638 iseq_bits_t * mark_offset_bits;
2639 int code_size = code_index;
2640
2641 bool needs_bitmap = false;
2642
2643 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2644 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2645 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2646 }
2647 else {
2648 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2649 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2650 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2651 }
2652
2653 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2654 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2655
2656 list = FIRST_ELEMENT(anchor);
2657 insns_info_index = code_index = sp = 0;
2658
2659 while (list) {
2660 switch (list->type) {
2661 case ISEQ_ELEMENT_INSN:
2662 {
2663 int j, len, insn;
2664 const char *types;
2665 VALUE *operands;
2666 INSN *iobj = (INSN *)list;
2667
2668 /* update sp */
2669 sp = calc_sp_depth(sp, iobj);
2670 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2671 operands = iobj->operands;
2672 insn = iobj->insn_id;
2673 generated_iseq[code_index] = insn;
2674 types = insn_op_types(insn);
2675 len = insn_len(insn);
2676
2677 for (j = 0; types[j]; j++) {
2678 char type = types[j];
2679
2680 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2681 switch (type) {
2682 case TS_OFFSET:
2683 {
2684 /* label(destination position) */
2685 LABEL *lobj = (LABEL *)operands[j];
2686 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2687 break;
2688 }
2689 case TS_CDHASH:
2690 {
2691 VALUE map = operands[j];
2692 struct cdhash_set_label_struct data;
2693 data.hash = map;
2694 data.pos = code_index;
2695 data.len = len;
2696 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2697
2698 rb_hash_rehash(map);
2699 freeze_hide_obj(map);
2700 generated_iseq[code_index + 1 + j] = map;
2701 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2702 RB_OBJ_WRITTEN(iseq, Qundef, map);
2703 needs_bitmap = true;
2704 break;
2705 }
2706 case TS_LINDEX:
2707 case TS_NUM: /* ulong */
2708 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2709 break;
2710 case TS_ISEQ: /* iseq */
2711 case TS_VALUE: /* VALUE */
2712 {
2713 VALUE v = operands[j];
2714 generated_iseq[code_index + 1 + j] = v;
2715 /* to mark ruby object */
2716 if (!SPECIAL_CONST_P(v)) {
2717 RB_OBJ_WRITTEN(iseq, Qundef, v);
2718 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2719 needs_bitmap = true;
2720 }
2721 break;
2722 }
2723 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2724 case TS_IC: /* inline cache: constants */
2725 {
2726 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2727 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2728 if (UNLIKELY(ic_index >= body->ic_size)) {
2729 BADINSN_DUMP(anchor, &iobj->link, 0);
2730 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2731 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2732 ic_index, ISEQ_IS_SIZE(body));
2733 }
2734
2735 ic->segments = array_to_idlist(operands[j]);
2736
2737 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2738 }
2739 break;
2740 case TS_IVC: /* inline ivar cache */
2741 {
2742 unsigned int ic_index = FIX2UINT(operands[j]);
2743
2744 IVC cache = ((IVC)&body->is_entries[ic_index]);
2745
2746 if (insn == BIN(setinstancevariable)) {
2747 cache->iv_set_name = SYM2ID(operands[j - 1]);
2748 }
2749 else {
2750 cache->iv_set_name = 0;
2751 }
2752
2753 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2754 }
2755 case TS_ISE: /* inline storage entry: `once` insn */
2756 case TS_ICVARC: /* inline cvar cache */
2757 {
2758 unsigned int ic_index = FIX2UINT(operands[j]);
2759 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2760 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2761 BADINSN_DUMP(anchor, &iobj->link, 0);
2762 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2763 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2764 ic_index, ISEQ_IS_SIZE(body));
2765 }
2766 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2767
2768 break;
2769 }
2770 case TS_CALLDATA:
2771 {
2772 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2773 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2774 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2775 cd->ci = source_ci;
2776 cd->cc = vm_cc_empty();
2777 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2778 break;
2779 }
2780 case TS_ID: /* ID */
2781 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2782 break;
2783 case TS_FUNCPTR:
2784 generated_iseq[code_index + 1 + j] = operands[j];
2785 break;
2786 case TS_BUILTIN:
2787 generated_iseq[code_index + 1 + j] = operands[j];
2788 break;
2789 default:
2790 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2791 "unknown operand type: %c", type);
2792 return COMPILE_NG;
2793 }
2794 }
2795 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2796 code_index += len;
2797 break;
2798 }
2799 case ISEQ_ELEMENT_LABEL:
2800 {
2801 LABEL *lobj = (LABEL *)list;
2802 if (lobj->sp != sp) {
2803 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2804 RSTRING_PTR(rb_iseq_path(iseq)),
2805 lobj->label_no, lobj->sp, sp);
2806 }
2807 sp = lobj->sp;
2808 break;
2809 }
2810 case ISEQ_ELEMENT_ADJUST:
2811 {
2812 ADJUST *adjust = (ADJUST *)list;
2813 int orig_sp = sp;
2814
2815 if (adjust->label) {
2816 sp = adjust->label->sp;
2817 }
2818 else {
2819 sp = 0;
2820 }
2821
2822 if (adjust->line_no != -1) {
2823 const int diff = orig_sp - sp;
2824 if (diff > 0) {
2825 if (insns_info_index == 0) {
2826 COMPILE_ERROR(iseq, adjust->line_no,
2827 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2828 }
2829 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2830 }
2831 if (diff > 1) {
2832 generated_iseq[code_index++] = BIN(adjuststack);
2833 generated_iseq[code_index++] = orig_sp - sp;
2834 }
2835 else if (diff == 1) {
2836 generated_iseq[code_index++] = BIN(pop);
2837 }
2838 else if (diff < 0) {
2839 int label_no = adjust->label ? adjust->label->label_no : -1;
2840 xfree(generated_iseq);
2841 xfree(insns_info);
2842 xfree(positions);
2843 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2844 xfree(mark_offset_bits);
2845 }
2846 debug_list(anchor, list);
2847 COMPILE_ERROR(iseq, adjust->line_no,
2848 "iseq_set_sequence: adjust bug to %d %d < %d",
2849 label_no, orig_sp, sp);
2850 return COMPILE_NG;
2851 }
2852 }
2853 break;
2854 }
2855 default:
2856 /* ignore */
2857 break;
2858 }
2859 list = list->next;
2860 }
2861
2862 body->iseq_encoded = (void *)generated_iseq;
2863 body->iseq_size = code_index;
2864 body->stack_max = stack_max;
2865
2866 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2867 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2868 }
2869 else {
2870 if (needs_bitmap) {
2871 body->mark_bits.list = mark_offset_bits;
2872 }
2873 else {
2874 body->mark_bits.list = NULL;
2875 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2876 ruby_xfree(mark_offset_bits);
2877 }
2878 }
2879
2880 /* get rid of memory leak when REALLOC failed */
2881 body->insns_info.body = insns_info;
2882 body->insns_info.positions = positions;
2883
2884 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2885 body->insns_info.body = insns_info;
2886 REALLOC_N(positions, unsigned int, insns_info_index);
2887 body->insns_info.positions = positions;
2888 body->insns_info.size = insns_info_index;
2889
2890 return COMPILE_OK;
2891}
2892
2893static int
2894label_get_position(LABEL *lobj)
2895{
2896 return lobj->position;
2897}
2898
2899static int
2900label_get_sp(LABEL *lobj)
2901{
2902 return lobj->sp;
2903}
2904
2905static int
2906iseq_set_exception_table(rb_iseq_t *iseq)
2907{
2908 const VALUE *tptr, *ptr;
2909 unsigned int tlen, i;
2910 struct iseq_catch_table_entry *entry;
2911
2912 ISEQ_BODY(iseq)->catch_table = NULL;
2913
2914 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2915 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2916 tlen = (int)RARRAY_LEN(catch_table_ary);
2917 tptr = RARRAY_CONST_PTR(catch_table_ary);
2918
2919 if (tlen > 0) {
2920 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2921 table->size = tlen;
2922
2923 for (i = 0; i < table->size; i++) {
2924 int pos;
2925 ptr = RARRAY_CONST_PTR(tptr[i]);
2926 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2927 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2928 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2929 RUBY_ASSERT(pos >= 0);
2930 entry->start = (unsigned int)pos;
2931 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2932 RUBY_ASSERT(pos >= 0);
2933 entry->end = (unsigned int)pos;
2934 entry->iseq = (rb_iseq_t *)ptr[3];
2935 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2936
2937 /* stack depth */
2938 if (ptr[4]) {
2939 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2940 entry->cont = label_get_position(lobj);
2941 entry->sp = label_get_sp(lobj);
2942
2943 /* TODO: Dirty Hack! Fix me */
2944 if (entry->type == CATCH_TYPE_RESCUE ||
2945 entry->type == CATCH_TYPE_BREAK ||
2946 entry->type == CATCH_TYPE_NEXT) {
2947 RUBY_ASSERT(entry->sp > 0);
2948 entry->sp--;
2949 }
2950 }
2951 else {
2952 entry->cont = 0;
2953 }
2954 }
2955 ISEQ_BODY(iseq)->catch_table = table;
2956 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2957 }
2958
2959 RB_GC_GUARD(catch_table_ary);
2960
2961 return COMPILE_OK;
2962}
2963
2964/*
2965 * set optional argument table
2966 * def foo(a, b=expr1, c=expr2)
2967 * =>
2968 * b:
2969 * expr1
2970 * c:
2971 * expr2
2972 */
2973static int
2974iseq_set_optargs_table(rb_iseq_t *iseq)
2975{
2976 int i;
2977 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2978
2979 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2980 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2981 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2982 }
2983 }
2984 return COMPILE_OK;
2985}
2986
2987static LINK_ELEMENT *
2988get_destination_insn(INSN *iobj)
2989{
2990 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2991 LINK_ELEMENT *list;
2992 rb_event_flag_t events = 0;
2993
2994 list = lobj->link.next;
2995 while (list) {
2996 switch (list->type) {
2997 case ISEQ_ELEMENT_INSN:
2998 case ISEQ_ELEMENT_ADJUST:
2999 goto found;
3000 case ISEQ_ELEMENT_LABEL:
3001 /* ignore */
3002 break;
3003 case ISEQ_ELEMENT_TRACE:
3004 {
3005 TRACE *trace = (TRACE *)list;
3006 events |= trace->event;
3007 }
3008 break;
3009 default: break;
3010 }
3011 list = list->next;
3012 }
3013 found:
3014 if (list && IS_INSN(list)) {
3015 INSN *iobj = (INSN *)list;
3016 iobj->insn_info.events |= events;
3017 }
3018 return list;
3019}
3020
3021static LINK_ELEMENT *
3022get_next_insn(INSN *iobj)
3023{
3024 LINK_ELEMENT *list = iobj->link.next;
3025
3026 while (list) {
3027 if (IS_INSN(list) || IS_ADJUST(list)) {
3028 return list;
3029 }
3030 list = list->next;
3031 }
3032 return 0;
3033}
3034
3035static LINK_ELEMENT *
3036get_prev_insn(INSN *iobj)
3037{
3038 LINK_ELEMENT *list = iobj->link.prev;
3039
3040 while (list) {
3041 if (IS_INSN(list) || IS_ADJUST(list)) {
3042 return list;
3043 }
3044 list = list->prev;
3045 }
3046 return 0;
3047}
3048
3049static void
3050unref_destination(INSN *iobj, int pos)
3051{
3052 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3053 --lobj->refcnt;
3054 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3055}
3056
3057static bool
3058replace_destination(INSN *dobj, INSN *nobj)
3059{
3060 VALUE n = OPERAND_AT(nobj, 0);
3061 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3062 LABEL *nl = (LABEL *)n;
3063 if (dl == nl) return false;
3064 --dl->refcnt;
3065 ++nl->refcnt;
3066 OPERAND_AT(dobj, 0) = n;
3067 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3068 return true;
3069}
3070
3071static LABEL*
3072find_destination(INSN *i)
3073{
3074 int pos, len = insn_len(i->insn_id);
3075 for (pos = 0; pos < len; ++pos) {
3076 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3077 return (LABEL *)OPERAND_AT(i, pos);
3078 }
3079 }
3080 return 0;
3081}
3082
3083static int
3084remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3085{
3086 LINK_ELEMENT *first = i, *end;
3087 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3088
3089 if (!i) return 0;
3090 unref_counts = ALLOCA_N(int, nlabels);
3091 MEMZERO(unref_counts, int, nlabels);
3092 end = i;
3093 do {
3094 LABEL *lab;
3095 if (IS_INSN(i)) {
3096 if (IS_INSN_ID(i, leave)) {
3097 end = i;
3098 break;
3099 }
3100 else if ((lab = find_destination((INSN *)i)) != 0) {
3101 unref_counts[lab->label_no]++;
3102 }
3103 }
3104 else if (IS_LABEL(i)) {
3105 lab = (LABEL *)i;
3106 if (lab->unremovable) return 0;
3107 if (lab->refcnt > unref_counts[lab->label_no]) {
3108 if (i == first) return 0;
3109 break;
3110 }
3111 continue;
3112 }
3113 else if (IS_TRACE(i)) {
3114 /* do nothing */
3115 }
3116 else if (IS_ADJUST(i)) {
3117 return 0;
3118 }
3119 end = i;
3120 } while ((i = i->next) != 0);
3121 i = first;
3122 do {
3123 if (IS_INSN(i)) {
3124 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3125 VALUE insn = INSN_OF(i);
3126 int pos, len = insn_len(insn);
3127 for (pos = 0; pos < len; ++pos) {
3128 switch (insn_op_types(insn)[pos]) {
3129 case TS_OFFSET:
3130 unref_destination((INSN *)i, pos);
3131 break;
3132 case TS_CALLDATA:
3133 --(body->ci_size);
3134 break;
3135 }
3136 }
3137 }
3138 ELEM_REMOVE(i);
3139 } while ((i != end) && (i = i->next) != 0);
3140 return 1;
3141}
3142
3143static int
3144iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3145{
3146 switch (OPERAND_AT(iobj, 0)) {
3147 case INT2FIX(0): /* empty array */
3148 ELEM_REMOVE(&iobj->link);
3149 return TRUE;
3150 case INT2FIX(1): /* single element array */
3151 ELEM_REMOVE(&iobj->link);
3152 return FALSE;
3153 default:
3154 iobj->insn_id = BIN(adjuststack);
3155 return TRUE;
3156 }
3157}
3158
3159static int
3160is_frozen_putstring(INSN *insn, VALUE *op)
3161{
3162 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3163 *op = OPERAND_AT(insn, 0);
3164 return 1;
3165 }
3166 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3167 *op = OPERAND_AT(insn, 0);
3168 return RB_TYPE_P(*op, T_STRING);
3169 }
3170 return 0;
3171}
3172
3173static int
3174optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3175{
3176 /*
3177 * putobject obj
3178 * dup
3179 * checktype T_XXX
3180 * branchif l1
3181 * l2:
3182 * ...
3183 * l1:
3184 *
3185 * => obj is a T_XXX
3186 *
3187 * putobject obj (T_XXX)
3188 * jump L1
3189 * L1:
3190 *
3191 * => obj is not a T_XXX
3192 *
3193 * putobject obj (T_XXX)
3194 * jump L2
3195 * L2:
3196 */
3197 int line, node_id;
3198 INSN *niobj, *ciobj, *dup = 0;
3199 LABEL *dest = 0;
3200 VALUE type;
3201
3202 switch (INSN_OF(iobj)) {
3203 case BIN(putstring):
3204 case BIN(putchilledstring):
3206 break;
3207 case BIN(putnil):
3208 type = INT2FIX(T_NIL);
3209 break;
3210 case BIN(putobject):
3211 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3212 break;
3213 default: return FALSE;
3214 }
3215
3216 ciobj = (INSN *)get_next_insn(iobj);
3217 if (IS_INSN_ID(ciobj, jump)) {
3218 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3219 }
3220 if (IS_INSN_ID(ciobj, dup)) {
3221 ciobj = (INSN *)get_next_insn(dup = ciobj);
3222 }
3223 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3224 niobj = (INSN *)get_next_insn(ciobj);
3225 if (!niobj) {
3226 /* TODO: putobject true/false */
3227 return FALSE;
3228 }
3229 switch (INSN_OF(niobj)) {
3230 case BIN(branchif):
3231 if (OPERAND_AT(ciobj, 0) == type) {
3232 dest = (LABEL *)OPERAND_AT(niobj, 0);
3233 }
3234 break;
3235 case BIN(branchunless):
3236 if (OPERAND_AT(ciobj, 0) != type) {
3237 dest = (LABEL *)OPERAND_AT(niobj, 0);
3238 }
3239 break;
3240 default:
3241 return FALSE;
3242 }
3243 line = ciobj->insn_info.line_no;
3244 node_id = ciobj->insn_info.node_id;
3245 if (!dest) {
3246 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3247 dest = (LABEL *)niobj->link.next; /* reuse label */
3248 }
3249 else {
3250 dest = NEW_LABEL(line);
3251 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3252 }
3253 }
3254 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3255 LABEL_REF(dest);
3256 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3257 return TRUE;
3258}
3259
3260static const struct rb_callinfo *
3261ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3262{
3263 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3264 vm_ci_flag(ci) | add,
3265 vm_ci_argc(ci),
3266 vm_ci_kwarg(ci));
3267 RB_OBJ_WRITTEN(iseq, ci, nci);
3268 return nci;
3269}
3270
3271static const struct rb_callinfo *
3272ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3273{
3274 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3275 vm_ci_flag(ci),
3276 argc,
3277 vm_ci_kwarg(ci));
3278 RB_OBJ_WRITTEN(iseq, ci, nci);
3279 return nci;
3280}
3281
3282#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3283
3284static int
3285iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3286{
3287 INSN *const iobj = (INSN *)list;
3288
3289 again:
3290 optimize_checktype(iseq, iobj);
3291
3292 if (IS_INSN_ID(iobj, jump)) {
3293 INSN *niobj, *diobj, *piobj;
3294 diobj = (INSN *)get_destination_insn(iobj);
3295 niobj = (INSN *)get_next_insn(iobj);
3296
3297 if (diobj == niobj) {
3298 /*
3299 * jump LABEL
3300 * LABEL:
3301 * =>
3302 * LABEL:
3303 */
3304 unref_destination(iobj, 0);
3305 ELEM_REMOVE(&iobj->link);
3306 return COMPILE_OK;
3307 }
3308 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3309 IS_INSN_ID(diobj, jump) &&
3310 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3311 diobj->insn_info.events == 0) {
3312 /*
3313 * useless jump elimination:
3314 * jump LABEL1
3315 * ...
3316 * LABEL1:
3317 * jump LABEL2
3318 *
3319 * => in this case, first jump instruction should jump to
3320 * LABEL2 directly
3321 */
3322 if (replace_destination(iobj, diobj)) {
3323 remove_unreachable_chunk(iseq, iobj->link.next);
3324 goto again;
3325 }
3326 }
3327 else if (IS_INSN_ID(diobj, leave)) {
3328 /*
3329 * jump LABEL
3330 * ...
3331 * LABEL:
3332 * leave
3333 * =>
3334 * leave
3335 * ...
3336 * LABEL:
3337 * leave
3338 */
3339 /* replace */
3340 unref_destination(iobj, 0);
3341 iobj->insn_id = BIN(leave);
3342 iobj->operand_size = 0;
3343 iobj->insn_info = diobj->insn_info;
3344 goto again;
3345 }
3346 else if (IS_INSN(iobj->link.prev) &&
3347 (piobj = (INSN *)iobj->link.prev) &&
3348 (IS_INSN_ID(piobj, branchif) ||
3349 IS_INSN_ID(piobj, branchunless))) {
3350 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3351 if (niobj == pdiobj) {
3352 int refcnt = IS_LABEL(piobj->link.next) ?
3353 ((LABEL *)piobj->link.next)->refcnt : 0;
3354 /*
3355 * useless jump elimination (if/unless destination):
3356 * if L1
3357 * jump L2
3358 * L1:
3359 * ...
3360 * L2:
3361 *
3362 * ==>
3363 * unless L2
3364 * L1:
3365 * ...
3366 * L2:
3367 */
3368 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3369 ? BIN(branchunless) : BIN(branchif);
3370 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3371 ELEM_REMOVE(&iobj->link);
3372 }
3373 else {
3374 /* TODO: replace other branch destinations too */
3375 }
3376 return COMPILE_OK;
3377 }
3378 else if (diobj == pdiobj) {
3379 /*
3380 * useless jump elimination (if/unless before jump):
3381 * L1:
3382 * ...
3383 * if L1
3384 * jump L1
3385 *
3386 * ==>
3387 * L1:
3388 * ...
3389 * pop
3390 * jump L1
3391 */
3392 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3393 ELEM_REPLACE(&piobj->link, &popiobj->link);
3394 }
3395 }
3396 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3397 goto again;
3398 }
3399 }
3400
3401 /*
3402 * putstring "beg"
3403 * putstring "end"
3404 * newrange excl
3405 *
3406 * ==>
3407 *
3408 * putobject "beg".."end"
3409 */
3410 if (IS_INSN_ID(iobj, newrange)) {
3411 INSN *const range = iobj;
3412 INSN *beg, *end;
3413 VALUE str_beg, str_end;
3414
3415 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3416 is_frozen_putstring(end, &str_end) &&
3417 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3418 is_frozen_putstring(beg, &str_beg)) {
3419 int excl = FIX2INT(OPERAND_AT(range, 0));
3420 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3421
3422 ELEM_REMOVE(&beg->link);
3423 ELEM_REMOVE(&end->link);
3424 range->insn_id = BIN(putobject);
3425 OPERAND_AT(range, 0) = lit_range;
3426 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3427 }
3428 }
3429
3430 if (IS_INSN_ID(iobj, leave)) {
3431 remove_unreachable_chunk(iseq, iobj->link.next);
3432 }
3433
3434 /*
3435 * ...
3436 * duparray [...]
3437 * concatarray | concattoarray
3438 * =>
3439 * ...
3440 * putobject [...]
3441 * concatarray | concattoarray
3442 */
3443 if (IS_INSN_ID(iobj, duparray)) {
3444 LINK_ELEMENT *next = iobj->link.next;
3445 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3446 iobj->insn_id = BIN(putobject);
3447 }
3448 }
3449
3450 /*
3451 * duparray [...]
3452 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3453 * =>
3454 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3455 */
3456 if (IS_INSN_ID(iobj, duparray)) {
3457 LINK_ELEMENT *next = iobj->link.next;
3458 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3459 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3460 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3461
3462 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3463 VALUE ary = iobj->operands[0];
3465
3466 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3467 ELEM_REMOVE(next);
3468 }
3469 }
3470 }
3471
3472 /*
3473 * duphash {...}
3474 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3475 * =>
3476 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3477 */
3478 if (IS_INSN_ID(iobj, duphash)) {
3479 LINK_ELEMENT *next = iobj->link.next;
3480 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3481 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3482 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3483
3484 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3485 VALUE hash = iobj->operands[0];
3486 rb_obj_reveal(hash, rb_cHash);
3487
3488 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3489 ELEM_REMOVE(next);
3490 }
3491 }
3492 }
3493
3494 /*
3495 * newarray 0
3496 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3497 * =>
3498 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3499 */
3500 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3501 LINK_ELEMENT *next = iobj->link.next;
3502 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3503 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3504 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3505
3506 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3507 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3508 ELEM_REMOVE(next);
3509 }
3510 }
3511 }
3512
3513 /*
3514 * newhash 0
3515 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3516 * =>
3517 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3518 */
3519 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3520 LINK_ELEMENT *next = iobj->link.next;
3521 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3522 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3523 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3524
3525 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3526 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3527 ELEM_REMOVE(next);
3528 }
3529 }
3530 }
3531
3532 if (IS_INSN_ID(iobj, branchif) ||
3533 IS_INSN_ID(iobj, branchnil) ||
3534 IS_INSN_ID(iobj, branchunless)) {
3535 /*
3536 * if L1
3537 * ...
3538 * L1:
3539 * jump L2
3540 * =>
3541 * if L2
3542 */
3543 INSN *nobj = (INSN *)get_destination_insn(iobj);
3544
3545 /* This is super nasty hack!!!
3546 *
3547 * This jump-jump optimization may ignore event flags of the jump
3548 * instruction being skipped. Actually, Line 2 TracePoint event
3549 * is never fired in the following code:
3550 *
3551 * 1: raise if 1 == 2
3552 * 2: while true
3553 * 3: break
3554 * 4: end
3555 *
3556 * This is critical for coverage measurement. [Bug #15980]
3557 *
3558 * This is a stopgap measure: stop the jump-jump optimization if
3559 * coverage measurement is enabled and if the skipped instruction
3560 * has any event flag.
3561 *
3562 * Note that, still, TracePoint Line event does not occur on Line 2.
3563 * This should be fixed in future.
3564 */
3565 int stop_optimization =
3566 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3567 nobj->link.type == ISEQ_ELEMENT_INSN &&
3568 nobj->insn_info.events;
3569 if (!stop_optimization) {
3570 INSN *pobj = (INSN *)iobj->link.prev;
3571 int prev_dup = 0;
3572 if (pobj) {
3573 if (!IS_INSN(&pobj->link))
3574 pobj = 0;
3575 else if (IS_INSN_ID(pobj, dup))
3576 prev_dup = 1;
3577 }
3578
3579 for (;;) {
3580 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3581 if (!replace_destination(iobj, nobj)) break;
3582 }
3583 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3584 !!(nobj = (INSN *)nobj->link.next) &&
3585 /* basic blocks, with no labels in the middle */
3586 nobj->insn_id == iobj->insn_id) {
3587 /*
3588 * dup
3589 * if L1
3590 * ...
3591 * L1:
3592 * dup
3593 * if L2
3594 * =>
3595 * dup
3596 * if L2
3597 * ...
3598 * L1:
3599 * dup
3600 * if L2
3601 */
3602 if (!replace_destination(iobj, nobj)) break;
3603 }
3604 else if (pobj) {
3605 /*
3606 * putnil
3607 * if L1
3608 * =>
3609 * # nothing
3610 *
3611 * putobject true
3612 * if L1
3613 * =>
3614 * jump L1
3615 *
3616 * putstring ".."
3617 * if L1
3618 * =>
3619 * jump L1
3620 *
3621 * putstring ".."
3622 * dup
3623 * if L1
3624 * =>
3625 * putstring ".."
3626 * jump L1
3627 *
3628 */
3629 int cond;
3630 if (prev_dup && IS_INSN(pobj->link.prev)) {
3631 pobj = (INSN *)pobj->link.prev;
3632 }
3633 if (IS_INSN_ID(pobj, putobject)) {
3634 cond = (IS_INSN_ID(iobj, branchif) ?
3635 OPERAND_AT(pobj, 0) != Qfalse :
3636 IS_INSN_ID(iobj, branchunless) ?
3637 OPERAND_AT(pobj, 0) == Qfalse :
3638 FALSE);
3639 }
3640 else if (IS_INSN_ID(pobj, putstring) ||
3641 IS_INSN_ID(pobj, duparray) ||
3642 IS_INSN_ID(pobj, newarray)) {
3643 cond = IS_INSN_ID(iobj, branchif);
3644 }
3645 else if (IS_INSN_ID(pobj, putnil)) {
3646 cond = !IS_INSN_ID(iobj, branchif);
3647 }
3648 else break;
3649 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3650 ELEM_REMOVE(iobj->link.prev);
3651 }
3652 else if (!iseq_pop_newarray(iseq, pobj)) {
3653 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3654 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3655 }
3656 if (cond) {
3657 if (prev_dup) {
3658 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3659 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3660 }
3661 iobj->insn_id = BIN(jump);
3662 goto again;
3663 }
3664 else {
3665 unref_destination(iobj, 0);
3666 ELEM_REMOVE(&iobj->link);
3667 }
3668 break;
3669 }
3670 else break;
3671 nobj = (INSN *)get_destination_insn(nobj);
3672 }
3673 }
3674 }
3675
3676 if (IS_INSN_ID(iobj, pop)) {
3677 /*
3678 * putself / putnil / putobject obj / putstring "..."
3679 * pop
3680 * =>
3681 * # do nothing
3682 */
3683 LINK_ELEMENT *prev = iobj->link.prev;
3684 if (IS_INSN(prev)) {
3685 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3686 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3687 previ == BIN(putself) || previ == BIN(putstring) ||
3688 previ == BIN(putchilledstring) ||
3689 previ == BIN(dup) ||
3690 previ == BIN(getlocal) ||
3691 previ == BIN(getblockparam) ||
3692 previ == BIN(getblockparamproxy) ||
3693 previ == BIN(getinstancevariable) ||
3694 previ == BIN(duparray)) {
3695 /* just push operand or static value and pop soon, no
3696 * side effects */
3697 ELEM_REMOVE(prev);
3698 ELEM_REMOVE(&iobj->link);
3699 }
3700 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3701 ELEM_REMOVE(&iobj->link);
3702 }
3703 else if (previ == BIN(concatarray)) {
3704 INSN *piobj = (INSN *)prev;
3705 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3706 INSN_OF(piobj) = BIN(pop);
3707 }
3708 else if (previ == BIN(concatstrings)) {
3709 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3710 ELEM_REMOVE(prev);
3711 }
3712 else {
3713 ELEM_REMOVE(&iobj->link);
3714 INSN_OF(prev) = BIN(adjuststack);
3715 }
3716 }
3717 }
3718 }
3719
3720 if (IS_INSN_ID(iobj, newarray) ||
3721 IS_INSN_ID(iobj, duparray) ||
3722 IS_INSN_ID(iobj, concatarray) ||
3723 IS_INSN_ID(iobj, splatarray) ||
3724 0) {
3725 /*
3726 * newarray N
3727 * splatarray
3728 * =>
3729 * newarray N
3730 * newarray always puts an array
3731 */
3732 LINK_ELEMENT *next = iobj->link.next;
3733 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3734 /* remove splatarray following always-array insn */
3735 ELEM_REMOVE(next);
3736 }
3737 }
3738
3739 if (IS_INSN_ID(iobj, newarray)) {
3740 LINK_ELEMENT *next = iobj->link.next;
3741 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3742 OPERAND_AT(next, 1) == INT2FIX(0)) {
3743 VALUE op1, op2;
3744 op1 = OPERAND_AT(iobj, 0);
3745 op2 = OPERAND_AT(next, 0);
3746 ELEM_REMOVE(next);
3747
3748 if (op1 == op2) {
3749 /*
3750 * newarray 2
3751 * expandarray 2, 0
3752 * =>
3753 * swap
3754 */
3755 if (op1 == INT2FIX(2)) {
3756 INSN_OF(iobj) = BIN(swap);
3757 iobj->operand_size = 0;
3758 }
3759 /*
3760 * newarray X
3761 * expandarray X, 0
3762 * =>
3763 * opt_reverse X
3764 */
3765 else {
3766 INSN_OF(iobj) = BIN(opt_reverse);
3767 }
3768 }
3769 else {
3770 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3771 INSN_OF(iobj) = BIN(opt_reverse);
3772 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3773
3774 if (op1 > op2) {
3775 /* X > Y
3776 * newarray X
3777 * expandarray Y, 0
3778 * =>
3779 * pop * (Y-X)
3780 * opt_reverse Y
3781 */
3782 for (; diff > 0; diff--) {
3783 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3784 }
3785 }
3786 else { /* (op1 < op2) */
3787 /* X < Y
3788 * newarray X
3789 * expandarray Y, 0
3790 * =>
3791 * putnil * (Y-X)
3792 * opt_reverse Y
3793 */
3794 for (; diff < 0; diff++) {
3795 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3796 }
3797 }
3798 }
3799 }
3800 }
3801
3802 if (IS_INSN_ID(iobj, duparray)) {
3803 LINK_ELEMENT *next = iobj->link.next;
3804 /*
3805 * duparray obj
3806 * expandarray X, 0
3807 * =>
3808 * putobject obj
3809 * expandarray X, 0
3810 */
3811 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3812 INSN_OF(iobj) = BIN(putobject);
3813 }
3814 }
3815
3816 if (IS_INSN_ID(iobj, anytostring)) {
3817 LINK_ELEMENT *next = iobj->link.next;
3818 /*
3819 * anytostring
3820 * concatstrings 1
3821 * =>
3822 * anytostring
3823 */
3824 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3825 OPERAND_AT(next, 0) == INT2FIX(1)) {
3826 ELEM_REMOVE(next);
3827 }
3828 }
3829
3830 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3831 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3832 /*
3833 * putstring ""
3834 * concatstrings N
3835 * =>
3836 * concatstrings N-1
3837 */
3838 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3839 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3840 INSN *next = (INSN *)iobj->link.next;
3841 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3842 ELEM_REMOVE(&next->link);
3843 }
3844 ELEM_REMOVE(&iobj->link);
3845 }
3846 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3847 INSN *next = (INSN *)iobj->link.next;
3848 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3849 VALUE src = OPERAND_AT(iobj, 0);
3850 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3851 VALUE path = rb_iseq_path(iseq);
3852 int line = iobj->insn_info.line_no;
3853 VALUE errinfo = rb_errinfo();
3854 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3855 if (NIL_P(re)) {
3856 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3857 rb_set_errinfo(errinfo);
3858 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3859 }
3860 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3861 ELEM_REMOVE(iobj->link.next);
3862 }
3863 }
3864 }
3865
3866 if (IS_INSN_ID(iobj, concatstrings)) {
3867 /*
3868 * concatstrings N
3869 * concatstrings M
3870 * =>
3871 * concatstrings N+M-1
3872 */
3873 LINK_ELEMENT *next = iobj->link.next;
3874 INSN *jump = 0;
3875 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3876 next = get_destination_insn(jump = (INSN *)next);
3877 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3878 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3879 OPERAND_AT(iobj, 0) = INT2FIX(n);
3880 if (jump) {
3881 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3882 if (!--label->refcnt) {
3883 ELEM_REMOVE(&label->link);
3884 }
3885 else {
3886 label = NEW_LABEL(0);
3887 OPERAND_AT(jump, 0) = (VALUE)label;
3888 }
3889 label->refcnt++;
3890 ELEM_INSERT_NEXT(next, &label->link);
3891 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3892 }
3893 else {
3894 ELEM_REMOVE(next);
3895 }
3896 }
3897 }
3898
3899 if (do_tailcallopt &&
3900 (IS_INSN_ID(iobj, send) ||
3901 IS_INSN_ID(iobj, invokesuper))) {
3902 /*
3903 * send ...
3904 * leave
3905 * =>
3906 * send ..., ... | VM_CALL_TAILCALL, ...
3907 * leave # unreachable
3908 */
3909 INSN *piobj = NULL;
3910 if (iobj->link.next) {
3911 LINK_ELEMENT *next = iobj->link.next;
3912 do {
3913 if (!IS_INSN(next)) {
3914 next = next->next;
3915 continue;
3916 }
3917 switch (INSN_OF(next)) {
3918 case BIN(nop):
3919 next = next->next;
3920 break;
3921 case BIN(jump):
3922 /* if cond
3923 * return tailcall
3924 * end
3925 */
3926 next = get_destination_insn((INSN *)next);
3927 break;
3928 case BIN(leave):
3929 piobj = iobj;
3930 /* fall through */
3931 default:
3932 next = NULL;
3933 break;
3934 }
3935 } while (next);
3936 }
3937
3938 if (piobj) {
3939 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3940 if (IS_INSN_ID(piobj, send) ||
3941 IS_INSN_ID(piobj, invokesuper)) {
3942 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3943 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3944 OPERAND_AT(piobj, 0) = (VALUE)ci;
3945 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3946 }
3947 }
3948 else {
3949 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3950 OPERAND_AT(piobj, 0) = (VALUE)ci;
3951 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3952 }
3953 }
3954 }
3955
3956 if (IS_INSN_ID(iobj, dup)) {
3957 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3958 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3959
3960 /*
3961 * dup
3962 * setlocal x, y
3963 * setlocal x, y
3964 * =>
3965 * dup
3966 * setlocal x, y
3967 */
3968 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3969 set2 = set1->next;
3970 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3971 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3972 ELEM_REMOVE(set1);
3973 ELEM_REMOVE(&iobj->link);
3974 }
3975 }
3976
3977 /*
3978 * dup
3979 * setlocal x, y
3980 * dup
3981 * setlocal x, y
3982 * =>
3983 * dup
3984 * setlocal x, y
3985 */
3986 else if (IS_NEXT_INSN_ID(set1, dup) &&
3987 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3988 set2 = set1->next->next;
3989 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3990 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3991 ELEM_REMOVE(set1->next);
3992 ELEM_REMOVE(set2);
3993 }
3994 }
3995 }
3996 }
3997
3998 /*
3999 * getlocal x, y
4000 * dup
4001 * setlocal x, y
4002 * =>
4003 * dup
4004 */
4005 if (IS_INSN_ID(iobj, getlocal)) {
4006 LINK_ELEMENT *niobj = &iobj->link;
4007 if (IS_NEXT_INSN_ID(niobj, dup)) {
4008 niobj = niobj->next;
4009 }
4010 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4011 LINK_ELEMENT *set1 = niobj->next;
4012 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4013 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4014 ELEM_REMOVE(set1);
4015 ELEM_REMOVE(niobj);
4016 }
4017 }
4018 }
4019
4020 /*
4021 * opt_invokebuiltin_delegate
4022 * trace
4023 * leave
4024 * =>
4025 * opt_invokebuiltin_delegate_leave
4026 * trace
4027 * leave
4028 */
4029 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4030 if (IS_TRACE(iobj->link.next)) {
4031 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4032 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4033 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4034 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4035 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4036 }
4037 }
4038 }
4039 }
4040
4041 /*
4042 * getblockparam
4043 * branchif / branchunless
4044 * =>
4045 * getblockparamproxy
4046 * branchif / branchunless
4047 */
4048 if (IS_INSN_ID(iobj, getblockparam)) {
4049 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4050 iobj->insn_id = BIN(getblockparamproxy);
4051 }
4052 }
4053
4054 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4055 LINK_ELEMENT *niobj = &iobj->link;
4056 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4057 niobj = niobj->next;
4058 LINK_ELEMENT *siobj;
4059 unsigned int set_flags = 0, unset_flags = 0;
4060
4061 /*
4062 * Eliminate hash allocation for f(*a, kw: 1)
4063 *
4064 * splatarray false
4065 * duphash
4066 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4067 * =>
4068 * splatarray false
4069 * putobject
4070 * send ARGS_SPLAT|KW_SPLAT
4071 */
4072 if (IS_NEXT_INSN_ID(niobj, send)) {
4073 siobj = niobj->next;
4074 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4075 unset_flags = VM_CALL_ARGS_BLOCKARG;
4076 }
4077 /*
4078 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4079 *
4080 * splatarray false
4081 * duphash
4082 * getlocal / getinstancevariable / getblockparamproxy
4083 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4084 * =>
4085 * splatarray false
4086 * putobject
4087 * getlocal / getinstancevariable / getblockparamproxy
4088 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4089 */
4090 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4091 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4092 siobj = niobj->next->next;
4093 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4094 }
4095
4096 if (set_flags) {
4097 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4098 unsigned int flags = vm_ci_flag(ci);
4099 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4100 ((INSN*)niobj)->insn_id = BIN(putobject);
4101 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4102
4103 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4104 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4105 RB_OBJ_WRITTEN(iseq, ci, nci);
4106 OPERAND_AT(siobj, 0) = (VALUE)nci;
4107 }
4108 }
4109 }
4110 }
4111
4112 return COMPILE_OK;
4113}
4114
4115static int
4116insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4117{
4118 if (insn_id == BIN(opt_neq)) {
4119 VALUE original_ci = iobj->operands[0];
4120 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4121 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4122 }
4123 else {
4124 iobj->insn_id = insn_id;
4125 iobj->operand_size = insn_len(insn_id) - 1;
4126 }
4127 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4128
4129 return COMPILE_OK;
4130}
4131
4132static int
4133iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4134{
4135 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4136 IS_INSN(iobj->link.next)) {
4137 /*
4138 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4139 */
4140 INSN *niobj = (INSN *)iobj->link.next;
4141 if (IS_INSN_ID(niobj, send)) {
4142 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4143 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4144 VALUE method = INT2FIX(0);
4145 switch (vm_ci_mid(ci)) {
4146 case idMax:
4147 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4148 break;
4149 case idMin:
4150 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4151 break;
4152 case idHash:
4153 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4154 break;
4155 }
4156
4157 if (method != INT2FIX(0)) {
4158 VALUE num = iobj->operands[0];
4159 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4160 ELEM_REMOVE(&niobj->link);
4161 return COMPILE_OK;
4162 }
4163 }
4164 }
4165 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4166 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4167 IS_NEXT_INSN_ID(&niobj->link, send)) {
4168 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4169 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4170 VALUE num = iobj->operands[0];
4171 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4172 ELEM_REMOVE(&iobj->link);
4173 ELEM_REMOVE(niobj->link.next);
4174 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4175 return COMPILE_OK;
4176 }
4177 }
4178 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4179 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4180 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4181 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4182 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4183 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4184 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4185 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4186 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4187 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4188 VALUE num = iobj->operands[0];
4189 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4190 // Remove the "send" insn.
4191 ELEM_REMOVE((niobj->link.next)->next);
4192 // Remove the modified insn from its original "newarray" position...
4193 ELEM_REMOVE(&iobj->link);
4194 // and insert it after the buffer insn.
4195 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4196 return COMPILE_OK;
4197 }
4198 }
4199
4200 // Break the "else if" chain since some prior checks abort after sub-ifs.
4201 // We already found "newarray". To match `[...].include?(arg)` we look for
4202 // the instruction(s) representing the argument followed by a "send".
4203 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4204 IS_INSN_ID(niobj, putobject) ||
4205 IS_INSN_ID(niobj, putself) ||
4206 IS_INSN_ID(niobj, getlocal) ||
4207 IS_INSN_ID(niobj, getinstancevariable)) &&
4208 IS_NEXT_INSN_ID(&niobj->link, send)) {
4209
4210 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4211 const struct rb_callinfo *ci;
4212 // Allow any number (0 or more) of simple method calls on the argument
4213 // (as in `[...].include?(arg.method1.method2)`.
4214 do {
4215 sendobj = sendobj->next;
4216 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4217 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4218
4219 // If this send is for .include? with one arg we can do our opt.
4220 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4221 VALUE num = iobj->operands[0];
4222 INSN *sendins = (INSN *)sendobj;
4223 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4224 // Remove the original "newarray" insn.
4225 ELEM_REMOVE(&iobj->link);
4226 return COMPILE_OK;
4227 }
4228 }
4229 }
4230
4231 /*
4232 * duparray [...]
4233 * some insn for the arg...
4234 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4235 * =>
4236 * arg insn...
4237 * opt_duparray_send [...], :include?, 1
4238 */
4239 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4240 INSN *niobj = (INSN *)iobj->link.next;
4241 if ((IS_INSN_ID(niobj, getlocal) ||
4242 IS_INSN_ID(niobj, getinstancevariable) ||
4243 IS_INSN_ID(niobj, putself)) &&
4244 IS_NEXT_INSN_ID(&niobj->link, send)) {
4245
4246 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4247 const struct rb_callinfo *ci;
4248 // Allow any number (0 or more) of simple method calls on the argument
4249 // (as in `[...].include?(arg.method1.method2)`.
4250 do {
4251 sendobj = sendobj->next;
4252 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4253 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4254
4255 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4256 // Move the array arg from duparray to opt_duparray_send.
4257 VALUE ary = iobj->operands[0];
4259
4260 INSN *sendins = (INSN *)sendobj;
4261 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4262
4263 // Remove the duparray insn.
4264 ELEM_REMOVE(&iobj->link);
4265 return COMPILE_OK;
4266 }
4267 }
4268 }
4269
4270
4271 if (IS_INSN_ID(iobj, send)) {
4272 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4273 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4274
4275#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4276 if (vm_ci_simple(ci)) {
4277 switch (vm_ci_argc(ci)) {
4278 case 0:
4279 switch (vm_ci_mid(ci)) {
4280 case idLength: SP_INSN(length); return COMPILE_OK;
4281 case idSize: SP_INSN(size); return COMPILE_OK;
4282 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4283 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4284 case idSucc: SP_INSN(succ); return COMPILE_OK;
4285 case idNot: SP_INSN(not); return COMPILE_OK;
4286 }
4287 break;
4288 case 1:
4289 switch (vm_ci_mid(ci)) {
4290 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4291 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4292 case idMULT: SP_INSN(mult); return COMPILE_OK;
4293 case idDIV: SP_INSN(div); return COMPILE_OK;
4294 case idMOD: SP_INSN(mod); return COMPILE_OK;
4295 case idEq: SP_INSN(eq); return COMPILE_OK;
4296 case idNeq: SP_INSN(neq); return COMPILE_OK;
4297 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4298 case idLT: SP_INSN(lt); return COMPILE_OK;
4299 case idLE: SP_INSN(le); return COMPILE_OK;
4300 case idGT: SP_INSN(gt); return COMPILE_OK;
4301 case idGE: SP_INSN(ge); return COMPILE_OK;
4302 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4303 case idAREF: SP_INSN(aref); return COMPILE_OK;
4304 case idAnd: SP_INSN(and); return COMPILE_OK;
4305 case idOr: SP_INSN(or); return COMPILE_OK;
4306 }
4307 break;
4308 case 2:
4309 switch (vm_ci_mid(ci)) {
4310 case idASET: SP_INSN(aset); return COMPILE_OK;
4311 }
4312 break;
4313 }
4314 }
4315
4316 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4317 iobj->insn_id = BIN(opt_send_without_block);
4318 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4319 }
4320 }
4321#undef SP_INSN
4322
4323 return COMPILE_OK;
4324}
4325
4326static inline int
4327tailcallable_p(rb_iseq_t *iseq)
4328{
4329 switch (ISEQ_BODY(iseq)->type) {
4330 case ISEQ_TYPE_TOP:
4331 case ISEQ_TYPE_EVAL:
4332 case ISEQ_TYPE_MAIN:
4333 /* not tail callable because cfp will be over popped */
4334 case ISEQ_TYPE_RESCUE:
4335 case ISEQ_TYPE_ENSURE:
4336 /* rescue block can't tail call because of errinfo */
4337 return FALSE;
4338 default:
4339 return TRUE;
4340 }
4341}
4342
4343static int
4344iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4345{
4346 LINK_ELEMENT *list;
4347 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4348 const int do_tailcallopt = tailcallable_p(iseq) &&
4349 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4350 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4351 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4352 int rescue_level = 0;
4353 int tailcallopt = do_tailcallopt;
4354
4355 list = FIRST_ELEMENT(anchor);
4356
4357 int do_block_optimization = 0;
4358 LABEL * block_loop_label = NULL;
4359
4360 // If we're optimizing a block
4361 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4362 do_block_optimization = 1;
4363
4364 // If the block starts with a nop and a label,
4365 // record the label so we can detect if it's a jump target
4366 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4367 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4368 block_loop_label = (LABEL *)le->next;
4369 }
4370 }
4371
4372 while (list) {
4373 if (IS_INSN(list)) {
4374 if (do_peepholeopt) {
4375 iseq_peephole_optimize(iseq, list, tailcallopt);
4376 }
4377 if (do_si) {
4378 iseq_specialized_instruction(iseq, (INSN *)list);
4379 }
4380 if (do_ou) {
4381 insn_operands_unification((INSN *)list);
4382 }
4383
4384 if (do_block_optimization) {
4385 INSN * item = (INSN *)list;
4386 // Give up if there is a throw
4387 if (IS_INSN_ID(item, throw)) {
4388 do_block_optimization = 0;
4389 }
4390 else {
4391 // If the instruction has a jump target, check if the
4392 // jump target is the block loop label
4393 const char *types = insn_op_types(item->insn_id);
4394 for (int j = 0; types[j]; j++) {
4395 if (types[j] == TS_OFFSET) {
4396 // If the jump target is equal to the block loop
4397 // label, then we can't do the optimization because
4398 // the leading `nop` instruction fires the block
4399 // entry tracepoint
4400 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4401 if (target == block_loop_label) {
4402 do_block_optimization = 0;
4403 }
4404 }
4405 }
4406 }
4407 }
4408 }
4409 if (IS_LABEL(list)) {
4410 switch (((LABEL *)list)->rescued) {
4411 case LABEL_RESCUE_BEG:
4412 rescue_level++;
4413 tailcallopt = FALSE;
4414 break;
4415 case LABEL_RESCUE_END:
4416 if (!--rescue_level) tailcallopt = do_tailcallopt;
4417 break;
4418 }
4419 }
4420 list = list->next;
4421 }
4422
4423 if (do_block_optimization) {
4424 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4425 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4426 ELEM_REMOVE(le);
4427 }
4428 }
4429 return COMPILE_OK;
4430}
4431
4432#if OPT_INSTRUCTIONS_UNIFICATION
4433static INSN *
4434new_unified_insn(rb_iseq_t *iseq,
4435 int insn_id, int size, LINK_ELEMENT *seq_list)
4436{
4437 INSN *iobj = 0;
4438 LINK_ELEMENT *list = seq_list;
4439 int i, argc = 0;
4440 VALUE *operands = 0, *ptr = 0;
4441
4442
4443 /* count argc */
4444 for (i = 0; i < size; i++) {
4445 iobj = (INSN *)list;
4446 argc += iobj->operand_size;
4447 list = list->next;
4448 }
4449
4450 if (argc > 0) {
4451 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4452 }
4453
4454 /* copy operands */
4455 list = seq_list;
4456 for (i = 0; i < size; i++) {
4457 iobj = (INSN *)list;
4458 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4459 ptr += iobj->operand_size;
4460 list = list->next;
4461 }
4462
4463 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4464}
4465#endif
4466
4467/*
4468 * This scheme can get more performance if do this optimize with
4469 * label address resolving.
4470 * It's future work (if compile time was bottle neck).
4471 */
4472static int
4473iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4474{
4475#if OPT_INSTRUCTIONS_UNIFICATION
4476 LINK_ELEMENT *list;
4477 INSN *iobj, *niobj;
4478 int id, k;
4479 intptr_t j;
4480
4481 list = FIRST_ELEMENT(anchor);
4482 while (list) {
4483 if (IS_INSN(list)) {
4484 iobj = (INSN *)list;
4485 id = iobj->insn_id;
4486 if (unified_insns_data[id] != 0) {
4487 const int *const *entry = unified_insns_data[id];
4488 for (j = 1; j < (intptr_t)entry[0]; j++) {
4489 const int *unified = entry[j];
4490 LINK_ELEMENT *li = list->next;
4491 for (k = 2; k < unified[1]; k++) {
4492 if (!IS_INSN(li) ||
4493 ((INSN *)li)->insn_id != unified[k]) {
4494 goto miss;
4495 }
4496 li = li->next;
4497 }
4498 /* matched */
4499 niobj =
4500 new_unified_insn(iseq, unified[0], unified[1] - 1,
4501 list);
4502
4503 /* insert to list */
4504 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4505 niobj->link.next = li;
4506 if (li) {
4507 li->prev = (LINK_ELEMENT *)niobj;
4508 }
4509
4510 list->prev->next = (LINK_ELEMENT *)niobj;
4511 list = (LINK_ELEMENT *)niobj;
4512 break;
4513 miss:;
4514 }
4515 }
4516 }
4517 list = list->next;
4518 }
4519#endif
4520 return COMPILE_OK;
4521}
4522
4523static int
4524all_string_result_p(const NODE *node)
4525{
4526 if (!node) return FALSE;
4527 switch (nd_type(node)) {
4528 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4529 return TRUE;
4530 case NODE_IF: case NODE_UNLESS:
4531 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4532 if (all_string_result_p(RNODE_IF(node)->nd_body))
4533 return all_string_result_p(RNODE_IF(node)->nd_else);
4534 return FALSE;
4535 case NODE_AND: case NODE_OR:
4536 if (!RNODE_AND(node)->nd_2nd)
4537 return all_string_result_p(RNODE_AND(node)->nd_1st);
4538 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4539 return FALSE;
4540 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4541 default:
4542 return FALSE;
4543 }
4544}
4545
4547 rb_iseq_t *const iseq;
4548 LINK_ANCHOR *const ret;
4549 VALUE lit;
4550 const NODE *lit_node;
4551 int cnt;
4552 int dregx;
4553};
4554
4555static int
4556append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4557{
4558 VALUE s = rb_str_new_mutable_parser_string(str);
4559 if (args->dregx) {
4560 VALUE error = rb_reg_check_preprocess(s);
4561 if (!NIL_P(error)) {
4562 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4563 return COMPILE_NG;
4564 }
4565 }
4566 if (NIL_P(args->lit)) {
4567 args->lit = s;
4568 args->lit_node = node;
4569 }
4570 else {
4571 rb_str_buf_append(args->lit, s);
4572 }
4573 return COMPILE_OK;
4574}
4575
4576static void
4577flush_dstr_fragment(struct dstr_ctxt *args)
4578{
4579 if (!NIL_P(args->lit)) {
4580 rb_iseq_t *iseq = args->iseq;
4581 VALUE lit = args->lit;
4582 args->lit = Qnil;
4583 lit = rb_fstring(lit);
4584 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4585 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4586 args->cnt++;
4587 }
4588}
4589
4590static int
4591compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4592{
4593 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4594 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4595
4596 if (str) {
4597 CHECK(append_dstr_fragment(args, node, str));
4598 }
4599
4600 while (list) {
4601 const NODE *const head = list->nd_head;
4602 if (nd_type_p(head, NODE_STR)) {
4603 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4604 }
4605 else if (nd_type_p(head, NODE_DSTR)) {
4606 CHECK(compile_dstr_fragments_0(args, head));
4607 }
4608 else {
4609 flush_dstr_fragment(args);
4610 rb_iseq_t *iseq = args->iseq;
4611 CHECK(COMPILE(args->ret, "each string", head));
4612 args->cnt++;
4613 }
4614 list = (struct RNode_LIST *)list->nd_next;
4615 }
4616 return COMPILE_OK;
4617}
4618
4619static int
4620compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4621{
4622 struct dstr_ctxt args = {
4623 .iseq = iseq, .ret = ret,
4624 .lit = Qnil, .lit_node = NULL,
4625 .cnt = 0, .dregx = dregx,
4626 };
4627 CHECK(compile_dstr_fragments_0(&args, node));
4628 flush_dstr_fragment(&args);
4629
4630 *cntp = args.cnt;
4631
4632 return COMPILE_OK;
4633}
4634
4635static int
4636compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4637{
4638 while (node && nd_type_p(node, NODE_BLOCK)) {
4639 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4640 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4641 node = RNODE_BLOCK(node)->nd_next;
4642 }
4643 if (node) {
4644 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4645 }
4646 return COMPILE_OK;
4647}
4648
4649static int
4650compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4651{
4652 int cnt;
4653 if (!RNODE_DSTR(node)->nd_next) {
4654 VALUE lit = rb_node_dstr_string_val(node);
4655 ADD_INSN1(ret, node, putstring, lit);
4656 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4657 }
4658 else {
4659 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4660 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4661 }
4662 return COMPILE_OK;
4663}
4664
4665static int
4666compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4667{
4668 int cnt;
4669 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4670
4671 if (!RNODE_DREGX(node)->nd_next) {
4672 if (!popped) {
4673 VALUE src = rb_node_dregx_string_val(node);
4674 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4675 ADD_INSN1(ret, node, putobject, match);
4676 RB_OBJ_WRITTEN(iseq, Qundef, match);
4677 }
4678 return COMPILE_OK;
4679 }
4680
4681 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4682 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4683
4684 if (popped) {
4685 ADD_INSN(ret, node, pop);
4686 }
4687
4688 return COMPILE_OK;
4689}
4690
4691static int
4692compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4693 LABEL *then_label, LABEL *else_label)
4694{
4695 const int line = nd_line(node);
4696 LABEL *lend = NEW_LABEL(line);
4697 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4698 + VM_SVAR_FLIPFLOP_START;
4699 VALUE key = INT2FIX(cnt);
4700
4701 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4702 ADD_INSNL(ret, node, branchif, lend);
4703
4704 /* *flip == 0 */
4705 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4706 ADD_INSNL(ret, node, branchunless, else_label);
4707 ADD_INSN1(ret, node, putobject, Qtrue);
4708 ADD_INSN1(ret, node, setspecial, key);
4709 if (!again) {
4710 ADD_INSNL(ret, node, jump, then_label);
4711 }
4712
4713 /* *flip == 1 */
4714 ADD_LABEL(ret, lend);
4715 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4716 ADD_INSNL(ret, node, branchunless, then_label);
4717 ADD_INSN1(ret, node, putobject, Qfalse);
4718 ADD_INSN1(ret, node, setspecial, key);
4719 ADD_INSNL(ret, node, jump, then_label);
4720
4721 return COMPILE_OK;
4722}
4723
4724static int
4725compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4726 LABEL *then_label, LABEL *else_label);
4727
4728#define COMPILE_SINGLE 2
4729static int
4730compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4731 LABEL *then_label, LABEL *else_label)
4732{
4733 DECL_ANCHOR(seq);
4734 INIT_ANCHOR(seq);
4735 LABEL *label = NEW_LABEL(nd_line(cond));
4736 if (!then_label) then_label = label;
4737 else if (!else_label) else_label = label;
4738
4739 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4740
4741 if (LIST_INSN_SIZE_ONE(seq)) {
4742 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4743 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4744 return COMPILE_OK;
4745 }
4746 if (!label->refcnt) {
4747 return COMPILE_SINGLE;
4748 }
4749 ADD_LABEL(seq, label);
4750 ADD_SEQ(ret, seq);
4751 return COMPILE_OK;
4752}
4753
4754static int
4755compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4756 LABEL *then_label, LABEL *else_label)
4757{
4758 int ok;
4759 DECL_ANCHOR(ignore);
4760
4761 again:
4762 switch (nd_type(cond)) {
4763 case NODE_AND:
4764 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4765 cond = RNODE_AND(cond)->nd_2nd;
4766 if (ok == COMPILE_SINGLE) {
4767 INIT_ANCHOR(ignore);
4768 ret = ignore;
4769 then_label = NEW_LABEL(nd_line(cond));
4770 }
4771 goto again;
4772 case NODE_OR:
4773 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4774 cond = RNODE_OR(cond)->nd_2nd;
4775 if (ok == COMPILE_SINGLE) {
4776 INIT_ANCHOR(ignore);
4777 ret = ignore;
4778 else_label = NEW_LABEL(nd_line(cond));
4779 }
4780 goto again;
4781 case NODE_SYM:
4782 case NODE_LINE:
4783 case NODE_FILE:
4784 case NODE_ENCODING:
4785 case NODE_INTEGER: /* NODE_INTEGER is always true */
4786 case NODE_FLOAT: /* NODE_FLOAT is always true */
4787 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4788 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4789 case NODE_TRUE:
4790 case NODE_STR:
4791 case NODE_REGX:
4792 case NODE_ZLIST:
4793 case NODE_LAMBDA:
4794 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4795 ADD_INSNL(ret, cond, jump, then_label);
4796 return COMPILE_OK;
4797 case NODE_FALSE:
4798 case NODE_NIL:
4799 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4800 ADD_INSNL(ret, cond, jump, else_label);
4801 return COMPILE_OK;
4802 case NODE_LIST:
4803 case NODE_ARGSCAT:
4804 case NODE_DREGX:
4805 case NODE_DSTR:
4806 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4807 ADD_INSNL(ret, cond, jump, then_label);
4808 return COMPILE_OK;
4809 case NODE_FLIP2:
4810 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4811 return COMPILE_OK;
4812 case NODE_FLIP3:
4813 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4814 return COMPILE_OK;
4815 case NODE_DEFINED:
4816 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4817 break;
4818 default:
4819 {
4820 DECL_ANCHOR(cond_seq);
4821 INIT_ANCHOR(cond_seq);
4822
4823 CHECK(COMPILE(cond_seq, "branch condition", cond));
4824
4825 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4826 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4827 if (insn->insn_id == BIN(putobject)) {
4828 if (RTEST(insn->operands[0])) {
4829 ADD_INSNL(ret, cond, jump, then_label);
4830 // maybe unreachable
4831 return COMPILE_OK;
4832 }
4833 else {
4834 ADD_INSNL(ret, cond, jump, else_label);
4835 return COMPILE_OK;
4836 }
4837 }
4838 }
4839 ADD_SEQ(ret, cond_seq);
4840 }
4841 break;
4842 }
4843
4844 ADD_INSNL(ret, cond, branchunless, else_label);
4845 ADD_INSNL(ret, cond, jump, then_label);
4846 return COMPILE_OK;
4847}
4848
4849#define HASH_BRACE 1
4850
4851static int
4852keyword_node_p(const NODE *const node)
4853{
4854 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4855}
4856
4857static VALUE
4858get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4859{
4860 switch (nd_type(node)) {
4861 case NODE_SYM:
4862 return rb_node_sym_string_val(node);
4863 default:
4864 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4865 }
4866}
4867
4868static VALUE
4869node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4870{
4871 NODE *node = node_hash->nd_head;
4872 VALUE hash = rb_hash_new();
4873 VALUE ary = rb_ary_new();
4874
4875 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4876 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4877 VALUE idx = rb_hash_aref(hash, key);
4878 if (!NIL_P(idx)) {
4879 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4880 (*count_ptr)--;
4881 }
4882 rb_hash_aset(hash, key, INT2FIX(i));
4883 rb_ary_store(ary, i, Qtrue);
4884 (*count_ptr)++;
4885 }
4886
4887 return ary;
4888}
4889
4890static int
4891compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4892 const NODE *const root_node,
4893 struct rb_callinfo_kwarg **const kw_arg_ptr,
4894 unsigned int *flag)
4895{
4896 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4897 RUBY_ASSERT(kw_arg_ptr != NULL);
4898 RUBY_ASSERT(flag != NULL);
4899
4900 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4901 const NODE *node = RNODE_HASH(root_node)->nd_head;
4902 int seen_nodes = 0;
4903
4904 while (node) {
4905 const NODE *key_node = RNODE_LIST(node)->nd_head;
4906 seen_nodes++;
4907
4908 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4909 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4910 /* can be keywords */
4911 }
4912 else {
4913 if (flag) {
4914 *flag |= VM_CALL_KW_SPLAT;
4915 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4916 /* A new hash will be created for the keyword arguments
4917 * in this case, so mark the method as passing mutable
4918 * keyword splat.
4919 */
4920 *flag |= VM_CALL_KW_SPLAT_MUT;
4921 }
4922 }
4923 return FALSE;
4924 }
4925 node = RNODE_LIST(node)->nd_next; /* skip value node */
4926 node = RNODE_LIST(node)->nd_next;
4927 }
4928
4929 /* may be keywords */
4930 node = RNODE_HASH(root_node)->nd_head;
4931 {
4932 int len = 0;
4933 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4934 struct rb_callinfo_kwarg *kw_arg =
4935 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4936 VALUE *keywords = kw_arg->keywords;
4937 int i = 0;
4938 int j = 0;
4939 kw_arg->references = 0;
4940 kw_arg->keyword_len = len;
4941
4942 *kw_arg_ptr = kw_arg;
4943
4944 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4945 const NODE *key_node = RNODE_LIST(node)->nd_head;
4946 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4947 int popped = TRUE;
4948 if (rb_ary_entry(key_index, i)) {
4949 keywords[j] = get_symbol_value(iseq, key_node);
4950 j++;
4951 popped = FALSE;
4952 }
4953 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4954 }
4955 RUBY_ASSERT(j == len);
4956 return TRUE;
4957 }
4958 }
4959 return FALSE;
4960}
4961
4962static int
4963compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4964{
4965 int len = 0;
4966
4967 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4968 if (CPDEBUG > 0) {
4969 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4970 }
4971
4972 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4973 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4974 }
4975 else {
4976 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4977 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4978 }
4979 }
4980
4981 return len;
4982}
4983
4984static inline bool
4985frozen_string_literal_p(const rb_iseq_t *iseq)
4986{
4987 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4988}
4989
4990static inline bool
4991static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
4992{
4993 switch (nd_type(node)) {
4994 case NODE_SYM:
4995 case NODE_REGX:
4996 case NODE_LINE:
4997 case NODE_ENCODING:
4998 case NODE_INTEGER:
4999 case NODE_FLOAT:
5000 case NODE_RATIONAL:
5001 case NODE_IMAGINARY:
5002 case NODE_NIL:
5003 case NODE_TRUE:
5004 case NODE_FALSE:
5005 return TRUE;
5006 case NODE_STR:
5007 case NODE_FILE:
5008 return hash_key || frozen_string_literal_p(iseq);
5009 default:
5010 return FALSE;
5011 }
5012}
5013
5014static inline VALUE
5015static_literal_value(const NODE *node, rb_iseq_t *iseq)
5016{
5017 switch (nd_type(node)) {
5018 case NODE_INTEGER:
5019 return rb_node_integer_literal_val(node);
5020 case NODE_FLOAT:
5021 return rb_node_float_literal_val(node);
5022 case NODE_RATIONAL:
5023 return rb_node_rational_literal_val(node);
5024 case NODE_IMAGINARY:
5025 return rb_node_imaginary_literal_val(node);
5026 case NODE_NIL:
5027 return Qnil;
5028 case NODE_TRUE:
5029 return Qtrue;
5030 case NODE_FALSE:
5031 return Qfalse;
5032 case NODE_SYM:
5033 return rb_node_sym_string_val(node);
5034 case NODE_REGX:
5035 return rb_node_regx_string_val(node);
5036 case NODE_LINE:
5037 return rb_node_line_lineno_val(node);
5038 case NODE_ENCODING:
5039 return rb_node_encoding_val(node);
5040 case NODE_FILE:
5041 case NODE_STR:
5042 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5043 VALUE lit = get_string_value(node);
5044 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5045 }
5046 else {
5047 return get_string_value(node);
5048 }
5049 default:
5050 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5051 }
5052}
5053
5054static int
5055compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5056{
5057 const NODE *line_node = node;
5058
5059 if (nd_type_p(node, NODE_ZLIST)) {
5060 if (!popped) {
5061 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5062 }
5063 return 0;
5064 }
5065
5066 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5067
5068 if (popped) {
5069 for (; node; node = RNODE_LIST(node)->nd_next) {
5070 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5071 }
5072 return 1;
5073 }
5074
5075 /* Compilation of an array literal.
5076 * The following code is essentially the same as:
5077 *
5078 * for (int count = 0; node; count++; node->nd_next) {
5079 * compile(node->nd_head);
5080 * }
5081 * ADD_INSN(newarray, count);
5082 *
5083 * However, there are three points.
5084 *
5085 * - The code above causes stack overflow for a big string literal.
5086 * The following limits the stack length up to max_stack_len.
5087 *
5088 * [x1,x2,...,x10000] =>
5089 * push x1 ; push x2 ; ...; push x256; newarray 256;
5090 * push x257; push x258; ...; push x512; pushtoarray 256;
5091 * push x513; push x514; ...; push x768; pushtoarray 256;
5092 * ...
5093 *
5094 * - Long subarray can be optimized by pre-allocating a hidden array.
5095 *
5096 * [1,2,3,...,100] =>
5097 * duparray [1,2,3,...,100]
5098 *
5099 * [x, 1,2,3,...,100, z] =>
5100 * push x; newarray 1;
5101 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5102 * push z; pushtoarray 1;
5103 *
5104 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5105 * to only push it onto the array if it is not empty
5106 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5107 *
5108 * [1,2,3,**kw] =>
5109 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5110 */
5111
5112 const int max_stack_len = 0x100;
5113 const int min_tmp_ary_len = 0x40;
5114 int stack_len = 0;
5115
5116 /* Either create a new array, or push to the existing array */
5117#define FLUSH_CHUNK \
5118 if (stack_len) { \
5119 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5120 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5121 first_chunk = FALSE; \
5122 stack_len = 0; \
5123 }
5124
5125 while (node) {
5126 int count = 1;
5127
5128 /* pre-allocation check (this branch can be omittable) */
5129 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5130 /* count the elements that are optimizable */
5131 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5132 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5133 count++;
5134
5135 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5136 /* The literal contains only optimizable elements, or the subarray is long enough */
5137 VALUE ary = rb_ary_hidden_new(count);
5138
5139 /* Create a hidden array */
5140 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5141 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5142 OBJ_FREEZE(ary);
5143
5144 /* Emit optimized code */
5145 FLUSH_CHUNK;
5146 if (first_chunk) {
5147 ADD_INSN1(ret, line_node, duparray, ary);
5148 first_chunk = FALSE;
5149 }
5150 else {
5151 ADD_INSN1(ret, line_node, putobject, ary);
5152 ADD_INSN(ret, line_node, concattoarray);
5153 }
5154 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5155 }
5156 }
5157
5158 /* Base case: Compile "count" elements */
5159 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5160 if (CPDEBUG > 0) {
5161 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5162 }
5163
5164 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5165 /* Create array or push existing non-keyword elements onto array */
5166 if (stack_len == 0 && first_chunk) {
5167 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5168 }
5169 else {
5170 FLUSH_CHUNK;
5171 }
5172 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5173 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5174 return 1;
5175 }
5176 else {
5177 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5178 stack_len++;
5179 }
5180
5181 /* If there are many pushed elements, flush them to avoid stack overflow */
5182 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5183 }
5184 }
5185
5186 FLUSH_CHUNK;
5187#undef FLUSH_CHUNK
5188 return 1;
5189}
5190
5191static inline int
5192static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5193{
5194 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);
5195}
5196
5197static int
5198compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5199{
5200 const NODE *line_node = node;
5201
5202 node = RNODE_HASH(node)->nd_head;
5203
5204 if (!node || nd_type_p(node, NODE_ZLIST)) {
5205 if (!popped) {
5206 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5207 }
5208 return 0;
5209 }
5210
5211 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5212
5213 if (popped) {
5214 for (; node; node = RNODE_LIST(node)->nd_next) {
5215 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5216 }
5217 return 1;
5218 }
5219
5220 /* Compilation of a hash literal (or keyword arguments).
5221 * This is very similar to compile_array, but there are some differences:
5222 *
5223 * - It contains key-value pairs. So we need to take every two elements.
5224 * We can assume that the length is always even.
5225 *
5226 * - Merging is done by a method call (id_core_hash_merge_ptr).
5227 * Sometimes we need to insert the receiver, so "anchor" is needed.
5228 * In addition, a method call is much slower than concatarray.
5229 * So it pays only when the subsequence is really long.
5230 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5231 *
5232 * - We need to handle keyword splat: **kw.
5233 * For **kw, the key part (node->nd_head) is NULL, and the value part
5234 * (node->nd_next->nd_head) is "kw".
5235 * The code is a bit difficult to avoid hash allocation for **{}.
5236 */
5237
5238 const int max_stack_len = 0x100;
5239 const int min_tmp_hash_len = 0x800;
5240 int stack_len = 0;
5241 int first_chunk = 1;
5242 DECL_ANCHOR(anchor);
5243 INIT_ANCHOR(anchor);
5244
5245 /* Convert pushed elements to a hash, and merge if needed */
5246#define FLUSH_CHUNK() \
5247 if (stack_len) { \
5248 if (first_chunk) { \
5249 APPEND_LIST(ret, anchor); \
5250 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5251 } \
5252 else { \
5253 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5254 ADD_INSN(ret, line_node, swap); \
5255 APPEND_LIST(ret, anchor); \
5256 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5257 } \
5258 INIT_ANCHOR(anchor); \
5259 first_chunk = stack_len = 0; \
5260 }
5261
5262 while (node) {
5263 int count = 1;
5264
5265 /* pre-allocation check (this branch can be omittable) */
5266 if (static_literal_node_pair_p(node, iseq)) {
5267 /* count the elements that are optimizable */
5268 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5269 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5270 count++;
5271
5272 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5273 /* The literal contains only optimizable elements, or the subsequence is long enough */
5274 VALUE ary = rb_ary_hidden_new(count);
5275
5276 /* Create a hidden hash */
5277 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5278 VALUE elem[2];
5279 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5280 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5281 rb_ary_cat(ary, elem, 2);
5282 }
5283 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5284 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5285 hash = rb_obj_hide(hash);
5286 OBJ_FREEZE(hash);
5287
5288 /* Emit optimized code */
5289 FLUSH_CHUNK();
5290 if (first_chunk) {
5291 ADD_INSN1(ret, line_node, duphash, hash);
5292 first_chunk = 0;
5293 }
5294 else {
5295 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5296 ADD_INSN(ret, line_node, swap);
5297
5298 ADD_INSN1(ret, line_node, putobject, hash);
5299
5300 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5301 }
5302 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5303 }
5304 }
5305
5306 /* Base case: Compile "count" elements */
5307 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5308
5309 if (CPDEBUG > 0) {
5310 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5311 }
5312
5313 if (RNODE_LIST(node)->nd_head) {
5314 /* Normal key-value pair */
5315 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5316 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5317 stack_len += 2;
5318
5319 /* If there are many pushed elements, flush them to avoid stack overflow */
5320 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5321 }
5322 else {
5323 /* kwsplat case: foo(..., **kw, ...) */
5324 FLUSH_CHUNK();
5325
5326 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5327 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5328 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5329 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5330 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5331
5332 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5333 if (empty_kw) {
5334 if (only_kw && method_call_keywords) {
5335 /* **{} appears at the only keyword argument in method call,
5336 * so it won't be modified.
5337 * kw is a special NODE_LIT that contains a special empty hash,
5338 * so this emits: putobject {}.
5339 * This is only done for method calls and not for literal hashes,
5340 * because literal hashes should always result in a new hash.
5341 */
5342 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5343 }
5344 else if (first_kw) {
5345 /* **{} appears as the first keyword argument, so it may be modified.
5346 * We need to create a fresh hash object.
5347 */
5348 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5349 }
5350 /* Any empty keyword splats that are not the first can be ignored.
5351 * since merging an empty hash into the existing hash is the same
5352 * as not merging it. */
5353 }
5354 else {
5355 if (only_kw && method_call_keywords) {
5356 /* **kw is only keyword argument in method call.
5357 * Use directly. This will be not be flagged as mutable.
5358 * This is only done for method calls and not for literal hashes,
5359 * because literal hashes should always result in a new hash.
5360 */
5361 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5362 }
5363 else {
5364 /* There is more than one keyword argument, or this is not a method
5365 * call. In that case, we need to add an empty hash (if first keyword),
5366 * or merge the hash to the accumulated hash (if not the first keyword).
5367 */
5368 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5369 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5370 else ADD_INSN(ret, line_node, swap);
5371
5372 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5373
5374 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5375 }
5376 }
5377
5378 first_chunk = 0;
5379 }
5380 }
5381 }
5382
5383 FLUSH_CHUNK();
5384#undef FLUSH_CHUNK
5385 return 1;
5386}
5387
5388VALUE
5389rb_node_case_when_optimizable_literal(const NODE *const node)
5390{
5391 switch (nd_type(node)) {
5392 case NODE_INTEGER:
5393 return rb_node_integer_literal_val(node);
5394 case NODE_FLOAT: {
5395 VALUE v = rb_node_float_literal_val(node);
5396 double ival;
5397
5398 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5399 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5400 }
5401 return v;
5402 }
5403 case NODE_RATIONAL:
5404 case NODE_IMAGINARY:
5405 return Qundef;
5406 case NODE_NIL:
5407 return Qnil;
5408 case NODE_TRUE:
5409 return Qtrue;
5410 case NODE_FALSE:
5411 return Qfalse;
5412 case NODE_SYM:
5413 return rb_node_sym_string_val(node);
5414 case NODE_LINE:
5415 return rb_node_line_lineno_val(node);
5416 case NODE_STR:
5417 return rb_node_str_string_val(node);
5418 case NODE_FILE:
5419 return rb_node_file_path_val(node);
5420 }
5421 return Qundef;
5422}
5423
5424static int
5425when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5426 LABEL *l1, int only_special_literals, VALUE literals)
5427{
5428 while (vals) {
5429 const NODE *val = RNODE_LIST(vals)->nd_head;
5430 VALUE lit = rb_node_case_when_optimizable_literal(val);
5431
5432 if (UNDEF_P(lit)) {
5433 only_special_literals = 0;
5434 }
5435 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5436 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5437 }
5438
5439 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5440 debugp_param("nd_lit", get_string_value(val));
5441 lit = get_string_value(val);
5442 ADD_INSN1(cond_seq, val, putobject, lit);
5443 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5444 }
5445 else {
5446 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5447 }
5448
5449 // Emit pattern === target
5450 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5451 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5452 ADD_INSNL(cond_seq, val, branchif, l1);
5453 vals = RNODE_LIST(vals)->nd_next;
5454 }
5455 return only_special_literals;
5456}
5457
5458static int
5459when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5460 LABEL *l1, int only_special_literals, VALUE literals)
5461{
5462 const NODE *line_node = vals;
5463
5464 switch (nd_type(vals)) {
5465 case NODE_LIST:
5466 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5467 return COMPILE_NG;
5468 break;
5469 case NODE_SPLAT:
5470 ADD_INSN (cond_seq, line_node, dup);
5471 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5472 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5473 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5474 ADD_INSNL(cond_seq, line_node, branchif, l1);
5475 break;
5476 case NODE_ARGSCAT:
5477 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5478 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5479 break;
5480 case NODE_ARGSPUSH:
5481 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5482 ADD_INSN (cond_seq, line_node, dup);
5483 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5484 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5485 ADD_INSNL(cond_seq, line_node, branchif, l1);
5486 break;
5487 default:
5488 ADD_INSN (cond_seq, line_node, dup);
5489 CHECK(COMPILE(cond_seq, "when val", vals));
5490 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5491 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5492 ADD_INSNL(cond_seq, line_node, branchif, l1);
5493 break;
5494 }
5495 return COMPILE_OK;
5496}
5497
5498/* Multiple Assignment Handling
5499 *
5500 * In order to handle evaluation of multiple assignment such that the left hand side
5501 * is evaluated before the right hand side, we need to process the left hand side
5502 * and see if there are any attributes that need to be assigned, or constants set
5503 * on explicit objects. If so, we add instructions to evaluate the receiver of
5504 * any assigned attributes or constants before we process the right hand side.
5505 *
5506 * For a multiple assignment such as:
5507 *
5508 * l1.m1, l2[0] = r3, r4
5509 *
5510 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5511 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5512 * On the VM stack, this looks like:
5513 *
5514 * self # putself
5515 * l1 # send
5516 * l1, self # putself
5517 * l1, l2 # send
5518 * l1, l2, 0 # putobject 0
5519 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5520 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5521 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5522 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5523 * l1, l2, 0, [r3, r4], r4, m1= # send
5524 * l1, l2, 0, [r3, r4], r4 # pop
5525 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5526 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5527 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5528 * l1, l2, 0, [r3, r4], r4, []= # send
5529 * l1, l2, 0, [r3, r4], r4 # pop
5530 * l1, l2, 0, [r3, r4] # pop
5531 * [r3, r4], l2, 0, [r3, r4] # setn 3
5532 * [r3, r4], l2, 0 # pop
5533 * [r3, r4], l2 # pop
5534 * [r3, r4] # pop
5535 *
5536 * This is made more complex when you have to handle splats, post args,
5537 * and arbitrary levels of nesting. You need to keep track of the total
5538 * number of attributes to set, and for each attribute, how many entries
5539 * are on the stack before the final attribute, in order to correctly
5540 * calculate the topn value to use to get the receiver of the attribute
5541 * setter method.
5542 *
5543 * A brief description of the VM stack for simple multiple assignment
5544 * with no splat (rhs_array will not be present if the return value of
5545 * the multiple assignment is not needed):
5546 *
5547 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5548 *
5549 * For multiple assignment with splats, while processing the part before
5550 * the splat (splat+post here is an array of the splat and the post arguments):
5551 *
5552 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5553 *
5554 * When processing the splat and post arguments:
5555 *
5556 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5557 *
5558 * When processing nested multiple assignment, existing values on the stack
5559 * are kept. So for:
5560 *
5561 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5562 *
5563 * The stack layout would be the following before processing the nested
5564 * multiple assignment:
5565 *
5566 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5567 *
5568 * In order to handle this correctly, we need to keep track of the nesting
5569 * level for each attribute assignment, as well as the attribute number
5570 * (left hand side attributes are processed left to right) and number of
5571 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5572 * this information.
5573 *
5574 * We also need to track information for the entire multiple assignment, such
5575 * as the total number of arguments, and the current nesting level, to
5576 * handle both nested multiple assignment as well as cases where the
5577 * rhs is not needed. We also need to keep track of all attribute
5578 * assignments in this, which we do using a linked listed. struct masgn_state
5579 * tracks this information.
5580 */
5581
5583 INSN *before_insn;
5584 struct masgn_lhs_node *next;
5585 const NODE *line_node;
5586 int argn;
5587 int num_args;
5588 int lhs_pos;
5589};
5590
5592 struct masgn_lhs_node *first_memo;
5593 struct masgn_lhs_node *last_memo;
5594 int lhs_level;
5595 int num_args;
5596 bool nested;
5597};
5598
5599static int
5600add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5601{
5602 if (!state) {
5603 rb_bug("no masgn_state");
5604 }
5605
5606 struct masgn_lhs_node *memo;
5607 memo = malloc(sizeof(struct masgn_lhs_node));
5608 if (!memo) {
5609 return COMPILE_NG;
5610 }
5611
5612 memo->before_insn = before_insn;
5613 memo->line_node = line_node;
5614 memo->argn = state->num_args + 1;
5615 memo->num_args = argc;
5616 state->num_args += argc;
5617 memo->lhs_pos = lhs_pos;
5618 memo->next = NULL;
5619 if (!state->first_memo) {
5620 state->first_memo = memo;
5621 }
5622 else {
5623 state->last_memo->next = memo;
5624 }
5625 state->last_memo = memo;
5626
5627 return COMPILE_OK;
5628}
5629
5630static 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);
5631
5632static int
5633compile_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)
5634{
5635 switch (nd_type(node)) {
5636 case NODE_ATTRASGN: {
5637 INSN *iobj;
5638 const NODE *line_node = node;
5639
5640 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5641
5642 bool safenav_call = false;
5643 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5644 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5645 ASSUME(iobj);
5646 ELEM_REMOVE(insn_element);
5647 if (!IS_INSN_ID(iobj, send)) {
5648 safenav_call = true;
5649 iobj = (INSN *)get_prev_insn(iobj);
5650 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5651 }
5652 (pre->last = iobj->link.prev)->next = 0;
5653
5654 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5655 int argc = vm_ci_argc(ci) + 1;
5656 ci = ci_argc_set(iseq, ci, argc);
5657 OPERAND_AT(iobj, 0) = (VALUE)ci;
5658 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5659
5660 if (argc == 1) {
5661 ADD_INSN(lhs, line_node, swap);
5662 }
5663 else {
5664 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5665 }
5666
5667 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5668 return COMPILE_NG;
5669 }
5670
5671 iobj->link.prev = lhs->last;
5672 lhs->last->next = &iobj->link;
5673 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5674 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5675 int argc = vm_ci_argc(ci);
5676 bool dupsplat = false;
5677 ci = ci_argc_set(iseq, ci, argc - 1);
5678 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5679 /* Given h[*a], _ = ary
5680 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5681 * `a` must be dupped, because it will be appended with ary[0]
5682 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5683 */
5684 dupsplat = true;
5685 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5686 }
5687 OPERAND_AT(iobj, 0) = (VALUE)ci;
5688 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5689
5690 /* Given: h[*a], h[*b, 1] = ary
5691 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5692 * so this uses splatarray true on a to dup it before using pushtoarray
5693 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5694 * so you can use pushtoarray directly
5695 */
5696 int line_no = nd_line(line_node);
5697 int node_id = nd_node_id(line_node);
5698
5699 if (dupsplat) {
5700 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5701 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5702 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5703 }
5704 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5705 }
5706 if (!safenav_call) {
5707 ADD_INSN(lhs, line_node, pop);
5708 if (argc != 1) {
5709 ADD_INSN(lhs, line_node, pop);
5710 }
5711 }
5712 for (int i=0; i < argc; i++) {
5713 ADD_INSN(post, line_node, pop);
5714 }
5715 break;
5716 }
5717 case NODE_MASGN: {
5718 DECL_ANCHOR(nest_rhs);
5719 INIT_ANCHOR(nest_rhs);
5720 DECL_ANCHOR(nest_lhs);
5721 INIT_ANCHOR(nest_lhs);
5722
5723 int prev_level = state->lhs_level;
5724 bool prev_nested = state->nested;
5725 state->nested = 1;
5726 state->lhs_level = lhs_pos - 1;
5727 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5728 state->lhs_level = prev_level;
5729 state->nested = prev_nested;
5730
5731 ADD_SEQ(lhs, nest_rhs);
5732 ADD_SEQ(lhs, nest_lhs);
5733 break;
5734 }
5735 case NODE_CDECL:
5736 if (!RNODE_CDECL(node)->nd_vid) {
5737 /* Special handling only needed for expr::C, not for C */
5738 INSN *iobj;
5739
5740 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5741
5742 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5743 iobj = (INSN *)insn_element; /* setconstant insn */
5744 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5745 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5746 ELEM_REMOVE(insn_element);
5747 pre->last = iobj->link.prev;
5748 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5749
5750 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5751 return COMPILE_NG;
5752 }
5753
5754 ADD_INSN(post, node, pop);
5755 break;
5756 }
5757 /* Fallthrough */
5758 default: {
5759 DECL_ANCHOR(anchor);
5760 INIT_ANCHOR(anchor);
5761 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5762 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5763 ADD_SEQ(lhs, anchor);
5764 }
5765 }
5766
5767 return COMPILE_OK;
5768}
5769
5770static int
5771compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5772{
5773 if (lhsn) {
5774 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5775 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5776 }
5777 return COMPILE_OK;
5778}
5779
5780static int
5781compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5782 const NODE *rhsn, const NODE *orig_lhsn)
5783{
5784 VALUE mem[64];
5785 const int memsize = numberof(mem);
5786 int memindex = 0;
5787 int llen = 0, rlen = 0;
5788 int i;
5789 const NODE *lhsn = orig_lhsn;
5790
5791#define MEMORY(v) { \
5792 int i; \
5793 if (memindex == memsize) return 0; \
5794 for (i=0; i<memindex; i++) { \
5795 if (mem[i] == (v)) return 0; \
5796 } \
5797 mem[memindex++] = (v); \
5798}
5799
5800 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5801 return 0;
5802 }
5803
5804 while (lhsn) {
5805 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5806 switch (nd_type(ln)) {
5807 case NODE_LASGN:
5808 case NODE_DASGN:
5809 case NODE_IASGN:
5810 case NODE_CVASGN:
5811 MEMORY(get_nd_vid(ln));
5812 break;
5813 default:
5814 return 0;
5815 }
5816 lhsn = RNODE_LIST(lhsn)->nd_next;
5817 llen++;
5818 }
5819
5820 while (rhsn) {
5821 if (llen <= rlen) {
5822 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5823 }
5824 else {
5825 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5826 }
5827 rhsn = RNODE_LIST(rhsn)->nd_next;
5828 rlen++;
5829 }
5830
5831 if (llen > rlen) {
5832 for (i=0; i<llen-rlen; i++) {
5833 ADD_INSN(ret, orig_lhsn, putnil);
5834 }
5835 }
5836
5837 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5838 return 1;
5839}
5840
5841static int
5842compile_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)
5843{
5844 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5845 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5846 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5847 const NODE *lhsn_count = lhsn;
5848 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5849
5850 int llen = 0;
5851 int lpos = 0;
5852
5853 while (lhsn_count) {
5854 llen++;
5855 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5856 }
5857 while (lhsn) {
5858 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5859 lpos++;
5860 lhsn = RNODE_LIST(lhsn)->nd_next;
5861 }
5862
5863 if (lhs_splat) {
5864 if (nd_type_p(splatn, NODE_POSTARG)) {
5865 /*a, b, *r, p1, p2 */
5866 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5867 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5868 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5869 int ppos = 0;
5870 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5871
5872 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5873
5874 if (NODE_NAMED_REST_P(restn)) {
5875 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5876 }
5877 while (postn) {
5878 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5879 ppos++;
5880 postn = RNODE_LIST(postn)->nd_next;
5881 }
5882 }
5883 else {
5884 /* a, b, *r */
5885 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5886 }
5887 }
5888
5889 if (!state->nested) {
5890 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5891 }
5892
5893 if (!popped) {
5894 ADD_INSN(rhs, node, dup);
5895 }
5896 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5897 return COMPILE_OK;
5898}
5899
5900static int
5901compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5902{
5903 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5904 struct masgn_state state;
5905 state.lhs_level = popped ? 0 : 1;
5906 state.nested = 0;
5907 state.num_args = 0;
5908 state.first_memo = NULL;
5909 state.last_memo = NULL;
5910
5911 DECL_ANCHOR(pre);
5912 INIT_ANCHOR(pre);
5913 DECL_ANCHOR(rhs);
5914 INIT_ANCHOR(rhs);
5915 DECL_ANCHOR(lhs);
5916 INIT_ANCHOR(lhs);
5917 DECL_ANCHOR(post);
5918 INIT_ANCHOR(post);
5919 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5920
5921 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5922 while (memo) {
5923 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5924 for (int i = 0; i < memo->num_args; i++) {
5925 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5926 }
5927 tmp_memo = memo->next;
5928 free(memo);
5929 memo = tmp_memo;
5930 }
5931 CHECK(ok);
5932
5933 ADD_SEQ(ret, pre);
5934 ADD_SEQ(ret, rhs);
5935 ADD_SEQ(ret, lhs);
5936 if (!popped && state.num_args >= 1) {
5937 /* make sure rhs array is returned before popping */
5938 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5939 }
5940 ADD_SEQ(ret, post);
5941 }
5942 return COMPILE_OK;
5943}
5944
5945static VALUE
5946collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5947{
5948 VALUE arr = rb_ary_new();
5949 for (;;) {
5950 switch (nd_type(node)) {
5951 case NODE_CONST:
5952 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5953 return arr;
5954 case NODE_COLON3:
5955 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5956 rb_ary_unshift(arr, ID2SYM(idNULL));
5957 return arr;
5958 case NODE_COLON2:
5959 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5960 node = RNODE_COLON2(node)->nd_head;
5961 break;
5962 default:
5963 return Qfalse;
5964 }
5965 }
5966}
5967
5968static int
5969compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5970 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5971{
5972 switch (nd_type(node)) {
5973 case NODE_CONST:
5974 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5975 ADD_INSN1(body, node, putobject, Qtrue);
5976 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5977 break;
5978 case NODE_COLON3:
5979 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5980 ADD_INSN(body, node, pop);
5981 ADD_INSN1(body, node, putobject, rb_cObject);
5982 ADD_INSN1(body, node, putobject, Qtrue);
5983 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5984 break;
5985 case NODE_COLON2:
5986 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5987 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5988 ADD_INSN1(body, node, putobject, Qfalse);
5989 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5990 break;
5991 default:
5992 CHECK(COMPILE(pref, "const colon2 prefix", node));
5993 break;
5994 }
5995 return COMPILE_OK;
5996}
5997
5998static int
5999compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6000{
6001 if (nd_type_p(cpath, NODE_COLON3)) {
6002 /* toplevel class ::Foo */
6003 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6004 return VM_DEFINECLASS_FLAG_SCOPED;
6005 }
6006 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6007 /* Bar::Foo */
6008 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6009 return VM_DEFINECLASS_FLAG_SCOPED;
6010 }
6011 else {
6012 /* class at cbase Foo */
6013 ADD_INSN1(ret, cpath, putspecialobject,
6014 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6015 return 0;
6016 }
6017}
6018
6019static inline int
6020private_recv_p(const NODE *node)
6021{
6022 NODE *recv = get_nd_recv(node);
6023 if (recv && nd_type_p(recv, NODE_SELF)) {
6024 return RNODE_SELF(recv)->nd_state != 0;
6025 }
6026 return 0;
6027}
6028
6029static void
6030defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6031 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6032
6033static int
6034compile_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);
6035
6036static void
6037defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6038 const NODE *const node, LABEL **lfinish, VALUE needstr,
6039 bool keep_result)
6040{
6041 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6042 enum node_type type;
6043 const int line = nd_line(node);
6044 const NODE *line_node = node;
6045
6046 switch (type = nd_type(node)) {
6047
6048 /* easy literals */
6049 case NODE_NIL:
6050 expr_type = DEFINED_NIL;
6051 break;
6052 case NODE_SELF:
6053 expr_type = DEFINED_SELF;
6054 break;
6055 case NODE_TRUE:
6056 expr_type = DEFINED_TRUE;
6057 break;
6058 case NODE_FALSE:
6059 expr_type = DEFINED_FALSE;
6060 break;
6061
6062 case NODE_HASH:
6063 case NODE_LIST:{
6064 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6065
6066 if (vals) {
6067 do {
6068 if (RNODE_LIST(vals)->nd_head) {
6069 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6070
6071 if (!lfinish[1]) {
6072 lfinish[1] = NEW_LABEL(line);
6073 }
6074 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6075 }
6076 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6077 }
6078 }
6079 /* fall through */
6080 case NODE_STR:
6081 case NODE_SYM:
6082 case NODE_REGX:
6083 case NODE_LINE:
6084 case NODE_FILE:
6085 case NODE_ENCODING:
6086 case NODE_INTEGER:
6087 case NODE_FLOAT:
6088 case NODE_RATIONAL:
6089 case NODE_IMAGINARY:
6090 case NODE_ZLIST:
6091 case NODE_AND:
6092 case NODE_OR:
6093 default:
6094 expr_type = DEFINED_EXPR;
6095 break;
6096
6097 case NODE_SPLAT:
6098 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6099 if (!lfinish[1]) {
6100 lfinish[1] = NEW_LABEL(line);
6101 }
6102 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6103 expr_type = DEFINED_EXPR;
6104 break;
6105
6106 /* variables */
6107 case NODE_LVAR:
6108 case NODE_DVAR:
6109 expr_type = DEFINED_LVAR;
6110 break;
6111
6112#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6113 case NODE_IVAR:
6114 ADD_INSN3(ret, line_node, definedivar,
6115 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6116 return;
6117
6118 case NODE_GVAR:
6119 ADD_INSN(ret, line_node, putnil);
6120 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6121 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6122 return;
6123
6124 case NODE_CVAR:
6125 ADD_INSN(ret, line_node, putnil);
6126 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6127 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6128 return;
6129
6130 case NODE_CONST:
6131 ADD_INSN(ret, line_node, putnil);
6132 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6133 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6134 return;
6135 case NODE_COLON2:
6136 if (!lfinish[1]) {
6137 lfinish[1] = NEW_LABEL(line);
6138 }
6139 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6140 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6141 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6142
6143 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6144 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6145 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6146 }
6147 else {
6148 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6149 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6150 }
6151 return;
6152 case NODE_COLON3:
6153 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6154 ADD_INSN3(ret, line_node, defined,
6155 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6156 return;
6157
6158 /* method dispatch */
6159 case NODE_CALL:
6160 case NODE_OPCALL:
6161 case NODE_VCALL:
6162 case NODE_FCALL:
6163 case NODE_ATTRASGN:{
6164 const int explicit_receiver =
6165 (type == NODE_CALL || type == NODE_OPCALL ||
6166 (type == NODE_ATTRASGN && !private_recv_p(node)));
6167
6168 if (get_nd_args(node) || explicit_receiver) {
6169 if (!lfinish[1]) {
6170 lfinish[1] = NEW_LABEL(line);
6171 }
6172 if (!lfinish[2]) {
6173 lfinish[2] = NEW_LABEL(line);
6174 }
6175 }
6176 if (get_nd_args(node)) {
6177 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6178 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6179 }
6180 if (explicit_receiver) {
6181 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6182 switch (nd_type(get_nd_recv(node))) {
6183 case NODE_CALL:
6184 case NODE_OPCALL:
6185 case NODE_VCALL:
6186 case NODE_FCALL:
6187 case NODE_ATTRASGN:
6188 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6189 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6190 break;
6191 default:
6192 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6193 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6194 break;
6195 }
6196 if (keep_result) {
6197 ADD_INSN(ret, line_node, dup);
6198 }
6199 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6200 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6201 }
6202 else {
6203 ADD_INSN(ret, line_node, putself);
6204 if (keep_result) {
6205 ADD_INSN(ret, line_node, dup);
6206 }
6207 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6208 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6209 }
6210 return;
6211 }
6212
6213 case NODE_YIELD:
6214 ADD_INSN(ret, line_node, putnil);
6215 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6216 PUSH_VAL(DEFINED_YIELD));
6217 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6218 return;
6219
6220 case NODE_BACK_REF:
6221 case NODE_NTH_REF:
6222 ADD_INSN(ret, line_node, putnil);
6223 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6224 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6225 PUSH_VAL(DEFINED_GVAR));
6226 return;
6227
6228 case NODE_SUPER:
6229 case NODE_ZSUPER:
6230 ADD_INSN(ret, line_node, putnil);
6231 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6232 PUSH_VAL(DEFINED_ZSUPER));
6233 return;
6234
6235#undef PUSH_VAL
6236 case NODE_OP_ASGN1:
6237 case NODE_OP_ASGN2:
6238 case NODE_OP_ASGN_OR:
6239 case NODE_OP_ASGN_AND:
6240 case NODE_MASGN:
6241 case NODE_LASGN:
6242 case NODE_DASGN:
6243 case NODE_GASGN:
6244 case NODE_IASGN:
6245 case NODE_CDECL:
6246 case NODE_CVASGN:
6247 case NODE_OP_CDECL:
6248 expr_type = DEFINED_ASGN;
6249 break;
6250 }
6251
6252 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6253
6254 if (needstr != Qfalse) {
6255 VALUE str = rb_iseq_defined_string(expr_type);
6256 ADD_INSN1(ret, line_node, putobject, str);
6257 }
6258 else {
6259 ADD_INSN1(ret, line_node, putobject, Qtrue);
6260 }
6261}
6262
6263static void
6264build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6265{
6266 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6267 iseq_set_exception_local_table(iseq);
6268}
6269
6270static void
6271defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6272 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6273{
6274 LINK_ELEMENT *lcur = ret->last;
6275 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6276 if (lfinish[1]) {
6277 int line = nd_line(node);
6278 LABEL *lstart = NEW_LABEL(line);
6279 LABEL *lend = NEW_LABEL(line);
6280 const rb_iseq_t *rescue;
6282 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6283 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6284 rb_str_concat(rb_str_new2("defined guard in "),
6285 ISEQ_BODY(iseq)->location.label),
6286 ISEQ_TYPE_RESCUE, 0);
6287 lstart->rescued = LABEL_RESCUE_BEG;
6288 lend->rescued = LABEL_RESCUE_END;
6289 APPEND_LABEL(ret, lcur, lstart);
6290 ADD_LABEL(ret, lend);
6291 if (!ignore) {
6292 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6293 }
6294 }
6295}
6296
6297static int
6298compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6299{
6300 const int line = nd_line(node);
6301 const NODE *line_node = node;
6302 if (!RNODE_DEFINED(node)->nd_head) {
6303 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6304 ADD_INSN1(ret, line_node, putobject, str);
6305 }
6306 else {
6307 LABEL *lfinish[3];
6308 LINK_ELEMENT *last = ret->last;
6309 lfinish[0] = NEW_LABEL(line);
6310 lfinish[1] = 0;
6311 lfinish[2] = 0;
6312 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6313 if (lfinish[1]) {
6314 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6315 ADD_INSN(ret, line_node, swap);
6316 if (lfinish[2]) {
6317 ADD_LABEL(ret, lfinish[2]);
6318 }
6319 ADD_INSN(ret, line_node, pop);
6320 ADD_LABEL(ret, lfinish[1]);
6321 }
6322 ADD_LABEL(ret, lfinish[0]);
6323 }
6324 return COMPILE_OK;
6325}
6326
6327static VALUE
6328make_name_for_block(const rb_iseq_t *orig_iseq)
6329{
6330 int level = 1;
6331 const rb_iseq_t *iseq = orig_iseq;
6332
6333 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6334 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6335 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6336 level++;
6337 }
6338 iseq = ISEQ_BODY(iseq)->parent_iseq;
6339 }
6340 }
6341
6342 if (level == 1) {
6343 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6344 }
6345 else {
6346 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6347 }
6348}
6349
6350static void
6351push_ensure_entry(rb_iseq_t *iseq,
6353 struct ensure_range *er, const void *const node)
6354{
6355 enl->ensure_node = node;
6356 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6357 enl->erange = er;
6358 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6359}
6360
6361static void
6362add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6363 LABEL *lstart, LABEL *lend)
6364{
6365 struct ensure_range *ne =
6366 compile_data_alloc(iseq, sizeof(struct ensure_range));
6367
6368 while (erange->next != 0) {
6369 erange = erange->next;
6370 }
6371 ne->next = 0;
6372 ne->begin = lend;
6373 ne->end = erange->end;
6374 erange->end = lstart;
6375
6376 erange->next = ne;
6377}
6378
6379static bool
6380can_add_ensure_iseq(const rb_iseq_t *iseq)
6381{
6383 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6384 while (e) {
6385 if (e->ensure_node) return false;
6386 e = e->prev;
6387 }
6388 }
6389 return true;
6390}
6391
6392static void
6393add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6394{
6395 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6396
6398 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6399 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6400 DECL_ANCHOR(ensure);
6401
6402 INIT_ANCHOR(ensure);
6403 while (enlp) {
6404 if (enlp->erange != NULL) {
6405 DECL_ANCHOR(ensure_part);
6406 LABEL *lstart = NEW_LABEL(0);
6407 LABEL *lend = NEW_LABEL(0);
6408 INIT_ANCHOR(ensure_part);
6409
6410 add_ensure_range(iseq, enlp->erange, lstart, lend);
6411
6412 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6413 ADD_LABEL(ensure_part, lstart);
6414 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6415 ADD_LABEL(ensure_part, lend);
6416 ADD_SEQ(ensure, ensure_part);
6417 }
6418 else {
6419 if (!is_return) {
6420 break;
6421 }
6422 }
6423 enlp = enlp->prev;
6424 }
6425 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6426 ADD_SEQ(ret, ensure);
6427}
6428
6429#if RUBY_DEBUG
6430static int
6431check_keyword(const NODE *node)
6432{
6433 /* This check is essentially a code clone of compile_keyword_arg. */
6434
6435 if (nd_type_p(node, NODE_LIST)) {
6436 while (RNODE_LIST(node)->nd_next) {
6437 node = RNODE_LIST(node)->nd_next;
6438 }
6439 node = RNODE_LIST(node)->nd_head;
6440 }
6441
6442 return keyword_node_p(node);
6443}
6444#endif
6445
6446static bool
6447keyword_node_single_splat_p(NODE *kwnode)
6448{
6449 RUBY_ASSERT(keyword_node_p(kwnode));
6450
6451 NODE *node = RNODE_HASH(kwnode)->nd_head;
6452 return RNODE_LIST(node)->nd_head == NULL &&
6453 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6454}
6455
6456static void
6457compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6458 NODE *kwnode, unsigned int *flag_ptr)
6459{
6460 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6461 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6462 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6463 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6464 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6465}
6466
6467#define SPLATARRAY_FALSE 0
6468#define SPLATARRAY_TRUE 1
6469#define DUP_SINGLE_KW_SPLAT 2
6470
6471static int
6472setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6473 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6474{
6475 if (!argn) return 0;
6476
6477 NODE *kwnode = NULL;
6478
6479 switch (nd_type(argn)) {
6480 case NODE_LIST: {
6481 // f(x, y, z)
6482 int len = compile_args(iseq, args, argn, &kwnode);
6483 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6484
6485 if (kwnode) {
6486 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6487 len -= 1;
6488 }
6489 else {
6490 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6491 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6492 }
6493 else {
6494 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6495 }
6496 }
6497 }
6498
6499 return len;
6500 }
6501 case NODE_SPLAT: {
6502 // f(*a)
6503 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6504 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6505 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6506 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6507 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6508 return 1;
6509 }
6510 case NODE_ARGSCAT: {
6511 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6512 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6513 bool args_pushed = false;
6514
6515 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6516 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6517 if (kwnode) rest_len--;
6518 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6519 args_pushed = true;
6520 }
6521 else {
6522 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6523 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6524 }
6525
6526 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6527 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6528 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6529 argc += 1;
6530 }
6531 else if (!args_pushed) {
6532 ADD_INSN(args, argn, concattoarray);
6533 }
6534
6535 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6536 if (kwnode) {
6537 // kwsplat
6538 *flag_ptr |= VM_CALL_KW_SPLAT;
6539 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6540 argc += 1;
6541 }
6542
6543 return argc;
6544 }
6545 case NODE_ARGSPUSH: {
6546 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6547 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6548
6549 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6550 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6551 if (kwnode) rest_len--;
6552 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6553 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6554 }
6555 else {
6556 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6557 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6558 }
6559 else {
6560 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6561 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6562 }
6563 }
6564
6565 if (kwnode) {
6566 // f(*a, k:1)
6567 *flag_ptr |= VM_CALL_KW_SPLAT;
6568 if (!keyword_node_single_splat_p(kwnode)) {
6569 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6570 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6571 }
6572 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6573 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6574 }
6575 else {
6576 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6577 }
6578 argc += 1;
6579 }
6580
6581 return argc;
6582 }
6583 default: {
6584 UNKNOWN_NODE("setup_arg", argn, Qnil);
6585 }
6586 }
6587}
6588
6589static void
6590setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6591{
6592 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6593 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6594 }
6595}
6596
6597static bool
6598setup_args_dup_rest_p(const NODE *argn)
6599{
6600 switch(nd_type(argn)) {
6601 case NODE_LVAR:
6602 case NODE_DVAR:
6603 case NODE_GVAR:
6604 case NODE_IVAR:
6605 case NODE_CVAR:
6606 case NODE_CONST:
6607 case NODE_COLON3:
6608 case NODE_INTEGER:
6609 case NODE_FLOAT:
6610 case NODE_RATIONAL:
6611 case NODE_IMAGINARY:
6612 case NODE_STR:
6613 case NODE_SYM:
6614 case NODE_REGX:
6615 case NODE_SELF:
6616 case NODE_NIL:
6617 case NODE_TRUE:
6618 case NODE_FALSE:
6619 case NODE_LAMBDA:
6620 case NODE_NTH_REF:
6621 case NODE_BACK_REF:
6622 return false;
6623 case NODE_COLON2:
6624 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6625 case NODE_LIST:
6626 while (argn) {
6627 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6628 return true;
6629 }
6630 argn = RNODE_LIST(argn)->nd_next;
6631 }
6632 return false;
6633 default:
6634 return true;
6635 }
6636}
6637
6638static VALUE
6639setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6640 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6641{
6642 VALUE ret;
6643 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6644
6645 if (argn) {
6646 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6647 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6648
6649 if (check_arg) {
6650 switch(nd_type(check_arg)) {
6651 case(NODE_SPLAT):
6652 // avoid caller side array allocation for f(*arg)
6653 dup_rest = SPLATARRAY_FALSE;
6654 break;
6655 case(NODE_ARGSCAT):
6656 // avoid caller side array allocation for f(1, *arg)
6657 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6658 break;
6659 case(NODE_ARGSPUSH):
6660 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6661 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6662 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6663 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6664 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6665 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6666
6667 if (dup_rest == SPLATARRAY_FALSE) {
6668 // require allocation for keyword key/value/splat that may modify splatted argument
6669 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6670 while (node) {
6671 NODE *key_node = RNODE_LIST(node)->nd_head;
6672 if (key_node && setup_args_dup_rest_p(key_node)) {
6673 dup_rest = SPLATARRAY_TRUE;
6674 break;
6675 }
6676
6677 node = RNODE_LIST(node)->nd_next;
6678 NODE *value_node = RNODE_LIST(node)->nd_head;
6679 if (setup_args_dup_rest_p(value_node)) {
6680 dup_rest = SPLATARRAY_TRUE;
6681 break;
6682 }
6683
6684 node = RNODE_LIST(node)->nd_next;
6685 }
6686 }
6687 break;
6688 default:
6689 break;
6690 }
6691 }
6692
6693 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6694 // for block pass that may modify splatted argument, dup rest and kwrest if given
6695 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6696 }
6697 }
6698 initial_dup_rest = dup_rest;
6699
6700 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6701 DECL_ANCHOR(arg_block);
6702 INIT_ANCHOR(arg_block);
6703
6704 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6705 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6706
6707 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6708 const NODE * arg_node =
6709 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6710
6711 int argc = 0;
6712
6713 // Only compile leading args:
6714 // foo(x, y, ...)
6715 // ^^^^
6716 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6717 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6718 }
6719
6720 *flag |= VM_CALL_FORWARDING;
6721
6722 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6723 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6724 return INT2FIX(argc);
6725 }
6726 else {
6727 *flag |= VM_CALL_ARGS_BLOCKARG;
6728
6729 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6730 }
6731
6732 if (LIST_INSN_SIZE_ONE(arg_block)) {
6733 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6734 if (IS_INSN(elem)) {
6735 INSN *iobj = (INSN *)elem;
6736 if (iobj->insn_id == BIN(getblockparam)) {
6737 iobj->insn_id = BIN(getblockparamproxy);
6738 }
6739 }
6740 }
6741 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6742 ADD_SEQ(args, arg_block);
6743 }
6744 else {
6745 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6746 }
6747 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6748 return ret;
6749}
6750
6751static void
6752build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6753{
6754 const NODE *body = ptr;
6755 int line = nd_line(body);
6756 VALUE argc = INT2FIX(0);
6757 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6758
6759 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6760 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6761 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6762 iseq_set_local_table(iseq, 0, 0);
6763}
6764
6765static void
6766compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6767{
6768 const NODE *vars;
6769 LINK_ELEMENT *last;
6770 int line = nd_line(node);
6771 const NODE *line_node = node;
6772 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6773
6774#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6775 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6776#else
6777 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6778#endif
6779 ADD_INSN(ret, line_node, dup);
6780 ADD_INSNL(ret, line_node, branchunless, fail_label);
6781
6782 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6783 INSN *cap;
6784 if (RNODE_BLOCK(vars)->nd_next) {
6785 ADD_INSN(ret, line_node, dup);
6786 }
6787 last = ret->last;
6788 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6789 last = last->next; /* putobject :var */
6790 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6791 NULL, INT2FIX(0), NULL);
6792 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6793#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6794 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6795 /* only one name */
6796 DECL_ANCHOR(nom);
6797
6798 INIT_ANCHOR(nom);
6799 ADD_INSNL(nom, line_node, jump, end_label);
6800 ADD_LABEL(nom, fail_label);
6801# if 0 /* $~ must be MatchData or nil */
6802 ADD_INSN(nom, line_node, pop);
6803 ADD_INSN(nom, line_node, putnil);
6804# endif
6805 ADD_LABEL(nom, end_label);
6806 (nom->last->next = cap->link.next)->prev = nom->last;
6807 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6808 return;
6809 }
6810#endif
6811 }
6812 ADD_INSNL(ret, line_node, jump, end_label);
6813 ADD_LABEL(ret, fail_label);
6814 ADD_INSN(ret, line_node, pop);
6815 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6816 last = ret->last;
6817 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6818 last = last->next; /* putobject :var */
6819 ((INSN*)last)->insn_id = BIN(putnil);
6820 ((INSN*)last)->operand_size = 0;
6821 }
6822 ADD_LABEL(ret, end_label);
6823}
6824
6825static int
6826optimizable_range_item_p(const NODE *n)
6827{
6828 if (!n) return FALSE;
6829 switch (nd_type(n)) {
6830 case NODE_LINE:
6831 return TRUE;
6832 case NODE_INTEGER:
6833 return TRUE;
6834 case NODE_NIL:
6835 return TRUE;
6836 default:
6837 return FALSE;
6838 }
6839}
6840
6841static VALUE
6842optimized_range_item(const NODE *n)
6843{
6844 switch (nd_type(n)) {
6845 case NODE_LINE:
6846 return rb_node_line_lineno_val(n);
6847 case NODE_INTEGER:
6848 return rb_node_integer_literal_val(n);
6849 case NODE_FLOAT:
6850 return rb_node_float_literal_val(n);
6851 case NODE_RATIONAL:
6852 return rb_node_rational_literal_val(n);
6853 case NODE_IMAGINARY:
6854 return rb_node_imaginary_literal_val(n);
6855 case NODE_NIL:
6856 return Qnil;
6857 default:
6858 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6859 }
6860}
6861
6862static int
6863compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6864{
6865 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6866 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6867
6868 const int line = nd_line(node);
6869 const NODE *line_node = node;
6870 DECL_ANCHOR(cond_seq);
6871 LABEL *then_label, *else_label, *end_label;
6872 VALUE branches = Qfalse;
6873
6874 INIT_ANCHOR(cond_seq);
6875 then_label = NEW_LABEL(line);
6876 else_label = NEW_LABEL(line);
6877 end_label = 0;
6878
6879 NODE *cond = RNODE_IF(node)->nd_cond;
6880 if (nd_type(cond) == NODE_BLOCK) {
6881 cond = RNODE_BLOCK(cond)->nd_head;
6882 }
6883
6884 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6885 ADD_SEQ(ret, cond_seq);
6886
6887 if (then_label->refcnt && else_label->refcnt) {
6888 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6889 }
6890
6891 if (then_label->refcnt) {
6892 ADD_LABEL(ret, then_label);
6893
6894 DECL_ANCHOR(then_seq);
6895 INIT_ANCHOR(then_seq);
6896 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6897
6898 if (else_label->refcnt) {
6899 const NODE *const coverage_node = node_body ? node_body : node;
6900 add_trace_branch_coverage(
6901 iseq,
6902 ret,
6903 nd_code_loc(coverage_node),
6904 nd_node_id(coverage_node),
6905 0,
6906 type == NODE_IF ? "then" : "else",
6907 branches);
6908 end_label = NEW_LABEL(line);
6909 ADD_INSNL(then_seq, line_node, jump, end_label);
6910 if (!popped) {
6911 ADD_INSN(then_seq, line_node, pop);
6912 }
6913 }
6914 ADD_SEQ(ret, then_seq);
6915 }
6916
6917 if (else_label->refcnt) {
6918 ADD_LABEL(ret, else_label);
6919
6920 DECL_ANCHOR(else_seq);
6921 INIT_ANCHOR(else_seq);
6922 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6923
6924 if (then_label->refcnt) {
6925 const NODE *const coverage_node = node_else ? node_else : node;
6926 add_trace_branch_coverage(
6927 iseq,
6928 ret,
6929 nd_code_loc(coverage_node),
6930 nd_node_id(coverage_node),
6931 1,
6932 type == NODE_IF ? "else" : "then",
6933 branches);
6934 }
6935 ADD_SEQ(ret, else_seq);
6936 }
6937
6938 if (end_label) {
6939 ADD_LABEL(ret, end_label);
6940 }
6941
6942 return COMPILE_OK;
6943}
6944
6945static int
6946compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6947{
6948 const NODE *vals;
6949 const NODE *node = orig_node;
6950 LABEL *endlabel, *elselabel;
6951 DECL_ANCHOR(head);
6952 DECL_ANCHOR(body_seq);
6953 DECL_ANCHOR(cond_seq);
6954 int only_special_literals = 1;
6955 VALUE literals = rb_hash_new();
6956 int line;
6957 enum node_type type;
6958 const NODE *line_node;
6959 VALUE branches = Qfalse;
6960 int branch_id = 0;
6961
6962 INIT_ANCHOR(head);
6963 INIT_ANCHOR(body_seq);
6964 INIT_ANCHOR(cond_seq);
6965
6966 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6967
6968 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6969
6970 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6971
6972 node = RNODE_CASE(node)->nd_body;
6973 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6974 type = nd_type(node);
6975 line = nd_line(node);
6976 line_node = node;
6977
6978 endlabel = NEW_LABEL(line);
6979 elselabel = NEW_LABEL(line);
6980
6981 ADD_SEQ(ret, head); /* case VAL */
6982
6983 while (type == NODE_WHEN) {
6984 LABEL *l1;
6985
6986 l1 = NEW_LABEL(line);
6987 ADD_LABEL(body_seq, l1);
6988 ADD_INSN(body_seq, line_node, pop);
6989
6990 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6991 add_trace_branch_coverage(
6992 iseq,
6993 body_seq,
6994 nd_code_loc(coverage_node),
6995 nd_node_id(coverage_node),
6996 branch_id++,
6997 "when",
6998 branches);
6999
7000 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7001 ADD_INSNL(body_seq, line_node, jump, endlabel);
7002
7003 vals = RNODE_WHEN(node)->nd_head;
7004 if (vals) {
7005 switch (nd_type(vals)) {
7006 case NODE_LIST:
7007 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7008 if (only_special_literals < 0) return COMPILE_NG;
7009 break;
7010 case NODE_SPLAT:
7011 case NODE_ARGSCAT:
7012 case NODE_ARGSPUSH:
7013 only_special_literals = 0;
7014 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7015 break;
7016 default:
7017 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7018 }
7019 }
7020 else {
7021 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7022 }
7023
7024 node = RNODE_WHEN(node)->nd_next;
7025 if (!node) {
7026 break;
7027 }
7028 type = nd_type(node);
7029 line = nd_line(node);
7030 line_node = node;
7031 }
7032 /* else */
7033 if (node) {
7034 ADD_LABEL(cond_seq, elselabel);
7035 ADD_INSN(cond_seq, line_node, pop);
7036 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7037 CHECK(COMPILE_(cond_seq, "else", node, popped));
7038 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7039 }
7040 else {
7041 debugs("== else (implicit)\n");
7042 ADD_LABEL(cond_seq, elselabel);
7043 ADD_INSN(cond_seq, orig_node, pop);
7044 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7045 if (!popped) {
7046 ADD_INSN(cond_seq, orig_node, putnil);
7047 }
7048 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7049 }
7050
7051 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7052 ADD_INSN(ret, orig_node, dup);
7053 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7054 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7055 LABEL_REF(elselabel);
7056 }
7057
7058 ADD_SEQ(ret, cond_seq);
7059 ADD_SEQ(ret, body_seq);
7060 ADD_LABEL(ret, endlabel);
7061 return COMPILE_OK;
7062}
7063
7064static int
7065compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7066{
7067 const NODE *vals;
7068 const NODE *val;
7069 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7070 LABEL *endlabel;
7071 DECL_ANCHOR(body_seq);
7072 VALUE branches = Qfalse;
7073 int branch_id = 0;
7074
7075 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7076
7077 INIT_ANCHOR(body_seq);
7078 endlabel = NEW_LABEL(nd_line(node));
7079
7080 while (node && nd_type_p(node, NODE_WHEN)) {
7081 const int line = nd_line(node);
7082 LABEL *l1 = NEW_LABEL(line);
7083 ADD_LABEL(body_seq, l1);
7084
7085 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7086 add_trace_branch_coverage(
7087 iseq,
7088 body_seq,
7089 nd_code_loc(coverage_node),
7090 nd_node_id(coverage_node),
7091 branch_id++,
7092 "when",
7093 branches);
7094
7095 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7096 ADD_INSNL(body_seq, node, jump, endlabel);
7097
7098 vals = RNODE_WHEN(node)->nd_head;
7099 if (!vals) {
7100 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7101 }
7102 switch (nd_type(vals)) {
7103 case NODE_LIST:
7104 while (vals) {
7105 LABEL *lnext;
7106 val = RNODE_LIST(vals)->nd_head;
7107 lnext = NEW_LABEL(nd_line(val));
7108 debug_compile("== when2\n", (void)0);
7109 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7110 ADD_LABEL(ret, lnext);
7111 vals = RNODE_LIST(vals)->nd_next;
7112 }
7113 break;
7114 case NODE_SPLAT:
7115 case NODE_ARGSCAT:
7116 case NODE_ARGSPUSH:
7117 ADD_INSN(ret, vals, putnil);
7118 CHECK(COMPILE(ret, "when2/cond splat", vals));
7119 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7120 ADD_INSNL(ret, vals, branchif, l1);
7121 break;
7122 default:
7123 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7124 }
7125 node = RNODE_WHEN(node)->nd_next;
7126 }
7127 /* else */
7128 const NODE *const coverage_node = node ? node : orig_node;
7129 add_trace_branch_coverage(
7130 iseq,
7131 ret,
7132 nd_code_loc(coverage_node),
7133 nd_node_id(coverage_node),
7134 branch_id,
7135 "else",
7136 branches);
7137 CHECK(COMPILE_(ret, "else", node, popped));
7138 ADD_INSNL(ret, orig_node, jump, endlabel);
7139
7140 ADD_SEQ(ret, body_seq);
7141 ADD_LABEL(ret, endlabel);
7142 return COMPILE_OK;
7143}
7144
7145static 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);
7146
7147static 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);
7148static 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);
7149static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7150static 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);
7151static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7152
7153#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7154#define CASE3_BI_OFFSET_ERROR_STRING 1
7155#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7156#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7157#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7158
7159static int
7160iseq_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)
7161{
7162 const int line = nd_line(node);
7163 const NODE *line_node = node;
7164
7165 switch (nd_type(node)) {
7166 case NODE_ARYPTN: {
7167 /*
7168 * if pattern.use_rest_num?
7169 * rest_num = 0
7170 * end
7171 * if pattern.has_constant_node?
7172 * unless pattern.constant === obj
7173 * goto match_failed
7174 * end
7175 * end
7176 * unless obj.respond_to?(:deconstruct)
7177 * goto match_failed
7178 * end
7179 * d = obj.deconstruct
7180 * unless Array === d
7181 * goto type_error
7182 * end
7183 * min_argc = pattern.pre_args_num + pattern.post_args_num
7184 * if pattern.has_rest_arg?
7185 * unless d.length >= min_argc
7186 * goto match_failed
7187 * end
7188 * else
7189 * unless d.length == min_argc
7190 * goto match_failed
7191 * end
7192 * end
7193 * pattern.pre_args_num.each do |i|
7194 * unless pattern.pre_args[i].match?(d[i])
7195 * goto match_failed
7196 * end
7197 * end
7198 * if pattern.use_rest_num?
7199 * rest_num = d.length - min_argc
7200 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7201 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7202 * goto match_failed
7203 * end
7204 * end
7205 * end
7206 * pattern.post_args_num.each do |i|
7207 * j = pattern.pre_args_num + i
7208 * j += rest_num
7209 * unless pattern.post_args[i].match?(d[j])
7210 * goto match_failed
7211 * end
7212 * end
7213 * goto matched
7214 * type_error:
7215 * FrozenCore.raise TypeError
7216 * match_failed:
7217 * goto unmatched
7218 */
7219 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7220 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7221 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7222
7223 const int min_argc = pre_args_num + post_args_num;
7224 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7225 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7226
7227 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7228 int i;
7229 match_failed = NEW_LABEL(line);
7230 type_error = NEW_LABEL(line);
7231 deconstruct = NEW_LABEL(line);
7232 deconstructed = NEW_LABEL(line);
7233
7234 if (use_rest_num) {
7235 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7236 ADD_INSN(ret, line_node, swap);
7237 if (base_index) {
7238 base_index++;
7239 }
7240 }
7241
7242 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7243
7244 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7245
7246 ADD_INSN(ret, line_node, dup);
7247 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7248 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7249 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7250 if (in_single_pattern) {
7251 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7252 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7253 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7254 INT2FIX(min_argc), base_index + 1 /* (1) */));
7255 }
7256 ADD_INSNL(ret, line_node, branchunless, match_failed);
7257
7258 for (i = 0; i < pre_args_num; i++) {
7259 ADD_INSN(ret, line_node, dup);
7260 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7261 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7262 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));
7263 args = RNODE_LIST(args)->nd_next;
7264 }
7265
7266 if (RNODE_ARYPTN(node)->rest_arg) {
7267 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7268 ADD_INSN(ret, line_node, dup);
7269 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7270 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7271 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7272 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7273 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7274 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7275 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7276
7277 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));
7278 }
7279 else {
7280 if (post_args_num > 0) {
7281 ADD_INSN(ret, line_node, dup);
7282 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7283 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7284 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7285 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7286 ADD_INSN(ret, line_node, pop);
7287 }
7288 }
7289 }
7290
7291 args = RNODE_ARYPTN(node)->post_args;
7292 for (i = 0; i < post_args_num; i++) {
7293 ADD_INSN(ret, line_node, dup);
7294
7295 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7296 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7297 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7298
7299 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7300 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));
7301 args = RNODE_LIST(args)->nd_next;
7302 }
7303
7304 ADD_INSN(ret, line_node, pop);
7305 if (use_rest_num) {
7306 ADD_INSN(ret, line_node, pop);
7307 }
7308 ADD_INSNL(ret, line_node, jump, matched);
7309 ADD_INSN(ret, line_node, putnil);
7310 if (use_rest_num) {
7311 ADD_INSN(ret, line_node, putnil);
7312 }
7313
7314 ADD_LABEL(ret, type_error);
7315 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7316 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7317 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7318 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7319 ADD_INSN(ret, line_node, pop);
7320
7321 ADD_LABEL(ret, match_failed);
7322 ADD_INSN(ret, line_node, pop);
7323 if (use_rest_num) {
7324 ADD_INSN(ret, line_node, pop);
7325 }
7326 ADD_INSNL(ret, line_node, jump, unmatched);
7327
7328 break;
7329 }
7330 case NODE_FNDPTN: {
7331 /*
7332 * if pattern.has_constant_node?
7333 * unless pattern.constant === obj
7334 * goto match_failed
7335 * end
7336 * end
7337 * unless obj.respond_to?(:deconstruct)
7338 * goto match_failed
7339 * end
7340 * d = obj.deconstruct
7341 * unless Array === d
7342 * goto type_error
7343 * end
7344 * unless d.length >= pattern.args_num
7345 * goto match_failed
7346 * end
7347 *
7348 * begin
7349 * len = d.length
7350 * limit = d.length - pattern.args_num
7351 * i = 0
7352 * while i <= limit
7353 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7354 * if pattern.has_pre_rest_arg_id
7355 * unless pattern.pre_rest_arg.match?(d[0, i])
7356 * goto find_failed
7357 * end
7358 * end
7359 * if pattern.has_post_rest_arg_id
7360 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7361 * goto find_failed
7362 * end
7363 * end
7364 * goto find_succeeded
7365 * end
7366 * i+=1
7367 * end
7368 * find_failed:
7369 * goto match_failed
7370 * find_succeeded:
7371 * end
7372 *
7373 * goto matched
7374 * type_error:
7375 * FrozenCore.raise TypeError
7376 * match_failed:
7377 * goto unmatched
7378 */
7379 const NODE *args = RNODE_FNDPTN(node)->args;
7380 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7381
7382 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7383 match_failed = NEW_LABEL(line);
7384 type_error = NEW_LABEL(line);
7385 deconstruct = NEW_LABEL(line);
7386 deconstructed = NEW_LABEL(line);
7387
7388 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7389
7390 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7391
7392 ADD_INSN(ret, line_node, dup);
7393 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7394 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7395 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7396 if (in_single_pattern) {
7397 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) */));
7398 }
7399 ADD_INSNL(ret, line_node, branchunless, match_failed);
7400
7401 {
7402 LABEL *while_begin = NEW_LABEL(nd_line(node));
7403 LABEL *next_loop = NEW_LABEL(nd_line(node));
7404 LABEL *find_succeeded = NEW_LABEL(line);
7405 LABEL *find_failed = NEW_LABEL(nd_line(node));
7406 int j;
7407
7408 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7409 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7410
7411 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7412 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7413 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7414
7415 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7416
7417 ADD_LABEL(ret, while_begin);
7418
7419 ADD_INSN(ret, line_node, dup);
7420 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7421 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7422 ADD_INSNL(ret, line_node, branchunless, find_failed);
7423
7424 for (j = 0; j < args_num; j++) {
7425 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7426 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7427 if (j != 0) {
7428 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7429 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7430 }
7431 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7432
7433 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));
7434 args = RNODE_LIST(args)->nd_next;
7435 }
7436
7437 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7438 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7439 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7440 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7441 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7442 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));
7443 }
7444 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7445 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7446 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7447 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7448 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7449 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7450 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7451 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));
7452 }
7453 ADD_INSNL(ret, line_node, jump, find_succeeded);
7454
7455 ADD_LABEL(ret, next_loop);
7456 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7457 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7458 ADD_INSNL(ret, line_node, jump, while_begin);
7459
7460 ADD_LABEL(ret, find_failed);
7461 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7462 if (in_single_pattern) {
7463 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7464 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7465 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7466 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7467 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7468
7469 ADD_INSN1(ret, line_node, putobject, Qfalse);
7470 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7471
7472 ADD_INSN(ret, line_node, pop);
7473 ADD_INSN(ret, line_node, pop);
7474 }
7475 ADD_INSNL(ret, line_node, jump, match_failed);
7476 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7477
7478 ADD_LABEL(ret, find_succeeded);
7479 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7480 }
7481
7482 ADD_INSN(ret, line_node, pop);
7483 ADD_INSNL(ret, line_node, jump, matched);
7484 ADD_INSN(ret, line_node, putnil);
7485
7486 ADD_LABEL(ret, type_error);
7487 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7488 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7489 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7490 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7491 ADD_INSN(ret, line_node, pop);
7492
7493 ADD_LABEL(ret, match_failed);
7494 ADD_INSN(ret, line_node, pop);
7495 ADD_INSNL(ret, line_node, jump, unmatched);
7496
7497 break;
7498 }
7499 case NODE_HSHPTN: {
7500 /*
7501 * keys = nil
7502 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7503 * keys = pattern.kw_args_node.keys
7504 * end
7505 * if pattern.has_constant_node?
7506 * unless pattern.constant === obj
7507 * goto match_failed
7508 * end
7509 * end
7510 * unless obj.respond_to?(:deconstruct_keys)
7511 * goto match_failed
7512 * end
7513 * d = obj.deconstruct_keys(keys)
7514 * unless Hash === d
7515 * goto type_error
7516 * end
7517 * if pattern.has_kw_rest_arg_node?
7518 * d = d.dup
7519 * end
7520 * if pattern.has_kw_args_node?
7521 * pattern.kw_args_node.each |k,|
7522 * unless d.key?(k)
7523 * goto match_failed
7524 * end
7525 * end
7526 * pattern.kw_args_node.each |k, pat|
7527 * if pattern.has_kw_rest_arg_node?
7528 * unless pat.match?(d.delete(k))
7529 * goto match_failed
7530 * end
7531 * else
7532 * unless pat.match?(d[k])
7533 * goto match_failed
7534 * end
7535 * end
7536 * end
7537 * else
7538 * unless d.empty?
7539 * goto match_failed
7540 * end
7541 * end
7542 * if pattern.has_kw_rest_arg_node?
7543 * if pattern.no_rest_keyword?
7544 * unless d.empty?
7545 * goto match_failed
7546 * end
7547 * else
7548 * unless pattern.kw_rest_arg_node.match?(d)
7549 * goto match_failed
7550 * end
7551 * end
7552 * end
7553 * goto matched
7554 * type_error:
7555 * FrozenCore.raise TypeError
7556 * match_failed:
7557 * goto unmatched
7558 */
7559 LABEL *match_failed, *type_error;
7560 VALUE keys = Qnil;
7561
7562 match_failed = NEW_LABEL(line);
7563 type_error = NEW_LABEL(line);
7564
7565 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7566 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7567 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7568 while (kw_args) {
7569 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7570 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7571 }
7572 }
7573
7574 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7575
7576 ADD_INSN(ret, line_node, dup);
7577 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7578 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7579 if (in_single_pattern) {
7580 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7581 }
7582 ADD_INSNL(ret, line_node, branchunless, match_failed);
7583
7584 if (NIL_P(keys)) {
7585 ADD_INSN(ret, line_node, putnil);
7586 }
7587 else {
7588 ADD_INSN1(ret, line_node, duparray, keys);
7589 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7590 }
7591 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7592
7593 ADD_INSN(ret, line_node, dup);
7594 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7595 ADD_INSNL(ret, line_node, branchunless, type_error);
7596
7597 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7598 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7599 }
7600
7601 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7602 int i;
7603 int keys_num;
7604 const NODE *args;
7605 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7606 if (args) {
7607 DECL_ANCHOR(match_values);
7608 INIT_ANCHOR(match_values);
7609 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7610 for (i = 0; i < keys_num; i++) {
7611 NODE *key_node = RNODE_LIST(args)->nd_head;
7612 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7613 VALUE key = get_symbol_value(iseq, key_node);
7614
7615 ADD_INSN(ret, line_node, dup);
7616 ADD_INSN1(ret, line_node, putobject, key);
7617 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7618 if (in_single_pattern) {
7619 LABEL *match_succeeded;
7620 match_succeeded = NEW_LABEL(line);
7621
7622 ADD_INSN(ret, line_node, dup);
7623 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7624
7625 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7626 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7627 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7628 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7629 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7630 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7631 ADD_INSN1(ret, line_node, putobject, key); // (7)
7632 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7633
7634 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7635
7636 ADD_LABEL(ret, match_succeeded);
7637 }
7638 ADD_INSNL(ret, line_node, branchunless, match_failed);
7639
7640 ADD_INSN(match_values, line_node, dup);
7641 ADD_INSN1(match_values, line_node, putobject, key);
7642 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7643 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7644 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7645 }
7646 ADD_SEQ(ret, match_values);
7647 }
7648 }
7649 else {
7650 ADD_INSN(ret, line_node, dup);
7651 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7652 if (in_single_pattern) {
7653 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7654 }
7655 ADD_INSNL(ret, line_node, branchunless, match_failed);
7656 }
7657
7658 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7659 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7660 ADD_INSN(ret, line_node, dup);
7661 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7662 if (in_single_pattern) {
7663 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7664 }
7665 ADD_INSNL(ret, line_node, branchunless, match_failed);
7666 }
7667 else {
7668 ADD_INSN(ret, line_node, dup); // (11)
7669 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));
7670 }
7671 }
7672
7673 ADD_INSN(ret, line_node, pop);
7674 ADD_INSNL(ret, line_node, jump, matched);
7675 ADD_INSN(ret, line_node, putnil);
7676
7677 ADD_LABEL(ret, type_error);
7678 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7679 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7680 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7681 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7682 ADD_INSN(ret, line_node, pop);
7683
7684 ADD_LABEL(ret, match_failed);
7685 ADD_INSN(ret, line_node, pop);
7686 ADD_INSNL(ret, line_node, jump, unmatched);
7687 break;
7688 }
7689 case NODE_SYM:
7690 case NODE_REGX:
7691 case NODE_LINE:
7692 case NODE_INTEGER:
7693 case NODE_FLOAT:
7694 case NODE_RATIONAL:
7695 case NODE_IMAGINARY:
7696 case NODE_FILE:
7697 case NODE_ENCODING:
7698 case NODE_STR:
7699 case NODE_XSTR:
7700 case NODE_DSTR:
7701 case NODE_DSYM:
7702 case NODE_DREGX:
7703 case NODE_LIST:
7704 case NODE_ZLIST:
7705 case NODE_LAMBDA:
7706 case NODE_DOT2:
7707 case NODE_DOT3:
7708 case NODE_CONST:
7709 case NODE_LVAR:
7710 case NODE_DVAR:
7711 case NODE_IVAR:
7712 case NODE_CVAR:
7713 case NODE_GVAR:
7714 case NODE_TRUE:
7715 case NODE_FALSE:
7716 case NODE_SELF:
7717 case NODE_NIL:
7718 case NODE_COLON2:
7719 case NODE_COLON3:
7720 case NODE_BEGIN:
7721 case NODE_BLOCK:
7722 case NODE_ONCE:
7723 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7724 if (in_single_pattern) {
7725 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7726 }
7727 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7728 if (in_single_pattern) {
7729 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7730 }
7731 ADD_INSNL(ret, line_node, branchif, matched);
7732 ADD_INSNL(ret, line_node, jump, unmatched);
7733 break;
7734 case NODE_LASGN: {
7735 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7736 ID id = RNODE_LASGN(node)->nd_vid;
7737 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7738
7739 if (in_alt_pattern) {
7740 const char *name = rb_id2name(id);
7741 if (name && strlen(name) > 0 && name[0] != '_') {
7742 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7743 rb_id2str(id));
7744 return COMPILE_NG;
7745 }
7746 }
7747
7748 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7749 ADD_INSNL(ret, line_node, jump, matched);
7750 break;
7751 }
7752 case NODE_DASGN: {
7753 int idx, lv, ls;
7754 ID id = RNODE_DASGN(node)->nd_vid;
7755
7756 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7757
7758 if (in_alt_pattern) {
7759 const char *name = rb_id2name(id);
7760 if (name && strlen(name) > 0 && name[0] != '_') {
7761 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7762 rb_id2str(id));
7763 return COMPILE_NG;
7764 }
7765 }
7766
7767 if (idx < 0) {
7768 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7769 rb_id2str(id));
7770 return COMPILE_NG;
7771 }
7772 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7773 ADD_INSNL(ret, line_node, jump, matched);
7774 break;
7775 }
7776 case NODE_IF:
7777 case NODE_UNLESS: {
7778 LABEL *match_failed;
7779 match_failed = unmatched;
7780 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7781 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7782 if (in_single_pattern) {
7783 LABEL *match_succeeded;
7784 match_succeeded = NEW_LABEL(line);
7785
7786 ADD_INSN(ret, line_node, dup);
7787 if (nd_type_p(node, NODE_IF)) {
7788 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7789 }
7790 else {
7791 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7792 }
7793
7794 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7795 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7796 ADD_INSN1(ret, line_node, putobject, Qfalse);
7797 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7798
7799 ADD_INSN(ret, line_node, pop);
7800 ADD_INSN(ret, line_node, pop);
7801
7802 ADD_LABEL(ret, match_succeeded);
7803 }
7804 if (nd_type_p(node, NODE_IF)) {
7805 ADD_INSNL(ret, line_node, branchunless, match_failed);
7806 }
7807 else {
7808 ADD_INSNL(ret, line_node, branchif, match_failed);
7809 }
7810 ADD_INSNL(ret, line_node, jump, matched);
7811 break;
7812 }
7813 case NODE_HASH: {
7814 NODE *n;
7815 LABEL *match_failed;
7816 match_failed = NEW_LABEL(line);
7817
7818 n = RNODE_HASH(node)->nd_head;
7819 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7820 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7821 return COMPILE_NG;
7822 }
7823
7824 ADD_INSN(ret, line_node, dup); // (1)
7825 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));
7826 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));
7827 ADD_INSN(ret, line_node, putnil);
7828
7829 ADD_LABEL(ret, match_failed);
7830 ADD_INSN(ret, line_node, pop);
7831 ADD_INSNL(ret, line_node, jump, unmatched);
7832 break;
7833 }
7834 case NODE_OR: {
7835 LABEL *match_succeeded, *fin;
7836 match_succeeded = NEW_LABEL(line);
7837 fin = NEW_LABEL(line);
7838
7839 ADD_INSN(ret, line_node, dup); // (1)
7840 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));
7841 ADD_LABEL(ret, match_succeeded);
7842 ADD_INSN(ret, line_node, pop);
7843 ADD_INSNL(ret, line_node, jump, matched);
7844 ADD_INSN(ret, line_node, putnil);
7845 ADD_LABEL(ret, fin);
7846 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7847 break;
7848 }
7849 default:
7850 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7851 }
7852 return COMPILE_OK;
7853}
7854
7855static int
7856iseq_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)
7857{
7858 LABEL *fin = NEW_LABEL(nd_line(node));
7859 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7860 ADD_LABEL(ret, fin);
7861 return COMPILE_OK;
7862}
7863
7864static int
7865iseq_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)
7866{
7867 const NODE *line_node = node;
7868
7869 if (RNODE_ARYPTN(node)->nd_pconst) {
7870 ADD_INSN(ret, line_node, dup); // (1)
7871 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7872 if (in_single_pattern) {
7873 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7874 }
7875 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7876 if (in_single_pattern) {
7877 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7878 }
7879 ADD_INSNL(ret, line_node, branchunless, match_failed);
7880 }
7881 return COMPILE_OK;
7882}
7883
7884
7885static int
7886iseq_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)
7887{
7888 const NODE *line_node = node;
7889
7890 // NOTE: this optimization allows us to re-use the #deconstruct value
7891 // (or its absence).
7892 if (use_deconstructed_cache) {
7893 // If value is nil then we haven't tried to deconstruct
7894 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7895 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7896
7897 // If false then the value is not deconstructable
7898 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7899 ADD_INSNL(ret, line_node, branchunless, match_failed);
7900
7901 // Drop value, add deconstructed to the stack and jump
7902 ADD_INSN(ret, line_node, pop); // (1)
7903 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7904 ADD_INSNL(ret, line_node, jump, deconstructed);
7905 }
7906 else {
7907 ADD_INSNL(ret, line_node, jump, deconstruct);
7908 }
7909
7910 ADD_LABEL(ret, deconstruct);
7911 ADD_INSN(ret, line_node, dup);
7912 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7913 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7914
7915 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7916 if (use_deconstructed_cache) {
7917 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7918 }
7919
7920 if (in_single_pattern) {
7921 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7922 }
7923
7924 ADD_INSNL(ret, line_node, branchunless, match_failed);
7925
7926 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7927
7928 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7929 if (use_deconstructed_cache) {
7930 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7931 }
7932
7933 ADD_INSN(ret, line_node, dup);
7934 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7935 ADD_INSNL(ret, line_node, branchunless, type_error);
7936
7937 ADD_LABEL(ret, deconstructed);
7938
7939 return COMPILE_OK;
7940}
7941
7942static int
7943iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7944{
7945 /*
7946 * if match_succeeded?
7947 * goto match_succeeded
7948 * end
7949 * error_string = FrozenCore.sprintf(errmsg, matchee)
7950 * key_error_p = false
7951 * match_succeeded:
7952 */
7953 const int line = nd_line(node);
7954 const NODE *line_node = node;
7955 LABEL *match_succeeded = NEW_LABEL(line);
7956
7957 ADD_INSN(ret, line_node, dup);
7958 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7959
7960 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7961 ADD_INSN1(ret, line_node, putobject, errmsg);
7962 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7963 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7964 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7965
7966 ADD_INSN1(ret, line_node, putobject, Qfalse);
7967 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7968
7969 ADD_INSN(ret, line_node, pop);
7970 ADD_INSN(ret, line_node, pop);
7971 ADD_LABEL(ret, match_succeeded);
7972
7973 return COMPILE_OK;
7974}
7975
7976static int
7977iseq_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)
7978{
7979 /*
7980 * if match_succeeded?
7981 * goto match_succeeded
7982 * end
7983 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7984 * key_error_p = false
7985 * match_succeeded:
7986 */
7987 const int line = nd_line(node);
7988 const NODE *line_node = node;
7989 LABEL *match_succeeded = NEW_LABEL(line);
7990
7991 ADD_INSN(ret, line_node, dup);
7992 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7993
7994 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7995 ADD_INSN1(ret, line_node, putobject, errmsg);
7996 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7997 ADD_INSN(ret, line_node, dup);
7998 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7999 ADD_INSN1(ret, line_node, putobject, pattern_length);
8000 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8001 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8002
8003 ADD_INSN1(ret, line_node, putobject, Qfalse);
8004 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8005
8006 ADD_INSN(ret, line_node, pop);
8007 ADD_INSN(ret, line_node, pop);
8008 ADD_LABEL(ret, match_succeeded);
8009
8010 return COMPILE_OK;
8011}
8012
8013static int
8014iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8015{
8016 /*
8017 * if match_succeeded?
8018 * goto match_succeeded
8019 * end
8020 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8021 * key_error_p = false
8022 * match_succeeded:
8023 */
8024 const int line = nd_line(node);
8025 const NODE *line_node = node;
8026 LABEL *match_succeeded = NEW_LABEL(line);
8027
8028 ADD_INSN(ret, line_node, dup);
8029 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8030
8031 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8032 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8033 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8034 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8035 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8036 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8037
8038 ADD_INSN1(ret, line_node, putobject, Qfalse);
8039 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8040
8041 ADD_INSN(ret, line_node, pop);
8042 ADD_INSN(ret, line_node, pop);
8043
8044 ADD_LABEL(ret, match_succeeded);
8045 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8046 ADD_INSN(ret, line_node, pop);
8047 ADD_INSN(ret, line_node, pop);
8048
8049 return COMPILE_OK;
8050}
8051
8052static int
8053compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8054{
8055 const NODE *pattern;
8056 const NODE *node = orig_node;
8057 LABEL *endlabel, *elselabel;
8058 DECL_ANCHOR(head);
8059 DECL_ANCHOR(body_seq);
8060 DECL_ANCHOR(cond_seq);
8061 int line;
8062 enum node_type type;
8063 const NODE *line_node;
8064 VALUE branches = 0;
8065 int branch_id = 0;
8066 bool single_pattern;
8067
8068 INIT_ANCHOR(head);
8069 INIT_ANCHOR(body_seq);
8070 INIT_ANCHOR(cond_seq);
8071
8072 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8073
8074 node = RNODE_CASE3(node)->nd_body;
8075 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8076 type = nd_type(node);
8077 line = nd_line(node);
8078 line_node = node;
8079 single_pattern = !RNODE_IN(node)->nd_next;
8080
8081 endlabel = NEW_LABEL(line);
8082 elselabel = NEW_LABEL(line);
8083
8084 if (single_pattern) {
8085 /* allocate stack for ... */
8086 ADD_INSN(head, line_node, putnil); /* key_error_key */
8087 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8088 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8089 ADD_INSN(head, line_node, putnil); /* error_string */
8090 }
8091 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8092
8093 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8094
8095 ADD_SEQ(ret, head); /* case VAL */
8096
8097 while (type == NODE_IN) {
8098 LABEL *l1;
8099
8100 if (branch_id) {
8101 ADD_INSN(body_seq, line_node, putnil);
8102 }
8103 l1 = NEW_LABEL(line);
8104 ADD_LABEL(body_seq, l1);
8105 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8106
8107 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8108 add_trace_branch_coverage(
8109 iseq,
8110 body_seq,
8111 nd_code_loc(coverage_node),
8112 nd_node_id(coverage_node),
8113 branch_id++,
8114 "in",
8115 branches);
8116
8117 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8118 ADD_INSNL(body_seq, line_node, jump, endlabel);
8119
8120 pattern = RNODE_IN(node)->nd_head;
8121 if (pattern) {
8122 int pat_line = nd_line(pattern);
8123 LABEL *next_pat = NEW_LABEL(pat_line);
8124 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8125 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8126 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8127 ADD_LABEL(cond_seq, next_pat);
8128 LABEL_UNREMOVABLE(next_pat);
8129 }
8130 else {
8131 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8132 return COMPILE_NG;
8133 }
8134
8135 node = RNODE_IN(node)->nd_next;
8136 if (!node) {
8137 break;
8138 }
8139 type = nd_type(node);
8140 line = nd_line(node);
8141 line_node = node;
8142 }
8143 /* else */
8144 if (node) {
8145 ADD_LABEL(cond_seq, elselabel);
8146 ADD_INSN(cond_seq, line_node, pop);
8147 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8148 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8149 CHECK(COMPILE_(cond_seq, "else", node, popped));
8150 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8151 ADD_INSN(cond_seq, line_node, putnil);
8152 if (popped) {
8153 ADD_INSN(cond_seq, line_node, putnil);
8154 }
8155 }
8156 else {
8157 debugs("== else (implicit)\n");
8158 ADD_LABEL(cond_seq, elselabel);
8159 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8160 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8161
8162 if (single_pattern) {
8163 /*
8164 * if key_error_p
8165 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8166 * else
8167 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8168 * end
8169 */
8170 LABEL *key_error, *fin;
8171 struct rb_callinfo_kwarg *kw_arg;
8172
8173 key_error = NEW_LABEL(line);
8174 fin = NEW_LABEL(line);
8175
8176 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8177 kw_arg->references = 0;
8178 kw_arg->keyword_len = 2;
8179 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8180 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8181
8182 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8183 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8184 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8185 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8186 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8187 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8188 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8189 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8190 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8191 ADD_INSNL(cond_seq, orig_node, jump, fin);
8192
8193 ADD_LABEL(cond_seq, key_error);
8194 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8195 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8196 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8197 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8198 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8199 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8200 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8201 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8202 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8203 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8204
8205 ADD_LABEL(cond_seq, fin);
8206 }
8207 else {
8208 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8209 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8210 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8211 }
8212 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8213 if (!popped) {
8214 ADD_INSN(cond_seq, orig_node, putnil);
8215 }
8216 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8217 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8218 if (popped) {
8219 ADD_INSN(cond_seq, line_node, putnil);
8220 }
8221 }
8222
8223 ADD_SEQ(ret, cond_seq);
8224 ADD_SEQ(ret, body_seq);
8225 ADD_LABEL(ret, endlabel);
8226 return COMPILE_OK;
8227}
8228
8229#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8230#undef CASE3_BI_OFFSET_ERROR_STRING
8231#undef CASE3_BI_OFFSET_KEY_ERROR_P
8232#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8233#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8234
8235static int
8236compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8237{
8238 const int line = (int)nd_line(node);
8239 const NODE *line_node = node;
8240
8241 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8242 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8243 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8244 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8245 VALUE branches = Qfalse;
8246
8248
8249 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8250 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8251 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8252 LABEL *end_label = NEW_LABEL(line);
8253 LABEL *adjust_label = NEW_LABEL(line);
8254
8255 LABEL *next_catch_label = NEW_LABEL(line);
8256 LABEL *tmp_label = NULL;
8257
8258 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8259 push_ensure_entry(iseq, &enl, NULL, NULL);
8260
8261 if (RNODE_WHILE(node)->nd_state == 1) {
8262 ADD_INSNL(ret, line_node, jump, next_label);
8263 }
8264 else {
8265 tmp_label = NEW_LABEL(line);
8266 ADD_INSNL(ret, line_node, jump, tmp_label);
8267 }
8268 ADD_LABEL(ret, adjust_label);
8269 ADD_INSN(ret, line_node, putnil);
8270 ADD_LABEL(ret, next_catch_label);
8271 ADD_INSN(ret, line_node, pop);
8272 ADD_INSNL(ret, line_node, jump, next_label);
8273 if (tmp_label) ADD_LABEL(ret, tmp_label);
8274
8275 ADD_LABEL(ret, redo_label);
8276 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8277
8278 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8279 add_trace_branch_coverage(
8280 iseq,
8281 ret,
8282 nd_code_loc(coverage_node),
8283 nd_node_id(coverage_node),
8284 0,
8285 "body",
8286 branches);
8287
8288 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8289 ADD_LABEL(ret, next_label); /* next */
8290
8291 if (type == NODE_WHILE) {
8292 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8293 redo_label, end_label));
8294 }
8295 else {
8296 /* until */
8297 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8298 end_label, redo_label));
8299 }
8300
8301 ADD_LABEL(ret, end_label);
8302 ADD_ADJUST_RESTORE(ret, adjust_label);
8303
8304 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8305 /* ADD_INSN(ret, line_node, putundef); */
8306 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8307 return COMPILE_NG;
8308 }
8309 else {
8310 ADD_INSN(ret, line_node, putnil);
8311 }
8312
8313 ADD_LABEL(ret, break_label); /* break */
8314
8315 if (popped) {
8316 ADD_INSN(ret, line_node, pop);
8317 }
8318
8319 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8320 break_label);
8321 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8322 next_catch_label);
8323 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8324 ISEQ_COMPILE_DATA(iseq)->redo_label);
8325
8326 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8327 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8328 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8329 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8330 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8331 return COMPILE_OK;
8332}
8333
8334static int
8335compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8336{
8337 const int line = nd_line(node);
8338 const NODE *line_node = node;
8339 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8340 LABEL *retry_label = NEW_LABEL(line);
8341 LABEL *retry_end_l = NEW_LABEL(line);
8342 const rb_iseq_t *child_iseq;
8343
8344 ADD_LABEL(ret, retry_label);
8345 if (nd_type_p(node, NODE_FOR)) {
8346 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8347
8348 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8349 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8350 ISEQ_TYPE_BLOCK, line);
8351 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8352 }
8353 else {
8354 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8355 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8356 ISEQ_TYPE_BLOCK, line);
8357 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8358 }
8359
8360 {
8361 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8362 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8363 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8364 //
8365 // Normally, "send" instruction is at the last.
8366 // However, qcall under branch coverage measurement adds some instructions after the "send".
8367 //
8368 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8369 INSN *iobj;
8370 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8371 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8372 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8373 iobj = (INSN*) get_prev_insn(iobj);
8374 }
8375 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8376
8377 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8378 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8379 if (&iobj->link == LAST_ELEMENT(ret)) {
8380 ret->last = (LINK_ELEMENT*) retry_end_l;
8381 }
8382 }
8383
8384 if (popped) {
8385 ADD_INSN(ret, line_node, pop);
8386 }
8387
8388 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8389
8390 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8391 return COMPILE_OK;
8392}
8393
8394static int
8395compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8396{
8397 /* massign to var in "for"
8398 * (args.length == 1 && Array.try_convert(args[0])) || args
8399 */
8400 const NODE *line_node = node;
8401 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8402 LABEL *not_single = NEW_LABEL(nd_line(var));
8403 LABEL *not_ary = NEW_LABEL(nd_line(var));
8404 CHECK(COMPILE(ret, "for var", var));
8405 ADD_INSN(ret, line_node, dup);
8406 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8407 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8408 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8409 ADD_INSNL(ret, line_node, branchunless, not_single);
8410 ADD_INSN(ret, line_node, dup);
8411 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8412 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8413 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8414 ADD_INSN(ret, line_node, swap);
8415 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8416 ADD_INSN(ret, line_node, dup);
8417 ADD_INSNL(ret, line_node, branchunless, not_ary);
8418 ADD_INSN(ret, line_node, swap);
8419 ADD_LABEL(ret, not_ary);
8420 ADD_INSN(ret, line_node, pop);
8421 ADD_LABEL(ret, not_single);
8422 return COMPILE_OK;
8423}
8424
8425static int
8426compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8427{
8428 const NODE *line_node = node;
8429 unsigned long throw_flag = 0;
8430
8431 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8432 /* while/until */
8433 LABEL *splabel = NEW_LABEL(0);
8434 ADD_LABEL(ret, splabel);
8435 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8436 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8437 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8438 add_ensure_iseq(ret, iseq, 0);
8439 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8440 ADD_ADJUST_RESTORE(ret, splabel);
8441
8442 if (!popped) {
8443 ADD_INSN(ret, line_node, putnil);
8444 }
8445 }
8446 else {
8447 const rb_iseq_t *ip = iseq;
8448
8449 while (ip) {
8450 if (!ISEQ_COMPILE_DATA(ip)) {
8451 ip = 0;
8452 break;
8453 }
8454
8455 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8456 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8457 }
8458 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8459 throw_flag = 0;
8460 }
8461 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8462 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8463 return COMPILE_NG;
8464 }
8465 else {
8466 ip = ISEQ_BODY(ip)->parent_iseq;
8467 continue;
8468 }
8469
8470 /* escape from block */
8471 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8472 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8473 if (popped) {
8474 ADD_INSN(ret, line_node, pop);
8475 }
8476 return COMPILE_OK;
8477 }
8478 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8479 return COMPILE_NG;
8480 }
8481 return COMPILE_OK;
8482}
8483
8484static int
8485compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8486{
8487 const NODE *line_node = node;
8488 unsigned long throw_flag = 0;
8489
8490 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8491 LABEL *splabel = NEW_LABEL(0);
8492 debugs("next in while loop\n");
8493 ADD_LABEL(ret, splabel);
8494 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8495 add_ensure_iseq(ret, iseq, 0);
8496 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8497 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8498 ADD_ADJUST_RESTORE(ret, splabel);
8499 if (!popped) {
8500 ADD_INSN(ret, line_node, putnil);
8501 }
8502 }
8503 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8504 LABEL *splabel = NEW_LABEL(0);
8505 debugs("next in block\n");
8506 ADD_LABEL(ret, splabel);
8507 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8508 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8509 add_ensure_iseq(ret, iseq, 0);
8510 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8511 ADD_ADJUST_RESTORE(ret, splabel);
8512
8513 if (!popped) {
8514 ADD_INSN(ret, line_node, putnil);
8515 }
8516 }
8517 else {
8518 const rb_iseq_t *ip = iseq;
8519
8520 while (ip) {
8521 if (!ISEQ_COMPILE_DATA(ip)) {
8522 ip = 0;
8523 break;
8524 }
8525
8526 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8527 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8528 /* while loop */
8529 break;
8530 }
8531 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8532 break;
8533 }
8534 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8535 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8536 return COMPILE_NG;
8537 }
8538
8539 ip = ISEQ_BODY(ip)->parent_iseq;
8540 }
8541 if (ip != 0) {
8542 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8543 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8544
8545 if (popped) {
8546 ADD_INSN(ret, line_node, pop);
8547 }
8548 }
8549 else {
8550 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8551 return COMPILE_NG;
8552 }
8553 }
8554 return COMPILE_OK;
8555}
8556
8557static int
8558compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8559{
8560 const NODE *line_node = node;
8561
8562 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8563 LABEL *splabel = NEW_LABEL(0);
8564 debugs("redo in while");
8565 ADD_LABEL(ret, splabel);
8566 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8567 add_ensure_iseq(ret, iseq, 0);
8568 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8569 ADD_ADJUST_RESTORE(ret, splabel);
8570 if (!popped) {
8571 ADD_INSN(ret, line_node, putnil);
8572 }
8573 }
8574 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8575 LABEL *splabel = NEW_LABEL(0);
8576
8577 debugs("redo in block");
8578 ADD_LABEL(ret, splabel);
8579 add_ensure_iseq(ret, iseq, 0);
8580 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8581 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8582 ADD_ADJUST_RESTORE(ret, splabel);
8583
8584 if (!popped) {
8585 ADD_INSN(ret, line_node, putnil);
8586 }
8587 }
8588 else {
8589 const rb_iseq_t *ip = iseq;
8590
8591 while (ip) {
8592 if (!ISEQ_COMPILE_DATA(ip)) {
8593 ip = 0;
8594 break;
8595 }
8596
8597 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8598 break;
8599 }
8600 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8601 break;
8602 }
8603 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8604 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8605 return COMPILE_NG;
8606 }
8607
8608 ip = ISEQ_BODY(ip)->parent_iseq;
8609 }
8610 if (ip != 0) {
8611 ADD_INSN(ret, line_node, putnil);
8612 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8613
8614 if (popped) {
8615 ADD_INSN(ret, line_node, pop);
8616 }
8617 }
8618 else {
8619 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8620 return COMPILE_NG;
8621 }
8622 }
8623 return COMPILE_OK;
8624}
8625
8626static int
8627compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8628{
8629 const NODE *line_node = node;
8630
8631 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8632 ADD_INSN(ret, line_node, putnil);
8633 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8634
8635 if (popped) {
8636 ADD_INSN(ret, line_node, pop);
8637 }
8638 }
8639 else {
8640 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8641 return COMPILE_NG;
8642 }
8643 return COMPILE_OK;
8644}
8645
8646static int
8647compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8648{
8649 const int line = nd_line(node);
8650 const NODE *line_node = node;
8651 LABEL *lstart = NEW_LABEL(line);
8652 LABEL *lend = NEW_LABEL(line);
8653 LABEL *lcont = NEW_LABEL(line);
8654 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8655 rb_str_concat(rb_str_new2("rescue in "),
8656 ISEQ_BODY(iseq)->location.label),
8657 ISEQ_TYPE_RESCUE, line);
8658
8659 lstart->rescued = LABEL_RESCUE_BEG;
8660 lend->rescued = LABEL_RESCUE_END;
8661 ADD_LABEL(ret, lstart);
8662
8663 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8664 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8665 {
8666 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8667 }
8668 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8669
8670 ADD_LABEL(ret, lend);
8671 if (RNODE_RESCUE(node)->nd_else) {
8672 ADD_INSN(ret, line_node, pop);
8673 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8674 }
8675 ADD_INSN(ret, line_node, nop);
8676 ADD_LABEL(ret, lcont);
8677
8678 if (popped) {
8679 ADD_INSN(ret, line_node, pop);
8680 }
8681
8682 /* register catch entry */
8683 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8684 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8685 return COMPILE_OK;
8686}
8687
8688static int
8689compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8690{
8691 const int line = nd_line(node);
8692 const NODE *line_node = node;
8693 const NODE *resq = node;
8694 const NODE *narg;
8695 LABEL *label_miss, *label_hit;
8696
8697 while (resq) {
8698 label_miss = NEW_LABEL(line);
8699 label_hit = NEW_LABEL(line);
8700
8701 narg = RNODE_RESBODY(resq)->nd_args;
8702 if (narg) {
8703 switch (nd_type(narg)) {
8704 case NODE_LIST:
8705 while (narg) {
8706 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8707 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8708 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8709 ADD_INSNL(ret, line_node, branchif, label_hit);
8710 narg = RNODE_LIST(narg)->nd_next;
8711 }
8712 break;
8713 case NODE_SPLAT:
8714 case NODE_ARGSCAT:
8715 case NODE_ARGSPUSH:
8716 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8717 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8718 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8719 ADD_INSNL(ret, line_node, branchif, label_hit);
8720 break;
8721 default:
8722 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8723 }
8724 }
8725 else {
8726 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8727 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8728 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8729 ADD_INSNL(ret, line_node, branchif, label_hit);
8730 }
8731 ADD_INSNL(ret, line_node, jump, label_miss);
8732 ADD_LABEL(ret, label_hit);
8733 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8734
8735 if (RNODE_RESBODY(resq)->nd_exc_var) {
8736 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8737 }
8738
8739 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) {
8740 // empty body
8741 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8742 }
8743 else {
8744 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8745 }
8746
8747 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8748 ADD_INSN(ret, line_node, nop);
8749 }
8750 ADD_INSN(ret, line_node, leave);
8751 ADD_LABEL(ret, label_miss);
8752 resq = RNODE_RESBODY(resq)->nd_next;
8753 }
8754 return COMPILE_OK;
8755}
8756
8757static int
8758compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8759{
8760 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8761 const NODE *line_node = node;
8762 DECL_ANCHOR(ensr);
8763 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8764 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8765 ISEQ_TYPE_ENSURE, line);
8766 LABEL *lstart = NEW_LABEL(line);
8767 LABEL *lend = NEW_LABEL(line);
8768 LABEL *lcont = NEW_LABEL(line);
8769 LINK_ELEMENT *last;
8770 int last_leave = 0;
8771 struct ensure_range er;
8773 struct ensure_range *erange;
8774
8775 INIT_ANCHOR(ensr);
8776 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8777 last = ensr->last;
8778 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8779
8780 er.begin = lstart;
8781 er.end = lend;
8782 er.next = 0;
8783 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8784
8785 ADD_LABEL(ret, lstart);
8786 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8787 ADD_LABEL(ret, lend);
8788 ADD_SEQ(ret, ensr);
8789 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8790 ADD_LABEL(ret, lcont);
8791 if (last_leave) ADD_INSN(ret, line_node, pop);
8792
8793 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8794 if (lstart->link.next != &lend->link) {
8795 while (erange) {
8796 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8797 ensure, lcont);
8798 erange = erange->next;
8799 }
8800 }
8801
8802 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8803 return COMPILE_OK;
8804}
8805
8806static int
8807compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8808{
8809 const NODE *line_node = node;
8810
8811 if (iseq) {
8812 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8813 const rb_iseq_t *is = iseq;
8814 enum rb_iseq_type t = type;
8815 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8816 LABEL *splabel = 0;
8817
8818 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8819 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8820 t = ISEQ_BODY(is)->type;
8821 }
8822 switch (t) {
8823 case ISEQ_TYPE_TOP:
8824 case ISEQ_TYPE_MAIN:
8825 if (retval) {
8826 rb_warn("argument of top-level return is ignored");
8827 }
8828 if (is == iseq) {
8829 /* plain top-level, leave directly */
8830 type = ISEQ_TYPE_METHOD;
8831 }
8832 break;
8833 default:
8834 break;
8835 }
8836
8837 if (type == ISEQ_TYPE_METHOD) {
8838 splabel = NEW_LABEL(0);
8839 ADD_LABEL(ret, splabel);
8840 ADD_ADJUST(ret, line_node, 0);
8841 }
8842
8843 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8844
8845 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8846 add_ensure_iseq(ret, iseq, 1);
8847 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8848 ADD_INSN(ret, line_node, leave);
8849 ADD_ADJUST_RESTORE(ret, splabel);
8850
8851 if (!popped) {
8852 ADD_INSN(ret, line_node, putnil);
8853 }
8854 }
8855 else {
8856 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8857 if (popped) {
8858 ADD_INSN(ret, line_node, pop);
8859 }
8860 }
8861 }
8862 return COMPILE_OK;
8863}
8864
8865static bool
8866drop_unreachable_return(LINK_ANCHOR *ret)
8867{
8868 LINK_ELEMENT *i = ret->last, *last;
8869 if (!i) return false;
8870 if (IS_TRACE(i)) i = i->prev;
8871 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8872 last = i = i->prev;
8873 if (IS_ADJUST(i)) i = i->prev;
8874 if (!IS_INSN(i)) return false;
8875 switch (INSN_OF(i)) {
8876 case BIN(leave):
8877 case BIN(jump):
8878 break;
8879 default:
8880 return false;
8881 }
8882 (ret->last = last->prev)->next = NULL;
8883 return true;
8884}
8885
8886static int
8887compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8888{
8889 CHECK(COMPILE_(ret, "nd_body", node, popped));
8890
8891 if (!popped && !all_string_result_p(node)) {
8892 const NODE *line_node = node;
8893 const unsigned int flag = VM_CALL_FCALL;
8894
8895 // Note, this dup could be removed if we are willing to change anytostring. It pops
8896 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8897 ADD_INSN(ret, line_node, dup);
8898 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8899 ADD_INSN(ret, line_node, anytostring);
8900 }
8901 return COMPILE_OK;
8902}
8903
8904static void
8905compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8906{
8907 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8908
8909 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8910 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8911}
8912
8913static LABEL *
8914qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8915{
8916 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8917 VALUE br = 0;
8918
8919 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8920 *branches = br;
8921 ADD_INSN(recv, line_node, dup);
8922 ADD_INSNL(recv, line_node, branchnil, else_label);
8923 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8924 return else_label;
8925}
8926
8927static void
8928qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8929{
8930 LABEL *end_label;
8931 if (!else_label) return;
8932 end_label = NEW_LABEL(nd_line(line_node));
8933 ADD_INSNL(ret, line_node, jump, end_label);
8934 ADD_LABEL(ret, else_label);
8935 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8936 ADD_LABEL(ret, end_label);
8937}
8938
8939static int
8940compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8941{
8942 /* optimization shortcut
8943 * "literal".freeze -> opt_str_freeze("literal")
8944 */
8945 if (get_nd_recv(node) &&
8946 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8947 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8948 get_nd_args(node) == NULL &&
8949 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8950 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8951 VALUE str = get_string_value(get_nd_recv(node));
8952 if (get_node_call_nd_mid(node) == idUMinus) {
8953 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8954 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8955 }
8956 else {
8957 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8958 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8959 }
8960 RB_OBJ_WRITTEN(iseq, Qundef, str);
8961 if (popped) {
8962 ADD_INSN(ret, line_node, pop);
8963 }
8964 return TRUE;
8965 }
8966 return FALSE;
8967}
8968
8969static int
8970iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8971{
8972 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8973}
8974
8975static const struct rb_builtin_function *
8976iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8977{
8978 int i;
8979 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8980 for (i=0; table[i].index != -1; i++) {
8981 if (strcmp(table[i].name, name) == 0) {
8982 return &table[i];
8983 }
8984 }
8985 return NULL;
8986}
8987
8988static const char *
8989iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8990{
8991 const char *name = rb_id2name(mid);
8992 static const char prefix[] = "__builtin_";
8993 const size_t prefix_len = sizeof(prefix) - 1;
8994
8995 switch (type) {
8996 case NODE_CALL:
8997 if (recv) {
8998 switch (nd_type(recv)) {
8999 case NODE_VCALL:
9000 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9001 return name;
9002 }
9003 break;
9004 case NODE_CONST:
9005 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9006 return name;
9007 }
9008 break;
9009 default: break;
9010 }
9011 }
9012 break;
9013 case NODE_VCALL:
9014 case NODE_FCALL:
9015 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9016 return &name[prefix_len];
9017 }
9018 break;
9019 default: break;
9020 }
9021 return NULL;
9022}
9023
9024static int
9025delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9026{
9027
9028 if (argc == 0) {
9029 *pstart_index = 0;
9030 return TRUE;
9031 }
9032 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9033 unsigned int start=0;
9034
9035 // local_table: [p1, p2, p3, l1, l2, l3]
9036 // arguments: [p3, l1, l2] -> 2
9037 for (start = 0;
9038 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9039 start++) {
9040 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9041
9042 for (unsigned int i=start; i-start<argc; i++) {
9043 if (IS_INSN(elem) &&
9044 INSN_OF(elem) == BIN(getlocal)) {
9045 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9046 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9047
9048 if (local_level == 0) {
9049 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9050 if (0) { // for debug
9051 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9052 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9053 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9054 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9055 }
9056 if (i == index) {
9057 elem = elem->next;
9058 continue; /* for */
9059 }
9060 else {
9061 goto next;
9062 }
9063 }
9064 else {
9065 goto fail; // level != 0 is unsupported
9066 }
9067 }
9068 else {
9069 goto fail; // insn is not a getlocal
9070 }
9071 }
9072 goto success;
9073 next:;
9074 }
9075 fail:
9076 return FALSE;
9077 success:
9078 *pstart_index = start;
9079 return TRUE;
9080 }
9081 else {
9082 return FALSE;
9083 }
9084}
9085
9086// Compile Primitive.attr! :leaf, ...
9087static int
9088compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9089{
9090 VALUE symbol;
9091 VALUE string;
9092 if (!node) goto no_arg;
9093 while (node) {
9094 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9095 const NODE *next = RNODE_LIST(node)->nd_next;
9096
9097 node = RNODE_LIST(node)->nd_head;
9098 if (!node) goto no_arg;
9099 switch (nd_type(node)) {
9100 case NODE_SYM:
9101 symbol = rb_node_sym_string_val(node);
9102 break;
9103 default:
9104 goto bad_arg;
9105 }
9106
9107 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9108
9109 string = rb_sym2str(symbol);
9110 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9111 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9112 }
9113 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9114 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9115 }
9116 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9117 iseq_set_use_block(iseq);
9118 }
9119 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9120 // Let the iseq act like a C method in backtraces
9121 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9122 }
9123 else {
9124 goto unknown_arg;
9125 }
9126 node = next;
9127 }
9128 return COMPILE_OK;
9129 no_arg:
9130 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9131 return COMPILE_NG;
9132 non_symbol_arg:
9133 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9134 return COMPILE_NG;
9135 unknown_arg:
9136 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9137 return COMPILE_NG;
9138 bad_arg:
9139 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9140}
9141
9142static int
9143compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9144{
9145 VALUE name;
9146
9147 if (!node) goto no_arg;
9148 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9149 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9150 node = RNODE_LIST(node)->nd_head;
9151 if (!node) goto no_arg;
9152 switch (nd_type(node)) {
9153 case NODE_SYM:
9154 name = rb_node_sym_string_val(node);
9155 break;
9156 default:
9157 goto bad_arg;
9158 }
9159 if (!SYMBOL_P(name)) goto non_symbol_arg;
9160 if (!popped) {
9161 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9162 }
9163 return COMPILE_OK;
9164 no_arg:
9165 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9166 return COMPILE_NG;
9167 too_many_arg:
9168 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9169 return COMPILE_NG;
9170 non_symbol_arg:
9171 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9172 rb_builtin_class_name(name));
9173 return COMPILE_NG;
9174 bad_arg:
9175 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9176}
9177
9178static NODE *
9179mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9180{
9181 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9182 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9183 return RNODE_IF(node)->nd_body;
9184 }
9185 else {
9186 rb_bug("mandatory_node: can't find mandatory node");
9187 }
9188}
9189
9190static int
9191compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9192{
9193 // arguments
9194 struct rb_args_info args = {
9195 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9196 };
9197 rb_node_args_t args_node;
9198 rb_node_init(RNODE(&args_node), NODE_ARGS);
9199 args_node.nd_ainfo = args;
9200
9201 // local table without non-mandatory parameters
9202 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9203 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9204
9205 VALUE idtmp = 0;
9206 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9207 tbl->size = table_size;
9208
9209 int i;
9210
9211 // lead parameters
9212 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9213 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9214 }
9215 // local variables
9216 for (; i<table_size; i++) {
9217 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9218 }
9219
9220 rb_node_scope_t scope_node;
9221 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9222 scope_node.nd_tbl = tbl;
9223 scope_node.nd_body = mandatory_node(iseq, node);
9224 scope_node.nd_parent = NULL;
9225 scope_node.nd_args = &args_node;
9226
9227 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9228
9229 const rb_iseq_t *mandatory_only_iseq =
9230 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9231 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9232 nd_line(line_node), NULL, 0,
9233 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9234 ISEQ_BODY(iseq)->variable.script_lines);
9235 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9236
9237 ALLOCV_END(idtmp);
9238 return COMPILE_OK;
9239}
9240
9241static int
9242compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9243 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9244{
9245 NODE *args_node = get_nd_args(node);
9246
9247 if (parent_block != NULL) {
9248 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9249 return COMPILE_NG;
9250 }
9251 else {
9252# define BUILTIN_INLINE_PREFIX "_bi"
9253 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9254 bool cconst = false;
9255 retry:;
9256 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9257
9258 if (bf == NULL) {
9259 if (strcmp("cstmt!", builtin_func) == 0 ||
9260 strcmp("cexpr!", builtin_func) == 0) {
9261 // ok
9262 }
9263 else if (strcmp("cconst!", builtin_func) == 0) {
9264 cconst = true;
9265 }
9266 else if (strcmp("cinit!", builtin_func) == 0) {
9267 // ignore
9268 return COMPILE_OK;
9269 }
9270 else if (strcmp("attr!", builtin_func) == 0) {
9271 return compile_builtin_attr(iseq, args_node);
9272 }
9273 else if (strcmp("arg!", builtin_func) == 0) {
9274 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9275 }
9276 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9277 if (popped) {
9278 rb_bug("mandatory_only? should be in if condition");
9279 }
9280 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9281 rb_bug("mandatory_only? should be put on top");
9282 }
9283
9284 ADD_INSN1(ret, line_node, putobject, Qfalse);
9285 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9286 }
9287 else if (1) {
9288 rb_bug("can't find builtin function:%s", builtin_func);
9289 }
9290 else {
9291 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9292 return COMPILE_NG;
9293 }
9294
9295 int inline_index = nd_line(node);
9296 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9297 builtin_func = inline_func;
9298 args_node = NULL;
9299 goto retry;
9300 }
9301
9302 if (cconst) {
9303 typedef VALUE(*builtin_func0)(void *, VALUE);
9304 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9305 ADD_INSN1(ret, line_node, putobject, const_val);
9306 return COMPILE_OK;
9307 }
9308
9309 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9310
9311 unsigned int flag = 0;
9312 struct rb_callinfo_kwarg *keywords = NULL;
9313 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9314
9315 if (FIX2INT(argc) != bf->argc) {
9316 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9317 builtin_func, bf->argc, FIX2INT(argc));
9318 return COMPILE_NG;
9319 }
9320
9321 unsigned int start_index;
9322 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9323 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9324 }
9325 else {
9326 ADD_SEQ(ret, args);
9327 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9328 }
9329
9330 if (popped) ADD_INSN(ret, line_node, pop);
9331 return COMPILE_OK;
9332 }
9333}
9334
9335static int
9336compile_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)
9337{
9338 /* call: obj.method(...)
9339 * fcall: func(...)
9340 * vcall: func
9341 */
9342 DECL_ANCHOR(recv);
9343 DECL_ANCHOR(args);
9344 ID mid = get_node_call_nd_mid(node);
9345 VALUE argc;
9346 unsigned int flag = 0;
9347 struct rb_callinfo_kwarg *keywords = NULL;
9348 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9349 LABEL *else_label = NULL;
9350 VALUE branches = Qfalse;
9351
9352 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9353
9354 INIT_ANCHOR(recv);
9355 INIT_ANCHOR(args);
9356
9357#if OPT_SUPPORT_JOKE
9358 if (nd_type_p(node, NODE_VCALL)) {
9359 ID id_bitblt;
9360 ID id_answer;
9361
9362 CONST_ID(id_bitblt, "bitblt");
9363 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9364
9365 if (mid == id_bitblt) {
9366 ADD_INSN(ret, line_node, bitblt);
9367 return COMPILE_OK;
9368 }
9369 else if (mid == id_answer) {
9370 ADD_INSN(ret, line_node, answer);
9371 return COMPILE_OK;
9372 }
9373 }
9374 /* only joke */
9375 {
9376 ID goto_id;
9377 ID label_id;
9378
9379 CONST_ID(goto_id, "__goto__");
9380 CONST_ID(label_id, "__label__");
9381
9382 if (nd_type_p(node, NODE_FCALL) &&
9383 (mid == goto_id || mid == label_id)) {
9384 LABEL *label;
9385 st_data_t data;
9386 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9387 VALUE label_name;
9388
9389 if (!labels_table) {
9390 labels_table = st_init_numtable();
9391 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9392 }
9393 {
9394 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9395 return COMPILE_NG;
9396 }
9397
9398 if (mid == goto_id) {
9399 ADD_INSNL(ret, line_node, jump, label);
9400 }
9401 else {
9402 ADD_LABEL(ret, label);
9403 }
9404 return COMPILE_OK;
9405 }
9406 }
9407#endif
9408
9409 const char *builtin_func;
9410 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9411 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9412 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9413 }
9414
9415 /* receiver */
9416 if (!assume_receiver) {
9417 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9418 int idx, level;
9419
9420 if (mid == idCall &&
9421 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9422 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9423 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9424 }
9425 else if (private_recv_p(node)) {
9426 ADD_INSN(recv, node, putself);
9427 flag |= VM_CALL_FCALL;
9428 }
9429 else {
9430 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9431 }
9432
9433 if (type == NODE_QCALL) {
9434 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9435 }
9436 }
9437 else if (type == NODE_FCALL || type == NODE_VCALL) {
9438 ADD_CALL_RECEIVER(recv, line_node);
9439 }
9440 }
9441
9442 /* args */
9443 if (type != NODE_VCALL) {
9444 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9445 CHECK(!NIL_P(argc));
9446 }
9447 else {
9448 argc = INT2FIX(0);
9449 }
9450
9451 ADD_SEQ(ret, recv);
9452
9453 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9454 mid == rb_intern("new") &&
9455 parent_block == NULL &&
9456 !(flag & VM_CALL_ARGS_BLOCKARG);
9457
9458 if (inline_new) {
9459 ADD_INSN(ret, node, putnil);
9460 ADD_INSN(ret, node, swap);
9461 }
9462
9463 ADD_SEQ(ret, args);
9464
9465 debugp_param("call args argc", argc);
9466 debugp_param("call method", ID2SYM(mid));
9467
9468 switch ((int)type) {
9469 case NODE_VCALL:
9470 flag |= VM_CALL_VCALL;
9471 /* VCALL is funcall, so fall through */
9472 case NODE_FCALL:
9473 flag |= VM_CALL_FCALL;
9474 }
9475
9476 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9477 ADD_INSN(ret, line_node, splatkw);
9478 }
9479
9480 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9481 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9482
9483 if (inline_new) {
9484 // Jump unless the receiver uses the "basic" implementation of "new"
9485 VALUE ci;
9486 if (flag & VM_CALL_FORWARDING) {
9487 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9488 }
9489 else {
9490 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9491 }
9492 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9493 LABEL_REF(not_basic_new);
9494
9495 // optimized path
9496 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9497 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9498
9499 ADD_LABEL(ret, not_basic_new);
9500 // Fall back to normal send
9501 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9502 ADD_INSN(ret, line_node, swap);
9503
9504 ADD_LABEL(ret, not_basic_new_finish);
9505 ADD_INSN(ret, line_node, pop);
9506 }
9507 else {
9508 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9509 }
9510
9511 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9512 if (popped) {
9513 ADD_INSN(ret, line_node, pop);
9514 }
9515 return COMPILE_OK;
9516}
9517
9518static int
9519compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9520{
9521 const int line = nd_line(node);
9522 VALUE argc;
9523 unsigned int flag = 0;
9524 int asgnflag = 0;
9525 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9526
9527 /*
9528 * a[x] (op)= y
9529 *
9530 * nil # nil
9531 * eval a # nil a
9532 * eval x # nil a x
9533 * dupn 2 # nil a x a x
9534 * send :[] # nil a x a[x]
9535 * eval y # nil a x a[x] y
9536 * send op # nil a x ret
9537 * setn 3 # ret a x ret
9538 * send []= # ret ?
9539 * pop # ret
9540 */
9541
9542 /*
9543 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9544 * NODE_OP_ASGN nd_recv
9545 * nd_args->nd_head
9546 * nd_args->nd_body
9547 * nd_mid
9548 */
9549
9550 if (!popped) {
9551 ADD_INSN(ret, node, putnil);
9552 }
9553 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9554 CHECK(asgnflag != -1);
9555 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9556 case NODE_ZLIST:
9557 argc = INT2FIX(0);
9558 break;
9559 default:
9560 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9561 CHECK(!NIL_P(argc));
9562 }
9563 int dup_argn = FIX2INT(argc) + 1;
9564 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9565 flag |= asgnflag;
9566 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9567
9568 if (id == idOROP || id == idANDOP) {
9569 /* a[x] ||= y or a[x] &&= y
9570
9571 unless/if a[x]
9572 a[x]= y
9573 else
9574 nil
9575 end
9576 */
9577 LABEL *label = NEW_LABEL(line);
9578 LABEL *lfin = NEW_LABEL(line);
9579
9580 ADD_INSN(ret, node, dup);
9581 if (id == idOROP) {
9582 ADD_INSNL(ret, node, branchif, label);
9583 }
9584 else { /* idANDOP */
9585 ADD_INSNL(ret, node, branchunless, label);
9586 }
9587 ADD_INSN(ret, node, pop);
9588
9589 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9590 if (!popped) {
9591 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9592 }
9593 if (flag & VM_CALL_ARGS_SPLAT) {
9594 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9595 ADD_INSN(ret, node, swap);
9596 ADD_INSN1(ret, node, splatarray, Qtrue);
9597 ADD_INSN(ret, node, swap);
9598 flag |= VM_CALL_ARGS_SPLAT_MUT;
9599 }
9600 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9601 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9602 }
9603 else {
9604 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9605 }
9606 ADD_INSN(ret, node, pop);
9607 ADD_INSNL(ret, node, jump, lfin);
9608 ADD_LABEL(ret, label);
9609 if (!popped) {
9610 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9611 }
9612 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9613 ADD_LABEL(ret, lfin);
9614 }
9615 else {
9616 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9617 ADD_SEND(ret, node, id, INT2FIX(1));
9618 if (!popped) {
9619 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9620 }
9621 if (flag & VM_CALL_ARGS_SPLAT) {
9622 if (flag & VM_CALL_KW_SPLAT) {
9623 ADD_INSN1(ret, node, topn, INT2FIX(2));
9624 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9625 ADD_INSN1(ret, node, splatarray, Qtrue);
9626 flag |= VM_CALL_ARGS_SPLAT_MUT;
9627 }
9628 ADD_INSN(ret, node, swap);
9629 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9630 ADD_INSN1(ret, node, setn, INT2FIX(2));
9631 ADD_INSN(ret, node, pop);
9632 }
9633 else {
9634 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9635 ADD_INSN(ret, node, swap);
9636 ADD_INSN1(ret, node, splatarray, Qtrue);
9637 ADD_INSN(ret, node, swap);
9638 flag |= VM_CALL_ARGS_SPLAT_MUT;
9639 }
9640 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9641 }
9642 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9643 }
9644 else {
9645 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9646 }
9647 ADD_INSN(ret, node, pop);
9648 }
9649 return COMPILE_OK;
9650}
9651
9652static int
9653compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9654{
9655 const int line = nd_line(node);
9656 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9657 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9658 int asgnflag;
9659 LABEL *lfin = NEW_LABEL(line);
9660 LABEL *lcfin = NEW_LABEL(line);
9661 LABEL *lskip = 0;
9662 /*
9663 class C; attr_accessor :c; end
9664 r = C.new
9665 r.a &&= v # asgn2
9666
9667 eval r # r
9668 dup # r r
9669 eval r.a # r o
9670
9671 # or
9672 dup # r o o
9673 if lcfin # r o
9674 pop # r
9675 eval v # r v
9676 swap # v r
9677 topn 1 # v r v
9678 send a= # v ?
9679 jump lfin # v ?
9680
9681 lcfin: # r o
9682 swap # o r
9683
9684 lfin: # o ?
9685 pop # o
9686
9687 # or (popped)
9688 if lcfin # r
9689 eval v # r v
9690 send a= # ?
9691 jump lfin # ?
9692
9693 lcfin: # r
9694
9695 lfin: # ?
9696 pop #
9697
9698 # and
9699 dup # r o o
9700 unless lcfin
9701 pop # r
9702 eval v # r v
9703 swap # v r
9704 topn 1 # v r v
9705 send a= # v ?
9706 jump lfin # v ?
9707
9708 # others
9709 eval v # r o v
9710 send ?? # r w
9711 send a= # w
9712
9713 */
9714
9715 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9716 CHECK(asgnflag != -1);
9717 if (RNODE_OP_ASGN2(node)->nd_aid) {
9718 lskip = NEW_LABEL(line);
9719 ADD_INSN(ret, node, dup);
9720 ADD_INSNL(ret, node, branchnil, lskip);
9721 }
9722 ADD_INSN(ret, node, dup);
9723 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9724
9725 if (atype == idOROP || atype == idANDOP) {
9726 if (!popped) {
9727 ADD_INSN(ret, node, dup);
9728 }
9729 if (atype == idOROP) {
9730 ADD_INSNL(ret, node, branchif, lcfin);
9731 }
9732 else { /* idANDOP */
9733 ADD_INSNL(ret, node, branchunless, lcfin);
9734 }
9735 if (!popped) {
9736 ADD_INSN(ret, node, pop);
9737 }
9738 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9739 if (!popped) {
9740 ADD_INSN(ret, node, swap);
9741 ADD_INSN1(ret, node, topn, INT2FIX(1));
9742 }
9743 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9744 ADD_INSNL(ret, node, jump, lfin);
9745
9746 ADD_LABEL(ret, lcfin);
9747 if (!popped) {
9748 ADD_INSN(ret, node, swap);
9749 }
9750
9751 ADD_LABEL(ret, lfin);
9752 }
9753 else {
9754 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9755 ADD_SEND(ret, node, atype, INT2FIX(1));
9756 if (!popped) {
9757 ADD_INSN(ret, node, swap);
9758 ADD_INSN1(ret, node, topn, INT2FIX(1));
9759 }
9760 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9761 }
9762 if (lskip && popped) {
9763 ADD_LABEL(ret, lskip);
9764 }
9765 ADD_INSN(ret, node, pop);
9766 if (lskip && !popped) {
9767 ADD_LABEL(ret, lskip);
9768 }
9769 return COMPILE_OK;
9770}
9771
9772static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9773
9774static int
9775compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9776{
9777 const int line = nd_line(node);
9778 LABEL *lfin = 0;
9779 LABEL *lassign = 0;
9780 ID mid;
9781
9782 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9783 case NODE_COLON3:
9784 ADD_INSN1(ret, node, putobject, rb_cObject);
9785 break;
9786 case NODE_COLON2:
9787 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9788 break;
9789 default:
9790 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9791 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9792 return COMPILE_NG;
9793 }
9794 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9795 /* cref */
9796 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9797 lassign = NEW_LABEL(line);
9798 ADD_INSN(ret, node, dup); /* cref cref */
9799 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9800 ID2SYM(mid), Qtrue); /* cref bool */
9801 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9802 }
9803 ADD_INSN(ret, node, dup); /* cref cref */
9804 ADD_INSN1(ret, node, putobject, Qtrue);
9805 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9806
9807 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9808 lfin = NEW_LABEL(line);
9809 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9810 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9811 ADD_INSNL(ret, node, branchif, lfin);
9812 else /* idANDOP */
9813 ADD_INSNL(ret, node, branchunless, lfin);
9814 /* cref [obj] */
9815 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9816 if (lassign) ADD_LABEL(ret, lassign);
9817 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9818 /* cref value */
9819 if (popped)
9820 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9821 else {
9822 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9823 ADD_INSN(ret, node, swap); /* cref value value cref */
9824 }
9825 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9826 ADD_LABEL(ret, lfin); /* cref [value] */
9827 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9828 ADD_INSN(ret, node, pop); /* [value] */
9829 }
9830 else {
9831 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9832 /* cref obj value */
9833 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9834 /* cref value */
9835 ADD_INSN(ret, node, swap); /* value cref */
9836 if (!popped) {
9837 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9838 ADD_INSN(ret, node, swap); /* value value cref */
9839 }
9840 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9841 }
9842 return COMPILE_OK;
9843}
9844
9845static int
9846compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9847{
9848 const int line = nd_line(node);
9849 LABEL *lfin = NEW_LABEL(line);
9850 LABEL *lassign;
9851
9852 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9853 LABEL *lfinish[2];
9854 lfinish[0] = lfin;
9855 lfinish[1] = 0;
9856 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9857 lassign = lfinish[1];
9858 if (!lassign) {
9859 lassign = NEW_LABEL(line);
9860 }
9861 ADD_INSNL(ret, node, branchunless, lassign);
9862 }
9863 else {
9864 lassign = NEW_LABEL(line);
9865 }
9866
9867 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9868
9869 if (!popped) {
9870 ADD_INSN(ret, node, dup);
9871 }
9872
9873 if (type == NODE_OP_ASGN_AND) {
9874 ADD_INSNL(ret, node, branchunless, lfin);
9875 }
9876 else {
9877 ADD_INSNL(ret, node, branchif, lfin);
9878 }
9879
9880 if (!popped) {
9881 ADD_INSN(ret, node, pop);
9882 }
9883
9884 ADD_LABEL(ret, lassign);
9885 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9886 ADD_LABEL(ret, lfin);
9887 return COMPILE_OK;
9888}
9889
9890static int
9891compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9892{
9893 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9894 DECL_ANCHOR(args);
9895 int argc;
9896 unsigned int flag = 0;
9897 struct rb_callinfo_kwarg *keywords = NULL;
9898 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9899 int use_block = 1;
9900
9901 INIT_ANCHOR(args);
9902 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9903
9904 if (type == NODE_SUPER) {
9905 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9906 CHECK(!NIL_P(vargc));
9907 argc = FIX2INT(vargc);
9908 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9909 ADD_INSN(args, node, splatkw);
9910 }
9911
9912 if (flag & VM_CALL_ARGS_BLOCKARG) {
9913 use_block = 0;
9914 }
9915 }
9916 else {
9917 /* NODE_ZSUPER */
9918 int i;
9919 const rb_iseq_t *liseq = body->local_iseq;
9920 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9921 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9922 int lvar_level = get_lvar_level(iseq);
9923
9924 argc = local_body->param.lead_num;
9925
9926 /* normal arguments */
9927 for (i = 0; i < local_body->param.lead_num; i++) {
9928 int idx = local_body->local_table_size - i;
9929 ADD_GETLOCAL(args, node, idx, lvar_level);
9930 }
9931
9932 /* forward ... */
9933 if (local_body->param.flags.forwardable) {
9934 flag |= VM_CALL_FORWARDING;
9935 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9936 ADD_GETLOCAL(args, node, idx, lvar_level);
9937 }
9938
9939 if (local_body->param.flags.has_opt) {
9940 /* optional arguments */
9941 int j;
9942 for (j = 0; j < local_body->param.opt_num; j++) {
9943 int idx = local_body->local_table_size - (i + j);
9944 ADD_GETLOCAL(args, node, idx, lvar_level);
9945 }
9946 i += j;
9947 argc = i;
9948 }
9949 if (local_body->param.flags.has_rest) {
9950 /* rest argument */
9951 int idx = local_body->local_table_size - local_body->param.rest_start;
9952 ADD_GETLOCAL(args, node, idx, lvar_level);
9953 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9954
9955 argc = local_body->param.rest_start + 1;
9956 flag |= VM_CALL_ARGS_SPLAT;
9957 }
9958 if (local_body->param.flags.has_post) {
9959 /* post arguments */
9960 int post_len = local_body->param.post_num;
9961 int post_start = local_body->param.post_start;
9962
9963 if (local_body->param.flags.has_rest) {
9964 int j;
9965 for (j=0; j<post_len; j++) {
9966 int idx = local_body->local_table_size - (post_start + j);
9967 ADD_GETLOCAL(args, node, idx, lvar_level);
9968 }
9969 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9970 flag |= VM_CALL_ARGS_SPLAT_MUT;
9971 /* argc is settled at above */
9972 }
9973 else {
9974 int j;
9975 for (j=0; j<post_len; j++) {
9976 int idx = local_body->local_table_size - (post_start + j);
9977 ADD_GETLOCAL(args, node, idx, lvar_level);
9978 }
9979 argc = post_len + post_start;
9980 }
9981 }
9982
9983 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9984 int local_size = local_body->local_table_size;
9985 argc++;
9986
9987 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9988
9989 if (local_body->param.flags.has_kwrest) {
9990 int idx = local_body->local_table_size - local_kwd->rest_start;
9991 ADD_GETLOCAL(args, node, idx, lvar_level);
9992 RUBY_ASSERT(local_kwd->num > 0);
9993 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9994 }
9995 else {
9996 ADD_INSN1(args, node, newhash, INT2FIX(0));
9997 }
9998 for (i = 0; i < local_kwd->num; ++i) {
9999 ID id = local_kwd->table[i];
10000 int idx = local_size - get_local_var_idx(liseq, id);
10001 ADD_INSN1(args, node, putobject, ID2SYM(id));
10002 ADD_GETLOCAL(args, node, idx, lvar_level);
10003 }
10004 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10005 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10006 }
10007 else if (local_body->param.flags.has_kwrest) {
10008 int idx = local_body->local_table_size - local_kwd->rest_start;
10009 ADD_GETLOCAL(args, node, idx, lvar_level);
10010 argc++;
10011 flag |= VM_CALL_KW_SPLAT;
10012 }
10013 }
10014
10015 if (use_block && parent_block == NULL) {
10016 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10017 }
10018
10019 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10020 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10021 ADD_INSN(ret, node, putself);
10022 ADD_SEQ(ret, args);
10023
10024 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10025
10026 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10027 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10028 }
10029 else {
10030 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10031 }
10032
10033 if (popped) {
10034 ADD_INSN(ret, node, pop);
10035 }
10036 return COMPILE_OK;
10037}
10038
10039static int
10040compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10041{
10042 DECL_ANCHOR(args);
10043 VALUE argc;
10044 unsigned int flag = 0;
10045 struct rb_callinfo_kwarg *keywords = NULL;
10046
10047 INIT_ANCHOR(args);
10048
10049 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10050 case ISEQ_TYPE_TOP:
10051 case ISEQ_TYPE_MAIN:
10052 case ISEQ_TYPE_CLASS:
10053 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10054 return COMPILE_NG;
10055 default: /* valid */;
10056 }
10057
10058 if (RNODE_YIELD(node)->nd_head) {
10059 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10060 CHECK(!NIL_P(argc));
10061 }
10062 else {
10063 argc = INT2FIX(0);
10064 }
10065
10066 ADD_SEQ(ret, args);
10067 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10068 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10069
10070 if (popped) {
10071 ADD_INSN(ret, node, pop);
10072 }
10073
10074 int level = 0;
10075 const rb_iseq_t *tmp_iseq = iseq;
10076 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10077 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10078 }
10079 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10080
10081 return COMPILE_OK;
10082}
10083
10084static int
10085compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10086{
10087 DECL_ANCHOR(recv);
10088 DECL_ANCHOR(val);
10089
10090 INIT_ANCHOR(recv);
10091 INIT_ANCHOR(val);
10092 switch ((int)type) {
10093 case NODE_MATCH:
10094 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10095 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10096 INT2FIX(0));
10097 break;
10098 case NODE_MATCH2:
10099 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10100 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10101 break;
10102 case NODE_MATCH3:
10103 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10104 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10105 break;
10106 }
10107
10108 ADD_SEQ(ret, recv);
10109 ADD_SEQ(ret, val);
10110 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10111
10112 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10113 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10114 }
10115
10116 if (popped) {
10117 ADD_INSN(ret, node, pop);
10118 }
10119 return COMPILE_OK;
10120}
10121
10122static int
10123compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10124{
10125 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10126 /* constant */
10127 VALUE segments;
10128 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10129 (segments = collect_const_segments(iseq, node))) {
10130 ISEQ_BODY(iseq)->ic_size++;
10131 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10132 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10133 }
10134 else {
10135 /* constant */
10136 DECL_ANCHOR(pref);
10137 DECL_ANCHOR(body);
10138
10139 INIT_ANCHOR(pref);
10140 INIT_ANCHOR(body);
10141 CHECK(compile_const_prefix(iseq, node, pref, body));
10142 if (LIST_INSN_SIZE_ZERO(pref)) {
10143 ADD_INSN(ret, node, putnil);
10144 ADD_SEQ(ret, body);
10145 }
10146 else {
10147 ADD_SEQ(ret, pref);
10148 ADD_SEQ(ret, body);
10149 }
10150 }
10151 }
10152 else {
10153 /* function call */
10154 ADD_CALL_RECEIVER(ret, node);
10155 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10156 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10157 }
10158 if (popped) {
10159 ADD_INSN(ret, node, pop);
10160 }
10161 return COMPILE_OK;
10162}
10163
10164static int
10165compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10166{
10167 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10168
10169 /* add cache insn */
10170 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10171 ISEQ_BODY(iseq)->ic_size++;
10172 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10173 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10174 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10175 }
10176 else {
10177 ADD_INSN1(ret, node, putobject, rb_cObject);
10178 ADD_INSN1(ret, node, putobject, Qtrue);
10179 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10180 }
10181
10182 if (popped) {
10183 ADD_INSN(ret, node, pop);
10184 }
10185 return COMPILE_OK;
10186}
10187
10188static int
10189compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10190{
10191 VALUE flag = INT2FIX(excl);
10192 const NODE *b = RNODE_DOT2(node)->nd_beg;
10193 const NODE *e = RNODE_DOT2(node)->nd_end;
10194
10195 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10196 if (!popped) {
10197 VALUE bv = optimized_range_item(b);
10198 VALUE ev = optimized_range_item(e);
10199 VALUE val = rb_range_new(bv, ev, excl);
10200 ADD_INSN1(ret, node, putobject, val);
10201 RB_OBJ_WRITTEN(iseq, Qundef, val);
10202 }
10203 }
10204 else {
10205 CHECK(COMPILE_(ret, "min", b, popped));
10206 CHECK(COMPILE_(ret, "max", e, popped));
10207 if (!popped) {
10208 ADD_INSN1(ret, node, newrange, flag);
10209 }
10210 }
10211 return COMPILE_OK;
10212}
10213
10214static int
10215compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10216{
10217 if (!popped) {
10218 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10219 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10220 }
10221 else {
10222 const rb_iseq_t *ip = iseq;
10223 int level = 0;
10224 while (ip) {
10225 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10226 break;
10227 }
10228 ip = ISEQ_BODY(ip)->parent_iseq;
10229 level++;
10230 }
10231 if (ip) {
10232 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10233 }
10234 else {
10235 ADD_INSN(ret, node, putnil);
10236 }
10237 }
10238 }
10239 return COMPILE_OK;
10240}
10241
10242static int
10243compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10244{
10245 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10246 LABEL *end_label = NEW_LABEL(nd_line(node));
10247 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10248
10249 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10250 /* required argument. do nothing */
10251 COMPILE_ERROR(ERROR_ARGS "unreachable");
10252 return COMPILE_NG;
10253 }
10254 else if (nd_type_p(default_value, NODE_SYM) ||
10255 nd_type_p(default_value, NODE_REGX) ||
10256 nd_type_p(default_value, NODE_LINE) ||
10257 nd_type_p(default_value, NODE_INTEGER) ||
10258 nd_type_p(default_value, NODE_FLOAT) ||
10259 nd_type_p(default_value, NODE_RATIONAL) ||
10260 nd_type_p(default_value, NODE_IMAGINARY) ||
10261 nd_type_p(default_value, NODE_NIL) ||
10262 nd_type_p(default_value, NODE_TRUE) ||
10263 nd_type_p(default_value, NODE_FALSE)) {
10264 COMPILE_ERROR(ERROR_ARGS "unreachable");
10265 return COMPILE_NG;
10266 }
10267 else {
10268 /* if keywordcheck(_kw_bits, nth_keyword)
10269 * kw = default_value
10270 * end
10271 */
10272 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10273 int keyword_idx = body->param.keyword->num;
10274
10275 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10276 ADD_INSNL(ret, node, branchif, end_label);
10277 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10278 ADD_LABEL(ret, end_label);
10279 }
10280 return COMPILE_OK;
10281}
10282
10283static int
10284compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10285{
10286 DECL_ANCHOR(recv);
10287 DECL_ANCHOR(args);
10288 unsigned int flag = 0;
10289 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10290 VALUE argc;
10291 LABEL *else_label = NULL;
10292 VALUE branches = Qfalse;
10293
10294 INIT_ANCHOR(recv);
10295 INIT_ANCHOR(args);
10296 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10297 CHECK(!NIL_P(argc));
10298
10299 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10300 CHECK(asgnflag != -1);
10301 flag |= (unsigned int)asgnflag;
10302
10303 debugp_param("argc", argc);
10304 debugp_param("nd_mid", ID2SYM(mid));
10305
10306 if (!rb_is_attrset_id(mid)) {
10307 /* safe nav attr */
10308 mid = rb_id_attrset(mid);
10309 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10310 }
10311 if (!popped) {
10312 ADD_INSN(ret, node, putnil);
10313 ADD_SEQ(ret, recv);
10314 ADD_SEQ(ret, args);
10315
10316 if (flag & VM_CALL_ARGS_SPLAT) {
10317 ADD_INSN(ret, node, dup);
10318 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10319 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10320 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10321 ADD_INSN (ret, node, pop);
10322 }
10323 else {
10324 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10325 }
10326 }
10327 else {
10328 ADD_SEQ(ret, recv);
10329 ADD_SEQ(ret, args);
10330 }
10331 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10332 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10333 ADD_INSN(ret, node, pop);
10334 return COMPILE_OK;
10335}
10336
10337static int
10338compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10339{
10340 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10341 ADD_SEQ(ret, sub);
10342
10343 if (copy) {
10344 /*
10345 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10346 * NEW_LIST(value, loc), loc);
10347 */
10348 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10349 }
10350 else {
10351 /*
10352 * NEW_CALL(fcore, rb_intern("make_shareable"),
10353 * NEW_LIST(value, loc), loc);
10354 */
10355 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10356 }
10357
10358 return COMPILE_OK;
10359}
10360
10361static VALUE
10362node_const_decl_val(const NODE *node)
10363{
10364 VALUE path;
10365 switch (nd_type(node)) {
10366 case NODE_CDECL:
10367 if (RNODE_CDECL(node)->nd_vid) {
10368 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10369 goto end;
10370 }
10371 else {
10372 node = RNODE_CDECL(node)->nd_else;
10373 }
10374 break;
10375 case NODE_COLON2:
10376 break;
10377 case NODE_COLON3:
10378 // ::Const
10379 path = rb_str_new_cstr("::");
10380 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10381 goto end;
10382 default:
10383 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10385 }
10386
10387 path = rb_ary_new();
10388 if (node) {
10389 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10390 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10391 }
10392 if (node && nd_type_p(node, NODE_CONST)) {
10393 // Const::Name
10394 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10395 }
10396 else if (node && nd_type_p(node, NODE_COLON3)) {
10397 // ::Const::Name
10398 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10399 rb_ary_push(path, rb_str_new(0, 0));
10400 }
10401 else {
10402 // expression::Name
10403 rb_ary_push(path, rb_str_new_cstr("..."));
10404 }
10405 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10406 }
10407 end:
10408 path = rb_fstring(path);
10409 return path;
10410}
10411
10412static VALUE
10413const_decl_path(NODE *dest)
10414{
10415 VALUE path = Qnil;
10416 if (!nd_type_p(dest, NODE_CALL)) {
10417 path = node_const_decl_val(dest);
10418 }
10419 return path;
10420}
10421
10422static int
10423compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10424{
10425 /*
10426 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10427 */
10428 VALUE path = const_decl_path(dest);
10429 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10430 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10431 ADD_INSN1(ret, value, putobject, path);
10432 RB_OBJ_WRITTEN(iseq, Qundef, path);
10433 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10434
10435 return COMPILE_OK;
10436}
10437
10438#ifndef SHAREABLE_BARE_EXPRESSION
10439#define SHAREABLE_BARE_EXPRESSION 1
10440#endif
10441
10442static int
10443compile_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)
10444{
10445# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10446 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10447 VALUE lit = Qnil;
10448 DECL_ANCHOR(anchor);
10449
10450 enum node_type type = node ? nd_type(node) : NODE_NIL;
10451 switch (type) {
10452 case NODE_TRUE:
10453 *value_p = Qtrue;
10454 goto compile;
10455 case NODE_FALSE:
10456 *value_p = Qfalse;
10457 goto compile;
10458 case NODE_NIL:
10459 *value_p = Qnil;
10460 goto compile;
10461 case NODE_SYM:
10462 *value_p = rb_node_sym_string_val(node);
10463 goto compile;
10464 case NODE_REGX:
10465 *value_p = rb_node_regx_string_val(node);
10466 goto compile;
10467 case NODE_LINE:
10468 *value_p = rb_node_line_lineno_val(node);
10469 goto compile;
10470 case NODE_INTEGER:
10471 *value_p = rb_node_integer_literal_val(node);
10472 goto compile;
10473 case NODE_FLOAT:
10474 *value_p = rb_node_float_literal_val(node);
10475 goto compile;
10476 case NODE_RATIONAL:
10477 *value_p = rb_node_rational_literal_val(node);
10478 goto compile;
10479 case NODE_IMAGINARY:
10480 *value_p = rb_node_imaginary_literal_val(node);
10481 goto compile;
10482 case NODE_ENCODING:
10483 *value_p = rb_node_encoding_val(node);
10484
10485 compile:
10486 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10487 *shareable_literal_p = 1;
10488 return COMPILE_OK;
10489
10490 case NODE_DSTR:
10491 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10492 if (shareable == rb_parser_shareable_literal) {
10493 /*
10494 * NEW_CALL(node, idUMinus, 0, loc);
10495 *
10496 * -"#{var}"
10497 */
10498 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10499 }
10500 *value_p = Qundef;
10501 *shareable_literal_p = 1;
10502 return COMPILE_OK;
10503
10504 case NODE_STR:{
10505 VALUE lit = rb_node_str_string_val(node);
10506 ADD_INSN1(ret, node, putobject, lit);
10507 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10508 *value_p = lit;
10509 *shareable_literal_p = 1;
10510
10511 return COMPILE_OK;
10512 }
10513
10514 case NODE_FILE:{
10515 VALUE lit = rb_node_file_path_val(node);
10516 ADD_INSN1(ret, node, putobject, lit);
10517 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10518 *value_p = lit;
10519 *shareable_literal_p = 1;
10520
10521 return COMPILE_OK;
10522 }
10523
10524 case NODE_ZLIST:{
10525 VALUE lit = rb_ary_new();
10526 OBJ_FREEZE(lit);
10527 ADD_INSN1(ret, node, putobject, lit);
10528 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10529 *value_p = lit;
10530 *shareable_literal_p = 1;
10531
10532 return COMPILE_OK;
10533 }
10534
10535 case NODE_LIST:{
10536 INIT_ANCHOR(anchor);
10537 lit = rb_ary_new();
10538 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10539 VALUE val;
10540 int shareable_literal_p2;
10541 NODE *elt = RNODE_LIST(n)->nd_head;
10542 if (elt) {
10543 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10544 if (shareable_literal_p2) {
10545 /* noop */
10546 }
10547 else if (RTEST(lit)) {
10548 rb_ary_clear(lit);
10549 lit = Qfalse;
10550 }
10551 }
10552 if (RTEST(lit)) {
10553 if (!UNDEF_P(val)) {
10554 rb_ary_push(lit, val);
10555 }
10556 else {
10557 rb_ary_clear(lit);
10558 lit = Qnil; /* make shareable at runtime */
10559 }
10560 }
10561 }
10562 break;
10563 }
10564 case NODE_HASH:{
10565 if (!RNODE_HASH(node)->nd_brace) {
10566 *value_p = Qundef;
10567 *shareable_literal_p = 0;
10568 return COMPILE_OK;
10569 }
10570 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10571 if (!RNODE_LIST(n)->nd_head) {
10572 // If the hash node have a keyword splat, fall back to the default case.
10573 goto compile_shareable;
10574 }
10575 }
10576
10577 INIT_ANCHOR(anchor);
10578 lit = rb_hash_new();
10579 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10580 VALUE key_val = 0;
10581 VALUE value_val = 0;
10582 int shareable_literal_p2;
10583 NODE *key = RNODE_LIST(n)->nd_head;
10584 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10585 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10586 if (shareable_literal_p2) {
10587 /* noop */
10588 }
10589 else if (RTEST(lit)) {
10590 rb_hash_clear(lit);
10591 lit = Qfalse;
10592 }
10593 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10594 if (shareable_literal_p2) {
10595 /* noop */
10596 }
10597 else if (RTEST(lit)) {
10598 rb_hash_clear(lit);
10599 lit = Qfalse;
10600 }
10601 if (RTEST(lit)) {
10602 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10603 rb_hash_aset(lit, key_val, value_val);
10604 }
10605 else {
10606 rb_hash_clear(lit);
10607 lit = Qnil; /* make shareable at runtime */
10608 }
10609 }
10610 }
10611 break;
10612 }
10613
10614 default:
10615
10616 compile_shareable:
10617 if (shareable == rb_parser_shareable_literal &&
10618 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10619 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10620 *value_p = Qundef;
10621 *shareable_literal_p = 1;
10622 return COMPILE_OK;
10623 }
10624 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10625 *value_p = Qundef;
10626 *shareable_literal_p = 0;
10627 return COMPILE_OK;
10628 }
10629
10630 /* Array or Hash that does not have keyword splat */
10631 if (!lit) {
10632 if (nd_type(node) == NODE_LIST) {
10633 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10634 }
10635 else if (nd_type(node) == NODE_HASH) {
10636 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10637 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10638 }
10639 *value_p = Qundef;
10640 *shareable_literal_p = 0;
10641 ADD_SEQ(ret, anchor);
10642 return COMPILE_OK;
10643 }
10644 if (NIL_P(lit)) {
10645 // if shareable_literal, all elements should have been ensured
10646 // as shareable
10647 if (nd_type(node) == NODE_LIST) {
10648 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10649 }
10650 else if (nd_type(node) == NODE_HASH) {
10651 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10652 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10653 }
10654 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10655 *value_p = Qundef;
10656 *shareable_literal_p = 1;
10657 }
10658 else {
10660 ADD_INSN1(ret, node, putobject, val);
10661 RB_OBJ_WRITTEN(iseq, Qundef, val);
10662 *value_p = val;
10663 *shareable_literal_p = 1;
10664 }
10665
10666 return COMPILE_OK;
10667}
10668
10669static int
10670compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10671{
10672 int literal_p = 0;
10673 VALUE val;
10674 DECL_ANCHOR(anchor);
10675 INIT_ANCHOR(anchor);
10676
10677 switch (shareable) {
10678 case rb_parser_shareable_none:
10679 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10680 return COMPILE_OK;
10681
10682 case rb_parser_shareable_literal:
10683 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10684 ADD_SEQ(ret, anchor);
10685 return COMPILE_OK;
10686
10687 case rb_parser_shareable_copy:
10688 case rb_parser_shareable_everything:
10689 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10690 if (!literal_p) {
10691 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10692 }
10693 else {
10694 ADD_SEQ(ret, anchor);
10695 }
10696 return COMPILE_OK;
10697 default:
10698 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10699 }
10700}
10701
10702static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10710static int
10711iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10712{
10713 if (node == 0) {
10714 if (!popped) {
10715 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10716 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10717 debugs("node: NODE_NIL(implicit)\n");
10718 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10719 }
10720 return COMPILE_OK;
10721 }
10722 return iseq_compile_each0(iseq, ret, node, popped);
10723}
10724
10725static int
10726iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10727{
10728 const int line = (int)nd_line(node);
10729 const enum node_type type = nd_type(node);
10730 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10731
10732 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10733 /* ignore */
10734 }
10735 else {
10736 if (nd_fl_newline(node)) {
10737 int event = RUBY_EVENT_LINE;
10738 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10739 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10740 event |= RUBY_EVENT_COVERAGE_LINE;
10741 }
10742 ADD_TRACE(ret, event);
10743 }
10744 }
10745
10746 debug_node_start(node);
10747#undef BEFORE_RETURN
10748#define BEFORE_RETURN debug_node_end()
10749
10750 switch (type) {
10751 case NODE_BLOCK:
10752 CHECK(compile_block(iseq, ret, node, popped));
10753 break;
10754 case NODE_IF:
10755 case NODE_UNLESS:
10756 CHECK(compile_if(iseq, ret, node, popped, type));
10757 break;
10758 case NODE_CASE:
10759 CHECK(compile_case(iseq, ret, node, popped));
10760 break;
10761 case NODE_CASE2:
10762 CHECK(compile_case2(iseq, ret, node, popped));
10763 break;
10764 case NODE_CASE3:
10765 CHECK(compile_case3(iseq, ret, node, popped));
10766 break;
10767 case NODE_WHILE:
10768 case NODE_UNTIL:
10769 CHECK(compile_loop(iseq, ret, node, popped, type));
10770 break;
10771 case NODE_FOR:
10772 case NODE_ITER:
10773 CHECK(compile_iter(iseq, ret, node, popped));
10774 break;
10775 case NODE_FOR_MASGN:
10776 CHECK(compile_for_masgn(iseq, ret, node, popped));
10777 break;
10778 case NODE_BREAK:
10779 CHECK(compile_break(iseq, ret, node, popped));
10780 break;
10781 case NODE_NEXT:
10782 CHECK(compile_next(iseq, ret, node, popped));
10783 break;
10784 case NODE_REDO:
10785 CHECK(compile_redo(iseq, ret, node, popped));
10786 break;
10787 case NODE_RETRY:
10788 CHECK(compile_retry(iseq, ret, node, popped));
10789 break;
10790 case NODE_BEGIN:{
10791 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10792 break;
10793 }
10794 case NODE_RESCUE:
10795 CHECK(compile_rescue(iseq, ret, node, popped));
10796 break;
10797 case NODE_RESBODY:
10798 CHECK(compile_resbody(iseq, ret, node, popped));
10799 break;
10800 case NODE_ENSURE:
10801 CHECK(compile_ensure(iseq, ret, node, popped));
10802 break;
10803
10804 case NODE_AND:
10805 case NODE_OR:{
10806 LABEL *end_label = NEW_LABEL(line);
10807 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10808 if (!popped) {
10809 ADD_INSN(ret, node, dup);
10810 }
10811 if (type == NODE_AND) {
10812 ADD_INSNL(ret, node, branchunless, end_label);
10813 }
10814 else {
10815 ADD_INSNL(ret, node, branchif, end_label);
10816 }
10817 if (!popped) {
10818 ADD_INSN(ret, node, pop);
10819 }
10820 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10821 ADD_LABEL(ret, end_label);
10822 break;
10823 }
10824
10825 case NODE_MASGN:{
10826 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10827 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10828 compile_massign(iseq, ret, node, popped);
10829 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10830 break;
10831 }
10832
10833 case NODE_LASGN:{
10834 ID id = RNODE_LASGN(node)->nd_vid;
10835 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10836
10837 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10838 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10839
10840 if (!popped) {
10841 ADD_INSN(ret, node, dup);
10842 }
10843 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10844 break;
10845 }
10846 case NODE_DASGN: {
10847 int idx, lv, ls;
10848 ID id = RNODE_DASGN(node)->nd_vid;
10849 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10850 debugi("dassn id", rb_id2str(id) ? id : '*');
10851
10852 if (!popped) {
10853 ADD_INSN(ret, node, dup);
10854 }
10855
10856 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10857
10858 if (idx < 0) {
10859 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10860 rb_id2str(id));
10861 goto ng;
10862 }
10863 ADD_SETLOCAL(ret, node, ls - idx, lv);
10864 break;
10865 }
10866 case NODE_GASGN:{
10867 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10868
10869 if (!popped) {
10870 ADD_INSN(ret, node, dup);
10871 }
10872 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10873 break;
10874 }
10875 case NODE_IASGN:{
10876 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10877 if (!popped) {
10878 ADD_INSN(ret, node, dup);
10879 }
10880 ADD_INSN2(ret, node, setinstancevariable,
10881 ID2SYM(RNODE_IASGN(node)->nd_vid),
10882 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10883 break;
10884 }
10885 case NODE_CDECL:{
10886 if (RNODE_CDECL(node)->nd_vid) {
10887 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10888
10889 if (!popped) {
10890 ADD_INSN(ret, node, dup);
10891 }
10892
10893 ADD_INSN1(ret, node, putspecialobject,
10894 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10895 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10896 }
10897 else {
10898 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10899 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10900 ADD_INSN(ret, node, swap);
10901
10902 if (!popped) {
10903 ADD_INSN1(ret, node, topn, INT2FIX(1));
10904 ADD_INSN(ret, node, swap);
10905 }
10906
10907 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10908 }
10909 break;
10910 }
10911 case NODE_CVASGN:{
10912 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10913 if (!popped) {
10914 ADD_INSN(ret, node, dup);
10915 }
10916 ADD_INSN2(ret, node, setclassvariable,
10917 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10918 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10919 break;
10920 }
10921 case NODE_OP_ASGN1:
10922 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10923 break;
10924 case NODE_OP_ASGN2:
10925 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10926 break;
10927 case NODE_OP_CDECL:
10928 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10929 break;
10930 case NODE_OP_ASGN_AND:
10931 case NODE_OP_ASGN_OR:
10932 CHECK(compile_op_log(iseq, ret, node, popped, type));
10933 break;
10934 case NODE_CALL: /* obj.foo */
10935 case NODE_OPCALL: /* foo[] */
10936 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10937 break;
10938 }
10939 case NODE_QCALL: /* obj&.foo */
10940 case NODE_FCALL: /* foo() */
10941 case NODE_VCALL: /* foo (variable or call) */
10942 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10943 goto ng;
10944 }
10945 break;
10946 case NODE_SUPER:
10947 case NODE_ZSUPER:
10948 CHECK(compile_super(iseq, ret, node, popped, type));
10949 break;
10950 case NODE_LIST:{
10951 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10952 break;
10953 }
10954 case NODE_ZLIST:{
10955 if (!popped) {
10956 ADD_INSN1(ret, node, newarray, INT2FIX(0));
10957 }
10958 break;
10959 }
10960 case NODE_HASH:
10961 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10962 break;
10963 case NODE_RETURN:
10964 CHECK(compile_return(iseq, ret, node, popped));
10965 break;
10966 case NODE_YIELD:
10967 CHECK(compile_yield(iseq, ret, node, popped));
10968 break;
10969 case NODE_LVAR:{
10970 if (!popped) {
10971 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10972 }
10973 break;
10974 }
10975 case NODE_DVAR:{
10976 int lv, idx, ls;
10977 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
10978 if (!popped) {
10979 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10980 if (idx < 0) {
10981 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
10982 rb_id2str(RNODE_DVAR(node)->nd_vid));
10983 goto ng;
10984 }
10985 ADD_GETLOCAL(ret, node, ls - idx, lv);
10986 }
10987 break;
10988 }
10989 case NODE_GVAR:{
10990 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
10991 if (popped) {
10992 ADD_INSN(ret, node, pop);
10993 }
10994 break;
10995 }
10996 case NODE_IVAR:{
10997 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
10998 if (!popped) {
10999 ADD_INSN2(ret, node, getinstancevariable,
11000 ID2SYM(RNODE_IVAR(node)->nd_vid),
11001 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11002 }
11003 break;
11004 }
11005 case NODE_CONST:{
11006 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11007
11008 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11009 body->ic_size++;
11010 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11011 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11012 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11013 }
11014 else {
11015 ADD_INSN(ret, node, putnil);
11016 ADD_INSN1(ret, node, putobject, Qtrue);
11017 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11018 }
11019
11020 if (popped) {
11021 ADD_INSN(ret, node, pop);
11022 }
11023 break;
11024 }
11025 case NODE_CVAR:{
11026 if (!popped) {
11027 ADD_INSN2(ret, node, getclassvariable,
11028 ID2SYM(RNODE_CVAR(node)->nd_vid),
11029 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11030 }
11031 break;
11032 }
11033 case NODE_NTH_REF:{
11034 if (!popped) {
11035 if (!RNODE_NTH_REF(node)->nd_nth) {
11036 ADD_INSN(ret, node, putnil);
11037 break;
11038 }
11039 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11040 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11041 }
11042 break;
11043 }
11044 case NODE_BACK_REF:{
11045 if (!popped) {
11046 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11047 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11048 }
11049 break;
11050 }
11051 case NODE_MATCH:
11052 case NODE_MATCH2:
11053 case NODE_MATCH3:
11054 CHECK(compile_match(iseq, ret, node, popped, type));
11055 break;
11056 case NODE_SYM:{
11057 if (!popped) {
11058 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11059 }
11060 break;
11061 }
11062 case NODE_LINE:{
11063 if (!popped) {
11064 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11065 }
11066 break;
11067 }
11068 case NODE_ENCODING:{
11069 if (!popped) {
11070 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11071 }
11072 break;
11073 }
11074 case NODE_INTEGER:{
11075 VALUE lit = rb_node_integer_literal_val(node);
11076 debugp_param("integer", lit);
11077 if (!popped) {
11078 ADD_INSN1(ret, node, putobject, lit);
11079 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11080 }
11081 break;
11082 }
11083 case NODE_FLOAT:{
11084 VALUE lit = rb_node_float_literal_val(node);
11085 debugp_param("float", lit);
11086 if (!popped) {
11087 ADD_INSN1(ret, node, putobject, lit);
11088 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11089 }
11090 break;
11091 }
11092 case NODE_RATIONAL:{
11093 VALUE lit = rb_node_rational_literal_val(node);
11094 debugp_param("rational", lit);
11095 if (!popped) {
11096 ADD_INSN1(ret, node, putobject, lit);
11097 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11098 }
11099 break;
11100 }
11101 case NODE_IMAGINARY:{
11102 VALUE lit = rb_node_imaginary_literal_val(node);
11103 debugp_param("imaginary", lit);
11104 if (!popped) {
11105 ADD_INSN1(ret, node, putobject, lit);
11106 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11107 }
11108 break;
11109 }
11110 case NODE_FILE:
11111 case NODE_STR:{
11112 debugp_param("nd_lit", get_string_value(node));
11113 if (!popped) {
11114 VALUE lit = get_string_value(node);
11115 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11116 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11117 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11118 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11119 }
11120 switch (option->frozen_string_literal) {
11121 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11122 ADD_INSN1(ret, node, putchilledstring, lit);
11123 break;
11124 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11125 ADD_INSN1(ret, node, putstring, lit);
11126 break;
11127 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11128 ADD_INSN1(ret, node, putobject, lit);
11129 break;
11130 default:
11131 rb_bug("invalid frozen_string_literal");
11132 }
11133 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11134 }
11135 break;
11136 }
11137 case NODE_DSTR:{
11138 compile_dstr(iseq, ret, node);
11139
11140 if (popped) {
11141 ADD_INSN(ret, node, pop);
11142 }
11143 break;
11144 }
11145 case NODE_XSTR:{
11146 ADD_CALL_RECEIVER(ret, node);
11147 VALUE str = rb_node_str_string_val(node);
11148 ADD_INSN1(ret, node, putobject, str);
11149 RB_OBJ_WRITTEN(iseq, Qundef, str);
11150 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11151
11152 if (popped) {
11153 ADD_INSN(ret, node, pop);
11154 }
11155 break;
11156 }
11157 case NODE_DXSTR:{
11158 ADD_CALL_RECEIVER(ret, node);
11159 compile_dstr(iseq, ret, node);
11160 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11161
11162 if (popped) {
11163 ADD_INSN(ret, node, pop);
11164 }
11165 break;
11166 }
11167 case NODE_EVSTR:
11168 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11169 break;
11170 case NODE_REGX:{
11171 if (!popped) {
11172 VALUE lit = rb_node_regx_string_val(node);
11173 ADD_INSN1(ret, node, putobject, lit);
11174 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11175 }
11176 break;
11177 }
11178 case NODE_DREGX:
11179 compile_dregx(iseq, ret, node, popped);
11180 break;
11181 case NODE_ONCE:{
11182 int ic_index = body->ise_size++;
11183 const rb_iseq_t *block_iseq;
11184 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11185
11186 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11187 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11188
11189 if (popped) {
11190 ADD_INSN(ret, node, pop);
11191 }
11192 break;
11193 }
11194 case NODE_ARGSCAT:{
11195 if (popped) {
11196 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11197 ADD_INSN1(ret, node, splatarray, Qfalse);
11198 ADD_INSN(ret, node, pop);
11199 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11200 ADD_INSN1(ret, node, splatarray, Qfalse);
11201 ADD_INSN(ret, node, pop);
11202 }
11203 else {
11204 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11205 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11206 if (nd_type_p(body_node, NODE_LIST)) {
11207 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11208 }
11209 else {
11210 CHECK(COMPILE(ret, "argscat body", body_node));
11211 ADD_INSN(ret, node, concattoarray);
11212 }
11213 }
11214 break;
11215 }
11216 case NODE_ARGSPUSH:{
11217 if (popped) {
11218 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11219 ADD_INSN1(ret, node, splatarray, Qfalse);
11220 ADD_INSN(ret, node, pop);
11221 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11222 }
11223 else {
11224 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11225 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11226 if (keyword_node_p(body_node)) {
11227 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11228 ADD_INSN(ret, node, pushtoarraykwsplat);
11229 }
11230 else if (static_literal_node_p(body_node, iseq, false)) {
11231 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11232 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11233 }
11234 else {
11235 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11236 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11237 }
11238 }
11239 break;
11240 }
11241 case NODE_SPLAT:{
11242 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11243 ADD_INSN1(ret, node, splatarray, Qtrue);
11244
11245 if (popped) {
11246 ADD_INSN(ret, node, pop);
11247 }
11248 break;
11249 }
11250 case NODE_DEFN:{
11251 ID mid = RNODE_DEFN(node)->nd_mid;
11252 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11253 rb_id2str(mid),
11254 ISEQ_TYPE_METHOD, line);
11255
11256 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11257 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11258 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11259
11260 if (!popped) {
11261 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11262 }
11263
11264 break;
11265 }
11266 case NODE_DEFS:{
11267 ID mid = RNODE_DEFS(node)->nd_mid;
11268 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11269 rb_id2str(mid),
11270 ISEQ_TYPE_METHOD, line);
11271
11272 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11273 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11274 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11275 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11276
11277 if (!popped) {
11278 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11279 }
11280 break;
11281 }
11282 case NODE_ALIAS:{
11283 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11284 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11285 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11286 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11287 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11288
11289 if (popped) {
11290 ADD_INSN(ret, node, pop);
11291 }
11292 break;
11293 }
11294 case NODE_VALIAS:{
11295 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11296 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11297 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11298 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11299
11300 if (popped) {
11301 ADD_INSN(ret, node, pop);
11302 }
11303 break;
11304 }
11305 case NODE_UNDEF:{
11306 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11307
11308 for (long i = 0; i < ary->len; i++) {
11309 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11310 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11311 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11312 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11313
11314 if (i < ary->len - 1) {
11315 ADD_INSN(ret, node, pop);
11316 }
11317 }
11318
11319 if (popped) {
11320 ADD_INSN(ret, node, pop);
11321 }
11322 break;
11323 }
11324 case NODE_CLASS:{
11325 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11326 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11327 ISEQ_TYPE_CLASS, line);
11328 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11329 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11330 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11331
11332 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11333 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11334 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11335
11336 if (popped) {
11337 ADD_INSN(ret, node, pop);
11338 }
11339 break;
11340 }
11341 case NODE_MODULE:{
11342 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11343 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11344 ISEQ_TYPE_CLASS, line);
11345 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11346 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11347
11348 ADD_INSN (ret, node, putnil); /* dummy */
11349 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11350 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11351
11352 if (popped) {
11353 ADD_INSN(ret, node, pop);
11354 }
11355 break;
11356 }
11357 case NODE_SCLASS:{
11358 ID singletonclass;
11359 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11360 ISEQ_TYPE_CLASS, line);
11361
11362 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11363 ADD_INSN (ret, node, putnil);
11364 CONST_ID(singletonclass, "singletonclass");
11365 ADD_INSN3(ret, node, defineclass,
11366 ID2SYM(singletonclass), singleton_class,
11367 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11368 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11369
11370 if (popped) {
11371 ADD_INSN(ret, node, pop);
11372 }
11373 break;
11374 }
11375 case NODE_COLON2:
11376 CHECK(compile_colon2(iseq, ret, node, popped));
11377 break;
11378 case NODE_COLON3:
11379 CHECK(compile_colon3(iseq, ret, node, popped));
11380 break;
11381 case NODE_DOT2:
11382 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11383 break;
11384 case NODE_DOT3:
11385 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11386 break;
11387 case NODE_FLIP2:
11388 case NODE_FLIP3:{
11389 LABEL *lend = NEW_LABEL(line);
11390 LABEL *ltrue = NEW_LABEL(line);
11391 LABEL *lfalse = NEW_LABEL(line);
11392 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11393 ltrue, lfalse));
11394 ADD_LABEL(ret, ltrue);
11395 ADD_INSN1(ret, node, putobject, Qtrue);
11396 ADD_INSNL(ret, node, jump, lend);
11397 ADD_LABEL(ret, lfalse);
11398 ADD_INSN1(ret, node, putobject, Qfalse);
11399 ADD_LABEL(ret, lend);
11400 break;
11401 }
11402 case NODE_SELF:{
11403 if (!popped) {
11404 ADD_INSN(ret, node, putself);
11405 }
11406 break;
11407 }
11408 case NODE_NIL:{
11409 if (!popped) {
11410 ADD_INSN(ret, node, putnil);
11411 }
11412 break;
11413 }
11414 case NODE_TRUE:{
11415 if (!popped) {
11416 ADD_INSN1(ret, node, putobject, Qtrue);
11417 }
11418 break;
11419 }
11420 case NODE_FALSE:{
11421 if (!popped) {
11422 ADD_INSN1(ret, node, putobject, Qfalse);
11423 }
11424 break;
11425 }
11426 case NODE_ERRINFO:
11427 CHECK(compile_errinfo(iseq, ret, node, popped));
11428 break;
11429 case NODE_DEFINED:
11430 if (!popped) {
11431 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11432 }
11433 break;
11434 case NODE_POSTEXE:{
11435 /* compiled to:
11436 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11437 */
11438 int is_index = body->ise_size++;
11440 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11441 const rb_iseq_t *once_iseq =
11442 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11443
11444 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11445 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11446
11447 if (popped) {
11448 ADD_INSN(ret, node, pop);
11449 }
11450 break;
11451 }
11452 case NODE_KW_ARG:
11453 CHECK(compile_kw_arg(iseq, ret, node, popped));
11454 break;
11455 case NODE_DSYM:{
11456 compile_dstr(iseq, ret, node);
11457 if (!popped) {
11458 ADD_INSN(ret, node, intern);
11459 }
11460 else {
11461 ADD_INSN(ret, node, pop);
11462 }
11463 break;
11464 }
11465 case NODE_ATTRASGN:
11466 CHECK(compile_attrasgn(iseq, ret, node, popped));
11467 break;
11468 case NODE_LAMBDA:{
11469 /* compile same as lambda{...} */
11470 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11471 VALUE argc = INT2FIX(0);
11472
11473 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11474 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11475 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11476
11477 if (popped) {
11478 ADD_INSN(ret, node, pop);
11479 }
11480 break;
11481 }
11482 default:
11483 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11484 ng:
11485 debug_node_end();
11486 return COMPILE_NG;
11487 }
11488
11489 debug_node_end();
11490 return COMPILE_OK;
11491}
11492
11493/***************************/
11494/* instruction information */
11495/***************************/
11496
11497static int
11498insn_data_length(INSN *iobj)
11499{
11500 return insn_len(iobj->insn_id);
11501}
11502
11503static int
11504calc_sp_depth(int depth, INSN *insn)
11505{
11506 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11507}
11508
11509static VALUE
11510opobj_inspect(VALUE obj)
11511{
11512 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11513 switch (BUILTIN_TYPE(obj)) {
11514 case T_STRING:
11515 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11516 break;
11517 case T_ARRAY:
11518 obj = rb_ary_dup(obj);
11519 break;
11520 default:
11521 break;
11522 }
11523 }
11524 return rb_inspect(obj);
11525}
11526
11527
11528
11529static VALUE
11530insn_data_to_s_detail(INSN *iobj)
11531{
11532 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11533
11534 if (iobj->operands) {
11535 const char *types = insn_op_types(iobj->insn_id);
11536 int j;
11537
11538 for (j = 0; types[j]; j++) {
11539 char type = types[j];
11540
11541 switch (type) {
11542 case TS_OFFSET: /* label(destination position) */
11543 {
11544 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11545 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11546 break;
11547 }
11548 break;
11549 case TS_ISEQ: /* iseq */
11550 {
11551 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11552 VALUE val = Qnil;
11553 if (0 && iseq) { /* TODO: invalidate now */
11554 val = (VALUE)iseq;
11555 }
11556 rb_str_concat(str, opobj_inspect(val));
11557 }
11558 break;
11559 case TS_LINDEX:
11560 case TS_NUM: /* ulong */
11561 case TS_VALUE: /* VALUE */
11562 {
11563 VALUE v = OPERAND_AT(iobj, j);
11564 if (!CLASS_OF(v))
11565 rb_str_cat2(str, "<hidden>");
11566 else {
11567 rb_str_concat(str, opobj_inspect(v));
11568 }
11569 break;
11570 }
11571 case TS_ID: /* ID */
11572 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11573 break;
11574 case TS_IC: /* inline cache */
11575 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11576 break;
11577 case TS_IVC: /* inline ivar cache */
11578 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11579 break;
11580 case TS_ICVARC: /* inline cvar cache */
11581 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11582 break;
11583 case TS_ISE: /* inline storage entry */
11584 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11585 break;
11586 case TS_CALLDATA: /* we store these as call infos at compile time */
11587 {
11588 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11589 rb_str_cat2(str, "<calldata:");
11590 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11591 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11592 break;
11593 }
11594 case TS_CDHASH: /* case/when condition cache */
11595 rb_str_cat2(str, "<ch>");
11596 break;
11597 case TS_FUNCPTR:
11598 {
11599 void *func = (void *)OPERAND_AT(iobj, j);
11600#ifdef HAVE_DLADDR
11601 Dl_info info;
11602 if (dladdr(func, &info) && info.dli_sname) {
11603 rb_str_cat2(str, info.dli_sname);
11604 break;
11605 }
11606#endif
11607 rb_str_catf(str, "<%p>", func);
11608 }
11609 break;
11610 case TS_BUILTIN:
11611 rb_str_cat2(str, "<TS_BUILTIN>");
11612 break;
11613 default:{
11614 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11615 }
11616 }
11617 if (types[j + 1]) {
11618 rb_str_cat2(str, ", ");
11619 }
11620 }
11621 }
11622 return str;
11623}
11624
11625static void
11626dump_disasm_list(const LINK_ELEMENT *link)
11627{
11628 dump_disasm_list_with_cursor(link, NULL, NULL);
11629}
11630
11631static void
11632dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11633{
11634 int pos = 0;
11635 INSN *iobj;
11636 LABEL *lobj;
11637 VALUE str;
11638
11639 printf("-- raw disasm--------\n");
11640
11641 while (link) {
11642 if (curr) printf(curr == link ? "*" : " ");
11643 switch (link->type) {
11644 case ISEQ_ELEMENT_INSN:
11645 {
11646 iobj = (INSN *)link;
11647 str = insn_data_to_s_detail(iobj);
11648 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11649 pos += insn_data_length(iobj);
11650 break;
11651 }
11652 case ISEQ_ELEMENT_LABEL:
11653 {
11654 lobj = (LABEL *)link;
11655 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11656 dest == lobj ? " <---" : "");
11657 break;
11658 }
11659 case ISEQ_ELEMENT_TRACE:
11660 {
11661 TRACE *trace = (TRACE *)link;
11662 printf(" trace: %0x\n", trace->event);
11663 break;
11664 }
11665 case ISEQ_ELEMENT_ADJUST:
11666 {
11667 ADJUST *adjust = (ADJUST *)link;
11668 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11669 break;
11670 }
11671 default:
11672 /* ignore */
11673 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11674 }
11675 link = link->next;
11676 }
11677 printf("---------------------\n");
11678 fflush(stdout);
11679}
11680
11681int
11682rb_insn_len(VALUE insn)
11683{
11684 return insn_len(insn);
11685}
11686
11687const char *
11688rb_insns_name(int i)
11689{
11690 return insn_name(i);
11691}
11692
11693VALUE
11694rb_insns_name_array(void)
11695{
11696 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11697 int i;
11698 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11699 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11700 }
11701 return rb_ary_freeze(ary);
11702}
11703
11704static LABEL *
11705register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11706{
11707 LABEL *label = 0;
11708 st_data_t tmp;
11709 obj = rb_to_symbol_type(obj);
11710
11711 if (st_lookup(labels_table, obj, &tmp) == 0) {
11712 label = NEW_LABEL(0);
11713 st_insert(labels_table, obj, (st_data_t)label);
11714 }
11715 else {
11716 label = (LABEL *)tmp;
11717 }
11718 LABEL_REF(label);
11719 return label;
11720}
11721
11722static VALUE
11723get_exception_sym2type(VALUE sym)
11724{
11725 static VALUE symRescue, symEnsure, symRetry;
11726 static VALUE symBreak, symRedo, symNext;
11727
11728 if (symRescue == 0) {
11729 symRescue = ID2SYM(rb_intern_const("rescue"));
11730 symEnsure = ID2SYM(rb_intern_const("ensure"));
11731 symRetry = ID2SYM(rb_intern_const("retry"));
11732 symBreak = ID2SYM(rb_intern_const("break"));
11733 symRedo = ID2SYM(rb_intern_const("redo"));
11734 symNext = ID2SYM(rb_intern_const("next"));
11735 }
11736
11737 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11738 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11739 if (sym == symRetry) return CATCH_TYPE_RETRY;
11740 if (sym == symBreak) return CATCH_TYPE_BREAK;
11741 if (sym == symRedo) return CATCH_TYPE_REDO;
11742 if (sym == symNext) return CATCH_TYPE_NEXT;
11743 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11744 return 0;
11745}
11746
11747static int
11748iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11749 VALUE exception)
11750{
11751 int i;
11752
11753 for (i=0; i<RARRAY_LEN(exception); i++) {
11754 const rb_iseq_t *eiseq;
11755 VALUE v, type;
11756 LABEL *lstart, *lend, *lcont;
11757 unsigned int sp;
11758
11759 v = rb_to_array_type(RARRAY_AREF(exception, i));
11760 if (RARRAY_LEN(v) != 6) {
11761 rb_raise(rb_eSyntaxError, "wrong exception entry");
11762 }
11763 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11764 if (NIL_P(RARRAY_AREF(v, 1))) {
11765 eiseq = NULL;
11766 }
11767 else {
11768 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11769 }
11770
11771 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11772 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11773 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11774 sp = NUM2UINT(RARRAY_AREF(v, 5));
11775
11776 /* TODO: Dirty Hack! Fix me */
11777 if (type == CATCH_TYPE_RESCUE ||
11778 type == CATCH_TYPE_BREAK ||
11779 type == CATCH_TYPE_NEXT) {
11780 ++sp;
11781 }
11782
11783 lcont->sp = sp;
11784
11785 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11786
11787 RB_GC_GUARD(v);
11788 }
11789 return COMPILE_OK;
11790}
11791
11792static struct st_table *
11793insn_make_insn_table(void)
11794{
11795 struct st_table *table;
11796 int i;
11797 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11798
11799 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11800 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11801 }
11802
11803 return table;
11804}
11805
11806static const rb_iseq_t *
11807iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11808{
11809 VALUE iseqw;
11810 const rb_iseq_t *loaded_iseq;
11811
11812 if (RB_TYPE_P(op, T_ARRAY)) {
11813 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11814 }
11815 else if (CLASS_OF(op) == rb_cISeq) {
11816 iseqw = op;
11817 }
11818 else {
11819 rb_raise(rb_eSyntaxError, "ISEQ is required");
11820 }
11821
11822 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11823 return loaded_iseq;
11824}
11825
11826static VALUE
11827iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11828{
11829 ID mid = 0;
11830 int orig_argc = 0;
11831 unsigned int flag = 0;
11832 struct rb_callinfo_kwarg *kw_arg = 0;
11833
11834 if (!NIL_P(op)) {
11835 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11836 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11837 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11838 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11839
11840 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11841 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11842 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11843
11844 if (!NIL_P(vkw_arg)) {
11845 int i;
11846 int len = RARRAY_LENINT(vkw_arg);
11847 size_t n = rb_callinfo_kwarg_bytes(len);
11848
11849 kw_arg = xmalloc(n);
11850 kw_arg->references = 0;
11851 kw_arg->keyword_len = len;
11852 for (i = 0; i < len; i++) {
11853 VALUE kw = RARRAY_AREF(vkw_arg, i);
11854 SYM2ID(kw); /* make immortal */
11855 kw_arg->keywords[i] = kw;
11856 }
11857 }
11858 }
11859
11860 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11861 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11862 return (VALUE)ci;
11863}
11864
11865static rb_event_flag_t
11866event_name_to_flag(VALUE sym)
11867{
11868#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11869 CHECK_EVENT(RUBY_EVENT_LINE);
11870 CHECK_EVENT(RUBY_EVENT_CLASS);
11871 CHECK_EVENT(RUBY_EVENT_END);
11872 CHECK_EVENT(RUBY_EVENT_CALL);
11873 CHECK_EVENT(RUBY_EVENT_RETURN);
11874 CHECK_EVENT(RUBY_EVENT_B_CALL);
11875 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11876 CHECK_EVENT(RUBY_EVENT_RESCUE);
11877#undef CHECK_EVENT
11878 return RUBY_EVENT_NONE;
11879}
11880
11881static int
11882iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11883 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11884{
11885 /* TODO: body should be frozen */
11886 long i, len = RARRAY_LEN(body);
11887 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11888 int j;
11889 int line_no = 0, node_id = -1, insn_idx = 0;
11890 int ret = COMPILE_OK;
11891
11892 /*
11893 * index -> LABEL *label
11894 */
11895 static struct st_table *insn_table;
11896
11897 if (insn_table == 0) {
11898 insn_table = insn_make_insn_table();
11899 }
11900
11901 for (i=0; i<len; i++) {
11902 VALUE obj = RARRAY_AREF(body, i);
11903
11904 if (SYMBOL_P(obj)) {
11905 rb_event_flag_t event;
11906 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11907 ADD_TRACE(anchor, event);
11908 }
11909 else {
11910 LABEL *label = register_label(iseq, labels_table, obj);
11911 ADD_LABEL(anchor, label);
11912 }
11913 }
11914 else if (FIXNUM_P(obj)) {
11915 line_no = NUM2INT(obj);
11916 }
11917 else if (RB_TYPE_P(obj, T_ARRAY)) {
11918 VALUE *argv = 0;
11919 int argc = RARRAY_LENINT(obj) - 1;
11920 st_data_t insn_id;
11921 VALUE insn;
11922
11923 if (node_ids) {
11924 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11925 }
11926
11927 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11928 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11929 /* TODO: exception */
11930 COMPILE_ERROR(iseq, line_no,
11931 "unknown instruction: %+"PRIsVALUE, insn);
11932 ret = COMPILE_NG;
11933 break;
11934 }
11935
11936 if (argc != insn_len((VALUE)insn_id)-1) {
11937 COMPILE_ERROR(iseq, line_no,
11938 "operand size mismatch");
11939 ret = COMPILE_NG;
11940 break;
11941 }
11942
11943 if (argc > 0) {
11944 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11945
11946 // add element before operand setup to make GC root
11947 ADD_ELEM(anchor,
11948 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11949 (enum ruby_vminsn_type)insn_id, argc, argv));
11950
11951 for (j=0; j<argc; j++) {
11952 VALUE op = rb_ary_entry(obj, j+1);
11953 switch (insn_op_type((VALUE)insn_id, j)) {
11954 case TS_OFFSET: {
11955 LABEL *label = register_label(iseq, labels_table, op);
11956 argv[j] = (VALUE)label;
11957 break;
11958 }
11959 case TS_LINDEX:
11960 case TS_NUM:
11961 (void)NUM2INT(op);
11962 argv[j] = op;
11963 break;
11964 case TS_VALUE:
11965 argv[j] = op;
11966 RB_OBJ_WRITTEN(iseq, Qundef, op);
11967 break;
11968 case TS_ISEQ:
11969 {
11970 if (op != Qnil) {
11971 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
11972 argv[j] = v;
11973 RB_OBJ_WRITTEN(iseq, Qundef, v);
11974 }
11975 else {
11976 argv[j] = 0;
11977 }
11978 }
11979 break;
11980 case TS_ISE:
11981 argv[j] = op;
11982 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11983 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
11984 }
11985 break;
11986 case TS_IC:
11987 {
11988 VALUE segments = rb_ary_new();
11989 op = rb_to_array_type(op);
11990
11991 for (int i = 0; i < RARRAY_LEN(op); i++) {
11992 VALUE sym = RARRAY_AREF(op, i);
11993 sym = rb_to_symbol_type(sym);
11994 rb_ary_push(segments, sym);
11995 }
11996
11997 RB_GC_GUARD(op);
11998 argv[j] = segments;
11999 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12000 ISEQ_BODY(iseq)->ic_size++;
12001 }
12002 break;
12003 case TS_IVC: /* inline ivar cache */
12004 argv[j] = op;
12005 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12006 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12007 }
12008 break;
12009 case TS_ICVARC: /* inline cvar cache */
12010 argv[j] = op;
12011 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12012 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12013 }
12014 break;
12015 case TS_CALLDATA:
12016 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12017 break;
12018 case TS_ID:
12019 argv[j] = rb_to_symbol_type(op);
12020 break;
12021 case TS_CDHASH:
12022 {
12023 int i;
12024 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12025
12026 RHASH_TBL_RAW(map)->type = &cdhash_type;
12027 op = rb_to_array_type(op);
12028 for (i=0; i<RARRAY_LEN(op); i+=2) {
12029 VALUE key = RARRAY_AREF(op, i);
12030 VALUE sym = RARRAY_AREF(op, i+1);
12031 LABEL *label =
12032 register_label(iseq, labels_table, sym);
12033 rb_hash_aset(map, key, (VALUE)label | 1);
12034 }
12035 RB_GC_GUARD(op);
12036 argv[j] = map;
12037 RB_OBJ_WRITTEN(iseq, Qundef, map);
12038 }
12039 break;
12040 case TS_FUNCPTR:
12041 {
12042#if SIZEOF_VALUE <= SIZEOF_LONG
12043 long funcptr = NUM2LONG(op);
12044#else
12045 LONG_LONG funcptr = NUM2LL(op);
12046#endif
12047 argv[j] = (VALUE)funcptr;
12048 }
12049 break;
12050 default:
12051 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12052 }
12053 }
12054 }
12055 else {
12056 ADD_ELEM(anchor,
12057 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12058 (enum ruby_vminsn_type)insn_id, argc, NULL));
12059 }
12060 }
12061 else {
12062 rb_raise(rb_eTypeError, "unexpected object for instruction");
12063 }
12064 }
12065 RTYPEDDATA_DATA(labels_wrapper) = 0;
12066 RB_GC_GUARD(labels_wrapper);
12067 validate_labels(iseq, labels_table);
12068 if (!ret) return ret;
12069 return iseq_setup(iseq, anchor);
12070}
12071
12072#define CHECK_ARRAY(v) rb_to_array_type(v)
12073#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12074
12075static int
12076int_param(int *dst, VALUE param, VALUE sym)
12077{
12078 VALUE val = rb_hash_aref(param, sym);
12079 if (FIXNUM_P(val)) {
12080 *dst = FIX2INT(val);
12081 return TRUE;
12082 }
12083 else if (!NIL_P(val)) {
12084 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12085 sym, val);
12086 }
12087 return FALSE;
12088}
12089
12090static const struct rb_iseq_param_keyword *
12091iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12092{
12093 int i, j;
12094 int len = RARRAY_LENINT(keywords);
12095 int default_len;
12096 VALUE key, sym, default_val;
12097 VALUE *dvs;
12098 ID *ids;
12099 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12100
12101 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12102
12103 keyword->num = len;
12104#define SYM(s) ID2SYM(rb_intern_const(#s))
12105 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12106 i = keyword->bits_start - keyword->num;
12107 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12108#undef SYM
12109
12110 /* required args */
12111 for (i = 0; i < len; i++) {
12112 VALUE val = RARRAY_AREF(keywords, i);
12113
12114 if (!SYMBOL_P(val)) {
12115 goto default_values;
12116 }
12117 ids[i] = SYM2ID(val);
12118 keyword->required_num++;
12119 }
12120
12121 default_values: /* note: we intentionally preserve `i' from previous loop */
12122 default_len = len - i;
12123 if (default_len == 0) {
12124 keyword->table = ids;
12125 return keyword;
12126 }
12127 else if (default_len < 0) {
12129 }
12130
12131 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12132
12133 for (j = 0; i < len; i++, j++) {
12134 key = RARRAY_AREF(keywords, i);
12135 CHECK_ARRAY(key);
12136
12137 switch (RARRAY_LEN(key)) {
12138 case 1:
12139 sym = RARRAY_AREF(key, 0);
12140 default_val = Qundef;
12141 break;
12142 case 2:
12143 sym = RARRAY_AREF(key, 0);
12144 default_val = RARRAY_AREF(key, 1);
12145 break;
12146 default:
12147 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12148 }
12149 ids[i] = SYM2ID(sym);
12150 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12151 }
12152
12153 keyword->table = ids;
12154 keyword->default_values = dvs;
12155
12156 return keyword;
12157}
12158
12159static void
12160iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12161{
12162 rb_gc_mark_and_move(obj);
12163}
12164
12165void
12166rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12167{
12168 INSN *iobj = 0;
12169 size_t size = sizeof(INSN);
12170 unsigned int pos = 0;
12171
12172 while (storage) {
12173#ifdef STRICT_ALIGNMENT
12174 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12175#else
12176 const size_t padding = 0; /* expected to be optimized by compiler */
12177#endif /* STRICT_ALIGNMENT */
12178 size_t offset = pos + size + padding;
12179 if (offset > storage->size || offset > storage->pos) {
12180 pos = 0;
12181 storage = storage->next;
12182 }
12183 else {
12184#ifdef STRICT_ALIGNMENT
12185 pos += (int)padding;
12186#endif /* STRICT_ALIGNMENT */
12187
12188 iobj = (INSN *)&storage->buff[pos];
12189
12190 if (iobj->operands) {
12191 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12192 }
12193 pos += (int)size;
12194 }
12195 }
12196}
12197
12198static const rb_data_type_t labels_wrapper_type = {
12199 .wrap_struct_name = "compiler/labels_wrapper",
12200 .function = {
12201 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12202 .dfree = (RUBY_DATA_FUNC)st_free_table,
12203 },
12204 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12205};
12206
12207void
12208rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12209 VALUE exception, VALUE body)
12210{
12211#define SYM(s) ID2SYM(rb_intern_const(#s))
12212 int i, len;
12213 unsigned int arg_size, local_size, stack_max;
12214 ID *tbl;
12215 struct st_table *labels_table = st_init_numtable();
12216 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12217 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12218 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12219 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12220 DECL_ANCHOR(anchor);
12221 INIT_ANCHOR(anchor);
12222
12223 len = RARRAY_LENINT(locals);
12224 ISEQ_BODY(iseq)->local_table_size = len;
12225 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12226
12227 for (i = 0; i < len; i++) {
12228 VALUE lv = RARRAY_AREF(locals, i);
12229
12230 if (sym_arg_rest == lv) {
12231 tbl[i] = 0;
12232 }
12233 else {
12234 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12235 }
12236 }
12237
12238#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12239 if (INT_PARAM(lead_num)) {
12240 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12241 }
12242 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12243 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12244 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12245 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12246#undef INT_PARAM
12247 {
12248#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12249 int x;
12250 INT_PARAM(arg_size);
12251 INT_PARAM(local_size);
12252 INT_PARAM(stack_max);
12253#undef INT_PARAM
12254 }
12255
12256 VALUE node_ids = Qfalse;
12257#ifdef USE_ISEQ_NODE_ID
12258 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12259 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12260 rb_raise(rb_eTypeError, "node_ids is not an array");
12261 }
12262#endif
12263
12264 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12265 len = RARRAY_LENINT(arg_opt_labels);
12266 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12267
12268 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12269 VALUE *opt_table = ALLOC_N(VALUE, len);
12270
12271 for (i = 0; i < len; i++) {
12272 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12273 LABEL *label = register_label(iseq, labels_table, ent);
12274 opt_table[i] = (VALUE)label;
12275 }
12276
12277 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12278 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12279 }
12280 }
12281 else if (!NIL_P(arg_opt_labels)) {
12282 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12283 arg_opt_labels);
12284 }
12285
12286 if (RB_TYPE_P(keywords, T_ARRAY)) {
12287 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12288 }
12289 else if (!NIL_P(keywords)) {
12290 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12291 keywords);
12292 }
12293
12294 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12295 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12296 }
12297
12298 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12299 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12300 }
12301
12302 if (int_param(&i, params, SYM(kwrest))) {
12303 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12304 if (keyword == NULL) {
12305 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12306 }
12307 keyword->rest_start = i;
12308 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12309 }
12310#undef SYM
12311 iseq_calc_param_size(iseq);
12312
12313 /* exception */
12314 iseq_build_from_ary_exception(iseq, labels_table, exception);
12315
12316 /* body */
12317 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12318
12319 ISEQ_BODY(iseq)->param.size = arg_size;
12320 ISEQ_BODY(iseq)->local_table_size = local_size;
12321 ISEQ_BODY(iseq)->stack_max = stack_max;
12322}
12323
12324/* for parser */
12325
12326int
12327rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12328{
12329 if (iseq) {
12330 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12331 while (body->type == ISEQ_TYPE_BLOCK ||
12332 body->type == ISEQ_TYPE_RESCUE ||
12333 body->type == ISEQ_TYPE_ENSURE ||
12334 body->type == ISEQ_TYPE_EVAL ||
12335 body->type == ISEQ_TYPE_MAIN
12336 ) {
12337 unsigned int i;
12338
12339 for (i = 0; i < body->local_table_size; i++) {
12340 if (body->local_table[i] == id) {
12341 return 1;
12342 }
12343 }
12344 iseq = body->parent_iseq;
12345 body = ISEQ_BODY(iseq);
12346 }
12347 }
12348 return 0;
12349}
12350
12351int
12352rb_local_defined(ID id, const rb_iseq_t *iseq)
12353{
12354 if (iseq) {
12355 unsigned int i;
12356 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12357
12358 for (i=0; i<body->local_table_size; i++) {
12359 if (body->local_table[i] == id) {
12360 return 1;
12361 }
12362 }
12363 }
12364 return 0;
12365}
12366
12367/* ISeq binary format */
12368
12369#ifndef IBF_ISEQ_DEBUG
12370#define IBF_ISEQ_DEBUG 0
12371#endif
12372
12373#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12374#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12375#endif
12376
12377typedef uint32_t ibf_offset_t;
12378#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12379
12380#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12381#ifdef RUBY_DEVEL
12382#define IBF_DEVEL_VERSION 4
12383#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12384#else
12385#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12386#endif
12387
12388static const char IBF_ENDIAN_MARK =
12389#ifdef WORDS_BIGENDIAN
12390 'b'
12391#else
12392 'l'
12393#endif
12394 ;
12395
12397 char magic[4]; /* YARB */
12398 uint32_t major_version;
12399 uint32_t minor_version;
12400 uint32_t size;
12401 uint32_t extra_size;
12402
12403 uint32_t iseq_list_size;
12404 uint32_t global_object_list_size;
12405 ibf_offset_t iseq_list_offset;
12406 ibf_offset_t global_object_list_offset;
12407 uint8_t endian;
12408 uint8_t wordsize; /* assume no 2048-bit CPU */
12409};
12410
12412 VALUE str;
12413 st_table *obj_table; /* obj -> obj number */
12414};
12415
12416struct ibf_dump {
12417 st_table *iseq_table; /* iseq -> iseq number */
12418 struct ibf_dump_buffer global_buffer;
12419 struct ibf_dump_buffer *current_buffer;
12420};
12421
12423 const char *buff;
12424 ibf_offset_t size;
12425
12426 VALUE obj_list; /* [obj0, ...] */
12427 unsigned int obj_list_size;
12428 ibf_offset_t obj_list_offset;
12429};
12430
12431struct ibf_load {
12432 const struct ibf_header *header;
12433 VALUE iseq_list; /* [iseq0, ...] */
12434 struct ibf_load_buffer global_buffer;
12435 VALUE loader_obj;
12436 rb_iseq_t *iseq;
12437 VALUE str;
12438 struct ibf_load_buffer *current_buffer;
12439};
12440
12442 long size;
12443 VALUE buffer[1];
12444};
12445
12446static void
12447pinned_list_mark(void *ptr)
12448{
12449 long i;
12450 struct pinned_list *list = (struct pinned_list *)ptr;
12451 for (i = 0; i < list->size; i++) {
12452 if (list->buffer[i]) {
12453 rb_gc_mark(list->buffer[i]);
12454 }
12455 }
12456}
12457
12458static const rb_data_type_t pinned_list_type = {
12459 "pinned_list",
12460 {
12461 pinned_list_mark,
12463 NULL, // No external memory to report,
12464 },
12465 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12466};
12467
12468static VALUE
12469pinned_list_fetch(VALUE list, long offset)
12470{
12471 struct pinned_list * ptr;
12472
12473 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12474
12475 if (offset >= ptr->size) {
12476 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12477 }
12478
12479 return ptr->buffer[offset];
12480}
12481
12482static void
12483pinned_list_store(VALUE list, long offset, VALUE object)
12484{
12485 struct pinned_list * ptr;
12486
12487 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12488
12489 if (offset >= ptr->size) {
12490 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12491 }
12492
12493 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12494}
12495
12496static VALUE
12497pinned_list_new(long size)
12498{
12499 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12500 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12501 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12502 ptr->size = size;
12503 return obj_list;
12504}
12505
12506static ibf_offset_t
12507ibf_dump_pos(struct ibf_dump *dump)
12508{
12509 long pos = RSTRING_LEN(dump->current_buffer->str);
12510#if SIZEOF_LONG > SIZEOF_INT
12511 if (pos >= UINT_MAX) {
12512 rb_raise(rb_eRuntimeError, "dump size exceeds");
12513 }
12514#endif
12515 return (unsigned int)pos;
12516}
12517
12518static void
12519ibf_dump_align(struct ibf_dump *dump, size_t align)
12520{
12521 ibf_offset_t pos = ibf_dump_pos(dump);
12522 if (pos % align) {
12523 static const char padding[sizeof(VALUE)];
12524 size_t size = align - ((size_t)pos % align);
12525#if SIZEOF_LONG > SIZEOF_INT
12526 if (pos + size >= UINT_MAX) {
12527 rb_raise(rb_eRuntimeError, "dump size exceeds");
12528 }
12529#endif
12530 for (; size > sizeof(padding); size -= sizeof(padding)) {
12531 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12532 }
12533 rb_str_cat(dump->current_buffer->str, padding, size);
12534 }
12535}
12536
12537static ibf_offset_t
12538ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12539{
12540 ibf_offset_t pos = ibf_dump_pos(dump);
12541#if SIZEOF_LONG > SIZEOF_INT
12542 /* ensure the resulting dump does not exceed UINT_MAX */
12543 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12544 rb_raise(rb_eRuntimeError, "dump size exceeds");
12545 }
12546#endif
12547 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12548 return pos;
12549}
12550
12551static ibf_offset_t
12552ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12553{
12554 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12555}
12556
12557static void
12558ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12559{
12560 VALUE str = dump->current_buffer->str;
12561 char *ptr = RSTRING_PTR(str);
12562 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12563 rb_bug("ibf_dump_overwrite: overflow");
12564 memcpy(ptr + offset, buff, size);
12565}
12566
12567static const void *
12568ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12569{
12570 ibf_offset_t beg = *offset;
12571 *offset += size;
12572 return load->current_buffer->buff + beg;
12573}
12574
12575static void *
12576ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12577{
12578 void *buff = ruby_xmalloc2(x, y);
12579 size_t size = x * y;
12580 memcpy(buff, load->current_buffer->buff + offset, size);
12581 return buff;
12582}
12583
12584#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12585
12586#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12587#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12588#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12589#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12590#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12591
12592static int
12593ibf_table_lookup(struct st_table *table, st_data_t key)
12594{
12595 st_data_t val;
12596
12597 if (st_lookup(table, key, &val)) {
12598 return (int)val;
12599 }
12600 else {
12601 return -1;
12602 }
12603}
12604
12605static int
12606ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12607{
12608 int index = ibf_table_lookup(table, key);
12609
12610 if (index < 0) { /* not found */
12611 index = (int)table->num_entries;
12612 st_insert(table, key, (st_data_t)index);
12613 }
12614
12615 return index;
12616}
12617
12618/* dump/load generic */
12619
12620static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12621
12622static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12623static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12624
12625static st_table *
12626ibf_dump_object_table_new(void)
12627{
12628 st_table *obj_table = st_init_numtable(); /* need free */
12629 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12630
12631 return obj_table;
12632}
12633
12634static VALUE
12635ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12636{
12637 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12638}
12639
12640static VALUE
12641ibf_dump_id(struct ibf_dump *dump, ID id)
12642{
12643 if (id == 0 || rb_id2name(id) == NULL) {
12644 return 0;
12645 }
12646 return ibf_dump_object(dump, rb_id2sym(id));
12647}
12648
12649static ID
12650ibf_load_id(const struct ibf_load *load, const ID id_index)
12651{
12652 if (id_index == 0) {
12653 return 0;
12654 }
12655 VALUE sym = ibf_load_object(load, id_index);
12656 if (rb_integer_type_p(sym)) {
12657 /* Load hidden local variables as indexes */
12658 return NUM2ULONG(sym);
12659 }
12660 return rb_sym2id(sym);
12661}
12662
12663/* dump/load: code */
12664
12665static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12666
12667static int
12668ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12669{
12670 if (iseq == NULL) {
12671 return -1;
12672 }
12673 else {
12674 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12675 }
12676}
12677
12678static unsigned char
12679ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12680{
12681 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12682 return (unsigned char)load->current_buffer->buff[(*offset)++];
12683}
12684
12685/*
12686 * Small uint serialization
12687 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12688 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12689 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12690 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12691 * ...
12692 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12693 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12694 */
12695static void
12696ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12697{
12698 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12699 ibf_dump_write(dump, &x, sizeof(VALUE));
12700 return;
12701 }
12702
12703 enum { max_byte_length = sizeof(VALUE) + 1 };
12704
12705 unsigned char bytes[max_byte_length];
12706 ibf_offset_t n;
12707
12708 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12709 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12710 }
12711
12712 x <<= 1;
12713 x |= 1;
12714 x <<= n;
12715 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12716 n++;
12717
12718 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12719}
12720
12721static VALUE
12722ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12723{
12724 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12725 union { char s[sizeof(VALUE)]; VALUE v; } x;
12726
12727 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12728 *offset += sizeof(VALUE);
12729
12730 return x.v;
12731 }
12732
12733 enum { max_byte_length = sizeof(VALUE) + 1 };
12734
12735 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12736 const unsigned char c = buffer[*offset];
12737
12738 ibf_offset_t n =
12739 c & 1 ? 1 :
12740 c == 0 ? 9 : ntz_int32(c) + 1;
12741 VALUE x = (VALUE)c >> n;
12742
12743 if (*offset + n > load->current_buffer->size) {
12744 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12745 }
12746
12747 ibf_offset_t i;
12748 for (i = 1; i < n; i++) {
12749 x <<= 8;
12750 x |= (VALUE)buffer[*offset + i];
12751 }
12752
12753 *offset += n;
12754 return x;
12755}
12756
12757static void
12758ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12759{
12760 // short: index
12761 // short: name.length
12762 // bytes: name
12763 // // omit argc (only verify with name)
12764 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12765
12766 size_t len = strlen(bf->name);
12767 ibf_dump_write_small_value(dump, (VALUE)len);
12768 ibf_dump_write(dump, bf->name, len);
12769}
12770
12771static const struct rb_builtin_function *
12772ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12773{
12774 int i = (int)ibf_load_small_value(load, offset);
12775 int len = (int)ibf_load_small_value(load, offset);
12776 const char *name = (char *)ibf_load_ptr(load, offset, len);
12777
12778 if (0) {
12779 fprintf(stderr, "%.*s!!\n", len, name);
12780 }
12781
12782 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12783 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12784 if (strncmp(table[i].name, name, len) != 0) {
12785 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12786 }
12787 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12788
12789 return &table[i];
12790}
12791
12792static ibf_offset_t
12793ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12794{
12795 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12796 const int iseq_size = body->iseq_size;
12797 int code_index;
12798 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12799
12800 ibf_offset_t offset = ibf_dump_pos(dump);
12801
12802 for (code_index=0; code_index<iseq_size;) {
12803 const VALUE insn = orig_code[code_index++];
12804 const char *types = insn_op_types(insn);
12805 int op_index;
12806
12807 /* opcode */
12808 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12809 ibf_dump_write_small_value(dump, insn);
12810
12811 /* operands */
12812 for (op_index=0; types[op_index]; op_index++, code_index++) {
12813 VALUE op = orig_code[code_index];
12814 VALUE wv;
12815
12816 switch (types[op_index]) {
12817 case TS_CDHASH:
12818 case TS_VALUE:
12819 wv = ibf_dump_object(dump, op);
12820 break;
12821 case TS_ISEQ:
12822 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12823 break;
12824 case TS_IC:
12825 {
12826 IC ic = (IC)op;
12827 VALUE arr = idlist_to_array(ic->segments);
12828 wv = ibf_dump_object(dump, arr);
12829 }
12830 break;
12831 case TS_ISE:
12832 case TS_IVC:
12833 case TS_ICVARC:
12834 {
12836 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12837 }
12838 break;
12839 case TS_CALLDATA:
12840 {
12841 goto skip_wv;
12842 }
12843 case TS_ID:
12844 wv = ibf_dump_id(dump, (ID)op);
12845 break;
12846 case TS_FUNCPTR:
12847 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12848 goto skip_wv;
12849 case TS_BUILTIN:
12850 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12851 goto skip_wv;
12852 default:
12853 wv = op;
12854 break;
12855 }
12856 ibf_dump_write_small_value(dump, wv);
12857 skip_wv:;
12858 }
12859 RUBY_ASSERT(insn_len(insn) == op_index+1);
12860 }
12861
12862 return offset;
12863}
12864
12865static VALUE *
12866ibf_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)
12867{
12868 VALUE iseqv = (VALUE)iseq;
12869 unsigned int code_index;
12870 ibf_offset_t reading_pos = bytecode_offset;
12871 VALUE *code = ALLOC_N(VALUE, iseq_size);
12872
12873 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12874 struct rb_call_data *cd_entries = load_body->call_data;
12875 int ic_index = 0;
12876
12877 iseq_bits_t * mark_offset_bits;
12878
12879 iseq_bits_t tmp[1] = {0};
12880
12881 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12882 mark_offset_bits = tmp;
12883 }
12884 else {
12885 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12886 }
12887 bool needs_bitmap = false;
12888
12889 for (code_index=0; code_index<iseq_size;) {
12890 /* opcode */
12891 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12892 const char *types = insn_op_types(insn);
12893 int op_index;
12894
12895 code_index++;
12896
12897 /* operands */
12898 for (op_index=0; types[op_index]; op_index++, code_index++) {
12899 const char operand_type = types[op_index];
12900 switch (operand_type) {
12901 case TS_VALUE:
12902 {
12903 VALUE op = ibf_load_small_value(load, &reading_pos);
12904 VALUE v = ibf_load_object(load, op);
12905 code[code_index] = v;
12906 if (!SPECIAL_CONST_P(v)) {
12907 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12908 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12909 needs_bitmap = true;
12910 }
12911 break;
12912 }
12913 case TS_CDHASH:
12914 {
12915 VALUE op = ibf_load_small_value(load, &reading_pos);
12916 VALUE v = ibf_load_object(load, op);
12917 v = rb_hash_dup(v); // hash dumped as frozen
12918 RHASH_TBL_RAW(v)->type = &cdhash_type;
12919 rb_hash_rehash(v); // hash function changed
12920 freeze_hide_obj(v);
12921
12922 // Overwrite the existing hash in the object list. This
12923 // is to keep the object alive during load time.
12924 // [Bug #17984] [ruby-core:104259]
12925 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12926
12927 code[code_index] = v;
12928 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12929 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12930 needs_bitmap = true;
12931 break;
12932 }
12933 case TS_ISEQ:
12934 {
12935 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12936 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12937 code[code_index] = v;
12938 if (!SPECIAL_CONST_P(v)) {
12939 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12940 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12941 needs_bitmap = true;
12942 }
12943 break;
12944 }
12945 case TS_IC:
12946 {
12947 VALUE op = ibf_load_small_value(load, &reading_pos);
12948 VALUE arr = ibf_load_object(load, op);
12949
12950 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12951 ic->segments = array_to_idlist(arr);
12952
12953 code[code_index] = (VALUE)ic;
12954 }
12955 break;
12956 case TS_ISE:
12957 case TS_ICVARC:
12958 case TS_IVC:
12959 {
12960 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
12961
12962 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12963 code[code_index] = (VALUE)ic;
12964
12965 if (operand_type == TS_IVC) {
12966 IVC cache = (IVC)ic;
12967
12968 if (insn == BIN(setinstancevariable)) {
12969 ID iv_name = (ID)code[code_index - 1];
12970 cache->iv_set_name = iv_name;
12971 }
12972 else {
12973 cache->iv_set_name = 0;
12974 }
12975
12976 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12977 }
12978
12979 }
12980 break;
12981 case TS_CALLDATA:
12982 {
12983 code[code_index] = (VALUE)cd_entries++;
12984 }
12985 break;
12986 case TS_ID:
12987 {
12988 VALUE op = ibf_load_small_value(load, &reading_pos);
12989 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
12990 }
12991 break;
12992 case TS_FUNCPTR:
12993 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12994 break;
12995 case TS_BUILTIN:
12996 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
12997 break;
12998 default:
12999 code[code_index] = ibf_load_small_value(load, &reading_pos);
13000 continue;
13001 }
13002 }
13003 if (insn_len(insn) != op_index+1) {
13004 rb_raise(rb_eRuntimeError, "operand size mismatch");
13005 }
13006 }
13007
13008 load_body->iseq_encoded = code;
13009 load_body->iseq_size = code_index;
13010
13011 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13012 load_body->mark_bits.single = mark_offset_bits[0];
13013 }
13014 else {
13015 if (needs_bitmap) {
13016 load_body->mark_bits.list = mark_offset_bits;
13017 }
13018 else {
13019 load_body->mark_bits.list = 0;
13020 ruby_xfree(mark_offset_bits);
13021 }
13022 }
13023
13024 RUBY_ASSERT(code_index == iseq_size);
13025 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13026 return code;
13027}
13028
13029static ibf_offset_t
13030ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13031{
13032 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13033
13034 if (opt_num > 0) {
13035 IBF_W_ALIGN(VALUE);
13036 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13037 }
13038 else {
13039 return ibf_dump_pos(dump);
13040 }
13041}
13042
13043static VALUE *
13044ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13045{
13046 if (opt_num > 0) {
13047 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13048 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13049 return table;
13050 }
13051 else {
13052 return NULL;
13053 }
13054}
13055
13056static ibf_offset_t
13057ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13058{
13059 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13060
13061 if (kw) {
13062 struct rb_iseq_param_keyword dump_kw = *kw;
13063 int dv_num = kw->num - kw->required_num;
13064 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13065 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13066 int i;
13067
13068 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13069 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13070
13071 dump_kw.table = IBF_W(ids, ID, kw->num);
13072 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13073 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13074 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13075 }
13076 else {
13077 return 0;
13078 }
13079}
13080
13081static const struct rb_iseq_param_keyword *
13082ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13083{
13084 if (param_keyword_offset) {
13085 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13086 int dv_num = kw->num - kw->required_num;
13087 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13088
13089 int i;
13090 for (i=0; i<dv_num; i++) {
13091 dvs[i] = ibf_load_object(load, dvs[i]);
13092 }
13093
13094 // Will be set once the local table is loaded.
13095 kw->table = NULL;
13096
13097 kw->default_values = dvs;
13098 return kw;
13099 }
13100 else {
13101 return NULL;
13102 }
13103}
13104
13105static ibf_offset_t
13106ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13107{
13108 ibf_offset_t offset = ibf_dump_pos(dump);
13109 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13110
13111 unsigned int i;
13112 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13113 ibf_dump_write_small_value(dump, entries[i].line_no);
13114#ifdef USE_ISEQ_NODE_ID
13115 ibf_dump_write_small_value(dump, entries[i].node_id);
13116#endif
13117 ibf_dump_write_small_value(dump, entries[i].events);
13118 }
13119
13120 return offset;
13121}
13122
13123static struct iseq_insn_info_entry *
13124ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13125{
13126 ibf_offset_t reading_pos = body_offset;
13127 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13128
13129 unsigned int i;
13130 for (i = 0; i < size; i++) {
13131 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13132#ifdef USE_ISEQ_NODE_ID
13133 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13134#endif
13135 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13136 }
13137
13138 return entries;
13139}
13140
13141static ibf_offset_t
13142ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13143{
13144 ibf_offset_t offset = ibf_dump_pos(dump);
13145
13146 unsigned int last = 0;
13147 unsigned int i;
13148 for (i = 0; i < size; i++) {
13149 ibf_dump_write_small_value(dump, positions[i] - last);
13150 last = positions[i];
13151 }
13152
13153 return offset;
13154}
13155
13156static unsigned int *
13157ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13158{
13159 ibf_offset_t reading_pos = positions_offset;
13160 unsigned int *positions = ALLOC_N(unsigned int, size);
13161
13162 unsigned int last = 0;
13163 unsigned int i;
13164 for (i = 0; i < size; i++) {
13165 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13166 last = positions[i];
13167 }
13168
13169 return positions;
13170}
13171
13172static ibf_offset_t
13173ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13174{
13175 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13176 const int size = body->local_table_size;
13177 ID *table = ALLOCA_N(ID, size);
13178 int i;
13179
13180 for (i=0; i<size; i++) {
13181 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13182 if (v == 0) {
13183 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13184 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13185 }
13186 table[i] = v;
13187 }
13188
13189 IBF_W_ALIGN(ID);
13190 return ibf_dump_write(dump, table, sizeof(ID) * size);
13191}
13192
13193static ID *
13194ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13195{
13196 if (size > 0) {
13197 ID *table = IBF_R(local_table_offset, ID, size);
13198 int i;
13199
13200 for (i=0; i<size; i++) {
13201 table[i] = ibf_load_id(load, table[i]);
13202 }
13203 return table;
13204 }
13205 else {
13206 return NULL;
13207 }
13208}
13209
13210static ibf_offset_t
13211ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13212{
13213 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13214
13215 if (table) {
13216 int *iseq_indices = ALLOCA_N(int, table->size);
13217 unsigned int i;
13218
13219 for (i=0; i<table->size; i++) {
13220 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13221 }
13222
13223 const ibf_offset_t offset = ibf_dump_pos(dump);
13224
13225 for (i=0; i<table->size; i++) {
13226 ibf_dump_write_small_value(dump, iseq_indices[i]);
13227 ibf_dump_write_small_value(dump, table->entries[i].type);
13228 ibf_dump_write_small_value(dump, table->entries[i].start);
13229 ibf_dump_write_small_value(dump, table->entries[i].end);
13230 ibf_dump_write_small_value(dump, table->entries[i].cont);
13231 ibf_dump_write_small_value(dump, table->entries[i].sp);
13232 }
13233 return offset;
13234 }
13235 else {
13236 return ibf_dump_pos(dump);
13237 }
13238}
13239
13240static void
13241ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13242{
13243 if (size) {
13244 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13245 table->size = size;
13246 ISEQ_BODY(parent_iseq)->catch_table = table;
13247
13248 ibf_offset_t reading_pos = catch_table_offset;
13249
13250 unsigned int i;
13251 for (i=0; i<table->size; i++) {
13252 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13253 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13254 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13255 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13256 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13257 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13258
13259 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13260 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13261 }
13262 }
13263 else {
13264 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13265 }
13266}
13267
13268static ibf_offset_t
13269ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13270{
13271 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13272 const unsigned int ci_size = body->ci_size;
13273 const struct rb_call_data *cds = body->call_data;
13274
13275 ibf_offset_t offset = ibf_dump_pos(dump);
13276
13277 unsigned int i;
13278
13279 for (i = 0; i < ci_size; i++) {
13280 const struct rb_callinfo *ci = cds[i].ci;
13281 if (ci != NULL) {
13282 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13283 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13284 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13285
13286 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13287 if (kwarg) {
13288 int len = kwarg->keyword_len;
13289 ibf_dump_write_small_value(dump, len);
13290 for (int j=0; j<len; j++) {
13291 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13292 ibf_dump_write_small_value(dump, keyword);
13293 }
13294 }
13295 else {
13296 ibf_dump_write_small_value(dump, 0);
13297 }
13298 }
13299 else {
13300 // TODO: truncate NULL ci from call_data.
13301 ibf_dump_write_small_value(dump, (VALUE)-1);
13302 }
13303 }
13304
13305 return offset;
13306}
13307
13309 ID id;
13310 VALUE name;
13311 VALUE val;
13312};
13313
13315 size_t num;
13316 struct outer_variable_pair pairs[1];
13317};
13318
13319static enum rb_id_table_iterator_result
13320store_outer_variable(ID id, VALUE val, void *dump)
13321{
13322 struct outer_variable_list *ovlist = dump;
13323 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13324 pair->id = id;
13325 pair->name = rb_id2str(id);
13326 pair->val = val;
13327 return ID_TABLE_CONTINUE;
13328}
13329
13330static int
13331outer_variable_cmp(const void *a, const void *b, void *arg)
13332{
13333 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13334 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13335
13336 if (!ap->name) {
13337 return -1;
13338 }
13339 else if (!bp->name) {
13340 return 1;
13341 }
13342
13343 return rb_str_cmp(ap->name, bp->name);
13344}
13345
13346static ibf_offset_t
13347ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13348{
13349 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13350
13351 ibf_offset_t offset = ibf_dump_pos(dump);
13352
13353 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13354 ibf_dump_write_small_value(dump, (VALUE)size);
13355 if (size > 0) {
13356 VALUE buff;
13357 size_t buffsize =
13358 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13359 offsetof(struct outer_variable_list, pairs),
13360 rb_eArgError);
13361 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13362 ovlist->num = 0;
13363 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13364 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13365 for (size_t i = 0; i < size; ++i) {
13366 ID id = ovlist->pairs[i].id;
13367 ID val = ovlist->pairs[i].val;
13368 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13369 ibf_dump_write_small_value(dump, val);
13370 }
13371 }
13372
13373 return offset;
13374}
13375
13376/* note that we dump out rb_call_info but load back rb_call_data */
13377static void
13378ibf_load_ci_entries(const struct ibf_load *load,
13379 ibf_offset_t ci_entries_offset,
13380 unsigned int ci_size,
13381 struct rb_call_data **cd_ptr)
13382{
13383 if (!ci_size) {
13384 *cd_ptr = NULL;
13385 return;
13386 }
13387
13388 ibf_offset_t reading_pos = ci_entries_offset;
13389
13390 unsigned int i;
13391
13392 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13393 *cd_ptr = cds;
13394
13395 for (i = 0; i < ci_size; i++) {
13396 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13397 if (mid_index != (VALUE)-1) {
13398 ID mid = ibf_load_id(load, mid_index);
13399 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13400 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13401
13402 struct rb_callinfo_kwarg *kwarg = NULL;
13403 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13404 if (kwlen > 0) {
13405 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13406 kwarg->references = 0;
13407 kwarg->keyword_len = kwlen;
13408 for (int j=0; j<kwlen; j++) {
13409 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13410 kwarg->keywords[j] = ibf_load_object(load, keyword);
13411 }
13412 }
13413
13414 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13415 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13416 cds[i].cc = vm_cc_empty();
13417 }
13418 else {
13419 // NULL ci
13420 cds[i].ci = NULL;
13421 cds[i].cc = NULL;
13422 }
13423 }
13424}
13425
13426static struct rb_id_table *
13427ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13428{
13429 ibf_offset_t reading_pos = outer_variables_offset;
13430
13431 struct rb_id_table *tbl = NULL;
13432
13433 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13434
13435 if (table_size > 0) {
13436 tbl = rb_id_table_create(table_size);
13437 }
13438
13439 for (size_t i = 0; i < table_size; i++) {
13440 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13441 VALUE value = ibf_load_small_value(load, &reading_pos);
13442 if (!key) key = rb_make_temporary_id(i);
13443 rb_id_table_insert(tbl, key, value);
13444 }
13445
13446 return tbl;
13447}
13448
13449static ibf_offset_t
13450ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13451{
13452 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13453
13454 unsigned int *positions;
13455
13456 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13457
13458 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13459 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13460 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13461
13462#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13463 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13464
13465 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13466 struct ibf_dump_buffer buffer;
13467 buffer.str = rb_str_new(0, 0);
13468 buffer.obj_table = ibf_dump_object_table_new();
13469 dump->current_buffer = &buffer;
13470#endif
13471
13472 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13473 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13474 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13475 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13476 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13477
13478 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13479 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13480 ruby_xfree(positions);
13481
13482 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13483 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13484 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13485 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13486 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13487 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13488 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13489 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13490
13491#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13492 ibf_offset_t local_obj_list_offset;
13493 unsigned int local_obj_list_size;
13494
13495 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13496#endif
13497
13498 ibf_offset_t body_offset = ibf_dump_pos(dump);
13499
13500 /* dump the constant body */
13501 unsigned int param_flags =
13502 (body->param.flags.has_lead << 0) |
13503 (body->param.flags.has_opt << 1) |
13504 (body->param.flags.has_rest << 2) |
13505 (body->param.flags.has_post << 3) |
13506 (body->param.flags.has_kw << 4) |
13507 (body->param.flags.has_kwrest << 5) |
13508 (body->param.flags.has_block << 6) |
13509 (body->param.flags.ambiguous_param0 << 7) |
13510 (body->param.flags.accepts_no_kwarg << 8) |
13511 (body->param.flags.ruby2_keywords << 9) |
13512 (body->param.flags.anon_rest << 10) |
13513 (body->param.flags.anon_kwrest << 11) |
13514 (body->param.flags.use_block << 12) |
13515 (body->param.flags.forwardable << 13) ;
13516
13517#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13518# define IBF_BODY_OFFSET(x) (x)
13519#else
13520# define IBF_BODY_OFFSET(x) (body_offset - (x))
13521#endif
13522
13523 ibf_dump_write_small_value(dump, body->type);
13524 ibf_dump_write_small_value(dump, body->iseq_size);
13525 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13526 ibf_dump_write_small_value(dump, bytecode_size);
13527 ibf_dump_write_small_value(dump, param_flags);
13528 ibf_dump_write_small_value(dump, body->param.size);
13529 ibf_dump_write_small_value(dump, body->param.lead_num);
13530 ibf_dump_write_small_value(dump, body->param.opt_num);
13531 ibf_dump_write_small_value(dump, body->param.rest_start);
13532 ibf_dump_write_small_value(dump, body->param.post_start);
13533 ibf_dump_write_small_value(dump, body->param.post_num);
13534 ibf_dump_write_small_value(dump, body->param.block_start);
13535 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13536 ibf_dump_write_small_value(dump, param_keyword_offset);
13537 ibf_dump_write_small_value(dump, location_pathobj_index);
13538 ibf_dump_write_small_value(dump, location_base_label_index);
13539 ibf_dump_write_small_value(dump, location_label_index);
13540 ibf_dump_write_small_value(dump, body->location.first_lineno);
13541 ibf_dump_write_small_value(dump, body->location.node_id);
13542 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13543 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13544 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13545 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13546 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13547 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13548 ibf_dump_write_small_value(dump, body->insns_info.size);
13549 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13550 ibf_dump_write_small_value(dump, catch_table_size);
13551 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13552 ibf_dump_write_small_value(dump, parent_iseq_index);
13553 ibf_dump_write_small_value(dump, local_iseq_index);
13554 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13555 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13556 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13557 ibf_dump_write_small_value(dump, body->variable.flip_count);
13558 ibf_dump_write_small_value(dump, body->local_table_size);
13559 ibf_dump_write_small_value(dump, body->ivc_size);
13560 ibf_dump_write_small_value(dump, body->icvarc_size);
13561 ibf_dump_write_small_value(dump, body->ise_size);
13562 ibf_dump_write_small_value(dump, body->ic_size);
13563 ibf_dump_write_small_value(dump, body->ci_size);
13564 ibf_dump_write_small_value(dump, body->stack_max);
13565 ibf_dump_write_small_value(dump, body->builtin_attrs);
13566 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13567
13568#undef IBF_BODY_OFFSET
13569
13570#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13571 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13572
13573 dump->current_buffer = saved_buffer;
13574 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13575
13576 ibf_offset_t offset = ibf_dump_pos(dump);
13577 ibf_dump_write_small_value(dump, iseq_start);
13578 ibf_dump_write_small_value(dump, iseq_length_bytes);
13579 ibf_dump_write_small_value(dump, body_offset);
13580
13581 ibf_dump_write_small_value(dump, local_obj_list_offset);
13582 ibf_dump_write_small_value(dump, local_obj_list_size);
13583
13584 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13585
13586 return offset;
13587#else
13588 return body_offset;
13589#endif
13590}
13591
13592static VALUE
13593ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13594{
13595 VALUE str = ibf_load_object(load, str_index);
13596 if (str != Qnil) {
13597 str = rb_fstring(str);
13598 }
13599 return str;
13600}
13601
13602static void
13603ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13604{
13605 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13606
13607 ibf_offset_t reading_pos = offset;
13608
13609#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13610 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13611 load->current_buffer = &load->global_buffer;
13612
13613 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13614 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13615 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13616
13617 struct ibf_load_buffer buffer;
13618 buffer.buff = load->global_buffer.buff + iseq_start;
13619 buffer.size = iseq_length_bytes;
13620 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13621 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13622 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13623
13624 load->current_buffer = &buffer;
13625 reading_pos = body_offset;
13626#endif
13627
13628#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13629# define IBF_BODY_OFFSET(x) (x)
13630#else
13631# define IBF_BODY_OFFSET(x) (offset - (x))
13632#endif
13633
13634 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13635 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13636 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13637 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13638 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13639 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13640 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13641 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13642 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13643 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13644 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13645 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13646 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13647 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13648 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13649 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13650 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13651 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13652 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13653 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13654 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13655 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13656 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13657 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13658 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13659 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13660 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13661 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13662 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13663 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13664 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13665 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13666 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13667 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13668 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13669 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13670
13671 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13672 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13673 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13674 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13675
13676 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13677 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13678 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13679 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13680
13681 // setup fname and dummy frame
13682 VALUE path = ibf_load_object(load, location_pathobj_index);
13683 {
13684 VALUE realpath = Qnil;
13685
13686 if (RB_TYPE_P(path, T_STRING)) {
13687 realpath = path = rb_fstring(path);
13688 }
13689 else if (RB_TYPE_P(path, T_ARRAY)) {
13690 VALUE pathobj = path;
13691 if (RARRAY_LEN(pathobj) != 2) {
13692 rb_raise(rb_eRuntimeError, "path object size mismatch");
13693 }
13694 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13695 realpath = RARRAY_AREF(pathobj, 1);
13696 if (!NIL_P(realpath)) {
13697 if (!RB_TYPE_P(realpath, T_STRING)) {
13698 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13699 "(%x), path=%+"PRIsVALUE,
13700 realpath, TYPE(realpath), path);
13701 }
13702 realpath = rb_fstring(realpath);
13703 }
13704 }
13705 else {
13706 rb_raise(rb_eRuntimeError, "unexpected path object");
13707 }
13708 rb_iseq_pathobj_set(iseq, path, realpath);
13709 }
13710
13711 // push dummy frame
13712 rb_execution_context_t *ec = GET_EC();
13713 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13714
13715#undef IBF_BODY_OFFSET
13716
13717 load_body->type = type;
13718 load_body->stack_max = stack_max;
13719 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13720 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13721 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13722 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13723 load_body->param.flags.has_kw = FALSE;
13724 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13725 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13726 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13727 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13728 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13729 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13730 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13731 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13732 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13733 load_body->param.size = param_size;
13734 load_body->param.lead_num = param_lead_num;
13735 load_body->param.opt_num = param_opt_num;
13736 load_body->param.rest_start = param_rest_start;
13737 load_body->param.post_start = param_post_start;
13738 load_body->param.post_num = param_post_num;
13739 load_body->param.block_start = param_block_start;
13740 load_body->local_table_size = local_table_size;
13741 load_body->ci_size = ci_size;
13742 load_body->insns_info.size = insns_info_size;
13743
13744 ISEQ_COVERAGE_SET(iseq, Qnil);
13745 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13746 load_body->variable.flip_count = variable_flip_count;
13747 load_body->variable.script_lines = Qnil;
13748
13749 load_body->location.first_lineno = location_first_lineno;
13750 load_body->location.node_id = location_node_id;
13751 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13752 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13753 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13754 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13755 load_body->builtin_attrs = builtin_attrs;
13756 load_body->prism = prism;
13757
13758 load_body->ivc_size = ivc_size;
13759 load_body->icvarc_size = icvarc_size;
13760 load_body->ise_size = ise_size;
13761 load_body->ic_size = ic_size;
13762
13763 if (ISEQ_IS_SIZE(load_body)) {
13764 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13765 }
13766 else {
13767 load_body->is_entries = NULL;
13768 }
13769 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13770 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13771 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13772 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13773 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13774 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13775 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13776 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13777 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13778
13779 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13780 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13781 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13782
13783 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13784 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13785 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13786
13787 // This must be done after the local table is loaded.
13788 if (load_body->param.keyword != NULL) {
13789 RUBY_ASSERT(load_body->local_table);
13790 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13791 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13792 }
13793
13794 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13795#if VM_INSN_INFO_TABLE_IMPL == 2
13796 rb_iseq_insns_info_encode_positions(iseq);
13797#endif
13798
13799 rb_iseq_translate_threaded_code(iseq);
13800
13801#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13802 load->current_buffer = &load->global_buffer;
13803#endif
13804
13805 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13806 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13807
13808#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13809 load->current_buffer = saved_buffer;
13810#endif
13811 verify_call_cache(iseq);
13812
13813 RB_GC_GUARD(dummy_frame);
13814 rb_vm_pop_frame_no_int(ec);
13815}
13816
13818{
13819 struct ibf_dump *dump;
13820 VALUE offset_list;
13821};
13822
13823static int
13824ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13825{
13826 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13827 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13828
13829 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13830 rb_ary_push(args->offset_list, UINT2NUM(offset));
13831
13832 return ST_CONTINUE;
13833}
13834
13835static void
13836ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13837{
13838 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13839
13840 struct ibf_dump_iseq_list_arg args;
13841 args.dump = dump;
13842 args.offset_list = offset_list;
13843
13844 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13845
13846 st_index_t i;
13847 st_index_t size = dump->iseq_table->num_entries;
13848 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13849
13850 for (i = 0; i < size; i++) {
13851 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13852 }
13853
13854 ibf_dump_align(dump, sizeof(ibf_offset_t));
13855 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13856 header->iseq_list_size = (unsigned int)size;
13857}
13858
13859#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13860
13861/*
13862 * Binary format
13863 * - ibf_object_header
13864 * - ibf_object_xxx (xxx is type)
13865 */
13866
13868 unsigned int type: 5;
13869 unsigned int special_const: 1;
13870 unsigned int frozen: 1;
13871 unsigned int internal: 1;
13872};
13873
13874enum ibf_object_class_index {
13875 IBF_OBJECT_CLASS_OBJECT,
13876 IBF_OBJECT_CLASS_ARRAY,
13877 IBF_OBJECT_CLASS_STANDARD_ERROR,
13878 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13879 IBF_OBJECT_CLASS_TYPE_ERROR,
13880 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13881};
13882
13884 long srcstr;
13885 char option;
13886};
13887
13889 long len;
13890 long keyval[FLEX_ARY_LEN];
13891};
13892
13894 long class_index;
13895 long len;
13896 long beg;
13897 long end;
13898 int excl;
13899};
13900
13902 ssize_t slen;
13903 BDIGIT digits[FLEX_ARY_LEN];
13904};
13905
13906enum ibf_object_data_type {
13907 IBF_OBJECT_DATA_ENCODING,
13908};
13909
13911 long a, b;
13912};
13913
13915 long str;
13916};
13917
13918#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13919 ((((offset) - 1) / (align) + 1) * (align))
13920#define IBF_OBJBODY(type, offset) (const type *)\
13921 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13922
13923static const void *
13924ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13925{
13926 if (offset >= load->current_buffer->size) {
13927 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13928 }
13929 return load->current_buffer->buff + offset;
13930}
13931
13932NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13933
13934static void
13935ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13936{
13937 char buff[0x100];
13938 rb_raw_obj_info(buff, sizeof(buff), obj);
13939 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13940}
13941
13942NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13943
13944static VALUE
13945ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13946{
13947 rb_raise(rb_eArgError, "unsupported");
13949}
13950
13951static void
13952ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13953{
13954 enum ibf_object_class_index cindex;
13955 if (obj == rb_cObject) {
13956 cindex = IBF_OBJECT_CLASS_OBJECT;
13957 }
13958 else if (obj == rb_cArray) {
13959 cindex = IBF_OBJECT_CLASS_ARRAY;
13960 }
13961 else if (obj == rb_eStandardError) {
13962 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13963 }
13964 else if (obj == rb_eNoMatchingPatternError) {
13965 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13966 }
13967 else if (obj == rb_eTypeError) {
13968 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13969 }
13970 else if (obj == rb_eNoMatchingPatternKeyError) {
13971 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13972 }
13973 else {
13974 rb_obj_info_dump(obj);
13975 rb_p(obj);
13976 rb_bug("unsupported class");
13977 }
13978 ibf_dump_write_small_value(dump, (VALUE)cindex);
13979}
13980
13981static VALUE
13982ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13983{
13984 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13985
13986 switch (cindex) {
13987 case IBF_OBJECT_CLASS_OBJECT:
13988 return rb_cObject;
13989 case IBF_OBJECT_CLASS_ARRAY:
13990 return rb_cArray;
13991 case IBF_OBJECT_CLASS_STANDARD_ERROR:
13992 return rb_eStandardError;
13993 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13995 case IBF_OBJECT_CLASS_TYPE_ERROR:
13996 return rb_eTypeError;
13997 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13999 }
14000
14001 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14002}
14003
14004
14005static void
14006ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14007{
14008 double dbl = RFLOAT_VALUE(obj);
14009 (void)IBF_W(&dbl, double, 1);
14010}
14011
14012static VALUE
14013ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14014{
14015 const double *dblp = IBF_OBJBODY(double, offset);
14016 return DBL2NUM(*dblp);
14017}
14018
14019static void
14020ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14021{
14022 long encindex = (long)rb_enc_get_index(obj);
14023 long len = RSTRING_LEN(obj);
14024 const char *ptr = RSTRING_PTR(obj);
14025
14026 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14027 rb_encoding *enc = rb_enc_from_index((int)encindex);
14028 const char *enc_name = rb_enc_name(enc);
14029 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14030 }
14031
14032 ibf_dump_write_small_value(dump, encindex);
14033 ibf_dump_write_small_value(dump, len);
14034 IBF_WP(ptr, char, len);
14035}
14036
14037static VALUE
14038ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14039{
14040 ibf_offset_t reading_pos = offset;
14041
14042 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14043 const long len = (long)ibf_load_small_value(load, &reading_pos);
14044 const char *ptr = load->current_buffer->buff + reading_pos;
14045
14046 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14047 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14048 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14049 }
14050
14051 VALUE str;
14052 if (header->frozen && !header->internal) {
14053 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14054 }
14055 else {
14056 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14057
14058 if (header->internal) rb_obj_hide(str);
14059 if (header->frozen) str = rb_fstring(str);
14060 }
14061 return str;
14062}
14063
14064static void
14065ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14066{
14067 VALUE srcstr = RREGEXP_SRC(obj);
14068 struct ibf_object_regexp regexp;
14069 regexp.option = (char)rb_reg_options(obj);
14070 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14071
14072 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14073 ibf_dump_write_small_value(dump, regexp.srcstr);
14074}
14075
14076static VALUE
14077ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14078{
14079 struct ibf_object_regexp regexp;
14080 regexp.option = ibf_load_byte(load, &offset);
14081 regexp.srcstr = ibf_load_small_value(load, &offset);
14082
14083 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14084 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14085
14086 if (header->internal) rb_obj_hide(reg);
14087 if (header->frozen) rb_obj_freeze(reg);
14088
14089 return reg;
14090}
14091
14092static void
14093ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14094{
14095 long i, len = RARRAY_LEN(obj);
14096 ibf_dump_write_small_value(dump, len);
14097 for (i=0; i<len; i++) {
14098 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14099 ibf_dump_write_small_value(dump, index);
14100 }
14101}
14102
14103static VALUE
14104ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14105{
14106 ibf_offset_t reading_pos = offset;
14107
14108 const long len = (long)ibf_load_small_value(load, &reading_pos);
14109
14110 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14111 int i;
14112
14113 for (i=0; i<len; i++) {
14114 const VALUE index = ibf_load_small_value(load, &reading_pos);
14115 rb_ary_push(ary, ibf_load_object(load, index));
14116 }
14117
14118 if (header->frozen) rb_ary_freeze(ary);
14119
14120 return ary;
14121}
14122
14123static int
14124ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14125{
14126 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14127
14128 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14129 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14130
14131 ibf_dump_write_small_value(dump, key_index);
14132 ibf_dump_write_small_value(dump, val_index);
14133 return ST_CONTINUE;
14134}
14135
14136static void
14137ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14138{
14139 long len = RHASH_SIZE(obj);
14140 ibf_dump_write_small_value(dump, (VALUE)len);
14141
14142 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14143}
14144
14145static VALUE
14146ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14147{
14148 long len = (long)ibf_load_small_value(load, &offset);
14149 VALUE obj = rb_hash_new_with_size(len);
14150 int i;
14151
14152 for (i = 0; i < len; i++) {
14153 VALUE key_index = ibf_load_small_value(load, &offset);
14154 VALUE val_index = ibf_load_small_value(load, &offset);
14155
14156 VALUE key = ibf_load_object(load, key_index);
14157 VALUE val = ibf_load_object(load, val_index);
14158 rb_hash_aset(obj, key, val);
14159 }
14160 rb_hash_rehash(obj);
14161
14162 if (header->internal) rb_obj_hide(obj);
14163 if (header->frozen) rb_obj_freeze(obj);
14164
14165 return obj;
14166}
14167
14168static void
14169ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14170{
14171 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14172 struct ibf_object_struct_range range;
14173 VALUE beg, end;
14174 IBF_ZERO(range);
14175 range.len = 3;
14176 range.class_index = 0;
14177
14178 rb_range_values(obj, &beg, &end, &range.excl);
14179 range.beg = (long)ibf_dump_object(dump, beg);
14180 range.end = (long)ibf_dump_object(dump, end);
14181
14182 IBF_W_ALIGN(struct ibf_object_struct_range);
14183 IBF_WV(range);
14184 }
14185 else {
14186 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14187 rb_class_name(CLASS_OF(obj)));
14188 }
14189}
14190
14191static VALUE
14192ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14193{
14194 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14195 VALUE beg = ibf_load_object(load, range->beg);
14196 VALUE end = ibf_load_object(load, range->end);
14197 VALUE obj = rb_range_new(beg, end, range->excl);
14198 if (header->internal) rb_obj_hide(obj);
14199 if (header->frozen) rb_obj_freeze(obj);
14200 return obj;
14201}
14202
14203static void
14204ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14205{
14206 ssize_t len = BIGNUM_LEN(obj);
14207 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14208 BDIGIT *d = BIGNUM_DIGITS(obj);
14209
14210 (void)IBF_W(&slen, ssize_t, 1);
14211 IBF_WP(d, BDIGIT, len);
14212}
14213
14214static VALUE
14215ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14216{
14217 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14218 int sign = bignum->slen > 0;
14219 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14220 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14223 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14224 big_unpack_flags |
14225 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14226 if (header->internal) rb_obj_hide(obj);
14227 if (header->frozen) rb_obj_freeze(obj);
14228 return obj;
14229}
14230
14231static void
14232ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14233{
14234 if (rb_data_is_encoding(obj)) {
14235 rb_encoding *enc = rb_to_encoding(obj);
14236 const char *name = rb_enc_name(enc);
14237 long len = strlen(name) + 1;
14238 long data[2];
14239 data[0] = IBF_OBJECT_DATA_ENCODING;
14240 data[1] = len;
14241 (void)IBF_W(data, long, 2);
14242 IBF_WP(name, char, len);
14243 }
14244 else {
14245 ibf_dump_object_unsupported(dump, obj);
14246 }
14247}
14248
14249static VALUE
14250ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14251{
14252 const long *body = IBF_OBJBODY(long, offset);
14253 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14254 /* const long len = body[1]; */
14255 const char *data = (const char *)&body[2];
14256
14257 switch (type) {
14258 case IBF_OBJECT_DATA_ENCODING:
14259 {
14260 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14261 return encobj;
14262 }
14263 }
14264
14265 return ibf_load_object_unsupported(load, header, offset);
14266}
14267
14268static void
14269ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14270{
14271 long data[2];
14272 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14273 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14274
14275 (void)IBF_W(data, long, 2);
14276}
14277
14278static VALUE
14279ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14280{
14281 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14282 VALUE a = ibf_load_object(load, nums->a);
14283 VALUE b = ibf_load_object(load, nums->b);
14284 VALUE obj = header->type == T_COMPLEX ?
14285 rb_complex_new(a, b) : rb_rational_new(a, b);
14286
14287 if (header->internal) rb_obj_hide(obj);
14288 if (header->frozen) rb_obj_freeze(obj);
14289 return obj;
14290}
14291
14292static void
14293ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14294{
14295 ibf_dump_object_string(dump, rb_sym2str(obj));
14296}
14297
14298static VALUE
14299ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14300{
14301 ibf_offset_t reading_pos = offset;
14302
14303 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14304 const long len = (long)ibf_load_small_value(load, &reading_pos);
14305 const char *ptr = load->current_buffer->buff + reading_pos;
14306
14307 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14308 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14309 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14310 }
14311
14312 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14313 return ID2SYM(id);
14314}
14315
14316typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14317static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14318 ibf_dump_object_unsupported, /* T_NONE */
14319 ibf_dump_object_unsupported, /* T_OBJECT */
14320 ibf_dump_object_class, /* T_CLASS */
14321 ibf_dump_object_unsupported, /* T_MODULE */
14322 ibf_dump_object_float, /* T_FLOAT */
14323 ibf_dump_object_string, /* T_STRING */
14324 ibf_dump_object_regexp, /* T_REGEXP */
14325 ibf_dump_object_array, /* T_ARRAY */
14326 ibf_dump_object_hash, /* T_HASH */
14327 ibf_dump_object_struct, /* T_STRUCT */
14328 ibf_dump_object_bignum, /* T_BIGNUM */
14329 ibf_dump_object_unsupported, /* T_FILE */
14330 ibf_dump_object_data, /* T_DATA */
14331 ibf_dump_object_unsupported, /* T_MATCH */
14332 ibf_dump_object_complex_rational, /* T_COMPLEX */
14333 ibf_dump_object_complex_rational, /* T_RATIONAL */
14334 ibf_dump_object_unsupported, /* 0x10 */
14335 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14336 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14337 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14338 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14339 ibf_dump_object_unsupported, /* T_FIXNUM */
14340 ibf_dump_object_unsupported, /* T_UNDEF */
14341 ibf_dump_object_unsupported, /* 0x17 */
14342 ibf_dump_object_unsupported, /* 0x18 */
14343 ibf_dump_object_unsupported, /* 0x19 */
14344 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14345 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14346 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14347 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14348 ibf_dump_object_unsupported, /* 0x1e */
14349 ibf_dump_object_unsupported, /* 0x1f */
14350};
14351
14352static void
14353ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14354{
14355 unsigned char byte =
14356 (header.type << 0) |
14357 (header.special_const << 5) |
14358 (header.frozen << 6) |
14359 (header.internal << 7);
14360
14361 IBF_WV(byte);
14362}
14363
14364static struct ibf_object_header
14365ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14366{
14367 unsigned char byte = ibf_load_byte(load, offset);
14368
14369 struct ibf_object_header header;
14370 header.type = (byte >> 0) & 0x1f;
14371 header.special_const = (byte >> 5) & 0x01;
14372 header.frozen = (byte >> 6) & 0x01;
14373 header.internal = (byte >> 7) & 0x01;
14374
14375 return header;
14376}
14377
14378static ibf_offset_t
14379ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14380{
14381 struct ibf_object_header obj_header;
14382 ibf_offset_t current_offset;
14383 IBF_ZERO(obj_header);
14384 obj_header.type = TYPE(obj);
14385
14386 IBF_W_ALIGN(ibf_offset_t);
14387 current_offset = ibf_dump_pos(dump);
14388
14389 if (SPECIAL_CONST_P(obj) &&
14390 ! (SYMBOL_P(obj) ||
14391 RB_FLOAT_TYPE_P(obj))) {
14392 obj_header.special_const = TRUE;
14393 obj_header.frozen = TRUE;
14394 obj_header.internal = TRUE;
14395 ibf_dump_object_object_header(dump, obj_header);
14396 ibf_dump_write_small_value(dump, obj);
14397 }
14398 else {
14399 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14400 obj_header.special_const = FALSE;
14401 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14402 ibf_dump_object_object_header(dump, obj_header);
14403 (*dump_object_functions[obj_header.type])(dump, obj);
14404 }
14405
14406 return current_offset;
14407}
14408
14409typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14410static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14411 ibf_load_object_unsupported, /* T_NONE */
14412 ibf_load_object_unsupported, /* T_OBJECT */
14413 ibf_load_object_class, /* T_CLASS */
14414 ibf_load_object_unsupported, /* T_MODULE */
14415 ibf_load_object_float, /* T_FLOAT */
14416 ibf_load_object_string, /* T_STRING */
14417 ibf_load_object_regexp, /* T_REGEXP */
14418 ibf_load_object_array, /* T_ARRAY */
14419 ibf_load_object_hash, /* T_HASH */
14420 ibf_load_object_struct, /* T_STRUCT */
14421 ibf_load_object_bignum, /* T_BIGNUM */
14422 ibf_load_object_unsupported, /* T_FILE */
14423 ibf_load_object_data, /* T_DATA */
14424 ibf_load_object_unsupported, /* T_MATCH */
14425 ibf_load_object_complex_rational, /* T_COMPLEX */
14426 ibf_load_object_complex_rational, /* T_RATIONAL */
14427 ibf_load_object_unsupported, /* 0x10 */
14428 ibf_load_object_unsupported, /* T_NIL */
14429 ibf_load_object_unsupported, /* T_TRUE */
14430 ibf_load_object_unsupported, /* T_FALSE */
14431 ibf_load_object_symbol,
14432 ibf_load_object_unsupported, /* T_FIXNUM */
14433 ibf_load_object_unsupported, /* T_UNDEF */
14434 ibf_load_object_unsupported, /* 0x17 */
14435 ibf_load_object_unsupported, /* 0x18 */
14436 ibf_load_object_unsupported, /* 0x19 */
14437 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14438 ibf_load_object_unsupported, /* T_NODE 0x1b */
14439 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14440 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14441 ibf_load_object_unsupported, /* 0x1e */
14442 ibf_load_object_unsupported, /* 0x1f */
14443};
14444
14445static VALUE
14446ibf_load_object(const struct ibf_load *load, VALUE object_index)
14447{
14448 if (object_index == 0) {
14449 return Qnil;
14450 }
14451 else {
14452 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14453 if (!obj) {
14454 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14455 ibf_offset_t offset = offsets[object_index];
14456 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14457
14458#if IBF_ISEQ_DEBUG
14459 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14460 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14461 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14462 header.type, header.special_const, header.frozen, header.internal);
14463#endif
14464 if (offset >= load->current_buffer->size) {
14465 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14466 }
14467
14468 if (header.special_const) {
14469 ibf_offset_t reading_pos = offset;
14470
14471 obj = ibf_load_small_value(load, &reading_pos);
14472 }
14473 else {
14474 obj = (*load_object_functions[header.type])(load, &header, offset);
14475 }
14476
14477 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14478 }
14479#if IBF_ISEQ_DEBUG
14480 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14481 object_index, obj);
14482#endif
14483 return obj;
14484 }
14485}
14486
14488{
14489 struct ibf_dump *dump;
14490 VALUE offset_list;
14491};
14492
14493static int
14494ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14495{
14496 VALUE obj = (VALUE)key;
14497 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14498
14499 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14500 rb_ary_push(args->offset_list, UINT2NUM(offset));
14501
14502 return ST_CONTINUE;
14503}
14504
14505static void
14506ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14507{
14508 st_table *obj_table = dump->current_buffer->obj_table;
14509 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14510
14511 struct ibf_dump_object_list_arg args;
14512 args.dump = dump;
14513 args.offset_list = offset_list;
14514
14515 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14516
14517 IBF_W_ALIGN(ibf_offset_t);
14518 *obj_list_offset = ibf_dump_pos(dump);
14519
14520 st_index_t size = obj_table->num_entries;
14521 st_index_t i;
14522
14523 for (i=0; i<size; i++) {
14524 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14525 IBF_WV(offset);
14526 }
14527
14528 *obj_list_size = (unsigned int)size;
14529}
14530
14531static void
14532ibf_dump_mark(void *ptr)
14533{
14534 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14535 rb_gc_mark(dump->global_buffer.str);
14536
14537 rb_mark_set(dump->global_buffer.obj_table);
14538 rb_mark_set(dump->iseq_table);
14539}
14540
14541static void
14542ibf_dump_free(void *ptr)
14543{
14544 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14545 if (dump->global_buffer.obj_table) {
14546 st_free_table(dump->global_buffer.obj_table);
14547 dump->global_buffer.obj_table = 0;
14548 }
14549 if (dump->iseq_table) {
14550 st_free_table(dump->iseq_table);
14551 dump->iseq_table = 0;
14552 }
14553}
14554
14555static size_t
14556ibf_dump_memsize(const void *ptr)
14557{
14558 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14559 size_t size = 0;
14560 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14561 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14562 return size;
14563}
14564
14565static const rb_data_type_t ibf_dump_type = {
14566 "ibf_dump",
14567 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14568 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14569};
14570
14571static void
14572ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14573{
14574 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14575 dump->iseq_table = NULL;
14576
14577 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14578 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14579 dump->iseq_table = st_init_numtable(); /* need free */
14580
14581 dump->current_buffer = &dump->global_buffer;
14582}
14583
14584VALUE
14585rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14586{
14587 struct ibf_dump *dump;
14588 struct ibf_header header = {{0}};
14589 VALUE dump_obj;
14590 VALUE str;
14591
14592 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14593 ISEQ_BODY(iseq)->local_iseq != iseq) {
14594 rb_raise(rb_eRuntimeError, "should be top of iseq");
14595 }
14596 if (RTEST(ISEQ_COVERAGE(iseq))) {
14597 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14598 }
14599
14600 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14601 ibf_dump_setup(dump, dump_obj);
14602
14603 ibf_dump_write(dump, &header, sizeof(header));
14604 ibf_dump_iseq(dump, iseq);
14605
14606 header.magic[0] = 'Y'; /* YARB */
14607 header.magic[1] = 'A';
14608 header.magic[2] = 'R';
14609 header.magic[3] = 'B';
14610 header.major_version = IBF_MAJOR_VERSION;
14611 header.minor_version = IBF_MINOR_VERSION;
14612 header.endian = IBF_ENDIAN_MARK;
14613 header.wordsize = (uint8_t)SIZEOF_VALUE;
14614 ibf_dump_iseq_list(dump, &header);
14615 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14616 header.size = ibf_dump_pos(dump);
14617
14618 if (RTEST(opt)) {
14619 VALUE opt_str = opt;
14620 const char *ptr = StringValuePtr(opt_str);
14621 header.extra_size = RSTRING_LENINT(opt_str);
14622 ibf_dump_write(dump, ptr, header.extra_size);
14623 }
14624 else {
14625 header.extra_size = 0;
14626 }
14627
14628 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14629
14630 str = dump->global_buffer.str;
14631 RB_GC_GUARD(dump_obj);
14632 return str;
14633}
14634
14635static const ibf_offset_t *
14636ibf_iseq_list(const struct ibf_load *load)
14637{
14638 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14639}
14640
14641void
14642rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14643{
14644 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14645 rb_iseq_t *prev_src_iseq = load->iseq;
14646 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14647 load->iseq = iseq;
14648#if IBF_ISEQ_DEBUG
14649 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14650 iseq->aux.loader.index, offset,
14651 load->header->size);
14652#endif
14653 ibf_load_iseq_each(load, iseq, offset);
14654 ISEQ_COMPILE_DATA_CLEAR(iseq);
14655 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14656 rb_iseq_init_trace(iseq);
14657 load->iseq = prev_src_iseq;
14658}
14659
14660#if USE_LAZY_LOAD
14661const rb_iseq_t *
14662rb_iseq_complete(const rb_iseq_t *iseq)
14663{
14664 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14665 return iseq;
14666}
14667#endif
14668
14669static rb_iseq_t *
14670ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14671{
14672 int iseq_index = (int)(VALUE)index_iseq;
14673
14674#if IBF_ISEQ_DEBUG
14675 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14676 (void *)index_iseq, (void *)load->iseq_list);
14677#endif
14678 if (iseq_index == -1) {
14679 return NULL;
14680 }
14681 else {
14682 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14683
14684#if IBF_ISEQ_DEBUG
14685 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14686#endif
14687 if (iseqv) {
14688 return (rb_iseq_t *)iseqv;
14689 }
14690 else {
14691 rb_iseq_t *iseq = iseq_imemo_alloc();
14692#if IBF_ISEQ_DEBUG
14693 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14694#endif
14695 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14696 iseq->aux.loader.obj = load->loader_obj;
14697 iseq->aux.loader.index = iseq_index;
14698#if IBF_ISEQ_DEBUG
14699 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14700 (void *)iseq, (void *)load->loader_obj, iseq_index);
14701#endif
14702 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14703
14704 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14705#if IBF_ISEQ_DEBUG
14706 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14707#endif
14708 rb_ibf_load_iseq_complete(iseq);
14709 }
14710
14711#if IBF_ISEQ_DEBUG
14712 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14713 (void *)iseq, (void *)load->iseq);
14714#endif
14715 return iseq;
14716 }
14717 }
14718}
14719
14720static void
14721ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14722{
14723 struct ibf_header *header = (struct ibf_header *)bytes;
14724 load->loader_obj = loader_obj;
14725 load->global_buffer.buff = bytes;
14726 load->header = header;
14727 load->global_buffer.size = header->size;
14728 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14729 load->global_buffer.obj_list_size = header->global_object_list_size;
14730 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14731 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14732 load->iseq = NULL;
14733
14734 load->current_buffer = &load->global_buffer;
14735
14736 if (size < header->size) {
14737 rb_raise(rb_eRuntimeError, "broken binary format");
14738 }
14739 if (strncmp(header->magic, "YARB", 4) != 0) {
14740 rb_raise(rb_eRuntimeError, "unknown binary format");
14741 }
14742 if (header->major_version != IBF_MAJOR_VERSION ||
14743 header->minor_version != IBF_MINOR_VERSION) {
14744 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14745 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14746 }
14747 if (header->endian != IBF_ENDIAN_MARK) {
14748 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14749 }
14750 if (header->wordsize != SIZEOF_VALUE) {
14751 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14752 }
14753 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14754 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14755 header->iseq_list_offset);
14756 }
14757 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14758 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14759 load->global_buffer.obj_list_offset);
14760 }
14761}
14762
14763static void
14764ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14765{
14766 StringValue(str);
14767
14768 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14769 rb_raise(rb_eRuntimeError, "broken binary format");
14770 }
14771
14772 if (USE_LAZY_LOAD) {
14773 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14774 }
14775
14776 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14777 RB_OBJ_WRITE(loader_obj, &load->str, str);
14778}
14779
14780static void
14781ibf_loader_mark(void *ptr)
14782{
14783 struct ibf_load *load = (struct ibf_load *)ptr;
14784 rb_gc_mark(load->str);
14785 rb_gc_mark(load->iseq_list);
14786 rb_gc_mark(load->global_buffer.obj_list);
14787}
14788
14789static void
14790ibf_loader_free(void *ptr)
14791{
14792 struct ibf_load *load = (struct ibf_load *)ptr;
14793 ruby_xfree(load);
14794}
14795
14796static size_t
14797ibf_loader_memsize(const void *ptr)
14798{
14799 return sizeof(struct ibf_load);
14800}
14801
14802static const rb_data_type_t ibf_load_type = {
14803 "ibf_loader",
14804 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14805 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14806};
14807
14808const rb_iseq_t *
14809rb_iseq_ibf_load(VALUE str)
14810{
14811 struct ibf_load *load;
14812 rb_iseq_t *iseq;
14813 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14814
14815 ibf_load_setup(load, loader_obj, str);
14816 iseq = ibf_load_iseq(load, 0);
14817
14818 RB_GC_GUARD(loader_obj);
14819 return iseq;
14820}
14821
14822const rb_iseq_t *
14823rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14824{
14825 struct ibf_load *load;
14826 rb_iseq_t *iseq;
14827 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14828
14829 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14830 iseq = ibf_load_iseq(load, 0);
14831
14832 RB_GC_GUARD(loader_obj);
14833 return iseq;
14834}
14835
14836VALUE
14837rb_iseq_ibf_load_extra_data(VALUE str)
14838{
14839 struct ibf_load *load;
14840 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14841 VALUE extra_str;
14842
14843 ibf_load_setup(load, loader_obj, str);
14844 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14845 RB_GC_GUARD(loader_obj);
14846 return extra_str;
14847}
14848
14849#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:1674
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:695
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:109
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:100
VALUE rb_cHash
Hash class.
Definition hash.c:109
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:684
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:907
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1326
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c: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:1839
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:69
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:4220
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:3757
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1711
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4121
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4107
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3525
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:3723
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4175
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:3994
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3238
#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:1513
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:498
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:974
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:993
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:943
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:1429
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:163
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:103
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:523
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:458
#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:505
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9067
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:30
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:280
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:287
Definition vm_core.h:290
Definition iseq.h:251
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:204
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:211
struct rb_iseq_constant_body::@154 param
parameter information
Definition st.h:79
Definition vm_core.h:299
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145