Ruby 4.1.0dev (2026-09-26 revision b49347c28a15c475eba951ce426564647aeeacf0)
compile.c (b49347c28a15c475eba951ce426564647aeeacf0)
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/coverage.h"
25#include "internal/complex.h"
26#include "internal/encoding.h"
27#include "internal/error.h"
28#include "internal/gc.h"
29#include "internal/hash.h"
30#include "internal/io.h"
31#include "internal/numeric.h"
32#include "internal/object.h"
33#include "internal/rational.h"
34#include "internal/re.h"
35#include "internal/ruby_parser.h"
36#include "internal/symbol.h"
37#include "internal/thread.h"
38#include "internal/variable.h"
39#include "iseq.h"
40#include "ruby/ractor.h"
41#include "ruby/re.h"
42#include "ruby/util.h"
43#include "vm_core.h"
44#include "vm_callinfo.h"
45#include "vm_debug.h"
46#include "yjit.h"
47
48#include "builtin.h"
49#include "insns.inc"
50#include "insns_info.inc"
51
52#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
53
54typedef struct iseq_link_element {
55 enum {
56 ISEQ_ELEMENT_ANCHOR,
57 ISEQ_ELEMENT_LABEL,
58 ISEQ_ELEMENT_INSN,
59 ISEQ_ELEMENT_ADJUST,
60 ISEQ_ELEMENT_TRACE,
61 } type;
62 struct iseq_link_element *next;
63 struct iseq_link_element *prev;
65
66typedef struct iseq_link_anchor {
67 LINK_ELEMENT anchor;
68 LINK_ELEMENT *last;
70
71typedef enum {
72 LABEL_RESCUE_NONE,
73 LABEL_RESCUE_BEG,
74 LABEL_RESCUE_END,
75 LABEL_RESCUE_TYPE_MAX
76} LABEL_RESCUE_TYPE;
77
78typedef struct iseq_label_data {
79 LINK_ELEMENT link;
80 int label_no;
81 int position;
82 int sc_state;
83 int sp;
84 int refcnt;
85 unsigned int set: 1;
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
88} LABEL;
89
90typedef struct iseq_insn_data {
91 LINK_ELEMENT link;
92 enum ruby_vminsn_type insn_id;
93 int operand_size;
94 int sc_state;
95 VALUE *operands;
96 struct {
97 int line_no;
98 int node_id;
99 rb_event_flag_t events;
100 } insn_info;
101} INSN;
102
103typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
122 const void *ensure_node;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
142#ifndef CPDEBUG
143#define CPDEBUG 0
144#endif
145
146#if CPDEBUG >= 0
147#define compile_debug CPDEBUG
148#else
149#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
150#endif
151
152#if CPDEBUG
153
154#define compile_debug_print_indent(level) \
155 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156
157#define debugp(header, value) (void) \
158 (compile_debug_print_indent(1) && \
159 ruby_debug_print_value(1, compile_debug, (header), (value)))
160
161#define debugi(header, id) (void) \
162 (compile_debug_print_indent(1) && \
163 ruby_debug_print_id(1, compile_debug, (header), (id)))
164
165#define debugp_param(header, value) (void) \
166 (compile_debug_print_indent(1) && \
167 ruby_debug_print_value(1, compile_debug, (header), (value)))
168
169#define debugp_verbose(header, value) (void) \
170 (compile_debug_print_indent(2) && \
171 ruby_debug_print_value(2, compile_debug, (header), (value)))
172
173#define debugp_verbose_node(header, value) (void) \
174 (compile_debug_print_indent(10) && \
175 ruby_debug_print_value(10, compile_debug, (header), (value)))
176
177#define debug_node_start(node) ((void) \
178 (compile_debug_print_indent(1) && \
179 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
180 gl_node_level++)
181
182#define debug_node_end() gl_node_level --
183
184#else
185
186#define debugi(header, id) ((void)0)
187#define debugp(header, value) ((void)0)
188#define debugp_verbose(header, value) ((void)0)
189#define debugp_verbose_node(header, value) ((void)0)
190#define debugp_param(header, value) ((void)0)
191#define debug_node_start(node) ((void)0)
192#define debug_node_end() ((void)0)
193#endif
194
195#if CPDEBUG > 1 || CPDEBUG < 0
196#undef printf
197#define printf ruby_debug_printf
198#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#else
201#define debugs if(0)printf
202#define debug_compile(msg, v) (v)
203#endif
204
205#define LVAR_ERRINFO (1)
206
207/* create new label */
208#define NEW_LABEL(l) new_label_body(iseq, (l))
209#define LABEL_FORMAT "<L%03d>"
210
211#define NEW_ISEQ(node, name, type, line_no) \
212 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213
214#define NEW_CHILD_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216
217#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
218 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
219
220/* add instructions */
221#define ADD_SEQ(seq1, seq2) \
222 APPEND_LIST((seq1), (seq2))
223
224/* add an instruction */
225#define ADD_INSN(seq, line_node, insn) \
226 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
227
228/* add an instruction with the given line number and node id */
229#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
230 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
231
232/* insert an instruction before next */
233#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
234 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
235
236/* insert an instruction after prev */
237#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
238 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
239
240/* add an instruction with some operands (1, 2, 3, 5) */
241#define ADD_INSN1(seq, line_node, insn, op1) \
242 ADD_ELEM((seq), (LINK_ELEMENT *) \
243 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
244
245/* insert an instruction with some operands (1, 2, 3, 5) before next */
246#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
247 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
248 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
249
250/* insert an instruction with some operands (1, 2, 3, 5) after prev */
251#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
252 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
253 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
254
255#define LABEL_REF(label) ((label)->refcnt++)
256
257/* add an instruction with label operand (alias of ADD_INSN1) */
258#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
259
260#define ADD_INSN2(seq, line_node, insn, op1, op2) \
261 ADD_ELEM((seq), (LINK_ELEMENT *) \
262 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
263
264#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
265 ADD_ELEM((seq), (LINK_ELEMENT *) \
266 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
267
268/* Specific Insn factory */
269#define ADD_SEND(seq, line_node, id, argc) \
270 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
271
272#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
273 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
274
275#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
276 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
277
278#define ADD_CALL_RECEIVER(seq, line_node) \
279 ADD_INSN((seq), (line_node), putself)
280
281#define ADD_CALL(seq, line_node, id, argc) \
282 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
283
284#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
285 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
286
287#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
288 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)))
289
290#define ADD_TRACE(seq, event) \
291 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
292#define ADD_TRACE_WITH_DATA(seq, event, data) \
293 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
294
295static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
297
298#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
299#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
300
301/* add label */
302#define ADD_LABEL(seq, label) \
303 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
304
305#define APPEND_LABEL(seq, before, label) \
306 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
307
308#define ADD_ADJUST(seq, line_node, label) \
309 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
310
311#define ADD_ADJUST_RESTORE(seq, label) \
312 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
313
314#define LABEL_UNREMOVABLE(label) \
315 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
316#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
317 VALUE _e = rb_ary_new3(5, (type), \
318 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
319 (VALUE)(iseqv), (VALUE)(lc) | 1); \
320 LABEL_UNREMOVABLE(ls); \
321 LABEL_REF(le); \
322 LABEL_REF(lc); \
323 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
324 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
325 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
326} while (0)
327
328/* compile node */
329#define COMPILE(anchor, desc, node) \
330 (debug_compile("== " desc "\n", \
331 iseq_compile_each(iseq, (anchor), (node), 0)))
332
333/* compile node, this node's value will be popped */
334#define COMPILE_POPPED(anchor, desc, node) \
335 (debug_compile("== " desc "\n", \
336 iseq_compile_each(iseq, (anchor), (node), 1)))
337
338/* compile node, which is popped when 'popped' is true */
339#define COMPILE_(anchor, desc, node, popped) \
340 (debug_compile("== " desc "\n", \
341 iseq_compile_each(iseq, (anchor), (node), (popped))))
342
343#define COMPILE_RECV(anchor, desc, node, recv) \
344 (private_recv_p(node) ? \
345 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
346 COMPILE(anchor, desc, recv) ? 0 : -1)
347
348#define OPERAND_AT(insn, idx) \
349 (((INSN*)(insn))->operands[(idx)])
350
351#define INSN_OF(insn) \
352 (((INSN*)(insn))->insn_id)
353
354#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
355#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
356#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
357#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
358#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
359#define IS_NEXT_INSN_ID(link, insn) \
360 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
361
362static inline bool
363IS_INDEPENDENT_INSN(LINK_ELEMENT *link)
364{
365 if (!IS_INSN(link)) {
366 return false;
367 }
368
369 enum ruby_vminsn_type type = INSN_OF(link);
370
371 return (
372 type == BIN(putobject) ||
373 type == BIN(putspecialobject) ||
374 type == BIN(putnil) ||
375 type == BIN(putself) ||
376 type == BIN(duphash) ||
377 type == BIN(getinstancevariable) ||
378 type == BIN(getlocal) ||
379 type == BIN(getlocal_WC_0) ||
380 type == BIN(getlocal_WC_1) ||
381 type == BIN(putobject_INT2FIX_0_) ||
382 type == BIN(putobject_INT2FIX_1_) ||
383 type == BIN(opt_getconstant_path)
384 );
385}
386
387/* error */
388#if CPDEBUG > 0
390#endif
391RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
392static void
393append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
394{
395 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
396 VALUE file = rb_iseq_path(iseq);
397 VALUE err = err_info == Qtrue ? Qfalse : err_info;
398 va_list args;
399
400 va_start(args, fmt);
401 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
402 va_end(args);
403 if (NIL_P(err_info)) {
404 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
405 rb_set_errinfo(err);
406 }
407 else if (!err_info) {
408 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
409 }
410 if (compile_debug) {
411 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
412 rb_exc_fatal(err);
413 }
414}
415
416#if 0
417static void
418compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
419{
420 va_list args;
421 va_start(args, fmt);
422 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
423 va_end(args);
424 abort();
425}
426#endif
427
428#define COMPILE_ERROR append_compile_error
429
430#define ERROR_ARGS_AT(n) iseq, nd_line(n),
431#define ERROR_ARGS ERROR_ARGS_AT(node)
432
433#define EXPECT_NODE(prefix, node, ndtype, errval) \
434do { \
435 const NODE *error_node = (node); \
436 enum node_type error_type = nd_type(error_node); \
437 if (error_type != (ndtype)) { \
438 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
439 prefix ": " #ndtype " is expected, but %s", \
440 ruby_node_name(error_type)); \
441 return errval; \
442 } \
443} while (0)
444
445#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
446do { \
447 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
448 prefix ": must be " #ndtype ", but 0"); \
449 return errval; \
450} while (0)
451
452#define UNKNOWN_NODE(prefix, node, errval) \
453do { \
454 const NODE *error_node = (node); \
455 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
456 ruby_node_name(nd_type(error_node))); \
457 return errval; \
458} while (0)
459
460#define COMPILE_OK 1
461#define COMPILE_NG 0
462
463#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
464#define NO_CHECK(sub) (void)(sub)
465#define BEFORE_RETURN
466
467#define DECL_ANCHOR(name) \
468 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
469#define INIT_ANCHOR(name) \
470 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
471
472static inline VALUE
473freeze_hide_obj(VALUE obj)
474{
475 OBJ_FREEZE(obj);
476 RBASIC_CLEAR_CLASS(obj);
477 return obj;
478}
479
480#include "optinsn.inc"
481#if OPT_INSTRUCTIONS_UNIFICATION
482#include "optunifs.inc"
483#endif
484
485/* for debug */
486#if CPDEBUG < 0
487#define ISEQ_ARG iseq,
488#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
489#else
490#define ISEQ_ARG
491#define ISEQ_ARG_DECLARE
492#endif
493
494#if CPDEBUG
495#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
496#endif
497
498static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
499static void dump_disasm_list(const LINK_ELEMENT *elem);
500
501static int insn_data_length(INSN *iobj);
502static int calc_sp_depth(int depth, INSN *iobj);
503
504static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
505static LABEL *new_label_body(rb_iseq_t *iseq, long line);
506static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
507static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
508
509
510static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
511static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
512static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
513static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
514static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
515
516static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
517static int iseq_set_exception_local_table(rb_iseq_t *iseq);
518static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
519
520static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
521static int iseq_set_exception_table(rb_iseq_t *iseq);
522static int iseq_set_optargs_table(rb_iseq_t *iseq);
523static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
524
525static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
526static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
527
528/*
529 * To make Array to LinkedList, use link_anchor
530 */
531
532static void
533verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
534{
535#if CPDEBUG
536 int flag = 0;
537 LINK_ELEMENT *list, *plist;
538
539 if (!compile_debug) return;
540
541 list = anchor->anchor.next;
542 plist = &anchor->anchor;
543 while (list) {
544 if (plist != list->prev) {
545 flag += 1;
546 }
547 plist = list;
548 list = list->next;
549 }
550
551 if (anchor->last != plist && anchor->last != 0) {
552 flag |= 0x70000;
553 }
554
555 if (flag != 0) {
556 rb_bug("list verify error: %08x (%s)", flag, info);
557 }
558#endif
559}
560#if CPDEBUG < 0
561#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
562#endif
563
564static void
565verify_call_cache(rb_iseq_t *iseq)
566{
567#if CPDEBUG
568 VALUE *original = rb_iseq_original_iseq(iseq);
569 size_t i = 0;
570 while (i < ISEQ_BODY(iseq)->iseq_size) {
571 VALUE insn = original[i];
572 const char *types = insn_op_types(insn);
573
574 for (int j=0; types[j]; j++) {
575 if (types[j] == TS_CALLDATA) {
576 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
577 const struct rb_callinfo *ci = cd->ci;
578 const struct rb_callcache *cc = cd->cc;
579 if (cc != vm_cc_empty()) {
580 vm_ci_dump(ci);
581 rb_bug("call cache is not initialized by vm_cc_empty()");
582 }
583 }
584 }
585 i += insn_len(insn);
586 }
587
588 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
589 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
590 const struct rb_callinfo *ci = cd->ci;
591 const struct rb_callcache *cc = cd->cc;
592 if (cc != NULL && cc != vm_cc_empty()) {
593 vm_ci_dump(ci);
594 rb_bug("call cache is not initialized by vm_cc_empty()");
595 }
596 }
597#endif
598}
599
600/*
601 * elem1, elem2 => elem1, elem2, elem
602 */
603static void
604ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
605{
606 elem->prev = anchor->last;
607 anchor->last->next = elem;
608 anchor->last = elem;
609 verify_list("add", anchor);
610}
611
612/*
613 * elem1, before, elem2 => elem1, before, elem, elem2
614 */
615static void
616APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
617{
618 elem->prev = before;
619 elem->next = before->next;
620 elem->next->prev = elem;
621 before->next = elem;
622 if (before == anchor->last) anchor->last = elem;
623 verify_list("add", anchor);
624}
625#if CPDEBUG < 0
626#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
627#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
628#endif
629
630static int
631branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
632{
633 if (!ISEQ_COVERAGE(iseq)) return 0;
634 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
635 if (first_line <= 0) return 0;
636 return 1;
637}
638
639static VALUE
640setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
641{
642 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
643 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
644 VALUE branch = rb_ary_hidden_new(6);
645
646 rb_hash_aset(structure, key, branch);
647 rb_ary_push(branch, ID2SYM(rb_intern(type)));
648 rb_ary_push(branch, INT2FIX(first_lineno));
649 rb_ary_push(branch, INT2FIX(first_column));
650 rb_ary_push(branch, INT2FIX(last_lineno));
651 rb_ary_push(branch, INT2FIX(last_column));
652 return branch;
653}
654
655static VALUE
656decl_branch_base(rb_iseq_t *iseq, int node_id, const rb_code_location_t *loc, const char *type)
657{
658 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
659
660 /*
661 * A branch base is keyed by [source_hash (in two halves), node_id, first_lineno],
662 * which identifies the branch node stably even across (re-)evals against
663 * the same path.
664 *
665 * if !structure[key]
666 * structure[key] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
667 * else
668 * branches = structure[key][5]
669 * end
670 */
671 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
672 VALUE key = rb_ary_new_from_args(4,
673 ULONG2NUM((unsigned long)(source_hash >> 32)),
674 ULONG2NUM((unsigned long)(source_hash & 0xffffffff)),
675 INT2FIX(node_id),
676 INT2FIX(loc->beg_pos.lineno));
677 rb_ary_freeze(key);
678
679 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
680 VALUE branch_base = rb_hash_aref(structure, key);
681 VALUE branches;
682
683 if (NIL_P(branch_base)) {
684 branch_base = setup_branch(loc, type, structure, key);
685 branches = rb_hash_new();
686 rb_obj_hide(branches);
687 rb_ary_push(branch_base, branches);
688 }
689 else {
690 branches = RARRAY_AREF(branch_base, 5);
691 }
692
693 return branches;
694}
695
696static NODE
697generate_dummy_line_node(int lineno, int node_id)
698{
699 NODE dummy = { 0 };
700 nd_set_line(&dummy, lineno);
701 nd_set_node_id(&dummy, node_id);
702 return dummy;
703}
704
705static void
706add_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)
707{
708 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
709
710 /*
711 * if !branches[branch_id]
712 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
713 * else
714 * counter_idx= branches[branch_id][5]
715 * end
716 */
717
718 VALUE key = INT2FIX(branch_id);
719 VALUE branch = rb_hash_aref(branches, key);
720 long counter_idx;
721
722 if (NIL_P(branch)) {
723 branch = setup_branch(loc, type, branches, key);
724 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
725 counter_idx = RARRAY_LEN(counters);
726 rb_ary_push(branch, LONG2FIX(counter_idx));
727 rb_ary_push(counters, INT2FIX(0));
728 }
729 else {
730 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
731 }
732
733 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
734 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
735}
736
737#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
738
739static int
740validate_label(st_data_t name, st_data_t label, st_data_t arg)
741{
742 rb_iseq_t *iseq = (rb_iseq_t *)arg;
743 LABEL *lobj = (LABEL *)label;
744 if (!lobj->link.next) {
745 do {
746 COMPILE_ERROR(iseq, lobj->position,
747 "%"PRIsVALUE": undefined label",
748 rb_sym2str((VALUE)name));
749 } while (0);
750 }
751 return ST_CONTINUE;
752}
753
754static void
755validate_labels(rb_iseq_t *iseq, st_table *labels_table)
756{
757 st_foreach(labels_table, validate_label, (st_data_t)iseq);
758 st_free_table(labels_table);
759}
760
761static NODE *
762get_nd_recv(const NODE *node)
763{
764 switch (nd_type(node)) {
765 case NODE_CALL:
766 return RNODE_CALL(node)->nd_recv;
767 case NODE_OPCALL:
768 return RNODE_OPCALL(node)->nd_recv;
769 case NODE_FCALL:
770 return 0;
771 case NODE_QCALL:
772 return RNODE_QCALL(node)->nd_recv;
773 case NODE_VCALL:
774 return 0;
775 case NODE_ATTRASGN:
776 return RNODE_ATTRASGN(node)->nd_recv;
777 case NODE_OP_ASGN1:
778 return RNODE_OP_ASGN1(node)->nd_recv;
779 case NODE_OP_ASGN2:
780 return RNODE_OP_ASGN2(node)->nd_recv;
781 default:
782 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
783 }
784}
785
786static ID
787get_node_call_nd_mid(const NODE *node)
788{
789 switch (nd_type(node)) {
790 case NODE_CALL:
791 return RNODE_CALL(node)->nd_mid;
792 case NODE_OPCALL:
793 return RNODE_OPCALL(node)->nd_mid;
794 case NODE_FCALL:
795 return RNODE_FCALL(node)->nd_mid;
796 case NODE_QCALL:
797 return RNODE_QCALL(node)->nd_mid;
798 case NODE_VCALL:
799 return RNODE_VCALL(node)->nd_mid;
800 case NODE_ATTRASGN:
801 return RNODE_ATTRASGN(node)->nd_mid;
802 default:
803 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
804 }
805}
806
807static NODE *
808get_nd_args(const NODE *node)
809{
810 switch (nd_type(node)) {
811 case NODE_CALL:
812 return RNODE_CALL(node)->nd_args;
813 case NODE_OPCALL:
814 return RNODE_OPCALL(node)->nd_args;
815 case NODE_FCALL:
816 return RNODE_FCALL(node)->nd_args;
817 case NODE_QCALL:
818 return RNODE_QCALL(node)->nd_args;
819 case NODE_VCALL:
820 return 0;
821 case NODE_ATTRASGN:
822 return RNODE_ATTRASGN(node)->nd_args;
823 default:
824 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
825 }
826}
827
828static ID
829get_node_colon_nd_mid(const NODE *node)
830{
831 switch (nd_type(node)) {
832 case NODE_COLON2:
833 return RNODE_COLON2(node)->nd_mid;
834 case NODE_COLON3:
835 return RNODE_COLON3(node)->nd_mid;
836 default:
837 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
838 }
839}
840
841static ID
842get_nd_vid(const NODE *node)
843{
844 switch (nd_type(node)) {
845 case NODE_LASGN:
846 return RNODE_LASGN(node)->nd_vid;
847 case NODE_DASGN:
848 return RNODE_DASGN(node)->nd_vid;
849 case NODE_IASGN:
850 return RNODE_IASGN(node)->nd_vid;
851 case NODE_CVASGN:
852 return RNODE_CVASGN(node)->nd_vid;
853 default:
854 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
855 }
856}
857
858static NODE *
859get_nd_value(const NODE *node)
860{
861 switch (nd_type(node)) {
862 case NODE_LASGN:
863 return RNODE_LASGN(node)->nd_value;
864 case NODE_DASGN:
865 return RNODE_DASGN(node)->nd_value;
866 default:
867 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
868 }
869}
870
871static VALUE
872get_string_value(const NODE *node)
873{
874 switch (nd_type(node)) {
875 case NODE_STR:
876 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
877 case NODE_FILE:
878 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
879 default:
880 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
881 }
882}
883
884VALUE
885rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
886{
887 DECL_ANCHOR(ret);
888 INIT_ANCHOR(ret);
889
890 (*ifunc->func)(iseq, ret, ifunc->data);
891
892 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
893
894 CHECK(iseq_setup_insn(iseq, ret));
895 return iseq_setup(iseq, ret);
896}
897
898static bool drop_unreachable_return(LINK_ANCHOR *ret);
899
900VALUE
901rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
902{
903 DECL_ANCHOR(ret);
904 INIT_ANCHOR(ret);
905
906 if (node == 0) {
907 NO_CHECK(COMPILE(ret, "nil", node));
908 iseq_set_local_table(iseq, 0, 0);
909 }
910 /* assume node is T_NODE */
911 else if (nd_type_p(node, NODE_SCOPE)) {
912 /* iseq type of top, method, class, block */
913 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
914 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
915 iseq_set_parameters_lvar_state(iseq);
916
917 switch (ISEQ_BODY(iseq)->type) {
918 case ISEQ_TYPE_BLOCK:
919 {
920 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
921 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
922
923 start->rescued = LABEL_RESCUE_BEG;
924 end->rescued = LABEL_RESCUE_END;
925
926 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
927 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
928 ADD_LABEL(ret, start);
929 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
930 ADD_LABEL(ret, end);
931 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
932 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
933
934 /* wide range catch handler must put at last */
935 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
936 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
937 break;
938 }
939 case ISEQ_TYPE_CLASS:
940 {
941 ADD_TRACE(ret, RUBY_EVENT_CLASS);
942 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
943 ADD_TRACE(ret, RUBY_EVENT_END);
944 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
945 break;
946 }
947 case ISEQ_TYPE_METHOD:
948 {
949 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
950 ADD_TRACE(ret, RUBY_EVENT_CALL);
951 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
952 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
953 ADD_TRACE(ret, RUBY_EVENT_RETURN);
954 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
955 break;
956 }
957 default: {
958 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
959 break;
960 }
961 }
962 }
963 else {
964 const char *m;
965#define INVALID_ISEQ_TYPE(type) \
966 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
967 switch (ISEQ_BODY(iseq)->type) {
968 case INVALID_ISEQ_TYPE(METHOD);
969 case INVALID_ISEQ_TYPE(CLASS);
970 case INVALID_ISEQ_TYPE(BLOCK);
971 case INVALID_ISEQ_TYPE(EVAL);
972 case INVALID_ISEQ_TYPE(MAIN);
973 case INVALID_ISEQ_TYPE(TOP);
974#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
975 case ISEQ_TYPE_RESCUE:
976 iseq_set_exception_local_table(iseq);
977 CHECK(COMPILE(ret, "rescue", node));
978 break;
979 case ISEQ_TYPE_ENSURE:
980 iseq_set_exception_local_table(iseq);
981 CHECK(COMPILE_POPPED(ret, "ensure", node));
982 break;
983 case ISEQ_TYPE_PLAIN:
984 CHECK(COMPILE(ret, "ensure", node));
985 break;
986 default:
987 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
988 return COMPILE_NG;
989 invalid_iseq_type:
990 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
991 return COMPILE_NG;
992 }
993 }
994
995 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
996 NODE dummy_line_node = generate_dummy_line_node(0, -1);
997 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
998 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
999 }
1000 else if (!drop_unreachable_return(ret)) {
1001 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
1002 }
1003
1004#if OPT_SUPPORT_JOKE
1005 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
1006 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
1007 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
1008 validate_labels(iseq, labels_table);
1009 }
1010#endif
1011 CHECK(iseq_setup_insn(iseq, ret));
1012 return iseq_setup(iseq, ret);
1013}
1014
1015static int
1016rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
1017{
1018#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1019 const void * const *table = rb_vm_get_insns_address_table();
1020 unsigned int i;
1021 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
1022
1023 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1024 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
1025 int len = insn_len(insn);
1026 encoded[i] = (VALUE)table[insn];
1027 i += len;
1028 }
1029 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
1030#endif
1031
1032#if USE_YJIT
1033 rb_yjit_live_iseq_count++;
1034 rb_yjit_iseq_alloc_count++;
1035#endif
1036
1037 return COMPILE_OK;
1038}
1039
1040VALUE *
1041rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1042{
1043 struct rb_iseq_variable *v = ISEQ_VARIABLE(iseq);
1044 VALUE *original_code = v ? RUBY_ATOMIC_PTR_LOAD(v->original_iseq) : NULL;
1045
1046 if (original_code) return original_code;
1047 original_code = ALLOC_N(VALUE, ISEQ_BODY(iseq)->iseq_size);
1048 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1049
1050#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1051 {
1052 unsigned int i;
1053
1054 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1055 const void *addr = (const void *)original_code[i];
1056 const int insn = rb_vm_insn_addr2insn(addr);
1057
1058 original_code[i] = insn;
1059 i += insn_len(insn);
1060 }
1061 }
1062#endif
1063
1064 /* Concurrent callers can each build a copy; publish only fully
1065 * translated code and keep the first one. */
1066 v = rb_iseq_variable_ensure((rb_iseq_t *)iseq);
1067 VALUE *prev = ATOMIC_PTR_CAS(v->original_iseq,
1068 NULL, original_code);
1069 if (prev) {
1070 SIZED_FREE_N(original_code, ISEQ_BODY(iseq)->iseq_size);
1071 return prev;
1072 }
1073 return original_code;
1074}
1075
1076/*********************************************/
1077/* definition of data structure for compiler */
1078/*********************************************/
1079
1080#if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1081# define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1082#else
1083# define ALIGNMENT_SIZE SIZEOF_VALUE
1084#endif
1085#define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1086
1087#define ALIGNMENT_SIZE_OF(type) alignment_size_assert(RUBY_ALIGNOF(type), #type)
1088
1089static inline size_t
1090alignment_size_assert(size_t align, const char *type)
1091{
1092 RUBY_ASSERT((align & (align - 1)) == 0,
1093 "ALIGNMENT_SIZE_OF(%s):%zd == (2 ** N) is expected", type, align);
1094 return align;
1095}
1096
1097/* calculate padding size for aligned memory access */
1098static inline size_t
1099calc_padding(void *ptr, size_t align)
1100{
1101 size_t mis;
1102 size_t padding = 0;
1103
1104 mis = (size_t)ptr & (align - 1);
1105 if (mis > 0) {
1106 padding = align - mis;
1107 }
1108
1109 return padding;
1110}
1111
1112static void *
1113compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size, size_t align)
1114{
1115 void *ptr = 0;
1116 struct iseq_compile_data_storage *storage = *arena;
1117 size_t padding = calc_padding((void *)&storage->buff[storage->pos], align);
1118
1119 if (size >= INT_MAX - padding) rb_memerror();
1120 if (storage->pos + size + padding > storage->size) {
1121 unsigned int alloc_size = storage->size;
1122
1123 while (alloc_size < size + PADDING_SIZE_MAX) {
1124 if (alloc_size >= INT_MAX / 2) rb_memerror();
1125 alloc_size *= 2;
1126 }
1127 storage->next = (void *)ALLOC_N(char, alloc_size +
1128 offsetof(struct iseq_compile_data_storage, buff));
1129 storage = *arena = storage->next;
1130 storage->next = 0;
1131 storage->pos = 0;
1132 storage->size = alloc_size;
1133 padding = calc_padding((void *)&storage->buff[storage->pos], align);
1134 }
1135
1136 storage->pos += (int)padding;
1137
1138 ptr = (void *)&storage->buff[storage->pos];
1139 storage->pos += (int)size;
1140 return ptr;
1141}
1142
1143static void *
1144compile_data_alloc(rb_iseq_t *iseq, size_t size, size_t align)
1145{
1146 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1147 return compile_data_alloc_with_arena(arena, size, align);
1148}
1149
1150#define compile_data_alloc_type(iseq, type) \
1151 (type *)compile_data_alloc(iseq, sizeof(type), ALIGNMENT_SIZE_OF(type))
1152
1153static inline void *
1154compile_data_alloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1155{
1156 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1157 return compile_data_alloc(iseq, size, align);
1158}
1159
1160#define compile_data_alloc2_type(iseq, type, num) \
1161 (type *)compile_data_alloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1162
1163static inline void *
1164compile_data_calloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1165{
1166 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1167 void *p = compile_data_alloc(iseq, size, align);
1168 memset(p, 0, size);
1169 return p;
1170}
1171
1172#define compile_data_calloc2_type(iseq, type, num) \
1173 (type *)compile_data_calloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1174
1175static INSN *
1176compile_data_alloc_insn(rb_iseq_t *iseq)
1177{
1178 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1179 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN), ALIGNMENT_SIZE_OF(INSN));
1180}
1181
1182static LABEL *
1183compile_data_alloc_label(rb_iseq_t *iseq)
1184{
1185 return compile_data_alloc_type(iseq, LABEL);
1186}
1187
1188static ADJUST *
1189compile_data_alloc_adjust(rb_iseq_t *iseq)
1190{
1191 return compile_data_alloc_type(iseq, ADJUST);
1192}
1193
1194static TRACE *
1195compile_data_alloc_trace(rb_iseq_t *iseq)
1196{
1197 return compile_data_alloc_type(iseq, TRACE);
1198}
1199
1200/*
1201 * elem1, elemX => elem1, elem2, elemX
1202 */
1203static void
1204ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1205{
1206 elem2->next = elem1->next;
1207 elem2->prev = elem1;
1208 elem1->next = elem2;
1209 if (elem2->next) {
1210 elem2->next->prev = elem2;
1211 }
1212}
1213
1214/*
1215 * elem1, elemX => elemX, elem2, elem1
1216 */
1217static void
1218ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1219{
1220 elem2->prev = elem1->prev;
1221 elem2->next = elem1;
1222 elem1->prev = elem2;
1223 if (elem2->prev) {
1224 elem2->prev->next = elem2;
1225 }
1226}
1227
1228/*
1229 * elemX, elem1, elemY => elemX, elem2, elemY
1230 */
1231static void
1232ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1233{
1234 elem2->prev = elem1->prev;
1235 elem2->next = elem1->next;
1236 if (elem1->prev) {
1237 elem1->prev->next = elem2;
1238 }
1239 if (elem1->next) {
1240 elem1->next->prev = elem2;
1241 }
1242}
1243
1244static void
1245ELEM_REMOVE(LINK_ELEMENT *elem)
1246{
1247 elem->prev->next = elem->next;
1248 if (elem->next) {
1249 elem->next->prev = elem->prev;
1250 }
1251}
1252
1253/*
1254 * elem1, elem2 => elem2, elem1
1255 */
1256static void
1257ELEM_SWAP(LINK_ELEMENT *first, LINK_ELEMENT *second)
1258{
1259 RUBY_ASSERT(first->next == second);
1260 RUBY_ASSERT(first == second->prev);
1261
1262 first->prev->next = second;
1263 second->next->prev = first;
1264
1265 first->next = second->next;
1266 second->next = first;
1267
1268 second->prev = first->prev;
1269 first->prev = second;
1270
1271 if (IS_INSN(first) && IS_INSN(second)) {
1272 INSN *first_insn = (INSN*)first;
1273 INSN *second_insn = (INSN*)second;
1274
1275 // [Bug #22299] If both instructions are on the same line and the first one carries
1276 // a line event we need to swap the event as well.
1277 if (first_insn->insn_info.line_no == second_insn->insn_info.line_no) {
1278 rb_event_flag_t mask = (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE);
1279 rb_event_flag_t first_events = first_insn->insn_info.events & mask;
1280 rb_event_flag_t second_events = second_insn->insn_info.events & mask;
1281 first_insn->insn_info.events = (first_insn->insn_info.events & ~mask) | second_events;
1282 second_insn->insn_info.events = (second_insn->insn_info.events & ~mask) | first_events;
1283 }
1284 }
1285}
1286
1287static LINK_ELEMENT *
1288FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1289{
1290 return anchor->anchor.next;
1291}
1292
1293static LINK_ELEMENT *
1294LAST_ELEMENT(LINK_ANCHOR *const anchor)
1295{
1296 return anchor->last;
1297}
1298
1299static LINK_ELEMENT *
1300ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1301{
1302 while (elem) {
1303 switch (elem->type) {
1304 case ISEQ_ELEMENT_INSN:
1305 case ISEQ_ELEMENT_ADJUST:
1306 return elem;
1307 default:
1308 elem = elem->next;
1309 }
1310 }
1311 return NULL;
1312}
1313
1314static int
1315LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1316{
1317 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1318 if (first_insn != NULL &&
1319 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1320 return TRUE;
1321 }
1322 else {
1323 return FALSE;
1324 }
1325}
1326
1327static int
1328LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1329{
1330 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1331 return TRUE;
1332 }
1333 else {
1334 return FALSE;
1335 }
1336}
1337
1338/*
1339 * anc1: e1, e2, e3
1340 * anc2: e4, e5
1341 *#=>
1342 * anc1: e1, e2, e3, e4, e5
1343 * anc2: e4, e5 (broken)
1344 */
1345static void
1346APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1347{
1348 if (anc2->anchor.next) {
1349 /* LINK_ANCHOR must not loop */
1350 RUBY_ASSERT(anc2->last != &anc2->anchor);
1351 anc1->last->next = anc2->anchor.next;
1352 anc2->anchor.next->prev = anc1->last;
1353 anc1->last = anc2->last;
1354 }
1355 else {
1356 RUBY_ASSERT(anc2->last == &anc2->anchor);
1357 }
1358 verify_list("append", anc1);
1359}
1360#if CPDEBUG < 0
1361#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1362#endif
1363
1364#if CPDEBUG && 0
1365static void
1366debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1367{
1368 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1369 printf("----\n");
1370 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1371 (void *)anchor->anchor.next, (void *)anchor->last);
1372 while (list) {
1373 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1374 (void *)list->prev, (int)list->type);
1375 list = list->next;
1376 }
1377 printf("----\n");
1378
1379 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1380 verify_list("debug list", anchor);
1381}
1382#if CPDEBUG < 0
1383#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1384#endif
1385#else
1386#define debug_list(anc, cur) ((void)0)
1387#endif
1388
1389static TRACE *
1390new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1391{
1392 TRACE *trace = compile_data_alloc_trace(iseq);
1393
1394 trace->link.type = ISEQ_ELEMENT_TRACE;
1395 trace->link.next = NULL;
1396 trace->event = event;
1397 trace->data = data;
1398
1399 return trace;
1400}
1401
1402static LABEL *
1403new_label_body(rb_iseq_t *iseq, long line)
1404{
1405 LABEL *labelobj = compile_data_alloc_label(iseq);
1406
1407 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1408 labelobj->link.next = 0;
1409
1410 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1411 labelobj->sc_state = 0;
1412 labelobj->sp = -1;
1413 labelobj->refcnt = 0;
1414 labelobj->set = 0;
1415 labelobj->rescued = LABEL_RESCUE_NONE;
1416 labelobj->unremovable = 0;
1417 labelobj->position = -1;
1418 return labelobj;
1419}
1420
1421static ADJUST *
1422new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1423{
1424 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1425 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1426 adjust->link.next = 0;
1427 adjust->label = label;
1428 adjust->line_no = line;
1429 LABEL_UNREMOVABLE(label);
1430 return adjust;
1431}
1432
1433static void
1434iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1435{
1436 const char *types = insn_op_types(insn->insn_id);
1437 for (int j = 0; types[j]; j++) {
1438 char type = types[j];
1439 switch (type) {
1440 case TS_CDHASH:
1441 case TS_ISEQ:
1442 case TS_VALUE:
1443 case TS_IC: // constant path array
1444 case TS_CALLDATA: // ci is stored.
1445 func(&OPERAND_AT(insn, j), data);
1446 break;
1447 default:
1448 break;
1449 }
1450 }
1451}
1452
1453static void
1454iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1455{
1456 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1458 RBASIC_CLASS(*obj) == 0 || // hidden
1459 RB_OBJ_SHAREABLE_P(*obj));
1460}
1461
1462static INSN *
1463new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1464{
1465 INSN *iobj = compile_data_alloc_insn(iseq);
1466
1467 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1468
1469 iobj->link.type = ISEQ_ELEMENT_INSN;
1470 iobj->link.next = 0;
1471 iobj->insn_id = insn_id;
1472 iobj->insn_info.line_no = line_no;
1473 iobj->insn_info.node_id = node_id;
1474 iobj->insn_info.events = 0;
1475 iobj->operands = argv;
1476 iobj->operand_size = argc;
1477 iobj->sc_state = 0;
1478
1479 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1480
1481 return iobj;
1482}
1483
1484static INSN *
1485new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1486{
1487 VALUE *operands = 0;
1488 va_list argv;
1489 if (argc > 0) {
1490 int i;
1491 va_start(argv, argc);
1492 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1493 for (i = 0; i < argc; i++) {
1494 VALUE v = va_arg(argv, VALUE);
1495 operands[i] = v;
1496 }
1497 va_end(argv);
1498 }
1499 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1500}
1501
1502static INSN *
1503insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1504{
1505 VALUE *operands = 0;
1506 va_list argv;
1507 if (argc > 0) {
1508 int i;
1509 va_start(argv, argc);
1510 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1511 for (i = 0; i < argc; i++) {
1512 VALUE v = va_arg(argv, VALUE);
1513 operands[i] = v;
1514 }
1515 va_end(argv);
1516 }
1517
1518 iobj->insn_id = insn_id;
1519 iobj->operand_size = argc;
1520 iobj->operands = operands;
1521 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1522
1523 return iobj;
1524}
1525
1526static const struct rb_callinfo *
1527new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1528{
1529 VM_ASSERT(argc >= 0);
1530
1531 if (kw_arg) {
1532 flag |= VM_CALL_KWARG;
1533 argc += kw_arg->keyword_len;
1534 }
1535
1536 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1537 && !has_blockiseq) {
1538 flag |= VM_CALL_ARGS_SIMPLE;
1539 }
1540
1541 ISEQ_BODY(iseq)->ci_size++;
1542 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1543 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1544 return ci;
1545}
1546
1547static INSN *
1548new_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)
1549{
1550 VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
1551 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1552 operands[0] = ci;
1553 operands[1] = (VALUE)blockiseq;
1554 if (blockiseq) {
1555 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1556 }
1557
1558 INSN *insn;
1559
1560 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1561 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1562 }
1563 else {
1564 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1565 }
1566
1567 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1568 RB_GC_GUARD(ci);
1569 return insn;
1570}
1571
1572static rb_iseq_t *
1573new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1574 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1575{
1576 rb_iseq_t *ret_iseq;
1577 VALUE ast_value = rb_ruby_ast_new(node);
1578
1579 // The child AST wrapper does not carry the source hash, so copy it from
1580 // the enclosing iseq before compiling, for grandchildren to inherit it.
1581 if (ISEQ_BODY(iseq)->source_hash) {
1582 rb_ast_t *child_ast = rb_ruby_ast_data_get(ast_value);
1583 child_ast->body.source_hash = ISEQ_BODY(iseq)->source_hash;
1584 child_ast->body.has_source_hash = 1;
1585 }
1586
1587 debugs("[new_child_iseq]> ---------------------------------------\n");
1588 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1589 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1590 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1591 line_no, parent,
1592 isolated_depth ? isolated_depth + 1 : 0,
1593 type, ISEQ_COMPILE_DATA(iseq)->option,
1594 ISEQ_SCRIPT_LINES(iseq));
1595 debugs("[new_child_iseq]< ---------------------------------------\n");
1596 return ret_iseq;
1597}
1598
1599static rb_iseq_t *
1600new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1601 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1602{
1603 rb_iseq_t *ret_iseq;
1604
1605 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1606 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1607 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1608 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1609 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1610 return ret_iseq;
1611}
1612
1613static void
1614set_catch_except_p(rb_iseq_t *iseq)
1615{
1616 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1617 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1618 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1619 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1620 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1621 }
1622 }
1623}
1624
1625/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1626 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1627 if catch table exists. But we want to optimize while loop, which always has catch
1628 table entries for break/next/redo.
1629
1630 So this function sets true for limited ISeqs with break/next/redo catch table entries
1631 whose child ISeq would really raise an exception. */
1632static void
1633update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1634{
1635 unsigned int pos;
1636 size_t i;
1637 int insn;
1638 const struct iseq_catch_table *ct = body->catch_table;
1639
1640 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1641 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1642 pos = 0;
1643 while (pos < body->iseq_size) {
1644 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1645 if (insn == BIN(throw)) {
1646 set_catch_except_p(iseq);
1647 break;
1648 }
1649 pos += insn_len(insn);
1650 }
1651
1652 if (ct == NULL)
1653 return;
1654
1655 for (i = 0; i < ct->size; i++) {
1656 const struct iseq_catch_table_entry *entry =
1657 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1658 if (entry->type != CATCH_TYPE_BREAK
1659 && entry->type != CATCH_TYPE_NEXT
1660 && entry->type != CATCH_TYPE_REDO) {
1661 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1662 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1663 break;
1664 }
1665 }
1666}
1667
1668static void
1669iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1670{
1671 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1672 if (NIL_P(catch_table_ary)) return;
1673 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1674 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1675 for (i = 0; i < tlen; i++) {
1676 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1677 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1678 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1679 LINK_ELEMENT *e;
1680
1681 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1682
1683 if (ct != CATCH_TYPE_BREAK
1684 && ct != CATCH_TYPE_NEXT
1685 && ct != CATCH_TYPE_REDO) {
1686
1687 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1688 if (e == cont) {
1689 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1690 ELEM_INSERT_NEXT(end, &nop->link);
1691 break;
1692 }
1693 }
1694 }
1695 }
1696
1697 RB_GC_GUARD(catch_table_ary);
1698}
1699
1700static int
1701iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1702{
1703 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1704 return COMPILE_NG;
1705
1706 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1707
1708 if (compile_debug > 5)
1709 dump_disasm_list(FIRST_ELEMENT(anchor));
1710
1711 debugs("[compile step 3.1 (iseq_optimize)]\n");
1712 iseq_optimize(iseq, anchor);
1713
1714 if (compile_debug > 5)
1715 dump_disasm_list(FIRST_ELEMENT(anchor));
1716
1717 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1718 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1719 iseq_insns_unification(iseq, anchor);
1720 if (compile_debug > 5)
1721 dump_disasm_list(FIRST_ELEMENT(anchor));
1722 }
1723
1724 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1725 iseq_insert_nop_between_end_and_cont(iseq);
1726 if (compile_debug > 5)
1727 dump_disasm_list(FIRST_ELEMENT(anchor));
1728
1729 return COMPILE_OK;
1730}
1731
1732static int
1733iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1734{
1735 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1736 return COMPILE_NG;
1737
1738 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1739 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1740 if (compile_debug > 5)
1741 dump_disasm_list(FIRST_ELEMENT(anchor));
1742
1743 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1744 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1745
1746 debugs("[compile step 4.3 (set_optargs_table)] \n");
1747 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1748
1749 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1750 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1751
1752 debugs("[compile step 6 (update_catch_except_flags)] \n");
1753 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1754 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1755
1756 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1757 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1758 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1759 ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
1760 ISEQ_BODY(iseq)->catch_table = NULL;
1761 }
1762
1763#if VM_INSN_INFO_TABLE_IMPL == 2
1764 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1765 rb_iseq_insns_info_encode_positions(iseq);
1766#endif
1767
1768 if (compile_debug > 1) {
1769 VALUE str = rb_iseq_disasm(iseq);
1770 printf("%s\n", StringValueCStr(str));
1771 }
1772 verify_call_cache(iseq);
1773 debugs("[compile step: finish]\n");
1774
1775 return COMPILE_OK;
1776}
1777
1778static int
1779iseq_set_exception_local_table(rb_iseq_t *iseq)
1780{
1781 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1782 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1783 ISEQ_BODY(iseq)->lvar_states.list = NULL; // $! is read-only, so don't need lvar_states
1784 return COMPILE_OK;
1785}
1786
1787static int
1788get_lvar_level(const rb_iseq_t *iseq)
1789{
1790 int lev = 0;
1791 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1792 lev++;
1793 iseq = ISEQ_BODY(iseq)->parent_iseq;
1794 }
1795 return lev;
1796}
1797
1798static int
1799get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1800{
1801 unsigned int i;
1802
1803 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1804 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1805 return (int)i;
1806 }
1807 }
1808 return -1;
1809}
1810
1811static int
1812get_local_var_idx(const rb_iseq_t *iseq, ID id)
1813{
1814 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1815
1816 if (idx < 0) {
1817 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1818 "get_local_var_idx: %d", idx);
1819 }
1820
1821 return idx;
1822}
1823
1824static int
1825get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1826{
1827 int lv = 0, idx = -1;
1828 const rb_iseq_t *const topmost_iseq = iseq;
1829
1830 while (iseq) {
1831 idx = get_dyna_var_idx_at_raw(iseq, id);
1832 if (idx >= 0) {
1833 break;
1834 }
1835 iseq = ISEQ_BODY(iseq)->parent_iseq;
1836 lv++;
1837 }
1838
1839 if (idx < 0) {
1840 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1841 "get_dyna_var_idx: -1");
1842 }
1843
1844 *level = lv;
1845 *ls = ISEQ_BODY(iseq)->local_table_size;
1846 return idx;
1847}
1848
1849static int
1850iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1851{
1852 const struct rb_iseq_constant_body *body;
1853 while (level > 0) {
1854 iseq = ISEQ_BODY(iseq)->parent_iseq;
1855 level--;
1856 }
1857 body = ISEQ_BODY(iseq);
1858 if (body->local_iseq == iseq && /* local variables */
1859 body->param.flags.has_block &&
1860 body->local_table_size - body->param.block_start == idx) {
1861 return TRUE;
1862 }
1863 else {
1864 return FALSE;
1865 }
1866}
1867
1868static int
1869iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1870{
1871 int level, ls;
1872 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1873 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1874 *pidx = ls - idx;
1875 *plevel = level;
1876 return TRUE;
1877 }
1878 else {
1879 return FALSE;
1880 }
1881}
1882
1883static void
1884access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1885{
1886 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1887
1888 if (isolated_depth && level >= isolated_depth) {
1889 if (id == rb_intern("yield")) {
1890 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1891 }
1892 else {
1893 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1894 }
1895 }
1896
1897 for (int i=0; i<level; i++) {
1898 VALUE val;
1899 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1900
1901 if (!ovs) {
1902 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1903 }
1904
1905 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1906 if (write && !val) {
1907 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1908 }
1909 }
1910 else {
1911 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1912 }
1913
1914 iseq = ISEQ_BODY(iseq)->parent_iseq;
1915 }
1916}
1917
1918static ID
1919iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1920{
1921 for (int i=0; i<level; i++) {
1922 iseq = ISEQ_BODY(iseq)->parent_iseq;
1923 }
1924
1925 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1926 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1927 return id;
1928}
1929
1930static void
1931update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1932{
1933 for (int i=0; i<level; i++) {
1934 iseq = ISEQ_BODY(iseq)->parent_iseq;
1935 }
1936
1937 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1938 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1939 switch (iseq_lvar_state_get(states, table_idx)) {
1940 case lvar_uninitialized:
1941 iseq_lvar_state_set(states, table_idx, lvar_initialized);
1942 break;
1943 case lvar_initialized:
1944 iseq_lvar_state_set(states, table_idx, lvar_reassigned);
1945 break;
1946 case lvar_reassigned:
1947 /* nothing */
1948 break;
1949 default:
1950 rb_bug("unreachable");
1951 }
1952}
1953
1954static int
1955iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1956{
1957 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1958
1959 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1960 iseq_lvar_state_set(states, i, lvar_initialized);
1961 }
1962
1963 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1964 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1965 for (int i=0; i<opt_num; i++) {
1966 iseq_lvar_state_set(states, lead_num + i, lvar_uninitialized);
1967 }
1968
1969 return COMPILE_OK;
1970}
1971
1972static void
1973iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1974{
1975 if (iseq_local_block_param_p(iseq, idx, level)) {
1976 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1977 }
1978 else {
1979 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1980 }
1981 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1982}
1983
1984static void
1985iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1986{
1987 if (iseq_local_block_param_p(iseq, idx, level)) {
1988 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1989 }
1990 else {
1991 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1992 }
1993 update_lvar_state(iseq, level, idx);
1994 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1995}
1996
1997
1998
1999static void
2000iseq_calc_param_size(rb_iseq_t *iseq)
2001{
2002 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2003 if (body->param.flags.has_opt ||
2004 body->param.flags.has_post ||
2005 body->param.flags.has_rest ||
2006 body->param.flags.has_block ||
2007 body->param.flags.has_kw ||
2008 body->param.flags.has_kwrest) {
2009
2010 if (body->param.flags.has_block) {
2011 body->param.size = body->param.block_start + 1;
2012 }
2013 else if (body->param.flags.has_kwrest) {
2014 body->param.size = body->param.keyword->rest_start + 1;
2015 }
2016 else if (body->param.flags.has_kw) {
2017 body->param.size = body->param.keyword->bits_start + 1;
2018 }
2019 else if (body->param.flags.has_post) {
2020 body->param.size = body->param.post_start + body->param.post_num;
2021 }
2022 else if (body->param.flags.has_rest) {
2023 body->param.size = body->param.rest_start + 1;
2024 }
2025 else if (body->param.flags.has_opt) {
2026 body->param.size = body->param.lead_num + body->param.opt_num;
2027 }
2028 else {
2030 }
2031 }
2032 else {
2033 body->param.size = body->param.lead_num;
2034 }
2035}
2036
2037static int
2038iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
2039 const struct rb_args_info *args, int arg_size)
2040{
2041 const rb_node_kw_arg_t *node = args->kw_args;
2042 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2043 struct rb_iseq_param_keyword *keyword;
2044 const VALUE default_values = rb_ary_hidden_new(1);
2045 const VALUE complex_mark = rb_str_tmp_new(0);
2046 int kw = 0, rkw = 0, di = 0, i;
2047
2048 body->param.flags.has_kw = TRUE;
2049 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2050
2051 while (node) {
2052 kw++;
2053 node = node->nd_next;
2054 }
2055 if (kw > VM_CALL_KW_LEN_MAX) {
2056 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args)) "too many keyword parameters (%d, maximum is %d)",
2057 kw, (int)VM_CALL_KW_LEN_MAX);
2058 }
2059 arg_size += kw;
2060 keyword->bits_start = arg_size++;
2061
2062 node = args->kw_args;
2063 while (node) {
2064 const NODE *val_node = get_nd_value(node->nd_body);
2065 VALUE dv;
2066
2067 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2068 ++rkw;
2069 }
2070 else {
2071 switch (nd_type(val_node)) {
2072 case NODE_SYM:
2073 dv = rb_node_sym_string_val(val_node);
2074 break;
2075 case NODE_REGX:
2076 dv = rb_node_regx_string_val(val_node);
2077 break;
2078 case NODE_LINE:
2079 dv = rb_node_line_lineno_val(val_node);
2080 break;
2081 case NODE_INTEGER:
2082 dv = rb_node_integer_literal_val(val_node);
2083 break;
2084 case NODE_FLOAT:
2085 dv = rb_node_float_literal_val(val_node);
2086 break;
2087 case NODE_RATIONAL:
2088 dv = rb_node_rational_literal_val(val_node);
2089 break;
2090 case NODE_IMAGINARY:
2091 dv = rb_node_imaginary_literal_val(val_node);
2092 break;
2093 case NODE_ENCODING:
2094 dv = rb_node_encoding_val(val_node);
2095 break;
2096 case NODE_NIL:
2097 dv = Qnil;
2098 break;
2099 case NODE_TRUE:
2100 dv = Qtrue;
2101 break;
2102 case NODE_FALSE:
2103 dv = Qfalse;
2104 break;
2105 default:
2106 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2107 dv = complex_mark;
2108 }
2109
2110 keyword->num = ++di;
2111 rb_ary_push(default_values, dv);
2112 }
2113
2114 node = node->nd_next;
2115 }
2116
2117 keyword->num = kw;
2118
2119 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2120 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2121 keyword->rest_start = arg_size++;
2122 body->param.flags.has_kwrest = TRUE;
2123
2124 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2125 }
2126 keyword->required_num = rkw;
2127 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2128
2129 if (RARRAY_LEN(default_values)) {
2130 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2131
2132 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2133 VALUE dv = RARRAY_AREF(default_values, i);
2134 if (dv == complex_mark) dv = Qundef;
2136 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2137 }
2138
2139 keyword->default_values = dvs;
2140 }
2141 return arg_size;
2142}
2143
2144static void
2145iseq_set_use_block(rb_iseq_t *iseq)
2146{
2147 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2148 if (!body->param.flags.use_block) {
2149 body->param.flags.use_block = 1;
2150
2151 rb_vm_t *vm = GET_VM();
2152
2153 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2154 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2155 set_insert(&vm->unused_block_warning_table, key);
2156 }
2157 }
2158}
2159
2160static int
2161iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2162{
2163 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2164
2165 if (node_args) {
2166 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2167 const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
2168 ID rest_id = 0;
2169 int last_comma = 0;
2170 ID block_id = 0;
2171 int arg_size;
2172
2173 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2174
2175 body->param.lead_num = arg_size = (int)args->pre_args_num;
2176 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2177 debugs(" - argc: %d\n", body->param.lead_num);
2178
2179 rest_id = args->rest_arg;
2180 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2181 last_comma = 1;
2182 rest_id = 0;
2183 }
2184 block_id = args->block_arg;
2185
2186 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2187
2188 if (optimized_forward) {
2189 rest_id = 0;
2190 block_id = 0;
2191 }
2192
2193 if (args->opt_args) {
2194 const rb_node_opt_arg_t *node = args->opt_args;
2195 LABEL *label;
2196 VALUE labels = rb_ary_hidden_new(1);
2197 VALUE *opt_table;
2198 int i = 0, j;
2199
2200 while (node) {
2201 label = NEW_LABEL(nd_line(RNODE(node)));
2202 rb_ary_push(labels, (VALUE)label | 1);
2203 ADD_LABEL(optargs, label);
2204 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2205 node = node->nd_next;
2206 i += 1;
2207 }
2208
2209 /* last label */
2210 label = NEW_LABEL(nd_line(node_args));
2211 rb_ary_push(labels, (VALUE)label | 1);
2212 ADD_LABEL(optargs, label);
2213
2214 opt_table = ALLOC_N(VALUE, i+1);
2215
2216 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2217 for (j = 0; j < i+1; j++) {
2218 opt_table[j] &= ~1;
2219 }
2220 rb_ary_clear(labels);
2221
2222 body->param.flags.has_opt = TRUE;
2223 body->param.opt_num = i;
2224 body->param.opt_table = opt_table;
2225 arg_size += i;
2226 }
2227
2228 if (rest_id) {
2229 body->param.rest_start = arg_size++;
2230 body->param.flags.has_rest = TRUE;
2231 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2232 RUBY_ASSERT(body->param.rest_start != -1);
2233 }
2234
2235 if (args->first_post_arg) {
2236 body->param.post_start = arg_size;
2237 body->param.post_num = args->post_args_num;
2238 body->param.flags.has_post = TRUE;
2239 arg_size += args->post_args_num;
2240
2241 if (body->param.flags.has_rest) { /* TODO: why that? */
2242 body->param.post_start = body->param.rest_start + 1;
2243 }
2244 }
2245
2246 if (args->kw_args) {
2247 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2248 }
2249 else if (args->kw_rest_arg && !optimized_forward) {
2250 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2251 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2252 keyword->rest_start = arg_size++;
2253 body->param.keyword = keyword;
2254 body->param.flags.has_kwrest = TRUE;
2255
2256 static ID anon_kwrest = 0;
2257 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2258 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2259 }
2260 else if (args->no_kwarg) {
2261 body->param.flags.accepts_no_kwarg = TRUE;
2262 }
2263
2264 if (args->no_blockarg) {
2265 body->param.flags.accepts_no_block = TRUE;
2266 }
2267 else if (block_id) {
2268 body->param.block_start = arg_size++;
2269 body->param.flags.has_block = TRUE;
2270 iseq_set_use_block(iseq);
2271 }
2272
2273 // Only optimize specifically methods like this: `foo(...)`
2274 if (optimized_forward) {
2275 body->param.flags.use_block = 1;
2276 body->param.flags.forwardable = TRUE;
2277 arg_size = 1;
2278 }
2279
2280 iseq_calc_param_size(iseq);
2281 body->param.size = arg_size;
2282
2283 if (args->pre_init) { /* m_init */
2284 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2285 }
2286 if (args->post_init) { /* p_init */
2287 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2288 }
2289
2290 if (body->type == ISEQ_TYPE_BLOCK) {
2291 if (body->param.flags.has_opt == FALSE &&
2292 body->param.flags.has_post == FALSE &&
2293 body->param.flags.has_rest == FALSE &&
2294 body->param.flags.has_kw == FALSE &&
2295 body->param.flags.has_kwrest == FALSE) {
2296
2297 if (body->param.lead_num == 1 && last_comma == 0) {
2298 /* {|a|} */
2299 body->param.flags.ambiguous_param0 = TRUE;
2300 }
2301 }
2302 }
2303 }
2304
2305 return COMPILE_OK;
2306}
2307
2308static int
2309iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2310{
2311 unsigned int size = tbl ? tbl->size : 0;
2312 unsigned int offset = 0;
2313
2314 if (node_args) {
2315 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2316
2317 // If we have a function that only has `...` as the parameter,
2318 // then its local table should only be `...`
2319 // FIXME: I think this should be fixed in the AST rather than special case here.
2320 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2321 CHECK(size >= 3);
2322 size -= 3;
2323 offset += 3;
2324 }
2325 }
2326
2327 if (size > 0) {
2328 ID *ids = ALLOC_N(ID, size);
2329 MEMCPY(ids, tbl->ids + offset, ID, size);
2330 ISEQ_BODY(iseq)->local_table = ids;
2331
2332 if (ISEQ_LVAR_STATES_EMBED_P(size)) {
2333 /* states are embedded in the body; zero them out */
2334 memset(ISEQ_BODY(iseq)->lvar_states.single, 0, sizeof(ISEQ_BODY(iseq)->lvar_states.single));
2335 }
2336 else {
2337 ISEQ_BODY(iseq)->lvar_states.list = ZALLOC_N(uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
2338 }
2339 }
2340 ISEQ_BODY(iseq)->local_table_size = size;
2341
2342 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2343 return COMPILE_OK;
2344}
2345
2346int
2347rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2348{
2349 int tval, tlit;
2350
2351 if (val == lit) {
2352 return 0;
2353 }
2354 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2355 return val != lit;
2356 }
2357 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2358 return -1;
2359 }
2360 else if (tlit != tval) {
2361 return -1;
2362 }
2363 else if (tlit == T_SYMBOL) {
2364 return val != lit;
2365 }
2366 else if (tlit == T_STRING) {
2367 return rb_str_hash_cmp(lit, val);
2368 }
2369 else if (tlit == T_BIGNUM) {
2370 long x = FIX2LONG(rb_big_cmp(lit, val));
2371
2372 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2373 * There is no need to call rb_fix2int here. */
2374 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2375 return (int)x;
2376 }
2377 else if (tlit == T_FLOAT) {
2378 return rb_float_cmp(lit, val);
2379 }
2380 else if (tlit == T_RATIONAL) {
2381 const struct RRational *rat1 = RRATIONAL(val);
2382 const struct RRational *rat2 = RRATIONAL(lit);
2383 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2384 }
2385 else if (tlit == T_COMPLEX) {
2386 const struct RComplex *comp1 = RCOMPLEX(val);
2387 const struct RComplex *comp2 = RCOMPLEX(lit);
2388 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2389 }
2390 else if (tlit == T_REGEXP) {
2391 return rb_reg_equal(val, lit) ? 0 : -1;
2392 }
2393 else {
2395 }
2396}
2397
2398st_index_t
2399rb_iseq_cdhash_hash(VALUE a)
2400{
2401 switch (OBJ_BUILTIN_TYPE(a)) {
2402 case -1:
2403 case T_SYMBOL:
2404 return (st_index_t)a;
2405 case T_STRING:
2406 return rb_str_hash(a);
2407 case T_BIGNUM:
2408 return FIX2LONG(rb_big_hash(a));
2409 case T_FLOAT:
2410 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2411 case T_RATIONAL:
2412 return rb_rational_hash(a);
2413 case T_COMPLEX:
2414 return rb_complex_hash(a);
2415 case T_REGEXP:
2416 return NUM2LONG(rb_reg_hash(a));
2417 default:
2419 }
2420}
2421
2422static const struct st_hash_type cdhash_type = {
2423 rb_iseq_cdhash_cmp,
2424 rb_iseq_cdhash_hash,
2425};
2426
2427static VALUE
2428cdhash_new(size_t size)
2429{
2430 VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
2431 RB_OBJ_SET_SHAREABLE(cdhash);
2432 return cdhash;
2433}
2434
2435static void
2436cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
2437{
2438 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2439 st_insert(tbl, key, val);
2440 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2441}
2442
2443static void
2444cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
2445{
2446 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2447 VALUE dontcare;
2448 if (!st_lookup(tbl, key, &dontcare)) {
2449 st_insert(tbl, key, val);
2450 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2451 }
2452}
2453
2455 VALUE hash;
2456 int pos;
2457 int len;
2458};
2459
2460static int
2461cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
2462{
2463 return ST_REPLACE;
2464}
2465
2466static int
2467cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
2468{
2469 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2470 LABEL *lobj = (LABEL *)(*value & ~1);
2471 *value = lobj->position - (data->pos+data->len);
2472 return ST_CONTINUE;
2473}
2474
2475static inline VALUE
2476get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2477{
2478 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2479}
2480
2481static inline VALUE
2482get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2483{
2484 VALUE val;
2485 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2486 if (tbl) {
2487 if (rb_id_table_lookup(tbl,id,&val)) {
2488 return val;
2489 }
2490 }
2491 else {
2492 tbl = rb_id_table_create(1);
2493 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2494 }
2495 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2496 rb_id_table_insert(tbl,id,val);
2497 return val;
2498}
2499
2500#define BADINSN_DUMP(anchor, list, dest) \
2501 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2502
2503#define BADINSN_ERROR \
2504 (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
2505 SIZED_FREE_N(insns_info, insns_info_size), \
2506 BADINSN_DUMP(anchor, list, NULL), \
2507 COMPILE_ERROR)
2508
2509static int
2510fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2511{
2512 int stack_max = 0, sp = 0, line = 0;
2513 LINK_ELEMENT *list;
2514
2515 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2516 if (IS_LABEL(list)) {
2517 LABEL *lobj = (LABEL *)list;
2518 lobj->set = TRUE;
2519 }
2520 }
2521
2522 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2523 switch (list->type) {
2524 case ISEQ_ELEMENT_INSN:
2525 {
2526 int j, len, insn;
2527 const char *types;
2528 VALUE *operands;
2529 INSN *iobj = (INSN *)list;
2530
2531 /* update sp */
2532 sp = calc_sp_depth(sp, iobj);
2533 if (sp < 0) {
2534 BADINSN_DUMP(anchor, list, NULL);
2535 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2536 "argument stack underflow (%d)", sp);
2537 return -1;
2538 }
2539 if (sp > stack_max) {
2540 stack_max = sp;
2541 }
2542
2543 line = iobj->insn_info.line_no;
2544 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2545 operands = iobj->operands;
2546 insn = iobj->insn_id;
2547 types = insn_op_types(insn);
2548 len = insn_len(insn);
2549
2550 /* operand check */
2551 if (iobj->operand_size != len - 1) {
2552 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2553 BADINSN_DUMP(anchor, list, NULL);
2554 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2555 "operand size miss! (%d for %d)",
2556 iobj->operand_size, len - 1);
2557 return -1;
2558 }
2559
2560 for (j = 0; types[j]; j++) {
2561 if (types[j] == TS_OFFSET) {
2562 /* label(destination position) */
2563 LABEL *lobj = (LABEL *)operands[j];
2564 if (!lobj->set) {
2565 BADINSN_DUMP(anchor, list, NULL);
2566 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2567 "unknown label: "LABEL_FORMAT, lobj->label_no);
2568 return -1;
2569 }
2570 if (lobj->sp == -1) {
2571 lobj->sp = sp;
2572 }
2573 else if (lobj->sp != sp) {
2574 VALUE path = rb_iseq_path(iseq);
2575 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2576 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2577 lobj->label_no, lobj->sp, sp);
2578 }
2579 }
2580 }
2581 break;
2582 }
2583 case ISEQ_ELEMENT_LABEL:
2584 {
2585 LABEL *lobj = (LABEL *)list;
2586 if (lobj->sp == -1) {
2587 lobj->sp = sp;
2588 }
2589 else {
2590 if (lobj->sp != sp) {
2591 VALUE path = rb_iseq_path(iseq);
2592 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2593 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2594 lobj->label_no, lobj->sp, sp);
2595 }
2596 sp = lobj->sp;
2597 }
2598 break;
2599 }
2600 case ISEQ_ELEMENT_TRACE:
2601 {
2602 /* ignore */
2603 break;
2604 }
2605 case ISEQ_ELEMENT_ADJUST:
2606 {
2607 ADJUST *adjust = (ADJUST *)list;
2608 int orig_sp = sp;
2609
2610 sp = adjust->label ? adjust->label->sp : 0;
2611 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2612 BADINSN_DUMP(anchor, list, NULL);
2613 COMPILE_ERROR(iseq, adjust->line_no,
2614 "iseq_set_sequence: adjust bug %d < %d",
2615 orig_sp, sp);
2616 return -1;
2617 }
2618 break;
2619 }
2620 default:
2621 BADINSN_DUMP(anchor, list, NULL);
2622 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2623 return -1;
2624 }
2625 }
2626 return stack_max;
2627}
2628
2629static int
2630add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2631 int insns_info_index, int code_index, const INSN *iobj)
2632{
2633 if (insns_info_index == 0 ||
2634 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2635#ifdef USE_ISEQ_NODE_ID
2636 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2637#endif
2638 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2639 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2640#ifdef USE_ISEQ_NODE_ID
2641 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2642#endif
2643 insns_info[insns_info_index].events = iobj->insn_info.events;
2644 positions[insns_info_index] = code_index;
2645 return TRUE;
2646 }
2647 return FALSE;
2648}
2649
2650static int
2651add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2652 int insns_info_index, int code_index, const ADJUST *adjust)
2653{
2654 insns_info[insns_info_index].line_no = adjust->line_no;
2655 insns_info[insns_info_index].node_id = -1;
2656 insns_info[insns_info_index].events = 0;
2657 positions[insns_info_index] = code_index;
2658 return TRUE;
2659}
2660
2661static ID *
2662array_to_idlist(VALUE arr)
2663{
2665 long size = RARRAY_LEN(arr);
2666 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2667 for (long i = 0; i < size; i++) {
2668 VALUE sym = RARRAY_AREF(arr, i);
2669 ids[i] = SYM2ID(sym);
2670 }
2671 ids[size] = 0;
2672 return ids;
2673}
2674
2675static VALUE
2676idlist_to_array(const ID *ids)
2677{
2678 VALUE arr = rb_ary_new();
2679 while (*ids) {
2680 rb_ary_push(arr, ID2SYM(*ids++));
2681 }
2682 return arr;
2683}
2684
2688static int
2689iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2690{
2691 struct iseq_insn_info_entry *insns_info;
2692 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2693 unsigned int *positions;
2694 LINK_ELEMENT *list;
2695 VALUE *generated_iseq;
2696 rb_event_flag_t events = 0;
2697 long data = 0;
2698
2699 int insn_num, code_index, insns_info_index, sp = 0;
2700 int stack_max = fix_sp_depth(iseq, anchor);
2701
2702 if (stack_max < 0) return COMPILE_NG;
2703
2704 /* fix label position */
2705 insn_num = code_index = 0;
2706 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2707 switch (list->type) {
2708 case ISEQ_ELEMENT_INSN:
2709 {
2710 INSN *iobj = (INSN *)list;
2711 /* update sp */
2712 sp = calc_sp_depth(sp, iobj);
2713 insn_num++;
2714 events = iobj->insn_info.events |= events;
2715 if (ISEQ_COVERAGE(iseq)) {
2716 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2717 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2718 int line = iobj->insn_info.line_no - 1;
2719 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2720 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2721 }
2722 }
2723 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2724 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2725 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2726 }
2727 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2728 }
2729 }
2730 code_index += insn_data_length(iobj);
2731 events = 0;
2732 data = 0;
2733 break;
2734 }
2735 case ISEQ_ELEMENT_LABEL:
2736 {
2737 LABEL *lobj = (LABEL *)list;
2738 lobj->position = code_index;
2739 if (lobj->sp != sp) {
2740 VALUE path = rb_iseq_path(iseq);
2741 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2742 RSTRING_LENINT(path), RSTRING_PTR(path),
2743 lobj->label_no, lobj->sp, sp);
2744 }
2745 sp = lobj->sp;
2746 break;
2747 }
2748 case ISEQ_ELEMENT_TRACE:
2749 {
2750 TRACE *trace = (TRACE *)list;
2751 events |= trace->event;
2752 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2753 break;
2754 }
2755 case ISEQ_ELEMENT_ADJUST:
2756 {
2757 ADJUST *adjust = (ADJUST *)list;
2758 if (adjust->line_no != -1) {
2759 int orig_sp = sp;
2760 sp = adjust->label ? adjust->label->sp : 0;
2761 if (orig_sp - sp > 0) {
2762 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2763 code_index++; /* insn */
2764 insn_num++;
2765 }
2766 }
2767 break;
2768 }
2769 default: break;
2770 }
2771 }
2772
2773 /* make instruction sequence */
2774 const int generated_iseq_size = code_index;
2775 generated_iseq = ALLOC_N(VALUE, code_index);
2776
2777 const int insns_info_size = insn_num;
2778 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2779
2780 const int positions_size = insn_num;
2781 positions = ALLOC_N(unsigned int, insn_num);
2782 if (ISEQ_IS_SIZE(body)) {
2783 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2784 }
2785 else {
2786 body->is_entries = NULL;
2787 }
2788
2789 if (body->ci_size) {
2790 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2791 }
2792 else {
2793 body->call_data = NULL;
2794 }
2795 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2796
2797 // Calculate the bitmask buffer size.
2798 // Round the generated_iseq size up to the nearest multiple
2799 // of the number of bits in an unsigned long.
2800
2801 // Allocate enough room for the bitmask list
2802 iseq_bits_t * mark_offset_bits;
2803 int code_size = code_index;
2804
2805 bool needs_bitmap = false;
2806
2807 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2808 if (mark_offset_bits_size == 1) {
2809 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2810 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2811 }
2812 else {
2813 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2814 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2815 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2816 }
2817
2818 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2819 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2820
2821 list = FIRST_ELEMENT(anchor);
2822 insns_info_index = code_index = sp = 0;
2823
2824 while (list) {
2825 switch (list->type) {
2826 case ISEQ_ELEMENT_INSN:
2827 {
2828 int j, len, insn;
2829 const char *types;
2830 VALUE *operands;
2831 INSN *iobj = (INSN *)list;
2832
2833 /* update sp */
2834 sp = calc_sp_depth(sp, iobj);
2835 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2836 operands = iobj->operands;
2837 insn = iobj->insn_id;
2838 generated_iseq[code_index] = insn;
2839 types = insn_op_types(insn);
2840 len = insn_len(insn);
2841
2842 for (j = 0; types[j]; j++) {
2843 char type = types[j];
2844
2845 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2846 switch (type) {
2847 case TS_OFFSET:
2848 {
2849 /* label(destination position) */
2850 LABEL *lobj = (LABEL *)operands[j];
2851 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2852 break;
2853 }
2854 case TS_CDHASH:
2855 {
2856 VALUE map = operands[j];
2857 struct cdhash_set_label_struct data;
2858 data.hash = map;
2859 data.pos = code_index;
2860 data.len = len;
2861 st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
2862
2863 generated_iseq[code_index + 1 + j] = map;
2864 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2865 RB_OBJ_WRITTEN(iseq, Qundef, map);
2866 needs_bitmap = true;
2867 break;
2868 }
2869 case TS_LINDEX:
2870 case TS_NUM: /* ulong */
2871 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2872 break;
2873 case TS_ISEQ: /* iseq */
2874 case TS_VALUE: /* VALUE */
2875 {
2876 VALUE v = operands[j];
2877 generated_iseq[code_index + 1 + j] = v;
2878 /* to mark ruby object */
2879 if (!SPECIAL_CONST_P(v)) {
2880 RB_OBJ_WRITTEN(iseq, Qundef, v);
2881 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2882 needs_bitmap = true;
2883 }
2884 break;
2885 }
2886 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2887 case TS_IC: /* inline cache: constants */
2888 {
2889 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2890 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2891 if (UNLIKELY(ic_index >= body->ic_size)) {
2892 BADINSN_DUMP(anchor, &iobj->link, 0);
2893 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2894 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2895 ic_index, ISEQ_IS_SIZE(body));
2896 }
2897
2898 ic->segments = array_to_idlist(operands[j]);
2899
2900 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2901 }
2902 break;
2903 case TS_IVC: /* inline ivar cache */
2904 {
2905 unsigned int ic_index = FIX2UINT(operands[j]);
2906
2907 IVC cache = ((IVC)&body->is_entries[ic_index]);
2908
2909 if (insn == BIN(setinstancevariable)) {
2910 cache->iv_set_name = SYM2ID(operands[j - 1]);
2911 cache->value = IVAR_CACHE_INIT;
2912 }
2913 else {
2914 cache->iv_set_name = 0;
2915 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
2916 }
2917 }
2918 case TS_ISE: /* inline storage entry: `once` insn */
2919 case TS_ICVARC: /* inline cvar cache */
2920 {
2921 unsigned int ic_index = FIX2UINT(operands[j]);
2922 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2923 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2924 BADINSN_DUMP(anchor, &iobj->link, 0);
2925 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2926 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2927 ic_index, ISEQ_IS_SIZE(body));
2928 }
2929 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2930
2931 break;
2932 }
2933 case TS_CALLDATA:
2934 {
2935 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2936 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2937 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2938 cd->ci = source_ci;
2939 cd->cc = vm_cc_empty();
2940 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2941 break;
2942 }
2943 case TS_ID: /* ID */
2944 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2945 break;
2946 case TS_FUNCPTR:
2947 generated_iseq[code_index + 1 + j] = operands[j];
2948 break;
2949 case TS_BUILTIN:
2950 generated_iseq[code_index + 1 + j] = operands[j];
2951 break;
2952 default:
2953 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2954 "unknown operand type: %c", type);
2955 return COMPILE_NG;
2956 }
2957 }
2958 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2959 code_index += len;
2960 break;
2961 }
2962 case ISEQ_ELEMENT_LABEL:
2963 {
2964 LABEL *lobj = (LABEL *)list;
2965 if (lobj->sp != sp) {
2966 VALUE path = rb_iseq_path(iseq);
2967 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2968 RSTRING_LENINT(path), RSTRING_PTR(path),
2969 lobj->label_no, lobj->sp, sp);
2970 }
2971 sp = lobj->sp;
2972 break;
2973 }
2974 case ISEQ_ELEMENT_ADJUST:
2975 {
2976 ADJUST *adjust = (ADJUST *)list;
2977 int orig_sp = sp;
2978
2979 if (adjust->label) {
2980 sp = adjust->label->sp;
2981 }
2982 else {
2983 sp = 0;
2984 }
2985
2986 if (adjust->line_no != -1) {
2987 const int diff = orig_sp - sp;
2988 if (diff > 0) {
2989 if (insns_info_index == 0) {
2990 COMPILE_ERROR(iseq, adjust->line_no,
2991 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2992 }
2993 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2994 }
2995 if (diff > 1) {
2996 generated_iseq[code_index++] = BIN(adjuststack);
2997 generated_iseq[code_index++] = orig_sp - sp;
2998 }
2999 else if (diff == 1) {
3000 generated_iseq[code_index++] = BIN(pop);
3001 }
3002 else if (diff < 0) {
3003 int label_no = adjust->label ? adjust->label->label_no : -1;
3004 SIZED_FREE_N(generated_iseq, generated_iseq_size);
3005 SIZED_FREE_N(insns_info, insns_info_size);
3006 SIZED_FREE_N(positions, positions_size);
3007 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
3008 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
3009 }
3010 debug_list(anchor, list);
3011 COMPILE_ERROR(iseq, adjust->line_no,
3012 "iseq_set_sequence: adjust bug to %d %d < %d",
3013 label_no, orig_sp, sp);
3014 return COMPILE_NG;
3015 }
3016 }
3017 break;
3018 }
3019 default:
3020 /* ignore */
3021 break;
3022 }
3023 list = list->next;
3024 }
3025
3026 body->iseq_encoded = (void *)generated_iseq;
3027 body->iseq_size = code_index;
3028 body->stack_max = stack_max;
3029
3030 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
3031 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
3032 }
3033 else {
3034 if (needs_bitmap) {
3035 body->mark_bits.list = mark_offset_bits;
3036 }
3037 else {
3038 body->mark_bits.list = NULL;
3039 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
3040 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
3041 }
3042 }
3043
3044 /* get rid of memory leak when REALLOC failed */
3045 body->insns_info.body = insns_info;
3046 body->insns_info.positions_or_succ_index_table.positions = positions;
3047
3048 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
3049 body->insns_info.body = insns_info;
3050 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
3051 body->insns_info.positions_or_succ_index_table.positions = positions;
3052 body->insns_info.size = insns_info_index;
3053
3054 return COMPILE_OK;
3055}
3056
3057static int
3058label_get_position(LABEL *lobj)
3059{
3060 return lobj->position;
3061}
3062
3063static int
3064label_get_sp(LABEL *lobj)
3065{
3066 return lobj->sp;
3067}
3068
3069static int
3070iseq_set_exception_table(rb_iseq_t *iseq)
3071{
3072 const VALUE *tptr, *ptr;
3073 unsigned int tlen, i;
3074 struct iseq_catch_table_entry *entry;
3075
3076 ISEQ_BODY(iseq)->catch_table = NULL;
3077
3078 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
3079 if (NIL_P(catch_table_ary)) return COMPILE_OK;
3080 tlen = (int)RARRAY_LEN(catch_table_ary);
3081 tptr = RARRAY_CONST_PTR(catch_table_ary);
3082
3083 if (tlen > 0) {
3084 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
3085 table->size = tlen;
3086
3087 for (i = 0; i < table->size; i++) {
3088 int pos;
3089 ptr = RARRAY_CONST_PTR(tptr[i]);
3090 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
3091 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
3092 pos = label_get_position((LABEL *)(ptr[1] & ~1));
3093 RUBY_ASSERT(pos >= 0);
3094 entry->start = (unsigned int)pos;
3095 pos = label_get_position((LABEL *)(ptr[2] & ~1));
3096 RUBY_ASSERT(pos >= 0);
3097 entry->end = (unsigned int)pos;
3098 entry->iseq = (rb_iseq_t *)ptr[3];
3099 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
3100
3101 /* stack depth */
3102 if (ptr[4]) {
3103 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3104 entry->cont = label_get_position(lobj);
3105 entry->sp = label_get_sp(lobj);
3106
3107 /* TODO: Dirty Hack! Fix me */
3108 if (entry->type == CATCH_TYPE_RESCUE ||
3109 entry->type == CATCH_TYPE_BREAK ||
3110 entry->type == CATCH_TYPE_NEXT) {
3111 RUBY_ASSERT(entry->sp > 0);
3112 entry->sp--;
3113 }
3114 }
3115 else {
3116 entry->cont = 0;
3117 }
3118 }
3119 ISEQ_BODY(iseq)->catch_table = table;
3120 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3121 }
3122
3123 RB_GC_GUARD(catch_table_ary);
3124
3125 return COMPILE_OK;
3126}
3127
3128/*
3129 * set optional argument table
3130 * def foo(a, b=expr1, c=expr2)
3131 * =>
3132 * b:
3133 * expr1
3134 * c:
3135 * expr2
3136 */
3137static int
3138iseq_set_optargs_table(rb_iseq_t *iseq)
3139{
3140 int i;
3141 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3142
3143 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3144 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3145 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3146 }
3147 }
3148 return COMPILE_OK;
3149}
3150
3151static LINK_ELEMENT *
3152get_destination_insn(INSN *iobj)
3153{
3154 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3155 LINK_ELEMENT *list;
3156 rb_event_flag_t events = 0;
3157
3158 list = lobj->link.next;
3159 while (list) {
3160 switch (list->type) {
3161 case ISEQ_ELEMENT_INSN:
3162 case ISEQ_ELEMENT_ADJUST:
3163 goto found;
3164 case ISEQ_ELEMENT_LABEL:
3165 /* ignore */
3166 break;
3167 case ISEQ_ELEMENT_TRACE:
3168 {
3169 TRACE *trace = (TRACE *)list;
3170 events |= trace->event;
3171 }
3172 break;
3173 default: break;
3174 }
3175 list = list->next;
3176 }
3177 found:
3178 if (list && IS_INSN(list)) {
3179 INSN *iobj = (INSN *)list;
3180 iobj->insn_info.events |= events;
3181 }
3182 return list;
3183}
3184
3185static LINK_ELEMENT *
3186get_next_insn(INSN *iobj)
3187{
3188 LINK_ELEMENT *list = iobj->link.next;
3189
3190 while (list) {
3191 if (IS_INSN(list) || IS_ADJUST(list)) {
3192 return list;
3193 }
3194 list = list->next;
3195 }
3196 return 0;
3197}
3198
3199static LINK_ELEMENT *
3200get_prev_insn(INSN *iobj)
3201{
3202 LINK_ELEMENT *list = iobj->link.prev;
3203
3204 while (list) {
3205 if (IS_INSN(list) || IS_ADJUST(list)) {
3206 return list;
3207 }
3208 list = list->prev;
3209 }
3210 return 0;
3211}
3212
3213static void
3214unref_destination(INSN *iobj, int pos)
3215{
3216 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3217 --lobj->refcnt;
3218 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3219}
3220
3221static bool
3222replace_destination(INSN *dobj, INSN *nobj)
3223{
3224 VALUE n = OPERAND_AT(nobj, 0);
3225 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3226 LABEL *nl = (LABEL *)n;
3227 if (dl == nl) return false;
3228 --dl->refcnt;
3229 ++nl->refcnt;
3230 OPERAND_AT(dobj, 0) = n;
3231 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3232 return true;
3233}
3234
3235static LABEL*
3236find_destination(INSN *i)
3237{
3238 int pos, len = insn_len(i->insn_id);
3239 for (pos = 0; pos < len; ++pos) {
3240 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3241 return (LABEL *)OPERAND_AT(i, pos);
3242 }
3243 }
3244 return 0;
3245}
3246
3247static int
3248remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3249{
3250 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3251 LABEL *pending = 0;
3252 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3253
3254 if (!i) return 0;
3255 unref_counts = ALLOCA_N(int, nlabels);
3256 MEMZERO(unref_counts, int, nlabels);
3257
3258 end = i;
3259 scan = i;
3260 do {
3261 LABEL *lab;
3262 if (IS_INSN(scan)) {
3263 if (IS_INSN_ID(scan, leave)) {
3264 if (pending) break;
3265 end = scan;
3266 break;
3267 }
3268 else if ((lab = find_destination((INSN *)scan)) != 0) {
3269 unref_counts[lab->label_no]++;
3270 if (lab == pending && lab->refcnt <= unref_counts[lab->label_no]) {
3271 pending = 0;
3272 }
3273 }
3274 }
3275 else if (IS_LABEL(scan)) {
3276 lab = (LABEL *)scan;
3277 if (lab->unremovable) {
3278 if (pending) break;
3279 return 0;
3280 }
3281 if (lab->refcnt > unref_counts[lab->label_no]) {
3282 if (pending) break;
3283 pending = lab;
3284 pending_end = (scan == first) ? 0 : end;
3285 }
3286 continue;
3287 }
3288 else if (IS_ADJUST(scan)) {
3289 if (pending) break;
3290 return 0;
3291 }
3292 if (!pending) end = scan;
3293 } while ((scan = scan->next) != 0);
3294
3295 if (pending) {
3296 if (!pending_end) return 0;
3297 end = pending_end;
3298 }
3299 i = first;
3300 do {
3301 if (IS_INSN(i)) {
3302 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3303 VALUE insn = INSN_OF(i);
3304 int pos, len = insn_len(insn);
3305 for (pos = 0; pos < len; ++pos) {
3306 switch (insn_op_types(insn)[pos]) {
3307 case TS_OFFSET:
3308 unref_destination((INSN *)i, pos);
3309 break;
3310 case TS_CALLDATA:
3311 --(body->ci_size);
3312 break;
3313 }
3314 }
3315 }
3316 ELEM_REMOVE(i);
3317 } while ((i != end) && (i = i->next) != 0);
3318 return 1;
3319}
3320
3321static int
3322iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3323{
3324 switch (OPERAND_AT(iobj, 0)) {
3325 case INT2FIX(0): /* empty array */
3326 ELEM_REMOVE(&iobj->link);
3327 return TRUE;
3328 case INT2FIX(1): /* single element array */
3329 ELEM_REMOVE(&iobj->link);
3330 return FALSE;
3331 default:
3332 iobj->insn_id = BIN(adjuststack);
3333 return TRUE;
3334 }
3335}
3336
3337static int
3338is_frozen_putstring(INSN *insn, VALUE *op)
3339{
3340 if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
3341 *op = OPERAND_AT(insn, 0);
3342 return 1;
3343 }
3344 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3345 *op = OPERAND_AT(insn, 0);
3346 return RB_TYPE_P(*op, T_STRING);
3347 }
3348 return 0;
3349}
3350
3351static int
3352insn_has_label_before(LINK_ELEMENT *elem)
3353{
3354 LINK_ELEMENT *prev = elem->prev;
3355 while (prev) {
3356 if (prev->type == ISEQ_ELEMENT_LABEL) {
3357 LABEL *label = (LABEL *)prev;
3358 if (label->refcnt > 0) {
3359 return 1;
3360 }
3361 }
3362 else if (prev->type == ISEQ_ELEMENT_INSN) {
3363 break;
3364 }
3365 prev = prev->prev;
3366 }
3367 return 0;
3368}
3369
3370static int
3371optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3372{
3373 /*
3374 * putobject obj
3375 * dup
3376 * checktype T_XXX
3377 * branchif l1
3378 * l2:
3379 * ...
3380 * l1:
3381 *
3382 * => obj is a T_XXX
3383 *
3384 * putobject obj (T_XXX)
3385 * jump L1
3386 * L1:
3387 *
3388 * => obj is not a T_XXX
3389 *
3390 * putobject obj (T_XXX)
3391 * jump L2
3392 * L2:
3393 */
3394 int line, node_id;
3395 INSN *niobj, *ciobj, *dup = 0;
3396 LABEL *dest = 0;
3397 VALUE type;
3398
3399 switch (INSN_OF(iobj)) {
3400 case BIN(dupstring):
3401 case BIN(dupchilledstring):
3403 break;
3404 case BIN(putnil):
3405 type = INT2FIX(T_NIL);
3406 break;
3407 case BIN(putobject):
3408 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3409 break;
3410 default: return FALSE;
3411 }
3412
3413 ciobj = (INSN *)get_next_insn(iobj);
3414 if (IS_INSN_ID(ciobj, jump)) {
3415 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3416 }
3417 if (IS_INSN_ID(ciobj, dup)) {
3418 ciobj = (INSN *)get_next_insn(dup = ciobj);
3419 }
3420 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3421 niobj = (INSN *)get_next_insn(ciobj);
3422 if (!niobj) {
3423 /* TODO: putobject true/false */
3424 return FALSE;
3425 }
3426 switch (INSN_OF(niobj)) {
3427 case BIN(branchif):
3428 if (OPERAND_AT(ciobj, 0) == type) {
3429 dest = (LABEL *)OPERAND_AT(niobj, 0);
3430 }
3431 break;
3432 case BIN(branchunless):
3433 if (OPERAND_AT(ciobj, 0) != type) {
3434 dest = (LABEL *)OPERAND_AT(niobj, 0);
3435 }
3436 break;
3437 default:
3438 return FALSE;
3439 }
3440 line = ciobj->insn_info.line_no;
3441 node_id = ciobj->insn_info.node_id;
3442 if (!dest) {
3443 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3444 dest = (LABEL *)niobj->link.next; /* reuse label */
3445 }
3446 else {
3447 dest = NEW_LABEL(line);
3448 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3449 }
3450 }
3451 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3452 LABEL_REF(dest);
3453 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3454 return TRUE;
3455}
3456
3457static const struct rb_callinfo *
3458ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3459{
3460 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3461 vm_ci_flag(ci) | add,
3462 vm_ci_argc(ci),
3463 vm_ci_kwarg(ci));
3464 RB_OBJ_WRITTEN(iseq, ci, nci);
3465 return nci;
3466}
3467
3468static const struct rb_callinfo *
3469ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3470{
3471 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3472 vm_ci_flag(ci),
3473 argc,
3474 vm_ci_kwarg(ci));
3475 RB_OBJ_WRITTEN(iseq, ci, nci);
3476 return nci;
3477}
3478
3479#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3480
3481static VALUE
3482iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3483{
3484 VALUE errinfo = rb_errinfo();
3485 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3486 if (NIL_P(re)) {
3487 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3488 rb_set_errinfo(errinfo);
3489 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3490 }
3491 else {
3493 }
3494 return re;
3495}
3496
3497static int
3498iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3499{
3500 INSN *const iobj = (INSN *)list;
3501
3502 again:
3503 optimize_checktype(iseq, iobj);
3504
3505 if (IS_INSN_ID(iobj, jump)) {
3506 INSN *niobj, *diobj, *piobj;
3507 diobj = (INSN *)get_destination_insn(iobj);
3508 niobj = (INSN *)get_next_insn(iobj);
3509
3510 if (diobj == niobj) {
3511 /*
3512 * jump LABEL
3513 * LABEL:
3514 * =>
3515 * LABEL:
3516 */
3517 unref_destination(iobj, 0);
3518 ELEM_REMOVE(&iobj->link);
3519 return COMPILE_OK;
3520 }
3521 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3522 IS_INSN_ID(diobj, jump) &&
3523 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3524 diobj->insn_info.events == 0) {
3525 /*
3526 * useless jump elimination:
3527 * jump LABEL1
3528 * ...
3529 * LABEL1:
3530 * jump LABEL2
3531 *
3532 * => in this case, first jump instruction should jump to
3533 * LABEL2 directly
3534 */
3535 if (replace_destination(iobj, diobj)) {
3536 remove_unreachable_chunk(iseq, iobj->link.next);
3537 goto again;
3538 }
3539 }
3540 else if (IS_INSN_ID(diobj, leave)) {
3541 /*
3542 * jump LABEL
3543 * ...
3544 * LABEL:
3545 * leave
3546 * =>
3547 * leave
3548 * ...
3549 * LABEL:
3550 * leave
3551 */
3552 /* replace */
3553 unref_destination(iobj, 0);
3554 iobj->insn_id = BIN(leave);
3555 iobj->operand_size = 0;
3556 iobj->insn_info = diobj->insn_info;
3557 goto again;
3558 }
3559 else if (IS_INSN(iobj->link.prev) &&
3560 (piobj = (INSN *)iobj->link.prev) &&
3561 (IS_INSN_ID(piobj, branchif) ||
3562 IS_INSN_ID(piobj, branchunless))) {
3563 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3564 if (niobj == pdiobj) {
3565 int refcnt = IS_LABEL(piobj->link.next) ?
3566 ((LABEL *)piobj->link.next)->refcnt : 0;
3567 /*
3568 * useless jump elimination (if/unless destination):
3569 * if L1
3570 * jump L2
3571 * L1:
3572 * ...
3573 * L2:
3574 *
3575 * ==>
3576 * unless L2
3577 * L1:
3578 * ...
3579 * L2:
3580 */
3581 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3582 ? BIN(branchunless) : BIN(branchif);
3583 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3584 ELEM_REMOVE(&iobj->link);
3585 }
3586 else {
3587 /* TODO: replace other branch destinations too */
3588 }
3589 return COMPILE_OK;
3590 }
3591 else if (diobj == pdiobj) {
3592 /*
3593 * useless jump elimination (if/unless before jump):
3594 * L1:
3595 * ...
3596 * if L1
3597 * jump L1
3598 *
3599 * ==>
3600 * L1:
3601 * ...
3602 * pop
3603 * jump L1
3604 */
3605 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3606 ELEM_REPLACE(&piobj->link, &popiobj->link);
3607 }
3608 }
3609 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3610 goto again;
3611 }
3612 }
3613
3614 /*
3615 * dupstring "beg"
3616 * dupstring "end"
3617 * newrange excl
3618 *
3619 * ==>
3620 *
3621 * putobject "beg".."end"
3622 */
3623 if (IS_INSN_ID(iobj, newrange)) {
3624 INSN *const range = iobj;
3625 INSN *beg, *end;
3626 VALUE str_beg, str_end;
3627
3628 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3629 is_frozen_putstring(end, &str_end) &&
3630 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3631 is_frozen_putstring(beg, &str_beg) &&
3632 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3633 int excl = FIX2INT(OPERAND_AT(range, 0));
3634 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3635
3636 ELEM_REMOVE(&beg->link);
3637 ELEM_REMOVE(&end->link);
3638 range->insn_id = BIN(putobject);
3639 OPERAND_AT(range, 0) = lit_range;
3640 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3641 }
3642 }
3643
3644 if (IS_INSN_ID(iobj, leave)) {
3645 remove_unreachable_chunk(iseq, iobj->link.next);
3646 }
3647
3648 /*
3649 * ...
3650 * duparray [...]
3651 * concatarray | concattoarray
3652 * =>
3653 * ...
3654 * putobject [...]
3655 * concatarray | concattoarray
3656 */
3657 if (IS_INSN_ID(iobj, duparray)) {
3658 LINK_ELEMENT *next = iobj->link.next;
3659 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3660 iobj->insn_id = BIN(putobject);
3661 }
3662 }
3663
3664 /*
3665 * duparray [...]
3666 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3667 * =>
3668 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3669 */
3670 if (IS_INSN_ID(iobj, duparray)) {
3671 LINK_ELEMENT *next = iobj->link.next;
3672 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3673 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3674 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3675
3676 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3677 VALUE ary = iobj->operands[0];
3679
3680 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3681 ELEM_REMOVE(next);
3682 }
3683 }
3684 }
3685
3686 /*
3687 * duphash {...}
3688 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3689 * =>
3690 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3691 */
3692 if (IS_INSN_ID(iobj, duphash)) {
3693 LINK_ELEMENT *next = iobj->link.next;
3694 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3695 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3696 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3697
3698 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3699 VALUE hash = iobj->operands[0];
3700 rb_obj_reveal(hash, rb_cHash);
3702
3703 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3704 ELEM_REMOVE(next);
3705 }
3706 }
3707 }
3708
3709 /*
3710 * newarray 0
3711 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3712 * =>
3713 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3714 */
3715 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3716 LINK_ELEMENT *next = iobj->link.next;
3717 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3718 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3719 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3720
3721 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3722 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3723 ELEM_REMOVE(next);
3724 }
3725 }
3726 }
3727
3728 /*
3729 * newhash 0
3730 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3731 * =>
3732 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3733 */
3734 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3735 LINK_ELEMENT *next = iobj->link.next;
3736 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3737 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3738 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3739
3740 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3741 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3742 ELEM_REMOVE(next);
3743 }
3744 }
3745 }
3746
3747 if (IS_INSN_ID(iobj, branchif) ||
3748 IS_INSN_ID(iobj, branchnil) ||
3749 IS_INSN_ID(iobj, branchunless)) {
3750 /*
3751 * if L1
3752 * ...
3753 * L1:
3754 * jump L2
3755 * =>
3756 * if L2
3757 */
3758 INSN *nobj = (INSN *)get_destination_insn(iobj);
3759
3760 /* This jump-jump optimization may ignore line events on the jump
3761 * instruction being skipped. For example, the Line 2 TracePoint
3762 * event would otherwise never fire in the following code:
3763 *
3764 * 1: raise if 1 == 2
3765 * 2: while true
3766 * 3: break
3767 * 4: end
3768 *
3769 * Do not skip a jump that carries a line event. This applies even
3770 * when coverage is disabled because TracePoint consumes the same
3771 * event. [Bug #15980]
3772 */
3773 int stop_optimization =
3774 nobj->link.type == ISEQ_ELEMENT_INSN &&
3775 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3776 if (!stop_optimization) {
3777 INSN *pobj = (INSN *)iobj->link.prev;
3778 int prev_dup = 0;
3779 if (pobj) {
3780 if (!IS_INSN(&pobj->link))
3781 pobj = 0;
3782 else if (IS_INSN_ID(pobj, dup))
3783 prev_dup = 1;
3784 }
3785
3786 for (;;) {
3787 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3788 if (!replace_destination(iobj, nobj)) break;
3789 }
3790 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3791 !!(nobj = (INSN *)nobj->link.next) &&
3792 IS_INSN(&nobj->link) &&
3793 /* basic blocks, with no labels in the middle */
3794 nobj->insn_id == iobj->insn_id) {
3795 /*
3796 * dup
3797 * if L1
3798 * ...
3799 * L1:
3800 * dup
3801 * if L2
3802 * =>
3803 * dup
3804 * if L2
3805 * ...
3806 * L1:
3807 * dup
3808 * if L2
3809 */
3810 if (!replace_destination(iobj, nobj)) break;
3811 }
3812 else if (pobj) {
3813 /*
3814 * putnil
3815 * if L1
3816 * =>
3817 * # nothing
3818 *
3819 * putobject true
3820 * if L1
3821 * =>
3822 * jump L1
3823 *
3824 * dupstring ".."
3825 * if L1
3826 * =>
3827 * jump L1
3828 *
3829 * dupstring ".."
3830 * dup
3831 * if L1
3832 * =>
3833 * dupstring ".."
3834 * jump L1
3835 *
3836 */
3837 int cond;
3838 if (prev_dup && IS_INSN(pobj->link.prev)) {
3839 pobj = (INSN *)pobj->link.prev;
3840 }
3841 if (IS_INSN_ID(pobj, putobject)) {
3842 cond = (IS_INSN_ID(iobj, branchif) ?
3843 OPERAND_AT(pobj, 0) != Qfalse :
3844 IS_INSN_ID(iobj, branchunless) ?
3845 OPERAND_AT(pobj, 0) == Qfalse :
3846 FALSE);
3847 }
3848 else if (IS_INSN_ID(pobj, dupstring) ||
3849 IS_INSN_ID(pobj, duparray) ||
3850 IS_INSN_ID(pobj, newarray)) {
3851 cond = IS_INSN_ID(iobj, branchif);
3852 }
3853 else if (IS_INSN_ID(pobj, putnil)) {
3854 cond = !IS_INSN_ID(iobj, branchif);
3855 }
3856 else break;
3857 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3858 ELEM_REMOVE(iobj->link.prev);
3859 }
3860 else if (!iseq_pop_newarray(iseq, pobj)) {
3861 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3862 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3863 }
3864 if (cond) {
3865 if (prev_dup) {
3866 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3867 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3868 }
3869 iobj->insn_id = BIN(jump);
3870 goto again;
3871 }
3872 else {
3873 unref_destination(iobj, 0);
3874 ELEM_REMOVE(&iobj->link);
3875 }
3876 break;
3877 }
3878 else break;
3879 {
3880 LINK_ELEMENT *dest = get_destination_insn(nobj);
3881 if (!dest || !IS_INSN(dest)) break;
3882 nobj = (INSN *)dest;
3883 }
3884 }
3885 }
3886 }
3887
3888 if (IS_INSN_ID(iobj, pop)) {
3889 /*
3890 * putself / putnil / putobject obj / dupstring "..."
3891 * pop
3892 * =>
3893 * # do nothing
3894 */
3895 LINK_ELEMENT *prev = iobj->link.prev;
3896 if (IS_INSN(prev)) {
3897 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3898 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3899 previ == BIN(putself) || previ == BIN(dupstring) ||
3900 previ == BIN(dupchilledstring) ||
3901 previ == BIN(dup) ||
3902 previ == BIN(getlocal) ||
3903 previ == BIN(getblockparam) ||
3904 previ == BIN(getblockparamproxy) ||
3905 previ == BIN(getinstancevariable) ||
3906 previ == BIN(duparray)) {
3907 /* just push operand or static value and pop soon, no
3908 * side effects */
3909 ELEM_REMOVE(prev);
3910 ELEM_REMOVE(&iobj->link);
3911 }
3912 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3913 ELEM_REMOVE(&iobj->link);
3914 }
3915 else if (previ == BIN(concatarray)) {
3916 INSN *piobj = (INSN *)prev;
3917 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3918 INSN_OF(piobj) = BIN(pop);
3919 }
3920 else if (previ == BIN(concatstrings)) {
3921 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3922 ELEM_REMOVE(prev);
3923 }
3924 else {
3925 ELEM_REMOVE(&iobj->link);
3926 INSN_OF(prev) = BIN(adjuststack);
3927 }
3928 }
3929 }
3930 }
3931
3932 if (IS_INSN_ID(iobj, newarray) ||
3933 IS_INSN_ID(iobj, duparray) ||
3934 IS_INSN_ID(iobj, concatarray) ||
3935 IS_INSN_ID(iobj, splatarray) ||
3936 0) {
3937 /*
3938 * newarray N
3939 * splatarray
3940 * =>
3941 * newarray N
3942 * newarray always puts an array
3943 */
3944 LINK_ELEMENT *next = iobj->link.next;
3945 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3946 /* remove splatarray following always-array insn */
3947 ELEM_REMOVE(next);
3948 }
3949 }
3950
3951 if (IS_INSN_ID(iobj, newarray)) {
3952 LINK_ELEMENT *next = iobj->link.next;
3953 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3954 OPERAND_AT(next, 1) == INT2FIX(0)) {
3955 VALUE op1, op2;
3956 op1 = OPERAND_AT(iobj, 0);
3957 op2 = OPERAND_AT(next, 0);
3958 ELEM_REMOVE(next);
3959
3960 if (op1 == op2) {
3961 /*
3962 * newarray 2
3963 * expandarray 2, 0
3964 * =>
3965 * swap
3966 */
3967 if (op1 == INT2FIX(2)) {
3968 INSN_OF(iobj) = BIN(swap);
3969 iobj->operand_size = 0;
3970 }
3971 /*
3972 * newarray X
3973 * expandarray X, 0
3974 * =>
3975 * opt_reverse X
3976 */
3977 else {
3978 INSN_OF(iobj) = BIN(opt_reverse);
3979 }
3980 }
3981 else {
3982 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3983 INSN_OF(iobj) = BIN(opt_reverse);
3984 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3985
3986 if (op1 > op2) {
3987 /* X > Y
3988 * newarray X
3989 * expandarray Y, 0
3990 * =>
3991 * pop * (Y-X)
3992 * opt_reverse Y
3993 */
3994 for (; diff > 0; diff--) {
3995 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3996 }
3997 }
3998 else { /* (op1 < op2) */
3999 /* X < Y
4000 * newarray X
4001 * expandarray Y, 0
4002 * =>
4003 * putnil * (Y-X)
4004 * opt_reverse Y
4005 */
4006 for (; diff < 0; diff++) {
4007 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
4008 }
4009 }
4010 }
4011 }
4012 }
4013
4014 if (IS_INSN_ID(iobj, duparray)) {
4015 LINK_ELEMENT *next = iobj->link.next;
4016 /*
4017 * duparray obj
4018 * expandarray X, 0
4019 * =>
4020 * putobject obj
4021 * expandarray X, 0
4022 */
4023 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
4024 INSN_OF(iobj) = BIN(putobject);
4025 }
4026 }
4027
4028 if (IS_INSN_ID(iobj, anytostring)) {
4029 LINK_ELEMENT *next = iobj->link.next;
4030 /*
4031 * anytostring
4032 * concatstrings 1
4033 * =>
4034 * anytostring
4035 */
4036 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
4037 OPERAND_AT(next, 0) == INT2FIX(1)) {
4038 ELEM_REMOVE(next);
4039 }
4040 }
4041
4042 if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
4043 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
4044 /*
4045 * dupstring ""
4046 * concatstrings N
4047 * =>
4048 * concatstrings N-1
4049 */
4050 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
4051 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
4052 INSN *next = (INSN *)iobj->link.next;
4053 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
4054 ELEM_REMOVE(&next->link);
4055 }
4056 ELEM_REMOVE(&iobj->link);
4057 }
4058 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
4059 INSN *next = (INSN *)iobj->link.next;
4060 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
4061 VALUE src = OPERAND_AT(iobj, 0);
4062 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
4063 VALUE path = rb_iseq_path(iseq);
4064 int line = iobj->insn_info.line_no;
4065 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
4066 /* The folded operand is a Regexp, so the instruction must be
4067 * putobject: dupstring/dupchilledstring would resurrect the
4068 * Regexp as a String at run time (e.g. for a /o regexp whose
4069 * interpolation folds to a constant, such as /#{"a"}/o). */
4070 iobj->insn_id = BIN(putobject);
4071 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
4072 ELEM_REMOVE(iobj->link.next);
4073 }
4074 }
4075 }
4076
4077 if (IS_INSN_ID(iobj, concatstrings)) {
4078 /*
4079 * concatstrings N
4080 * concatstrings M
4081 * =>
4082 * concatstrings N+M-1
4083 */
4084 LINK_ELEMENT *next = iobj->link.next;
4085 INSN *jump = 0;
4086 if (IS_INSN(next) && IS_INSN_ID(next, jump))
4087 next = get_destination_insn(jump = (INSN *)next);
4088 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
4089 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
4090 OPERAND_AT(iobj, 0) = INT2FIX(n);
4091 if (jump) {
4092 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
4093 if (!--label->refcnt) {
4094 ELEM_REMOVE(&label->link);
4095 }
4096 else {
4097 label = NEW_LABEL(0);
4098 OPERAND_AT(jump, 0) = (VALUE)label;
4099 }
4100 label->refcnt++;
4101 ELEM_INSERT_NEXT(next, &label->link);
4102 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
4103 }
4104 else {
4105 ELEM_REMOVE(next);
4106 }
4107 }
4108 }
4109
4110 if (do_tailcallopt &&
4111 (IS_INSN_ID(iobj, send) ||
4112 IS_INSN_ID(iobj, invokesuper))) {
4113 /*
4114 * send ...
4115 * leave
4116 * =>
4117 * send ..., ... | VM_CALL_TAILCALL, ...
4118 * leave # unreachable
4119 */
4120 INSN *piobj = NULL;
4121 if (iobj->link.next) {
4122 LINK_ELEMENT *next = iobj->link.next;
4123 do {
4124 if (!IS_INSN(next)) {
4125 next = next->next;
4126 continue;
4127 }
4128 switch (INSN_OF(next)) {
4129 case BIN(nop):
4130 next = next->next;
4131 break;
4132 case BIN(jump):
4133 /* if cond
4134 * return tailcall
4135 * end
4136 */
4137 next = get_destination_insn((INSN *)next);
4138 break;
4139 case BIN(leave):
4140 piobj = iobj;
4141 /* fall through */
4142 default:
4143 next = NULL;
4144 break;
4145 }
4146 } while (next);
4147 }
4148
4149 if (piobj) {
4150 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4151 if (IS_INSN_ID(piobj, send) ||
4152 IS_INSN_ID(piobj, invokesuper)) {
4153 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4154 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4155 OPERAND_AT(piobj, 0) = (VALUE)ci;
4156 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4157 }
4158 }
4159 else {
4160 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4161 OPERAND_AT(piobj, 0) = (VALUE)ci;
4162 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4163 }
4164 }
4165 }
4166
4167 if (IS_INSN_ID(iobj, dup)) {
4168 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4169 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4170
4171 /*
4172 * dup
4173 * setlocal x, y
4174 * setlocal x, y
4175 * =>
4176 * dup
4177 * setlocal x, y
4178 */
4179 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4180 set2 = set1->next;
4181 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4182 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4183 ELEM_REMOVE(set1);
4184 ELEM_REMOVE(&iobj->link);
4185 }
4186 }
4187
4188 /*
4189 * dup
4190 * setlocal x, y
4191 * dup
4192 * setlocal x, y
4193 * =>
4194 * dup
4195 * setlocal x, y
4196 */
4197 else if (IS_NEXT_INSN_ID(set1, dup) &&
4198 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4199 set2 = set1->next->next;
4200 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4201 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4202 ELEM_REMOVE(set1->next);
4203 ELEM_REMOVE(set2);
4204 }
4205 }
4206 }
4207 }
4208
4209 /*
4210 * getlocal x, y
4211 * dup
4212 * setlocal x, y
4213 * =>
4214 * dup
4215 */
4216 if (IS_INSN_ID(iobj, getlocal)) {
4217 LINK_ELEMENT *niobj = &iobj->link;
4218 if (IS_NEXT_INSN_ID(niobj, dup)) {
4219 niobj = niobj->next;
4220 }
4221 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4222 LINK_ELEMENT *set1 = niobj->next;
4223 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4224 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4225 ELEM_REMOVE(set1);
4226 ELEM_REMOVE(niobj);
4227 }
4228 }
4229 }
4230
4231 /*
4232 * opt_invokebuiltin_delegate
4233 * trace
4234 * leave
4235 * =>
4236 * opt_invokebuiltin_delegate_leave
4237 * trace
4238 * leave
4239 */
4240 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4241 if (IS_TRACE(iobj->link.next)) {
4242 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4243 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4244 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4245 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4246 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4247 }
4248 }
4249 }
4250 }
4251
4252 /*
4253 * getblockparam
4254 * branchif / branchunless
4255 * =>
4256 * getblockparamproxy
4257 * branchif / branchunless
4258 */
4259 if (IS_INSN_ID(iobj, getblockparam)) {
4260 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4261 iobj->insn_id = BIN(getblockparamproxy);
4262 }
4263 }
4264
4265 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4266 LINK_ELEMENT *niobj = &iobj->link;
4267 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4268 niobj = niobj->next;
4269 LINK_ELEMENT *siobj;
4270 unsigned int set_flags = 0, unset_flags = 0;
4271
4272 /*
4273 * Eliminate hash allocation for f(*a, kw: 1)
4274 *
4275 * splatarray false
4276 * duphash
4277 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4278 * =>
4279 * splatarray false
4280 * putobject
4281 * send ARGS_SPLAT|KW_SPLAT
4282 */
4283 if (IS_NEXT_INSN_ID(niobj, send)) {
4284 siobj = niobj->next;
4285 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4286 unset_flags = VM_CALL_ARGS_BLOCKARG;
4287 }
4288 /*
4289 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4290 *
4291 * splatarray false
4292 * duphash
4293 * getlocal / getinstancevariable / getblockparamproxy
4294 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4295 * =>
4296 * splatarray false
4297 * putobject
4298 * getlocal / getinstancevariable / getblockparamproxy
4299 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4300 */
4301 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4302 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4303 siobj = niobj->next->next;
4304 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4305 }
4306
4307 if (set_flags) {
4308 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4309 unsigned int flags = vm_ci_flag(ci);
4310 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4311 ((INSN*)niobj)->insn_id = BIN(putobject);
4312 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4313
4314 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4315 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4316 RB_OBJ_WRITTEN(iseq, ci, nci);
4317 OPERAND_AT(siobj, 0) = (VALUE)nci;
4318 }
4319 }
4320 }
4321 }
4322
4323 /*
4324 * putself / (or any other independent instruction)
4325 * putnil / (or any other independent instruction)
4326 * swap
4327 * =>
4328 * putnil / (or any other independent instruction)
4329 * putself / (or any other independent instruction)
4330 */
4331 if (IS_NEXT_INSN_ID(&iobj->link, swap)) {
4332 LINK_ELEMENT *second = &iobj->link;
4333 LINK_ELEMENT *first = second->prev;
4334 LINK_ELEMENT *swap = second->next;
4335
4336 if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) {
4337 ELEM_REMOVE(swap);
4338 ELEM_SWAP(first, second);
4339 }
4340 }
4341
4342 return COMPILE_OK;
4343}
4344
4345static int
4346insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4347{
4348 if (insn_id == BIN(opt_neq)) {
4349 VALUE original_ci = iobj->operands[0];
4350 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4351 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4352 }
4353 else {
4354 iobj->insn_id = insn_id;
4355 iobj->operand_size = insn_len(insn_id) - 1;
4356 }
4357 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4358
4359 return COMPILE_OK;
4360}
4361
4362static int
4363iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4364{
4365 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4366 IS_INSN(iobj->link.next)) {
4367 /*
4368 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4369 */
4370 INSN *niobj = (INSN *)iobj->link.next;
4371 if (IS_INSN_ID(niobj, send)) {
4372 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4373 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4374 VALUE method = INT2FIX(0);
4375 switch (vm_ci_mid(ci)) {
4376 case idMax:
4377 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4378 break;
4379 case idMin:
4380 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4381 break;
4382 case idHash:
4383 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4384 break;
4385 }
4386
4387 if (method != INT2FIX(0)) {
4388 VALUE num = iobj->operands[0];
4389 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4390 ELEM_REMOVE(&niobj->link);
4391 return COMPILE_OK;
4392 }
4393 }
4394 }
4395 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4396 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4397 IS_NEXT_INSN_ID(&niobj->link, send)) {
4398 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4399 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4400 VALUE num = iobj->operands[0];
4401 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4402 ELEM_REMOVE(&iobj->link);
4403 ELEM_REMOVE(niobj->link.next);
4404 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4405 return COMPILE_OK;
4406 }
4407 }
4408 // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
4409 // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4410 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4411 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4412 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4413 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4414 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4415 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4416 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4417 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4418 VALUE num = iobj->operands[0];
4419 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4420 // Remove the "send" insn.
4421 ELEM_REMOVE((niobj->link.next)->next);
4422 // Remove the modified insn from its original "newarray" position...
4423 ELEM_REMOVE(&iobj->link);
4424 // and insert it after the buffer insn.
4425 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4426 return COMPILE_OK;
4427 }
4428 }
4429
4430 // Break the "else if" chain since some prior checks abort after sub-ifs.
4431 // We already found "newarray". To match `[...].include?(arg)` we look for
4432 // the instruction(s) representing the argument followed by a "send".
4433 if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4434 IS_INSN_ID(niobj, putobject) ||
4435 IS_INSN_ID(niobj, putself) ||
4436 IS_INSN_ID(niobj, getlocal) ||
4437 IS_INSN_ID(niobj, getinstancevariable)) &&
4438 IS_NEXT_INSN_ID(&niobj->link, send)) {
4439
4440 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4441 const struct rb_callinfo *ci;
4442 // Allow any number (0 or more) of simple method calls on the argument
4443 // (as in `[...].include?(arg.method1.method2)`.
4444 do {
4445 sendobj = sendobj->next;
4446 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4447 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4448
4449 // If this send is for .include? with one arg we can do our opt.
4450 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4451 VALUE num = iobj->operands[0];
4452 INSN *sendins = (INSN *)sendobj;
4453 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4454 // Remove the original "newarray" insn.
4455 ELEM_REMOVE(&iobj->link);
4456 return COMPILE_OK;
4457 }
4458 }
4459 }
4460
4461 /*
4462 * duparray [...]
4463 * some insn for the arg...
4464 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4465 * =>
4466 * arg insn...
4467 * opt_duparray_send [...], :include?, 1
4468 */
4469 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4470 INSN *niobj = (INSN *)iobj->link.next;
4471 if ((IS_INSN_ID(niobj, getlocal) ||
4472 IS_INSN_ID(niobj, getinstancevariable) ||
4473 IS_INSN_ID(niobj, putself) ||
4474 IS_INSN_ID(niobj, putobject) ||
4475 IS_INSN_ID(niobj, putnil)) &&
4476 IS_NEXT_INSN_ID(&niobj->link, send)) {
4477
4478 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4479 const struct rb_callinfo *ci;
4480 // Allow any number (0 or more) of simple method calls on the argument
4481 // (as in `[...].include?(arg.method1.method2)`.
4482 do {
4483 sendobj = sendobj->next;
4484 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4485 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4486
4487 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4488 // Move the array arg from duparray to opt_duparray_send.
4489 VALUE ary = iobj->operands[0];
4491
4492 INSN *sendins = (INSN *)sendobj;
4493 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4494
4495 // Remove the duparray insn.
4496 ELEM_REMOVE(&iobj->link);
4497 return COMPILE_OK;
4498 }
4499 }
4500 }
4501
4502
4503 if (IS_INSN_ID(iobj, send)) {
4504 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4505 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4506
4507#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4508 if (vm_ci_simple(ci)) {
4509 switch (vm_ci_argc(ci)) {
4510 case 0:
4511 switch (vm_ci_mid(ci)) {
4512 case idLength: SP_INSN(length); return COMPILE_OK;
4513 case idSize: SP_INSN(size); return COMPILE_OK;
4514 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4515 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4516 case idSucc: SP_INSN(succ); return COMPILE_OK;
4517 case idNot: SP_INSN(not); return COMPILE_OK;
4518 }
4519 break;
4520 case 1:
4521 switch (vm_ci_mid(ci)) {
4522 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4523 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4524 case idMULT: SP_INSN(mult); return COMPILE_OK;
4525 case idDIV: SP_INSN(div); return COMPILE_OK;
4526 case idMOD: SP_INSN(mod); return COMPILE_OK;
4527 case idEq: SP_INSN(eq); return COMPILE_OK;
4528 case idNeq: SP_INSN(neq); return COMPILE_OK;
4529 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4530 case idLT: SP_INSN(lt); return COMPILE_OK;
4531 case idLE: SP_INSN(le); return COMPILE_OK;
4532 case idGT: SP_INSN(gt); return COMPILE_OK;
4533 case idGE: SP_INSN(ge); return COMPILE_OK;
4534 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4535 case idAREF: SP_INSN(aref); return COMPILE_OK;
4536 case idAnd: SP_INSN(and); return COMPILE_OK;
4537 case idOr: SP_INSN(or); return COMPILE_OK;
4538 }
4539 break;
4540 case 2:
4541 switch (vm_ci_mid(ci)) {
4542 case idASET: SP_INSN(aset); return COMPILE_OK;
4543 }
4544 break;
4545 }
4546 }
4547
4548 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4549 iobj->insn_id = BIN(opt_send_without_block);
4550 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4551 }
4552 }
4553#undef SP_INSN
4554
4555 return COMPILE_OK;
4556}
4557
4558static inline int
4559tailcallable_p(rb_iseq_t *iseq)
4560{
4561 switch (ISEQ_BODY(iseq)->type) {
4562 case ISEQ_TYPE_TOP:
4563 case ISEQ_TYPE_EVAL:
4564 case ISEQ_TYPE_MAIN:
4565 /* not tail callable because cfp will be over popped */
4566 case ISEQ_TYPE_RESCUE:
4567 case ISEQ_TYPE_ENSURE:
4568 /* rescue block can't tail call because of errinfo */
4569 return FALSE;
4570 default:
4571 return TRUE;
4572 }
4573}
4574
4575static int
4576iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4577{
4578 LINK_ELEMENT *list;
4579 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4580 const int do_tailcallopt = tailcallable_p(iseq) &&
4581 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4582 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4583 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4584 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4585 int rescue_level = 0;
4586 int tailcallopt = do_tailcallopt;
4587
4588 list = FIRST_ELEMENT(anchor);
4589
4590 int do_block_optimization = 0;
4591 LABEL * block_loop_label = NULL;
4592
4593 // If we're optimizing a block
4594 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4595 do_block_optimization = 1;
4596
4597 // If the block starts with a nop and a label,
4598 // record the label so we can detect if it's a jump target
4599 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4600 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4601 block_loop_label = (LABEL *)le->next;
4602 }
4603 }
4604
4605 while (list) {
4606 if (IS_INSN(list)) {
4607 if (do_peepholeopt) {
4608 iseq_peephole_optimize(iseq, list, tailcallopt);
4609 }
4610 if (do_si) {
4611 iseq_specialized_instruction(iseq, (INSN *)list);
4612 }
4613 if (do_ou) {
4614 insn_operands_unification((INSN *)list);
4615 }
4616
4617 if (do_without_ints) {
4618 INSN *item = (INSN *)list;
4619 if (IS_INSN_ID(item, jump)) {
4620 item->insn_id = BIN(jump_without_ints);
4621 }
4622 else if (IS_INSN_ID(item, branchif)) {
4623 item->insn_id = BIN(branchif_without_ints);
4624 }
4625 else if (IS_INSN_ID(item, branchunless)) {
4626 item->insn_id = BIN(branchunless_without_ints);
4627 }
4628 else if (IS_INSN_ID(item, branchnil)) {
4629 item->insn_id = BIN(branchnil_without_ints);
4630 }
4631 }
4632
4633 if (do_block_optimization) {
4634 INSN * item = (INSN *)list;
4635 // Give up if there is a throw
4636 if (IS_INSN_ID(item, throw)) {
4637 do_block_optimization = 0;
4638 }
4639 else {
4640 // If the instruction has a jump target, check if the
4641 // jump target is the block loop label
4642 const char *types = insn_op_types(item->insn_id);
4643 for (int j = 0; types[j]; j++) {
4644 if (types[j] == TS_OFFSET) {
4645 // If the jump target is equal to the block loop
4646 // label, then we can't do the optimization because
4647 // the leading `nop` instruction fires the block
4648 // entry tracepoint
4649 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4650 if (target == block_loop_label) {
4651 do_block_optimization = 0;
4652 }
4653 }
4654 }
4655 }
4656 }
4657 }
4658 if (IS_LABEL(list)) {
4659 switch (((LABEL *)list)->rescued) {
4660 case LABEL_RESCUE_BEG:
4661 rescue_level++;
4662 tailcallopt = FALSE;
4663 break;
4664 case LABEL_RESCUE_END:
4665 if (!--rescue_level) tailcallopt = do_tailcallopt;
4666 break;
4667 }
4668 }
4669 list = list->next;
4670 }
4671
4672 if (do_block_optimization) {
4673 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4674 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4675 ELEM_REMOVE(le);
4676 }
4677 }
4678 return COMPILE_OK;
4679}
4680
4681#if OPT_INSTRUCTIONS_UNIFICATION
4682static INSN *
4683new_unified_insn(rb_iseq_t *iseq,
4684 int insn_id, int size, LINK_ELEMENT *seq_list)
4685{
4686 INSN *iobj = 0;
4687 LINK_ELEMENT *list = seq_list;
4688 int i, argc = 0;
4689 VALUE *operands = 0, *ptr = 0;
4690
4691
4692 /* count argc */
4693 for (i = 0; i < size; i++) {
4694 iobj = (INSN *)list;
4695 argc += iobj->operand_size;
4696 list = list->next;
4697 }
4698
4699 if (argc > 0) {
4700 ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
4701 }
4702
4703 /* copy operands */
4704 list = seq_list;
4705 for (i = 0; i < size; i++) {
4706 iobj = (INSN *)list;
4707 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4708 ptr += iobj->operand_size;
4709 list = list->next;
4710 }
4711
4712 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4713}
4714#endif
4715
4716/*
4717 * This scheme can get more performance if do this optimize with
4718 * label address resolving.
4719 * It's future work (if compile time was bottle neck).
4720 */
4721static int
4722iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4723{
4724#if OPT_INSTRUCTIONS_UNIFICATION
4725 LINK_ELEMENT *list;
4726 INSN *iobj, *niobj;
4727 int id, k;
4728 intptr_t j;
4729
4730 list = FIRST_ELEMENT(anchor);
4731 while (list) {
4732 if (IS_INSN(list)) {
4733 iobj = (INSN *)list;
4734 id = iobj->insn_id;
4735 if (unified_insns_data[id] != 0) {
4736 const int *const *entry = unified_insns_data[id];
4737 for (j = 1; j < (intptr_t)entry[0]; j++) {
4738 const int *unified = entry[j];
4739 LINK_ELEMENT *li = list->next;
4740 for (k = 2; k < unified[1]; k++) {
4741 if (!IS_INSN(li) ||
4742 ((INSN *)li)->insn_id != unified[k]) {
4743 goto miss;
4744 }
4745 li = li->next;
4746 }
4747 /* matched */
4748 niobj =
4749 new_unified_insn(iseq, unified[0], unified[1] - 1,
4750 list);
4751
4752 /* insert to list */
4753 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4754 niobj->link.next = li;
4755 if (li) {
4756 li->prev = (LINK_ELEMENT *)niobj;
4757 }
4758
4759 list->prev->next = (LINK_ELEMENT *)niobj;
4760 list = (LINK_ELEMENT *)niobj;
4761 break;
4762 miss:;
4763 }
4764 }
4765 }
4766 list = list->next;
4767 }
4768#endif
4769 return COMPILE_OK;
4770}
4771
4772static int
4773all_string_result_p(const NODE *node)
4774{
4775 if (!node) return FALSE;
4776 switch (nd_type(node)) {
4777 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4778 return TRUE;
4779 case NODE_IF: case NODE_UNLESS:
4780 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4781 if (all_string_result_p(RNODE_IF(node)->nd_body))
4782 return all_string_result_p(RNODE_IF(node)->nd_else);
4783 return FALSE;
4784 case NODE_AND: case NODE_OR:
4785 if (!RNODE_AND(node)->nd_2nd)
4786 return all_string_result_p(RNODE_AND(node)->nd_1st);
4787 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4788 return FALSE;
4789 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4790 default:
4791 return FALSE;
4792 }
4793}
4794
4796 rb_iseq_t *const iseq;
4797 LINK_ANCHOR *const ret;
4798 VALUE lit;
4799 const NODE *lit_node;
4800 int cnt;
4801 int dregx;
4802};
4803
4804static int
4805append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4806{
4807 VALUE s = rb_str_new_mutable_parser_string(str);
4808 if (args->dregx) {
4809 VALUE error = rb_reg_check_preprocess(s);
4810 if (!NIL_P(error)) {
4811 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4812 return COMPILE_NG;
4813 }
4814 }
4815 if (NIL_P(args->lit)) {
4816 args->lit = s;
4817 args->lit_node = node;
4818 }
4819 else {
4820 rb_str_buf_append(args->lit, s);
4821 }
4822 return COMPILE_OK;
4823}
4824
4825static void
4826flush_dstr_fragment(struct dstr_ctxt *args)
4827{
4828 if (!NIL_P(args->lit)) {
4829 rb_iseq_t *iseq = args->iseq;
4830 VALUE lit = args->lit;
4831 args->lit = Qnil;
4832 lit = rb_fstring(lit);
4833 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4834 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4835 args->cnt++;
4836 }
4837}
4838
4839static int
4840compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4841{
4842 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4843 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4844
4845 if (str) {
4846 CHECK(append_dstr_fragment(args, node, str));
4847 }
4848
4849 while (list) {
4850 const NODE *const head = list->nd_head;
4851 if (nd_type_p(head, NODE_STR)) {
4852 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4853 }
4854 else if (nd_type_p(head, NODE_DSTR)) {
4855 CHECK(compile_dstr_fragments_0(args, head));
4856 }
4857 else {
4858 flush_dstr_fragment(args);
4859 rb_iseq_t *iseq = args->iseq;
4860 CHECK(COMPILE(args->ret, "each string", head));
4861 args->cnt++;
4862 }
4863 list = (struct RNode_LIST *)list->nd_next;
4864 }
4865 return COMPILE_OK;
4866}
4867
4868static int
4869compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4870{
4871 struct dstr_ctxt args = {
4872 .iseq = iseq, .ret = ret,
4873 .lit = Qnil, .lit_node = NULL,
4874 .cnt = 0, .dregx = dregx,
4875 };
4876 CHECK(compile_dstr_fragments_0(&args, node));
4877 flush_dstr_fragment(&args);
4878
4879 *cntp = args.cnt;
4880
4881 return COMPILE_OK;
4882}
4883
4884static int
4885compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4886{
4887 while (node && nd_type_p(node, NODE_BLOCK)) {
4888 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4889 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4890 node = RNODE_BLOCK(node)->nd_next;
4891 }
4892 if (node) {
4893 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4894 }
4895 return COMPILE_OK;
4896}
4897
4898static int
4899compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4900{
4901 int cnt;
4902 if (!RNODE_DSTR(node)->nd_next) {
4903 VALUE lit = rb_node_dstr_string_val(node);
4904 ADD_INSN1(ret, node, dupstring, lit);
4906 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4907 }
4908 else {
4909 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4910 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4911 }
4912 return COMPILE_OK;
4913}
4914
4915static int
4916compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4917{
4918 int cnt;
4919 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4920
4921 if (!RNODE_DREGX(node)->nd_next) {
4922 if (!popped) {
4923 VALUE src = rb_node_dregx_string_val(node);
4924 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4925 ADD_INSN1(ret, node, putobject, match);
4926 RB_OBJ_WRITTEN(iseq, Qundef, match);
4927 }
4928 return COMPILE_OK;
4929 }
4930
4931 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4932 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4933
4934 if (popped) {
4935 ADD_INSN(ret, node, pop);
4936 }
4937
4938 return COMPILE_OK;
4939}
4940
4941static int
4942compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4943 LABEL *then_label, LABEL *else_label)
4944{
4945 const int line = nd_line(node);
4946 LABEL *lend = NEW_LABEL(line);
4947 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4948 + VM_SVAR_FLIPFLOP_START;
4949 VALUE key = INT2FIX(cnt);
4950
4951 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4952 ADD_INSNL(ret, node, branchif, lend);
4953
4954 /* *flip == 0 */
4955 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4956 ADD_INSNL(ret, node, branchunless, else_label);
4957 ADD_INSN1(ret, node, putobject, Qtrue);
4958 ADD_INSN1(ret, node, setspecial, key);
4959 if (!again) {
4960 ADD_INSNL(ret, node, jump, then_label);
4961 }
4962
4963 /* *flip == 1 */
4964 ADD_LABEL(ret, lend);
4965 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4966 ADD_INSNL(ret, node, branchunless, then_label);
4967 ADD_INSN1(ret, node, putobject, Qfalse);
4968 ADD_INSN1(ret, node, setspecial, key);
4969 ADD_INSNL(ret, node, jump, then_label);
4970
4971 return COMPILE_OK;
4972}
4973
4974static int
4975compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4976 LABEL *then_label, LABEL *else_label);
4977
4978#define COMPILE_SINGLE 2
4979static int
4980compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4981 LABEL *then_label, LABEL *else_label)
4982{
4983 DECL_ANCHOR(seq);
4984 INIT_ANCHOR(seq);
4985 LABEL *label = NEW_LABEL(nd_line(cond));
4986 if (!then_label) then_label = label;
4987 else if (!else_label) else_label = label;
4988
4989 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4990
4991 if (LIST_INSN_SIZE_ONE(seq)) {
4992 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4993 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4994 return COMPILE_OK;
4995 }
4996 if (!label->refcnt) {
4997 return COMPILE_SINGLE;
4998 }
4999 ADD_LABEL(seq, label);
5000 ADD_SEQ(ret, seq);
5001 return COMPILE_OK;
5002}
5003
5004static int
5005compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
5006 LABEL *then_label, LABEL *else_label)
5007{
5008 int ok;
5009 DECL_ANCHOR(ignore);
5010
5011 again:
5012 switch (nd_type(cond)) {
5013 case NODE_AND:
5014 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
5015 cond = RNODE_AND(cond)->nd_2nd;
5016 if (ok == COMPILE_SINGLE) {
5017 ADD_INSNL(ret, cond, jump, else_label);
5018 INIT_ANCHOR(ignore);
5019 ret = ignore;
5020 then_label = NEW_LABEL(nd_line(cond));
5021 }
5022 goto again;
5023 case NODE_OR:
5024 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
5025 cond = RNODE_OR(cond)->nd_2nd;
5026 if (ok == COMPILE_SINGLE) {
5027 ADD_INSNL(ret, cond, jump, then_label);
5028 INIT_ANCHOR(ignore);
5029 ret = ignore;
5030 else_label = NEW_LABEL(nd_line(cond));
5031 }
5032 goto again;
5033 case NODE_SYM:
5034 case NODE_LINE:
5035 case NODE_FILE:
5036 case NODE_ENCODING:
5037 case NODE_INTEGER: /* NODE_INTEGER is always true */
5038 case NODE_FLOAT: /* NODE_FLOAT is always true */
5039 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
5040 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
5041 case NODE_TRUE:
5042 case NODE_STR:
5043 case NODE_REGX:
5044 case NODE_ZLIST:
5045 case NODE_LAMBDA:
5046 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5047 ADD_INSNL(ret, cond, jump, then_label);
5048 return COMPILE_OK;
5049 case NODE_FALSE:
5050 case NODE_NIL:
5051 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5052 ADD_INSNL(ret, cond, jump, else_label);
5053 return COMPILE_OK;
5054 case NODE_LIST:
5055 case NODE_ARGSCAT:
5056 case NODE_DREGX:
5057 case NODE_DSTR:
5058 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
5059 ADD_INSNL(ret, cond, jump, then_label);
5060 return COMPILE_OK;
5061 case NODE_FLIP2:
5062 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
5063 return COMPILE_OK;
5064 case NODE_FLIP3:
5065 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
5066 return COMPILE_OK;
5067 case NODE_DEFINED:
5068 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
5069 break;
5070 default:
5071 {
5072 DECL_ANCHOR(cond_seq);
5073 INIT_ANCHOR(cond_seq);
5074
5075 CHECK(COMPILE(cond_seq, "branch condition", cond));
5076
5077 if (LIST_INSN_SIZE_ONE(cond_seq)) {
5078 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
5079 if (insn->insn_id == BIN(putobject)) {
5080 if (RTEST(insn->operands[0])) {
5081 ADD_INSNL(ret, cond, jump, then_label);
5082 // maybe unreachable
5083 return COMPILE_OK;
5084 }
5085 else {
5086 ADD_INSNL(ret, cond, jump, else_label);
5087 return COMPILE_OK;
5088 }
5089 }
5090 }
5091 ADD_SEQ(ret, cond_seq);
5092 }
5093 break;
5094 }
5095
5096 ADD_INSNL(ret, cond, branchunless, else_label);
5097 ADD_INSNL(ret, cond, jump, then_label);
5098 return COMPILE_OK;
5099}
5100
5101#define HASH_BRACE 1
5102
5103static int
5104keyword_node_p(const NODE *const node)
5105{
5106 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
5107}
5108
5109static VALUE
5110get_symbol_value(rb_iseq_t *iseq, const NODE *node)
5111{
5112 switch (nd_type(node)) {
5113 case NODE_SYM:
5114 return rb_node_sym_string_val(node);
5115 default:
5116 UNKNOWN_NODE("get_symbol_value", node, Qnil);
5117 }
5118}
5119
5120static VALUE
5121node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
5122{
5123 NODE *node = node_hash->nd_head;
5124 VALUE hash = rb_hash_new();
5125 VALUE ary = rb_ary_new();
5126
5127 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5128 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
5129 VALUE idx = rb_hash_aref(hash, key);
5130 if (!NIL_P(idx)) {
5131 rb_ary_store(ary, FIX2INT(idx), Qfalse);
5132 (*count_ptr)--;
5133 }
5134 rb_hash_aset(hash, key, INT2FIX(i));
5135 rb_ary_store(ary, i, Qtrue);
5136 (*count_ptr)++;
5137 }
5138
5139 return ary;
5140}
5141
5142static int
5143compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5144 const NODE *const root_node,
5145 struct rb_callinfo_kwarg **const kw_arg_ptr,
5146 unsigned int *flag)
5147{
5148 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5149 RUBY_ASSERT(kw_arg_ptr != NULL);
5150 RUBY_ASSERT(flag != NULL);
5151
5152 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5153 const NODE *node = RNODE_HASH(root_node)->nd_head;
5154 int seen_nodes = 0;
5155
5156 while (node) {
5157 const NODE *key_node = RNODE_LIST(node)->nd_head;
5158 seen_nodes++;
5159
5160 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5161 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5162 /* can be keywords */
5163 }
5164 else {
5165 if (flag) {
5166 *flag |= VM_CALL_KW_SPLAT;
5167 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5168 /* A new hash will be created for the keyword arguments
5169 * in this case, so mark the method as passing mutable
5170 * keyword splat.
5171 */
5172 *flag |= VM_CALL_KW_SPLAT_MUT;
5173 }
5174 }
5175 return FALSE;
5176 }
5177 node = RNODE_LIST(node)->nd_next; /* skip value node */
5178 node = RNODE_LIST(node)->nd_next;
5179 }
5180
5181 /* may be keywords */
5182 node = RNODE_HASH(root_node)->nd_head;
5183 {
5184 int len = 0;
5185 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5186
5187 if (len > VM_CALL_KW_LEN_MAX) {
5188 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5189 len, (int)VM_CALL_KW_LEN_MAX);
5190 }
5191
5192 struct rb_callinfo_kwarg *kw_arg =
5193 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5194 VALUE *keywords = kw_arg->keywords;
5195 int i = 0;
5196 int j = 0;
5197 kw_arg->references = 0;
5198 kw_arg->keyword_len = len;
5199
5200 *kw_arg_ptr = kw_arg;
5201
5202 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5203 const NODE *key_node = RNODE_LIST(node)->nd_head;
5204 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5205 int popped = TRUE;
5206 if (rb_ary_entry(key_index, i)) {
5207 keywords[j] = get_symbol_value(iseq, key_node);
5208 j++;
5209 popped = FALSE;
5210 }
5211 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5212 }
5213 RUBY_ASSERT(j == len);
5214 return TRUE;
5215 }
5216 }
5217 return FALSE;
5218}
5219
5220static int
5221compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5222{
5223 int len = 0;
5224
5225 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5226 if (CPDEBUG > 0) {
5227 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5228 }
5229
5230 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5231 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5232 }
5233 else {
5234 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5235 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5236 }
5237 }
5238
5239 return len;
5240}
5241
5242static inline bool
5243frozen_string_literal_p(const rb_iseq_t *iseq)
5244{
5245 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5246}
5247
5248static inline bool
5249static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5250{
5251 switch (nd_type(node)) {
5252 case NODE_SYM:
5253 case NODE_REGX:
5254 case NODE_LINE:
5255 case NODE_ENCODING:
5256 case NODE_INTEGER:
5257 case NODE_FLOAT:
5258 case NODE_RATIONAL:
5259 case NODE_IMAGINARY:
5260 case NODE_NIL:
5261 case NODE_TRUE:
5262 case NODE_FALSE:
5263 return TRUE;
5264 case NODE_STR:
5265 case NODE_FILE:
5266 return hash_key || frozen_string_literal_p(iseq);
5267 default:
5268 return FALSE;
5269 }
5270}
5271
5272static inline VALUE
5273static_literal_value(const NODE *node, rb_iseq_t *iseq)
5274{
5275 switch (nd_type(node)) {
5276 case NODE_INTEGER:
5277 {
5278 VALUE lit = rb_node_integer_literal_val(node);
5279 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5280 return lit;
5281 }
5282 case NODE_FLOAT:
5283 {
5284 VALUE lit = rb_node_float_literal_val(node);
5285 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5286 return lit;
5287 }
5288 case NODE_RATIONAL:
5289 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5290 case NODE_IMAGINARY:
5291 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5292 case NODE_NIL:
5293 return Qnil;
5294 case NODE_TRUE:
5295 return Qtrue;
5296 case NODE_FALSE:
5297 return Qfalse;
5298 case NODE_SYM:
5299 return rb_node_sym_string_val(node);
5300 case NODE_REGX:
5301 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5302 case NODE_LINE:
5303 return rb_node_line_lineno_val(node);
5304 case NODE_ENCODING:
5305 return rb_node_encoding_val(node);
5306 case NODE_FILE:
5307 case NODE_STR:
5308 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5309 VALUE lit = get_string_value(node);
5310 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5312 return str;
5313 }
5314 else {
5315 return get_string_value(node);
5316 }
5317 default:
5318 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5319 }
5320}
5321
5322static int
5323compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5324{
5325 const NODE *line_node = node;
5326
5327 if (nd_type_p(node, NODE_ZLIST)) {
5328 if (!popped) {
5329 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5330 }
5331 return 0;
5332 }
5333
5334 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5335
5336 if (popped) {
5337 for (; node; node = RNODE_LIST(node)->nd_next) {
5338 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5339 }
5340 return 1;
5341 }
5342
5343 /* Compilation of an array literal.
5344 * The following code is essentially the same as:
5345 *
5346 * for (int count = 0; node; count++; node->nd_next) {
5347 * compile(node->nd_head);
5348 * }
5349 * ADD_INSN(newarray, count);
5350 *
5351 * However, there are three points.
5352 *
5353 * - The code above causes stack overflow for a big string literal.
5354 * The following limits the stack length up to max_stack_len.
5355 *
5356 * [x1,x2,...,x10000] =>
5357 * push x1 ; push x2 ; ...; push x256; newarray 256;
5358 * push x257; push x258; ...; push x512; pushtoarray 256;
5359 * push x513; push x514; ...; push x768; pushtoarray 256;
5360 * ...
5361 *
5362 * - Long subarray can be optimized by pre-allocating a hidden array.
5363 *
5364 * [1,2,3,...,100] =>
5365 * duparray [1,2,3,...,100]
5366 *
5367 * [x, 1,2,3,...,100, z] =>
5368 * push x; newarray 1;
5369 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5370 * push z; pushtoarray 1;
5371 *
5372 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5373 * to only push it onto the array if it is not empty
5374 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5375 *
5376 * [1,2,3,**kw] =>
5377 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5378 */
5379
5380 const int max_stack_len = 0x100;
5381 const int min_tmp_ary_len = 0x40;
5382 int stack_len = 0;
5383
5384 /* Either create a new array, or push to the existing array */
5385#define FLUSH_CHUNK \
5386 if (stack_len) { \
5387 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5388 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5389 first_chunk = FALSE; \
5390 stack_len = 0; \
5391 }
5392
5393 while (node) {
5394 int count = 1;
5395
5396 /* pre-allocation check (this branch can be omittable) */
5397 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5398 /* count the elements that are optimizable */
5399 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5400 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5401 count++;
5402
5403 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5404 /* The literal contains only optimizable elements, or the subarray is long enough */
5405 VALUE ary = rb_ary_hidden_new(count);
5406
5407 /* Create a hidden array */
5408 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5409 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5411
5412 /* Emit optimized code */
5413 FLUSH_CHUNK;
5414 if (first_chunk) {
5415 ADD_INSN1(ret, line_node, duparray, ary);
5416 first_chunk = FALSE;
5417 }
5418 else {
5419 ADD_INSN1(ret, line_node, putobject, ary);
5420 ADD_INSN(ret, line_node, concattoarray);
5421 }
5423 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5424 }
5425 }
5426
5427 /* Base case: Compile "count" elements */
5428 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5429 if (CPDEBUG > 0) {
5430 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5431 }
5432
5433 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5434 /* Create array or push existing non-keyword elements onto array */
5435 if (stack_len == 0 && first_chunk) {
5436 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5437 }
5438 else {
5439 FLUSH_CHUNK;
5440 }
5441 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5442 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5443 return 1;
5444 }
5445 else {
5446 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5447 stack_len++;
5448 }
5449
5450 /* If there are many pushed elements, flush them to avoid stack overflow */
5451 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5452 }
5453 }
5454
5455 FLUSH_CHUNK;
5456#undef FLUSH_CHUNK
5457 return 1;
5458}
5459
5460static inline int
5461static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5462{
5463 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);
5464}
5465
5466static int
5467compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5468{
5469 const NODE *line_node = node;
5470
5471 node = RNODE_HASH(node)->nd_head;
5472
5473 if (!node || nd_type_p(node, NODE_ZLIST)) {
5474 if (!popped) {
5475 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5476 }
5477 return 0;
5478 }
5479
5480 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5481
5482 if (popped) {
5483 for (; node; node = RNODE_LIST(node)->nd_next) {
5484 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5485 }
5486 return 1;
5487 }
5488
5489 /* Compilation of a hash literal (or keyword arguments).
5490 * This is very similar to compile_array, but there are some differences:
5491 *
5492 * - It contains key-value pairs. So we need to take every two elements.
5493 * We can assume that the length is always even.
5494 *
5495 * - Merging is done by a method call (id_core_hash_merge_bang_ptr).
5496 * Sometimes we need to insert the receiver, so "anchor" is needed.
5497 * In addition, a method call is much slower than concatarray.
5498 * So it pays only when the subsequence is really long.
5499 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5500 *
5501 * - We need to handle keyword splat: **kw.
5502 * For **kw, the key part (node->nd_head) is NULL, and the value part
5503 * (node->nd_next->nd_head) is "kw".
5504 * The code is a bit difficult to avoid hash allocation for **{}.
5505 */
5506
5507 const int max_stack_len = 0x100;
5508 const int min_tmp_hash_len = 0x800;
5509 int stack_len = 0;
5510 int first_chunk = 1;
5511 DECL_ANCHOR(anchor);
5512 INIT_ANCHOR(anchor);
5513
5514 /* Convert pushed elements to a hash, and merge if needed */
5515#define FLUSH_CHUNK() \
5516 if (stack_len) { \
5517 if (first_chunk) { \
5518 APPEND_LIST(ret, anchor); \
5519 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5520 } \
5521 else { \
5522 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5523 ADD_INSN(ret, line_node, swap); \
5524 APPEND_LIST(ret, anchor); \
5525 ADD_SEND(ret, line_node, id_core_hash_merge_bang_ptr, INT2FIX(stack_len + 1)); \
5526 } \
5527 INIT_ANCHOR(anchor); \
5528 first_chunk = stack_len = 0; \
5529 }
5530
5531 while (node) {
5532 int count = 1;
5533
5534 /* pre-allocation check (this branch can be omittable) */
5535 if (static_literal_node_pair_p(node, iseq)) {
5536 /* count the elements that are optimizable */
5537 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5538 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5539 count++;
5540
5541 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5542 /* The literal contains only optimizable elements, or the subsequence is long enough */
5543 VALUE ary = rb_ary_hidden_new(count);
5544
5545 /* Create a hidden hash */
5546 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5547 VALUE elem[2];
5548 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5549 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5550 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5551 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5552 rb_ary_cat(ary, elem, 2);
5553 }
5554 VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
5555 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5556 RB_GC_GUARD(ary);
5557 hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
5558
5559 /* Emit optimized code */
5560 FLUSH_CHUNK();
5561 if (first_chunk) {
5562 ADD_INSN1(ret, line_node, duphash, hash);
5563 first_chunk = 0;
5564 }
5565 else {
5566 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5567 ADD_INSN(ret, line_node, swap);
5568
5569 ADD_INSN1(ret, line_node, putobject, hash);
5570
5571 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5572 }
5573 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5574 }
5575 }
5576
5577 /* Base case: Compile "count" elements */
5578 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5579
5580 if (CPDEBUG > 0) {
5581 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5582 }
5583
5584 if (RNODE_LIST(node)->nd_head) {
5585 /* Normal key-value pair */
5586 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5587 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5588 stack_len += 2;
5589
5590 /* If there are many pushed elements, flush them to avoid stack overflow */
5591 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5592 }
5593 else {
5594 /* kwsplat case: foo(..., **kw, ...) */
5595 FLUSH_CHUNK();
5596
5597 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5598 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5599 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5600 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5601 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5602
5603 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5604 if (empty_kw) {
5605 if (only_kw && method_call_keywords) {
5606 /* **{} appears at the only keyword argument in method call,
5607 * so it won't be modified.
5608 * kw is a special NODE_LIT that contains a special empty hash,
5609 * so this emits: putobject {}.
5610 * This is only done for method calls and not for literal hashes,
5611 * because literal hashes should always result in a new hash.
5612 */
5613 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5614 }
5615 else if (first_kw) {
5616 /* **{} appears as the first keyword argument, so it may be modified.
5617 * We need to create a fresh hash object.
5618 */
5619 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5620 }
5621 /* Any empty keyword splats that are not the first can be ignored.
5622 * since merging an empty hash into the existing hash is the same
5623 * as not merging it. */
5624 }
5625 else {
5626 if (only_kw && method_call_keywords) {
5627 /* **kw is only keyword argument in method call.
5628 * Use directly. This will be not be flagged as mutable.
5629 * This is only done for method calls and not for literal hashes,
5630 * because literal hashes should always result in a new hash.
5631 */
5632 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5633 }
5634 else {
5635 /* There is more than one keyword argument, or this is not a method
5636 * call. In that case, we need to add an empty hash (if first keyword),
5637 * or merge the hash to the accumulated hash (if not the first keyword).
5638 */
5639 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5640 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5641 else ADD_INSN(ret, line_node, swap);
5642
5643 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5644
5645 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5646 }
5647 }
5648
5649 first_chunk = 0;
5650 }
5651 }
5652 }
5653
5654 FLUSH_CHUNK();
5655#undef FLUSH_CHUNK
5656 return 1;
5657}
5658
5659static VALUE
5660rb_node_case_when_optimizable_literal(const NODE *const node)
5661{
5662 switch (nd_type(node)) {
5663 case NODE_INTEGER:
5664 return rb_node_integer_literal_val(node);
5665 case NODE_FLOAT: {
5666 VALUE v = rb_node_float_literal_val(node);
5667 double ival;
5668
5669 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5670 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5671 }
5672 return v;
5673 }
5674 case NODE_RATIONAL:
5675 case NODE_IMAGINARY:
5676 return Qundef;
5677 case NODE_NIL:
5678 return Qnil;
5679 case NODE_TRUE:
5680 return Qtrue;
5681 case NODE_FALSE:
5682 return Qfalse;
5683 case NODE_SYM:
5684 return rb_node_sym_string_val(node);
5685 case NODE_LINE:
5686 return rb_node_line_lineno_val(node);
5687 case NODE_STR:
5688 return rb_node_str_string_val(node);
5689 case NODE_FILE:
5690 return rb_node_file_path_val(node);
5691 }
5692 return Qundef;
5693}
5694
5695static int
5696when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5697 LABEL *l1, int only_special_literals, VALUE literals)
5698{
5699 while (vals) {
5700 const NODE *val = RNODE_LIST(vals)->nd_head;
5701 VALUE lit = rb_node_case_when_optimizable_literal(val);
5702
5703 if (UNDEF_P(lit)) {
5704 only_special_literals = 0;
5705 }
5706 else {
5707 cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
5708 }
5709
5710 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5711 debugp_param("nd_lit", get_string_value(val));
5712 lit = get_string_value(val);
5713 ADD_INSN1(cond_seq, val, putobject, lit);
5714 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5715 }
5716 else {
5717 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5718 }
5719
5720 // Emit pattern === target
5721 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5722 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5723 ADD_INSNL(cond_seq, val, branchif, l1);
5724 vals = RNODE_LIST(vals)->nd_next;
5725 }
5726 return only_special_literals;
5727}
5728
5729static int
5730when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5731 LABEL *l1, int only_special_literals, VALUE literals)
5732{
5733 const NODE *line_node = vals;
5734
5735 switch (nd_type(vals)) {
5736 case NODE_LIST:
5737 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5738 return COMPILE_NG;
5739 break;
5740 case NODE_SPLAT:
5741 ADD_INSN (cond_seq, line_node, dup);
5742 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5743 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5744 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5745 ADD_INSNL(cond_seq, line_node, branchif, l1);
5746 break;
5747 case NODE_ARGSCAT:
5748 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5749 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5750 break;
5751 case NODE_ARGSPUSH:
5752 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5753 ADD_INSN (cond_seq, line_node, dup);
5754 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5755 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5756 ADD_INSNL(cond_seq, line_node, branchif, l1);
5757 break;
5758 default:
5759 ADD_INSN (cond_seq, line_node, dup);
5760 CHECK(COMPILE(cond_seq, "when val", vals));
5761 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5762 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5763 ADD_INSNL(cond_seq, line_node, branchif, l1);
5764 break;
5765 }
5766 return COMPILE_OK;
5767}
5768
5769/* Multiple Assignment Handling
5770 *
5771 * In order to handle evaluation of multiple assignment such that the left hand side
5772 * is evaluated before the right hand side, we need to process the left hand side
5773 * and see if there are any attributes that need to be assigned, or constants set
5774 * on explicit objects. If so, we add instructions to evaluate the receiver of
5775 * any assigned attributes or constants before we process the right hand side.
5776 *
5777 * For a multiple assignment such as:
5778 *
5779 * l1.m1, l2[0] = r3, r4
5780 *
5781 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5782 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5783 * On the VM stack, this looks like:
5784 *
5785 * self # putself
5786 * l1 # send
5787 * l1, self # putself
5788 * l1, l2 # send
5789 * l1, l2, 0 # putobject 0
5790 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5791 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5792 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5793 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5794 * l1, l2, 0, [r3, r4], r4, m1= # send
5795 * l1, l2, 0, [r3, r4], r4 # pop
5796 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5797 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5798 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5799 * l1, l2, 0, [r3, r4], r4, []= # send
5800 * l1, l2, 0, [r3, r4], r4 # pop
5801 * l1, l2, 0, [r3, r4] # pop
5802 * [r3, r4], l2, 0, [r3, r4] # setn 3
5803 * [r3, r4], l2, 0 # pop
5804 * [r3, r4], l2 # pop
5805 * [r3, r4] # pop
5806 *
5807 * This is made more complex when you have to handle splats, post args,
5808 * and arbitrary levels of nesting. You need to keep track of the total
5809 * number of attributes to set, and for each attribute, how many entries
5810 * are on the stack before the final attribute, in order to correctly
5811 * calculate the topn value to use to get the receiver of the attribute
5812 * setter method.
5813 *
5814 * A brief description of the VM stack for simple multiple assignment
5815 * with no splat (rhs_array will not be present if the return value of
5816 * the multiple assignment is not needed):
5817 *
5818 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5819 *
5820 * For multiple assignment with splats, while processing the part before
5821 * the splat (splat+post here is an array of the splat and the post arguments):
5822 *
5823 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5824 *
5825 * When processing the splat and post arguments:
5826 *
5827 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5828 *
5829 * When processing nested multiple assignment, existing values on the stack
5830 * are kept. So for:
5831 *
5832 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5833 *
5834 * The stack layout would be the following before processing the nested
5835 * multiple assignment:
5836 *
5837 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5838 *
5839 * In order to handle this correctly, we need to keep track of the nesting
5840 * level for each attribute assignment, as well as the attribute number
5841 * (left hand side attributes are processed left to right) and number of
5842 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5843 * this information.
5844 *
5845 * We also need to track information for the entire multiple assignment, such
5846 * as the total number of arguments, and the current nesting level, to
5847 * handle both nested multiple assignment as well as cases where the
5848 * rhs is not needed. We also need to keep track of all attribute
5849 * assignments in this, which we do using a linked listed. struct masgn_state
5850 * tracks this information.
5851 */
5852
5854 INSN *before_insn;
5855 struct masgn_lhs_node *next;
5856 const NODE *line_node;
5857 int argn;
5858 int num_args;
5859 int lhs_pos;
5860};
5861
5863 struct masgn_lhs_node *first_memo;
5864 struct masgn_lhs_node *last_memo;
5865 int lhs_level;
5866 int num_args;
5867 bool nested;
5868};
5869
5870static int
5871add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5872{
5873 if (!state) {
5874 rb_bug("no masgn_state");
5875 }
5876
5877 struct masgn_lhs_node *memo;
5878 memo = malloc(sizeof(struct masgn_lhs_node));
5879 if (!memo) {
5880 return COMPILE_NG;
5881 }
5882
5883 memo->before_insn = before_insn;
5884 memo->line_node = line_node;
5885 memo->argn = state->num_args + 1;
5886 memo->num_args = argc;
5887 state->num_args += argc;
5888 memo->lhs_pos = lhs_pos;
5889 memo->next = NULL;
5890 if (!state->first_memo) {
5891 state->first_memo = memo;
5892 }
5893 else {
5894 state->last_memo->next = memo;
5895 }
5896 state->last_memo = memo;
5897
5898 return COMPILE_OK;
5899}
5900
5901static 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);
5902
5903static int
5904compile_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)
5905{
5906 switch (nd_type(node)) {
5907 case NODE_ATTRASGN: {
5908 INSN *iobj;
5909 const NODE *line_node = node;
5910
5911 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5912
5913 bool safenav_call = false;
5914 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5915 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5916 ASSUME(iobj);
5917 ELEM_REMOVE(insn_element);
5918 if (!IS_INSN_ID(iobj, send)) {
5919 safenav_call = true;
5920 iobj = (INSN *)get_prev_insn(iobj);
5921 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5922 }
5923 (pre->last = iobj->link.prev)->next = 0;
5924
5925 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5926 int argc = vm_ci_argc(ci) + 1;
5927 ci = ci_argc_set(iseq, ci, argc);
5928 OPERAND_AT(iobj, 0) = (VALUE)ci;
5929 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5930
5931 if (argc == 1) {
5932 ADD_INSN(lhs, line_node, swap);
5933 }
5934 else {
5935 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5936 }
5937
5938 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5939 return COMPILE_NG;
5940 }
5941
5942 iobj->link.prev = lhs->last;
5943 lhs->last->next = &iobj->link;
5944 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5945 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5946 int argc = vm_ci_argc(ci);
5947 bool dupsplat = false;
5948 ci = ci_argc_set(iseq, ci, argc - 1);
5949 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5950 /* Given h[*a], _ = ary
5951 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5952 * `a` must be dupped, because it will be appended with ary[0]
5953 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5954 */
5955 dupsplat = true;
5956 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5957 }
5958 OPERAND_AT(iobj, 0) = (VALUE)ci;
5959 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5960
5961 /* Given: h[*a], h[*b, 1] = ary
5962 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5963 * so this uses splatarray true on a to dup it before using pushtoarray
5964 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5965 * so you can use pushtoarray directly
5966 */
5967 int line_no = nd_line(line_node);
5968 int node_id = nd_node_id(line_node);
5969
5970 if (dupsplat) {
5971 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5972 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5973 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5974 }
5975 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5976 }
5977 if (!safenav_call) {
5978 ADD_INSN(lhs, line_node, pop);
5979 if (argc != 1) {
5980 ADD_INSN(lhs, line_node, pop);
5981 }
5982 }
5983 for (int i=0; i < argc; i++) {
5984 ADD_INSN(post, line_node, pop);
5985 }
5986 break;
5987 }
5988 case NODE_MASGN: {
5989 DECL_ANCHOR(nest_rhs);
5990 INIT_ANCHOR(nest_rhs);
5991 DECL_ANCHOR(nest_lhs);
5992 INIT_ANCHOR(nest_lhs);
5993
5994 int prev_level = state->lhs_level;
5995 bool prev_nested = state->nested;
5996 state->nested = 1;
5997 state->lhs_level = lhs_pos - 1;
5998 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5999 state->lhs_level = prev_level;
6000 state->nested = prev_nested;
6001
6002 ADD_SEQ(lhs, nest_rhs);
6003 ADD_SEQ(lhs, nest_lhs);
6004 break;
6005 }
6006 case NODE_CDECL:
6007 if (!RNODE_CDECL(node)->nd_vid) {
6008 /* Special handling only needed for expr::C, not for C */
6009 INSN *iobj;
6010
6011 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
6012
6013 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
6014 iobj = (INSN *)insn_element; /* setconstant insn */
6015 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
6016 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
6017 ELEM_REMOVE(insn_element);
6018 pre->last = iobj->link.prev;
6019 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
6020
6021 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
6022 return COMPILE_NG;
6023 }
6024
6025 ADD_INSN(post, node, pop);
6026 break;
6027 }
6028 /* Fallthrough */
6029 default: {
6030 DECL_ANCHOR(anchor);
6031 INIT_ANCHOR(anchor);
6032 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
6033 ELEM_REMOVE(FIRST_ELEMENT(anchor));
6034 ADD_SEQ(lhs, anchor);
6035 }
6036 }
6037
6038 return COMPILE_OK;
6039}
6040
6041static int
6042compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
6043{
6044 if (lhsn) {
6045 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
6046 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
6047 }
6048 return COMPILE_OK;
6049}
6050
6051static int
6052compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6053 const NODE *rhsn, const NODE *orig_lhsn)
6054{
6055 VALUE mem[64];
6056 const int memsize = numberof(mem);
6057 int memindex = 0;
6058 int llen = 0, rlen = 0;
6059 int i;
6060 const NODE *lhsn = orig_lhsn;
6061
6062#define MEMORY(v) { \
6063 int i; \
6064 if (memindex == memsize) return 0; \
6065 for (i=0; i<memindex; i++) { \
6066 if (mem[i] == (v)) return 0; \
6067 } \
6068 mem[memindex++] = (v); \
6069}
6070
6071 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
6072 return 0;
6073 }
6074
6075 while (lhsn) {
6076 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
6077 switch (nd_type(ln)) {
6078 case NODE_LASGN:
6079 case NODE_DASGN:
6080 case NODE_IASGN:
6081 case NODE_CVASGN:
6082 MEMORY(get_nd_vid(ln));
6083 break;
6084 default:
6085 return 0;
6086 }
6087 lhsn = RNODE_LIST(lhsn)->nd_next;
6088 llen++;
6089 }
6090
6091 while (rhsn) {
6092 if (llen <= rlen) {
6093 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
6094 }
6095 else {
6096 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
6097 }
6098 rhsn = RNODE_LIST(rhsn)->nd_next;
6099 rlen++;
6100 }
6101
6102 if (llen > rlen) {
6103 for (i=0; i<llen-rlen; i++) {
6104 ADD_INSN(ret, orig_lhsn, putnil);
6105 }
6106 }
6107
6108 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
6109 return 1;
6110}
6111
6112static int
6113compile_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)
6114{
6115 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
6116 const NODE *splatn = RNODE_MASGN(node)->nd_args;
6117 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
6118 const NODE *lhsn_count = lhsn;
6119 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
6120
6121 int llen = 0;
6122 int lpos = 0;
6123
6124 while (lhsn_count) {
6125 llen++;
6126 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
6127 }
6128 while (lhsn) {
6129 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
6130 lpos++;
6131 lhsn = RNODE_LIST(lhsn)->nd_next;
6132 }
6133
6134 if (lhs_splat) {
6135 if (nd_type_p(splatn, NODE_POSTARG)) {
6136 /*a, b, *r, p1, p2 */
6137 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
6138 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
6139 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
6140 int ppos = 0;
6141 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
6142
6143 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6144
6145 if (NODE_NAMED_REST_P(restn)) {
6146 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6147 }
6148 while (postn) {
6149 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6150 ppos++;
6151 postn = RNODE_LIST(postn)->nd_next;
6152 }
6153 }
6154 else {
6155 /* a, b, *r */
6156 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6157 }
6158 }
6159
6160 if (!state->nested) {
6161 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6162 }
6163
6164 if (!popped) {
6165 ADD_INSN(rhs, node, dup);
6166 }
6167 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6168 return COMPILE_OK;
6169}
6170
6171static int
6172compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6173{
6174 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6175 struct masgn_state state;
6176 state.lhs_level = popped ? 0 : 1;
6177 state.nested = 0;
6178 state.num_args = 0;
6179 state.first_memo = NULL;
6180 state.last_memo = NULL;
6181
6182 DECL_ANCHOR(pre);
6183 INIT_ANCHOR(pre);
6184 DECL_ANCHOR(rhs);
6185 INIT_ANCHOR(rhs);
6186 DECL_ANCHOR(lhs);
6187 INIT_ANCHOR(lhs);
6188 DECL_ANCHOR(post);
6189 INIT_ANCHOR(post);
6190 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6191
6192 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6193 while (memo) {
6194 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6195 for (int i = 0; i < memo->num_args; i++) {
6196 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6197 }
6198 tmp_memo = memo->next;
6199 free(memo);
6200 memo = tmp_memo;
6201 }
6202 CHECK(ok);
6203
6204 ADD_SEQ(ret, pre);
6205 ADD_SEQ(ret, rhs);
6206 ADD_SEQ(ret, lhs);
6207 if (!popped && state.num_args >= 1) {
6208 /* make sure rhs array is returned before popping */
6209 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6210 }
6211 ADD_SEQ(ret, post);
6212 }
6213 return COMPILE_OK;
6214}
6215
6216static VALUE
6217collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6218{
6219 VALUE arr = rb_ary_new();
6220 for (;;) {
6221 switch (nd_type(node)) {
6222 case NODE_CONST:
6223 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6225 return arr;
6226 case NODE_COLON3:
6227 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6228 rb_ary_unshift(arr, ID2SYM(idNULL));
6230 return arr;
6231 case NODE_COLON2:
6232 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6233 node = RNODE_COLON2(node)->nd_head;
6234 break;
6235 default:
6236 return Qfalse;
6237 }
6238 }
6239}
6240
6241static int
6242compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6243 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6244{
6245 switch (nd_type(node)) {
6246 case NODE_CONST:
6247 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6248 ADD_INSN1(body, node, putobject, Qtrue);
6249 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6250 break;
6251 case NODE_COLON3:
6252 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6253 ADD_INSN(body, node, pop);
6254 ADD_INSN1(body, node, putobject, rb_cObject);
6255 ADD_INSN1(body, node, putobject, Qtrue);
6256 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6257 break;
6258 case NODE_COLON2:
6259 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6260 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6261 ADD_INSN1(body, node, putobject, Qfalse);
6262 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6263 break;
6264 default:
6265 CHECK(COMPILE(pref, "const colon2 prefix", node));
6266 break;
6267 }
6268 return COMPILE_OK;
6269}
6270
6271static int
6272cpath_const_p(const NODE *node)
6273{
6274 switch (nd_type(node)) {
6275 case NODE_CONST:
6276 case NODE_COLON3:
6277 return TRUE;
6278 case NODE_COLON2:
6279 if (RNODE_COLON2(node)->nd_head) {
6280 return cpath_const_p(RNODE_COLON2(node)->nd_head);
6281 }
6282 return TRUE;
6283 default:
6284 return FALSE;
6285 }
6286}
6287
6288static int
6289compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6290{
6291 if (nd_type_p(cpath, NODE_COLON3)) {
6292 /* toplevel class ::Foo */
6293 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6294 return VM_DEFINECLASS_FLAG_SCOPED;
6295 }
6296 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6297 /* Bar::Foo or expr::Foo */
6298 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6299 int flags = VM_DEFINECLASS_FLAG_SCOPED;
6300 if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
6301 flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
6302 }
6303 return flags;
6304 }
6305 else {
6306 /* class at cbase Foo */
6307 ADD_INSN1(ret, cpath, putspecialobject,
6308 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6309 return 0;
6310 }
6311}
6312
6313static inline int
6314private_recv_p(const NODE *node)
6315{
6316 NODE *recv = get_nd_recv(node);
6317 if (recv && nd_type_p(recv, NODE_SELF)) {
6318 return RNODE_SELF(recv)->nd_state != 0;
6319 }
6320 return 0;
6321}
6322
6323static void
6324defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6325 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6326
6327static int
6328compile_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);
6329
6330static void
6331defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6332 const NODE *const node, LABEL **lfinish, VALUE needstr,
6333 bool keep_result)
6334{
6335 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6336 enum node_type type;
6337 const int line = nd_line(node);
6338 const NODE *line_node = node;
6339
6340 switch (type = nd_type(node)) {
6341
6342 /* easy literals */
6343 case NODE_NIL:
6344 expr_type = DEFINED_NIL;
6345 break;
6346 case NODE_SELF:
6347 expr_type = DEFINED_SELF;
6348 break;
6349 case NODE_TRUE:
6350 expr_type = DEFINED_TRUE;
6351 break;
6352 case NODE_FALSE:
6353 expr_type = DEFINED_FALSE;
6354 break;
6355
6356 case NODE_HASH:
6357 case NODE_LIST:{
6358 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6359
6360 if (vals) {
6361 do {
6362 if (RNODE_LIST(vals)->nd_head) {
6363 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6364
6365 if (!lfinish[1]) {
6366 lfinish[1] = NEW_LABEL(line);
6367 }
6368 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6369 }
6370 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6371 }
6372 }
6373 /* fall through */
6374 case NODE_STR:
6375 case NODE_SYM:
6376 case NODE_REGX:
6377 case NODE_LINE:
6378 case NODE_FILE:
6379 case NODE_ENCODING:
6380 case NODE_INTEGER:
6381 case NODE_FLOAT:
6382 case NODE_RATIONAL:
6383 case NODE_IMAGINARY:
6384 case NODE_ZLIST:
6385 case NODE_AND:
6386 case NODE_OR:
6387 default:
6388 expr_type = DEFINED_EXPR;
6389 break;
6390
6391 case NODE_SPLAT:
6392 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6393 if (!lfinish[1]) {
6394 lfinish[1] = NEW_LABEL(line);
6395 }
6396 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6397 expr_type = DEFINED_EXPR;
6398 break;
6399
6400 /* variables */
6401 case NODE_LVAR:
6402 case NODE_DVAR:
6403 expr_type = DEFINED_LVAR;
6404 break;
6405
6406#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6407 case NODE_IVAR:
6408 ADD_INSN3(ret, line_node, definedivar,
6409 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6410 return;
6411
6412 case NODE_GVAR:
6413 ADD_INSN(ret, line_node, putnil);
6414 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6415 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6416 return;
6417
6418 case NODE_CVAR:
6419 ADD_INSN(ret, line_node, putnil);
6420 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6421 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6422 return;
6423
6424 case NODE_CONST:
6425 ADD_INSN(ret, line_node, putnil);
6426 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6427 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6428 return;
6429 case NODE_COLON2:
6430 if (!lfinish[1]) {
6431 lfinish[1] = NEW_LABEL(line);
6432 }
6433 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6434 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6435 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6436
6437 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6438 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6439 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6440 }
6441 else {
6442 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6443 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6444 }
6445 return;
6446 case NODE_COLON3:
6447 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6448 ADD_INSN3(ret, line_node, defined,
6449 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6450 return;
6451
6452 /* method dispatch */
6453 case NODE_CALL:
6454 case NODE_OPCALL:
6455 case NODE_VCALL:
6456 case NODE_FCALL:
6457 case NODE_ATTRASGN:{
6458 const int explicit_receiver =
6459 (type == NODE_CALL || type == NODE_OPCALL ||
6460 (type == NODE_ATTRASGN && !private_recv_p(node)));
6461
6462 if (get_nd_args(node) || explicit_receiver) {
6463 if (!lfinish[1]) {
6464 lfinish[1] = NEW_LABEL(line);
6465 }
6466 if (!lfinish[2]) {
6467 lfinish[2] = NEW_LABEL(line);
6468 }
6469 }
6470 if (get_nd_args(node)) {
6471 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6472 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6473 }
6474 if (explicit_receiver) {
6475 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6476 switch (nd_type(get_nd_recv(node))) {
6477 case NODE_CALL:
6478 case NODE_OPCALL:
6479 case NODE_VCALL:
6480 case NODE_FCALL:
6481 case NODE_ATTRASGN:
6482 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6483 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6484 break;
6485 default:
6486 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6487 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6488 break;
6489 }
6490 if (keep_result) {
6491 ADD_INSN(ret, line_node, dup);
6492 }
6493 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6494 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6495 }
6496 else {
6497 ADD_INSN(ret, line_node, putself);
6498 if (keep_result) {
6499 ADD_INSN(ret, line_node, dup);
6500 }
6501 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6502 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6503 }
6504 return;
6505 }
6506
6507 case NODE_YIELD:
6508 ADD_INSN(ret, line_node, putnil);
6509 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6510 PUSH_VAL(DEFINED_YIELD));
6511 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6512 return;
6513
6514 case NODE_BACK_REF:
6515 case NODE_NTH_REF:
6516 ADD_INSN(ret, line_node, putnil);
6517 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6518 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6519 PUSH_VAL(DEFINED_GVAR));
6520 return;
6521
6522 case NODE_SUPER:
6523 case NODE_ZSUPER:
6524 ADD_INSN(ret, line_node, putnil);
6525 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6526 PUSH_VAL(DEFINED_ZSUPER));
6527 return;
6528
6529#undef PUSH_VAL
6530 case NODE_OP_ASGN1:
6531 case NODE_OP_ASGN2:
6532 case NODE_OP_ASGN_OR:
6533 case NODE_OP_ASGN_AND:
6534 case NODE_MASGN:
6535 case NODE_LASGN:
6536 case NODE_DASGN:
6537 case NODE_GASGN:
6538 case NODE_IASGN:
6539 case NODE_CDECL:
6540 case NODE_CVASGN:
6541 case NODE_OP_CDECL:
6542 expr_type = DEFINED_ASGN;
6543 break;
6544 }
6545
6546 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6547
6548 if (needstr != Qfalse) {
6549 VALUE str = rb_iseq_defined_string(expr_type);
6550 ADD_INSN1(ret, line_node, putobject, str);
6551 }
6552 else {
6553 ADD_INSN1(ret, line_node, putobject, Qtrue);
6554 }
6555}
6556
6557static void
6558build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6559{
6560 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6561 iseq_set_exception_local_table(iseq);
6562}
6563
6564static void
6565defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6566 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6567{
6568 LINK_ELEMENT *lcur = ret->last;
6569 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6570 if (lfinish[1]) {
6571 int line = nd_line(node);
6572 LABEL *lstart = NEW_LABEL(line);
6573 LABEL *lend = NEW_LABEL(line);
6574 const rb_iseq_t *rescue;
6576 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6577 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6578 rb_str_concat(rb_str_new2("defined guard in "),
6579 ISEQ_BODY(iseq)->location.label),
6580 ISEQ_TYPE_RESCUE, 0);
6581 lstart->rescued = LABEL_RESCUE_BEG;
6582 lend->rescued = LABEL_RESCUE_END;
6583 APPEND_LABEL(ret, lcur, lstart);
6584 ADD_LABEL(ret, lend);
6585 if (!ignore) {
6586 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6587 }
6588 }
6589}
6590
6591static int
6592compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6593{
6594 const int line = nd_line(node);
6595 const NODE *line_node = node;
6596 if (!RNODE_DEFINED(node)->nd_head) {
6597 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6598 ADD_INSN1(ret, line_node, putobject, str);
6599 }
6600 else {
6601 LABEL *lfinish[3];
6602 LINK_ELEMENT *last = ret->last;
6603 lfinish[0] = NEW_LABEL(line);
6604 lfinish[1] = 0;
6605 lfinish[2] = 0;
6606 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6607 if (lfinish[1]) {
6608 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6609 ADD_INSN(ret, line_node, swap);
6610 if (lfinish[2]) {
6611 ADD_LABEL(ret, lfinish[2]);
6612 }
6613 ADD_INSN(ret, line_node, pop);
6614 ADD_LABEL(ret, lfinish[1]);
6615 }
6616 ADD_LABEL(ret, lfinish[0]);
6617 }
6618 return COMPILE_OK;
6619}
6620
6621static VALUE
6622make_name_for_block(const rb_iseq_t *orig_iseq)
6623{
6624 int level = 1;
6625 const rb_iseq_t *iseq = orig_iseq;
6626
6627 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6628 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6629 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6630 level++;
6631 }
6632 iseq = ISEQ_BODY(iseq)->parent_iseq;
6633 }
6634 }
6635
6636 if (level == 1) {
6637 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6638 }
6639 else {
6640 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6641 }
6642}
6643
6644static void
6645push_ensure_entry(rb_iseq_t *iseq,
6647 struct ensure_range *er, const void *const node)
6648{
6649 enl->ensure_node = node;
6650 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6651 enl->erange = er;
6652 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6653}
6654
6655static void
6656add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6657 LABEL *lstart, LABEL *lend)
6658{
6659 struct ensure_range *ne =
6660 compile_data_alloc_type(iseq, struct ensure_range);
6661
6662 while (erange->next != 0) {
6663 erange = erange->next;
6664 }
6665 ne->next = 0;
6666 ne->begin = lend;
6667 ne->end = erange->end;
6668 erange->end = lstart;
6669
6670 erange->next = ne;
6671}
6672
6673static bool
6674can_add_ensure_iseq(const rb_iseq_t *iseq)
6675{
6677 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6678 while (e) {
6679 if (e->ensure_node) return false;
6680 e = e->prev;
6681 }
6682 }
6683 return true;
6684}
6685
6686static void
6687add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6688{
6689 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6690
6692 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6693 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6694 DECL_ANCHOR(ensure);
6695
6696 INIT_ANCHOR(ensure);
6697 while (enlp) {
6698 if (enlp->erange != NULL) {
6699 DECL_ANCHOR(ensure_part);
6700 LABEL *lstart = NEW_LABEL(0);
6701 LABEL *lend = NEW_LABEL(0);
6702 INIT_ANCHOR(ensure_part);
6703
6704 add_ensure_range(iseq, enlp->erange, lstart, lend);
6705
6706 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6707 ADD_LABEL(ensure_part, lstart);
6708 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6709 ADD_LABEL(ensure_part, lend);
6710 ADD_SEQ(ensure, ensure_part);
6711 }
6712 else {
6713 if (!is_return) {
6714 break;
6715 }
6716 }
6717 enlp = enlp->prev;
6718 }
6719 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6720 ADD_SEQ(ret, ensure);
6721}
6722
6723#if RUBY_DEBUG
6724static int
6725check_keyword(const NODE *node)
6726{
6727 /* This check is essentially a code clone of compile_keyword_arg. */
6728
6729 if (nd_type_p(node, NODE_LIST)) {
6730 while (RNODE_LIST(node)->nd_next) {
6731 node = RNODE_LIST(node)->nd_next;
6732 }
6733 node = RNODE_LIST(node)->nd_head;
6734 }
6735
6736 return keyword_node_p(node);
6737}
6738#endif
6739
6740static bool
6741keyword_node_single_splat_p(NODE *kwnode)
6742{
6743 RUBY_ASSERT(keyword_node_p(kwnode));
6744
6745 NODE *node = RNODE_HASH(kwnode)->nd_head;
6746 return RNODE_LIST(node)->nd_head == NULL &&
6747 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6748}
6749
6750static void
6751compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6752 NODE *kwnode, unsigned int *flag_ptr)
6753{
6754 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6755 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6756 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6757 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6758 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6759}
6760
6761#define SPLATARRAY_FALSE 0
6762#define SPLATARRAY_TRUE 1
6763#define DUP_SINGLE_KW_SPLAT 2
6764
6765static int
6766setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6767 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6768{
6769 if (!argn) return 0;
6770
6771 NODE *kwnode = NULL;
6772
6773 switch (nd_type(argn)) {
6774 case NODE_LIST: {
6775 // f(x, y, z)
6776 int len = compile_args(iseq, args, argn, &kwnode);
6777 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6778
6779 if (kwnode) {
6780 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6781 len -= 1;
6782 }
6783 else {
6784 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6785 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6786 }
6787 else {
6788 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6789 }
6790 }
6791 }
6792
6793 return len;
6794 }
6795 case NODE_SPLAT: {
6796 // f(*a)
6797 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6798 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6799 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6800 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6801 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6802 return 1;
6803 }
6804 case NODE_ARGSCAT: {
6805 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6806 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6807 bool args_pushed = false;
6808
6809 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6810 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6811 if (kwnode) rest_len--;
6812 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6813 args_pushed = true;
6814 }
6815 else {
6816 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6817 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6818 }
6819
6820 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6821 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6822 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6823 argc += 1;
6824 }
6825 else if (!args_pushed) {
6826 ADD_INSN(args, argn, concattoarray);
6827 }
6828
6829 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6830 if (kwnode) {
6831 // kwsplat
6832 *flag_ptr |= VM_CALL_KW_SPLAT;
6833 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6834 argc += 1;
6835 }
6836
6837 return argc;
6838 }
6839 case NODE_ARGSPUSH: {
6840 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6841 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6842
6843 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6844 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6845 if (kwnode) rest_len--;
6846 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6847 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6848 }
6849 else {
6850 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6851 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6852 }
6853 else {
6854 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6855 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6856 }
6857 }
6858
6859 if (kwnode) {
6860 // f(*a, k:1)
6861 *flag_ptr |= VM_CALL_KW_SPLAT;
6862 if (!keyword_node_single_splat_p(kwnode)) {
6863 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6864 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6865 }
6866 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6867 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6868 }
6869 else {
6870 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6871 }
6872 argc += 1;
6873 }
6874
6875 return argc;
6876 }
6877 default: {
6878 UNKNOWN_NODE("setup_arg", argn, Qnil);
6879 }
6880 }
6881}
6882
6883static void
6884setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6885{
6886 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6887 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6888 }
6889}
6890
6891static bool
6892setup_args_dup_rest_p(const NODE *argn)
6893{
6894 switch(nd_type(argn)) {
6895 case NODE_LVAR:
6896 case NODE_DVAR:
6897 case NODE_GVAR:
6898 case NODE_IVAR:
6899 case NODE_CVAR:
6900 case NODE_CONST:
6901 case NODE_COLON3:
6902 case NODE_INTEGER:
6903 case NODE_FLOAT:
6904 case NODE_RATIONAL:
6905 case NODE_IMAGINARY:
6906 case NODE_STR:
6907 case NODE_SYM:
6908 case NODE_REGX:
6909 case NODE_SELF:
6910 case NODE_NIL:
6911 case NODE_TRUE:
6912 case NODE_FALSE:
6913 case NODE_LAMBDA:
6914 case NODE_NTH_REF:
6915 case NODE_BACK_REF:
6916 return false;
6917 case NODE_COLON2:
6918 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6919 case NODE_LIST:
6920 while (argn) {
6921 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6922 return true;
6923 }
6924 argn = RNODE_LIST(argn)->nd_next;
6925 }
6926 return false;
6927 default:
6928 return true;
6929 }
6930}
6931
6932static VALUE
6933setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6934 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6935{
6936 VALUE ret;
6937 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6938
6939 if (argn) {
6940 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6941 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6942
6943 if (check_arg) {
6944 switch(nd_type(check_arg)) {
6945 case(NODE_SPLAT):
6946 // avoid caller side array allocation for f(*arg)
6947 dup_rest = SPLATARRAY_FALSE;
6948 break;
6949 case(NODE_ARGSCAT):
6950 // avoid caller side array allocation for f(1, *arg)
6951 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6952 break;
6953 case(NODE_ARGSPUSH):
6954 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6955 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6956 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6957 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6958 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6959 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6960
6961 if (dup_rest == SPLATARRAY_FALSE) {
6962 // require allocation for keyword key/value/splat that may modify splatted argument
6963 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6964 while (node) {
6965 NODE *key_node = RNODE_LIST(node)->nd_head;
6966 if (key_node && setup_args_dup_rest_p(key_node)) {
6967 dup_rest = SPLATARRAY_TRUE;
6968 break;
6969 }
6970
6971 node = RNODE_LIST(node)->nd_next;
6972 NODE *value_node = RNODE_LIST(node)->nd_head;
6973 if (setup_args_dup_rest_p(value_node)) {
6974 dup_rest = SPLATARRAY_TRUE;
6975 break;
6976 }
6977
6978 node = RNODE_LIST(node)->nd_next;
6979 }
6980 }
6981 break;
6982 default:
6983 break;
6984 }
6985 }
6986
6987 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6988 // for block pass that may modify splatted argument, dup rest and kwrest if given
6989 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6990 }
6991 }
6992 initial_dup_rest = dup_rest;
6993
6994 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6995 DECL_ANCHOR(arg_block);
6996 INIT_ANCHOR(arg_block);
6997
6998 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6999 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
7000
7001 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
7002 const NODE * arg_node =
7003 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
7004
7005 int argc = 0;
7006
7007 // Only compile leading args:
7008 // foo(x, y, ...)
7009 // ^^^^
7010 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
7011 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
7012 }
7013
7014 *flag |= VM_CALL_FORWARDING;
7015
7016 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
7017 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7018 return INT2FIX(argc);
7019 }
7020 else {
7021 *flag |= VM_CALL_ARGS_BLOCKARG;
7022
7023 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
7024 }
7025
7026 if (LIST_INSN_SIZE_ONE(arg_block)) {
7027 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
7028 if (IS_INSN(elem)) {
7029 INSN *iobj = (INSN *)elem;
7030 if (iobj->insn_id == BIN(getblockparam)) {
7031 iobj->insn_id = BIN(getblockparamproxy);
7032 }
7033 }
7034 }
7035 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
7036 ADD_SEQ(args, arg_block);
7037 }
7038 else {
7039 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
7040 }
7041 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7042 return ret;
7043}
7044
7045static void
7046build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
7047{
7048 const NODE *body = ptr;
7049 int line = nd_line(body);
7050 VALUE argc = INT2FIX(0);
7051 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
7052
7053 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7054 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
7055 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
7056 iseq_set_local_table(iseq, 0, 0);
7057}
7058
7059static void
7060compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
7061{
7062 const NODE *vars;
7063 LINK_ELEMENT *last;
7064 int line = nd_line(node);
7065 const NODE *line_node = node;
7066 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
7067
7068#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
7069 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
7070#else
7071 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
7072#endif
7073 ADD_INSN(ret, line_node, dup);
7074 ADD_INSNL(ret, line_node, branchunless, fail_label);
7075
7076 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7077 INSN *cap;
7078 if (RNODE_BLOCK(vars)->nd_next) {
7079 ADD_INSN(ret, line_node, dup);
7080 }
7081 last = ret->last;
7082 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7083 last = last->next; /* putobject :var */
7084 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
7085 NULL, INT2FIX(0), NULL);
7086 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
7087#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
7088 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
7089 /* only one name */
7090 DECL_ANCHOR(nom);
7091
7092 INIT_ANCHOR(nom);
7093 ADD_INSNL(nom, line_node, jump, end_label);
7094 ADD_LABEL(nom, fail_label);
7095# if 0 /* $~ must be MatchData or nil */
7096 ADD_INSN(nom, line_node, pop);
7097 ADD_INSN(nom, line_node, putnil);
7098# endif
7099 ADD_LABEL(nom, end_label);
7100 (nom->last->next = cap->link.next)->prev = nom->last;
7101 (cap->link.next = nom->anchor.next)->prev = &cap->link;
7102 return;
7103 }
7104#endif
7105 }
7106 ADD_INSNL(ret, line_node, jump, end_label);
7107 ADD_LABEL(ret, fail_label);
7108 ADD_INSN(ret, line_node, pop);
7109 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7110 last = ret->last;
7111 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7112 last = last->next; /* putobject :var */
7113 ((INSN*)last)->insn_id = BIN(putnil);
7114 ((INSN*)last)->operand_size = 0;
7115 }
7116 ADD_LABEL(ret, end_label);
7117}
7118
7119static int
7120optimizable_range_item_p(const NODE *n)
7121{
7122 if (!n) return FALSE;
7123 switch (nd_type(n)) {
7124 case NODE_LINE:
7125 return TRUE;
7126 case NODE_INTEGER:
7127 return TRUE;
7128 case NODE_NIL:
7129 return TRUE;
7130 default:
7131 return FALSE;
7132 }
7133}
7134
7135static VALUE
7136optimized_range_item(const NODE *n)
7137{
7138 switch (nd_type(n)) {
7139 case NODE_LINE:
7140 return rb_node_line_lineno_val(n);
7141 case NODE_INTEGER:
7142 return rb_node_integer_literal_val(n);
7143 case NODE_FLOAT:
7144 return rb_node_float_literal_val(n);
7145 case NODE_RATIONAL:
7146 return rb_node_rational_literal_val(n);
7147 case NODE_IMAGINARY:
7148 return rb_node_imaginary_literal_val(n);
7149 case NODE_NIL:
7150 return Qnil;
7151 default:
7152 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
7153 }
7154}
7155
7156static int
7157compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7158{
7159 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
7160 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
7161
7162 const int line = nd_line(node);
7163 const NODE *line_node = node;
7164 DECL_ANCHOR(cond_seq);
7165 LABEL *then_label, *else_label, *end_label;
7166 VALUE branches = Qfalse;
7167
7168 INIT_ANCHOR(cond_seq);
7169 then_label = NEW_LABEL(line);
7170 else_label = NEW_LABEL(line);
7171 end_label = 0;
7172
7173 NODE *cond = RNODE_IF(node)->nd_cond;
7174 if (nd_type(cond) == NODE_BLOCK) {
7175 cond = RNODE_BLOCK(cond)->nd_head;
7176 }
7177
7178 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7179 ADD_SEQ(ret, cond_seq);
7180
7181 if (then_label->refcnt && else_label->refcnt) {
7182 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7183 }
7184
7185 if (then_label->refcnt) {
7186 ADD_LABEL(ret, then_label);
7187
7188 DECL_ANCHOR(then_seq);
7189 INIT_ANCHOR(then_seq);
7190 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7191
7192 if (else_label->refcnt) {
7193 const NODE *const coverage_node = node_body ? node_body : node;
7194 add_trace_branch_coverage(
7195 iseq,
7196 ret,
7197 nd_code_loc(coverage_node),
7198 nd_node_id(coverage_node),
7199 0,
7200 type == NODE_IF ? "then" : "else",
7201 branches);
7202 end_label = NEW_LABEL(line);
7203 ADD_INSNL(then_seq, line_node, jump, end_label);
7204 if (!popped) {
7205 ADD_INSN(then_seq, line_node, pop);
7206 }
7207 }
7208 ADD_SEQ(ret, then_seq);
7209 }
7210
7211 if (else_label->refcnt) {
7212 ADD_LABEL(ret, else_label);
7213
7214 DECL_ANCHOR(else_seq);
7215 INIT_ANCHOR(else_seq);
7216 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7217
7218 if (then_label->refcnt) {
7219 const NODE *const coverage_node = node_else ? node_else : node;
7220 add_trace_branch_coverage(
7221 iseq,
7222 ret,
7223 nd_code_loc(coverage_node),
7224 nd_node_id(coverage_node),
7225 1,
7226 type == NODE_IF ? "else" : "then",
7227 branches);
7228 }
7229 ADD_SEQ(ret, else_seq);
7230 }
7231
7232 if (end_label) {
7233 ADD_LABEL(ret, end_label);
7234 }
7235
7236 return COMPILE_OK;
7237}
7238
7239static int
7240compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7241{
7242 const NODE *vals;
7243 const NODE *node = orig_node;
7244 LABEL *endlabel, *elselabel;
7245 DECL_ANCHOR(head);
7246 DECL_ANCHOR(body_seq);
7247 DECL_ANCHOR(cond_seq);
7248 int only_special_literals = 1;
7249 VALUE literals = cdhash_new(0);
7250 int line;
7251 enum node_type type;
7252 const NODE *line_node;
7253 VALUE branches = Qfalse;
7254 int branch_id = 0;
7255
7256 INIT_ANCHOR(head);
7257 INIT_ANCHOR(body_seq);
7258 INIT_ANCHOR(cond_seq);
7259
7260 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7261
7262 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
7263
7264 node = RNODE_CASE(node)->nd_body;
7265 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7266 type = nd_type(node);
7267 line = nd_line(node);
7268 line_node = node;
7269
7270 endlabel = NEW_LABEL(line);
7271 elselabel = NEW_LABEL(line);
7272
7273 ADD_SEQ(ret, head); /* case VAL */
7274
7275 while (type == NODE_WHEN) {
7276 LABEL *l1;
7277
7278 l1 = NEW_LABEL(line);
7279 ADD_LABEL(body_seq, l1);
7280 ADD_INSN(body_seq, line_node, pop);
7281
7282 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7283 add_trace_branch_coverage(
7284 iseq,
7285 body_seq,
7286 nd_code_loc(coverage_node),
7287 nd_node_id(coverage_node),
7288 branch_id++,
7289 "when",
7290 branches);
7291
7292 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7293 ADD_INSNL(body_seq, line_node, jump, endlabel);
7294
7295 vals = RNODE_WHEN(node)->nd_head;
7296 if (vals) {
7297 switch (nd_type(vals)) {
7298 case NODE_LIST:
7299 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7300 if (only_special_literals < 0) return COMPILE_NG;
7301 break;
7302 case NODE_SPLAT:
7303 case NODE_ARGSCAT:
7304 case NODE_ARGSPUSH:
7305 only_special_literals = 0;
7306 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7307 break;
7308 default:
7309 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7310 }
7311 }
7312 else {
7313 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7314 }
7315
7316 node = RNODE_WHEN(node)->nd_next;
7317 if (!node) {
7318 break;
7319 }
7320 type = nd_type(node);
7321 line = nd_line(node);
7322 line_node = node;
7323 }
7324 /* else */
7325 if (node) {
7326 ADD_LABEL(cond_seq, elselabel);
7327 ADD_INSN(cond_seq, line_node, pop);
7328 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7329 CHECK(COMPILE_(cond_seq, "else", node, popped));
7330 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7331 }
7332 else {
7333 debugs("== else (implicit)\n");
7334 ADD_LABEL(cond_seq, elselabel);
7335 ADD_INSN(cond_seq, orig_node, pop);
7336 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7337 if (!popped) {
7338 ADD_INSN(cond_seq, orig_node, putnil);
7339 }
7340 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7341 }
7342
7343 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7344 ADD_INSN(ret, orig_node, dup);
7345 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7346 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7347 LABEL_REF(elselabel);
7348 }
7349
7350 ADD_SEQ(ret, cond_seq);
7351 ADD_SEQ(ret, body_seq);
7352 ADD_LABEL(ret, endlabel);
7353 return COMPILE_OK;
7354}
7355
7356static int
7357compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7358{
7359 const NODE *vals;
7360 const NODE *val;
7361 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7362 LABEL *endlabel;
7363 DECL_ANCHOR(body_seq);
7364 VALUE branches = Qfalse;
7365 int branch_id = 0;
7366
7367 branches = decl_branch_base(iseq, nd_node_id(orig_node), nd_code_loc(orig_node), "case");
7368
7369 INIT_ANCHOR(body_seq);
7370 endlabel = NEW_LABEL(nd_line(node));
7371
7372 while (node && nd_type_p(node, NODE_WHEN)) {
7373 const int line = nd_line(node);
7374 LABEL *l1 = NEW_LABEL(line);
7375 ADD_LABEL(body_seq, l1);
7376
7377 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7378 add_trace_branch_coverage(
7379 iseq,
7380 body_seq,
7381 nd_code_loc(coverage_node),
7382 nd_node_id(coverage_node),
7383 branch_id++,
7384 "when",
7385 branches);
7386
7387 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7388 ADD_INSNL(body_seq, node, jump, endlabel);
7389
7390 vals = RNODE_WHEN(node)->nd_head;
7391 if (!vals) {
7392 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7393 }
7394 switch (nd_type(vals)) {
7395 case NODE_LIST:
7396 while (vals) {
7397 LABEL *lnext;
7398 val = RNODE_LIST(vals)->nd_head;
7399 lnext = NEW_LABEL(nd_line(val));
7400 debug_compile("== when2\n", (void)0);
7401 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7402 ADD_LABEL(ret, lnext);
7403 vals = RNODE_LIST(vals)->nd_next;
7404 }
7405 break;
7406 case NODE_SPLAT:
7407 case NODE_ARGSCAT:
7408 case NODE_ARGSPUSH:
7409 ADD_INSN(ret, vals, putnil);
7410 CHECK(COMPILE(ret, "when2/cond splat", vals));
7411 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7412 ADD_INSNL(ret, vals, branchif, l1);
7413 break;
7414 default:
7415 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7416 }
7417 node = RNODE_WHEN(node)->nd_next;
7418 }
7419 /* else */
7420 const NODE *const coverage_node = node ? node : orig_node;
7421 add_trace_branch_coverage(
7422 iseq,
7423 ret,
7424 nd_code_loc(coverage_node),
7425 nd_node_id(coverage_node),
7426 branch_id,
7427 "else",
7428 branches);
7429 CHECK(COMPILE_(ret, "else", node, popped));
7430 ADD_INSNL(ret, orig_node, jump, endlabel);
7431
7432 ADD_SEQ(ret, body_seq);
7433 ADD_LABEL(ret, endlabel);
7434 return COMPILE_OK;
7435}
7436
7437static 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);
7438
7439static 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);
7440static 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);
7441static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7442static 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);
7443static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7444
7445#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7446#define CASE3_BI_OFFSET_ERROR_STRING 1
7447#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7448#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7449#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7450
7451static int
7452iseq_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)
7453{
7454 const int line = nd_line(node);
7455 const NODE *line_node = node;
7456
7457 switch (nd_type(node)) {
7458 case NODE_ARYPTN: {
7459 /*
7460 * if pattern.use_rest_num?
7461 * rest_num = 0
7462 * end
7463 * if pattern.has_constant_node?
7464 * unless pattern.constant === obj
7465 * goto match_failed
7466 * end
7467 * end
7468 * unless obj.respond_to?(:deconstruct)
7469 * goto match_failed
7470 * end
7471 * d = obj.deconstruct
7472 * unless Array === d
7473 * goto type_error
7474 * end
7475 * min_argc = pattern.pre_args_num + pattern.post_args_num
7476 * if pattern.has_rest_arg?
7477 * unless d.length >= min_argc
7478 * goto match_failed
7479 * end
7480 * else
7481 * unless d.length == min_argc
7482 * goto match_failed
7483 * end
7484 * end
7485 * pattern.pre_args_num.each do |i|
7486 * unless pattern.pre_args[i].match?(d[i])
7487 * goto match_failed
7488 * end
7489 * end
7490 * if pattern.use_rest_num?
7491 * rest_num = d.length - min_argc
7492 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7493 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7494 * goto match_failed
7495 * end
7496 * end
7497 * end
7498 * pattern.post_args_num.each do |i|
7499 * j = pattern.pre_args_num + i
7500 * j += rest_num
7501 * unless pattern.post_args[i].match?(d[j])
7502 * goto match_failed
7503 * end
7504 * end
7505 * goto matched
7506 * type_error:
7507 * FrozenCore.raise TypeError
7508 * match_failed:
7509 * goto unmatched
7510 */
7511 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7512 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7513 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7514
7515 const int min_argc = pre_args_num + post_args_num;
7516 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7517 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7518
7519 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7520 int i;
7521 match_failed = NEW_LABEL(line);
7522 type_error = NEW_LABEL(line);
7523 deconstruct = NEW_LABEL(line);
7524 deconstructed = NEW_LABEL(line);
7525
7526 if (use_rest_num) {
7527 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7528 ADD_INSN(ret, line_node, swap);
7529 if (base_index) {
7530 base_index++;
7531 }
7532 }
7533
7534 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7535
7536 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7537
7538 ADD_INSN(ret, line_node, dup);
7539 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7540 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7541 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7542 if (in_single_pattern) {
7543 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7544 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7545 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7546 INT2FIX(min_argc), base_index + 1 /* (1) */));
7547 }
7548 ADD_INSNL(ret, line_node, branchunless, match_failed);
7549
7550 for (i = 0; i < pre_args_num; i++) {
7551 ADD_INSN(ret, line_node, dup);
7552 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7553 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7554 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));
7555 args = RNODE_LIST(args)->nd_next;
7556 }
7557
7558 if (RNODE_ARYPTN(node)->rest_arg) {
7559 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7560 ADD_INSN(ret, line_node, dup);
7561 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7562 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7563 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7564 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7565 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7566 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7567 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7568
7569 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));
7570 }
7571 else {
7572 if (post_args_num > 0) {
7573 ADD_INSN(ret, line_node, dup);
7574 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7575 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7576 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7577 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7578 ADD_INSN(ret, line_node, pop);
7579 }
7580 }
7581 }
7582
7583 args = RNODE_ARYPTN(node)->post_args;
7584 for (i = 0; i < post_args_num; i++) {
7585 ADD_INSN(ret, line_node, dup);
7586
7587 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7588 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7589 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7590
7591 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7592 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));
7593 args = RNODE_LIST(args)->nd_next;
7594 }
7595
7596 ADD_INSN(ret, line_node, pop);
7597 if (use_rest_num) {
7598 ADD_INSN(ret, line_node, pop);
7599 }
7600 ADD_INSNL(ret, line_node, jump, matched);
7601 ADD_INSN(ret, line_node, putnil);
7602 if (use_rest_num) {
7603 ADD_INSN(ret, line_node, putnil);
7604 }
7605
7606 ADD_LABEL(ret, type_error);
7607 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7608 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7609 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7610 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7611 ADD_INSN(ret, line_node, pop);
7612
7613 ADD_LABEL(ret, match_failed);
7614 ADD_INSN(ret, line_node, pop);
7615 if (use_rest_num) {
7616 ADD_INSN(ret, line_node, pop);
7617 }
7618 ADD_INSNL(ret, line_node, jump, unmatched);
7619
7620 break;
7621 }
7622 case NODE_FNDPTN: {
7623 /*
7624 * if pattern.has_constant_node?
7625 * unless pattern.constant === obj
7626 * goto match_failed
7627 * end
7628 * end
7629 * unless obj.respond_to?(:deconstruct)
7630 * goto match_failed
7631 * end
7632 * d = obj.deconstruct
7633 * unless Array === d
7634 * goto type_error
7635 * end
7636 * unless d.length >= pattern.args_num
7637 * goto match_failed
7638 * end
7639 *
7640 * begin
7641 * len = d.length
7642 * limit = d.length - pattern.args_num
7643 * i = 0
7644 * while i <= limit
7645 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7646 * if pattern.has_pre_rest_arg_id
7647 * unless pattern.pre_rest_arg.match?(d[0, i])
7648 * goto find_failed
7649 * end
7650 * end
7651 * if pattern.has_post_rest_arg_id
7652 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7653 * goto find_failed
7654 * end
7655 * end
7656 * goto find_succeeded
7657 * end
7658 * i+=1
7659 * end
7660 * find_failed:
7661 * goto match_failed
7662 * find_succeeded:
7663 * end
7664 *
7665 * goto matched
7666 * type_error:
7667 * FrozenCore.raise TypeError
7668 * match_failed:
7669 * goto unmatched
7670 */
7671 const NODE *args = RNODE_FNDPTN(node)->args;
7672 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7673
7674 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7675 match_failed = NEW_LABEL(line);
7676 type_error = NEW_LABEL(line);
7677 deconstruct = NEW_LABEL(line);
7678 deconstructed = NEW_LABEL(line);
7679
7680 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7681
7682 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7683
7684 ADD_INSN(ret, line_node, dup);
7685 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7686 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7687 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7688 if (in_single_pattern) {
7689 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) */));
7690 }
7691 ADD_INSNL(ret, line_node, branchunless, match_failed);
7692
7693 {
7694 LABEL *while_begin = NEW_LABEL(nd_line(node));
7695 LABEL *next_loop = NEW_LABEL(nd_line(node));
7696 LABEL *find_succeeded = NEW_LABEL(line);
7697 LABEL *find_failed = NEW_LABEL(nd_line(node));
7698 int j;
7699
7700 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7701 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7702
7703 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7704 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7705 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7706
7707 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7708
7709 ADD_LABEL(ret, while_begin);
7710
7711 ADD_INSN(ret, line_node, dup);
7712 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7713 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7714 ADD_INSNL(ret, line_node, branchunless, find_failed);
7715
7716 for (j = 0; j < args_num; j++) {
7717 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7718 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7719 if (j != 0) {
7720 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7721 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7722 }
7723 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7724
7725 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));
7726 args = RNODE_LIST(args)->nd_next;
7727 }
7728
7729 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7730 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7731 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7732 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7733 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7734 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));
7735 }
7736 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7737 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7738 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7739 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7740 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7741 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7742 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7743 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));
7744 }
7745 ADD_INSNL(ret, line_node, jump, find_succeeded);
7746
7747 ADD_LABEL(ret, next_loop);
7748 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7749 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7750 ADD_INSNL(ret, line_node, jump, while_begin);
7751
7752 ADD_LABEL(ret, find_failed);
7753 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7754 if (in_single_pattern) {
7755 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7756 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7757 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7758 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7759 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7760
7761 ADD_INSN1(ret, line_node, putobject, Qfalse);
7762 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7763
7764 ADD_INSN(ret, line_node, pop);
7765 ADD_INSN(ret, line_node, pop);
7766 }
7767 ADD_INSNL(ret, line_node, jump, match_failed);
7768 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7769
7770 ADD_LABEL(ret, find_succeeded);
7771 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7772 }
7773
7774 ADD_INSN(ret, line_node, pop);
7775 ADD_INSNL(ret, line_node, jump, matched);
7776 ADD_INSN(ret, line_node, putnil);
7777
7778 ADD_LABEL(ret, type_error);
7779 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7780 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7781 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7782 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7783 ADD_INSN(ret, line_node, pop);
7784
7785 ADD_LABEL(ret, match_failed);
7786 ADD_INSN(ret, line_node, pop);
7787 ADD_INSNL(ret, line_node, jump, unmatched);
7788
7789 break;
7790 }
7791 case NODE_HSHPTN: {
7792 /*
7793 * keys = nil
7794 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7795 * keys = pattern.kw_args_node.keys
7796 * end
7797 * if pattern.has_constant_node?
7798 * unless pattern.constant === obj
7799 * goto match_failed
7800 * end
7801 * end
7802 * unless obj.respond_to?(:deconstruct_keys)
7803 * goto match_failed
7804 * end
7805 * d = obj.deconstruct_keys(keys)
7806 * unless Hash === d
7807 * goto type_error
7808 * end
7809 * if pattern.has_kw_rest_arg_node?
7810 * d = d.dup
7811 * end
7812 * if pattern.has_kw_args_node?
7813 * pattern.kw_args_node.each |k,|
7814 * unless d.key?(k)
7815 * goto match_failed
7816 * end
7817 * end
7818 * pattern.kw_args_node.each |k, pat|
7819 * if pattern.has_kw_rest_arg_node?
7820 * unless pat.match?(d.delete(k))
7821 * goto match_failed
7822 * end
7823 * else
7824 * unless pat.match?(d[k])
7825 * goto match_failed
7826 * end
7827 * end
7828 * end
7829 * else
7830 * unless d.empty?
7831 * goto match_failed
7832 * end
7833 * end
7834 * if pattern.has_kw_rest_arg_node?
7835 * if pattern.no_rest_keyword?
7836 * unless d.empty?
7837 * goto match_failed
7838 * end
7839 * else
7840 * unless pattern.kw_rest_arg_node.match?(d)
7841 * goto match_failed
7842 * end
7843 * end
7844 * end
7845 * goto matched
7846 * type_error:
7847 * FrozenCore.raise TypeError
7848 * match_failed:
7849 * goto unmatched
7850 */
7851 LABEL *match_failed, *type_error;
7852 VALUE keys = Qnil;
7853
7854 match_failed = NEW_LABEL(line);
7855 type_error = NEW_LABEL(line);
7856
7857 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7858 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7859 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7860 while (kw_args) {
7861 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7862 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7863 }
7864 }
7865
7866 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7867
7868 ADD_INSN(ret, line_node, dup);
7869 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7870 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7871 if (in_single_pattern) {
7872 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7873 }
7874 ADD_INSNL(ret, line_node, branchunless, match_failed);
7875
7876 if (NIL_P(keys)) {
7877 ADD_INSN(ret, line_node, putnil);
7878 }
7879 else {
7881 ADD_INSN1(ret, line_node, duparray, keys);
7882 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7883 }
7884 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7885
7886 ADD_INSN(ret, line_node, dup);
7887 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7888 ADD_INSNL(ret, line_node, branchunless, type_error);
7889
7890 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7891 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7892 }
7893
7894 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7895 int i;
7896 int keys_num;
7897 const NODE *args;
7898 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7899 if (args) {
7900 DECL_ANCHOR(match_values);
7901 INIT_ANCHOR(match_values);
7902 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7903 for (i = 0; i < keys_num; i++) {
7904 NODE *key_node = RNODE_LIST(args)->nd_head;
7905 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7906 VALUE key = get_symbol_value(iseq, key_node);
7907
7908 ADD_INSN(ret, line_node, dup);
7909 ADD_INSN1(ret, line_node, putobject, key);
7910 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7911 if (in_single_pattern) {
7912 LABEL *match_succeeded;
7913 match_succeeded = NEW_LABEL(line);
7914
7915 ADD_INSN(ret, line_node, dup);
7916 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7917
7918 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7919 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7920 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7921 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7922 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7923 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7924 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7925 ADD_INSN1(ret, line_node, putobject, key); // (7)
7926 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7927
7928 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7929
7930 ADD_LABEL(ret, match_succeeded);
7931 }
7932 ADD_INSNL(ret, line_node, branchunless, match_failed);
7933
7934 ADD_INSN(match_values, line_node, dup);
7935 ADD_INSN1(match_values, line_node, putobject, key);
7936 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7937 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7938 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7939 }
7940 ADD_SEQ(ret, match_values);
7941 }
7942 }
7943 else {
7944 ADD_INSN(ret, line_node, dup);
7945 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7946 if (in_single_pattern) {
7947 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7948 }
7949 ADD_INSNL(ret, line_node, branchunless, match_failed);
7950 }
7951
7952 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7953 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7954 ADD_INSN(ret, line_node, dup);
7955 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7956 if (in_single_pattern) {
7957 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7958 }
7959 ADD_INSNL(ret, line_node, branchunless, match_failed);
7960 }
7961 else {
7962 ADD_INSN(ret, line_node, dup); // (11)
7963 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));
7964 }
7965 }
7966
7967 ADD_INSN(ret, line_node, pop);
7968 ADD_INSNL(ret, line_node, jump, matched);
7969 ADD_INSN(ret, line_node, putnil);
7970
7971 ADD_LABEL(ret, type_error);
7972 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7973 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7974 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7975 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7976 ADD_INSN(ret, line_node, pop);
7977
7978 ADD_LABEL(ret, match_failed);
7979 ADD_INSN(ret, line_node, pop);
7980 ADD_INSNL(ret, line_node, jump, unmatched);
7981 break;
7982 }
7983 case NODE_SYM:
7984 case NODE_REGX:
7985 case NODE_LINE:
7986 case NODE_INTEGER:
7987 case NODE_FLOAT:
7988 case NODE_RATIONAL:
7989 case NODE_IMAGINARY:
7990 case NODE_FILE:
7991 case NODE_ENCODING:
7992 case NODE_STR:
7993 case NODE_XSTR:
7994 case NODE_DSTR:
7995 case NODE_DSYM:
7996 case NODE_DREGX:
7997 case NODE_LIST:
7998 case NODE_ZLIST:
7999 case NODE_LAMBDA:
8000 case NODE_DOT2:
8001 case NODE_DOT3:
8002 case NODE_CONST:
8003 case NODE_LVAR:
8004 case NODE_DVAR:
8005 case NODE_IVAR:
8006 case NODE_CVAR:
8007 case NODE_GVAR:
8008 case NODE_TRUE:
8009 case NODE_FALSE:
8010 case NODE_SELF:
8011 case NODE_NIL:
8012 case NODE_COLON2:
8013 case NODE_COLON3:
8014 case NODE_BEGIN:
8015 case NODE_BLOCK:
8016 case NODE_ONCE:
8017 CHECK(COMPILE(ret, "case in literal", node)); // (1)
8018 if (in_single_pattern) {
8019 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8020 }
8021 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
8022 if (in_single_pattern) {
8023 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
8024 }
8025 ADD_INSNL(ret, line_node, branchif, matched);
8026 ADD_INSNL(ret, line_node, jump, unmatched);
8027 break;
8028 case NODE_LASGN: {
8029 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8030 ID id = RNODE_LASGN(node)->nd_vid;
8031 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8032
8033 if (in_alt_pattern) {
8034 const char *name = rb_id2name(id);
8035 if (name && strlen(name) > 0 && name[0] != '_') {
8036 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8037 rb_id2str(id));
8038 return COMPILE_NG;
8039 }
8040 }
8041
8042 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8043 ADD_INSNL(ret, line_node, jump, matched);
8044 break;
8045 }
8046 case NODE_DASGN: {
8047 int idx, lv, ls;
8048 ID id = RNODE_DASGN(node)->nd_vid;
8049
8050 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
8051
8052 if (in_alt_pattern) {
8053 const char *name = rb_id2name(id);
8054 if (name && strlen(name) > 0 && name[0] != '_') {
8055 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8056 rb_id2str(id));
8057 return COMPILE_NG;
8058 }
8059 }
8060
8061 if (idx < 0) {
8062 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
8063 rb_id2str(id));
8064 return COMPILE_NG;
8065 }
8066 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
8067 ADD_INSNL(ret, line_node, jump, matched);
8068 break;
8069 }
8070 case NODE_IF:
8071 case NODE_UNLESS: {
8072 LABEL *match_failed;
8073 match_failed = unmatched;
8074 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8075 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
8076 if (in_single_pattern) {
8077 LABEL *match_succeeded;
8078 match_succeeded = NEW_LABEL(line);
8079
8080 ADD_INSN(ret, line_node, dup);
8081 if (nd_type_p(node, NODE_IF)) {
8082 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8083 }
8084 else {
8085 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
8086 }
8087
8088 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
8089 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8090 ADD_INSN1(ret, line_node, putobject, Qfalse);
8091 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8092
8093 ADD_INSN(ret, line_node, pop);
8094 ADD_INSN(ret, line_node, pop);
8095
8096 ADD_LABEL(ret, match_succeeded);
8097 }
8098 if (nd_type_p(node, NODE_IF)) {
8099 ADD_INSNL(ret, line_node, branchunless, match_failed);
8100 }
8101 else {
8102 ADD_INSNL(ret, line_node, branchif, match_failed);
8103 }
8104 ADD_INSNL(ret, line_node, jump, matched);
8105 break;
8106 }
8107 case NODE_HASH: {
8108 NODE *n;
8109 LABEL *match_failed;
8110 match_failed = NEW_LABEL(line);
8111
8112 n = RNODE_HASH(node)->nd_head;
8113 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
8114 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8115 return COMPILE_NG;
8116 }
8117
8118 ADD_INSN(ret, line_node, dup); // (1)
8119 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));
8120 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));
8121 ADD_INSN(ret, line_node, putnil);
8122
8123 ADD_LABEL(ret, match_failed);
8124 ADD_INSN(ret, line_node, pop);
8125 ADD_INSNL(ret, line_node, jump, unmatched);
8126 break;
8127 }
8128 case NODE_OR: {
8129 LABEL *match_succeeded, *fin;
8130 match_succeeded = NEW_LABEL(line);
8131 fin = NEW_LABEL(line);
8132
8133 ADD_INSN(ret, line_node, dup); // (1)
8134 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));
8135 ADD_LABEL(ret, match_succeeded);
8136 ADD_INSN(ret, line_node, pop);
8137 ADD_INSNL(ret, line_node, jump, matched);
8138 ADD_INSN(ret, line_node, putnil);
8139 ADD_LABEL(ret, fin);
8140 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
8141 break;
8142 }
8143 default:
8144 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
8145 }
8146 return COMPILE_OK;
8147}
8148
8149static int
8150iseq_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)
8151{
8152 LABEL *fin = NEW_LABEL(nd_line(node));
8153 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8154 ADD_LABEL(ret, fin);
8155 return COMPILE_OK;
8156}
8157
8158static int
8159iseq_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)
8160{
8161 const NODE *line_node = node;
8162
8163 if (RNODE_ARYPTN(node)->nd_pconst) {
8164 ADD_INSN(ret, line_node, dup); // (1)
8165 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8166 if (in_single_pattern) {
8167 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8168 }
8169 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8170 if (in_single_pattern) {
8171 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8172 }
8173 ADD_INSNL(ret, line_node, branchunless, match_failed);
8174 }
8175 return COMPILE_OK;
8176}
8177
8178
8179static int
8180iseq_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)
8181{
8182 const NODE *line_node = node;
8183
8184 // NOTE: this optimization allows us to re-use the #deconstruct value
8185 // (or its absence).
8186 if (use_deconstructed_cache) {
8187 // If value is nil then we haven't tried to deconstruct
8188 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8189 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8190
8191 // If false then the value is not deconstructable
8192 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8193 ADD_INSNL(ret, line_node, branchunless, match_failed);
8194
8195 // Drop value, add deconstructed to the stack and jump
8196 ADD_INSN(ret, line_node, pop); // (1)
8197 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8198 ADD_INSNL(ret, line_node, jump, deconstructed);
8199 }
8200 else {
8201 ADD_INSNL(ret, line_node, jump, deconstruct);
8202 }
8203
8204 ADD_LABEL(ret, deconstruct);
8205 ADD_INSN(ret, line_node, dup);
8206 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8207 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8208
8209 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8210 if (use_deconstructed_cache) {
8211 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8212 }
8213
8214 if (in_single_pattern) {
8215 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8216 }
8217
8218 ADD_INSNL(ret, line_node, branchunless, match_failed);
8219
8220 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8221
8222 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8223 if (use_deconstructed_cache) {
8224 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8225 }
8226
8227 ADD_INSN(ret, line_node, dup);
8228 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8229 ADD_INSNL(ret, line_node, branchunless, type_error);
8230
8231 ADD_LABEL(ret, deconstructed);
8232
8233 return COMPILE_OK;
8234}
8235
8236static int
8237iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8238{
8239 /*
8240 * if match_succeeded?
8241 * goto match_succeeded
8242 * end
8243 * error_string = FrozenCore.sprintf(errmsg, matchee)
8244 * key_error_p = false
8245 * match_succeeded:
8246 */
8247 const int line = nd_line(node);
8248 const NODE *line_node = node;
8249 LABEL *match_succeeded = NEW_LABEL(line);
8250
8251 ADD_INSN(ret, line_node, dup);
8252 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8253
8254 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8255 ADD_INSN1(ret, line_node, putobject, errmsg);
8256 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8257 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8258 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8259
8260 ADD_INSN1(ret, line_node, putobject, Qfalse);
8261 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8262
8263 ADD_INSN(ret, line_node, pop);
8264 ADD_INSN(ret, line_node, pop);
8265 ADD_LABEL(ret, match_succeeded);
8266
8267 return COMPILE_OK;
8268}
8269
8270static int
8271iseq_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)
8272{
8273 /*
8274 * if match_succeeded?
8275 * goto match_succeeded
8276 * end
8277 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8278 * key_error_p = false
8279 * match_succeeded:
8280 */
8281 const int line = nd_line(node);
8282 const NODE *line_node = node;
8283 LABEL *match_succeeded = NEW_LABEL(line);
8284
8285 ADD_INSN(ret, line_node, dup);
8286 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8287
8288 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8289 ADD_INSN1(ret, line_node, putobject, errmsg);
8290 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8291 ADD_INSN(ret, line_node, dup);
8292 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8293 ADD_INSN1(ret, line_node, putobject, pattern_length);
8294 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8295 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8296
8297 ADD_INSN1(ret, line_node, putobject, Qfalse);
8298 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8299
8300 ADD_INSN(ret, line_node, pop);
8301 ADD_INSN(ret, line_node, pop);
8302 ADD_LABEL(ret, match_succeeded);
8303
8304 return COMPILE_OK;
8305}
8306
8307static int
8308iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8309{
8310 /*
8311 * if match_succeeded?
8312 * goto match_succeeded
8313 * end
8314 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8315 * key_error_p = false
8316 * match_succeeded:
8317 */
8318 const int line = nd_line(node);
8319 const NODE *line_node = node;
8320 LABEL *match_succeeded = NEW_LABEL(line);
8321
8322 ADD_INSN(ret, line_node, dup);
8323 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8324
8325 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8326 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8327 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8328 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8329 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8330 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8331
8332 ADD_INSN1(ret, line_node, putobject, Qfalse);
8333 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8334
8335 ADD_INSN(ret, line_node, pop);
8336 ADD_INSN(ret, line_node, pop);
8337
8338 ADD_LABEL(ret, match_succeeded);
8339 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8340 ADD_INSN(ret, line_node, pop);
8341 ADD_INSN(ret, line_node, pop);
8342
8343 return COMPILE_OK;
8344}
8345
8346static int
8347compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8348{
8349 const NODE *pattern;
8350 const NODE *node = orig_node;
8351 LABEL *endlabel, *elselabel;
8352 DECL_ANCHOR(head);
8353 DECL_ANCHOR(body_seq);
8354 DECL_ANCHOR(cond_seq);
8355 int line;
8356 enum node_type type;
8357 const NODE *line_node;
8358 VALUE branches = 0;
8359 int branch_id = 0;
8360 bool single_pattern;
8361
8362 INIT_ANCHOR(head);
8363 INIT_ANCHOR(body_seq);
8364 INIT_ANCHOR(cond_seq);
8365
8366 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
8367
8368 node = RNODE_CASE3(node)->nd_body;
8369 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8370 type = nd_type(node);
8371 line = nd_line(node);
8372 line_node = node;
8373 single_pattern = !RNODE_IN(node)->nd_next;
8374
8375 endlabel = NEW_LABEL(line);
8376 elselabel = NEW_LABEL(line);
8377
8378 if (single_pattern) {
8379 /* allocate stack for ... */
8380 ADD_INSN(head, line_node, putnil); /* key_error_key */
8381 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8382 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8383 ADD_INSN(head, line_node, putnil); /* error_string */
8384 }
8385 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8386
8387 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8388
8389 ADD_SEQ(ret, head); /* case VAL */
8390
8391 while (type == NODE_IN) {
8392 LABEL *l1;
8393
8394 if (branch_id) {
8395 ADD_INSN(body_seq, line_node, putnil);
8396 }
8397 l1 = NEW_LABEL(line);
8398 ADD_LABEL(body_seq, l1);
8399 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8400
8401 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8402 add_trace_branch_coverage(
8403 iseq,
8404 body_seq,
8405 nd_code_loc(coverage_node),
8406 nd_node_id(coverage_node),
8407 branch_id++,
8408 "in",
8409 branches);
8410
8411 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8412 ADD_INSNL(body_seq, line_node, jump, endlabel);
8413
8414 pattern = RNODE_IN(node)->nd_head;
8415 if (pattern) {
8416 int pat_line = nd_line(pattern);
8417 LABEL *next_pat = NEW_LABEL(pat_line);
8418 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8419 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8420 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8421 ADD_LABEL(cond_seq, next_pat);
8422 LABEL_UNREMOVABLE(next_pat);
8423 }
8424 else {
8425 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8426 return COMPILE_NG;
8427 }
8428
8429 node = RNODE_IN(node)->nd_next;
8430 if (!node) {
8431 break;
8432 }
8433 type = nd_type(node);
8434 line = nd_line(node);
8435 line_node = node;
8436 }
8437 /* else */
8438 if (node) {
8439 ADD_LABEL(cond_seq, elselabel);
8440 ADD_INSN(cond_seq, line_node, pop);
8441 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8442 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8443 CHECK(COMPILE_(cond_seq, "else", node, popped));
8444 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8445 ADD_INSN(cond_seq, line_node, putnil);
8446 if (popped) {
8447 ADD_INSN(cond_seq, line_node, putnil);
8448 }
8449 }
8450 else {
8451 debugs("== else (implicit)\n");
8452 ADD_LABEL(cond_seq, elselabel);
8453 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8454 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8455
8456 if (single_pattern) {
8457 /*
8458 * if key_error_p
8459 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8460 * else
8461 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8462 * end
8463 */
8464 LABEL *key_error, *fin;
8465 struct rb_callinfo_kwarg *kw_arg;
8466
8467 key_error = NEW_LABEL(line);
8468 fin = NEW_LABEL(line);
8469
8470 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8471 kw_arg->references = 0;
8472 kw_arg->keyword_len = 2;
8473 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8474 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8475
8476 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8477 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8478 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8479 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8480 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8481 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8482 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8483 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8484 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8485 ADD_INSNL(cond_seq, orig_node, jump, fin);
8486
8487 ADD_LABEL(cond_seq, key_error);
8488 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8489 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8490 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8491 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8492 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8493 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8494 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8495 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8496 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8497 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8498
8499 ADD_LABEL(cond_seq, fin);
8500 }
8501 else {
8502 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8503 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8504 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8505 }
8506 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8507 if (!popped) {
8508 ADD_INSN(cond_seq, orig_node, putnil);
8509 }
8510 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8511 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8512 if (popped) {
8513 ADD_INSN(cond_seq, line_node, putnil);
8514 }
8515 }
8516
8517 ADD_SEQ(ret, cond_seq);
8518 ADD_SEQ(ret, body_seq);
8519 ADD_LABEL(ret, endlabel);
8520 return COMPILE_OK;
8521}
8522
8523#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8524#undef CASE3_BI_OFFSET_ERROR_STRING
8525#undef CASE3_BI_OFFSET_KEY_ERROR_P
8526#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8527#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8528
8529static int
8530compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8531{
8532 const int line = (int)nd_line(node);
8533 const NODE *line_node = node;
8534
8535 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8536 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8537 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8538 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8539 VALUE branches = Qfalse;
8540
8542
8543 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8544 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8545 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8546 LABEL *end_label = NEW_LABEL(line);
8547 LABEL *adjust_label = NEW_LABEL(line);
8548
8549 LABEL *next_catch_label = NEW_LABEL(line);
8550 LABEL *tmp_label = NULL;
8551
8552 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8553 push_ensure_entry(iseq, &enl, NULL, NULL);
8554
8555 if (RNODE_WHILE(node)->nd_state == 1) {
8556 ADD_INSNL(ret, line_node, jump, next_label);
8557 }
8558 else {
8559 tmp_label = NEW_LABEL(line);
8560 ADD_INSNL(ret, line_node, jump, tmp_label);
8561 }
8562 ADD_LABEL(ret, adjust_label);
8563 ADD_INSN(ret, line_node, putnil);
8564 ADD_LABEL(ret, next_catch_label);
8565 ADD_INSN(ret, line_node, pop);
8566 ADD_INSNL(ret, line_node, jump, next_label);
8567 if (tmp_label) ADD_LABEL(ret, tmp_label);
8568
8569 ADD_LABEL(ret, redo_label);
8570 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8571
8572 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8573 add_trace_branch_coverage(
8574 iseq,
8575 ret,
8576 nd_code_loc(coverage_node),
8577 nd_node_id(coverage_node),
8578 0,
8579 "body",
8580 branches);
8581
8582 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8583 ADD_LABEL(ret, next_label); /* next */
8584
8585 if (type == NODE_WHILE) {
8586 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8587 redo_label, end_label));
8588 }
8589 else {
8590 /* until */
8591 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8592 end_label, redo_label));
8593 }
8594
8595 ADD_LABEL(ret, end_label);
8596 ADD_ADJUST_RESTORE(ret, adjust_label);
8597
8598 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8599 /* ADD_INSN(ret, line_node, putundef); */
8600 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8601 return COMPILE_NG;
8602 }
8603 else {
8604 ADD_INSN(ret, line_node, putnil);
8605 }
8606
8607 ADD_LABEL(ret, break_label); /* break */
8608
8609 if (popped) {
8610 ADD_INSN(ret, line_node, pop);
8611 }
8612
8613 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8614 break_label);
8615 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8616 next_catch_label);
8617 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8618 ISEQ_COMPILE_DATA(iseq)->redo_label);
8619
8620 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8621 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8622 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8623 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8624 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8625 return COMPILE_OK;
8626}
8627
8628static int
8629compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8630{
8631 const int line = nd_line(node);
8632 const NODE *line_node = node;
8633 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8634 LABEL *retry_label = NEW_LABEL(line);
8635 LABEL *retry_end_l = NEW_LABEL(line);
8636 const rb_iseq_t *child_iseq;
8637
8638 ADD_LABEL(ret, retry_label);
8639 if (nd_type_p(node, NODE_FOR)) {
8640 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8641
8642 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8643 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8644 ISEQ_TYPE_BLOCK, line);
8645 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8646 }
8647 else {
8648 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8649 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8650 ISEQ_TYPE_BLOCK, line);
8651 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8652 }
8653
8654 {
8655 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8656 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8657 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8658 //
8659 // Normally, "send" instruction is at the last.
8660 // However, qcall under branch coverage measurement adds some instructions after the "send".
8661 //
8662 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8663 INSN *iobj;
8664 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8665 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8666 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8667 iobj = (INSN*) get_prev_insn(iobj);
8668 }
8669 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8670
8671 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8672 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8673 if (&iobj->link == LAST_ELEMENT(ret)) {
8674 ret->last = (LINK_ELEMENT*) retry_end_l;
8675 }
8676 }
8677
8678 if (popped) {
8679 ADD_INSN(ret, line_node, pop);
8680 }
8681
8682 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8683
8684 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8685 return COMPILE_OK;
8686}
8687
8688static int
8689compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8690{
8691 /* massign to var in "for"
8692 * (args.length == 1 && Array.try_convert(args[0])) || args
8693 */
8694 const NODE *line_node = node;
8695 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8696 LABEL *not_single = NEW_LABEL(nd_line(var));
8697 LABEL *not_ary = NEW_LABEL(nd_line(var));
8698 CHECK(COMPILE(ret, "for var", var));
8699 ADD_INSN(ret, line_node, dup);
8700 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8701 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8702 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8703 ADD_INSNL(ret, line_node, branchunless, not_single);
8704 ADD_INSN(ret, line_node, dup);
8705 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8706 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8707 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8708 ADD_INSN(ret, line_node, swap);
8709 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8710 ADD_INSN(ret, line_node, dup);
8711 ADD_INSNL(ret, line_node, branchunless, not_ary);
8712 ADD_INSN(ret, line_node, swap);
8713 ADD_LABEL(ret, not_ary);
8714 ADD_INSN(ret, line_node, pop);
8715 ADD_LABEL(ret, not_single);
8716 return COMPILE_OK;
8717}
8718
8719static int
8720compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8721{
8722 const NODE *line_node = node;
8723 unsigned long throw_flag = 0;
8724
8725 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8726 /* while/until */
8727 LABEL *splabel = NEW_LABEL(0);
8728 ADD_LABEL(ret, splabel);
8729 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8730 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8731 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8732 add_ensure_iseq(ret, iseq, 0);
8733 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8734 ADD_ADJUST_RESTORE(ret, splabel);
8735
8736 if (!popped) {
8737 ADD_INSN(ret, line_node, putnil);
8738 }
8739 }
8740 else {
8741 const rb_iseq_t *ip = iseq;
8742
8743 while (ip) {
8744 if (!ISEQ_COMPILE_DATA(ip)) {
8745 ip = 0;
8746 break;
8747 }
8748
8749 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8750 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8751 }
8752 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8753 throw_flag = 0;
8754 }
8755 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8756 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8757 return COMPILE_NG;
8758 }
8759 else {
8760 ip = ISEQ_BODY(ip)->parent_iseq;
8761 continue;
8762 }
8763
8764 /* escape from block */
8765 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8766 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8767 if (popped) {
8768 ADD_INSN(ret, line_node, pop);
8769 }
8770 return COMPILE_OK;
8771 }
8772 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8773 return COMPILE_NG;
8774 }
8775 return COMPILE_OK;
8776}
8777
8778static int
8779compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8780{
8781 const NODE *line_node = node;
8782 unsigned long throw_flag = 0;
8783
8784 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8785 LABEL *splabel = NEW_LABEL(0);
8786 debugs("next in while loop\n");
8787 ADD_LABEL(ret, splabel);
8788 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8789 add_ensure_iseq(ret, iseq, 0);
8790 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8791 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8792 ADD_ADJUST_RESTORE(ret, splabel);
8793 if (!popped) {
8794 ADD_INSN(ret, line_node, putnil);
8795 }
8796 }
8797 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8798 LABEL *splabel = NEW_LABEL(0);
8799 debugs("next in block\n");
8800 ADD_LABEL(ret, splabel);
8801 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8802 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8803 add_ensure_iseq(ret, iseq, 0);
8804 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8805 ADD_ADJUST_RESTORE(ret, splabel);
8806
8807 if (!popped) {
8808 ADD_INSN(ret, line_node, putnil);
8809 }
8810 }
8811 else {
8812 const rb_iseq_t *ip = iseq;
8813
8814 while (ip) {
8815 if (!ISEQ_COMPILE_DATA(ip)) {
8816 ip = 0;
8817 break;
8818 }
8819
8820 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8821 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8822 /* while loop */
8823 break;
8824 }
8825 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8826 break;
8827 }
8828 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8829 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8830 return COMPILE_NG;
8831 }
8832
8833 ip = ISEQ_BODY(ip)->parent_iseq;
8834 }
8835 if (ip != 0) {
8836 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8837 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8838
8839 if (popped) {
8840 ADD_INSN(ret, line_node, pop);
8841 }
8842 }
8843 else {
8844 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8845 return COMPILE_NG;
8846 }
8847 }
8848 return COMPILE_OK;
8849}
8850
8851static int
8852compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8853{
8854 const NODE *line_node = node;
8855
8856 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8857 LABEL *splabel = NEW_LABEL(0);
8858 debugs("redo in while");
8859 ADD_LABEL(ret, splabel);
8860 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8861 add_ensure_iseq(ret, iseq, 0);
8862 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8863 ADD_ADJUST_RESTORE(ret, splabel);
8864 if (!popped) {
8865 ADD_INSN(ret, line_node, putnil);
8866 }
8867 }
8868 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8869 LABEL *splabel = NEW_LABEL(0);
8870
8871 debugs("redo in block");
8872 ADD_LABEL(ret, splabel);
8873 add_ensure_iseq(ret, iseq, 0);
8874 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8875 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8876 ADD_ADJUST_RESTORE(ret, splabel);
8877
8878 if (!popped) {
8879 ADD_INSN(ret, line_node, putnil);
8880 }
8881 }
8882 else {
8883 const rb_iseq_t *ip = iseq;
8884
8885 while (ip) {
8886 if (!ISEQ_COMPILE_DATA(ip)) {
8887 ip = 0;
8888 break;
8889 }
8890
8891 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8892 break;
8893 }
8894 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8895 break;
8896 }
8897 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8898 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8899 return COMPILE_NG;
8900 }
8901
8902 ip = ISEQ_BODY(ip)->parent_iseq;
8903 }
8904 if (ip != 0) {
8905 ADD_INSN(ret, line_node, putnil);
8906 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8907
8908 if (popped) {
8909 ADD_INSN(ret, line_node, pop);
8910 }
8911 }
8912 else {
8913 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8914 return COMPILE_NG;
8915 }
8916 }
8917 return COMPILE_OK;
8918}
8919
8920static int
8921compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8922{
8923 const NODE *line_node = node;
8924
8925 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8926 ADD_INSN(ret, line_node, putnil);
8927 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8928
8929 if (popped) {
8930 ADD_INSN(ret, line_node, pop);
8931 }
8932 }
8933 else {
8934 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8935 return COMPILE_NG;
8936 }
8937 return COMPILE_OK;
8938}
8939
8940static int
8941compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8942{
8943 const int line = nd_line(node);
8944 const NODE *line_node = node;
8945 LABEL *lstart = NEW_LABEL(line);
8946 LABEL *lend = NEW_LABEL(line);
8947 LABEL *lcont = NEW_LABEL(line);
8948 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8949 rb_str_concat(rb_str_new2("rescue in "),
8950 ISEQ_BODY(iseq)->location.label),
8951 ISEQ_TYPE_RESCUE, line);
8952
8953 lstart->rescued = LABEL_RESCUE_BEG;
8954 lend->rescued = LABEL_RESCUE_END;
8955 ADD_LABEL(ret, lstart);
8956
8957 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8958 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8959 {
8960 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8961 }
8962 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8963
8964 ADD_LABEL(ret, lend);
8965 if (RNODE_RESCUE(node)->nd_else) {
8966 ADD_INSN(ret, line_node, pop);
8967 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8968 }
8969 ADD_INSN(ret, line_node, nop);
8970 ADD_LABEL(ret, lcont);
8971
8972 if (popped) {
8973 ADD_INSN(ret, line_node, pop);
8974 }
8975
8976 /* register catch entry */
8977 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8978 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8979 return COMPILE_OK;
8980}
8981
8982static int
8983compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8984{
8985 const int line = nd_line(node);
8986 const NODE *line_node = node;
8987 const NODE *resq = node;
8988 const NODE *narg;
8989 LABEL *label_miss, *label_hit;
8990
8991 while (resq) {
8992 label_miss = NEW_LABEL(line);
8993 label_hit = NEW_LABEL(line);
8994
8995 narg = RNODE_RESBODY(resq)->nd_args;
8996 if (narg) {
8997 switch (nd_type(narg)) {
8998 case NODE_LIST:
8999 while (narg) {
9000 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9001 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
9002 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9003 ADD_INSNL(ret, line_node, branchif, label_hit);
9004 narg = RNODE_LIST(narg)->nd_next;
9005 }
9006 break;
9007 case NODE_SPLAT:
9008 case NODE_ARGSCAT:
9009 case NODE_ARGSPUSH:
9010 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9011 CHECK(COMPILE(ret, "rescue/cond splat", narg));
9012 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
9013 ADD_INSNL(ret, line_node, branchif, label_hit);
9014 break;
9015 default:
9016 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
9017 }
9018 }
9019 else {
9020 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9021 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
9022 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9023 ADD_INSNL(ret, line_node, branchif, label_hit);
9024 }
9025 ADD_INSNL(ret, line_node, jump, label_miss);
9026 ADD_LABEL(ret, label_hit);
9027 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
9028
9029 if (RNODE_RESBODY(resq)->nd_exc_var) {
9030 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
9031 }
9032
9033 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) {
9034 // empty body
9035 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
9036 }
9037 else {
9038 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
9039 }
9040
9041 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
9042 ADD_INSN(ret, line_node, nop);
9043 }
9044 ADD_INSN(ret, line_node, leave);
9045 ADD_LABEL(ret, label_miss);
9046 resq = RNODE_RESBODY(resq)->nd_next;
9047 }
9048 return COMPILE_OK;
9049}
9050
9051static int
9052compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9053{
9054 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
9055 const NODE *line_node = node;
9056 DECL_ANCHOR(ensr);
9057 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
9058 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
9059 ISEQ_TYPE_ENSURE, line);
9060 LABEL *lstart = NEW_LABEL(line);
9061 LABEL *lend = NEW_LABEL(line);
9062 LABEL *lcont = NEW_LABEL(line);
9063 LINK_ELEMENT *last;
9064 int last_leave = 0;
9065 struct ensure_range er;
9067 struct ensure_range *erange;
9068
9069 INIT_ANCHOR(ensr);
9070 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
9071 last = ensr->last;
9072 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
9073
9074 er.begin = lstart;
9075 er.end = lend;
9076 er.next = 0;
9077 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
9078
9079 ADD_LABEL(ret, lstart);
9080 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
9081 ADD_LABEL(ret, lend);
9082 ADD_SEQ(ret, ensr);
9083 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
9084 ADD_LABEL(ret, lcont);
9085 if (last_leave) ADD_INSN(ret, line_node, pop);
9086
9087 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
9088 if (lstart->link.next != &lend->link) {
9089 while (erange) {
9090 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
9091 ensure, lcont);
9092 erange = erange->next;
9093 }
9094 }
9095
9096 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
9097 return COMPILE_OK;
9098}
9099
9100static int
9101compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9102{
9103 const NODE *line_node = node;
9104
9105 if (iseq) {
9106 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
9107 const rb_iseq_t *is = iseq;
9108 enum rb_iseq_type t = type;
9109 const NODE *retval = RNODE_RETURN(node)->nd_stts;
9110 LABEL *splabel = 0;
9111
9112 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
9113 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
9114 t = ISEQ_BODY(is)->type;
9115 }
9116 switch (t) {
9117 case ISEQ_TYPE_TOP:
9118 case ISEQ_TYPE_MAIN:
9119 if (retval) {
9120 rb_warn("argument of top-level return is ignored");
9121 }
9122 if (is == iseq) {
9123 /* plain top-level, leave directly */
9124 type = ISEQ_TYPE_METHOD;
9125 }
9126 break;
9127 default:
9128 break;
9129 }
9130
9131 if (type == ISEQ_TYPE_METHOD) {
9132 splabel = NEW_LABEL(0);
9133 ADD_LABEL(ret, splabel);
9134 ADD_ADJUST(ret, line_node, 0);
9135 }
9136
9137 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
9138
9139 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
9140 add_ensure_iseq(ret, iseq, 1);
9141 ADD_TRACE(ret, RUBY_EVENT_RETURN);
9142 ADD_INSN(ret, line_node, leave);
9143 ADD_ADJUST_RESTORE(ret, splabel);
9144
9145 if (!popped) {
9146 ADD_INSN(ret, line_node, putnil);
9147 }
9148 }
9149 else {
9150 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
9151 if (popped) {
9152 ADD_INSN(ret, line_node, pop);
9153 }
9154 }
9155 }
9156 return COMPILE_OK;
9157}
9158
9159static bool
9160drop_unreachable_return(LINK_ANCHOR *ret)
9161{
9162 LINK_ELEMENT *i = ret->last, *last;
9163 if (!i) return false;
9164 if (IS_TRACE(i)) i = i->prev;
9165 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9166 last = i = i->prev;
9167 if (IS_ADJUST(i)) i = i->prev;
9168 if (!IS_INSN(i)) return false;
9169 switch (INSN_OF(i)) {
9170 case BIN(leave):
9171 case BIN(jump):
9172 break;
9173 default:
9174 return false;
9175 }
9176 (ret->last = last->prev)->next = NULL;
9177 return true;
9178}
9179
9180static int
9181compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9182{
9183 CHECK(COMPILE_(ret, "nd_body", node, popped));
9184
9185 if (!popped && !all_string_result_p(node)) {
9186 const NODE *line_node = node;
9187 const unsigned int flag = VM_CALL_FCALL;
9188
9189 // Note, this dup could be removed if we are willing to change anytostring. It pops
9190 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9191 ADD_INSN(ret, line_node, dup);
9192 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9193 ADD_INSN(ret, line_node, anytostring);
9194 }
9195 return COMPILE_OK;
9196}
9197
9198static void
9199compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9200{
9201 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9202
9203 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9204 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9205}
9206
9207static LABEL *
9208qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9209{
9210 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9211 VALUE br = 0;
9212
9213 br = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "&.");
9214 *branches = br;
9215 ADD_INSN(recv, line_node, dup);
9216 ADD_INSNL(recv, line_node, branchnil, else_label);
9217 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9218 return else_label;
9219}
9220
9221static void
9222qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9223{
9224 LABEL *end_label;
9225 if (!else_label) return;
9226 end_label = NEW_LABEL(nd_line(line_node));
9227 ADD_INSNL(ret, line_node, jump, end_label);
9228 ADD_LABEL(ret, else_label);
9229 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9230 ADD_LABEL(ret, end_label);
9231}
9232
9233static int
9234compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9235{
9236 /* optimization shortcut
9237 * "literal".freeze -> opt_str_freeze("literal")
9238 */
9239 if (get_nd_recv(node) &&
9240 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9241 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9242 get_nd_args(node) == NULL &&
9243 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9244 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9245 VALUE str = get_string_value(get_nd_recv(node));
9246 if (get_node_call_nd_mid(node) == idUMinus) {
9247 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9248 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9249 }
9250 else {
9251 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9252 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9253 }
9254 RB_OBJ_WRITTEN(iseq, Qundef, str);
9255 if (popped) {
9256 ADD_INSN(ret, line_node, pop);
9257 }
9258 return TRUE;
9259 }
9260 return FALSE;
9261}
9262
9263static int
9264iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9265{
9266 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9267}
9268
9269static const struct rb_builtin_function *
9270iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9271{
9272 int i;
9273 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9274 for (i=0; table[i].index != -1; i++) {
9275 if (strcmp(table[i].name, name) == 0) {
9276 return &table[i];
9277 }
9278 }
9279 return NULL;
9280}
9281
9282static const char *
9283iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9284{
9285 const char *name = rb_id2name(mid);
9286 static const char prefix[] = "__builtin_";
9287 const size_t prefix_len = sizeof(prefix) - 1;
9288
9289 switch (type) {
9290 case NODE_CALL:
9291 if (recv) {
9292 switch (nd_type(recv)) {
9293 case NODE_VCALL:
9294 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9295 return name;
9296 }
9297 break;
9298 case NODE_CONST:
9299 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9300 return name;
9301 }
9302 break;
9303 default: break;
9304 }
9305 }
9306 break;
9307 case NODE_VCALL:
9308 case NODE_FCALL:
9309 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9310 return &name[prefix_len];
9311 }
9312 break;
9313 default: break;
9314 }
9315 return NULL;
9316}
9317
9318static int
9319delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9320{
9321
9322 if (argc == 0) {
9323 *pstart_index = 0;
9324 return TRUE;
9325 }
9326 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9327 unsigned int start=0;
9328
9329 // local_table: [p1, p2, p3, l1, l2, l3]
9330 // arguments: [p3, l1, l2] -> 2
9331 for (start = 0;
9332 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9333 start++) {
9334 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9335
9336 for (unsigned int i=start; i-start<argc; i++) {
9337 if (IS_INSN(elem) &&
9338 INSN_OF(elem) == BIN(getlocal)) {
9339 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9340 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9341
9342 if (local_level == 0) {
9343 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9344 if (0) { // for debug
9345 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9346 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9347 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9348 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9349 }
9350 if (i == index) {
9351 elem = elem->next;
9352 continue; /* for */
9353 }
9354 else {
9355 goto next;
9356 }
9357 }
9358 else {
9359 goto fail; // level != 0 is unsupported
9360 }
9361 }
9362 else {
9363 goto fail; // insn is not a getlocal
9364 }
9365 }
9366 goto success;
9367 next:;
9368 }
9369 fail:
9370 return FALSE;
9371 success:
9372 *pstart_index = start;
9373 return TRUE;
9374 }
9375 else {
9376 return FALSE;
9377 }
9378}
9379
9380static int
9381compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
9382{
9383 VALUE string = rb_sym2str(symbol);
9384 if (rb_streql_lit(string, "leaf")) {
9385 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9386 }
9387 else if (rb_streql_lit(string, "inline_block")) {
9388 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9389 }
9390 else if (rb_streql_lit(string, "use_block")) {
9391 iseq_set_use_block(iseq);
9392 }
9393 else if (rb_streql_lit(string, "c_trace")) {
9394 // Let the iseq act like a C method in backtraces
9395 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9396 }
9397 else if (rb_streql_lit(string, "without_interrupts")) {
9398 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9399 }
9400 else if (rb_streql_lit(string, "caller_user_box")) {
9401 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_CALLER_USER_BOX;
9402 }
9403 else {
9404 return COMPILE_NG;
9405 }
9406 return COMPILE_OK;
9407}
9408
9409// Compile Primitive.attr! :leaf, ...
9410static int
9411compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9412{
9413 VALUE symbol;
9414 if (!node) goto no_arg;
9415 while (node) {
9416 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9417 const NODE *next = RNODE_LIST(node)->nd_next;
9418
9419 node = RNODE_LIST(node)->nd_head;
9420 if (!node) goto no_arg;
9421 switch (nd_type(node)) {
9422 case NODE_SYM:
9423 symbol = rb_node_sym_string_val(node);
9424 break;
9425 default:
9426 goto bad_arg;
9427 }
9428
9429 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9430 if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
9431 node = next;
9432 }
9433 return COMPILE_OK;
9434 no_arg:
9435 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9436 return COMPILE_NG;
9437 non_symbol_arg:
9438 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9439 return COMPILE_NG;
9440 unknown_arg:
9441 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
9442 return COMPILE_NG;
9443 bad_arg:
9444 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9445}
9446
9447static int
9448compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9449{
9450 VALUE name;
9451
9452 if (!node) goto no_arg;
9453 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9454 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9455 node = RNODE_LIST(node)->nd_head;
9456 if (!node) goto no_arg;
9457 switch (nd_type(node)) {
9458 case NODE_SYM:
9459 name = rb_node_sym_string_val(node);
9460 break;
9461 default:
9462 goto bad_arg;
9463 }
9464 if (!SYMBOL_P(name)) goto non_symbol_arg;
9465 if (!popped) {
9466 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9467 }
9468 return COMPILE_OK;
9469 no_arg:
9470 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9471 return COMPILE_NG;
9472 too_many_arg:
9473 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9474 return COMPILE_NG;
9475 non_symbol_arg:
9476 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9477 rb_builtin_class_name(name));
9478 return COMPILE_NG;
9479 bad_arg:
9480 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9481}
9482
9483static NODE *
9484mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9485{
9486 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9487 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9488 return RNODE_IF(node)->nd_body;
9489 }
9490 else {
9491 rb_bug("mandatory_node: can't find mandatory node");
9492 }
9493}
9494
9495static int
9496compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9497{
9498 // arguments
9499 struct rb_args_info args = {
9500 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9501 };
9502 rb_node_args_t args_node;
9503 rb_node_init(RNODE(&args_node), NODE_ARGS);
9504 args_node.nd_ainfo = args;
9505
9506 // local table without non-mandatory parameters
9507 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9508 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9509
9510 VALUE idtmp = 0;
9511 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9512 tbl->size = table_size;
9513
9514 int i;
9515
9516 // lead parameters
9517 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9518 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9519 }
9520 // local variables
9521 for (; i<table_size; i++) {
9522 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9523 }
9524
9525 rb_node_scope_t scope_node;
9526 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9527 scope_node.nd_tbl = tbl;
9528 scope_node.nd_body = mandatory_node(iseq, node);
9529 scope_node.nd_parent = NULL;
9530 scope_node.nd_args = &args_node;
9531
9532 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9533
9534 const rb_iseq_t *mandatory_only_iseq =
9535 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9536 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9537 nd_line(line_node), NULL, 0,
9538 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9539 ISEQ_SCRIPT_LINES(iseq));
9540 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9541
9542 ALLOCV_END(idtmp);
9543 return COMPILE_OK;
9544}
9545
9546static int
9547compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9548 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9549{
9550 NODE *args_node = get_nd_args(node);
9551
9552 if (parent_block != NULL) {
9553 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9554 return COMPILE_NG;
9555 }
9556 else {
9557# define BUILTIN_INLINE_PREFIX "_bi"
9558 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9559 bool cconst = false;
9560 retry:;
9561 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9562
9563 if (bf == NULL) {
9564 if (strcmp("cstmt!", builtin_func) == 0 ||
9565 strcmp("cexpr!", builtin_func) == 0) {
9566 // ok
9567 }
9568 else if (strcmp("cconst!", builtin_func) == 0) {
9569 cconst = true;
9570 }
9571 else if (strcmp("cinit!", builtin_func) == 0) {
9572 // ignore
9573 return COMPILE_OK;
9574 }
9575 else if (strcmp("attr!", builtin_func) == 0) {
9576 return compile_builtin_attr(iseq, args_node);
9577 }
9578 else if (strcmp("arg!", builtin_func) == 0) {
9579 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9580 }
9581 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9582 if (popped) {
9583 rb_bug("mandatory_only? should be in if condition");
9584 }
9585 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9586 rb_bug("mandatory_only? should be put on top");
9587 }
9588
9589 ADD_INSN1(ret, line_node, putobject, Qfalse);
9590 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9591 }
9592 else if (strcmp("local_self!", builtin_func) == 0) {
9593 // Push the local named "self" (e.g. the `self:` keyword
9594 // parameter of Ractor.shareable_proc) onto the stack.
9595 ID id_self;
9596 CONST_ID(id_self, "self");
9597 compile_lvar(iseq, ret, line_node, id_self);
9598 return COMPILE_OK;
9599 }
9600 else if (1) {
9601 rb_bug("can't find builtin function:%s", builtin_func);
9602 }
9603 else {
9604 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9605 return COMPILE_NG;
9606 }
9607
9608 int inline_index = nd_line(node);
9609 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9610 builtin_func = inline_func;
9611 args_node = NULL;
9612 goto retry;
9613 }
9614
9615 if (cconst) {
9616 typedef VALUE(*builtin_func0)(void *, VALUE);
9617 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9618 ADD_INSN1(ret, line_node, putobject, const_val);
9619 return COMPILE_OK;
9620 }
9621
9622 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9623
9624 unsigned int flag = 0;
9625 struct rb_callinfo_kwarg *keywords = NULL;
9626 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9627
9628 if (FIX2INT(argc) != bf->argc) {
9629 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9630 builtin_func, bf->argc, FIX2INT(argc));
9631 return COMPILE_NG;
9632 }
9633
9634 unsigned int start_index;
9635 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9636 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9637 }
9638 else {
9639 ADD_SEQ(ret, args);
9640 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9641 }
9642
9643 if (popped) ADD_INSN(ret, line_node, pop);
9644 return COMPILE_OK;
9645 }
9646}
9647
9648static int
9649compile_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)
9650{
9651 /* call: obj.method(...)
9652 * fcall: func(...)
9653 * vcall: func
9654 */
9655 DECL_ANCHOR(recv);
9656 DECL_ANCHOR(args);
9657 ID mid = get_node_call_nd_mid(node);
9658 VALUE argc;
9659 unsigned int flag = 0;
9660 struct rb_callinfo_kwarg *keywords = NULL;
9661 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9662 LABEL *else_label = NULL;
9663 VALUE branches = Qfalse;
9664
9665 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9666
9667 INIT_ANCHOR(recv);
9668 INIT_ANCHOR(args);
9669
9670#if OPT_SUPPORT_JOKE
9671 if (nd_type_p(node, NODE_VCALL)) {
9672 ID id_bitblt;
9673 ID id_answer;
9674
9675 CONST_ID(id_bitblt, "bitblt");
9676 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9677
9678 if (mid == id_bitblt) {
9679 ADD_INSN(ret, line_node, bitblt);
9680 return COMPILE_OK;
9681 }
9682 else if (mid == id_answer) {
9683 ADD_INSN(ret, line_node, answer);
9684 return COMPILE_OK;
9685 }
9686 }
9687 /* only joke */
9688 {
9689 ID goto_id;
9690 ID label_id;
9691
9692 CONST_ID(goto_id, "__goto__");
9693 CONST_ID(label_id, "__label__");
9694
9695 if (nd_type_p(node, NODE_FCALL) &&
9696 (mid == goto_id || mid == label_id)) {
9697 LABEL *label;
9698 st_data_t data;
9699 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9700 VALUE label_name;
9701
9702 if (!labels_table) {
9703 labels_table = st_init_numtable();
9704 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9705 }
9706 {
9707 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9708 return COMPILE_NG;
9709 }
9710
9711 if (mid == goto_id) {
9712 ADD_INSNL(ret, line_node, jump, label);
9713 }
9714 else {
9715 ADD_LABEL(ret, label);
9716 }
9717 return COMPILE_OK;
9718 }
9719 }
9720#endif
9721
9722 const char *builtin_func;
9723 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9724 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9725 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9726 }
9727
9728 /* receiver */
9729 if (!assume_receiver) {
9730 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9731 int idx, level;
9732
9733 if ((mid == idCall || mid == idAREF || mid == idYield || mid == idEqq) &&
9734 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9735 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9736 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9737 }
9738 else if (private_recv_p(node)) {
9739 ADD_INSN(recv, node, putself);
9740 flag |= VM_CALL_FCALL;
9741 }
9742 else {
9743 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9744 }
9745
9746 if (type == NODE_QCALL) {
9747 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9748 }
9749 }
9750 else if (type == NODE_FCALL || type == NODE_VCALL) {
9751 ADD_CALL_RECEIVER(recv, line_node);
9752 }
9753 }
9754
9755 /* args */
9756 if (type != NODE_VCALL) {
9757 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9758 CHECK(!NIL_P(argc));
9759 }
9760 else {
9761 argc = INT2FIX(0);
9762 }
9763
9764 ADD_SEQ(ret, recv);
9765
9766 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9767 mid == rb_intern("new") &&
9768 parent_block == NULL &&
9769 !(flag & VM_CALL_ARGS_BLOCKARG);
9770
9771 if (inline_new) {
9772 ADD_INSN(ret, node, putnil);
9773 ADD_INSN(ret, node, swap);
9774 }
9775
9776 ADD_SEQ(ret, args);
9777
9778 debugp_param("call args argc", argc);
9779 debugp_param("call method", ID2SYM(mid));
9780
9781 switch ((int)type) {
9782 case NODE_VCALL:
9783 flag |= VM_CALL_VCALL;
9784 /* VCALL is funcall, so fall through */
9785 case NODE_FCALL:
9786 flag |= VM_CALL_FCALL;
9787 }
9788
9789 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9790 ADD_INSN(ret, line_node, splatkw);
9791 }
9792
9793 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9794 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9795
9796 if (inline_new) {
9797 // Jump unless the receiver uses the "basic" implementation of "new"
9798 VALUE ci;
9799 if (flag & VM_CALL_FORWARDING) {
9800 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9801 }
9802 else {
9803 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9804 }
9805 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9806 LABEL_REF(not_basic_new);
9807
9808 // optimized path
9809 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9810 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9811
9812 ADD_LABEL(ret, not_basic_new);
9813 // Fall back to normal send
9814 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9815 ADD_INSN(ret, line_node, swap);
9816
9817 ADD_LABEL(ret, not_basic_new_finish);
9818 ADD_INSN(ret, line_node, pop);
9819 }
9820 else {
9821 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9822 }
9823
9824 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9825 if (popped) {
9826 ADD_INSN(ret, line_node, pop);
9827 }
9828 return COMPILE_OK;
9829}
9830
9831static int
9832compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9833{
9834 const int line = nd_line(node);
9835 VALUE argc;
9836 unsigned int flag = 0;
9837 int asgnflag = 0;
9838 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9839
9840 /*
9841 * a[x] (op)= y
9842 *
9843 * nil # nil
9844 * eval a # nil a
9845 * eval x # nil a x
9846 * dupn 2 # nil a x a x
9847 * send :[] # nil a x a[x]
9848 * eval y # nil a x a[x] y
9849 * send op # nil a x ret
9850 * setn 3 # ret a x ret
9851 * send []= # ret ?
9852 * pop # ret
9853 */
9854
9855 /*
9856 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9857 * NODE_OP_ASGN nd_recv
9858 * nd_args->nd_head
9859 * nd_args->nd_body
9860 * nd_mid
9861 */
9862
9863 if (!popped) {
9864 ADD_INSN(ret, node, putnil);
9865 }
9866 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9867 CHECK(asgnflag != -1);
9868 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9869 case NODE_ZLIST:
9870 argc = INT2FIX(0);
9871 break;
9872 default:
9873 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9874 CHECK(!NIL_P(argc));
9875 }
9876 int dup_argn = FIX2INT(argc) + 1;
9877 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9878 flag |= asgnflag;
9879 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9880
9881 if (id == idOROP || id == idANDOP) {
9882 /* a[x] ||= y or a[x] &&= y
9883
9884 unless/if a[x]
9885 a[x]= y
9886 else
9887 nil
9888 end
9889 */
9890 LABEL *label = NEW_LABEL(line);
9891 LABEL *lfin = NEW_LABEL(line);
9892
9893 ADD_INSN(ret, node, dup);
9894 if (id == idOROP) {
9895 ADD_INSNL(ret, node, branchif, label);
9896 }
9897 else { /* idANDOP */
9898 ADD_INSNL(ret, node, branchunless, label);
9899 }
9900 ADD_INSN(ret, node, pop);
9901
9902 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9903 if (!popped) {
9904 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9905 }
9906 if (flag & VM_CALL_ARGS_SPLAT) {
9907 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9908 ADD_INSN(ret, node, swap);
9909 ADD_INSN1(ret, node, splatarray, Qtrue);
9910 ADD_INSN(ret, node, swap);
9911 flag |= VM_CALL_ARGS_SPLAT_MUT;
9912 }
9913 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9914 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9915 }
9916 else {
9917 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9918 }
9919 ADD_INSN(ret, node, pop);
9920 ADD_INSNL(ret, node, jump, lfin);
9921 ADD_LABEL(ret, label);
9922 if (!popped) {
9923 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9924 }
9925 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9926 ADD_LABEL(ret, lfin);
9927 }
9928 else {
9929 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9930 ADD_SEND(ret, node, id, INT2FIX(1));
9931 if (!popped) {
9932 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9933 }
9934 if (flag & VM_CALL_ARGS_SPLAT) {
9935 if (flag & VM_CALL_KW_SPLAT) {
9936 ADD_INSN1(ret, node, topn, INT2FIX(2));
9937 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9938 ADD_INSN1(ret, node, splatarray, Qtrue);
9939 flag |= VM_CALL_ARGS_SPLAT_MUT;
9940 }
9941 ADD_INSN(ret, node, swap);
9942 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9943 ADD_INSN1(ret, node, setn, INT2FIX(2));
9944 ADD_INSN(ret, node, pop);
9945 }
9946 else {
9947 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9948 ADD_INSN(ret, node, swap);
9949 ADD_INSN1(ret, node, splatarray, Qtrue);
9950 ADD_INSN(ret, node, swap);
9951 flag |= VM_CALL_ARGS_SPLAT_MUT;
9952 }
9953 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9954 }
9955 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9956 }
9957 else {
9958 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9959 }
9960 ADD_INSN(ret, node, pop);
9961 }
9962 return COMPILE_OK;
9963}
9964
9965static int
9966compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9967{
9968 const int line = nd_line(node);
9969 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9970 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9971 int asgnflag;
9972 LABEL *lfin = NEW_LABEL(line);
9973 LABEL *lcfin = NEW_LABEL(line);
9974 LABEL *lskip = 0;
9975 /*
9976 class C; attr_accessor :c; end
9977 r = C.new
9978 r.a &&= v # asgn2
9979
9980 eval r # r
9981 dup # r r
9982 eval r.a # r o
9983
9984 # or
9985 dup # r o o
9986 if lcfin # r o
9987 pop # r
9988 eval v # r v
9989 swap # v r
9990 topn 1 # v r v
9991 send a= # v ?
9992 jump lfin # v ?
9993
9994 lcfin: # r o
9995 swap # o r
9996
9997 lfin: # o ?
9998 pop # o
9999
10000 # or (popped)
10001 if lcfin # r
10002 eval v # r v
10003 send a= # ?
10004 jump lfin # ?
10005
10006 lcfin: # r
10007
10008 lfin: # ?
10009 pop #
10010
10011 # and
10012 dup # r o o
10013 unless lcfin
10014 pop # r
10015 eval v # r v
10016 swap # v r
10017 topn 1 # v r v
10018 send a= # v ?
10019 jump lfin # v ?
10020
10021 # others
10022 eval v # r o v
10023 send ?? # r w
10024 send a= # w
10025
10026 */
10027
10028 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
10029 CHECK(asgnflag != -1);
10030 if (RNODE_OP_ASGN2(node)->nd_aid) {
10031 lskip = NEW_LABEL(line);
10032 ADD_INSN(ret, node, dup);
10033 ADD_INSNL(ret, node, branchnil, lskip);
10034 }
10035 ADD_INSN(ret, node, dup);
10036 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
10037
10038 if (atype == idOROP || atype == idANDOP) {
10039 if (!popped) {
10040 ADD_INSN(ret, node, dup);
10041 }
10042 if (atype == idOROP) {
10043 ADD_INSNL(ret, node, branchif, lcfin);
10044 }
10045 else { /* idANDOP */
10046 ADD_INSNL(ret, node, branchunless, lcfin);
10047 }
10048 if (!popped) {
10049 ADD_INSN(ret, node, pop);
10050 }
10051 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10052 if (!popped) {
10053 ADD_INSN(ret, node, swap);
10054 ADD_INSN1(ret, node, topn, INT2FIX(1));
10055 }
10056 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10057 ADD_INSNL(ret, node, jump, lfin);
10058
10059 ADD_LABEL(ret, lcfin);
10060 if (!popped) {
10061 ADD_INSN(ret, node, swap);
10062 }
10063
10064 ADD_LABEL(ret, lfin);
10065 }
10066 else {
10067 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10068 ADD_SEND(ret, node, atype, INT2FIX(1));
10069 if (!popped) {
10070 ADD_INSN(ret, node, swap);
10071 ADD_INSN1(ret, node, topn, INT2FIX(1));
10072 }
10073 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10074 }
10075 if (lskip && popped) {
10076 ADD_LABEL(ret, lskip);
10077 }
10078 ADD_INSN(ret, node, pop);
10079 if (lskip && !popped) {
10080 ADD_LABEL(ret, lskip);
10081 }
10082 return COMPILE_OK;
10083}
10084
10085static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
10086
10087static int
10088compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10089{
10090 const int line = nd_line(node);
10091 LABEL *lfin = 0;
10092 LABEL *lassign = 0;
10093 ID mid;
10094
10095 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
10096 case NODE_COLON3:
10097 ADD_INSN1(ret, node, putobject, rb_cObject);
10098 break;
10099 case NODE_COLON2:
10100 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
10101 break;
10102 default:
10103 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
10104 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
10105 return COMPILE_NG;
10106 }
10107 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
10108 /* cref */
10109 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
10110 lassign = NEW_LABEL(line);
10111 ADD_INSN(ret, node, dup); /* cref cref */
10112 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
10113 ID2SYM(mid), Qtrue); /* cref bool */
10114 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
10115 }
10116 ADD_INSN(ret, node, dup); /* cref cref */
10117 ADD_INSN1(ret, node, putobject, Qtrue);
10118 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
10119
10120 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
10121 lfin = NEW_LABEL(line);
10122 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
10123 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
10124 ADD_INSNL(ret, node, branchif, lfin);
10125 else /* idANDOP */
10126 ADD_INSNL(ret, node, branchunless, lfin);
10127 /* cref [obj] */
10128 if (!popped) ADD_INSN(ret, node, pop); /* cref */
10129 if (lassign) ADD_LABEL(ret, lassign);
10130 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10131 /* cref value */
10132 if (popped)
10133 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
10134 else {
10135 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
10136 ADD_INSN(ret, node, swap); /* cref value value cref */
10137 }
10138 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
10139 ADD_LABEL(ret, lfin); /* cref [value] */
10140 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
10141 ADD_INSN(ret, node, pop); /* [value] */
10142 }
10143 else {
10144 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10145 /* cref obj value */
10146 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
10147 /* cref value */
10148 ADD_INSN(ret, node, swap); /* value cref */
10149 if (!popped) {
10150 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
10151 ADD_INSN(ret, node, swap); /* value value cref */
10152 }
10153 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
10154 }
10155 return COMPILE_OK;
10156}
10157
10158static int
10159compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10160{
10161 const int line = nd_line(node);
10162 LABEL *lfin = NEW_LABEL(line);
10163 LABEL *lassign;
10164
10165 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
10166 LABEL *lfinish[2];
10167 lfinish[0] = lfin;
10168 lfinish[1] = 0;
10169 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
10170 lassign = lfinish[1];
10171 if (!lassign) {
10172 lassign = NEW_LABEL(line);
10173 }
10174 ADD_INSNL(ret, node, branchunless, lassign);
10175 }
10176 else {
10177 lassign = NEW_LABEL(line);
10178 }
10179
10180 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10181
10182 if (!popped) {
10183 ADD_INSN(ret, node, dup);
10184 }
10185
10186 if (type == NODE_OP_ASGN_AND) {
10187 ADD_INSNL(ret, node, branchunless, lfin);
10188 }
10189 else {
10190 ADD_INSNL(ret, node, branchif, lfin);
10191 }
10192
10193 if (!popped) {
10194 ADD_INSN(ret, node, pop);
10195 }
10196
10197 ADD_LABEL(ret, lassign);
10198 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10199 ADD_LABEL(ret, lfin);
10200 return COMPILE_OK;
10201}
10202
10203static int
10204compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10205{
10206 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10207 DECL_ANCHOR(args);
10208 int argc;
10209 unsigned int flag = 0;
10210 struct rb_callinfo_kwarg *keywords = NULL;
10211 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10212 int use_block = 1;
10213
10214 INIT_ANCHOR(args);
10215 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10216
10217 if (type == NODE_SUPER) {
10218 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10219 CHECK(!NIL_P(vargc));
10220 argc = FIX2INT(vargc);
10221 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10222 ADD_INSN(args, node, splatkw);
10223 }
10224
10225 if (flag & VM_CALL_ARGS_BLOCKARG) {
10226 use_block = 0;
10227 }
10228 }
10229 else {
10230 /* NODE_ZSUPER */
10231 int i;
10232 const rb_iseq_t *liseq = body->local_iseq;
10233 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10234 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10235 int lvar_level = get_lvar_level(iseq);
10236
10237 argc = local_body->param.lead_num;
10238
10239 /* normal arguments */
10240 for (i = 0; i < local_body->param.lead_num; i++) {
10241 int idx = local_body->local_table_size - i;
10242 ADD_GETLOCAL(args, node, idx, lvar_level);
10243 }
10244
10245 /* forward ... */
10246 if (local_body->param.flags.forwardable) {
10247 flag |= VM_CALL_FORWARDING;
10248 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10249 ADD_GETLOCAL(args, node, idx, lvar_level);
10250 }
10251
10252 if (local_body->param.flags.has_opt) {
10253 /* optional arguments */
10254 int j;
10255 for (j = 0; j < local_body->param.opt_num; j++) {
10256 int idx = local_body->local_table_size - (i + j);
10257 ADD_GETLOCAL(args, node, idx, lvar_level);
10258 }
10259 i += j;
10260 argc = i;
10261 }
10262 if (local_body->param.flags.has_rest) {
10263 /* rest argument */
10264 int idx = local_body->local_table_size - local_body->param.rest_start;
10265 ADD_GETLOCAL(args, node, idx, lvar_level);
10266 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10267
10268 argc = local_body->param.rest_start + 1;
10269 flag |= VM_CALL_ARGS_SPLAT;
10270 }
10271 if (local_body->param.flags.has_post) {
10272 /* post arguments */
10273 int post_len = local_body->param.post_num;
10274 int post_start = local_body->param.post_start;
10275
10276 if (local_body->param.flags.has_rest) {
10277 int j;
10278 for (j=0; j<post_len; j++) {
10279 int idx = local_body->local_table_size - (post_start + j);
10280 ADD_GETLOCAL(args, node, idx, lvar_level);
10281 }
10282 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10283 flag |= VM_CALL_ARGS_SPLAT_MUT;
10284 /* argc is settled at above */
10285 }
10286 else {
10287 int j;
10288 for (j=0; j<post_len; j++) {
10289 int idx = local_body->local_table_size - (post_start + j);
10290 ADD_GETLOCAL(args, node, idx, lvar_level);
10291 }
10292 argc = post_len + post_start;
10293 }
10294 }
10295
10296 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10297 int local_size = local_body->local_table_size;
10298 argc++;
10299
10300 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10301
10302 if (local_body->param.flags.has_kwrest) {
10303 int idx = local_body->local_table_size - local_kwd->rest_start;
10304 ADD_GETLOCAL(args, node, idx, lvar_level);
10305 RUBY_ASSERT(local_kwd->num > 0);
10306 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10307 }
10308 else {
10309 ADD_INSN1(args, node, newhash, INT2FIX(0));
10310 }
10311 for (i = 0; i < local_kwd->num; ++i) {
10312 ID id = local_kwd->table[i];
10313 int idx = local_size - get_local_var_idx(liseq, id);
10314 ADD_INSN1(args, node, putobject, ID2SYM(id));
10315 ADD_GETLOCAL(args, node, idx, lvar_level);
10316 }
10317 ADD_SEND(args, node, id_core_hash_merge_bang_ptr, INT2FIX(i * 2 + 1));
10318 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10319 }
10320 else if (local_body->param.flags.has_kwrest) {
10321 int idx = local_body->local_table_size - local_kwd->rest_start;
10322 ADD_GETLOCAL(args, node, idx, lvar_level);
10323 argc++;
10324 flag |= VM_CALL_KW_SPLAT;
10325 }
10326 }
10327
10328 if (use_block && parent_block == NULL) {
10329 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10330 }
10331
10332 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10333 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10334 ADD_INSN(ret, node, putself);
10335 ADD_SEQ(ret, args);
10336
10337 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10338
10339 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10340 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10341 }
10342 else {
10343 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10344 }
10345
10346 if (popped) {
10347 ADD_INSN(ret, node, pop);
10348 }
10349 return COMPILE_OK;
10350}
10351
10352static int
10353compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10354{
10355 DECL_ANCHOR(args);
10356 VALUE argc;
10357 unsigned int flag = 0;
10358 struct rb_callinfo_kwarg *keywords = NULL;
10359
10360 INIT_ANCHOR(args);
10361
10362 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10363 case ISEQ_TYPE_TOP:
10364 case ISEQ_TYPE_MAIN:
10365 case ISEQ_TYPE_CLASS:
10366 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10367 return COMPILE_NG;
10368 default: /* valid */;
10369 }
10370
10371 if (RNODE_YIELD(node)->nd_head) {
10372 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10373 CHECK(!NIL_P(argc));
10374 }
10375 else {
10376 argc = INT2FIX(0);
10377 }
10378
10379 ADD_SEQ(ret, args);
10380 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10381 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10382
10383 if (popped) {
10384 ADD_INSN(ret, node, pop);
10385 }
10386
10387 int level = 0;
10388 const rb_iseq_t *tmp_iseq = iseq;
10389 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10390 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10391 }
10392 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10393
10394 return COMPILE_OK;
10395}
10396
10397static int
10398compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10399{
10400 DECL_ANCHOR(recv);
10401 DECL_ANCHOR(val);
10402
10403 INIT_ANCHOR(recv);
10404 INIT_ANCHOR(val);
10405 switch ((int)type) {
10406 case NODE_MATCH:
10407 {
10408 VALUE re = rb_node_regx_string_val(node);
10410 ADD_INSN1(recv, node, putobject, re);
10411 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10412 INT2FIX(0));
10413 }
10414 break;
10415 case NODE_MATCH2:
10416 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10417 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10418 break;
10419 case NODE_MATCH3:
10420 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10421 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10422 break;
10423 }
10424
10425 ADD_SEQ(ret, recv);
10426 ADD_SEQ(ret, val);
10427 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10428
10429 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10430 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10431 }
10432
10433 if (popped) {
10434 ADD_INSN(ret, node, pop);
10435 }
10436 return COMPILE_OK;
10437}
10438
10439static int
10440compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10441{
10442 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10443 /* constant */
10444 VALUE segments;
10445 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10446 (segments = collect_const_segments(iseq, node))) {
10447 ISEQ_BODY(iseq)->ic_size++;
10448 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10449 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10450 }
10451 else {
10452 /* constant */
10453 DECL_ANCHOR(pref);
10454 DECL_ANCHOR(body);
10455
10456 INIT_ANCHOR(pref);
10457 INIT_ANCHOR(body);
10458 CHECK(compile_const_prefix(iseq, node, pref, body));
10459 if (LIST_INSN_SIZE_ZERO(pref)) {
10460 ADD_INSN(ret, node, putnil);
10461 ADD_SEQ(ret, body);
10462 }
10463 else {
10464 ADD_SEQ(ret, pref);
10465 ADD_SEQ(ret, body);
10466 }
10467 }
10468 }
10469 else {
10470 /* function call */
10471 ADD_CALL_RECEIVER(ret, node);
10472 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10473 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10474 }
10475 if (popped) {
10476 ADD_INSN(ret, node, pop);
10477 }
10478 return COMPILE_OK;
10479}
10480
10481static int
10482compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10483{
10484 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10485
10486 /* add cache insn */
10487 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10488 ISEQ_BODY(iseq)->ic_size++;
10489 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10491 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10492 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10493 }
10494 else {
10495 ADD_INSN1(ret, node, putobject, rb_cObject);
10496 ADD_INSN1(ret, node, putobject, Qtrue);
10497 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10498 }
10499
10500 if (popped) {
10501 ADD_INSN(ret, node, pop);
10502 }
10503 return COMPILE_OK;
10504}
10505
10506static int
10507compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10508{
10509 VALUE flag = INT2FIX(excl);
10510 const NODE *b = RNODE_DOT2(node)->nd_beg;
10511 const NODE *e = RNODE_DOT2(node)->nd_end;
10512
10513 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10514 if (!popped) {
10515 VALUE bv = optimized_range_item(b);
10516 VALUE ev = optimized_range_item(e);
10517 VALUE val = rb_range_new(bv, ev, excl);
10519 ADD_INSN1(ret, node, putobject, val);
10520 RB_OBJ_WRITTEN(iseq, Qundef, val);
10521 }
10522 }
10523 else {
10524 CHECK(COMPILE_(ret, "min", b, popped));
10525 CHECK(COMPILE_(ret, "max", e, popped));
10526 if (!popped) {
10527 ADD_INSN1(ret, node, newrange, flag);
10528 }
10529 }
10530 return COMPILE_OK;
10531}
10532
10533static int
10534compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10535{
10536 if (!popped) {
10537 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10538 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10539 }
10540 else {
10541 const rb_iseq_t *ip = iseq;
10542 int level = 0;
10543 while (ip) {
10544 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10545 break;
10546 }
10547 ip = ISEQ_BODY(ip)->parent_iseq;
10548 level++;
10549 }
10550 if (ip) {
10551 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10552 }
10553 else {
10554 ADD_INSN(ret, node, putnil);
10555 }
10556 }
10557 }
10558 return COMPILE_OK;
10559}
10560
10561static int
10562compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10563{
10564 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10565 LABEL *end_label = NEW_LABEL(nd_line(node));
10566 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10567
10568 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10569 /* required argument. do nothing */
10570 COMPILE_ERROR(ERROR_ARGS "unreachable");
10571 return COMPILE_NG;
10572 }
10573 else if (nd_type_p(default_value, NODE_SYM) ||
10574 nd_type_p(default_value, NODE_REGX) ||
10575 nd_type_p(default_value, NODE_LINE) ||
10576 nd_type_p(default_value, NODE_INTEGER) ||
10577 nd_type_p(default_value, NODE_FLOAT) ||
10578 nd_type_p(default_value, NODE_RATIONAL) ||
10579 nd_type_p(default_value, NODE_IMAGINARY) ||
10580 nd_type_p(default_value, NODE_NIL) ||
10581 nd_type_p(default_value, NODE_TRUE) ||
10582 nd_type_p(default_value, NODE_FALSE)) {
10583 COMPILE_ERROR(ERROR_ARGS "unreachable");
10584 return COMPILE_NG;
10585 }
10586 else {
10587 /* if keywordcheck(_kw_bits, nth_keyword)
10588 * kw = default_value
10589 * end
10590 */
10591 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10592 int keyword_idx = body->param.keyword->num;
10593
10594 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10595 ADD_INSNL(ret, node, branchif, end_label);
10596 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10597 ADD_LABEL(ret, end_label);
10598 }
10599 return COMPILE_OK;
10600}
10601
10602static int
10603compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10604{
10605 DECL_ANCHOR(recv);
10606 DECL_ANCHOR(args);
10607 unsigned int flag = 0;
10608 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10609 VALUE argc;
10610 LABEL *else_label = NULL;
10611 VALUE branches = Qfalse;
10612
10613 INIT_ANCHOR(recv);
10614 INIT_ANCHOR(args);
10615 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10616 CHECK(!NIL_P(argc));
10617
10618 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10619 CHECK(asgnflag != -1);
10620 flag |= (unsigned int)asgnflag;
10621
10622 debugp_param("argc", argc);
10623 debugp_param("nd_mid", ID2SYM(mid));
10624
10625 if (!rb_is_attrset_id(mid)) {
10626 /* safe nav attr */
10627 mid = rb_id_attrset(mid);
10628 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10629 }
10630 if (!popped) {
10631 ADD_INSN(ret, node, putnil);
10632 ADD_SEQ(ret, recv);
10633 ADD_SEQ(ret, args);
10634
10635 if (flag & VM_CALL_ARGS_SPLAT) {
10636 ADD_INSN(ret, node, dup);
10637 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10638 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10639 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10640 ADD_INSN (ret, node, pop);
10641 }
10642 else {
10643 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10644 }
10645 }
10646 else {
10647 ADD_SEQ(ret, recv);
10648 ADD_SEQ(ret, args);
10649 }
10650 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10651 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10652 ADD_INSN(ret, node, pop);
10653 return COMPILE_OK;
10654}
10655
10656static int
10657compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10658{
10659 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10660 ADD_SEQ(ret, sub);
10661
10662 if (copy) {
10663 /*
10664 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10665 * NEW_LIST(value, loc), loc);
10666 */
10667 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10668 }
10669 else {
10670 /*
10671 * NEW_CALL(fcore, rb_intern("make_shareable"),
10672 * NEW_LIST(value, loc), loc);
10673 */
10674 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10675 }
10676
10677 return COMPILE_OK;
10678}
10679
10680static VALUE
10681node_const_decl_val(const NODE *node)
10682{
10683 VALUE path;
10684 switch (nd_type(node)) {
10685 case NODE_CDECL:
10686 if (RNODE_CDECL(node)->nd_vid) {
10687 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10688 goto end;
10689 }
10690 else {
10691 node = RNODE_CDECL(node)->nd_else;
10692 }
10693 break;
10694 case NODE_COLON2:
10695 break;
10696 case NODE_COLON3:
10697 // ::Const
10698 path = rb_str_new_cstr("::");
10699 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10700 goto end;
10701 default:
10702 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10704 }
10705
10706 path = rb_ary_new();
10707 if (node) {
10708 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10709 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10710 }
10711 if (node && nd_type_p(node, NODE_CONST)) {
10712 // Const::Name
10713 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10714 }
10715 else if (node && nd_type_p(node, NODE_COLON3)) {
10716 // ::Const::Name
10717 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10718 rb_ary_push(path, rb_str_new(0, 0));
10719 }
10720 else {
10721 // expression::Name
10722 rb_ary_push(path, rb_str_new_cstr("..."));
10723 }
10724 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10725 }
10726 end:
10727 path = rb_fstring(path);
10728 return path;
10729}
10730
10731static VALUE
10732const_decl_path(NODE *dest)
10733{
10734 VALUE path = Qnil;
10735 if (!nd_type_p(dest, NODE_CALL)) {
10736 path = node_const_decl_val(dest);
10737 }
10738 return path;
10739}
10740
10741static int
10742compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10743{
10744 /*
10745 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10746 */
10747 VALUE path = const_decl_path(dest);
10748 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10749 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10750 ADD_INSN1(ret, value, putobject, path);
10751 RB_OBJ_WRITTEN(iseq, Qundef, path);
10752 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10753
10754 return COMPILE_OK;
10755}
10756
10757#ifndef SHAREABLE_BARE_EXPRESSION
10758#define SHAREABLE_BARE_EXPRESSION 1
10759#endif
10760
10761static int
10762compile_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)
10763{
10764# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10765 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10766 VALUE lit = Qnil;
10767 DECL_ANCHOR(anchor);
10768
10769 enum node_type type = node ? nd_type(node) : NODE_NIL;
10770 switch (type) {
10771 case NODE_TRUE:
10772 *value_p = Qtrue;
10773 goto compile;
10774 case NODE_FALSE:
10775 *value_p = Qfalse;
10776 goto compile;
10777 case NODE_NIL:
10778 *value_p = Qnil;
10779 goto compile;
10780 case NODE_SYM:
10781 *value_p = rb_node_sym_string_val(node);
10782 goto compile;
10783 case NODE_REGX:
10784 *value_p = rb_node_regx_string_val(node);
10785 goto compile;
10786 case NODE_LINE:
10787 *value_p = rb_node_line_lineno_val(node);
10788 goto compile;
10789 case NODE_INTEGER:
10790 *value_p = rb_node_integer_literal_val(node);
10791 goto compile;
10792 case NODE_FLOAT:
10793 *value_p = rb_node_float_literal_val(node);
10794 goto compile;
10795 case NODE_RATIONAL:
10796 *value_p = rb_node_rational_literal_val(node);
10797 goto compile;
10798 case NODE_IMAGINARY:
10799 *value_p = rb_node_imaginary_literal_val(node);
10800 goto compile;
10801 case NODE_ENCODING:
10802 *value_p = rb_node_encoding_val(node);
10803
10804 compile:
10805 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10806 *shareable_literal_p = 1;
10807 return COMPILE_OK;
10808
10809 case NODE_DSTR:
10810 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10811 if (shareable == rb_parser_shareable_literal) {
10812 /*
10813 * NEW_CALL(node, idUMinus, 0, loc);
10814 *
10815 * -"#{var}"
10816 */
10817 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10818 }
10819 *value_p = Qundef;
10820 *shareable_literal_p = 1;
10821 return COMPILE_OK;
10822
10823 case NODE_STR:{
10824 VALUE lit = rb_node_str_string_val(node);
10825 ADD_INSN1(ret, node, putobject, lit);
10826 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10827 *value_p = lit;
10828 *shareable_literal_p = 1;
10829
10830 return COMPILE_OK;
10831 }
10832
10833 case NODE_FILE:{
10834 VALUE lit = rb_node_file_path_val(node);
10835 ADD_INSN1(ret, node, putobject, lit);
10836 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10837 *value_p = lit;
10838 *shareable_literal_p = 1;
10839
10840 return COMPILE_OK;
10841 }
10842
10843 case NODE_ZLIST:{
10844 VALUE lit = rb_ary_new();
10845 OBJ_FREEZE(lit);
10846 ADD_INSN1(ret, node, putobject, lit);
10847 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10848 *value_p = lit;
10849 *shareable_literal_p = 1;
10850
10851 return COMPILE_OK;
10852 }
10853
10854 case NODE_LIST:{
10855 INIT_ANCHOR(anchor);
10856 lit = rb_ary_new();
10857 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10858 VALUE val;
10859 int shareable_literal_p2;
10860 NODE *elt = RNODE_LIST(n)->nd_head;
10861 if (elt) {
10862 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10863 if (shareable_literal_p2) {
10864 /* noop */
10865 }
10866 else if (RTEST(lit)) {
10867 rb_ary_clear(lit);
10868 lit = Qfalse;
10869 }
10870 }
10871 if (RTEST(lit)) {
10872 if (!UNDEF_P(val)) {
10873 rb_ary_push(lit, val);
10874 }
10875 else {
10876 rb_ary_clear(lit);
10877 lit = Qnil; /* make shareable at runtime */
10878 }
10879 }
10880 }
10881 break;
10882 }
10883 case NODE_HASH:{
10884 if (!RNODE_HASH(node)->nd_brace) {
10885 *value_p = Qundef;
10886 *shareable_literal_p = 0;
10887 return COMPILE_OK;
10888 }
10889 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10890 if (!RNODE_LIST(n)->nd_head) {
10891 // If the hash node have a keyword splat, fall back to the default case.
10892 goto compile_shareable;
10893 }
10894 }
10895
10896 INIT_ANCHOR(anchor);
10897 lit = rb_hash_new();
10898 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10899 VALUE key_val = 0;
10900 VALUE value_val = 0;
10901 int shareable_literal_p2;
10902 NODE *key = RNODE_LIST(n)->nd_head;
10903 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10904 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10905 if (shareable_literal_p2) {
10906 /* noop */
10907 }
10908 else if (RTEST(lit)) {
10909 rb_hash_clear(lit);
10910 lit = Qfalse;
10911 }
10912 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10913 if (shareable_literal_p2) {
10914 /* noop */
10915 }
10916 else if (RTEST(lit)) {
10917 rb_hash_clear(lit);
10918 lit = Qfalse;
10919 }
10920 if (RTEST(lit)) {
10921 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10922 rb_hash_aset(lit, key_val, value_val);
10923 }
10924 else {
10925 rb_hash_clear(lit);
10926 lit = Qnil; /* make shareable at runtime */
10927 }
10928 }
10929 }
10930 break;
10931 }
10932
10933 default:
10934
10935 compile_shareable:
10936 if (shareable == rb_parser_shareable_literal &&
10937 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10938 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10939 *value_p = Qundef;
10940 *shareable_literal_p = 1;
10941 return COMPILE_OK;
10942 }
10943 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10944 *value_p = Qundef;
10945 *shareable_literal_p = 0;
10946 return COMPILE_OK;
10947 }
10948
10949 /* Array or Hash that does not have keyword splat */
10950 if (!lit) {
10951 if (nd_type(node) == NODE_LIST) {
10952 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10953 }
10954 else if (nd_type(node) == NODE_HASH) {
10955 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10958 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10959 }
10960 *value_p = Qundef;
10961 *shareable_literal_p = 0;
10962 ADD_SEQ(ret, anchor);
10963 return COMPILE_OK;
10964 }
10965 if (NIL_P(lit)) {
10966 // if shareable_literal, all elements should have been ensured
10967 // as shareable
10968 if (nd_type(node) == NODE_LIST) {
10969 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10970 }
10971 else if (nd_type(node) == NODE_HASH) {
10972 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10975 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10976 }
10977 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10978 *value_p = Qundef;
10979 *shareable_literal_p = 1;
10980 }
10981 else {
10983 ADD_INSN1(ret, node, putobject, val);
10984 RB_OBJ_WRITTEN(iseq, Qundef, val);
10985 *value_p = val;
10986 *shareable_literal_p = 1;
10987 }
10988
10989 return COMPILE_OK;
10990}
10991
10992static int
10993compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10994{
10995 int literal_p = 0;
10996 VALUE val;
10997 DECL_ANCHOR(anchor);
10998 INIT_ANCHOR(anchor);
10999
11000 switch (shareable) {
11001 case rb_parser_shareable_none:
11002 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
11003 return COMPILE_OK;
11004
11005 case rb_parser_shareable_literal:
11006 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11007 ADD_SEQ(ret, anchor);
11008 return COMPILE_OK;
11009
11010 case rb_parser_shareable_copy:
11011 case rb_parser_shareable_everything:
11012 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11013 if (!literal_p) {
11014 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
11015 }
11016 else {
11017 ADD_SEQ(ret, anchor);
11018 }
11019 return COMPILE_OK;
11020 default:
11021 rb_bug("unexpected rb_parser_shareability: %d", shareable);
11022 }
11023}
11024
11025static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
11033static int
11034iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
11035{
11036 if (node == 0) {
11037 if (!popped) {
11038 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11039 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11040 debugs("node: NODE_NIL(implicit)\n");
11041 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11042 }
11043 return COMPILE_OK;
11044 }
11045 return iseq_compile_each0(iseq, ret, node, popped);
11046}
11047
11048static int
11049iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11050{
11051 const int line = (int)nd_line(node);
11052 const enum node_type type = nd_type(node);
11053 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11054
11055 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11056 /* ignore */
11057 }
11058 else {
11059 if (nd_fl_newline(node)) {
11060 int event = RUBY_EVENT_LINE;
11061 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11062 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11063 event |= RUBY_EVENT_COVERAGE_LINE;
11064 }
11065 ADD_TRACE(ret, event);
11066 }
11067 }
11068
11069 debug_node_start(node);
11070#undef BEFORE_RETURN
11071#define BEFORE_RETURN debug_node_end()
11072
11073 switch (type) {
11074 case NODE_BLOCK:
11075 CHECK(compile_block(iseq, ret, node, popped));
11076 break;
11077 case NODE_IF:
11078 case NODE_UNLESS:
11079 CHECK(compile_if(iseq, ret, node, popped, type));
11080 break;
11081 case NODE_CASE:
11082 CHECK(compile_case(iseq, ret, node, popped));
11083 break;
11084 case NODE_CASE2:
11085 CHECK(compile_case2(iseq, ret, node, popped));
11086 break;
11087 case NODE_CASE3:
11088 CHECK(compile_case3(iseq, ret, node, popped));
11089 break;
11090 case NODE_WHILE:
11091 case NODE_UNTIL:
11092 CHECK(compile_loop(iseq, ret, node, popped, type));
11093 break;
11094 case NODE_FOR:
11095 case NODE_ITER:
11096 CHECK(compile_iter(iseq, ret, node, popped));
11097 break;
11098 case NODE_FOR_MASGN:
11099 CHECK(compile_for_masgn(iseq, ret, node, popped));
11100 break;
11101 case NODE_BREAK:
11102 CHECK(compile_break(iseq, ret, node, popped));
11103 break;
11104 case NODE_NEXT:
11105 CHECK(compile_next(iseq, ret, node, popped));
11106 break;
11107 case NODE_REDO:
11108 CHECK(compile_redo(iseq, ret, node, popped));
11109 break;
11110 case NODE_RETRY:
11111 CHECK(compile_retry(iseq, ret, node, popped));
11112 break;
11113 case NODE_BEGIN:{
11114 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11115 break;
11116 }
11117 case NODE_RESCUE:
11118 CHECK(compile_rescue(iseq, ret, node, popped));
11119 break;
11120 case NODE_RESBODY:
11121 CHECK(compile_resbody(iseq, ret, node, popped));
11122 break;
11123 case NODE_ENSURE:
11124 CHECK(compile_ensure(iseq, ret, node, popped));
11125 break;
11126
11127 case NODE_AND:
11128 case NODE_OR:{
11129 LABEL *end_label = NEW_LABEL(line);
11130 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
11131 if (!popped) {
11132 ADD_INSN(ret, node, dup);
11133 }
11134 if (type == NODE_AND) {
11135 ADD_INSNL(ret, node, branchunless, end_label);
11136 }
11137 else {
11138 ADD_INSNL(ret, node, branchif, end_label);
11139 }
11140 if (!popped) {
11141 ADD_INSN(ret, node, pop);
11142 }
11143 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
11144 ADD_LABEL(ret, end_label);
11145 break;
11146 }
11147
11148 case NODE_MASGN:{
11149 compile_massign(iseq, ret, node, popped);
11150 break;
11151 }
11152
11153 case NODE_LASGN:{
11154 ID id = RNODE_LASGN(node)->nd_vid;
11155 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11156
11157 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11158 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11159
11160 if (!popped) {
11161 ADD_INSN(ret, node, dup);
11162 }
11163 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11164 break;
11165 }
11166 case NODE_DASGN: {
11167 int idx, lv, ls;
11168 ID id = RNODE_DASGN(node)->nd_vid;
11169 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11170 debugi("dassn id", rb_id2str(id) ? id : '*');
11171
11172 if (!popped) {
11173 ADD_INSN(ret, node, dup);
11174 }
11175
11176 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11177
11178 if (idx < 0) {
11179 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11180 rb_id2str(id));
11181 goto ng;
11182 }
11183 ADD_SETLOCAL(ret, node, ls - idx, lv);
11184 break;
11185 }
11186 case NODE_GASGN:{
11187 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11188
11189 if (!popped) {
11190 ADD_INSN(ret, node, dup);
11191 }
11192 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11193 break;
11194 }
11195 case NODE_IASGN:{
11196 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11197 if (!popped) {
11198 ADD_INSN(ret, node, dup);
11199 }
11200 ADD_INSN2(ret, node, setinstancevariable,
11201 ID2SYM(RNODE_IASGN(node)->nd_vid),
11202 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11203 break;
11204 }
11205 case NODE_CDECL:{
11206 if (RNODE_CDECL(node)->nd_vid) {
11207 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11208
11209 if (!popped) {
11210 ADD_INSN(ret, node, dup);
11211 }
11212
11213 ADD_INSN1(ret, node, putspecialobject,
11214 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11215 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11216 }
11217 else {
11218 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11219 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11220 ADD_INSN(ret, node, swap);
11221
11222 if (!popped) {
11223 ADD_INSN1(ret, node, topn, INT2FIX(1));
11224 ADD_INSN(ret, node, swap);
11225 }
11226
11227 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11228 }
11229 break;
11230 }
11231 case NODE_CVASGN:{
11232 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11233 if (!popped) {
11234 ADD_INSN(ret, node, dup);
11235 }
11236 ADD_INSN2(ret, node, setclassvariable,
11237 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11238 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11239 break;
11240 }
11241 case NODE_OP_ASGN1:
11242 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11243 break;
11244 case NODE_OP_ASGN2:
11245 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11246 break;
11247 case NODE_OP_CDECL:
11248 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11249 break;
11250 case NODE_OP_ASGN_AND:
11251 case NODE_OP_ASGN_OR:
11252 CHECK(compile_op_log(iseq, ret, node, popped, type));
11253 break;
11254 case NODE_CALL: /* obj.foo */
11255 case NODE_OPCALL: /* foo[] */
11256 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11257 break;
11258 }
11259 case NODE_QCALL: /* obj&.foo */
11260 case NODE_FCALL: /* foo() */
11261 case NODE_VCALL: /* foo (variable or call) */
11262 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11263 goto ng;
11264 }
11265 break;
11266 case NODE_SUPER:
11267 case NODE_ZSUPER:
11268 CHECK(compile_super(iseq, ret, node, popped, type));
11269 break;
11270 case NODE_LIST:{
11271 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11272 break;
11273 }
11274 case NODE_ZLIST:{
11275 if (!popped) {
11276 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11277 }
11278 break;
11279 }
11280 case NODE_HASH:
11281 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11282 break;
11283 case NODE_RETURN:
11284 CHECK(compile_return(iseq, ret, node, popped));
11285 break;
11286 case NODE_YIELD:
11287 CHECK(compile_yield(iseq, ret, node, popped));
11288 break;
11289 case NODE_LVAR:{
11290 if (!popped) {
11291 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11292 }
11293 break;
11294 }
11295 case NODE_DVAR:{
11296 int lv, idx, ls;
11297 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11298 if (!popped) {
11299 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11300 if (idx < 0) {
11301 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11302 rb_id2str(RNODE_DVAR(node)->nd_vid));
11303 goto ng;
11304 }
11305 ADD_GETLOCAL(ret, node, ls - idx, lv);
11306 }
11307 break;
11308 }
11309 case NODE_GVAR:{
11310 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11311 if (popped) {
11312 ADD_INSN(ret, node, pop);
11313 }
11314 break;
11315 }
11316 case NODE_IVAR:{
11317 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11318 if (!popped) {
11319 ADD_INSN2(ret, node, getinstancevariable,
11320 ID2SYM(RNODE_IVAR(node)->nd_vid),
11321 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11322 }
11323 break;
11324 }
11325 case NODE_CONST:{
11326 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11327
11328 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11329 body->ic_size++;
11330 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11332 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11333 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11334 }
11335 else {
11336 ADD_INSN(ret, node, putnil);
11337 ADD_INSN1(ret, node, putobject, Qtrue);
11338 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11339 }
11340
11341 if (popped) {
11342 ADD_INSN(ret, node, pop);
11343 }
11344 break;
11345 }
11346 case NODE_CVAR:{
11347 if (!popped) {
11348 ADD_INSN2(ret, node, getclassvariable,
11349 ID2SYM(RNODE_CVAR(node)->nd_vid),
11350 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11351 }
11352 break;
11353 }
11354 case NODE_NTH_REF:{
11355 if (!popped) {
11356 if (!RNODE_NTH_REF(node)->nd_nth) {
11357 ADD_INSN(ret, node, putnil);
11358 break;
11359 }
11360 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11361 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11362 }
11363 break;
11364 }
11365 case NODE_BACK_REF:{
11366 if (!popped) {
11367 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11368 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11369 }
11370 break;
11371 }
11372 case NODE_MATCH:
11373 case NODE_MATCH2:
11374 case NODE_MATCH3:
11375 CHECK(compile_match(iseq, ret, node, popped, type));
11376 break;
11377 case NODE_SYM:{
11378 if (!popped) {
11379 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11380 }
11381 break;
11382 }
11383 case NODE_LINE:{
11384 if (!popped) {
11385 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11386 }
11387 break;
11388 }
11389 case NODE_ENCODING:{
11390 if (!popped) {
11391 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11392 }
11393 break;
11394 }
11395 case NODE_INTEGER:{
11396 VALUE lit = rb_node_integer_literal_val(node);
11397 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11398 debugp_param("integer", lit);
11399 if (!popped) {
11400 ADD_INSN1(ret, node, putobject, lit);
11401 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11402 }
11403 break;
11404 }
11405 case NODE_FLOAT:{
11406 VALUE lit = rb_node_float_literal_val(node);
11407 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11408 debugp_param("float", lit);
11409 if (!popped) {
11410 ADD_INSN1(ret, node, putobject, lit);
11411 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11412 }
11413 break;
11414 }
11415 case NODE_RATIONAL:{
11416 VALUE lit = rb_node_rational_literal_val(node);
11418 debugp_param("rational", lit);
11419 if (!popped) {
11420 ADD_INSN1(ret, node, putobject, lit);
11421 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11422 }
11423 break;
11424 }
11425 case NODE_IMAGINARY:{
11426 VALUE lit = rb_node_imaginary_literal_val(node);
11428 debugp_param("imaginary", lit);
11429 if (!popped) {
11430 ADD_INSN1(ret, node, putobject, lit);
11431 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11432 }
11433 break;
11434 }
11435 case NODE_FILE:
11436 case NODE_STR:{
11437 debugp_param("nd_lit", get_string_value(node));
11438 if (!popped) {
11439 VALUE lit = get_string_value(node);
11440 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11441 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11442 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11443 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11445 }
11446 switch (option->frozen_string_literal) {
11447 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11448 ADD_INSN1(ret, node, dupchilledstring, lit);
11449 break;
11450 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11451 ADD_INSN1(ret, node, dupstring, lit);
11452 break;
11453 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11454 ADD_INSN1(ret, node, putobject, lit);
11455 break;
11456 default:
11457 rb_bug("invalid frozen_string_literal");
11458 }
11459 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11460 }
11461 break;
11462 }
11463 case NODE_DSTR:{
11464 compile_dstr(iseq, ret, node);
11465
11466 if (popped) {
11467 ADD_INSN(ret, node, pop);
11468 }
11469 break;
11470 }
11471 case NODE_XSTR:{
11472 ADD_CALL_RECEIVER(ret, node);
11473 VALUE str = rb_node_str_string_val(node);
11474 ADD_INSN1(ret, node, putobject, str);
11475 RB_OBJ_WRITTEN(iseq, Qundef, str);
11476 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11477
11478 if (popped) {
11479 ADD_INSN(ret, node, pop);
11480 }
11481 break;
11482 }
11483 case NODE_DXSTR:{
11484 ADD_CALL_RECEIVER(ret, node);
11485 compile_dstr(iseq, ret, node);
11486 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11487
11488 if (popped) {
11489 ADD_INSN(ret, node, pop);
11490 }
11491 break;
11492 }
11493 case NODE_EVSTR:
11494 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11495 break;
11496 case NODE_REGX:{
11497 if (!popped) {
11498 VALUE lit = rb_node_regx_string_val(node);
11500 ADD_INSN1(ret, node, putobject, lit);
11501 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11502 }
11503 break;
11504 }
11505 case NODE_DREGX:
11506 compile_dregx(iseq, ret, node, popped);
11507 break;
11508 case NODE_ONCE:{
11509 int ic_index = body->ise_size++;
11510 const rb_iseq_t *block_iseq;
11511 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11512
11513 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11514 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11515
11516 if (popped) {
11517 ADD_INSN(ret, node, pop);
11518 }
11519 break;
11520 }
11521 case NODE_ARGSCAT:{
11522 if (popped) {
11523 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11524 ADD_INSN1(ret, node, splatarray, Qfalse);
11525 ADD_INSN(ret, node, pop);
11526 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11527 ADD_INSN1(ret, node, splatarray, Qfalse);
11528 ADD_INSN(ret, node, pop);
11529 }
11530 else {
11531 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11532 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11533 if (nd_type_p(body_node, NODE_LIST)) {
11534 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11535 }
11536 else {
11537 CHECK(COMPILE(ret, "argscat body", body_node));
11538 ADD_INSN(ret, node, concattoarray);
11539 }
11540 }
11541 break;
11542 }
11543 case NODE_ARGSPUSH:{
11544 if (popped) {
11545 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11546 ADD_INSN1(ret, node, splatarray, Qfalse);
11547 ADD_INSN(ret, node, pop);
11548 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11549 }
11550 else {
11551 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11552 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11553 if (keyword_node_p(body_node)) {
11554 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11555 ADD_INSN(ret, node, pushtoarraykwsplat);
11556 }
11557 else if (static_literal_node_p(body_node, iseq, false)) {
11558 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11559 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11560 }
11561 else {
11562 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11563 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11564 }
11565 }
11566 break;
11567 }
11568 case NODE_SPLAT:{
11569 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11570 ADD_INSN1(ret, node, splatarray, Qtrue);
11571
11572 if (popped) {
11573 ADD_INSN(ret, node, pop);
11574 }
11575 break;
11576 }
11577 case NODE_DEFN:{
11578 ID mid = RNODE_DEFN(node)->nd_mid;
11579 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11580 rb_id2str(mid),
11581 ISEQ_TYPE_METHOD, line);
11582
11583 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11584 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11585 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11586
11587 if (!popped) {
11588 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11589 }
11590
11591 break;
11592 }
11593 case NODE_DEFS:{
11594 ID mid = RNODE_DEFS(node)->nd_mid;
11595 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11596 rb_id2str(mid),
11597 ISEQ_TYPE_METHOD, line);
11598
11599 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11600 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11601 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11602 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11603
11604 if (!popped) {
11605 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11606 }
11607 break;
11608 }
11609 case NODE_ALIAS:{
11610 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11611 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11612 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11613 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11614 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11615
11616 if (popped) {
11617 ADD_INSN(ret, node, pop);
11618 }
11619 break;
11620 }
11621 case NODE_VALIAS:{
11622 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11623 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11624 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11625 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11626
11627 if (popped) {
11628 ADD_INSN(ret, node, pop);
11629 }
11630 break;
11631 }
11632 case NODE_UNDEF:{
11633 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11634
11635 for (long i = 0; i < ary->len; i++) {
11636 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11637 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11638 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11639 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11640
11641 if (i < ary->len - 1) {
11642 ADD_INSN(ret, node, pop);
11643 }
11644 }
11645
11646 if (popped) {
11647 ADD_INSN(ret, node, pop);
11648 }
11649 break;
11650 }
11651 case NODE_CLASS:{
11652 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11653 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11654 ISEQ_TYPE_CLASS, line);
11655 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11656 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11657 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11658
11659 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11660 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11661 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11662
11663 if (popped) {
11664 ADD_INSN(ret, node, pop);
11665 }
11666 break;
11667 }
11668 case NODE_MODULE:{
11669 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11670 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11671 ISEQ_TYPE_CLASS, line);
11672 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11673 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11674
11675 ADD_INSN (ret, node, putnil); /* dummy */
11676 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11677 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11678
11679 if (popped) {
11680 ADD_INSN(ret, node, pop);
11681 }
11682 break;
11683 }
11684 case NODE_SCLASS:{
11685 ID singletonclass;
11686 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11687 ISEQ_TYPE_CLASS, line);
11688
11689 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11690 ADD_INSN (ret, node, putnil);
11691 CONST_ID(singletonclass, "singletonclass");
11692
11693 /* `class << self` in a class body and `class << Foo` (constant
11694 receiver) are stable. All other forms are potentially dynamic. */
11695 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11696 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11697 if (!(nd_type_p(recv, NODE_SELF) &&
11698 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11699 !cpath_const_p(recv)) {
11700 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11701 }
11702
11703 ADD_INSN3(ret, node, defineclass,
11704 ID2SYM(singletonclass), singleton_class,
11705 INT2FIX(sclass_flags));
11706 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11707
11708 if (popped) {
11709 ADD_INSN(ret, node, pop);
11710 }
11711 break;
11712 }
11713 case NODE_COLON2:
11714 CHECK(compile_colon2(iseq, ret, node, popped));
11715 break;
11716 case NODE_COLON3:
11717 CHECK(compile_colon3(iseq, ret, node, popped));
11718 break;
11719 case NODE_DOT2:
11720 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11721 break;
11722 case NODE_DOT3:
11723 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11724 break;
11725 case NODE_FLIP2:
11726 case NODE_FLIP3:{
11727 LABEL *lend = NEW_LABEL(line);
11728 LABEL *ltrue = NEW_LABEL(line);
11729 LABEL *lfalse = NEW_LABEL(line);
11730 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11731 ltrue, lfalse));
11732 ADD_LABEL(ret, ltrue);
11733 ADD_INSN1(ret, node, putobject, Qtrue);
11734 ADD_INSNL(ret, node, jump, lend);
11735 ADD_LABEL(ret, lfalse);
11736 ADD_INSN1(ret, node, putobject, Qfalse);
11737 ADD_LABEL(ret, lend);
11738 break;
11739 }
11740 case NODE_SELF:{
11741 if (!popped) {
11742 ADD_INSN(ret, node, putself);
11743 }
11744 break;
11745 }
11746 case NODE_NIL:{
11747 if (!popped) {
11748 ADD_INSN(ret, node, putnil);
11749 }
11750 break;
11751 }
11752 case NODE_TRUE:{
11753 if (!popped) {
11754 ADD_INSN1(ret, node, putobject, Qtrue);
11755 }
11756 break;
11757 }
11758 case NODE_FALSE:{
11759 if (!popped) {
11760 ADD_INSN1(ret, node, putobject, Qfalse);
11761 }
11762 break;
11763 }
11764 case NODE_ERRINFO:
11765 CHECK(compile_errinfo(iseq, ret, node, popped));
11766 break;
11767 case NODE_DEFINED:
11768 if (!popped) {
11769 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11770 }
11771 break;
11772 case NODE_POSTEXE:{
11773 /* compiled to:
11774 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11775 */
11776 int is_index = body->ise_size++;
11778 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11779 const rb_iseq_t *once_iseq =
11780 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11781
11782 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11783 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11784
11785 if (popped) {
11786 ADD_INSN(ret, node, pop);
11787 }
11788 break;
11789 }
11790 case NODE_KW_ARG:
11791 CHECK(compile_kw_arg(iseq, ret, node, popped));
11792 break;
11793 case NODE_DSYM:{
11794 compile_dstr(iseq, ret, node);
11795 if (!popped) {
11796 ADD_INSN(ret, node, intern);
11797 }
11798 else {
11799 ADD_INSN(ret, node, pop);
11800 }
11801 break;
11802 }
11803 case NODE_ATTRASGN:
11804 CHECK(compile_attrasgn(iseq, ret, node, popped));
11805 break;
11806 case NODE_LAMBDA:{
11807 /* compile same as lambda{...} */
11808 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11809 VALUE argc = INT2FIX(0);
11810
11811 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11812 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11813 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11814
11815 if (popped) {
11816 ADD_INSN(ret, node, pop);
11817 }
11818 break;
11819 }
11820 default:
11821 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11822 ng:
11823 debug_node_end();
11824 return COMPILE_NG;
11825 }
11826
11827 debug_node_end();
11828 return COMPILE_OK;
11829}
11830
11831/***************************/
11832/* instruction information */
11833/***************************/
11834
11835static int
11836insn_data_length(INSN *iobj)
11837{
11838 return insn_len(iobj->insn_id);
11839}
11840
11841static int
11842calc_sp_depth(int depth, INSN *insn)
11843{
11844 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11845}
11846
11847static VALUE
11848opobj_inspect(VALUE obj)
11849{
11850 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11851 switch (BUILTIN_TYPE(obj)) {
11852 case T_STRING:
11853 obj = rb_str_resurrect(obj);
11854 break;
11855 case T_ARRAY:
11856 obj = rb_ary_resurrect(obj);
11857 break;
11858 default:
11859 break;
11860 }
11861 }
11862 return rb_inspect(obj);
11863}
11864
11865
11866
11867static VALUE
11868insn_data_to_s_detail(INSN *iobj)
11869{
11870 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11871
11872 if (iobj->operands) {
11873 const char *types = insn_op_types(iobj->insn_id);
11874 int j;
11875
11876 for (j = 0; types[j]; j++) {
11877 char type = types[j];
11878
11879 switch (type) {
11880 case TS_OFFSET: /* label(destination position) */
11881 {
11882 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11883 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11884 break;
11885 }
11886 break;
11887 case TS_ISEQ: /* iseq */
11888 {
11889 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11890 VALUE val = Qnil;
11891 if (0 && iseq) { /* TODO: invalidate now */
11892 val = (VALUE)iseq;
11893 }
11894 rb_str_concat(str, opobj_inspect(val));
11895 }
11896 break;
11897 case TS_LINDEX:
11898 case TS_NUM: /* ulong */
11899 case TS_VALUE: /* VALUE */
11900 {
11901 VALUE v = OPERAND_AT(iobj, j);
11902 if (!CLASS_OF(v))
11903 rb_str_cat2(str, "<hidden>");
11904 else {
11905 rb_str_concat(str, opobj_inspect(v));
11906 }
11907 break;
11908 }
11909 case TS_ID: /* ID */
11910 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11911 break;
11912 case TS_IC: /* inline cache */
11913 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11914 break;
11915 case TS_IVC: /* inline ivar cache */
11916 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11917 break;
11918 case TS_ICVARC: /* inline cvar cache */
11919 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11920 break;
11921 case TS_ISE: /* inline storage entry */
11922 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11923 break;
11924 case TS_CALLDATA: /* we store these as call infos at compile time */
11925 {
11926 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11927 rb_str_cat2(str, "<calldata:");
11928 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
11929 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11930 break;
11931 }
11932 case TS_CDHASH: /* case/when condition cache */
11933 rb_str_cat2(str, "<ch>");
11934 break;
11935 case TS_FUNCPTR:
11936 {
11937 void *func = (void *)OPERAND_AT(iobj, j);
11938#ifdef HAVE_DLADDR
11939 Dl_info info;
11940 if (dladdr(func, &info) && info.dli_sname) {
11941 rb_str_cat2(str, info.dli_sname);
11942 break;
11943 }
11944#endif
11945 rb_str_catf(str, "<%p>", func);
11946 }
11947 break;
11948 case TS_BUILTIN:
11949 rb_str_cat2(str, "<TS_BUILTIN>");
11950 break;
11951 default:{
11952 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11953 }
11954 }
11955 if (types[j + 1]) {
11956 rb_str_cat2(str, ", ");
11957 }
11958 }
11959 }
11960 return str;
11961}
11962
11963static void
11964dump_disasm_list(const LINK_ELEMENT *link)
11965{
11966 dump_disasm_list_with_cursor(link, NULL, NULL);
11967}
11968
11969static void
11970dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11971{
11972 int pos = 0;
11973 INSN *iobj;
11974 LABEL *lobj;
11975 VALUE str;
11976
11977 printf("-- raw disasm--------\n");
11978
11979 while (link) {
11980 if (curr) printf(curr == link ? "*" : " ");
11981 switch (link->type) {
11982 case ISEQ_ELEMENT_INSN:
11983 {
11984 iobj = (INSN *)link;
11985 str = insn_data_to_s_detail(iobj);
11986 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11987 pos += insn_data_length(iobj);
11988 break;
11989 }
11990 case ISEQ_ELEMENT_LABEL:
11991 {
11992 lobj = (LABEL *)link;
11993 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11994 dest == lobj ? " <---" : "");
11995 break;
11996 }
11997 case ISEQ_ELEMENT_TRACE:
11998 {
11999 TRACE *trace = (TRACE *)link;
12000 printf(" trace: %0x\n", trace->event);
12001 break;
12002 }
12003 case ISEQ_ELEMENT_ADJUST:
12004 {
12005 ADJUST *adjust = (ADJUST *)link;
12006 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
12007 break;
12008 }
12009 default:
12010 /* ignore */
12011 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
12012 }
12013 link = link->next;
12014 }
12015 printf("---------------------\n");
12016 fflush(stdout);
12017}
12018
12019int
12020rb_insn_len(VALUE insn)
12021{
12022 return insn_len(insn);
12023}
12024
12025const char *
12026rb_insns_name(int i)
12027{
12028 return insn_name(i);
12029}
12030
12031VALUE
12032rb_insns_name_array(void)
12033{
12034 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
12035 int i;
12036 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12037 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12038 }
12039 return rb_ary_freeze(ary);
12040}
12041
12042static LABEL *
12043register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12044{
12045 LABEL *label = 0;
12046 st_data_t tmp;
12047 obj = rb_to_symbol_type(obj);
12048
12049 if (st_lookup(labels_table, obj, &tmp) == 0) {
12050 label = NEW_LABEL(0);
12051 st_insert(labels_table, obj, (st_data_t)label);
12052 }
12053 else {
12054 label = (LABEL *)tmp;
12055 }
12056 LABEL_REF(label);
12057 return label;
12058}
12059
12060static VALUE
12061get_exception_sym2type(VALUE sym)
12062{
12063 static VALUE symRescue, symEnsure, symRetry;
12064 static VALUE symBreak, symRedo, symNext;
12065
12066 if (symRescue == 0) {
12067 symRescue = ID2SYM(rb_intern_const("rescue"));
12068 symEnsure = ID2SYM(rb_intern_const("ensure"));
12069 symRetry = ID2SYM(rb_intern_const("retry"));
12070 symBreak = ID2SYM(rb_intern_const("break"));
12071 symRedo = ID2SYM(rb_intern_const("redo"));
12072 symNext = ID2SYM(rb_intern_const("next"));
12073 }
12074
12075 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12076 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12077 if (sym == symRetry) return CATCH_TYPE_RETRY;
12078 if (sym == symBreak) return CATCH_TYPE_BREAK;
12079 if (sym == symRedo) return CATCH_TYPE_REDO;
12080 if (sym == symNext) return CATCH_TYPE_NEXT;
12081 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12082 return 0;
12083}
12084
12085static int
12086iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12087 VALUE exception)
12088{
12089 int i;
12090
12091 for (i=0; i<RARRAY_LEN(exception); i++) {
12092 const rb_iseq_t *eiseq;
12093 VALUE v, type;
12094 LABEL *lstart, *lend, *lcont;
12095 unsigned int sp;
12096
12097 v = rb_to_array_type(RARRAY_AREF(exception, i));
12098 if (RARRAY_LEN(v) != 6) {
12099 rb_raise(rb_eSyntaxError, "wrong exception entry");
12100 }
12101 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12102 if (NIL_P(RARRAY_AREF(v, 1))) {
12103 eiseq = NULL;
12104 }
12105 else {
12106 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12107 }
12108
12109 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12110 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12111 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12112 sp = NUM2UINT(RARRAY_AREF(v, 5));
12113
12114 /* TODO: Dirty Hack! Fix me */
12115 if (type == CATCH_TYPE_RESCUE ||
12116 type == CATCH_TYPE_BREAK ||
12117 type == CATCH_TYPE_NEXT) {
12118 ++sp;
12119 }
12120
12121 lcont->sp = sp;
12122
12123 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12124
12125 RB_GC_GUARD(v);
12126 }
12127 return COMPILE_OK;
12128}
12129
12130static struct st_table *
12131insn_make_insn_table(void)
12132{
12133 struct st_table *table;
12134 int i;
12135 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12136
12137 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12138 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12139 }
12140
12141 return table;
12142}
12143
12144static const rb_iseq_t *
12145iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12146{
12147 VALUE iseqw;
12148 const rb_iseq_t *loaded_iseq;
12149
12150 if (RB_TYPE_P(op, T_ARRAY)) {
12151 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12152 }
12153 else if (CLASS_OF(op) == rb_cISeq) {
12154 iseqw = op;
12155 }
12156 else {
12157 rb_raise(rb_eSyntaxError, "ISEQ is required");
12158 }
12159
12160 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12161 return loaded_iseq;
12162}
12163
12164static VALUE
12165iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12166{
12167 ID mid = 0;
12168 int orig_argc = 0;
12169 unsigned int flag = 0;
12170 struct rb_callinfo_kwarg *kw_arg = 0;
12171
12172 if (!NIL_P(op)) {
12173 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12174 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12175 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12176 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12177
12178 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12179 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12180 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12181
12182 if (!NIL_P(vkw_arg)) {
12183 int i;
12184 int len = RARRAY_LENINT(vkw_arg);
12185 size_t n = rb_callinfo_kwarg_bytes(len);
12186
12187 kw_arg = xmalloc(n);
12188 kw_arg->references = 0;
12189 kw_arg->keyword_len = len;
12190 for (i = 0; i < len; i++) {
12191 VALUE kw = RARRAY_AREF(vkw_arg, i);
12192 SYM2ID(kw); /* make immortal */
12193 kw_arg->keywords[i] = kw;
12194 }
12195 }
12196 }
12197
12198 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12199 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12200 return (VALUE)ci;
12201}
12202
12203static rb_event_flag_t
12204event_name_to_flag(VALUE sym)
12205{
12206#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12207 CHECK_EVENT(RUBY_EVENT_LINE);
12208 CHECK_EVENT(RUBY_EVENT_CLASS);
12209 CHECK_EVENT(RUBY_EVENT_END);
12210 CHECK_EVENT(RUBY_EVENT_CALL);
12211 CHECK_EVENT(RUBY_EVENT_RETURN);
12212 CHECK_EVENT(RUBY_EVENT_B_CALL);
12213 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12214 CHECK_EVENT(RUBY_EVENT_RESCUE);
12215#undef CHECK_EVENT
12216 return RUBY_EVENT_NONE;
12217}
12218
12219static int
12220iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12221 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12222{
12223 /* TODO: body should be frozen */
12224 long i, len = RARRAY_LEN(body);
12225 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12226 int j;
12227 int line_no = 0, node_id = -1, insn_idx = 0;
12228 int ret = COMPILE_OK;
12229
12230 /*
12231 * index -> LABEL *label
12232 */
12233 static struct st_table *insn_table;
12234
12235 if (insn_table == 0) {
12236 insn_table = insn_make_insn_table();
12237 }
12238
12239 for (i=0; i<len; i++) {
12240 VALUE obj = RARRAY_AREF(body, i);
12241
12242 if (SYMBOL_P(obj)) {
12243 rb_event_flag_t event;
12244 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12245 ADD_TRACE(anchor, event);
12246 }
12247 else {
12248 LABEL *label = register_label(iseq, labels_table, obj);
12249 ADD_LABEL(anchor, label);
12250 }
12251 }
12252 else if (FIXNUM_P(obj)) {
12253 line_no = NUM2INT(obj);
12254 }
12255 else if (RB_TYPE_P(obj, T_ARRAY)) {
12256 VALUE *argv = 0;
12257 int argc = RARRAY_LENINT(obj) - 1;
12258 st_data_t insn_id;
12259 VALUE insn;
12260
12261 if (node_ids) {
12262 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12263 }
12264
12265 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12266 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12267 /* TODO: exception */
12268 COMPILE_ERROR(iseq, line_no,
12269 "unknown instruction: %+"PRIsVALUE, insn);
12270 ret = COMPILE_NG;
12271 break;
12272 }
12273
12274 if (argc != insn_len((VALUE)insn_id)-1) {
12275 COMPILE_ERROR(iseq, line_no,
12276 "operand size mismatch");
12277 ret = COMPILE_NG;
12278 break;
12279 }
12280
12281 if (argc > 0) {
12282 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12283
12284 // add element before operand setup to make GC root
12285 ADD_ELEM(anchor,
12286 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12287 (enum ruby_vminsn_type)insn_id, argc, argv));
12288
12289 for (j=0; j<argc; j++) {
12290 VALUE op = rb_ary_entry(obj, j+1);
12291 switch (insn_op_type((VALUE)insn_id, j)) {
12292 case TS_OFFSET: {
12293 LABEL *label = register_label(iseq, labels_table, op);
12294 argv[j] = (VALUE)label;
12295 break;
12296 }
12297 case TS_LINDEX:
12298 case TS_NUM:
12299 (void)NUM2INT(op);
12300 argv[j] = op;
12301 break;
12302 case TS_VALUE:
12303 argv[j] = op;
12304 RB_OBJ_WRITTEN(iseq, Qundef, op);
12305 break;
12306 case TS_ISEQ:
12307 {
12308 if (op != Qnil) {
12309 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12310 argv[j] = v;
12311 RB_OBJ_WRITTEN(iseq, Qundef, v);
12312 }
12313 else {
12314 argv[j] = 0;
12315 }
12316 }
12317 break;
12318 case TS_ISE:
12319 argv[j] = op;
12320 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12321 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12322 }
12323 break;
12324 case TS_IC:
12325 {
12326 VALUE segments = rb_ary_new();
12327 op = rb_to_array_type(op);
12328
12329 for (int i = 0; i < RARRAY_LEN(op); i++) {
12330 VALUE sym = RARRAY_AREF(op, i);
12331 sym = rb_to_symbol_type(sym);
12332 rb_ary_push(segments, sym);
12333 }
12334
12335 RB_GC_GUARD(op);
12336 argv[j] = segments;
12337 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12338 ISEQ_BODY(iseq)->ic_size++;
12339 }
12340 break;
12341 case TS_IVC: /* inline ivar cache */
12342 argv[j] = op;
12343 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12344 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12345 }
12346 break;
12347 case TS_ICVARC: /* inline cvar cache */
12348 argv[j] = op;
12349 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12350 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12351 }
12352 break;
12353 case TS_CALLDATA:
12354 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12355 break;
12356 case TS_ID:
12357 argv[j] = rb_to_symbol_type(op);
12358 break;
12359 case TS_CDHASH:
12360 {
12361 int i;
12362 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12363
12364 op = rb_to_array_type(op);
12365 for (i=0; i<RARRAY_LEN(op); i+=2) {
12366 VALUE key = RARRAY_AREF(op, i);
12367 VALUE sym = RARRAY_AREF(op, i+1);
12368 LABEL *label =
12369 register_label(iseq, labels_table, sym);
12370 cdhash_aset(map, key, (VALUE)label);
12371 }
12372 RB_GC_GUARD(op);
12373 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12374 argv[j] = map;
12375 RB_OBJ_WRITTEN(iseq, Qundef, map);
12376 }
12377 break;
12378 case TS_FUNCPTR:
12379 {
12380#if SIZEOF_VALUE <= SIZEOF_LONG
12381 long funcptr = NUM2LONG(op);
12382#else
12383 LONG_LONG funcptr = NUM2LL(op);
12384#endif
12385 argv[j] = (VALUE)funcptr;
12386 }
12387 break;
12388 default:
12389 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12390 }
12391 }
12392 }
12393 else {
12394 ADD_ELEM(anchor,
12395 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12396 (enum ruby_vminsn_type)insn_id, argc, NULL));
12397 }
12398 }
12399 else {
12400 rb_raise(rb_eTypeError, "unexpected object for instruction");
12401 }
12402 }
12403 RTYPEDDATA_DATA(labels_wrapper) = 0;
12404 RB_GC_GUARD(labels_wrapper);
12405 validate_labels(iseq, labels_table);
12406 if (!ret) return ret;
12407 return iseq_setup(iseq, anchor);
12408}
12409
12410#define CHECK_ARRAY(v) rb_to_array_type(v)
12411#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12412
12413static int
12414int_param(int *dst, VALUE param, VALUE sym)
12415{
12416 VALUE val = rb_hash_aref(param, sym);
12417 if (FIXNUM_P(val)) {
12418 *dst = FIX2INT(val);
12419 return TRUE;
12420 }
12421 else if (!NIL_P(val)) {
12422 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12423 sym, val);
12424 }
12425 return FALSE;
12426}
12427
12428static const struct rb_iseq_param_keyword *
12429iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12430{
12431 int i, j;
12432 int len = RARRAY_LENINT(keywords);
12433 int default_len;
12434 VALUE key, sym, default_val;
12435 VALUE *dvs;
12436 ID *ids;
12437 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12438
12439 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12440
12441 keyword->num = len;
12442#define SYM(s) ID2SYM(rb_intern_const(#s))
12443 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12444 i = keyword->bits_start - keyword->num;
12445 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12446#undef SYM
12447
12448 /* required args */
12449 for (i = 0; i < len; i++) {
12450 VALUE val = RARRAY_AREF(keywords, i);
12451
12452 if (!SYMBOL_P(val)) {
12453 goto default_values;
12454 }
12455 ids[i] = SYM2ID(val);
12456 keyword->required_num++;
12457 }
12458
12459 default_values: /* note: we intentionally preserve `i' from previous loop */
12460 default_len = len - i;
12461 if (default_len == 0) {
12462 keyword->table = ids;
12463 return keyword;
12464 }
12465 else if (default_len < 0) {
12467 }
12468
12469 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12470
12471 for (j = 0; i < len; i++, j++) {
12472 key = RARRAY_AREF(keywords, i);
12473 CHECK_ARRAY(key);
12474
12475 switch (RARRAY_LEN(key)) {
12476 case 1:
12477 sym = RARRAY_AREF(key, 0);
12478 default_val = Qundef;
12479 break;
12480 case 2:
12481 sym = RARRAY_AREF(key, 0);
12482 default_val = RARRAY_AREF(key, 1);
12483 break;
12484 default:
12485 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12486 }
12487 ids[i] = SYM2ID(sym);
12488 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12489 }
12490
12491 keyword->table = ids;
12492 keyword->default_values = dvs;
12493
12494 return keyword;
12495}
12496
12497static void
12498iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12499{
12500 rb_gc_mark_and_move(obj);
12501}
12502
12503void
12504rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12505{
12506 INSN *iobj = 0;
12507 size_t size = sizeof(INSN);
12508 size_t align = ALIGNMENT_SIZE_OF(INSN);
12509 unsigned int pos = 0;
12510
12511 while (storage) {
12512 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12513 size_t offset = pos + size + padding;
12514 if (offset > storage->size || offset > storage->pos) {
12515 pos = 0;
12516 storage = storage->next;
12517 }
12518 else {
12519 pos += (int)padding;
12520
12521 iobj = (INSN *)&storage->buff[pos];
12522
12523 if (iobj->operands) {
12524 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12525 }
12526 pos += (int)size;
12527 }
12528 }
12529}
12530
12531static const rb_data_type_t labels_wrapper_type = {
12532 .wrap_struct_name = "compiler/labels_wrapper",
12533 .function = {
12534 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12535 .dfree = (RUBY_DATA_FUNC)st_free_table,
12536 },
12537 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12538};
12539
12540void
12541rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12542 VALUE exception, VALUE body)
12543{
12544#define SYM(s) ID2SYM(rb_intern_const(#s))
12545 int i, len;
12546 unsigned int arg_size, local_size, stack_max;
12547 ID *tbl;
12548 struct st_table *labels_table = st_init_numtable();
12549 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12550 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12551 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12552 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12553 DECL_ANCHOR(anchor);
12554 INIT_ANCHOR(anchor);
12555
12556 len = RARRAY_LENINT(locals);
12557 ISEQ_BODY(iseq)->local_table_size = len;
12558 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12559
12560 for (i = 0; i < len; i++) {
12561 VALUE lv = RARRAY_AREF(locals, i);
12562
12563 if (sym_arg_rest == lv) {
12564 tbl[i] = 0;
12565 }
12566 else {
12567 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12568 }
12569 }
12570
12571#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12572 if (INT_PARAM(lead_num)) {
12573 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12574 }
12575 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12576 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12577 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12578 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12579#undef INT_PARAM
12580 {
12581#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12582 int x;
12583 INT_PARAM(arg_size);
12584 INT_PARAM(local_size);
12585 INT_PARAM(stack_max);
12586#undef INT_PARAM
12587 }
12588
12589 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12590 if (!NIL_P(source_hash)) {
12591 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12592 }
12593
12594 VALUE node_ids = Qfalse;
12595#ifdef USE_ISEQ_NODE_ID
12596 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12597 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12598 rb_raise(rb_eTypeError, "node_ids is not an array");
12599 }
12600#endif
12601
12602 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12603 len = RARRAY_LENINT(arg_opt_labels);
12604 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12605
12606 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12607 VALUE *opt_table = ALLOC_N(VALUE, len);
12608
12609 for (i = 0; i < len; i++) {
12610 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12611 LABEL *label = register_label(iseq, labels_table, ent);
12612 opt_table[i] = (VALUE)label;
12613 }
12614
12615 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12616 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12617 }
12618 }
12619 else if (!NIL_P(arg_opt_labels)) {
12620 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12621 arg_opt_labels);
12622 }
12623
12624 if (RB_TYPE_P(keywords, T_ARRAY)) {
12625 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12626 }
12627 else if (!NIL_P(keywords)) {
12628 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12629 keywords);
12630 }
12631
12632 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12633 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12634 }
12635
12636 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12637 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12638 }
12639
12640 if (int_param(&i, params, SYM(kwrest))) {
12641 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12642 if (keyword == NULL) {
12643 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12644 }
12645 keyword->rest_start = i;
12646 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12647 }
12648#undef SYM
12649 iseq_calc_param_size(iseq);
12650
12651 /* exception */
12652 iseq_build_from_ary_exception(iseq, labels_table, exception);
12653
12654 /* body */
12655 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12656
12657 ISEQ_BODY(iseq)->param.size = arg_size;
12658 ISEQ_BODY(iseq)->local_table_size = local_size;
12659 ISEQ_BODY(iseq)->stack_max = stack_max;
12660}
12661
12662/* for parser */
12663
12664int
12665rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12666{
12667 if (iseq) {
12668 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12669 while (body->type == ISEQ_TYPE_BLOCK ||
12670 body->type == ISEQ_TYPE_RESCUE ||
12671 body->type == ISEQ_TYPE_ENSURE ||
12672 body->type == ISEQ_TYPE_EVAL ||
12673 body->type == ISEQ_TYPE_MAIN
12674 ) {
12675 unsigned int i;
12676
12677 for (i = 0; i < body->local_table_size; i++) {
12678 if (body->local_table[i] == id) {
12679 return 1;
12680 }
12681 }
12682 iseq = body->parent_iseq;
12683 body = ISEQ_BODY(iseq);
12684 }
12685 }
12686 return 0;
12687}
12688
12689int
12690rb_local_defined(ID id, const rb_iseq_t *iseq)
12691{
12692 if (iseq) {
12693 unsigned int i;
12694 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12695
12696 for (i=0; i<body->local_table_size; i++) {
12697 if (body->local_table[i] == id) {
12698 return 1;
12699 }
12700 }
12701 }
12702 return 0;
12703}
12704
12705/* ISeq binary format */
12706
12707#ifndef IBF_ISEQ_DEBUG
12708#define IBF_ISEQ_DEBUG 0
12709#endif
12710
12711#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12712#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12713#endif
12714
12715typedef uint32_t ibf_offset_t;
12716#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12717
12718#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12719#ifdef RUBY_DEVEL
12720#define IBF_DEVEL_VERSION 8
12721#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12722#else
12723#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12724#endif
12725
12726static const char IBF_ENDIAN_MARK =
12727#ifdef WORDS_BIGENDIAN
12728 'b'
12729#else
12730 'l'
12731#endif
12732 ;
12733
12735 char magic[4]; /* YARB */
12736 uint32_t major_version;
12737 uint32_t minor_version;
12738 uint32_t size;
12739 uint32_t extra_size;
12740
12741 uint32_t iseq_list_size;
12742 uint32_t global_object_list_size;
12743 ibf_offset_t iseq_list_offset;
12744 ibf_offset_t global_object_list_offset;
12745 uint8_t endian;
12746 uint8_t wordsize; /* assume no 2048-bit CPU */
12747};
12748
12750 VALUE str;
12751 st_table *obj_table; /* obj -> obj number */
12752};
12753
12754struct ibf_dump {
12755 st_table *iseq_table; /* iseq -> iseq number */
12756 struct ibf_dump_buffer global_buffer;
12757 struct ibf_dump_buffer *current_buffer;
12758};
12759
12761 const char *buff;
12762 ibf_offset_t size;
12763
12764 VALUE obj_list; /* [obj0, ...] */
12765 unsigned int obj_list_size;
12766 ibf_offset_t obj_list_offset;
12767};
12768
12769struct ibf_load {
12770 const struct ibf_header *header;
12771 VALUE iseq_list; /* [iseq0, ...] */
12772 struct ibf_load_buffer global_buffer;
12773 VALUE loader_obj;
12774 rb_iseq_t *iseq;
12775 VALUE str;
12776 struct ibf_load_buffer *current_buffer;
12777};
12778
12780 long size;
12781 VALUE buffer[1];
12782};
12783
12784static void
12785pinned_list_mark(void *ptr)
12786{
12787 long i;
12788 struct pinned_list *list = (struct pinned_list *)ptr;
12789 for (i = 0; i < list->size; i++) {
12790 if (list->buffer[i]) {
12791 rb_gc_mark(list->buffer[i]);
12792 }
12793 }
12794}
12795
12796static const rb_data_type_t pinned_list_type = {
12797 "pinned_list",
12798 {
12799 pinned_list_mark,
12801 NULL, // No external memory to report,
12802 },
12803 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12804};
12805
12806static VALUE
12807pinned_list_fetch(VALUE list, long offset)
12808{
12809 struct pinned_list * ptr;
12810
12811 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12812
12813 if (offset < 0 || offset >= ptr->size) {
12814 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12815 }
12816
12817 return ptr->buffer[offset];
12818}
12819
12820static void
12821pinned_list_store(VALUE list, long offset, VALUE object)
12822{
12823 struct pinned_list * ptr;
12824
12825 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12826
12827 if (offset < 0 || offset >= ptr->size) {
12828 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12829 }
12830
12831 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12832}
12833
12834static VALUE
12835pinned_list_new(long size)
12836{
12837 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12838 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12839 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12840 ptr->size = size;
12841 return obj_list;
12842}
12843
12844static ibf_offset_t
12845ibf_dump_pos(struct ibf_dump *dump)
12846{
12847 long pos = RSTRING_LEN(dump->current_buffer->str);
12848#if SIZEOF_LONG > SIZEOF_INT
12849 if (pos >= UINT_MAX) {
12850 rb_raise(rb_eRuntimeError, "dump size exceeds");
12851 }
12852#endif
12853 return (unsigned int)pos;
12854}
12855
12856static void
12857ibf_dump_align(struct ibf_dump *dump, size_t align)
12858{
12859 ibf_offset_t pos = ibf_dump_pos(dump);
12860 if (pos % align) {
12861 static const char padding[sizeof(VALUE)];
12862 size_t size = align - ((size_t)pos % align);
12863#if SIZEOF_LONG > SIZEOF_INT
12864 if (pos + size >= UINT_MAX) {
12865 rb_raise(rb_eRuntimeError, "dump size exceeds");
12866 }
12867#endif
12868 for (; size > sizeof(padding); size -= sizeof(padding)) {
12869 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12870 }
12871 rb_str_cat(dump->current_buffer->str, padding, size);
12872 }
12873}
12874
12875static ibf_offset_t
12876ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12877{
12878 ibf_offset_t pos = ibf_dump_pos(dump);
12879#if SIZEOF_LONG > SIZEOF_INT
12880 /* ensure the resulting dump does not exceed UINT_MAX */
12881 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12882 rb_raise(rb_eRuntimeError, "dump size exceeds");
12883 }
12884#endif
12885 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12886 return pos;
12887}
12888
12889static ibf_offset_t
12890ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12891{
12892 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12893}
12894
12895static void
12896ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12897{
12898 VALUE str = dump->current_buffer->str;
12899 char *ptr = RSTRING_PTR(str);
12900 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12901 rb_bug("ibf_dump_overwrite: overflow");
12902 memcpy(ptr + offset, buff, size);
12903}
12904
12905static const void *
12906ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12907{
12908 ibf_offset_t beg = *offset;
12909 *offset += size;
12910 return load->current_buffer->buff + beg;
12911}
12912
12913static void *
12914ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12915{
12916 void *buff = ruby_xmalloc2(x, y);
12917 size_t size = x * y;
12918 memcpy(buff, load->current_buffer->buff + offset, size);
12919 return buff;
12920}
12921
12922#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12923
12924#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12925#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12926#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12927#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12928#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12929
12930static int
12931ibf_table_lookup(struct st_table *table, st_data_t key)
12932{
12933 st_data_t val;
12934
12935 if (st_lookup(table, key, &val)) {
12936 return (int)val;
12937 }
12938 else {
12939 return -1;
12940 }
12941}
12942
12943static int
12944ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12945{
12946 int index = ibf_table_lookup(table, key);
12947
12948 if (index < 0) { /* not found */
12949 index = (int)table->num_entries;
12950 st_insert(table, key, (st_data_t)index);
12951 }
12952
12953 return index;
12954}
12955
12956/* dump/load generic */
12957
12958static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12959
12960static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12961static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12962
12963static st_table *
12964ibf_dump_object_table_new(void)
12965{
12966 st_table *obj_table = st_init_numtable(); /* need free */
12967 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12968
12969 return obj_table;
12970}
12971
12972static VALUE
12973ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12974{
12975 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12976}
12977
12978static VALUE
12979ibf_dump_id(struct ibf_dump *dump, ID id)
12980{
12981 if (id == 0 || rb_id2name(id) == NULL) {
12982 return 0;
12983 }
12984 return ibf_dump_object(dump, rb_id2sym(id));
12985}
12986
12987static ID
12988ibf_load_id(const struct ibf_load *load, const ID id_index)
12989{
12990 if (id_index == 0) {
12991 return 0;
12992 }
12993 VALUE sym = ibf_load_object(load, id_index);
12994 if (rb_integer_type_p(sym)) {
12995 /* Load hidden local variables as indexes */
12996 return NUM2ULONG(sym);
12997 }
12998 return rb_sym2id(sym);
12999}
13000
13001/* dump/load: code */
13002
13003static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
13004
13005static int
13006ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
13007{
13008 if (iseq == NULL) {
13009 return -1;
13010 }
13011 else {
13012 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
13013 }
13014}
13015
13016static unsigned char
13017ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
13018{
13019 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
13020 return (unsigned char)load->current_buffer->buff[(*offset)++];
13021}
13022
13023/*
13024 * Small uint serialization
13025 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
13026 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
13027 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
13028 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13029 * ...
13030 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13031 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13032 */
13033static void
13034ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
13035{
13036 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13037 ibf_dump_write(dump, &x, sizeof(VALUE));
13038 return;
13039 }
13040
13041 enum { max_byte_length = sizeof(VALUE) + 1 };
13042
13043 unsigned char bytes[max_byte_length];
13044 ibf_offset_t n;
13045
13046 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13047 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13048 }
13049
13050 x <<= 1;
13051 x |= 1;
13052 x <<= n;
13053 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13054 n++;
13055
13056 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13057}
13058
13059static VALUE
13060ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13061{
13062 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13063 union { char s[sizeof(VALUE)]; VALUE v; } x;
13064
13065 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13066 *offset += sizeof(VALUE);
13067
13068 return x.v;
13069 }
13070
13071 enum { max_byte_length = sizeof(VALUE) + 1 };
13072
13073 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13074 const unsigned char c = buffer[*offset];
13075
13076 ibf_offset_t n =
13077 c & 1 ? 1 :
13078 c == 0 ? 9 : ntz_int32(c) + 1;
13079 VALUE x = (VALUE)c >> n;
13080
13081 if (*offset + n > load->current_buffer->size) {
13082 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13083 }
13084
13085 ibf_offset_t i;
13086 for (i = 1; i < n; i++) {
13087 x <<= 8;
13088 x |= (VALUE)buffer[*offset + i];
13089 }
13090
13091 *offset += n;
13092 return x;
13093}
13094
13095static void
13096ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13097{
13098 // short: index
13099 // short: name.length
13100 // bytes: name
13101 // // omit argc (only verify with name)
13102 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13103
13104 size_t len = strlen(bf->name);
13105 ibf_dump_write_small_value(dump, (VALUE)len);
13106 ibf_dump_write(dump, bf->name, len);
13107}
13108
13109static const struct rb_builtin_function *
13110ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13111{
13112 int i = (int)ibf_load_small_value(load, offset);
13113 int len = (int)ibf_load_small_value(load, offset);
13114 const char *name = (char *)ibf_load_ptr(load, offset, len);
13115
13116 if (0) {
13117 fprintf(stderr, "%.*s!!\n", len, name);
13118 }
13119
13120 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13121 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13122 if (strncmp(table[i].name, name, len) != 0) {
13123 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13124 i, len, name, table[i].name);
13125 }
13126 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13127
13128 return &table[i];
13129}
13130
13131static ibf_offset_t
13132ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13133{
13134 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13135 const int iseq_size = body->iseq_size;
13136 int code_index;
13137 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13138
13139 ibf_offset_t offset = ibf_dump_pos(dump);
13140
13141 for (code_index=0; code_index<iseq_size;) {
13142 const VALUE insn = orig_code[code_index++];
13143 const char *types = insn_op_types(insn);
13144 int op_index;
13145
13146 /* opcode */
13147 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13148 ibf_dump_write_small_value(dump, insn);
13149
13150 /* operands */
13151 for (op_index=0; types[op_index]; op_index++, code_index++) {
13152 VALUE op = orig_code[code_index];
13153 VALUE wv;
13154
13155 switch (types[op_index]) {
13156 case TS_CDHASH:
13157 case TS_VALUE:
13158 wv = ibf_dump_object(dump, op);
13159 break;
13160 case TS_ISEQ:
13161 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13162 break;
13163 case TS_IC:
13164 {
13165 IC ic = (IC)op;
13166 VALUE arr = idlist_to_array(ic->segments);
13167 wv = ibf_dump_object(dump, arr);
13168 }
13169 break;
13170 case TS_ISE:
13171 case TS_IVC:
13172 case TS_ICVARC:
13173 {
13175 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13176 }
13177 break;
13178 case TS_CALLDATA:
13179 {
13180 goto skip_wv;
13181 }
13182 case TS_ID:
13183 wv = ibf_dump_id(dump, (ID)op);
13184 break;
13185 case TS_FUNCPTR:
13186 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13187 goto skip_wv;
13188 case TS_BUILTIN:
13189 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13190 goto skip_wv;
13191 default:
13192 wv = op;
13193 break;
13194 }
13195 ibf_dump_write_small_value(dump, wv);
13196 skip_wv:;
13197 }
13198 RUBY_ASSERT(insn_len(insn) == op_index+1);
13199 }
13200
13201 return offset;
13202}
13203
13204static VALUE *
13205ibf_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)
13206{
13207 VALUE iseqv = (VALUE)iseq;
13208 unsigned int code_index;
13209 ibf_offset_t reading_pos = bytecode_offset;
13210 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13211
13212 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13213 struct rb_call_data *cd_entries = load_body->call_data;
13214 int ic_index = 0;
13215
13216 load_body->iseq_encoded = code;
13217 load_body->iseq_size = iseq_size;
13218
13219 iseq_bits_t * mark_offset_bits;
13220 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13221 load_body->mark_bits.single = 0;
13222 mark_offset_bits = &load_body->mark_bits.single;
13223 }
13224 else {
13225 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13226 mark_offset_bits = load_body->mark_bits.list;
13227 }
13228 bool needs_bitmap = false;
13229
13230 for (code_index=0; code_index<iseq_size;) {
13231 /* opcode */
13232 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13233 const char *types = insn_op_types(insn);
13234 int op_index;
13235
13236 code_index++;
13237
13238 /* operands */
13239 for (op_index=0; types[op_index]; op_index++, code_index++) {
13240 const char operand_type = types[op_index];
13241 switch (operand_type) {
13242 case TS_VALUE:
13243 {
13244 VALUE op = ibf_load_small_value(load, &reading_pos);
13245 VALUE v = ibf_load_object(load, op);
13246 code[code_index] = v;
13247 if (!SPECIAL_CONST_P(v)) {
13248 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13249 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13250 needs_bitmap = true;
13251 }
13252 break;
13253 }
13254 case TS_CDHASH:
13255 {
13256 VALUE op = ibf_load_small_value(load, &reading_pos);
13257 VALUE v = ibf_load_object(load, op);
13258
13259 // Overwrite the existing hash in the object list. This
13260 // is to keep the object alive during load time.
13261 // [Bug #17984] [ruby-core:104259]
13262 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13263
13264 code[code_index] = v;
13265 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13266 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13267 needs_bitmap = true;
13268 break;
13269 }
13270 case TS_ISEQ:
13271 {
13272 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13273 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13274 code[code_index] = v;
13275 if (!SPECIAL_CONST_P(v)) {
13276 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13277 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13278 needs_bitmap = true;
13279 }
13280 break;
13281 }
13282 case TS_IC:
13283 {
13284 VALUE op = ibf_load_small_value(load, &reading_pos);
13285 VALUE arr = ibf_load_object(load, op);
13286
13287 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13288 ic->segments = array_to_idlist(arr);
13289
13290 code[code_index] = (VALUE)ic;
13291 }
13292 break;
13293 case TS_ISE:
13294 case TS_ICVARC:
13295 case TS_IVC:
13296 {
13297 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13298
13299 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13300 code[code_index] = (VALUE)ic;
13301
13302 if (operand_type == TS_IVC) {
13303 IVC cache = (IVC)ic;
13304
13305 if (insn == BIN(setinstancevariable)) {
13306 ID iv_name = (ID)code[code_index - 1];
13307 cache->iv_set_name = iv_name;
13308 cache->value = IVAR_CACHE_INIT;
13309 }
13310 else {
13311 cache->iv_set_name = 0;
13312 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13313 }
13314 }
13315
13316 }
13317 break;
13318 case TS_CALLDATA:
13319 {
13320 code[code_index] = (VALUE)cd_entries++;
13321 }
13322 break;
13323 case TS_ID:
13324 {
13325 VALUE op = ibf_load_small_value(load, &reading_pos);
13326 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13327 }
13328 break;
13329 case TS_FUNCPTR:
13330 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13331 break;
13332 case TS_BUILTIN:
13333 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13334 break;
13335 default:
13336 code[code_index] = ibf_load_small_value(load, &reading_pos);
13337 continue;
13338 }
13339 }
13340 if (insn_len(insn) != op_index+1) {
13341 rb_raise(rb_eRuntimeError, "operand size mismatch");
13342 }
13343 }
13344
13345 if (!needs_bitmap) {
13346 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13347 load_body->mark_bits.list = NULL;
13348 }
13349
13350 RUBY_ASSERT(code_index == iseq_size);
13351 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13352 return code;
13353}
13354
13355static ibf_offset_t
13356ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13357{
13358 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13359
13360 if (opt_num > 0) {
13361 IBF_W_ALIGN(VALUE);
13362 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13363 }
13364 else {
13365 return ibf_dump_pos(dump);
13366 }
13367}
13368
13369static VALUE *
13370ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13371{
13372 if (opt_num > 0) {
13373 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13374 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13375 return table;
13376 }
13377 else {
13378 return NULL;
13379 }
13380}
13381
13382static ibf_offset_t
13383ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13384{
13385 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13386
13387 if (kw) {
13388 struct rb_iseq_param_keyword dump_kw = *kw;
13389 int dv_num = kw->num - kw->required_num;
13390 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13391 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13392 int i;
13393
13394 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13395 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13396
13397 dump_kw.table = IBF_W(ids, ID, kw->num);
13398 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13399 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13400 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13401 }
13402 else {
13403 return 0;
13404 }
13405}
13406
13407static const struct rb_iseq_param_keyword *
13408ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13409{
13410 if (param_keyword_offset) {
13411 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13412 int dv_num = kw->num - kw->required_num;
13413 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13414
13415 int i;
13416 for (i=0; i<dv_num; i++) {
13417 dvs[i] = ibf_load_object(load, dvs[i]);
13418 }
13419
13420 // Will be set once the local table is loaded.
13421 kw->table = NULL;
13422
13423 kw->default_values = dvs;
13424 return kw;
13425 }
13426 else {
13427 return NULL;
13428 }
13429}
13430
13431static ibf_offset_t
13432ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13433{
13434 ibf_offset_t offset = ibf_dump_pos(dump);
13435 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13436
13437 unsigned int i;
13438 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13439 ibf_dump_write_small_value(dump, entries[i].line_no);
13440#ifdef USE_ISEQ_NODE_ID
13441 ibf_dump_write_small_value(dump, entries[i].node_id);
13442#endif
13443 ibf_dump_write_small_value(dump, entries[i].events);
13444 }
13445
13446 return offset;
13447}
13448
13449static struct iseq_insn_info_entry *
13450ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13451{
13452 ibf_offset_t reading_pos = body_offset;
13453 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13454
13455 unsigned int i;
13456 for (i = 0; i < size; i++) {
13457 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13458#ifdef USE_ISEQ_NODE_ID
13459 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13460#endif
13461 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13462 }
13463
13464 return entries;
13465}
13466
13467static ibf_offset_t
13468ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13469{
13470 ibf_offset_t offset = ibf_dump_pos(dump);
13471
13472 unsigned int last = 0;
13473 unsigned int i;
13474 for (i = 0; i < size; i++) {
13475 ibf_dump_write_small_value(dump, positions[i] - last);
13476 last = positions[i];
13477 }
13478
13479 return offset;
13480}
13481
13482static unsigned int *
13483ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13484{
13485 ibf_offset_t reading_pos = positions_offset;
13486 unsigned int *positions = ALLOC_N(unsigned int, size);
13487
13488 unsigned int last = 0;
13489 unsigned int i;
13490 for (i = 0; i < size; i++) {
13491 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13492 last = positions[i];
13493 }
13494
13495 return positions;
13496}
13497
13498static ibf_offset_t
13499ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13500{
13501 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13502 const int size = body->local_table_size;
13503 ID *table = ALLOCA_N(ID, size);
13504 int i;
13505
13506 for (i=0; i<size; i++) {
13507 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13508 if (v == 0) {
13509 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13510 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13511 }
13512 table[i] = v;
13513 }
13514
13515 IBF_W_ALIGN(ID);
13516 return ibf_dump_write(dump, table, sizeof(ID) * size);
13517}
13518
13519static const ID *
13520ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13521{
13522 if (size > 0) {
13523 ID *table = IBF_R(local_table_offset, ID, size);
13524 int i;
13525
13526 for (i=0; i<size; i++) {
13527 table[i] = ibf_load_id(load, table[i]);
13528 }
13529
13530 if (size == 1 && table[0] == idERROR_INFO) {
13531 ruby_xfree_sized(table, sizeof(ID) * size);
13532 return rb_iseq_shared_exc_local_tbl;
13533 }
13534 else {
13535 return table;
13536 }
13537 }
13538 else {
13539 return NULL;
13540 }
13541}
13542
13543static ibf_offset_t
13544ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13545{
13546 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13547 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13548 IBF_W_ALIGN(uint8_t);
13549 if (iseq_has_lvar_states_p(body)) {
13550 return ibf_dump_write(dump, iseq_lvar_states(body), sizeof(uint8_t) * size);
13551 }
13552 else {
13553 return ibf_dump_write(dump, NULL, 0);
13554 }
13555}
13556
13557static void
13558ibf_load_lvar_states(const struct ibf_load *load, struct rb_iseq_constant_body *load_body, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13559{
13560 if (local_table == rb_iseq_shared_exc_local_tbl ||
13561 size <= 0) {
13562 load_body->lvar_states.list = NULL;
13563 }
13564 else if (ISEQ_LVAR_STATES_EMBED_P((unsigned int)size)) {
13565 ibf_offset_t pos = lvar_states_offset;
13566 const int len = sizeof(uint8_t) * ISEQ_LVAR_STATES_BUFLEN(size);
13567 memcpy(load_body->lvar_states.single, ibf_load_ptr(load, &pos, len), len);
13568 }
13569 else {
13570 load_body->lvar_states.list = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13571 }
13572}
13573
13574static ibf_offset_t
13575ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13576{
13577 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13578
13579 if (table) {
13580 int *iseq_indices = ALLOCA_N(int, table->size);
13581 unsigned int i;
13582
13583 for (i=0; i<table->size; i++) {
13584 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13585 }
13586
13587 const ibf_offset_t offset = ibf_dump_pos(dump);
13588
13589 for (i=0; i<table->size; i++) {
13590 ibf_dump_write_small_value(dump, iseq_indices[i]);
13591 ibf_dump_write_small_value(dump, table->entries[i].type);
13592 ibf_dump_write_small_value(dump, table->entries[i].start);
13593 ibf_dump_write_small_value(dump, table->entries[i].end);
13594 ibf_dump_write_small_value(dump, table->entries[i].cont);
13595 ibf_dump_write_small_value(dump, table->entries[i].sp);
13596 }
13597 return offset;
13598 }
13599 else {
13600 return ibf_dump_pos(dump);
13601 }
13602}
13603
13604static void
13605ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13606{
13607 if (size) {
13608 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13609 table->size = size;
13610 ISEQ_BODY(parent_iseq)->catch_table = table;
13611
13612 ibf_offset_t reading_pos = catch_table_offset;
13613
13614 unsigned int i;
13615 for (i=0; i<table->size; i++) {
13616 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13617 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13618 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13619 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13620 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13621 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13622
13623 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13624 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13625 }
13626 }
13627 else {
13628 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13629 }
13630}
13631
13632static ibf_offset_t
13633ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13634{
13635 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13636 const unsigned int ci_size = body->ci_size;
13637 const struct rb_call_data *cds = body->call_data;
13638
13639 ibf_offset_t offset = ibf_dump_pos(dump);
13640
13641 unsigned int i;
13642
13643 for (i = 0; i < ci_size; i++) {
13644 const struct rb_callinfo *ci = cds[i].ci;
13645 if (ci != NULL) {
13646 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13647 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13648 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13649
13650 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13651 if (kwarg) {
13652 int len = kwarg->keyword_len;
13653 ibf_dump_write_small_value(dump, len);
13654 for (int j=0; j<len; j++) {
13655 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13656 ibf_dump_write_small_value(dump, keyword);
13657 }
13658 }
13659 else {
13660 ibf_dump_write_small_value(dump, 0);
13661 }
13662 }
13663 else {
13664 // TODO: truncate NULL ci from call_data.
13665 ibf_dump_write_small_value(dump, (VALUE)-1);
13666 }
13667 }
13668
13669 return offset;
13670}
13671
13673 ID id;
13674 VALUE name;
13675 VALUE val;
13676};
13677
13679 size_t num;
13680 struct outer_variable_pair pairs[1];
13681};
13682
13683static enum rb_id_table_iterator_result
13684store_outer_variable(ID id, VALUE val, void *dump)
13685{
13686 struct outer_variable_list *ovlist = dump;
13687 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13688 pair->id = id;
13689 pair->name = rb_id2str(id);
13690 pair->val = val;
13691 return ID_TABLE_CONTINUE;
13692}
13693
13694static int
13695outer_variable_cmp(const void *a, const void *b, void *arg)
13696{
13697 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13698 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13699
13700 if (!ap->name) {
13701 return -1;
13702 }
13703 else if (!bp->name) {
13704 return 1;
13705 }
13706
13707 return rb_str_cmp(ap->name, bp->name);
13708}
13709
13710static ibf_offset_t
13711ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13712{
13713 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13714
13715 ibf_offset_t offset = ibf_dump_pos(dump);
13716
13717 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13718 ibf_dump_write_small_value(dump, (VALUE)size);
13719 if (size > 0) {
13720 VALUE buff;
13721 size_t buffsize =
13722 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13723 offsetof(struct outer_variable_list, pairs),
13724 rb_eArgError);
13725 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13726 ovlist->num = 0;
13727 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13728 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13729 for (size_t i = 0; i < size; ++i) {
13730 ID id = ovlist->pairs[i].id;
13731 ID val = ovlist->pairs[i].val;
13732 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13733 ibf_dump_write_small_value(dump, val);
13734 }
13735 }
13736
13737 return offset;
13738}
13739
13740/* note that we dump out rb_call_info but load back rb_call_data */
13741static void
13742ibf_load_ci_entries(const struct ibf_load *load,
13743 ibf_offset_t ci_entries_offset,
13744 unsigned int ci_size,
13745 struct rb_call_data **cd_ptr)
13746{
13747 if (!ci_size) {
13748 *cd_ptr = NULL;
13749 return;
13750 }
13751
13752 ibf_offset_t reading_pos = ci_entries_offset;
13753
13754 unsigned int i;
13755
13756 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13757 *cd_ptr = cds;
13758
13759 for (i = 0; i < ci_size; i++) {
13760 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13761 if (mid_index != (VALUE)-1) {
13762 ID mid = ibf_load_id(load, mid_index);
13763 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13764 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13765
13766 struct rb_callinfo_kwarg *kwarg = NULL;
13767 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13768 if (kwlen > 0) {
13769 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13770 kwarg->references = 0;
13771 kwarg->keyword_len = kwlen;
13772 for (int j=0; j<kwlen; j++) {
13773 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13774 kwarg->keywords[j] = ibf_load_object(load, keyword);
13775 }
13776 }
13777
13778 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13779 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13780 cds[i].cc = vm_cc_empty();
13781 }
13782 else {
13783 // NULL ci
13784 cds[i].ci = NULL;
13785 cds[i].cc = NULL;
13786 }
13787 }
13788}
13789
13790static struct rb_id_table *
13791ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13792{
13793 ibf_offset_t reading_pos = outer_variables_offset;
13794
13795 struct rb_id_table *tbl = NULL;
13796
13797 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13798
13799 if (table_size > 0) {
13800 tbl = rb_id_table_create(table_size);
13801 }
13802
13803 for (size_t i = 0; i < table_size; i++) {
13804 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13805 VALUE value = ibf_load_small_value(load, &reading_pos);
13806 if (!key) key = rb_make_temporary_id(i);
13807 rb_id_table_insert(tbl, key, value);
13808 }
13809
13810 return tbl;
13811}
13812
13813static ibf_offset_t
13814ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13815{
13816 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13817
13818 unsigned int *positions;
13819
13820 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13821
13822 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13823 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13824
13825#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13826 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13827
13828 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13829 struct ibf_dump_buffer buffer;
13830 buffer.str = rb_str_new(0, 0);
13831 buffer.obj_table = ibf_dump_object_table_new();
13832 dump->current_buffer = &buffer;
13833#endif
13834
13835 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13836 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13837 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13838 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13839 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13840
13841 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13842 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13843 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13844
13845 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13846 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13847 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13848 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13849 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13850 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13851 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13852 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13853 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13854 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13855
13856#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13857 ibf_offset_t local_obj_list_offset;
13858 unsigned int local_obj_list_size;
13859
13860 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13861#endif
13862
13863 ibf_offset_t body_offset = ibf_dump_pos(dump);
13864
13865 /* dump the constant body */
13866 unsigned int param_flags =
13867 (body->param.flags.has_lead << 0) |
13868 (body->param.flags.has_opt << 1) |
13869 (body->param.flags.has_rest << 2) |
13870 (body->param.flags.has_post << 3) |
13871 (body->param.flags.has_kw << 4) |
13872 (body->param.flags.has_kwrest << 5) |
13873 (body->param.flags.has_block << 6) |
13874 (body->param.flags.ambiguous_param0 << 7) |
13875 (body->param.flags.accepts_no_kwarg << 8) |
13876 (body->param.flags.ruby2_keywords << 9) |
13877 (body->param.flags.anon_rest << 10) |
13878 (body->param.flags.anon_kwrest << 11) |
13879 (body->param.flags.use_block << 12) |
13880 (body->param.flags.forwardable << 13) |
13881 (body->param.flags.accepts_no_block << 14);
13882
13883#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13884# define IBF_BODY_OFFSET(x) (x)
13885#else
13886# define IBF_BODY_OFFSET(x) (body_offset - (x))
13887#endif
13888
13889 ibf_dump_write_small_value(dump, body->type);
13890 ibf_dump_write_small_value(dump, body->iseq_size);
13891 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13892 ibf_dump_write_small_value(dump, bytecode_size);
13893 ibf_dump_write_small_value(dump, param_flags);
13894 ibf_dump_write_small_value(dump, body->param.size);
13895 ibf_dump_write_small_value(dump, body->param.lead_num);
13896 ibf_dump_write_small_value(dump, body->param.opt_num);
13897 ibf_dump_write_small_value(dump, body->param.rest_start);
13898 ibf_dump_write_small_value(dump, body->param.post_start);
13899 ibf_dump_write_small_value(dump, body->param.post_num);
13900 ibf_dump_write_small_value(dump, body->param.block_start);
13901 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13902 ibf_dump_write_small_value(dump, param_keyword_offset);
13903 ibf_dump_write_small_value(dump, location_pathobj_index);
13904 ibf_dump_write_small_value(dump, location_label_index);
13905 ibf_dump_write_small_value(dump, body->location.first_lineno);
13906 ibf_dump_write_small_value(dump, body->location.node_id);
13907 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
13908 * VALUE may be 32 bits wide. */
13909 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
13910 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
13911 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13912 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13913 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13914 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13915 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13916 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13917 ibf_dump_write_small_value(dump, body->insns_info.size);
13918 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13919 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13920 ibf_dump_write_small_value(dump, catch_table_size);
13921 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13922 ibf_dump_write_small_value(dump, parent_iseq_index);
13923 ibf_dump_write_small_value(dump, local_iseq_index);
13924 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13925 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13926 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13927 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
13928 ibf_dump_write_small_value(dump, body->local_table_size);
13929 ibf_dump_write_small_value(dump, body->ivc_size);
13930 ibf_dump_write_small_value(dump, body->icvarc_size);
13931 ibf_dump_write_small_value(dump, body->ise_size);
13932 ibf_dump_write_small_value(dump, body->ic_size);
13933 ibf_dump_write_small_value(dump, body->ci_size);
13934 ibf_dump_write_small_value(dump, body->stack_max);
13935 ibf_dump_write_small_value(dump, body->builtin_attrs);
13936 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13937
13938#undef IBF_BODY_OFFSET
13939
13940#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13941 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13942
13943 dump->current_buffer = saved_buffer;
13944 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13945
13946 ibf_offset_t offset = ibf_dump_pos(dump);
13947 ibf_dump_write_small_value(dump, iseq_start);
13948 ibf_dump_write_small_value(dump, iseq_length_bytes);
13949 ibf_dump_write_small_value(dump, body_offset);
13950
13951 ibf_dump_write_small_value(dump, local_obj_list_offset);
13952 ibf_dump_write_small_value(dump, local_obj_list_size);
13953
13954 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13955
13956 return offset;
13957#else
13958 return body_offset;
13959#endif
13960}
13961
13962static VALUE
13963ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13964{
13965 VALUE str = ibf_load_object(load, str_index);
13966 if (str != Qnil) {
13967 str = rb_fstring(str);
13968 }
13969 return str;
13970}
13971
13972static void
13973ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13974{
13975 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13976
13977 ibf_offset_t reading_pos = offset;
13978
13979#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13980 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13981 load->current_buffer = &load->global_buffer;
13982
13983 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13984 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13985 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13986
13987 struct ibf_load_buffer buffer;
13988 buffer.buff = load->global_buffer.buff + iseq_start;
13989 buffer.size = iseq_length_bytes;
13990 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13991 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13992 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13993
13994 load->current_buffer = &buffer;
13995 reading_pos = body_offset;
13996#endif
13997
13998#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13999# define IBF_BODY_OFFSET(x) (x)
14000#else
14001# define IBF_BODY_OFFSET(x) (offset - (x))
14002#endif
14003
14004 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
14005 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14006 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14007 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14008 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
14009 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14010 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
14011 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
14012 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
14013 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
14014 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
14015 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
14016 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14017 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14018 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
14019 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
14020 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
14021 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
14022 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
14023 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
14024 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
14025 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14026 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14027 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14028 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14029 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14030 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14031 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14032 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14033 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14034 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14035 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14036 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14037 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14038 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14039 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14040 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14041 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
14042 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14043
14044 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14045 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14046 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14047 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14048
14049 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14050 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14051 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14052 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14053
14054 // setup fname and dummy frame
14055 VALUE path = ibf_load_object(load, location_pathobj_index);
14056 {
14057 VALUE realpath = Qnil;
14058
14059 if (RB_TYPE_P(path, T_STRING)) {
14060 realpath = path = rb_fstring(path);
14061 }
14062 else if (RB_TYPE_P(path, T_ARRAY)) {
14063 VALUE pathobj = path;
14064 if (RARRAY_LEN(pathobj) != 2) {
14065 rb_raise(rb_eRuntimeError, "path object size mismatch");
14066 }
14067 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14068 realpath = RARRAY_AREF(pathobj, 1);
14069 if (!NIL_P(realpath)) {
14070 if (!RB_TYPE_P(realpath, T_STRING)) {
14071 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14072 "(%x), path=%+"PRIsVALUE,
14073 realpath, TYPE(realpath), path);
14074 }
14075 realpath = rb_fstring(realpath);
14076 }
14077 }
14078 else {
14079 rb_raise(rb_eRuntimeError, "unexpected path object");
14080 }
14081 rb_iseq_pathobj_set(iseq, path, realpath);
14082 }
14083
14084 // push dummy frame
14085 rb_execution_context_t *ec = GET_EC();
14086 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14087
14088#undef IBF_BODY_OFFSET
14089
14090 load_body->type = type;
14091 load_body->stack_max = stack_max;
14092 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14093 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14094 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14095 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14096 load_body->param.flags.has_kw = FALSE;
14097 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14098 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14099 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14100 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14101 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14102 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14103 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14104 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14105 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14106 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14107 load_body->param.size = param_size;
14108 load_body->param.lead_num = param_lead_num;
14109 load_body->param.opt_num = param_opt_num;
14110 load_body->param.rest_start = param_rest_start;
14111 load_body->param.post_start = param_post_start;
14112 load_body->param.post_num = param_post_num;
14113 load_body->param.block_start = param_block_start;
14114 load_body->local_table_size = local_table_size;
14115 load_body->ci_size = ci_size;
14116 load_body->insns_info.size = insns_info_size;
14117
14118 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14119 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14120 if (variable_flip_count) {
14121 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14122 v->flip_count = variable_flip_count;
14123 }
14124
14125 load_body->location.first_lineno = location_first_lineno;
14126 load_body->location.node_id = location_node_id;
14127 load_body->source_hash = source_hash;
14128 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14129 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14130 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14131 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14132 load_body->builtin_attrs = builtin_attrs;
14133 load_body->prism = prism;
14134
14135 load_body->ivc_size = ivc_size;
14136 load_body->icvarc_size = icvarc_size;
14137 load_body->ise_size = ise_size;
14138 load_body->ic_size = ic_size;
14139
14140 if (ISEQ_IS_SIZE(load_body)) {
14141 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14142 }
14143 else {
14144 load_body->is_entries = NULL;
14145 }
14146 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14147 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14148 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14149 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14150 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14151 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
14152 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14153 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14154 ibf_load_lvar_states(load, load_body, lvar_states_offset, local_table_size, load_body->local_table);
14155 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14156
14157 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14158 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14159 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14160
14161 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14162 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14163 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14164
14165 // This must be done after the local table is loaded.
14166 if (load_body->param.keyword != NULL) {
14167 RUBY_ASSERT(load_body->local_table);
14168 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14169 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14170 }
14171
14172 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14173#if VM_INSN_INFO_TABLE_IMPL == 2
14174 rb_iseq_insns_info_encode_positions(iseq);
14175#endif
14176
14177 rb_iseq_translate_threaded_code(iseq);
14178
14179#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14180 load->current_buffer = &load->global_buffer;
14181#endif
14182
14183 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14184
14185#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14186 load->current_buffer = saved_buffer;
14187#endif
14188 verify_call_cache(iseq);
14189
14190 RB_GC_GUARD(dummy_frame);
14191 rb_vm_pop_frame_no_int(ec);
14192}
14193
14195{
14196 struct ibf_dump *dump;
14197 VALUE offset_list;
14198};
14199
14200static int
14201ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14202{
14203 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14204 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14205
14206 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14207 rb_ary_push(args->offset_list, UINT2NUM(offset));
14208
14209 return ST_CONTINUE;
14210}
14211
14212static void
14213ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14214{
14215 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14216
14217 struct ibf_dump_iseq_list_arg args;
14218 args.dump = dump;
14219 args.offset_list = offset_list;
14220
14221 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14222
14223 st_index_t i;
14224 st_index_t size = dump->iseq_table->num_entries;
14225 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14226
14227 for (i = 0; i < size; i++) {
14228 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14229 }
14230
14231 ibf_dump_align(dump, sizeof(ibf_offset_t));
14232 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14233 header->iseq_list_size = (unsigned int)size;
14234}
14235
14236/*
14237 * Binary format
14238 * - ibf_object_header
14239 * - ibf_object_xxx (xxx is type)
14240 */
14241
14243 unsigned int type: 5;
14244 unsigned int special_const: 1;
14245 unsigned int frozen: 1;
14246 unsigned int internal: 1;
14247};
14248
14249enum ibf_object_class_index {
14250 IBF_OBJECT_CLASS_OBJECT,
14251 IBF_OBJECT_CLASS_ARRAY,
14252 IBF_OBJECT_CLASS_STANDARD_ERROR,
14253 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14254 IBF_OBJECT_CLASS_TYPE_ERROR,
14255 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14256};
14257
14259 long srcstr;
14260 char option;
14261};
14262
14264 long len;
14265 long keyval[FLEX_ARY_LEN];
14266};
14267
14269 long class_index;
14270 long len;
14271 long beg;
14272 long end;
14273 int excl;
14274};
14275
14277 ssize_t slen;
14278 BDIGIT digits[FLEX_ARY_LEN];
14279};
14280
14281enum ibf_object_data_type {
14282 IBF_OBJECT_DATA_ENCODING,
14283};
14284
14286 long a, b;
14287};
14288
14290 long str;
14291};
14292
14293#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14294 ((((offset) - 1) / (align) + 1) * (align))
14295/* No cast, since it's UB to create an unaligned pointer.
14296 * Leave as void* for use with memcpy in those cases.
14297 * We align the offset, but the buffer pointer is only VALUE aligned,
14298 * so the returned pointer may be unaligned for `type` .*/
14299#define IBF_OBJBODY(type, offset) \
14300 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14301
14302static const void *
14303ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14304{
14305 if (offset >= load->current_buffer->size) {
14306 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14307 }
14308 return load->current_buffer->buff + offset;
14309}
14310
14311NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14312
14313static void
14314ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14315{
14316 char buff[0x100];
14317 rb_raw_obj_info(buff, sizeof(buff), obj);
14318 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14319}
14320
14321NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14322
14323static VALUE
14324ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14325{
14326 rb_raise(rb_eArgError, "unsupported");
14328}
14329
14330static void
14331ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14332{
14333 enum ibf_object_class_index cindex;
14334 if (obj == rb_cObject) {
14335 cindex = IBF_OBJECT_CLASS_OBJECT;
14336 }
14337 else if (obj == rb_cArray) {
14338 cindex = IBF_OBJECT_CLASS_ARRAY;
14339 }
14340 else if (obj == rb_eStandardError) {
14341 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14342 }
14343 else if (obj == rb_eNoMatchingPatternError) {
14344 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14345 }
14346 else if (obj == rb_eTypeError) {
14347 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14348 }
14349 else if (obj == rb_eNoMatchingPatternKeyError) {
14350 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14351 }
14352 else {
14353 rb_obj_info_dump(obj);
14354 rb_p(obj);
14355 rb_bug("unsupported class");
14356 }
14357 ibf_dump_write_small_value(dump, (VALUE)cindex);
14358}
14359
14360static VALUE
14361ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14362{
14363 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14364
14365 switch (cindex) {
14366 case IBF_OBJECT_CLASS_OBJECT:
14367 return rb_cObject;
14368 case IBF_OBJECT_CLASS_ARRAY:
14369 return rb_cArray;
14370 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14371 return rb_eStandardError;
14372 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14374 case IBF_OBJECT_CLASS_TYPE_ERROR:
14375 return rb_eTypeError;
14376 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14378 }
14379
14380 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14381}
14382
14383
14384static void
14385ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14386{
14387 double dbl = RFLOAT_VALUE(obj);
14388 (void)IBF_W(&dbl, double, 1);
14389}
14390
14391static VALUE
14392ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14393{
14394 double d;
14395 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14396 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14397 VALUE f = DBL2NUM(d);
14398 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14399 return f;
14400}
14401
14402static void
14403ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14404{
14405 long encindex = (long)rb_enc_get_index(obj);
14406 long len = RSTRING_LEN(obj);
14407 const char *ptr = RSTRING_PTR(obj);
14408
14409 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14410 rb_encoding *enc = rb_enc_from_index((int)encindex);
14411 const char *enc_name = rb_enc_name(enc);
14412 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14413 }
14414
14415 ibf_dump_write_small_value(dump, encindex);
14416 ibf_dump_write_small_value(dump, len);
14417 IBF_WP(ptr, char, len);
14418}
14419
14420static VALUE
14421ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14422{
14423 ibf_offset_t reading_pos = offset;
14424
14425 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14426 const long len = (long)ibf_load_small_value(load, &reading_pos);
14427 const char *ptr = load->current_buffer->buff + reading_pos;
14428
14429 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14430 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14431 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14432 }
14433
14434 VALUE str;
14435 if (header->frozen && !header->internal) {
14436 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14437 }
14438 else {
14439 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14440
14441 if (header->internal) rb_obj_hide(str);
14442 if (header->frozen) str = rb_fstring(str);
14443 }
14444 return str;
14445}
14446
14447static void
14448ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14449{
14450 VALUE srcstr = RREGEXP_SRC(obj);
14451 struct ibf_object_regexp regexp;
14452 regexp.option = (char)rb_reg_options(obj);
14453 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14454
14455 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14456 ibf_dump_write_small_value(dump, regexp.srcstr);
14457}
14458
14459static VALUE
14460ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14461{
14462 struct ibf_object_regexp regexp;
14463 regexp.option = ibf_load_byte(load, &offset);
14464 regexp.srcstr = ibf_load_small_value(load, &offset);
14465
14466 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14467 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14468
14469 if (header->internal) rb_obj_hide(reg);
14470 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14471
14472 return reg;
14473}
14474
14475static void
14476ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14477{
14478 long i, len = RARRAY_LEN(obj);
14479 ibf_dump_write_small_value(dump, len);
14480 for (i=0; i<len; i++) {
14481 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14482 ibf_dump_write_small_value(dump, index);
14483 }
14484}
14485
14486static VALUE
14487ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14488{
14489 ibf_offset_t reading_pos = offset;
14490
14491 const long len = (long)ibf_load_small_value(load, &reading_pos);
14492
14493 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14494 int i;
14495
14496 for (i=0; i<len; i++) {
14497 const VALUE index = ibf_load_small_value(load, &reading_pos);
14498 rb_ary_push(ary, ibf_load_object(load, index));
14499 }
14500
14501 if (header->frozen) {
14502 rb_ary_freeze(ary);
14503 rb_ractor_make_shareable(ary); // TODO: check elements
14504 }
14505
14506 return ary;
14507}
14508
14509static int
14510ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14511{
14512 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14513
14514 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14515 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14516
14517 ibf_dump_write_small_value(dump, key_index);
14518 ibf_dump_write_small_value(dump, val_index);
14519 return ST_CONTINUE;
14520}
14521
14522static void
14523ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14524{
14525 long len = RHASH_SIZE(obj);
14526 ibf_dump_write_small_value(dump, (VALUE)len);
14527
14528 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14529}
14530
14531static VALUE
14532ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14533{
14534 long len = (long)ibf_load_small_value(load, &offset);
14535 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14536 int i;
14537
14538 for (i = 0; i < len; i++) {
14539 VALUE key_index = ibf_load_small_value(load, &offset);
14540 VALUE val_index = ibf_load_small_value(load, &offset);
14541
14542 VALUE key = ibf_load_object(load, key_index);
14543 VALUE val = ibf_load_object(load, val_index);
14544 rb_hash_aset(obj, key, val);
14545 }
14546
14547 if (header->internal) rb_obj_hide(obj);
14548 if (header->frozen) {
14550 }
14551
14552 return obj;
14553}
14554
14555static int
14556ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14557{
14558 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14559
14560 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14561
14562 ibf_dump_write_small_value(dump, key_index);
14563 ibf_dump_write_small_value(dump, val);
14564 return ST_CONTINUE;
14565}
14566
14567static void
14568ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14569{
14570 switch (imemo_type(obj)) {
14571 case imemo_cdhash: {
14572 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14573
14574 long len = tbl->num_entries;
14575 ibf_dump_write_small_value(dump, (VALUE)len);
14576 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14577 break;
14578 }
14579 default:
14580 ibf_dump_object_unsupported(dump, obj);
14581 break;
14582 }
14583}
14584
14585static VALUE
14586ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14587{
14588 long len = (long)ibf_load_small_value(load, &offset);
14589 VALUE obj = cdhash_new(len);
14590
14591 int i;
14592 for (i = 0; i < len; i++) {
14593 VALUE key_index = ibf_load_small_value(load, &offset);
14594 VALUE val = ibf_load_small_value(load, &offset);
14595
14596 VALUE key = ibf_load_object(load, key_index);
14597 cdhash_aset(obj, key, val);
14598 }
14599
14600 return obj;
14601}
14602
14603static void
14604ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14605{
14606 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14607 struct ibf_object_struct_range range;
14608 VALUE beg, end;
14609 IBF_ZERO(range);
14610 range.len = 3;
14611 range.class_index = 0;
14612
14613 rb_range_values(obj, &beg, &end, &range.excl);
14614 range.beg = (long)ibf_dump_object(dump, beg);
14615 range.end = (long)ibf_dump_object(dump, end);
14616
14617 IBF_W_ALIGN(struct ibf_object_struct_range);
14618 IBF_WV(range);
14619 }
14620 else {
14621 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14622 rb_class_name(CLASS_OF(obj)));
14623 }
14624}
14625
14626static VALUE
14627ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14628{
14629 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14630 VALUE beg = ibf_load_object(load, range->beg);
14631 VALUE end = ibf_load_object(load, range->end);
14632 VALUE obj = rb_range_new(beg, end, range->excl);
14633 if (header->internal) rb_obj_hide(obj);
14634 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14635 return obj;
14636}
14637
14638static void
14639ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14640{
14641 ssize_t len = BIGNUM_LEN(obj);
14642 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14643 BDIGIT *d = BIGNUM_DIGITS(obj);
14644
14645 (void)IBF_W(&slen, ssize_t, 1);
14646 IBF_WP(d, BDIGIT, len);
14647}
14648
14649static VALUE
14650ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14651{
14652 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14653 int sign = bignum->slen > 0;
14654 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14655 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14658 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14659 big_unpack_flags |
14660 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14661 if (header->internal) rb_obj_hide(obj);
14662 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14663 return obj;
14664}
14665
14666static void
14667ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14668{
14669 if (rb_data_is_encoding(obj)) {
14670 rb_encoding *enc = rb_to_encoding(obj);
14671 const char *name = rb_enc_name(enc);
14672 long len = strlen(name) + 1;
14673 long data[2];
14674 data[0] = IBF_OBJECT_DATA_ENCODING;
14675 data[1] = len;
14676 (void)IBF_W(data, long, 2);
14677 IBF_WP(name, char, len);
14678 }
14679 else {
14680 ibf_dump_object_unsupported(dump, obj);
14681 }
14682}
14683
14684static VALUE
14685ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14686{
14687 const long *body = IBF_OBJBODY(long, offset);
14688 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14689 /* const long len = body[1]; */
14690 const char *data = (const char *)&body[2];
14691
14692 switch (type) {
14693 case IBF_OBJECT_DATA_ENCODING:
14694 {
14695 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14696 return encobj;
14697 }
14698 }
14699
14700 return ibf_load_object_unsupported(load, header, offset);
14701}
14702
14703static void
14704ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14705{
14706 long data[2];
14707 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14708 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14709
14710 (void)IBF_W(data, long, 2);
14711}
14712
14713static VALUE
14714ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14715{
14716 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14717 VALUE a = ibf_load_object(load, nums->a);
14718 VALUE b = ibf_load_object(load, nums->b);
14719 VALUE obj = header->type == T_COMPLEX ?
14720 rb_complex_new(a, b) : rb_rational_new(a, b);
14721
14722 if (header->internal) rb_obj_hide(obj);
14723 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14724 return obj;
14725}
14726
14727static void
14728ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14729{
14730 ibf_dump_object_string(dump, rb_sym2str(obj));
14731}
14732
14733static VALUE
14734ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14735{
14736 ibf_offset_t reading_pos = offset;
14737
14738 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14739 const long len = (long)ibf_load_small_value(load, &reading_pos);
14740 const char *ptr = load->current_buffer->buff + reading_pos;
14741
14742 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14743 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14744 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14745 }
14746
14747 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14748 return ID2SYM(id);
14749}
14750
14751typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14752static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14753 ibf_dump_object_unsupported, /* T_NONE */
14754 ibf_dump_object_unsupported, /* T_OBJECT */
14755 ibf_dump_object_class, /* T_CLASS */
14756 ibf_dump_object_unsupported, /* T_MODULE */
14757 ibf_dump_object_float, /* T_FLOAT */
14758 ibf_dump_object_string, /* T_STRING */
14759 ibf_dump_object_regexp, /* T_REGEXP */
14760 ibf_dump_object_array, /* T_ARRAY */
14761 ibf_dump_object_hash, /* T_HASH */
14762 ibf_dump_object_struct, /* T_STRUCT */
14763 ibf_dump_object_bignum, /* T_BIGNUM */
14764 ibf_dump_object_unsupported, /* T_FILE */
14765 ibf_dump_object_data, /* T_DATA */
14766 ibf_dump_object_unsupported, /* T_MATCH */
14767 ibf_dump_object_complex_rational, /* T_COMPLEX */
14768 ibf_dump_object_complex_rational, /* T_RATIONAL */
14769 ibf_dump_object_unsupported, /* 0x10 */
14770 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14771 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14772 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14773 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14774 ibf_dump_object_unsupported, /* T_FIXNUM */
14775 ibf_dump_object_unsupported, /* T_UNDEF */
14776 ibf_dump_object_unsupported, /* 0x17 */
14777 ibf_dump_object_unsupported, /* 0x18 */
14778 ibf_dump_object_unsupported, /* 0x19 */
14779 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14780 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14781 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14782 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14783 ibf_dump_object_unsupported, /* 0x1e */
14784 ibf_dump_object_unsupported, /* 0x1f */
14785};
14786
14787static void
14788ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14789{
14790 unsigned char byte =
14791 (header.type << 0) |
14792 (header.special_const << 5) |
14793 (header.frozen << 6) |
14794 (header.internal << 7);
14795
14796 IBF_WV(byte);
14797}
14798
14799static struct ibf_object_header
14800ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14801{
14802 unsigned char byte = ibf_load_byte(load, offset);
14803
14804 struct ibf_object_header header;
14805 header.type = (byte >> 0) & 0x1f;
14806 header.special_const = (byte >> 5) & 0x01;
14807 header.frozen = (byte >> 6) & 0x01;
14808 header.internal = (byte >> 7) & 0x01;
14809
14810 return header;
14811}
14812
14813static ibf_offset_t
14814ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14815{
14816 struct ibf_object_header obj_header;
14817 ibf_offset_t current_offset;
14818 IBF_ZERO(obj_header);
14819 obj_header.type = TYPE(obj);
14820
14821 IBF_W_ALIGN(ibf_offset_t);
14822 current_offset = ibf_dump_pos(dump);
14823
14824 if (SPECIAL_CONST_P(obj) &&
14825 ! (SYMBOL_P(obj) ||
14826 RB_FLOAT_TYPE_P(obj))) {
14827 obj_header.special_const = TRUE;
14828 obj_header.frozen = TRUE;
14829 obj_header.internal = TRUE;
14830 ibf_dump_object_object_header(dump, obj_header);
14831 ibf_dump_write_small_value(dump, obj);
14832 }
14833 else {
14834 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14835 obj_header.special_const = FALSE;
14836 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14837 ibf_dump_object_object_header(dump, obj_header);
14838 (*dump_object_functions[obj_header.type])(dump, obj);
14839 }
14840
14841 return current_offset;
14842}
14843
14844typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14845static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14846 ibf_load_object_unsupported, /* T_NONE */
14847 ibf_load_object_unsupported, /* T_OBJECT */
14848 ibf_load_object_class, /* T_CLASS */
14849 ibf_load_object_unsupported, /* T_MODULE */
14850 ibf_load_object_float, /* T_FLOAT */
14851 ibf_load_object_string, /* T_STRING */
14852 ibf_load_object_regexp, /* T_REGEXP */
14853 ibf_load_object_array, /* T_ARRAY */
14854 ibf_load_object_hash, /* T_HASH */
14855 ibf_load_object_struct, /* T_STRUCT */
14856 ibf_load_object_bignum, /* T_BIGNUM */
14857 ibf_load_object_unsupported, /* T_FILE */
14858 ibf_load_object_data, /* T_DATA */
14859 ibf_load_object_unsupported, /* T_MATCH */
14860 ibf_load_object_complex_rational, /* T_COMPLEX */
14861 ibf_load_object_complex_rational, /* T_RATIONAL */
14862 ibf_load_object_unsupported, /* 0x10 */
14863 ibf_load_object_unsupported, /* T_NIL */
14864 ibf_load_object_unsupported, /* T_TRUE */
14865 ibf_load_object_unsupported, /* T_FALSE */
14866 ibf_load_object_symbol,
14867 ibf_load_object_unsupported, /* T_FIXNUM */
14868 ibf_load_object_unsupported, /* T_UNDEF */
14869 ibf_load_object_unsupported, /* 0x17 */
14870 ibf_load_object_unsupported, /* 0x18 */
14871 ibf_load_object_unsupported, /* 0x19 */
14872 ibf_load_object_imemo, /* T_IMEMO 0x1a */
14873 ibf_load_object_unsupported, /* T_NODE 0x1b */
14874 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14875 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14876 ibf_load_object_unsupported, /* 0x1e */
14877 ibf_load_object_unsupported, /* 0x1f */
14878};
14879
14880static VALUE
14881ibf_load_object(const struct ibf_load *load, VALUE object_index)
14882{
14883 if (object_index == 0) {
14884 return Qnil;
14885 }
14886 else {
14887 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14888 if (!obj) {
14889 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14890 ibf_offset_t offset = offsets[object_index];
14891 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14892
14893#if IBF_ISEQ_DEBUG
14894 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14895 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14896 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14897 header.type, header.special_const, header.frozen, header.internal);
14898#endif
14899 if (offset >= load->current_buffer->size) {
14900 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14901 }
14902
14903 if (header.special_const) {
14904 ibf_offset_t reading_pos = offset;
14905
14906 obj = ibf_load_small_value(load, &reading_pos);
14907 }
14908 else {
14909 obj = (*load_object_functions[header.type])(load, &header, offset);
14910 }
14911
14912 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14913 }
14914#if IBF_ISEQ_DEBUG
14915 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14916 object_index, obj);
14917#endif
14918 return obj;
14919 }
14920}
14921
14923{
14924 struct ibf_dump *dump;
14925 VALUE offset_list;
14926};
14927
14928static int
14929ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14930{
14931 VALUE obj = (VALUE)key;
14932 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14933
14934 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14935 rb_ary_push(args->offset_list, UINT2NUM(offset));
14936
14937 return ST_CONTINUE;
14938}
14939
14940static void
14941ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14942{
14943 st_table *obj_table = dump->current_buffer->obj_table;
14944 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14945
14946 struct ibf_dump_object_list_arg args;
14947 args.dump = dump;
14948 args.offset_list = offset_list;
14949
14950 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14951
14952 IBF_W_ALIGN(ibf_offset_t);
14953 *obj_list_offset = ibf_dump_pos(dump);
14954
14955 st_index_t size = obj_table->num_entries;
14956 st_index_t i;
14957
14958 for (i=0; i<size; i++) {
14959 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14960 IBF_WV(offset);
14961 }
14962
14963 *obj_list_size = (unsigned int)size;
14964}
14965
14966static void
14967ibf_dump_mark(void *ptr)
14968{
14969 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14970 rb_gc_mark(dump->global_buffer.str);
14971
14972 rb_mark_set(dump->global_buffer.obj_table);
14973 rb_mark_set(dump->iseq_table);
14974}
14975
14976static void
14977ibf_dump_free(void *ptr)
14978{
14979 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14980 if (dump->global_buffer.obj_table) {
14981 st_free_table(dump->global_buffer.obj_table);
14982 dump->global_buffer.obj_table = 0;
14983 }
14984 if (dump->iseq_table) {
14985 st_free_table(dump->iseq_table);
14986 dump->iseq_table = 0;
14987 }
14988}
14989
14990static size_t
14991ibf_dump_memsize(const void *ptr)
14992{
14993 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14994 size_t size = 0;
14995 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14996 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14997 return size;
14998}
14999
15000static const rb_data_type_t ibf_dump_type = {
15001 "ibf_dump",
15002 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
15003 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
15004};
15005
15006static void
15007ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
15008{
15009 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
15010 dump->iseq_table = NULL;
15011
15012 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
15013 dump->global_buffer.obj_table = ibf_dump_object_table_new();
15014 dump->iseq_table = st_init_numtable(); /* need free */
15015
15016 dump->current_buffer = &dump->global_buffer;
15017}
15018
15019static VALUE
15020iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
15021{
15022 struct ibf_header header = {{0}};
15023
15024 ibf_dump_write(dump, &header, sizeof(header));
15025 ibf_dump_iseq(dump, iseq);
15026
15027 header.magic[0] = 'Y'; /* YARB */
15028 header.magic[1] = 'A';
15029 header.magic[2] = 'R';
15030 header.magic[3] = 'B';
15031 header.major_version = IBF_MAJOR_VERSION;
15032 header.minor_version = IBF_MINOR_VERSION;
15033 header.endian = IBF_ENDIAN_MARK;
15034 header.wordsize = (uint8_t)SIZEOF_VALUE;
15035 ibf_dump_iseq_list(dump, &header);
15036 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
15037 header.size = ibf_dump_pos(dump);
15038
15039 if (RTEST(opt)) {
15040 VALUE opt_str = opt;
15041 const char *ptr = StringValuePtr(opt_str);
15042 header.extra_size = RSTRING_LENINT(opt_str);
15043 ibf_dump_write(dump, ptr, header.extra_size);
15044 }
15045 else {
15046 header.extra_size = 0;
15047 }
15048
15049 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15050
15051 return dump->global_buffer.str;
15052}
15053
15054VALUE
15055rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15056{
15057 struct ibf_dump *dump;
15058 VALUE dump_obj;
15059 VALUE str;
15060
15061 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15062 ISEQ_BODY(iseq)->local_iseq != iseq) {
15063 rb_raise(rb_eRuntimeError, "should be top of iseq");
15064 }
15065 if (RTEST(ISEQ_COVERAGE(iseq))) {
15066 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15067 }
15068
15069 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15070 ibf_dump_setup(dump, dump_obj);
15071
15072 str = iseq_ibf_dump_0(dump, iseq, opt);
15073 RB_GC_GUARD(dump_obj);
15074 return str;
15075}
15076
15077static const ibf_offset_t *
15078ibf_iseq_list(const struct ibf_load *load)
15079{
15080 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15081}
15082
15083void
15084rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15085{
15086 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15087 rb_iseq_t *prev_src_iseq = load->iseq;
15088 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15089 load->iseq = iseq;
15090#if IBF_ISEQ_DEBUG
15091 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15092 iseq->aux.loader.index, offset,
15093 load->header->size);
15094#endif
15095 ibf_load_iseq_each(load, iseq, offset);
15096 ISEQ_COMPILE_DATA_CLEAR(iseq);
15097 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15098 rb_iseq_init_trace(iseq);
15099 load->iseq = prev_src_iseq;
15100}
15101
15102#if USE_LAZY_LOAD
15103const rb_iseq_t *
15104rb_iseq_complete(const rb_iseq_t *iseq)
15105{
15106 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15107 return iseq;
15108}
15109#endif
15110
15111static rb_iseq_t *
15112ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15113{
15114 int iseq_index = (int)(VALUE)index_iseq;
15115
15116#if IBF_ISEQ_DEBUG
15117 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15118 (void *)index_iseq, (void *)load->iseq_list);
15119#endif
15120 if (iseq_index == -1) {
15121 return NULL;
15122 }
15123 else {
15124 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15125
15126#if IBF_ISEQ_DEBUG
15127 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15128#endif
15129 if (iseqv) {
15130 return (rb_iseq_t *)iseqv;
15131 }
15132 else {
15133 rb_iseq_t *iseq = iseq_imemo_alloc();
15134#if IBF_ISEQ_DEBUG
15135 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15136#endif
15137 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15138 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15139 iseq->aux.loader.index = iseq_index;
15140#if IBF_ISEQ_DEBUG
15141 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15142 (void *)iseq, (void *)load->loader_obj, iseq_index);
15143#endif
15144 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15145
15146 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15147#if IBF_ISEQ_DEBUG
15148 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15149#endif
15150 rb_ibf_load_iseq_complete(iseq);
15151 }
15152
15153#if IBF_ISEQ_DEBUG
15154 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15155 (void *)iseq, (void *)load->iseq);
15156#endif
15157 return iseq;
15158 }
15159 }
15160}
15161
15162static void
15163ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15164{
15165 struct ibf_header *header = (struct ibf_header *)bytes;
15166 load->loader_obj = loader_obj;
15167 load->global_buffer.buff = bytes;
15168 load->header = header;
15169 load->global_buffer.size = header->size;
15170 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15171 load->global_buffer.obj_list_size = header->global_object_list_size;
15172 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15173 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15174 load->iseq = NULL;
15175
15176 load->current_buffer = &load->global_buffer;
15177
15178 if (size < header->size) {
15179 rb_raise(rb_eRuntimeError, "broken binary format");
15180 }
15181 if (strncmp(header->magic, "YARB", 4) != 0) {
15182 rb_raise(rb_eRuntimeError, "unknown binary format");
15183 }
15184 if (header->major_version != IBF_MAJOR_VERSION ||
15185 header->minor_version != IBF_MINOR_VERSION) {
15186 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15187 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15188 }
15189 if (header->endian != IBF_ENDIAN_MARK) {
15190 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15191 }
15192 if (header->wordsize != SIZEOF_VALUE) {
15193 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15194 }
15195 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15196 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15197 header->iseq_list_offset);
15198 }
15199 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15200 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15201 load->global_buffer.obj_list_offset);
15202 }
15203}
15204
15205static void
15206ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15207{
15208 StringValue(str);
15209
15210 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15211 rb_raise(rb_eRuntimeError, "broken binary format");
15212 }
15213
15214 if (USE_LAZY_LOAD) {
15215 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15216 }
15217
15218 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15219 RB_OBJ_WRITE(loader_obj, &load->str, str);
15220}
15221
15222static void
15223ibf_loader_mark(void *ptr)
15224{
15225 struct ibf_load *load = (struct ibf_load *)ptr;
15226 rb_gc_mark(load->str);
15227 rb_gc_mark(load->iseq_list);
15228 rb_gc_mark(load->global_buffer.obj_list);
15229}
15230
15231static void
15232ibf_loader_free(void *ptr)
15233{
15234 struct ibf_load *load = (struct ibf_load *)ptr;
15235 SIZED_FREE(load);
15236}
15237
15238static size_t
15239ibf_loader_memsize(const void *ptr)
15240{
15241 return sizeof(struct ibf_load);
15242}
15243
15244static const rb_data_type_t ibf_load_type = {
15245 "ibf_loader",
15246 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15247 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15248};
15249
15250const rb_iseq_t *
15251rb_iseq_ibf_load(VALUE str)
15252{
15253 struct ibf_load *load;
15254 rb_iseq_t *iseq;
15255 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15256
15257 ibf_load_setup(load, loader_obj, str);
15258 iseq = ibf_load_iseq(load, 0);
15259
15260 RB_GC_GUARD(loader_obj);
15261 return iseq;
15262}
15263
15264const rb_iseq_t *
15265rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15266{
15267 struct ibf_load *load;
15268 rb_iseq_t *iseq;
15269 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15270
15271 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15272 iseq = ibf_load_iseq(load, 0);
15273
15274 RB_GC_GUARD(loader_obj);
15275 return iseq;
15276}
15277
15278/* collect the iseq table into an array indexed by iseq-list index */
15279static int
15280ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15281{
15282 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15283 srcs[(int)val] = (const rb_iseq_t *)key;
15284 return ST_CONTINUE;
15285}
15286
15287/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15288 * source by list index */
15289static void
15290iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15291{
15292 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15293 VALUE srcs_buf;
15294 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15295 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15296
15297 for (unsigned int i = 0; i < iseq_count; i++) {
15298 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15299 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15300 if (pc2branchindex != Qnil) {
15301 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15302 }
15303 }
15304
15305 ALLOCV_END(srcs_buf);
15306}
15307
15308/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15309const rb_iseq_t *
15310rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15311{
15312 struct ibf_dump *dump;
15313 VALUE dump_obj;
15314 VALUE str;
15315
15316 /* --- dump the subtree --- */
15317 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15318 ibf_dump_setup(dump, dump_obj);
15319
15320 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15321
15322 /* --- load it back --- */
15323 struct ibf_load *load;
15324 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15325 ibf_load_setup(load, loader_obj, str);
15326
15327 /* What the loader could not reconstruct is the same for every iseq in
15328 * the subtree: the only absent parent is the top's, every absent
15329 * local_iseq is the source's local root (runtime walks compare it
15330 * against the original frames, so a copy must not stand in), and
15331 * pathobj/script_lines/coverage are per-file values. */
15332 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15333 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15334 const rb_iseq_t *result = NULL;
15335 for (unsigned int i = 0; i < iseq_count; i++) {
15336 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15337 /* force completion even under USE_LAZY_LOAD */
15338 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15339 rb_ibf_load_iseq_complete(copy);
15340 }
15341
15342 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15343
15344 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15345 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15346 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15347 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15348 VALUE cov = ISEQ_COVERAGE(src_root);
15349 if (!NIL_P(sl) || !NIL_P(cov)) {
15350 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15351 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15352 RB_OBJ_WRITE(copy, &v->coverage, cov);
15353 }
15354
15355 if (i == 0) {
15356 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15357 result = copy;
15358 }
15359
15360 /* Shared across Ractors through the Proc#refined memo; the duplicated
15361 * subtree is self-contained, so mark each copy shareable. */
15363 }
15364
15365 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15366 iseq_subtree_copy_pc2branchindex(dump, load);
15367 }
15368
15369 RB_GC_GUARD(dump_obj);
15370 RB_GC_GUARD(loader_obj);
15371 return result;
15372}
15373
15374VALUE
15375rb_iseq_ibf_load_extra_data(VALUE str)
15376{
15377 struct ibf_load *load;
15378 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15379 VALUE extra_str;
15380
15381 ibf_load_setup(load, loader_obj, str);
15382 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15383 RB_GC_GUARD(loader_obj);
15384 return extra_str;
15385}
15386
15387#include "prism_compile.c"
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
Definition assert.h:311
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define RUBY_ATOMIC_PTR_LOAD(var)
Identical to RUBY_ATOMIC_LOAD, except it expects its arguments are void*.
Definition atomic.h:338
#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 rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#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 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 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:133
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#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:131
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:125
#define FLONUM_P
Old name of RB_FLONUM_P.
#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 ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define NUM2ULL
Old name of RB_NUM2ULL.
Definition long_long.h:35
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:129
#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:487
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1483
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1470
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1473
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1486
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:691
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1471
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1487
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1475
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1490
@ 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:103
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
VALUE rb_cHash
Hash class.
Definition hash.c:123
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:669
VALUE rb_cRange
Range class.
Definition range.c:35
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:906
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
Definition object.c:1309
#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:504
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:492
#define RB_POSFIXABLE(_)
Checks if the passed value is in range of fixnum, assuming it is a positive number.
Definition fixnum.h:43
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:33
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
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:550
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:568
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:532
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1235
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1259
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1857
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:77
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:2006
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4476
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:3898
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1783
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4261
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4247
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3666
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:2041
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:3864
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4315
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:4135
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3376
#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:1515
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:518
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:1129
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:1091
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
static VALUE RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
Freezes and marks the object as shareable.
Definition ractor.h:301
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1976
#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:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:385
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:56
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:69
#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:102
#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:438
#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:106
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:773
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
#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:604
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9158
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#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:31
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:367
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:338
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:249
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