Ruby 4.1.0dev (2026-08-28 revision 5eb9a6925b805a17dced976d5b741afe5086aab1)
compile.c (5eb9a6925b805a17dced976d5b741afe5086aab1)
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#define IS_NEXT_NEXT_INSN_ID(link, insn) \
362 ((link)->next && IS_NEXT_INSN_ID((link)->next, insn))
363
364static inline bool
365IS_INDEPENDENT_INSN(LINK_ELEMENT *link)
366{
367 if (!IS_INSN(link)) {
368 return false;
369 }
370
371 enum ruby_vminsn_type type = INSN_OF(link);
372
373 return (
374 type == BIN(putobject) ||
375 type == BIN(putspecialobject) ||
376 type == BIN(putnil) ||
377 type == BIN(putself) ||
378 type == BIN(duphash) ||
379 type == BIN(getinstancevariable) ||
380 type == BIN(getlocal) ||
381 type == BIN(opt_getconstant_path)
382 );
383}
384
385/* error */
386#if CPDEBUG > 0
388#endif
389RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
390static void
391append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
392{
393 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
394 VALUE file = rb_iseq_path(iseq);
395 VALUE err = err_info == Qtrue ? Qfalse : err_info;
396 va_list args;
397
398 va_start(args, fmt);
399 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
400 va_end(args);
401 if (NIL_P(err_info)) {
402 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
403 rb_set_errinfo(err);
404 }
405 else if (!err_info) {
406 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
407 }
408 if (compile_debug) {
409 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
410 rb_exc_fatal(err);
411 }
412}
413
414#if 0
415static void
416compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
417{
418 va_list args;
419 va_start(args, fmt);
420 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
421 va_end(args);
422 abort();
423}
424#endif
425
426#define COMPILE_ERROR append_compile_error
427
428#define ERROR_ARGS_AT(n) iseq, nd_line(n),
429#define ERROR_ARGS ERROR_ARGS_AT(node)
430
431#define EXPECT_NODE(prefix, node, ndtype, errval) \
432do { \
433 const NODE *error_node = (node); \
434 enum node_type error_type = nd_type(error_node); \
435 if (error_type != (ndtype)) { \
436 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
437 prefix ": " #ndtype " is expected, but %s", \
438 ruby_node_name(error_type)); \
439 return errval; \
440 } \
441} while (0)
442
443#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
444do { \
445 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
446 prefix ": must be " #ndtype ", but 0"); \
447 return errval; \
448} while (0)
449
450#define UNKNOWN_NODE(prefix, node, errval) \
451do { \
452 const NODE *error_node = (node); \
453 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
454 ruby_node_name(nd_type(error_node))); \
455 return errval; \
456} while (0)
457
458#define COMPILE_OK 1
459#define COMPILE_NG 0
460
461#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
462#define NO_CHECK(sub) (void)(sub)
463#define BEFORE_RETURN
464
465#define DECL_ANCHOR(name) \
466 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
467#define INIT_ANCHOR(name) \
468 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
469
470static inline VALUE
471freeze_hide_obj(VALUE obj)
472{
473 OBJ_FREEZE(obj);
474 RBASIC_CLEAR_CLASS(obj);
475 return obj;
476}
477
478#include "optinsn.inc"
479#if OPT_INSTRUCTIONS_UNIFICATION
480#include "optunifs.inc"
481#endif
482
483/* for debug */
484#if CPDEBUG < 0
485#define ISEQ_ARG iseq,
486#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
487#else
488#define ISEQ_ARG
489#define ISEQ_ARG_DECLARE
490#endif
491
492#if CPDEBUG
493#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
494#endif
495
496static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
497static void dump_disasm_list(const LINK_ELEMENT *elem);
498
499static int insn_data_length(INSN *iobj);
500static int calc_sp_depth(int depth, INSN *iobj);
501
502static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
503static LABEL *new_label_body(rb_iseq_t *iseq, long line);
504static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
505static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
506
507
508static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
509static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
510static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
511static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
512static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
513
514static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
515static int iseq_set_exception_local_table(rb_iseq_t *iseq);
516static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
517
518static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
519static int iseq_set_exception_table(rb_iseq_t *iseq);
520static int iseq_set_optargs_table(rb_iseq_t *iseq);
521static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
522
523static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
524static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
525
526/*
527 * To make Array to LinkedList, use link_anchor
528 */
529
530static void
531verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
532{
533#if CPDEBUG
534 int flag = 0;
535 LINK_ELEMENT *list, *plist;
536
537 if (!compile_debug) return;
538
539 list = anchor->anchor.next;
540 plist = &anchor->anchor;
541 while (list) {
542 if (plist != list->prev) {
543 flag += 1;
544 }
545 plist = list;
546 list = list->next;
547 }
548
549 if (anchor->last != plist && anchor->last != 0) {
550 flag |= 0x70000;
551 }
552
553 if (flag != 0) {
554 rb_bug("list verify error: %08x (%s)", flag, info);
555 }
556#endif
557}
558#if CPDEBUG < 0
559#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
560#endif
561
562static void
563verify_call_cache(rb_iseq_t *iseq)
564{
565#if CPDEBUG
566 VALUE *original = rb_iseq_original_iseq(iseq);
567 size_t i = 0;
568 while (i < ISEQ_BODY(iseq)->iseq_size) {
569 VALUE insn = original[i];
570 const char *types = insn_op_types(insn);
571
572 for (int j=0; types[j]; j++) {
573 if (types[j] == TS_CALLDATA) {
574 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
575 const struct rb_callinfo *ci = cd->ci;
576 const struct rb_callcache *cc = cd->cc;
577 if (cc != vm_cc_empty()) {
578 vm_ci_dump(ci);
579 rb_bug("call cache is not initialized by vm_cc_empty()");
580 }
581 }
582 }
583 i += insn_len(insn);
584 }
585
586 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
587 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
588 const struct rb_callinfo *ci = cd->ci;
589 const struct rb_callcache *cc = cd->cc;
590 if (cc != NULL && cc != vm_cc_empty()) {
591 vm_ci_dump(ci);
592 rb_bug("call cache is not initialized by vm_cc_empty()");
593 }
594 }
595#endif
596}
597
598/*
599 * elem1, elem2 => elem1, elem2, elem
600 */
601static void
602ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
603{
604 elem->prev = anchor->last;
605 anchor->last->next = elem;
606 anchor->last = elem;
607 verify_list("add", anchor);
608}
609
610/*
611 * elem1, before, elem2 => elem1, before, elem, elem2
612 */
613static void
614APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
615{
616 elem->prev = before;
617 elem->next = before->next;
618 elem->next->prev = elem;
619 before->next = elem;
620 if (before == anchor->last) anchor->last = elem;
621 verify_list("add", anchor);
622}
623#if CPDEBUG < 0
624#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
625#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
626#endif
627
628static int
629branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
630{
631 if (!ISEQ_COVERAGE(iseq)) return 0;
632 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
633 if (first_line <= 0) return 0;
634 return 1;
635}
636
637static VALUE
638setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
639{
640 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
641 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
642 VALUE branch = rb_ary_hidden_new(6);
643
644 rb_hash_aset(structure, key, branch);
645 rb_ary_push(branch, ID2SYM(rb_intern(type)));
646 rb_ary_push(branch, INT2FIX(first_lineno));
647 rb_ary_push(branch, INT2FIX(first_column));
648 rb_ary_push(branch, INT2FIX(last_lineno));
649 rb_ary_push(branch, INT2FIX(last_column));
650 return branch;
651}
652
653static VALUE
654decl_branch_base(rb_iseq_t *iseq, int node_id, const rb_code_location_t *loc, const char *type)
655{
656 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
657
658 /*
659 * A branch base is keyed by [source_hash (in two halves), node_id, first_lineno],
660 * which identifies the branch node stably even across (re-)evals against
661 * the same path.
662 *
663 * if !structure[key]
664 * structure[key] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
665 * else
666 * branches = structure[key][5]
667 * end
668 */
669 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
670 VALUE key = rb_ary_new_from_args(4,
671 ULONG2NUM((unsigned long)(source_hash >> 32)),
672 ULONG2NUM((unsigned long)(source_hash & 0xffffffff)),
673 INT2FIX(node_id),
674 INT2FIX(loc->beg_pos.lineno));
675 rb_ary_freeze(key);
676
677 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
678 VALUE branch_base = rb_hash_aref(structure, key);
679 VALUE branches;
680
681 if (NIL_P(branch_base)) {
682 branch_base = setup_branch(loc, type, structure, key);
683 branches = rb_hash_new();
684 rb_obj_hide(branches);
685 rb_ary_push(branch_base, branches);
686 }
687 else {
688 branches = RARRAY_AREF(branch_base, 5);
689 }
690
691 return branches;
692}
693
694static NODE
695generate_dummy_line_node(int lineno, int node_id)
696{
697 NODE dummy = { 0 };
698 nd_set_line(&dummy, lineno);
699 nd_set_node_id(&dummy, node_id);
700 return dummy;
701}
702
703static void
704add_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)
705{
706 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
707
708 /*
709 * if !branches[branch_id]
710 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
711 * else
712 * counter_idx= branches[branch_id][5]
713 * end
714 */
715
716 VALUE key = INT2FIX(branch_id);
717 VALUE branch = rb_hash_aref(branches, key);
718 long counter_idx;
719
720 if (NIL_P(branch)) {
721 branch = setup_branch(loc, type, branches, key);
722 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
723 counter_idx = RARRAY_LEN(counters);
724 rb_ary_push(branch, LONG2FIX(counter_idx));
725 rb_ary_push(counters, INT2FIX(0));
726 }
727 else {
728 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
729 }
730
731 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
732 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
733}
734
735#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
736
737static int
738validate_label(st_data_t name, st_data_t label, st_data_t arg)
739{
740 rb_iseq_t *iseq = (rb_iseq_t *)arg;
741 LABEL *lobj = (LABEL *)label;
742 if (!lobj->link.next) {
743 do {
744 COMPILE_ERROR(iseq, lobj->position,
745 "%"PRIsVALUE": undefined label",
746 rb_sym2str((VALUE)name));
747 } while (0);
748 }
749 return ST_CONTINUE;
750}
751
752static void
753validate_labels(rb_iseq_t *iseq, st_table *labels_table)
754{
755 st_foreach(labels_table, validate_label, (st_data_t)iseq);
756 st_free_table(labels_table);
757}
758
759static NODE *
760get_nd_recv(const NODE *node)
761{
762 switch (nd_type(node)) {
763 case NODE_CALL:
764 return RNODE_CALL(node)->nd_recv;
765 case NODE_OPCALL:
766 return RNODE_OPCALL(node)->nd_recv;
767 case NODE_FCALL:
768 return 0;
769 case NODE_QCALL:
770 return RNODE_QCALL(node)->nd_recv;
771 case NODE_VCALL:
772 return 0;
773 case NODE_ATTRASGN:
774 return RNODE_ATTRASGN(node)->nd_recv;
775 case NODE_OP_ASGN1:
776 return RNODE_OP_ASGN1(node)->nd_recv;
777 case NODE_OP_ASGN2:
778 return RNODE_OP_ASGN2(node)->nd_recv;
779 default:
780 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
781 }
782}
783
784static ID
785get_node_call_nd_mid(const NODE *node)
786{
787 switch (nd_type(node)) {
788 case NODE_CALL:
789 return RNODE_CALL(node)->nd_mid;
790 case NODE_OPCALL:
791 return RNODE_OPCALL(node)->nd_mid;
792 case NODE_FCALL:
793 return RNODE_FCALL(node)->nd_mid;
794 case NODE_QCALL:
795 return RNODE_QCALL(node)->nd_mid;
796 case NODE_VCALL:
797 return RNODE_VCALL(node)->nd_mid;
798 case NODE_ATTRASGN:
799 return RNODE_ATTRASGN(node)->nd_mid;
800 default:
801 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
802 }
803}
804
805static NODE *
806get_nd_args(const NODE *node)
807{
808 switch (nd_type(node)) {
809 case NODE_CALL:
810 return RNODE_CALL(node)->nd_args;
811 case NODE_OPCALL:
812 return RNODE_OPCALL(node)->nd_args;
813 case NODE_FCALL:
814 return RNODE_FCALL(node)->nd_args;
815 case NODE_QCALL:
816 return RNODE_QCALL(node)->nd_args;
817 case NODE_VCALL:
818 return 0;
819 case NODE_ATTRASGN:
820 return RNODE_ATTRASGN(node)->nd_args;
821 default:
822 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
823 }
824}
825
826static ID
827get_node_colon_nd_mid(const NODE *node)
828{
829 switch (nd_type(node)) {
830 case NODE_COLON2:
831 return RNODE_COLON2(node)->nd_mid;
832 case NODE_COLON3:
833 return RNODE_COLON3(node)->nd_mid;
834 default:
835 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
836 }
837}
838
839static ID
840get_nd_vid(const NODE *node)
841{
842 switch (nd_type(node)) {
843 case NODE_LASGN:
844 return RNODE_LASGN(node)->nd_vid;
845 case NODE_DASGN:
846 return RNODE_DASGN(node)->nd_vid;
847 case NODE_IASGN:
848 return RNODE_IASGN(node)->nd_vid;
849 case NODE_CVASGN:
850 return RNODE_CVASGN(node)->nd_vid;
851 default:
852 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
853 }
854}
855
856static NODE *
857get_nd_value(const NODE *node)
858{
859 switch (nd_type(node)) {
860 case NODE_LASGN:
861 return RNODE_LASGN(node)->nd_value;
862 case NODE_DASGN:
863 return RNODE_DASGN(node)->nd_value;
864 default:
865 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
866 }
867}
868
869static VALUE
870get_string_value(const NODE *node)
871{
872 switch (nd_type(node)) {
873 case NODE_STR:
874 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
875 case NODE_FILE:
876 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
877 default:
878 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
879 }
880}
881
882VALUE
883rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
884{
885 DECL_ANCHOR(ret);
886 INIT_ANCHOR(ret);
887
888 (*ifunc->func)(iseq, ret, ifunc->data);
889
890 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
891
892 CHECK(iseq_setup_insn(iseq, ret));
893 return iseq_setup(iseq, ret);
894}
895
896static bool drop_unreachable_return(LINK_ANCHOR *ret);
897
898VALUE
899rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
900{
901 DECL_ANCHOR(ret);
902 INIT_ANCHOR(ret);
903
904 if (node == 0) {
905 NO_CHECK(COMPILE(ret, "nil", node));
906 iseq_set_local_table(iseq, 0, 0);
907 }
908 /* assume node is T_NODE */
909 else if (nd_type_p(node, NODE_SCOPE)) {
910 /* iseq type of top, method, class, block */
911 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
912 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
913 iseq_set_parameters_lvar_state(iseq);
914
915 switch (ISEQ_BODY(iseq)->type) {
916 case ISEQ_TYPE_BLOCK:
917 {
918 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
919 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
920
921 start->rescued = LABEL_RESCUE_BEG;
922 end->rescued = LABEL_RESCUE_END;
923
924 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
925 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
926 ADD_LABEL(ret, start);
927 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
928 ADD_LABEL(ret, end);
929 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
930 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
931
932 /* wide range catch handler must put at last */
933 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
934 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
935 break;
936 }
937 case ISEQ_TYPE_CLASS:
938 {
939 ADD_TRACE(ret, RUBY_EVENT_CLASS);
940 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
941 ADD_TRACE(ret, RUBY_EVENT_END);
942 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
943 break;
944 }
945 case ISEQ_TYPE_METHOD:
946 {
947 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
948 ADD_TRACE(ret, RUBY_EVENT_CALL);
949 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
950 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
951 ADD_TRACE(ret, RUBY_EVENT_RETURN);
952 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
953 break;
954 }
955 default: {
956 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
957 break;
958 }
959 }
960 }
961 else {
962 const char *m;
963#define INVALID_ISEQ_TYPE(type) \
964 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
965 switch (ISEQ_BODY(iseq)->type) {
966 case INVALID_ISEQ_TYPE(METHOD);
967 case INVALID_ISEQ_TYPE(CLASS);
968 case INVALID_ISEQ_TYPE(BLOCK);
969 case INVALID_ISEQ_TYPE(EVAL);
970 case INVALID_ISEQ_TYPE(MAIN);
971 case INVALID_ISEQ_TYPE(TOP);
972#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
973 case ISEQ_TYPE_RESCUE:
974 iseq_set_exception_local_table(iseq);
975 CHECK(COMPILE(ret, "rescue", node));
976 break;
977 case ISEQ_TYPE_ENSURE:
978 iseq_set_exception_local_table(iseq);
979 CHECK(COMPILE_POPPED(ret, "ensure", node));
980 break;
981 case ISEQ_TYPE_PLAIN:
982 CHECK(COMPILE(ret, "ensure", node));
983 break;
984 default:
985 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
986 return COMPILE_NG;
987 invalid_iseq_type:
988 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
989 return COMPILE_NG;
990 }
991 }
992
993 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
994 NODE dummy_line_node = generate_dummy_line_node(0, -1);
995 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
996 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
997 }
998 else if (!drop_unreachable_return(ret)) {
999 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
1000 }
1001
1002#if OPT_SUPPORT_JOKE
1003 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
1004 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
1005 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
1006 validate_labels(iseq, labels_table);
1007 }
1008#endif
1009 CHECK(iseq_setup_insn(iseq, ret));
1010 return iseq_setup(iseq, ret);
1011}
1012
1013static int
1014rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
1015{
1016#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1017 const void * const *table = rb_vm_get_insns_address_table();
1018 unsigned int i;
1019 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
1020
1021 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1022 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
1023 int len = insn_len(insn);
1024 encoded[i] = (VALUE)table[insn];
1025 i += len;
1026 }
1027 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
1028#endif
1029
1030#if USE_YJIT
1031 rb_yjit_live_iseq_count++;
1032 rb_yjit_iseq_alloc_count++;
1033#endif
1034
1035 return COMPILE_OK;
1036}
1037
1038VALUE *
1039rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1040{
1041 struct rb_iseq_variable *v = ISEQ_VARIABLE(iseq);
1042 VALUE *original_code = v ? RUBY_ATOMIC_PTR_LOAD(v->original_iseq) : NULL;
1043
1044 if (original_code) return original_code;
1045 original_code = ALLOC_N(VALUE, ISEQ_BODY(iseq)->iseq_size);
1046 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1047
1048#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1049 {
1050 unsigned int i;
1051
1052 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1053 const void *addr = (const void *)original_code[i];
1054 const int insn = rb_vm_insn_addr2insn(addr);
1055
1056 original_code[i] = insn;
1057 i += insn_len(insn);
1058 }
1059 }
1060#endif
1061
1062 /* Concurrent callers can each build a copy; publish only fully
1063 * translated code and keep the first one. */
1064 v = rb_iseq_variable_ensure((rb_iseq_t *)iseq);
1065 VALUE *prev = ATOMIC_PTR_CAS(v->original_iseq,
1066 NULL, original_code);
1067 if (prev) {
1068 SIZED_FREE_N(original_code, ISEQ_BODY(iseq)->iseq_size);
1069 return prev;
1070 }
1071 return original_code;
1072}
1073
1074/*********************************************/
1075/* definition of data structure for compiler */
1076/*********************************************/
1077
1078#if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1079# define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1080#else
1081# define ALIGNMENT_SIZE SIZEOF_VALUE
1082#endif
1083#define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1084
1085#define ALIGNMENT_SIZE_OF(type) alignment_size_assert(RUBY_ALIGNOF(type), #type)
1086
1087static inline size_t
1088alignment_size_assert(size_t align, const char *type)
1089{
1090 RUBY_ASSERT((align & (align - 1)) == 0,
1091 "ALIGNMENT_SIZE_OF(%s):%zd == (2 ** N) is expected", type, align);
1092 return align;
1093}
1094
1095/* calculate padding size for aligned memory access */
1096static inline size_t
1097calc_padding(void *ptr, size_t align)
1098{
1099 size_t mis;
1100 size_t padding = 0;
1101
1102 mis = (size_t)ptr & (align - 1);
1103 if (mis > 0) {
1104 padding = align - mis;
1105 }
1106
1107 return padding;
1108}
1109
1110static void *
1111compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size, size_t align)
1112{
1113 void *ptr = 0;
1114 struct iseq_compile_data_storage *storage = *arena;
1115 size_t padding = calc_padding((void *)&storage->buff[storage->pos], align);
1116
1117 if (size >= INT_MAX - padding) rb_memerror();
1118 if (storage->pos + size + padding > storage->size) {
1119 unsigned int alloc_size = storage->size;
1120
1121 while (alloc_size < size + PADDING_SIZE_MAX) {
1122 if (alloc_size >= INT_MAX / 2) rb_memerror();
1123 alloc_size *= 2;
1124 }
1125 storage->next = (void *)ALLOC_N(char, alloc_size +
1126 offsetof(struct iseq_compile_data_storage, buff));
1127 storage = *arena = storage->next;
1128 storage->next = 0;
1129 storage->pos = 0;
1130 storage->size = alloc_size;
1131 padding = calc_padding((void *)&storage->buff[storage->pos], align);
1132 }
1133
1134 storage->pos += (int)padding;
1135
1136 ptr = (void *)&storage->buff[storage->pos];
1137 storage->pos += (int)size;
1138 return ptr;
1139}
1140
1141static void *
1142compile_data_alloc(rb_iseq_t *iseq, size_t size, size_t align)
1143{
1144 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1145 return compile_data_alloc_with_arena(arena, size, align);
1146}
1147
1148#define compile_data_alloc_type(iseq, type) \
1149 (type *)compile_data_alloc(iseq, sizeof(type), ALIGNMENT_SIZE_OF(type))
1150
1151static inline void *
1152compile_data_alloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1153{
1154 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1155 return compile_data_alloc(iseq, size, align);
1156}
1157
1158#define compile_data_alloc2_type(iseq, type, num) \
1159 (type *)compile_data_alloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1160
1161static inline void *
1162compile_data_calloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1163{
1164 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1165 void *p = compile_data_alloc(iseq, size, align);
1166 memset(p, 0, size);
1167 return p;
1168}
1169
1170#define compile_data_calloc2_type(iseq, type, num) \
1171 (type *)compile_data_calloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1172
1173static INSN *
1174compile_data_alloc_insn(rb_iseq_t *iseq)
1175{
1176 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1177 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN), ALIGNMENT_SIZE_OF(INSN));
1178}
1179
1180static LABEL *
1181compile_data_alloc_label(rb_iseq_t *iseq)
1182{
1183 return compile_data_alloc_type(iseq, LABEL);
1184}
1185
1186static ADJUST *
1187compile_data_alloc_adjust(rb_iseq_t *iseq)
1188{
1189 return compile_data_alloc_type(iseq, ADJUST);
1190}
1191
1192static TRACE *
1193compile_data_alloc_trace(rb_iseq_t *iseq)
1194{
1195 return compile_data_alloc_type(iseq, TRACE);
1196}
1197
1198/*
1199 * elem1, elemX => elem1, elem2, elemX
1200 */
1201static void
1202ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1203{
1204 elem2->next = elem1->next;
1205 elem2->prev = elem1;
1206 elem1->next = elem2;
1207 if (elem2->next) {
1208 elem2->next->prev = elem2;
1209 }
1210}
1211
1212/*
1213 * elem1, elemX => elemX, elem2, elem1
1214 */
1215static void
1216ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1217{
1218 elem2->prev = elem1->prev;
1219 elem2->next = elem1;
1220 elem1->prev = elem2;
1221 if (elem2->prev) {
1222 elem2->prev->next = elem2;
1223 }
1224}
1225
1226/*
1227 * elemX, elem1, elemY => elemX, elem2, elemY
1228 */
1229static void
1230ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1231{
1232 elem2->prev = elem1->prev;
1233 elem2->next = elem1->next;
1234 if (elem1->prev) {
1235 elem1->prev->next = elem2;
1236 }
1237 if (elem1->next) {
1238 elem1->next->prev = elem2;
1239 }
1240}
1241
1242static void
1243ELEM_REMOVE(LINK_ELEMENT *elem)
1244{
1245 elem->prev->next = elem->next;
1246 if (elem->next) {
1247 elem->next->prev = elem->prev;
1248 }
1249}
1250
1251/*
1252 * elem1, elem2 => elem2, elem1
1253 */
1254static void
1255ELEM_SWAP(LINK_ELEMENT *first, LINK_ELEMENT *second)
1256{
1257 RUBY_ASSERT(first->next == second);
1258 RUBY_ASSERT(first == second->prev);
1259
1260 first->prev->next = second;
1261 second->next->prev = first;
1262
1263 first->next = second->next;
1264 second->next = first;
1265
1266 second->prev = first->prev;
1267 first->prev = second;
1268}
1269
1270static LINK_ELEMENT *
1271FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1272{
1273 return anchor->anchor.next;
1274}
1275
1276static LINK_ELEMENT *
1277LAST_ELEMENT(LINK_ANCHOR *const anchor)
1278{
1279 return anchor->last;
1280}
1281
1282static LINK_ELEMENT *
1283ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1284{
1285 while (elem) {
1286 switch (elem->type) {
1287 case ISEQ_ELEMENT_INSN:
1288 case ISEQ_ELEMENT_ADJUST:
1289 return elem;
1290 default:
1291 elem = elem->next;
1292 }
1293 }
1294 return NULL;
1295}
1296
1297static int
1298LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1299{
1300 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1301 if (first_insn != NULL &&
1302 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1303 return TRUE;
1304 }
1305 else {
1306 return FALSE;
1307 }
1308}
1309
1310static int
1311LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1312{
1313 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1314 return TRUE;
1315 }
1316 else {
1317 return FALSE;
1318 }
1319}
1320
1321/*
1322 * anc1: e1, e2, e3
1323 * anc2: e4, e5
1324 *#=>
1325 * anc1: e1, e2, e3, e4, e5
1326 * anc2: e4, e5 (broken)
1327 */
1328static void
1329APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1330{
1331 if (anc2->anchor.next) {
1332 /* LINK_ANCHOR must not loop */
1333 RUBY_ASSERT(anc2->last != &anc2->anchor);
1334 anc1->last->next = anc2->anchor.next;
1335 anc2->anchor.next->prev = anc1->last;
1336 anc1->last = anc2->last;
1337 }
1338 else {
1339 RUBY_ASSERT(anc2->last == &anc2->anchor);
1340 }
1341 verify_list("append", anc1);
1342}
1343#if CPDEBUG < 0
1344#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1345#endif
1346
1347#if CPDEBUG && 0
1348static void
1349debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1350{
1351 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1352 printf("----\n");
1353 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1354 (void *)anchor->anchor.next, (void *)anchor->last);
1355 while (list) {
1356 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1357 (void *)list->prev, (int)list->type);
1358 list = list->next;
1359 }
1360 printf("----\n");
1361
1362 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1363 verify_list("debug list", anchor);
1364}
1365#if CPDEBUG < 0
1366#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1367#endif
1368#else
1369#define debug_list(anc, cur) ((void)0)
1370#endif
1371
1372static TRACE *
1373new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1374{
1375 TRACE *trace = compile_data_alloc_trace(iseq);
1376
1377 trace->link.type = ISEQ_ELEMENT_TRACE;
1378 trace->link.next = NULL;
1379 trace->event = event;
1380 trace->data = data;
1381
1382 return trace;
1383}
1384
1385static LABEL *
1386new_label_body(rb_iseq_t *iseq, long line)
1387{
1388 LABEL *labelobj = compile_data_alloc_label(iseq);
1389
1390 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1391 labelobj->link.next = 0;
1392
1393 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1394 labelobj->sc_state = 0;
1395 labelobj->sp = -1;
1396 labelobj->refcnt = 0;
1397 labelobj->set = 0;
1398 labelobj->rescued = LABEL_RESCUE_NONE;
1399 labelobj->unremovable = 0;
1400 labelobj->position = -1;
1401 return labelobj;
1402}
1403
1404static ADJUST *
1405new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1406{
1407 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1408 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1409 adjust->link.next = 0;
1410 adjust->label = label;
1411 adjust->line_no = line;
1412 LABEL_UNREMOVABLE(label);
1413 return adjust;
1414}
1415
1416static void
1417iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1418{
1419 const char *types = insn_op_types(insn->insn_id);
1420 for (int j = 0; types[j]; j++) {
1421 char type = types[j];
1422 switch (type) {
1423 case TS_CDHASH:
1424 case TS_ISEQ:
1425 case TS_VALUE:
1426 case TS_IC: // constant path array
1427 case TS_CALLDATA: // ci is stored.
1428 func(&OPERAND_AT(insn, j), data);
1429 break;
1430 default:
1431 break;
1432 }
1433 }
1434}
1435
1436static void
1437iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1438{
1439 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1441 RBASIC_CLASS(*obj) == 0 || // hidden
1442 RB_OBJ_SHAREABLE_P(*obj));
1443}
1444
1445static INSN *
1446new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1447{
1448 INSN *iobj = compile_data_alloc_insn(iseq);
1449
1450 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1451
1452 iobj->link.type = ISEQ_ELEMENT_INSN;
1453 iobj->link.next = 0;
1454 iobj->insn_id = insn_id;
1455 iobj->insn_info.line_no = line_no;
1456 iobj->insn_info.node_id = node_id;
1457 iobj->insn_info.events = 0;
1458 iobj->operands = argv;
1459 iobj->operand_size = argc;
1460 iobj->sc_state = 0;
1461
1462 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1463
1464 return iobj;
1465}
1466
1467static INSN *
1468new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1469{
1470 VALUE *operands = 0;
1471 va_list argv;
1472 if (argc > 0) {
1473 int i;
1474 va_start(argv, argc);
1475 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1476 for (i = 0; i < argc; i++) {
1477 VALUE v = va_arg(argv, VALUE);
1478 operands[i] = v;
1479 }
1480 va_end(argv);
1481 }
1482 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1483}
1484
1485static INSN *
1486insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1487{
1488 VALUE *operands = 0;
1489 va_list argv;
1490 if (argc > 0) {
1491 int i;
1492 va_start(argv, argc);
1493 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1494 for (i = 0; i < argc; i++) {
1495 VALUE v = va_arg(argv, VALUE);
1496 operands[i] = v;
1497 }
1498 va_end(argv);
1499 }
1500
1501 iobj->insn_id = insn_id;
1502 iobj->operand_size = argc;
1503 iobj->operands = operands;
1504 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1505
1506 return iobj;
1507}
1508
1509static const struct rb_callinfo *
1510new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1511{
1512 VM_ASSERT(argc >= 0);
1513
1514 if (kw_arg) {
1515 flag |= VM_CALL_KWARG;
1516 argc += kw_arg->keyword_len;
1517 }
1518
1519 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1520 && !has_blockiseq) {
1521 flag |= VM_CALL_ARGS_SIMPLE;
1522 }
1523
1524 ISEQ_BODY(iseq)->ci_size++;
1525 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1526 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1527 return ci;
1528}
1529
1530static INSN *
1531new_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)
1532{
1533 VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
1534 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1535 operands[0] = ci;
1536 operands[1] = (VALUE)blockiseq;
1537 if (blockiseq) {
1538 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1539 }
1540
1541 INSN *insn;
1542
1543 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1544 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1545 }
1546 else {
1547 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1548 }
1549
1550 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1551 RB_GC_GUARD(ci);
1552 return insn;
1553}
1554
1555static rb_iseq_t *
1556new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1557 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1558{
1559 rb_iseq_t *ret_iseq;
1560 VALUE ast_value = rb_ruby_ast_new(node);
1561
1562 // The child AST wrapper does not carry the source hash, so copy it from
1563 // the enclosing iseq before compiling, for grandchildren to inherit it.
1564 if (ISEQ_BODY(iseq)->source_hash) {
1565 rb_ast_t *child_ast = rb_ruby_ast_data_get(ast_value);
1566 child_ast->body.source_hash = ISEQ_BODY(iseq)->source_hash;
1567 child_ast->body.has_source_hash = 1;
1568 }
1569
1570 debugs("[new_child_iseq]> ---------------------------------------\n");
1571 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1572 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1573 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1574 line_no, parent,
1575 isolated_depth ? isolated_depth + 1 : 0,
1576 type, ISEQ_COMPILE_DATA(iseq)->option,
1577 ISEQ_SCRIPT_LINES(iseq));
1578 debugs("[new_child_iseq]< ---------------------------------------\n");
1579 return ret_iseq;
1580}
1581
1582static rb_iseq_t *
1583new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1584 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1585{
1586 rb_iseq_t *ret_iseq;
1587
1588 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1589 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1590 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1591 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1592 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1593 return ret_iseq;
1594}
1595
1596static void
1597set_catch_except_p(rb_iseq_t *iseq)
1598{
1599 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1600 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1601 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1602 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1603 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1604 }
1605 }
1606}
1607
1608/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1609 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1610 if catch table exists. But we want to optimize while loop, which always has catch
1611 table entries for break/next/redo.
1612
1613 So this function sets true for limited ISeqs with break/next/redo catch table entries
1614 whose child ISeq would really raise an exception. */
1615static void
1616update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1617{
1618 unsigned int pos;
1619 size_t i;
1620 int insn;
1621 const struct iseq_catch_table *ct = body->catch_table;
1622
1623 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1624 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1625 pos = 0;
1626 while (pos < body->iseq_size) {
1627 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1628 if (insn == BIN(throw)) {
1629 set_catch_except_p(iseq);
1630 break;
1631 }
1632 pos += insn_len(insn);
1633 }
1634
1635 if (ct == NULL)
1636 return;
1637
1638 for (i = 0; i < ct->size; i++) {
1639 const struct iseq_catch_table_entry *entry =
1640 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1641 if (entry->type != CATCH_TYPE_BREAK
1642 && entry->type != CATCH_TYPE_NEXT
1643 && entry->type != CATCH_TYPE_REDO) {
1644 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1645 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1646 break;
1647 }
1648 }
1649}
1650
1651static void
1652iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1653{
1654 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1655 if (NIL_P(catch_table_ary)) return;
1656 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1657 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1658 for (i = 0; i < tlen; i++) {
1659 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1660 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1661 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1662 LINK_ELEMENT *e;
1663
1664 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1665
1666 if (ct != CATCH_TYPE_BREAK
1667 && ct != CATCH_TYPE_NEXT
1668 && ct != CATCH_TYPE_REDO) {
1669
1670 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1671 if (e == cont) {
1672 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1673 ELEM_INSERT_NEXT(end, &nop->link);
1674 break;
1675 }
1676 }
1677 }
1678 }
1679
1680 RB_GC_GUARD(catch_table_ary);
1681}
1682
1683static int
1684iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1685{
1686 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1687 return COMPILE_NG;
1688
1689 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1690
1691 if (compile_debug > 5)
1692 dump_disasm_list(FIRST_ELEMENT(anchor));
1693
1694 debugs("[compile step 3.1 (iseq_optimize)]\n");
1695 iseq_optimize(iseq, anchor);
1696
1697 if (compile_debug > 5)
1698 dump_disasm_list(FIRST_ELEMENT(anchor));
1699
1700 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1701 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1702 iseq_insns_unification(iseq, anchor);
1703 if (compile_debug > 5)
1704 dump_disasm_list(FIRST_ELEMENT(anchor));
1705 }
1706
1707 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1708 iseq_insert_nop_between_end_and_cont(iseq);
1709 if (compile_debug > 5)
1710 dump_disasm_list(FIRST_ELEMENT(anchor));
1711
1712 return COMPILE_OK;
1713}
1714
1715static int
1716iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1717{
1718 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1719 return COMPILE_NG;
1720
1721 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1722 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1723 if (compile_debug > 5)
1724 dump_disasm_list(FIRST_ELEMENT(anchor));
1725
1726 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1727 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1728
1729 debugs("[compile step 4.3 (set_optargs_table)] \n");
1730 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1731
1732 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1733 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1734
1735 debugs("[compile step 6 (update_catch_except_flags)] \n");
1736 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1737 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1738
1739 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1740 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1741 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1742 ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
1743 ISEQ_BODY(iseq)->catch_table = NULL;
1744 }
1745
1746#if VM_INSN_INFO_TABLE_IMPL == 2
1747 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1748 rb_iseq_insns_info_encode_positions(iseq);
1749#endif
1750
1751 if (compile_debug > 1) {
1752 VALUE str = rb_iseq_disasm(iseq);
1753 printf("%s\n", StringValueCStr(str));
1754 }
1755 verify_call_cache(iseq);
1756 debugs("[compile step: finish]\n");
1757
1758 return COMPILE_OK;
1759}
1760
1761static int
1762iseq_set_exception_local_table(rb_iseq_t *iseq)
1763{
1764 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1765 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1766 ISEQ_BODY(iseq)->lvar_states = NULL; // $! is read-only, so don't need lvar_states
1767 return COMPILE_OK;
1768}
1769
1770static int
1771get_lvar_level(const rb_iseq_t *iseq)
1772{
1773 int lev = 0;
1774 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1775 lev++;
1776 iseq = ISEQ_BODY(iseq)->parent_iseq;
1777 }
1778 return lev;
1779}
1780
1781static int
1782get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1783{
1784 unsigned int i;
1785
1786 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1787 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1788 return (int)i;
1789 }
1790 }
1791 return -1;
1792}
1793
1794static int
1795get_local_var_idx(const rb_iseq_t *iseq, ID id)
1796{
1797 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1798
1799 if (idx < 0) {
1800 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1801 "get_local_var_idx: %d", idx);
1802 }
1803
1804 return idx;
1805}
1806
1807static int
1808get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1809{
1810 int lv = 0, idx = -1;
1811 const rb_iseq_t *const topmost_iseq = iseq;
1812
1813 while (iseq) {
1814 idx = get_dyna_var_idx_at_raw(iseq, id);
1815 if (idx >= 0) {
1816 break;
1817 }
1818 iseq = ISEQ_BODY(iseq)->parent_iseq;
1819 lv++;
1820 }
1821
1822 if (idx < 0) {
1823 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1824 "get_dyna_var_idx: -1");
1825 }
1826
1827 *level = lv;
1828 *ls = ISEQ_BODY(iseq)->local_table_size;
1829 return idx;
1830}
1831
1832static int
1833iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1834{
1835 const struct rb_iseq_constant_body *body;
1836 while (level > 0) {
1837 iseq = ISEQ_BODY(iseq)->parent_iseq;
1838 level--;
1839 }
1840 body = ISEQ_BODY(iseq);
1841 if (body->local_iseq == iseq && /* local variables */
1842 body->param.flags.has_block &&
1843 body->local_table_size - body->param.block_start == idx) {
1844 return TRUE;
1845 }
1846 else {
1847 return FALSE;
1848 }
1849}
1850
1851static int
1852iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1853{
1854 int level, ls;
1855 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1856 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1857 *pidx = ls - idx;
1858 *plevel = level;
1859 return TRUE;
1860 }
1861 else {
1862 return FALSE;
1863 }
1864}
1865
1866static void
1867access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1868{
1869 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1870
1871 if (isolated_depth && level >= isolated_depth) {
1872 if (id == rb_intern("yield")) {
1873 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1874 }
1875 else {
1876 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1877 }
1878 }
1879
1880 for (int i=0; i<level; i++) {
1881 VALUE val;
1882 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1883
1884 if (!ovs) {
1885 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1886 }
1887
1888 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1889 if (write && !val) {
1890 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1891 }
1892 }
1893 else {
1894 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1895 }
1896
1897 iseq = ISEQ_BODY(iseq)->parent_iseq;
1898 }
1899}
1900
1901static ID
1902iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1903{
1904 for (int i=0; i<level; i++) {
1905 iseq = ISEQ_BODY(iseq)->parent_iseq;
1906 }
1907
1908 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1909 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1910 return id;
1911}
1912
1913static void
1914update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1915{
1916 for (int i=0; i<level; i++) {
1917 iseq = ISEQ_BODY(iseq)->parent_iseq;
1918 }
1919
1920 uint8_t *states = ISEQ_BODY(iseq)->lvar_states;
1921 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1922 switch (iseq_lvar_state_get(states, table_idx)) {
1923 case lvar_uninitialized:
1924 iseq_lvar_state_set(states, table_idx, lvar_initialized);
1925 break;
1926 case lvar_initialized:
1927 iseq_lvar_state_set(states, table_idx, lvar_reassigned);
1928 break;
1929 case lvar_reassigned:
1930 /* nothing */
1931 break;
1932 default:
1933 rb_bug("unreachable");
1934 }
1935}
1936
1937static int
1938iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1939{
1940 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1941 iseq_lvar_state_set(ISEQ_BODY(iseq)->lvar_states, i, lvar_initialized);
1942 }
1943
1944 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1945 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1946 for (int i=0; i<opt_num; i++) {
1947 iseq_lvar_state_set(ISEQ_BODY(iseq)->lvar_states, lead_num + i, lvar_uninitialized);
1948 }
1949
1950 return COMPILE_OK;
1951}
1952
1953static void
1954iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1955{
1956 if (iseq_local_block_param_p(iseq, idx, level)) {
1957 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1958 }
1959 else {
1960 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1961 }
1962 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1963}
1964
1965static void
1966iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1967{
1968 if (iseq_local_block_param_p(iseq, idx, level)) {
1969 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1970 }
1971 else {
1972 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1973 }
1974 update_lvar_state(iseq, level, idx);
1975 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1976}
1977
1978
1979
1980static void
1981iseq_calc_param_size(rb_iseq_t *iseq)
1982{
1983 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1984 if (body->param.flags.has_opt ||
1985 body->param.flags.has_post ||
1986 body->param.flags.has_rest ||
1987 body->param.flags.has_block ||
1988 body->param.flags.has_kw ||
1989 body->param.flags.has_kwrest) {
1990
1991 if (body->param.flags.has_block) {
1992 body->param.size = body->param.block_start + 1;
1993 }
1994 else if (body->param.flags.has_kwrest) {
1995 body->param.size = body->param.keyword->rest_start + 1;
1996 }
1997 else if (body->param.flags.has_kw) {
1998 body->param.size = body->param.keyword->bits_start + 1;
1999 }
2000 else if (body->param.flags.has_post) {
2001 body->param.size = body->param.post_start + body->param.post_num;
2002 }
2003 else if (body->param.flags.has_rest) {
2004 body->param.size = body->param.rest_start + 1;
2005 }
2006 else if (body->param.flags.has_opt) {
2007 body->param.size = body->param.lead_num + body->param.opt_num;
2008 }
2009 else {
2011 }
2012 }
2013 else {
2014 body->param.size = body->param.lead_num;
2015 }
2016}
2017
2018static int
2019iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
2020 const struct rb_args_info *args, int arg_size)
2021{
2022 const rb_node_kw_arg_t *node = args->kw_args;
2023 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2024 struct rb_iseq_param_keyword *keyword;
2025 const VALUE default_values = rb_ary_hidden_new(1);
2026 const VALUE complex_mark = rb_str_tmp_new(0);
2027 int kw = 0, rkw = 0, di = 0, i;
2028
2029 body->param.flags.has_kw = TRUE;
2030 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2031
2032 while (node) {
2033 kw++;
2034 node = node->nd_next;
2035 }
2036 if (kw > VM_CALL_KW_LEN_MAX) {
2037 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args)) "too many keyword parameters (%d, maximum is %d)",
2038 kw, (int)VM_CALL_KW_LEN_MAX);
2039 }
2040 arg_size += kw;
2041 keyword->bits_start = arg_size++;
2042
2043 node = args->kw_args;
2044 while (node) {
2045 const NODE *val_node = get_nd_value(node->nd_body);
2046 VALUE dv;
2047
2048 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2049 ++rkw;
2050 }
2051 else {
2052 switch (nd_type(val_node)) {
2053 case NODE_SYM:
2054 dv = rb_node_sym_string_val(val_node);
2055 break;
2056 case NODE_REGX:
2057 dv = rb_node_regx_string_val(val_node);
2058 break;
2059 case NODE_LINE:
2060 dv = rb_node_line_lineno_val(val_node);
2061 break;
2062 case NODE_INTEGER:
2063 dv = rb_node_integer_literal_val(val_node);
2064 break;
2065 case NODE_FLOAT:
2066 dv = rb_node_float_literal_val(val_node);
2067 break;
2068 case NODE_RATIONAL:
2069 dv = rb_node_rational_literal_val(val_node);
2070 break;
2071 case NODE_IMAGINARY:
2072 dv = rb_node_imaginary_literal_val(val_node);
2073 break;
2074 case NODE_ENCODING:
2075 dv = rb_node_encoding_val(val_node);
2076 break;
2077 case NODE_NIL:
2078 dv = Qnil;
2079 break;
2080 case NODE_TRUE:
2081 dv = Qtrue;
2082 break;
2083 case NODE_FALSE:
2084 dv = Qfalse;
2085 break;
2086 default:
2087 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2088 dv = complex_mark;
2089 }
2090
2091 keyword->num = ++di;
2092 rb_ary_push(default_values, dv);
2093 }
2094
2095 node = node->nd_next;
2096 }
2097
2098 keyword->num = kw;
2099
2100 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2101 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2102 keyword->rest_start = arg_size++;
2103 body->param.flags.has_kwrest = TRUE;
2104
2105 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2106 }
2107 keyword->required_num = rkw;
2108 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2109
2110 if (RARRAY_LEN(default_values)) {
2111 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2112
2113 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2114 VALUE dv = RARRAY_AREF(default_values, i);
2115 if (dv == complex_mark) dv = Qundef;
2117 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2118 }
2119
2120 keyword->default_values = dvs;
2121 }
2122 return arg_size;
2123}
2124
2125static void
2126iseq_set_use_block(rb_iseq_t *iseq)
2127{
2128 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2129 if (!body->param.flags.use_block) {
2130 body->param.flags.use_block = 1;
2131
2132 rb_vm_t *vm = GET_VM();
2133
2134 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2135 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2136 set_insert(&vm->unused_block_warning_table, key);
2137 }
2138 }
2139}
2140
2141static int
2142iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2143{
2144 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2145
2146 if (node_args) {
2147 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2148 const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
2149 ID rest_id = 0;
2150 int last_comma = 0;
2151 ID block_id = 0;
2152 int arg_size;
2153
2154 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2155
2156 body->param.lead_num = arg_size = (int)args->pre_args_num;
2157 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2158 debugs(" - argc: %d\n", body->param.lead_num);
2159
2160 rest_id = args->rest_arg;
2161 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2162 last_comma = 1;
2163 rest_id = 0;
2164 }
2165 block_id = args->block_arg;
2166
2167 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2168
2169 if (optimized_forward) {
2170 rest_id = 0;
2171 block_id = 0;
2172 }
2173
2174 if (args->opt_args) {
2175 const rb_node_opt_arg_t *node = args->opt_args;
2176 LABEL *label;
2177 VALUE labels = rb_ary_hidden_new(1);
2178 VALUE *opt_table;
2179 int i = 0, j;
2180
2181 while (node) {
2182 label = NEW_LABEL(nd_line(RNODE(node)));
2183 rb_ary_push(labels, (VALUE)label | 1);
2184 ADD_LABEL(optargs, label);
2185 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2186 node = node->nd_next;
2187 i += 1;
2188 }
2189
2190 /* last label */
2191 label = NEW_LABEL(nd_line(node_args));
2192 rb_ary_push(labels, (VALUE)label | 1);
2193 ADD_LABEL(optargs, label);
2194
2195 opt_table = ALLOC_N(VALUE, i+1);
2196
2197 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2198 for (j = 0; j < i+1; j++) {
2199 opt_table[j] &= ~1;
2200 }
2201 rb_ary_clear(labels);
2202
2203 body->param.flags.has_opt = TRUE;
2204 body->param.opt_num = i;
2205 body->param.opt_table = opt_table;
2206 arg_size += i;
2207 }
2208
2209 if (rest_id) {
2210 body->param.rest_start = arg_size++;
2211 body->param.flags.has_rest = TRUE;
2212 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2213 RUBY_ASSERT(body->param.rest_start != -1);
2214 }
2215
2216 if (args->first_post_arg) {
2217 body->param.post_start = arg_size;
2218 body->param.post_num = args->post_args_num;
2219 body->param.flags.has_post = TRUE;
2220 arg_size += args->post_args_num;
2221
2222 if (body->param.flags.has_rest) { /* TODO: why that? */
2223 body->param.post_start = body->param.rest_start + 1;
2224 }
2225 }
2226
2227 if (args->kw_args) {
2228 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2229 }
2230 else if (args->kw_rest_arg && !optimized_forward) {
2231 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2232 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2233 keyword->rest_start = arg_size++;
2234 body->param.keyword = keyword;
2235 body->param.flags.has_kwrest = TRUE;
2236
2237 static ID anon_kwrest = 0;
2238 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2239 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2240 }
2241 else if (args->no_kwarg) {
2242 body->param.flags.accepts_no_kwarg = TRUE;
2243 }
2244
2245 if (args->no_blockarg) {
2246 body->param.flags.accepts_no_block = TRUE;
2247 }
2248 else if (block_id) {
2249 body->param.block_start = arg_size++;
2250 body->param.flags.has_block = TRUE;
2251 iseq_set_use_block(iseq);
2252 }
2253
2254 // Only optimize specifically methods like this: `foo(...)`
2255 if (optimized_forward) {
2256 body->param.flags.use_block = 1;
2257 body->param.flags.forwardable = TRUE;
2258 arg_size = 1;
2259 }
2260
2261 iseq_calc_param_size(iseq);
2262 body->param.size = arg_size;
2263
2264 if (args->pre_init) { /* m_init */
2265 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2266 }
2267 if (args->post_init) { /* p_init */
2268 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2269 }
2270
2271 if (body->type == ISEQ_TYPE_BLOCK) {
2272 if (body->param.flags.has_opt == FALSE &&
2273 body->param.flags.has_post == FALSE &&
2274 body->param.flags.has_rest == FALSE &&
2275 body->param.flags.has_kw == FALSE &&
2276 body->param.flags.has_kwrest == FALSE) {
2277
2278 if (body->param.lead_num == 1 && last_comma == 0) {
2279 /* {|a|} */
2280 body->param.flags.ambiguous_param0 = TRUE;
2281 }
2282 }
2283 }
2284 }
2285
2286 return COMPILE_OK;
2287}
2288
2289static int
2290iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2291{
2292 unsigned int size = tbl ? tbl->size : 0;
2293 unsigned int offset = 0;
2294
2295 if (node_args) {
2296 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2297
2298 // If we have a function that only has `...` as the parameter,
2299 // then its local table should only be `...`
2300 // FIXME: I think this should be fixed in the AST rather than special case here.
2301 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2302 CHECK(size >= 3);
2303 size -= 3;
2304 offset += 3;
2305 }
2306 }
2307
2308 if (size > 0) {
2309 ID *ids = ALLOC_N(ID, size);
2310 MEMCPY(ids, tbl->ids + offset, ID, size);
2311 ISEQ_BODY(iseq)->local_table = ids;
2312
2313 ISEQ_BODY(iseq)->lvar_states = ZALLOC_N(uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
2314 }
2315 ISEQ_BODY(iseq)->local_table_size = size;
2316
2317 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2318 return COMPILE_OK;
2319}
2320
2321int
2322rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2323{
2324 int tval, tlit;
2325
2326 if (val == lit) {
2327 return 0;
2328 }
2329 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2330 return val != lit;
2331 }
2332 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2333 return -1;
2334 }
2335 else if (tlit != tval) {
2336 return -1;
2337 }
2338 else if (tlit == T_SYMBOL) {
2339 return val != lit;
2340 }
2341 else if (tlit == T_STRING) {
2342 return rb_str_hash_cmp(lit, val);
2343 }
2344 else if (tlit == T_BIGNUM) {
2345 long x = FIX2LONG(rb_big_cmp(lit, val));
2346
2347 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2348 * There is no need to call rb_fix2int here. */
2349 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2350 return (int)x;
2351 }
2352 else if (tlit == T_FLOAT) {
2353 return rb_float_cmp(lit, val);
2354 }
2355 else if (tlit == T_RATIONAL) {
2356 const struct RRational *rat1 = RRATIONAL(val);
2357 const struct RRational *rat2 = RRATIONAL(lit);
2358 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2359 }
2360 else if (tlit == T_COMPLEX) {
2361 const struct RComplex *comp1 = RCOMPLEX(val);
2362 const struct RComplex *comp2 = RCOMPLEX(lit);
2363 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2364 }
2365 else if (tlit == T_REGEXP) {
2366 return rb_reg_equal(val, lit) ? 0 : -1;
2367 }
2368 else {
2370 }
2371}
2372
2373st_index_t
2374rb_iseq_cdhash_hash(VALUE a)
2375{
2376 switch (OBJ_BUILTIN_TYPE(a)) {
2377 case -1:
2378 case T_SYMBOL:
2379 return (st_index_t)a;
2380 case T_STRING:
2381 return rb_str_hash(a);
2382 case T_BIGNUM:
2383 return FIX2LONG(rb_big_hash(a));
2384 case T_FLOAT:
2385 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2386 case T_RATIONAL:
2387 return rb_rational_hash(a);
2388 case T_COMPLEX:
2389 return rb_complex_hash(a);
2390 case T_REGEXP:
2391 return NUM2LONG(rb_reg_hash(a));
2392 default:
2394 }
2395}
2396
2397static const struct st_hash_type cdhash_type = {
2398 rb_iseq_cdhash_cmp,
2399 rb_iseq_cdhash_hash,
2400};
2401
2402static VALUE
2403cdhash_new(size_t size)
2404{
2405 VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
2406 RB_OBJ_SET_SHAREABLE(cdhash);
2407 return cdhash;
2408}
2409
2410static void
2411cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
2412{
2413 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2414 st_insert(tbl, key, val);
2415 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2416}
2417
2418static void
2419cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
2420{
2421 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2422 VALUE dontcare;
2423 if (!st_lookup(tbl, key, &dontcare)) {
2424 st_insert(tbl, key, val);
2425 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2426 }
2427}
2428
2430 VALUE hash;
2431 int pos;
2432 int len;
2433};
2434
2435static int
2436cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
2437{
2438 return ST_REPLACE;
2439}
2440
2441static int
2442cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
2443{
2444 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2445 LABEL *lobj = (LABEL *)(*value & ~1);
2446 *value = lobj->position - (data->pos+data->len);
2447 return ST_CONTINUE;
2448}
2449
2450static inline VALUE
2451get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2452{
2453 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2454}
2455
2456static inline VALUE
2457get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2458{
2459 VALUE val;
2460 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2461 if (tbl) {
2462 if (rb_id_table_lookup(tbl,id,&val)) {
2463 return val;
2464 }
2465 }
2466 else {
2467 tbl = rb_id_table_create(1);
2468 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2469 }
2470 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2471 rb_id_table_insert(tbl,id,val);
2472 return val;
2473}
2474
2475#define BADINSN_DUMP(anchor, list, dest) \
2476 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2477
2478#define BADINSN_ERROR \
2479 (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
2480 SIZED_FREE_N(insns_info, insns_info_size), \
2481 BADINSN_DUMP(anchor, list, NULL), \
2482 COMPILE_ERROR)
2483
2484static int
2485fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2486{
2487 int stack_max = 0, sp = 0, line = 0;
2488 LINK_ELEMENT *list;
2489
2490 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2491 if (IS_LABEL(list)) {
2492 LABEL *lobj = (LABEL *)list;
2493 lobj->set = TRUE;
2494 }
2495 }
2496
2497 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2498 switch (list->type) {
2499 case ISEQ_ELEMENT_INSN:
2500 {
2501 int j, len, insn;
2502 const char *types;
2503 VALUE *operands;
2504 INSN *iobj = (INSN *)list;
2505
2506 /* update sp */
2507 sp = calc_sp_depth(sp, iobj);
2508 if (sp < 0) {
2509 BADINSN_DUMP(anchor, list, NULL);
2510 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2511 "argument stack underflow (%d)", sp);
2512 return -1;
2513 }
2514 if (sp > stack_max) {
2515 stack_max = sp;
2516 }
2517
2518 line = iobj->insn_info.line_no;
2519 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2520 operands = iobj->operands;
2521 insn = iobj->insn_id;
2522 types = insn_op_types(insn);
2523 len = insn_len(insn);
2524
2525 /* operand check */
2526 if (iobj->operand_size != len - 1) {
2527 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2528 BADINSN_DUMP(anchor, list, NULL);
2529 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2530 "operand size miss! (%d for %d)",
2531 iobj->operand_size, len - 1);
2532 return -1;
2533 }
2534
2535 for (j = 0; types[j]; j++) {
2536 if (types[j] == TS_OFFSET) {
2537 /* label(destination position) */
2538 LABEL *lobj = (LABEL *)operands[j];
2539 if (!lobj->set) {
2540 BADINSN_DUMP(anchor, list, NULL);
2541 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2542 "unknown label: "LABEL_FORMAT, lobj->label_no);
2543 return -1;
2544 }
2545 if (lobj->sp == -1) {
2546 lobj->sp = sp;
2547 }
2548 else if (lobj->sp != sp) {
2549 VALUE path = rb_iseq_path(iseq);
2550 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2551 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2552 lobj->label_no, lobj->sp, sp);
2553 }
2554 }
2555 }
2556 break;
2557 }
2558 case ISEQ_ELEMENT_LABEL:
2559 {
2560 LABEL *lobj = (LABEL *)list;
2561 if (lobj->sp == -1) {
2562 lobj->sp = sp;
2563 }
2564 else {
2565 if (lobj->sp != sp) {
2566 VALUE path = rb_iseq_path(iseq);
2567 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2568 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2569 lobj->label_no, lobj->sp, sp);
2570 }
2571 sp = lobj->sp;
2572 }
2573 break;
2574 }
2575 case ISEQ_ELEMENT_TRACE:
2576 {
2577 /* ignore */
2578 break;
2579 }
2580 case ISEQ_ELEMENT_ADJUST:
2581 {
2582 ADJUST *adjust = (ADJUST *)list;
2583 int orig_sp = sp;
2584
2585 sp = adjust->label ? adjust->label->sp : 0;
2586 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2587 BADINSN_DUMP(anchor, list, NULL);
2588 COMPILE_ERROR(iseq, adjust->line_no,
2589 "iseq_set_sequence: adjust bug %d < %d",
2590 orig_sp, sp);
2591 return -1;
2592 }
2593 break;
2594 }
2595 default:
2596 BADINSN_DUMP(anchor, list, NULL);
2597 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2598 return -1;
2599 }
2600 }
2601 return stack_max;
2602}
2603
2604static int
2605add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2606 int insns_info_index, int code_index, const INSN *iobj)
2607{
2608 if (insns_info_index == 0 ||
2609 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2610#ifdef USE_ISEQ_NODE_ID
2611 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2612#endif
2613 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2614 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2615#ifdef USE_ISEQ_NODE_ID
2616 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2617#endif
2618 insns_info[insns_info_index].events = iobj->insn_info.events;
2619 positions[insns_info_index] = code_index;
2620 return TRUE;
2621 }
2622 return FALSE;
2623}
2624
2625static int
2626add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2627 int insns_info_index, int code_index, const ADJUST *adjust)
2628{
2629 insns_info[insns_info_index].line_no = adjust->line_no;
2630 insns_info[insns_info_index].node_id = -1;
2631 insns_info[insns_info_index].events = 0;
2632 positions[insns_info_index] = code_index;
2633 return TRUE;
2634}
2635
2636static ID *
2637array_to_idlist(VALUE arr)
2638{
2640 long size = RARRAY_LEN(arr);
2641 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2642 for (long i = 0; i < size; i++) {
2643 VALUE sym = RARRAY_AREF(arr, i);
2644 ids[i] = SYM2ID(sym);
2645 }
2646 ids[size] = 0;
2647 return ids;
2648}
2649
2650static VALUE
2651idlist_to_array(const ID *ids)
2652{
2653 VALUE arr = rb_ary_new();
2654 while (*ids) {
2655 rb_ary_push(arr, ID2SYM(*ids++));
2656 }
2657 return arr;
2658}
2659
2663static int
2664iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2665{
2666 struct iseq_insn_info_entry *insns_info;
2667 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2668 unsigned int *positions;
2669 LINK_ELEMENT *list;
2670 VALUE *generated_iseq;
2671 rb_event_flag_t events = 0;
2672 long data = 0;
2673
2674 int insn_num, code_index, insns_info_index, sp = 0;
2675 int stack_max = fix_sp_depth(iseq, anchor);
2676
2677 if (stack_max < 0) return COMPILE_NG;
2678
2679 /* fix label position */
2680 insn_num = code_index = 0;
2681 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2682 switch (list->type) {
2683 case ISEQ_ELEMENT_INSN:
2684 {
2685 INSN *iobj = (INSN *)list;
2686 /* update sp */
2687 sp = calc_sp_depth(sp, iobj);
2688 insn_num++;
2689 events = iobj->insn_info.events |= events;
2690 if (ISEQ_COVERAGE(iseq)) {
2691 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2692 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2693 int line = iobj->insn_info.line_no - 1;
2694 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2695 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2696 }
2697 }
2698 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2699 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2700 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2701 }
2702 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2703 }
2704 }
2705 code_index += insn_data_length(iobj);
2706 events = 0;
2707 data = 0;
2708 break;
2709 }
2710 case ISEQ_ELEMENT_LABEL:
2711 {
2712 LABEL *lobj = (LABEL *)list;
2713 lobj->position = code_index;
2714 if (lobj->sp != sp) {
2715 VALUE path = rb_iseq_path(iseq);
2716 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2717 RSTRING_LENINT(path), RSTRING_PTR(path),
2718 lobj->label_no, lobj->sp, sp);
2719 }
2720 sp = lobj->sp;
2721 break;
2722 }
2723 case ISEQ_ELEMENT_TRACE:
2724 {
2725 TRACE *trace = (TRACE *)list;
2726 events |= trace->event;
2727 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2728 break;
2729 }
2730 case ISEQ_ELEMENT_ADJUST:
2731 {
2732 ADJUST *adjust = (ADJUST *)list;
2733 if (adjust->line_no != -1) {
2734 int orig_sp = sp;
2735 sp = adjust->label ? adjust->label->sp : 0;
2736 if (orig_sp - sp > 0) {
2737 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2738 code_index++; /* insn */
2739 insn_num++;
2740 }
2741 }
2742 break;
2743 }
2744 default: break;
2745 }
2746 }
2747
2748 /* make instruction sequence */
2749 const int generated_iseq_size = code_index;
2750 generated_iseq = ALLOC_N(VALUE, code_index);
2751
2752 const int insns_info_size = insn_num;
2753 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2754
2755 const int positions_size = insn_num;
2756 positions = ALLOC_N(unsigned int, insn_num);
2757 if (ISEQ_IS_SIZE(body)) {
2758 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2759 }
2760 else {
2761 body->is_entries = NULL;
2762 }
2763
2764 if (body->ci_size) {
2765 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2766 }
2767 else {
2768 body->call_data = NULL;
2769 }
2770 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2771
2772 // Calculate the bitmask buffer size.
2773 // Round the generated_iseq size up to the nearest multiple
2774 // of the number of bits in an unsigned long.
2775
2776 // Allocate enough room for the bitmask list
2777 iseq_bits_t * mark_offset_bits;
2778 int code_size = code_index;
2779
2780 bool needs_bitmap = false;
2781
2782 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2783 if (mark_offset_bits_size == 1) {
2784 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2785 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2786 }
2787 else {
2788 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2789 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2790 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2791 }
2792
2793 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2794 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2795
2796 list = FIRST_ELEMENT(anchor);
2797 insns_info_index = code_index = sp = 0;
2798
2799 while (list) {
2800 switch (list->type) {
2801 case ISEQ_ELEMENT_INSN:
2802 {
2803 int j, len, insn;
2804 const char *types;
2805 VALUE *operands;
2806 INSN *iobj = (INSN *)list;
2807
2808 /* update sp */
2809 sp = calc_sp_depth(sp, iobj);
2810 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2811 operands = iobj->operands;
2812 insn = iobj->insn_id;
2813 generated_iseq[code_index] = insn;
2814 types = insn_op_types(insn);
2815 len = insn_len(insn);
2816
2817 for (j = 0; types[j]; j++) {
2818 char type = types[j];
2819
2820 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2821 switch (type) {
2822 case TS_OFFSET:
2823 {
2824 /* label(destination position) */
2825 LABEL *lobj = (LABEL *)operands[j];
2826 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2827 break;
2828 }
2829 case TS_CDHASH:
2830 {
2831 VALUE map = operands[j];
2832 struct cdhash_set_label_struct data;
2833 data.hash = map;
2834 data.pos = code_index;
2835 data.len = len;
2836 st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
2837
2838 generated_iseq[code_index + 1 + j] = map;
2839 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2840 RB_OBJ_WRITTEN(iseq, Qundef, map);
2841 needs_bitmap = true;
2842 break;
2843 }
2844 case TS_LINDEX:
2845 case TS_NUM: /* ulong */
2846 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2847 break;
2848 case TS_ISEQ: /* iseq */
2849 case TS_VALUE: /* VALUE */
2850 {
2851 VALUE v = operands[j];
2852 generated_iseq[code_index + 1 + j] = v;
2853 /* to mark ruby object */
2854 if (!SPECIAL_CONST_P(v)) {
2855 RB_OBJ_WRITTEN(iseq, Qundef, v);
2856 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2857 needs_bitmap = true;
2858 }
2859 break;
2860 }
2861 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2862 case TS_IC: /* inline cache: constants */
2863 {
2864 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2865 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2866 if (UNLIKELY(ic_index >= body->ic_size)) {
2867 BADINSN_DUMP(anchor, &iobj->link, 0);
2868 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2869 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2870 ic_index, ISEQ_IS_SIZE(body));
2871 }
2872
2873 ic->segments = array_to_idlist(operands[j]);
2874
2875 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2876 }
2877 break;
2878 case TS_IVC: /* inline ivar cache */
2879 {
2880 unsigned int ic_index = FIX2UINT(operands[j]);
2881
2882 IVC cache = ((IVC)&body->is_entries[ic_index]);
2883
2884 if (insn == BIN(setinstancevariable)) {
2885 cache->iv_set_name = SYM2ID(operands[j - 1]);
2886 cache->value = IVAR_CACHE_INIT;
2887 }
2888 else {
2889 cache->iv_set_name = 0;
2890 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
2891 }
2892 }
2893 case TS_ISE: /* inline storage entry: `once` insn */
2894 case TS_ICVARC: /* inline cvar cache */
2895 {
2896 unsigned int ic_index = FIX2UINT(operands[j]);
2897 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2898 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2899 BADINSN_DUMP(anchor, &iobj->link, 0);
2900 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2901 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2902 ic_index, ISEQ_IS_SIZE(body));
2903 }
2904 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2905
2906 break;
2907 }
2908 case TS_CALLDATA:
2909 {
2910 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2911 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2912 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2913 cd->ci = source_ci;
2914 cd->cc = vm_cc_empty();
2915 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2916 break;
2917 }
2918 case TS_ID: /* ID */
2919 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2920 break;
2921 case TS_FUNCPTR:
2922 generated_iseq[code_index + 1 + j] = operands[j];
2923 break;
2924 case TS_BUILTIN:
2925 generated_iseq[code_index + 1 + j] = operands[j];
2926 break;
2927 default:
2928 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2929 "unknown operand type: %c", type);
2930 return COMPILE_NG;
2931 }
2932 }
2933 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2934 code_index += len;
2935 break;
2936 }
2937 case ISEQ_ELEMENT_LABEL:
2938 {
2939 LABEL *lobj = (LABEL *)list;
2940 if (lobj->sp != sp) {
2941 VALUE path = rb_iseq_path(iseq);
2942 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2943 RSTRING_LENINT(path), RSTRING_PTR(path),
2944 lobj->label_no, lobj->sp, sp);
2945 }
2946 sp = lobj->sp;
2947 break;
2948 }
2949 case ISEQ_ELEMENT_ADJUST:
2950 {
2951 ADJUST *adjust = (ADJUST *)list;
2952 int orig_sp = sp;
2953
2954 if (adjust->label) {
2955 sp = adjust->label->sp;
2956 }
2957 else {
2958 sp = 0;
2959 }
2960
2961 if (adjust->line_no != -1) {
2962 const int diff = orig_sp - sp;
2963 if (diff > 0) {
2964 if (insns_info_index == 0) {
2965 COMPILE_ERROR(iseq, adjust->line_no,
2966 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2967 }
2968 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2969 }
2970 if (diff > 1) {
2971 generated_iseq[code_index++] = BIN(adjuststack);
2972 generated_iseq[code_index++] = orig_sp - sp;
2973 }
2974 else if (diff == 1) {
2975 generated_iseq[code_index++] = BIN(pop);
2976 }
2977 else if (diff < 0) {
2978 int label_no = adjust->label ? adjust->label->label_no : -1;
2979 SIZED_FREE_N(generated_iseq, generated_iseq_size);
2980 SIZED_FREE_N(insns_info, insns_info_size);
2981 SIZED_FREE_N(positions, positions_size);
2982 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2983 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
2984 }
2985 debug_list(anchor, list);
2986 COMPILE_ERROR(iseq, adjust->line_no,
2987 "iseq_set_sequence: adjust bug to %d %d < %d",
2988 label_no, orig_sp, sp);
2989 return COMPILE_NG;
2990 }
2991 }
2992 break;
2993 }
2994 default:
2995 /* ignore */
2996 break;
2997 }
2998 list = list->next;
2999 }
3000
3001 body->iseq_encoded = (void *)generated_iseq;
3002 body->iseq_size = code_index;
3003 body->stack_max = stack_max;
3004
3005 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
3006 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
3007 }
3008 else {
3009 if (needs_bitmap) {
3010 body->mark_bits.list = mark_offset_bits;
3011 }
3012 else {
3013 body->mark_bits.list = NULL;
3014 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
3015 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
3016 }
3017 }
3018
3019 /* get rid of memory leak when REALLOC failed */
3020 body->insns_info.body = insns_info;
3021 body->insns_info.positions_or_succ_index_table.positions = positions;
3022
3023 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
3024 body->insns_info.body = insns_info;
3025 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
3026 body->insns_info.positions_or_succ_index_table.positions = positions;
3027 body->insns_info.size = insns_info_index;
3028
3029 return COMPILE_OK;
3030}
3031
3032static int
3033label_get_position(LABEL *lobj)
3034{
3035 return lobj->position;
3036}
3037
3038static int
3039label_get_sp(LABEL *lobj)
3040{
3041 return lobj->sp;
3042}
3043
3044static int
3045iseq_set_exception_table(rb_iseq_t *iseq)
3046{
3047 const VALUE *tptr, *ptr;
3048 unsigned int tlen, i;
3049 struct iseq_catch_table_entry *entry;
3050
3051 ISEQ_BODY(iseq)->catch_table = NULL;
3052
3053 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
3054 if (NIL_P(catch_table_ary)) return COMPILE_OK;
3055 tlen = (int)RARRAY_LEN(catch_table_ary);
3056 tptr = RARRAY_CONST_PTR(catch_table_ary);
3057
3058 if (tlen > 0) {
3059 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
3060 table->size = tlen;
3061
3062 for (i = 0; i < table->size; i++) {
3063 int pos;
3064 ptr = RARRAY_CONST_PTR(tptr[i]);
3065 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
3066 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
3067 pos = label_get_position((LABEL *)(ptr[1] & ~1));
3068 RUBY_ASSERT(pos >= 0);
3069 entry->start = (unsigned int)pos;
3070 pos = label_get_position((LABEL *)(ptr[2] & ~1));
3071 RUBY_ASSERT(pos >= 0);
3072 entry->end = (unsigned int)pos;
3073 entry->iseq = (rb_iseq_t *)ptr[3];
3074 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
3075
3076 /* stack depth */
3077 if (ptr[4]) {
3078 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3079 entry->cont = label_get_position(lobj);
3080 entry->sp = label_get_sp(lobj);
3081
3082 /* TODO: Dirty Hack! Fix me */
3083 if (entry->type == CATCH_TYPE_RESCUE ||
3084 entry->type == CATCH_TYPE_BREAK ||
3085 entry->type == CATCH_TYPE_NEXT) {
3086 RUBY_ASSERT(entry->sp > 0);
3087 entry->sp--;
3088 }
3089 }
3090 else {
3091 entry->cont = 0;
3092 }
3093 }
3094 ISEQ_BODY(iseq)->catch_table = table;
3095 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3096 }
3097
3098 RB_GC_GUARD(catch_table_ary);
3099
3100 return COMPILE_OK;
3101}
3102
3103/*
3104 * set optional argument table
3105 * def foo(a, b=expr1, c=expr2)
3106 * =>
3107 * b:
3108 * expr1
3109 * c:
3110 * expr2
3111 */
3112static int
3113iseq_set_optargs_table(rb_iseq_t *iseq)
3114{
3115 int i;
3116 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3117
3118 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3119 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3120 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3121 }
3122 }
3123 return COMPILE_OK;
3124}
3125
3126static LINK_ELEMENT *
3127get_destination_insn(INSN *iobj)
3128{
3129 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3130 LINK_ELEMENT *list;
3131 rb_event_flag_t events = 0;
3132
3133 list = lobj->link.next;
3134 while (list) {
3135 switch (list->type) {
3136 case ISEQ_ELEMENT_INSN:
3137 case ISEQ_ELEMENT_ADJUST:
3138 goto found;
3139 case ISEQ_ELEMENT_LABEL:
3140 /* ignore */
3141 break;
3142 case ISEQ_ELEMENT_TRACE:
3143 {
3144 TRACE *trace = (TRACE *)list;
3145 events |= trace->event;
3146 }
3147 break;
3148 default: break;
3149 }
3150 list = list->next;
3151 }
3152 found:
3153 if (list && IS_INSN(list)) {
3154 INSN *iobj = (INSN *)list;
3155 iobj->insn_info.events |= events;
3156 }
3157 return list;
3158}
3159
3160static LINK_ELEMENT *
3161get_next_insn(INSN *iobj)
3162{
3163 LINK_ELEMENT *list = iobj->link.next;
3164
3165 while (list) {
3166 if (IS_INSN(list) || IS_ADJUST(list)) {
3167 return list;
3168 }
3169 list = list->next;
3170 }
3171 return 0;
3172}
3173
3174static LINK_ELEMENT *
3175get_prev_insn(INSN *iobj)
3176{
3177 LINK_ELEMENT *list = iobj->link.prev;
3178
3179 while (list) {
3180 if (IS_INSN(list) || IS_ADJUST(list)) {
3181 return list;
3182 }
3183 list = list->prev;
3184 }
3185 return 0;
3186}
3187
3188static void
3189unref_destination(INSN *iobj, int pos)
3190{
3191 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3192 --lobj->refcnt;
3193 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3194}
3195
3196static bool
3197replace_destination(INSN *dobj, INSN *nobj)
3198{
3199 VALUE n = OPERAND_AT(nobj, 0);
3200 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3201 LABEL *nl = (LABEL *)n;
3202 if (dl == nl) return false;
3203 --dl->refcnt;
3204 ++nl->refcnt;
3205 OPERAND_AT(dobj, 0) = n;
3206 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3207 return true;
3208}
3209
3210static LABEL*
3211find_destination(INSN *i)
3212{
3213 int pos, len = insn_len(i->insn_id);
3214 for (pos = 0; pos < len; ++pos) {
3215 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3216 return (LABEL *)OPERAND_AT(i, pos);
3217 }
3218 }
3219 return 0;
3220}
3221
3222static int
3223remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3224{
3225 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3226 LABEL *pending = 0;
3227 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3228
3229 if (!i) return 0;
3230 unref_counts = ALLOCA_N(int, nlabels);
3231 MEMZERO(unref_counts, int, nlabels);
3232
3233 end = i;
3234 scan = i;
3235 do {
3236 LABEL *lab;
3237 if (IS_INSN(scan)) {
3238 if (IS_INSN_ID(scan, leave)) {
3239 if (pending) break;
3240 end = scan;
3241 break;
3242 }
3243 else if ((lab = find_destination((INSN *)scan)) != 0) {
3244 unref_counts[lab->label_no]++;
3245 if (lab == pending && lab->refcnt <= unref_counts[lab->label_no]) {
3246 pending = 0;
3247 }
3248 }
3249 }
3250 else if (IS_LABEL(scan)) {
3251 lab = (LABEL *)scan;
3252 if (lab->unremovable) {
3253 if (pending) break;
3254 return 0;
3255 }
3256 if (lab->refcnt > unref_counts[lab->label_no]) {
3257 if (pending) break;
3258 pending = lab;
3259 pending_end = (scan == first) ? 0 : end;
3260 }
3261 continue;
3262 }
3263 else if (IS_ADJUST(scan)) {
3264 if (pending) break;
3265 return 0;
3266 }
3267 if (!pending) end = scan;
3268 } while ((scan = scan->next) != 0);
3269
3270 if (pending) {
3271 if (!pending_end) return 0;
3272 end = pending_end;
3273 }
3274 i = first;
3275 do {
3276 if (IS_INSN(i)) {
3277 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3278 VALUE insn = INSN_OF(i);
3279 int pos, len = insn_len(insn);
3280 for (pos = 0; pos < len; ++pos) {
3281 switch (insn_op_types(insn)[pos]) {
3282 case TS_OFFSET:
3283 unref_destination((INSN *)i, pos);
3284 break;
3285 case TS_CALLDATA:
3286 --(body->ci_size);
3287 break;
3288 }
3289 }
3290 }
3291 ELEM_REMOVE(i);
3292 } while ((i != end) && (i = i->next) != 0);
3293 return 1;
3294}
3295
3296static int
3297iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3298{
3299 switch (OPERAND_AT(iobj, 0)) {
3300 case INT2FIX(0): /* empty array */
3301 ELEM_REMOVE(&iobj->link);
3302 return TRUE;
3303 case INT2FIX(1): /* single element array */
3304 ELEM_REMOVE(&iobj->link);
3305 return FALSE;
3306 default:
3307 iobj->insn_id = BIN(adjuststack);
3308 return TRUE;
3309 }
3310}
3311
3312static int
3313is_frozen_putstring(INSN *insn, VALUE *op)
3314{
3315 if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
3316 *op = OPERAND_AT(insn, 0);
3317 return 1;
3318 }
3319 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3320 *op = OPERAND_AT(insn, 0);
3321 return RB_TYPE_P(*op, T_STRING);
3322 }
3323 return 0;
3324}
3325
3326static int
3327insn_has_label_before(LINK_ELEMENT *elem)
3328{
3329 LINK_ELEMENT *prev = elem->prev;
3330 while (prev) {
3331 if (prev->type == ISEQ_ELEMENT_LABEL) {
3332 LABEL *label = (LABEL *)prev;
3333 if (label->refcnt > 0) {
3334 return 1;
3335 }
3336 }
3337 else if (prev->type == ISEQ_ELEMENT_INSN) {
3338 break;
3339 }
3340 prev = prev->prev;
3341 }
3342 return 0;
3343}
3344
3345static int
3346optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3347{
3348 /*
3349 * putobject obj
3350 * dup
3351 * checktype T_XXX
3352 * branchif l1
3353 * l2:
3354 * ...
3355 * l1:
3356 *
3357 * => obj is a T_XXX
3358 *
3359 * putobject obj (T_XXX)
3360 * jump L1
3361 * L1:
3362 *
3363 * => obj is not a T_XXX
3364 *
3365 * putobject obj (T_XXX)
3366 * jump L2
3367 * L2:
3368 */
3369 int line, node_id;
3370 INSN *niobj, *ciobj, *dup = 0;
3371 LABEL *dest = 0;
3372 VALUE type;
3373
3374 switch (INSN_OF(iobj)) {
3375 case BIN(dupstring):
3376 case BIN(dupchilledstring):
3378 break;
3379 case BIN(putnil):
3380 type = INT2FIX(T_NIL);
3381 break;
3382 case BIN(putobject):
3383 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3384 break;
3385 default: return FALSE;
3386 }
3387
3388 ciobj = (INSN *)get_next_insn(iobj);
3389 if (IS_INSN_ID(ciobj, jump)) {
3390 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3391 }
3392 if (IS_INSN_ID(ciobj, dup)) {
3393 ciobj = (INSN *)get_next_insn(dup = ciobj);
3394 }
3395 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3396 niobj = (INSN *)get_next_insn(ciobj);
3397 if (!niobj) {
3398 /* TODO: putobject true/false */
3399 return FALSE;
3400 }
3401 switch (INSN_OF(niobj)) {
3402 case BIN(branchif):
3403 if (OPERAND_AT(ciobj, 0) == type) {
3404 dest = (LABEL *)OPERAND_AT(niobj, 0);
3405 }
3406 break;
3407 case BIN(branchunless):
3408 if (OPERAND_AT(ciobj, 0) != type) {
3409 dest = (LABEL *)OPERAND_AT(niobj, 0);
3410 }
3411 break;
3412 default:
3413 return FALSE;
3414 }
3415 line = ciobj->insn_info.line_no;
3416 node_id = ciobj->insn_info.node_id;
3417 if (!dest) {
3418 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3419 dest = (LABEL *)niobj->link.next; /* reuse label */
3420 }
3421 else {
3422 dest = NEW_LABEL(line);
3423 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3424 }
3425 }
3426 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3427 LABEL_REF(dest);
3428 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3429 return TRUE;
3430}
3431
3432static const struct rb_callinfo *
3433ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3434{
3435 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3436 vm_ci_flag(ci) | add,
3437 vm_ci_argc(ci),
3438 vm_ci_kwarg(ci));
3439 RB_OBJ_WRITTEN(iseq, ci, nci);
3440 return nci;
3441}
3442
3443static const struct rb_callinfo *
3444ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3445{
3446 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3447 vm_ci_flag(ci),
3448 argc,
3449 vm_ci_kwarg(ci));
3450 RB_OBJ_WRITTEN(iseq, ci, nci);
3451 return nci;
3452}
3453
3454#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3455
3456static VALUE
3457iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3458{
3459 VALUE errinfo = rb_errinfo();
3460 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3461 if (NIL_P(re)) {
3462 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3463 rb_set_errinfo(errinfo);
3464 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3465 }
3466 else {
3467 RB_OBJ_SET_SHAREABLE(re);
3468 }
3469 return re;
3470}
3471
3472static int
3473iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3474{
3475 INSN *const iobj = (INSN *)list;
3476
3477 again:
3478 optimize_checktype(iseq, iobj);
3479
3480 if (IS_INSN_ID(iobj, jump)) {
3481 INSN *niobj, *diobj, *piobj;
3482 diobj = (INSN *)get_destination_insn(iobj);
3483 niobj = (INSN *)get_next_insn(iobj);
3484
3485 if (diobj == niobj) {
3486 /*
3487 * jump LABEL
3488 * LABEL:
3489 * =>
3490 * LABEL:
3491 */
3492 unref_destination(iobj, 0);
3493 ELEM_REMOVE(&iobj->link);
3494 return COMPILE_OK;
3495 }
3496 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3497 IS_INSN_ID(diobj, jump) &&
3498 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3499 diobj->insn_info.events == 0) {
3500 /*
3501 * useless jump elimination:
3502 * jump LABEL1
3503 * ...
3504 * LABEL1:
3505 * jump LABEL2
3506 *
3507 * => in this case, first jump instruction should jump to
3508 * LABEL2 directly
3509 */
3510 if (replace_destination(iobj, diobj)) {
3511 remove_unreachable_chunk(iseq, iobj->link.next);
3512 goto again;
3513 }
3514 }
3515 else if (IS_INSN_ID(diobj, leave)) {
3516 /*
3517 * jump LABEL
3518 * ...
3519 * LABEL:
3520 * leave
3521 * =>
3522 * leave
3523 * ...
3524 * LABEL:
3525 * leave
3526 */
3527 /* replace */
3528 unref_destination(iobj, 0);
3529 iobj->insn_id = BIN(leave);
3530 iobj->operand_size = 0;
3531 iobj->insn_info = diobj->insn_info;
3532 goto again;
3533 }
3534 else if (IS_INSN(iobj->link.prev) &&
3535 (piobj = (INSN *)iobj->link.prev) &&
3536 (IS_INSN_ID(piobj, branchif) ||
3537 IS_INSN_ID(piobj, branchunless))) {
3538 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3539 if (niobj == pdiobj) {
3540 int refcnt = IS_LABEL(piobj->link.next) ?
3541 ((LABEL *)piobj->link.next)->refcnt : 0;
3542 /*
3543 * useless jump elimination (if/unless destination):
3544 * if L1
3545 * jump L2
3546 * L1:
3547 * ...
3548 * L2:
3549 *
3550 * ==>
3551 * unless L2
3552 * L1:
3553 * ...
3554 * L2:
3555 */
3556 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3557 ? BIN(branchunless) : BIN(branchif);
3558 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3559 ELEM_REMOVE(&iobj->link);
3560 }
3561 else {
3562 /* TODO: replace other branch destinations too */
3563 }
3564 return COMPILE_OK;
3565 }
3566 else if (diobj == pdiobj) {
3567 /*
3568 * useless jump elimination (if/unless before jump):
3569 * L1:
3570 * ...
3571 * if L1
3572 * jump L1
3573 *
3574 * ==>
3575 * L1:
3576 * ...
3577 * pop
3578 * jump L1
3579 */
3580 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3581 ELEM_REPLACE(&piobj->link, &popiobj->link);
3582 }
3583 }
3584 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3585 goto again;
3586 }
3587 }
3588
3589 /*
3590 * dupstring "beg"
3591 * dupstring "end"
3592 * newrange excl
3593 *
3594 * ==>
3595 *
3596 * putobject "beg".."end"
3597 */
3598 if (IS_INSN_ID(iobj, newrange)) {
3599 INSN *const range = iobj;
3600 INSN *beg, *end;
3601 VALUE str_beg, str_end;
3602
3603 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3604 is_frozen_putstring(end, &str_end) &&
3605 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3606 is_frozen_putstring(beg, &str_beg) &&
3607 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3608 int excl = FIX2INT(OPERAND_AT(range, 0));
3609 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3610
3611 ELEM_REMOVE(&beg->link);
3612 ELEM_REMOVE(&end->link);
3613 range->insn_id = BIN(putobject);
3614 OPERAND_AT(range, 0) = lit_range;
3615 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3616 }
3617 }
3618
3619 if (IS_INSN_ID(iobj, leave)) {
3620 remove_unreachable_chunk(iseq, iobj->link.next);
3621 }
3622
3623 /*
3624 * ...
3625 * duparray [...]
3626 * concatarray | concattoarray
3627 * =>
3628 * ...
3629 * putobject [...]
3630 * concatarray | concattoarray
3631 */
3632 if (IS_INSN_ID(iobj, duparray)) {
3633 LINK_ELEMENT *next = iobj->link.next;
3634 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3635 iobj->insn_id = BIN(putobject);
3636 }
3637 }
3638
3639 /*
3640 * duparray [...]
3641 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3642 * =>
3643 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3644 */
3645 if (IS_INSN_ID(iobj, duparray)) {
3646 LINK_ELEMENT *next = iobj->link.next;
3647 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3648 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3649 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3650
3651 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3652 VALUE ary = iobj->operands[0];
3654
3655 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3656 ELEM_REMOVE(next);
3657 }
3658 }
3659 }
3660
3661 /*
3662 * duphash {...}
3663 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3664 * =>
3665 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3666 */
3667 if (IS_INSN_ID(iobj, duphash)) {
3668 LINK_ELEMENT *next = iobj->link.next;
3669 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3670 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3671 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3672
3673 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3674 VALUE hash = iobj->operands[0];
3675 rb_obj_reveal(hash, rb_cHash);
3676 RB_OBJ_SET_SHAREABLE(hash);
3677
3678 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3679 ELEM_REMOVE(next);
3680 }
3681 }
3682 }
3683
3684 /*
3685 * newarray 0
3686 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3687 * =>
3688 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3689 */
3690 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3691 LINK_ELEMENT *next = iobj->link.next;
3692 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3693 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3694 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3695
3696 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3697 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3698 ELEM_REMOVE(next);
3699 }
3700 }
3701 }
3702
3703 /*
3704 * newhash 0
3705 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3706 * =>
3707 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3708 */
3709 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3710 LINK_ELEMENT *next = iobj->link.next;
3711 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3712 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3713 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3714
3715 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3716 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3717 ELEM_REMOVE(next);
3718 }
3719 }
3720 }
3721
3722 if (IS_INSN_ID(iobj, branchif) ||
3723 IS_INSN_ID(iobj, branchnil) ||
3724 IS_INSN_ID(iobj, branchunless)) {
3725 /*
3726 * if L1
3727 * ...
3728 * L1:
3729 * jump L2
3730 * =>
3731 * if L2
3732 */
3733 INSN *nobj = (INSN *)get_destination_insn(iobj);
3734
3735 /* This jump-jump optimization may ignore line events on the jump
3736 * instruction being skipped. For example, the Line 2 TracePoint
3737 * event would otherwise never fire in the following code:
3738 *
3739 * 1: raise if 1 == 2
3740 * 2: while true
3741 * 3: break
3742 * 4: end
3743 *
3744 * Do not skip a jump that carries a line event. This applies even
3745 * when coverage is disabled because TracePoint consumes the same
3746 * event. [Bug #15980]
3747 */
3748 int stop_optimization =
3749 nobj->link.type == ISEQ_ELEMENT_INSN &&
3750 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3751 if (!stop_optimization) {
3752 INSN *pobj = (INSN *)iobj->link.prev;
3753 int prev_dup = 0;
3754 if (pobj) {
3755 if (!IS_INSN(&pobj->link))
3756 pobj = 0;
3757 else if (IS_INSN_ID(pobj, dup))
3758 prev_dup = 1;
3759 }
3760
3761 for (;;) {
3762 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3763 if (!replace_destination(iobj, nobj)) break;
3764 }
3765 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3766 !!(nobj = (INSN *)nobj->link.next) &&
3767 IS_INSN(&nobj->link) &&
3768 /* basic blocks, with no labels in the middle */
3769 nobj->insn_id == iobj->insn_id) {
3770 /*
3771 * dup
3772 * if L1
3773 * ...
3774 * L1:
3775 * dup
3776 * if L2
3777 * =>
3778 * dup
3779 * if L2
3780 * ...
3781 * L1:
3782 * dup
3783 * if L2
3784 */
3785 if (!replace_destination(iobj, nobj)) break;
3786 }
3787 else if (pobj) {
3788 /*
3789 * putnil
3790 * if L1
3791 * =>
3792 * # nothing
3793 *
3794 * putobject true
3795 * if L1
3796 * =>
3797 * jump L1
3798 *
3799 * dupstring ".."
3800 * if L1
3801 * =>
3802 * jump L1
3803 *
3804 * dupstring ".."
3805 * dup
3806 * if L1
3807 * =>
3808 * dupstring ".."
3809 * jump L1
3810 *
3811 */
3812 int cond;
3813 if (prev_dup && IS_INSN(pobj->link.prev)) {
3814 pobj = (INSN *)pobj->link.prev;
3815 }
3816 if (IS_INSN_ID(pobj, putobject)) {
3817 cond = (IS_INSN_ID(iobj, branchif) ?
3818 OPERAND_AT(pobj, 0) != Qfalse :
3819 IS_INSN_ID(iobj, branchunless) ?
3820 OPERAND_AT(pobj, 0) == Qfalse :
3821 FALSE);
3822 }
3823 else if (IS_INSN_ID(pobj, dupstring) ||
3824 IS_INSN_ID(pobj, duparray) ||
3825 IS_INSN_ID(pobj, newarray)) {
3826 cond = IS_INSN_ID(iobj, branchif);
3827 }
3828 else if (IS_INSN_ID(pobj, putnil)) {
3829 cond = !IS_INSN_ID(iobj, branchif);
3830 }
3831 else break;
3832 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3833 ELEM_REMOVE(iobj->link.prev);
3834 }
3835 else if (!iseq_pop_newarray(iseq, pobj)) {
3836 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3837 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3838 }
3839 if (cond) {
3840 if (prev_dup) {
3841 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3842 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3843 }
3844 iobj->insn_id = BIN(jump);
3845 goto again;
3846 }
3847 else {
3848 unref_destination(iobj, 0);
3849 ELEM_REMOVE(&iobj->link);
3850 }
3851 break;
3852 }
3853 else break;
3854 {
3855 LINK_ELEMENT *dest = get_destination_insn(nobj);
3856 if (!dest || !IS_INSN(dest)) break;
3857 nobj = (INSN *)dest;
3858 }
3859 }
3860 }
3861 }
3862
3863 if (IS_INSN_ID(iobj, pop)) {
3864 /*
3865 * putself / putnil / putobject obj / dupstring "..."
3866 * pop
3867 * =>
3868 * # do nothing
3869 */
3870 LINK_ELEMENT *prev = iobj->link.prev;
3871 if (IS_INSN(prev)) {
3872 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3873 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3874 previ == BIN(putself) || previ == BIN(dupstring) ||
3875 previ == BIN(dupchilledstring) ||
3876 previ == BIN(dup) ||
3877 previ == BIN(getlocal) ||
3878 previ == BIN(getblockparam) ||
3879 previ == BIN(getblockparamproxy) ||
3880 previ == BIN(getinstancevariable) ||
3881 previ == BIN(duparray)) {
3882 /* just push operand or static value and pop soon, no
3883 * side effects */
3884 ELEM_REMOVE(prev);
3885 ELEM_REMOVE(&iobj->link);
3886 }
3887 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3888 ELEM_REMOVE(&iobj->link);
3889 }
3890 else if (previ == BIN(concatarray)) {
3891 INSN *piobj = (INSN *)prev;
3892 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3893 INSN_OF(piobj) = BIN(pop);
3894 }
3895 else if (previ == BIN(concatstrings)) {
3896 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3897 ELEM_REMOVE(prev);
3898 }
3899 else {
3900 ELEM_REMOVE(&iobj->link);
3901 INSN_OF(prev) = BIN(adjuststack);
3902 }
3903 }
3904 }
3905 }
3906
3907 if (IS_INSN_ID(iobj, newarray) ||
3908 IS_INSN_ID(iobj, duparray) ||
3909 IS_INSN_ID(iobj, concatarray) ||
3910 IS_INSN_ID(iobj, splatarray) ||
3911 0) {
3912 /*
3913 * newarray N
3914 * splatarray
3915 * =>
3916 * newarray N
3917 * newarray always puts an array
3918 */
3919 LINK_ELEMENT *next = iobj->link.next;
3920 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3921 /* remove splatarray following always-array insn */
3922 ELEM_REMOVE(next);
3923 }
3924 }
3925
3926 if (IS_INSN_ID(iobj, newarray)) {
3927 LINK_ELEMENT *next = iobj->link.next;
3928 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3929 OPERAND_AT(next, 1) == INT2FIX(0)) {
3930 VALUE op1, op2;
3931 op1 = OPERAND_AT(iobj, 0);
3932 op2 = OPERAND_AT(next, 0);
3933 ELEM_REMOVE(next);
3934
3935 if (op1 == op2) {
3936 /*
3937 * newarray 2
3938 * expandarray 2, 0
3939 * =>
3940 * swap
3941 */
3942 if (op1 == INT2FIX(2)) {
3943 INSN_OF(iobj) = BIN(swap);
3944 iobj->operand_size = 0;
3945 }
3946 /*
3947 * newarray X
3948 * expandarray X, 0
3949 * =>
3950 * opt_reverse X
3951 */
3952 else {
3953 INSN_OF(iobj) = BIN(opt_reverse);
3954 }
3955 }
3956 else {
3957 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3958 INSN_OF(iobj) = BIN(opt_reverse);
3959 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3960
3961 if (op1 > op2) {
3962 /* X > Y
3963 * newarray X
3964 * expandarray Y, 0
3965 * =>
3966 * pop * (Y-X)
3967 * opt_reverse Y
3968 */
3969 for (; diff > 0; diff--) {
3970 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3971 }
3972 }
3973 else { /* (op1 < op2) */
3974 /* X < Y
3975 * newarray X
3976 * expandarray Y, 0
3977 * =>
3978 * putnil * (Y-X)
3979 * opt_reverse Y
3980 */
3981 for (; diff < 0; diff++) {
3982 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3983 }
3984 }
3985 }
3986 }
3987 }
3988
3989 if (IS_INSN_ID(iobj, duparray)) {
3990 LINK_ELEMENT *next = iobj->link.next;
3991 /*
3992 * duparray obj
3993 * expandarray X, 0
3994 * =>
3995 * putobject obj
3996 * expandarray X, 0
3997 */
3998 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3999 INSN_OF(iobj) = BIN(putobject);
4000 }
4001 }
4002
4003 if (IS_INSN_ID(iobj, anytostring)) {
4004 LINK_ELEMENT *next = iobj->link.next;
4005 /*
4006 * anytostring
4007 * concatstrings 1
4008 * =>
4009 * anytostring
4010 */
4011 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
4012 OPERAND_AT(next, 0) == INT2FIX(1)) {
4013 ELEM_REMOVE(next);
4014 }
4015 }
4016
4017 if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
4018 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
4019 /*
4020 * dupstring ""
4021 * concatstrings N
4022 * =>
4023 * concatstrings N-1
4024 */
4025 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
4026 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
4027 INSN *next = (INSN *)iobj->link.next;
4028 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
4029 ELEM_REMOVE(&next->link);
4030 }
4031 ELEM_REMOVE(&iobj->link);
4032 }
4033 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
4034 INSN *next = (INSN *)iobj->link.next;
4035 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
4036 VALUE src = OPERAND_AT(iobj, 0);
4037 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
4038 VALUE path = rb_iseq_path(iseq);
4039 int line = iobj->insn_info.line_no;
4040 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
4041 /* The folded operand is a Regexp, so the instruction must be
4042 * putobject: dupstring/dupchilledstring would resurrect the
4043 * Regexp as a String at run time (e.g. for a /o regexp whose
4044 * interpolation folds to a constant, such as /#{"a"}/o). */
4045 iobj->insn_id = BIN(putobject);
4046 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
4047 ELEM_REMOVE(iobj->link.next);
4048 }
4049 }
4050 }
4051
4052 if (IS_INSN_ID(iobj, concatstrings)) {
4053 /*
4054 * concatstrings N
4055 * concatstrings M
4056 * =>
4057 * concatstrings N+M-1
4058 */
4059 LINK_ELEMENT *next = iobj->link.next;
4060 INSN *jump = 0;
4061 if (IS_INSN(next) && IS_INSN_ID(next, jump))
4062 next = get_destination_insn(jump = (INSN *)next);
4063 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
4064 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
4065 OPERAND_AT(iobj, 0) = INT2FIX(n);
4066 if (jump) {
4067 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
4068 if (!--label->refcnt) {
4069 ELEM_REMOVE(&label->link);
4070 }
4071 else {
4072 label = NEW_LABEL(0);
4073 OPERAND_AT(jump, 0) = (VALUE)label;
4074 }
4075 label->refcnt++;
4076 ELEM_INSERT_NEXT(next, &label->link);
4077 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
4078 }
4079 else {
4080 ELEM_REMOVE(next);
4081 }
4082 }
4083 }
4084
4085 if (do_tailcallopt &&
4086 (IS_INSN_ID(iobj, send) ||
4087 IS_INSN_ID(iobj, invokesuper))) {
4088 /*
4089 * send ...
4090 * leave
4091 * =>
4092 * send ..., ... | VM_CALL_TAILCALL, ...
4093 * leave # unreachable
4094 */
4095 INSN *piobj = NULL;
4096 if (iobj->link.next) {
4097 LINK_ELEMENT *next = iobj->link.next;
4098 do {
4099 if (!IS_INSN(next)) {
4100 next = next->next;
4101 continue;
4102 }
4103 switch (INSN_OF(next)) {
4104 case BIN(nop):
4105 next = next->next;
4106 break;
4107 case BIN(jump):
4108 /* if cond
4109 * return tailcall
4110 * end
4111 */
4112 next = get_destination_insn((INSN *)next);
4113 break;
4114 case BIN(leave):
4115 piobj = iobj;
4116 /* fall through */
4117 default:
4118 next = NULL;
4119 break;
4120 }
4121 } while (next);
4122 }
4123
4124 if (piobj) {
4125 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4126 if (IS_INSN_ID(piobj, send) ||
4127 IS_INSN_ID(piobj, invokesuper)) {
4128 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4129 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4130 OPERAND_AT(piobj, 0) = (VALUE)ci;
4131 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4132 }
4133 }
4134 else {
4135 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4136 OPERAND_AT(piobj, 0) = (VALUE)ci;
4137 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4138 }
4139 }
4140 }
4141
4142 if (IS_INSN_ID(iobj, dup)) {
4143 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4144 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4145
4146 /*
4147 * dup
4148 * setlocal x, y
4149 * setlocal x, y
4150 * =>
4151 * dup
4152 * setlocal x, y
4153 */
4154 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4155 set2 = set1->next;
4156 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4157 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4158 ELEM_REMOVE(set1);
4159 ELEM_REMOVE(&iobj->link);
4160 }
4161 }
4162
4163 /*
4164 * dup
4165 * setlocal x, y
4166 * dup
4167 * setlocal x, y
4168 * =>
4169 * dup
4170 * setlocal x, y
4171 */
4172 else if (IS_NEXT_INSN_ID(set1, dup) &&
4173 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4174 set2 = set1->next->next;
4175 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4176 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4177 ELEM_REMOVE(set1->next);
4178 ELEM_REMOVE(set2);
4179 }
4180 }
4181 }
4182 }
4183
4184 /*
4185 * getlocal x, y
4186 * dup
4187 * setlocal x, y
4188 * =>
4189 * dup
4190 */
4191 if (IS_INSN_ID(iobj, getlocal)) {
4192 LINK_ELEMENT *niobj = &iobj->link;
4193 if (IS_NEXT_INSN_ID(niobj, dup)) {
4194 niobj = niobj->next;
4195 }
4196 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4197 LINK_ELEMENT *set1 = niobj->next;
4198 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4199 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4200 ELEM_REMOVE(set1);
4201 ELEM_REMOVE(niobj);
4202 }
4203 }
4204 }
4205
4206 /*
4207 * opt_invokebuiltin_delegate
4208 * trace
4209 * leave
4210 * =>
4211 * opt_invokebuiltin_delegate_leave
4212 * trace
4213 * leave
4214 */
4215 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4216 if (IS_TRACE(iobj->link.next)) {
4217 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4218 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4219 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4220 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4221 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4222 }
4223 }
4224 }
4225 }
4226
4227 /*
4228 * getblockparam
4229 * branchif / branchunless
4230 * =>
4231 * getblockparamproxy
4232 * branchif / branchunless
4233 */
4234 if (IS_INSN_ID(iobj, getblockparam)) {
4235 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4236 iobj->insn_id = BIN(getblockparamproxy);
4237 }
4238 }
4239
4240 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4241 LINK_ELEMENT *niobj = &iobj->link;
4242 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4243 niobj = niobj->next;
4244 LINK_ELEMENT *siobj;
4245 unsigned int set_flags = 0, unset_flags = 0;
4246
4247 /*
4248 * Eliminate hash allocation for f(*a, kw: 1)
4249 *
4250 * splatarray false
4251 * duphash
4252 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4253 * =>
4254 * splatarray false
4255 * putobject
4256 * send ARGS_SPLAT|KW_SPLAT
4257 */
4258 if (IS_NEXT_INSN_ID(niobj, send)) {
4259 siobj = niobj->next;
4260 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4261 unset_flags = VM_CALL_ARGS_BLOCKARG;
4262 }
4263 /*
4264 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4265 *
4266 * splatarray false
4267 * duphash
4268 * getlocal / getinstancevariable / getblockparamproxy
4269 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4270 * =>
4271 * splatarray false
4272 * putobject
4273 * getlocal / getinstancevariable / getblockparamproxy
4274 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4275 */
4276 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4277 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4278 siobj = niobj->next->next;
4279 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4280 }
4281
4282 if (set_flags) {
4283 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4284 unsigned int flags = vm_ci_flag(ci);
4285 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4286 ((INSN*)niobj)->insn_id = BIN(putobject);
4287 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4288
4289 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4290 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4291 RB_OBJ_WRITTEN(iseq, ci, nci);
4292 OPERAND_AT(siobj, 0) = (VALUE)nci;
4293 }
4294 }
4295 }
4296 }
4297
4298 /*
4299 * putself / (or any other independent instruction)
4300 * putnil / (or any other independent instruction)
4301 * swap
4302 * =>
4303 * putnil / (or any other independent instruction)
4304 * putself / (or any other independent instruction)
4305 */
4306 if (IS_NEXT_NEXT_INSN_ID(&iobj->link, swap)) {
4307 LINK_ELEMENT *first = &iobj->link;
4308 LINK_ELEMENT *second = first->next;
4309 LINK_ELEMENT *swap = second->next;
4310 if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) {
4311 ELEM_REMOVE(swap);
4312 ELEM_SWAP(first, second);
4313 }
4314 }
4315
4316 return COMPILE_OK;
4317}
4318
4319static int
4320insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4321{
4322 if (insn_id == BIN(opt_neq)) {
4323 VALUE original_ci = iobj->operands[0];
4324 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4325 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4326 }
4327 else {
4328 iobj->insn_id = insn_id;
4329 iobj->operand_size = insn_len(insn_id) - 1;
4330 }
4331 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4332
4333 return COMPILE_OK;
4334}
4335
4336static int
4337iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4338{
4339 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4340 IS_INSN(iobj->link.next)) {
4341 /*
4342 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4343 */
4344 INSN *niobj = (INSN *)iobj->link.next;
4345 if (IS_INSN_ID(niobj, send)) {
4346 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4347 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4348 VALUE method = INT2FIX(0);
4349 switch (vm_ci_mid(ci)) {
4350 case idMax:
4351 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4352 break;
4353 case idMin:
4354 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4355 break;
4356 case idHash:
4357 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4358 break;
4359 }
4360
4361 if (method != INT2FIX(0)) {
4362 VALUE num = iobj->operands[0];
4363 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4364 ELEM_REMOVE(&niobj->link);
4365 return COMPILE_OK;
4366 }
4367 }
4368 }
4369 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4370 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4371 IS_NEXT_INSN_ID(&niobj->link, send)) {
4372 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4373 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4374 VALUE num = iobj->operands[0];
4375 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4376 ELEM_REMOVE(&iobj->link);
4377 ELEM_REMOVE(niobj->link.next);
4378 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4379 return COMPILE_OK;
4380 }
4381 }
4382 // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
4383 // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4384 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4385 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4386 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4387 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4388 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4389 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4390 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4391 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4392 VALUE num = iobj->operands[0];
4393 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4394 // Remove the "send" insn.
4395 ELEM_REMOVE((niobj->link.next)->next);
4396 // Remove the modified insn from its original "newarray" position...
4397 ELEM_REMOVE(&iobj->link);
4398 // and insert it after the buffer insn.
4399 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4400 return COMPILE_OK;
4401 }
4402 }
4403
4404 // Break the "else if" chain since some prior checks abort after sub-ifs.
4405 // We already found "newarray". To match `[...].include?(arg)` we look for
4406 // the instruction(s) representing the argument followed by a "send".
4407 if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4408 IS_INSN_ID(niobj, putobject) ||
4409 IS_INSN_ID(niobj, putself) ||
4410 IS_INSN_ID(niobj, getlocal) ||
4411 IS_INSN_ID(niobj, getinstancevariable)) &&
4412 IS_NEXT_INSN_ID(&niobj->link, send)) {
4413
4414 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4415 const struct rb_callinfo *ci;
4416 // Allow any number (0 or more) of simple method calls on the argument
4417 // (as in `[...].include?(arg.method1.method2)`.
4418 do {
4419 sendobj = sendobj->next;
4420 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4421 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4422
4423 // If this send is for .include? with one arg we can do our opt.
4424 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4425 VALUE num = iobj->operands[0];
4426 INSN *sendins = (INSN *)sendobj;
4427 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4428 // Remove the original "newarray" insn.
4429 ELEM_REMOVE(&iobj->link);
4430 return COMPILE_OK;
4431 }
4432 }
4433 }
4434
4435 /*
4436 * duparray [...]
4437 * some insn for the arg...
4438 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4439 * =>
4440 * arg insn...
4441 * opt_duparray_send [...], :include?, 1
4442 */
4443 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4444 INSN *niobj = (INSN *)iobj->link.next;
4445 if ((IS_INSN_ID(niobj, getlocal) ||
4446 IS_INSN_ID(niobj, getinstancevariable) ||
4447 IS_INSN_ID(niobj, putself) ||
4448 IS_INSN_ID(niobj, putobject) ||
4449 IS_INSN_ID(niobj, putnil)) &&
4450 IS_NEXT_INSN_ID(&niobj->link, send)) {
4451
4452 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4453 const struct rb_callinfo *ci;
4454 // Allow any number (0 or more) of simple method calls on the argument
4455 // (as in `[...].include?(arg.method1.method2)`.
4456 do {
4457 sendobj = sendobj->next;
4458 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4459 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4460
4461 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4462 // Move the array arg from duparray to opt_duparray_send.
4463 VALUE ary = iobj->operands[0];
4465
4466 INSN *sendins = (INSN *)sendobj;
4467 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4468
4469 // Remove the duparray insn.
4470 ELEM_REMOVE(&iobj->link);
4471 return COMPILE_OK;
4472 }
4473 }
4474 }
4475
4476
4477 if (IS_INSN_ID(iobj, send)) {
4478 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4479 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4480
4481#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4482 if (vm_ci_simple(ci)) {
4483 switch (vm_ci_argc(ci)) {
4484 case 0:
4485 switch (vm_ci_mid(ci)) {
4486 case idLength: SP_INSN(length); return COMPILE_OK;
4487 case idSize: SP_INSN(size); return COMPILE_OK;
4488 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4489 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4490 case idSucc: SP_INSN(succ); return COMPILE_OK;
4491 case idNot: SP_INSN(not); return COMPILE_OK;
4492 }
4493 break;
4494 case 1:
4495 switch (vm_ci_mid(ci)) {
4496 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4497 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4498 case idMULT: SP_INSN(mult); return COMPILE_OK;
4499 case idDIV: SP_INSN(div); return COMPILE_OK;
4500 case idMOD: SP_INSN(mod); return COMPILE_OK;
4501 case idEq: SP_INSN(eq); return COMPILE_OK;
4502 case idNeq: SP_INSN(neq); return COMPILE_OK;
4503 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4504 case idLT: SP_INSN(lt); return COMPILE_OK;
4505 case idLE: SP_INSN(le); return COMPILE_OK;
4506 case idGT: SP_INSN(gt); return COMPILE_OK;
4507 case idGE: SP_INSN(ge); return COMPILE_OK;
4508 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4509 case idAREF: SP_INSN(aref); return COMPILE_OK;
4510 case idAnd: SP_INSN(and); return COMPILE_OK;
4511 case idOr: SP_INSN(or); return COMPILE_OK;
4512 }
4513 break;
4514 case 2:
4515 switch (vm_ci_mid(ci)) {
4516 case idASET: SP_INSN(aset); return COMPILE_OK;
4517 }
4518 break;
4519 }
4520 }
4521
4522 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4523 iobj->insn_id = BIN(opt_send_without_block);
4524 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4525 }
4526 }
4527#undef SP_INSN
4528
4529 return COMPILE_OK;
4530}
4531
4532static inline int
4533tailcallable_p(rb_iseq_t *iseq)
4534{
4535 switch (ISEQ_BODY(iseq)->type) {
4536 case ISEQ_TYPE_TOP:
4537 case ISEQ_TYPE_EVAL:
4538 case ISEQ_TYPE_MAIN:
4539 /* not tail callable because cfp will be over popped */
4540 case ISEQ_TYPE_RESCUE:
4541 case ISEQ_TYPE_ENSURE:
4542 /* rescue block can't tail call because of errinfo */
4543 return FALSE;
4544 default:
4545 return TRUE;
4546 }
4547}
4548
4549static int
4550iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4551{
4552 LINK_ELEMENT *list;
4553 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4554 const int do_tailcallopt = tailcallable_p(iseq) &&
4555 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4556 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4557 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4558 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4559 int rescue_level = 0;
4560 int tailcallopt = do_tailcallopt;
4561
4562 list = FIRST_ELEMENT(anchor);
4563
4564 int do_block_optimization = 0;
4565 LABEL * block_loop_label = NULL;
4566
4567 // If we're optimizing a block
4568 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4569 do_block_optimization = 1;
4570
4571 // If the block starts with a nop and a label,
4572 // record the label so we can detect if it's a jump target
4573 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4574 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4575 block_loop_label = (LABEL *)le->next;
4576 }
4577 }
4578
4579 while (list) {
4580 if (IS_INSN(list)) {
4581 if (do_peepholeopt) {
4582 iseq_peephole_optimize(iseq, list, tailcallopt);
4583 }
4584 if (do_si) {
4585 iseq_specialized_instruction(iseq, (INSN *)list);
4586 }
4587 if (do_ou) {
4588 insn_operands_unification((INSN *)list);
4589 }
4590
4591 if (do_without_ints) {
4592 INSN *item = (INSN *)list;
4593 if (IS_INSN_ID(item, jump)) {
4594 item->insn_id = BIN(jump_without_ints);
4595 }
4596 else if (IS_INSN_ID(item, branchif)) {
4597 item->insn_id = BIN(branchif_without_ints);
4598 }
4599 else if (IS_INSN_ID(item, branchunless)) {
4600 item->insn_id = BIN(branchunless_without_ints);
4601 }
4602 else if (IS_INSN_ID(item, branchnil)) {
4603 item->insn_id = BIN(branchnil_without_ints);
4604 }
4605 }
4606
4607 if (do_block_optimization) {
4608 INSN * item = (INSN *)list;
4609 // Give up if there is a throw
4610 if (IS_INSN_ID(item, throw)) {
4611 do_block_optimization = 0;
4612 }
4613 else {
4614 // If the instruction has a jump target, check if the
4615 // jump target is the block loop label
4616 const char *types = insn_op_types(item->insn_id);
4617 for (int j = 0; types[j]; j++) {
4618 if (types[j] == TS_OFFSET) {
4619 // If the jump target is equal to the block loop
4620 // label, then we can't do the optimization because
4621 // the leading `nop` instruction fires the block
4622 // entry tracepoint
4623 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4624 if (target == block_loop_label) {
4625 do_block_optimization = 0;
4626 }
4627 }
4628 }
4629 }
4630 }
4631 }
4632 if (IS_LABEL(list)) {
4633 switch (((LABEL *)list)->rescued) {
4634 case LABEL_RESCUE_BEG:
4635 rescue_level++;
4636 tailcallopt = FALSE;
4637 break;
4638 case LABEL_RESCUE_END:
4639 if (!--rescue_level) tailcallopt = do_tailcallopt;
4640 break;
4641 }
4642 }
4643 list = list->next;
4644 }
4645
4646 if (do_block_optimization) {
4647 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4648 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4649 ELEM_REMOVE(le);
4650 }
4651 }
4652 return COMPILE_OK;
4653}
4654
4655#if OPT_INSTRUCTIONS_UNIFICATION
4656static INSN *
4657new_unified_insn(rb_iseq_t *iseq,
4658 int insn_id, int size, LINK_ELEMENT *seq_list)
4659{
4660 INSN *iobj = 0;
4661 LINK_ELEMENT *list = seq_list;
4662 int i, argc = 0;
4663 VALUE *operands = 0, *ptr = 0;
4664
4665
4666 /* count argc */
4667 for (i = 0; i < size; i++) {
4668 iobj = (INSN *)list;
4669 argc += iobj->operand_size;
4670 list = list->next;
4671 }
4672
4673 if (argc > 0) {
4674 ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
4675 }
4676
4677 /* copy operands */
4678 list = seq_list;
4679 for (i = 0; i < size; i++) {
4680 iobj = (INSN *)list;
4681 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4682 ptr += iobj->operand_size;
4683 list = list->next;
4684 }
4685
4686 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4687}
4688#endif
4689
4690/*
4691 * This scheme can get more performance if do this optimize with
4692 * label address resolving.
4693 * It's future work (if compile time was bottle neck).
4694 */
4695static int
4696iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4697{
4698#if OPT_INSTRUCTIONS_UNIFICATION
4699 LINK_ELEMENT *list;
4700 INSN *iobj, *niobj;
4701 int id, k;
4702 intptr_t j;
4703
4704 list = FIRST_ELEMENT(anchor);
4705 while (list) {
4706 if (IS_INSN(list)) {
4707 iobj = (INSN *)list;
4708 id = iobj->insn_id;
4709 if (unified_insns_data[id] != 0) {
4710 const int *const *entry = unified_insns_data[id];
4711 for (j = 1; j < (intptr_t)entry[0]; j++) {
4712 const int *unified = entry[j];
4713 LINK_ELEMENT *li = list->next;
4714 for (k = 2; k < unified[1]; k++) {
4715 if (!IS_INSN(li) ||
4716 ((INSN *)li)->insn_id != unified[k]) {
4717 goto miss;
4718 }
4719 li = li->next;
4720 }
4721 /* matched */
4722 niobj =
4723 new_unified_insn(iseq, unified[0], unified[1] - 1,
4724 list);
4725
4726 /* insert to list */
4727 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4728 niobj->link.next = li;
4729 if (li) {
4730 li->prev = (LINK_ELEMENT *)niobj;
4731 }
4732
4733 list->prev->next = (LINK_ELEMENT *)niobj;
4734 list = (LINK_ELEMENT *)niobj;
4735 break;
4736 miss:;
4737 }
4738 }
4739 }
4740 list = list->next;
4741 }
4742#endif
4743 return COMPILE_OK;
4744}
4745
4746static int
4747all_string_result_p(const NODE *node)
4748{
4749 if (!node) return FALSE;
4750 switch (nd_type(node)) {
4751 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4752 return TRUE;
4753 case NODE_IF: case NODE_UNLESS:
4754 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4755 if (all_string_result_p(RNODE_IF(node)->nd_body))
4756 return all_string_result_p(RNODE_IF(node)->nd_else);
4757 return FALSE;
4758 case NODE_AND: case NODE_OR:
4759 if (!RNODE_AND(node)->nd_2nd)
4760 return all_string_result_p(RNODE_AND(node)->nd_1st);
4761 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4762 return FALSE;
4763 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4764 default:
4765 return FALSE;
4766 }
4767}
4768
4770 rb_iseq_t *const iseq;
4771 LINK_ANCHOR *const ret;
4772 VALUE lit;
4773 const NODE *lit_node;
4774 int cnt;
4775 int dregx;
4776};
4777
4778static int
4779append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4780{
4781 VALUE s = rb_str_new_mutable_parser_string(str);
4782 if (args->dregx) {
4783 VALUE error = rb_reg_check_preprocess(s);
4784 if (!NIL_P(error)) {
4785 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4786 return COMPILE_NG;
4787 }
4788 }
4789 if (NIL_P(args->lit)) {
4790 args->lit = s;
4791 args->lit_node = node;
4792 }
4793 else {
4794 rb_str_buf_append(args->lit, s);
4795 }
4796 return COMPILE_OK;
4797}
4798
4799static void
4800flush_dstr_fragment(struct dstr_ctxt *args)
4801{
4802 if (!NIL_P(args->lit)) {
4803 rb_iseq_t *iseq = args->iseq;
4804 VALUE lit = args->lit;
4805 args->lit = Qnil;
4806 lit = rb_fstring(lit);
4807 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4808 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4809 args->cnt++;
4810 }
4811}
4812
4813static int
4814compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4815{
4816 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4817 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4818
4819 if (str) {
4820 CHECK(append_dstr_fragment(args, node, str));
4821 }
4822
4823 while (list) {
4824 const NODE *const head = list->nd_head;
4825 if (nd_type_p(head, NODE_STR)) {
4826 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4827 }
4828 else if (nd_type_p(head, NODE_DSTR)) {
4829 CHECK(compile_dstr_fragments_0(args, head));
4830 }
4831 else {
4832 flush_dstr_fragment(args);
4833 rb_iseq_t *iseq = args->iseq;
4834 CHECK(COMPILE(args->ret, "each string", head));
4835 args->cnt++;
4836 }
4837 list = (struct RNode_LIST *)list->nd_next;
4838 }
4839 return COMPILE_OK;
4840}
4841
4842static int
4843compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4844{
4845 struct dstr_ctxt args = {
4846 .iseq = iseq, .ret = ret,
4847 .lit = Qnil, .lit_node = NULL,
4848 .cnt = 0, .dregx = dregx,
4849 };
4850 CHECK(compile_dstr_fragments_0(&args, node));
4851 flush_dstr_fragment(&args);
4852
4853 *cntp = args.cnt;
4854
4855 return COMPILE_OK;
4856}
4857
4858static int
4859compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4860{
4861 while (node && nd_type_p(node, NODE_BLOCK)) {
4862 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4863 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4864 node = RNODE_BLOCK(node)->nd_next;
4865 }
4866 if (node) {
4867 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4868 }
4869 return COMPILE_OK;
4870}
4871
4872static int
4873compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4874{
4875 int cnt;
4876 if (!RNODE_DSTR(node)->nd_next) {
4877 VALUE lit = rb_node_dstr_string_val(node);
4878 ADD_INSN1(ret, node, dupstring, lit);
4879 RB_OBJ_SET_SHAREABLE(lit);
4880 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4881 }
4882 else {
4883 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4884 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4885 }
4886 return COMPILE_OK;
4887}
4888
4889static int
4890compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4891{
4892 int cnt;
4893 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4894
4895 if (!RNODE_DREGX(node)->nd_next) {
4896 if (!popped) {
4897 VALUE src = rb_node_dregx_string_val(node);
4898 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4899 ADD_INSN1(ret, node, putobject, match);
4900 RB_OBJ_WRITTEN(iseq, Qundef, match);
4901 }
4902 return COMPILE_OK;
4903 }
4904
4905 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4906 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4907
4908 if (popped) {
4909 ADD_INSN(ret, node, pop);
4910 }
4911
4912 return COMPILE_OK;
4913}
4914
4915static int
4916compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4917 LABEL *then_label, LABEL *else_label)
4918{
4919 const int line = nd_line(node);
4920 LABEL *lend = NEW_LABEL(line);
4921 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4922 + VM_SVAR_FLIPFLOP_START;
4923 VALUE key = INT2FIX(cnt);
4924
4925 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4926 ADD_INSNL(ret, node, branchif, lend);
4927
4928 /* *flip == 0 */
4929 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4930 ADD_INSNL(ret, node, branchunless, else_label);
4931 ADD_INSN1(ret, node, putobject, Qtrue);
4932 ADD_INSN1(ret, node, setspecial, key);
4933 if (!again) {
4934 ADD_INSNL(ret, node, jump, then_label);
4935 }
4936
4937 /* *flip == 1 */
4938 ADD_LABEL(ret, lend);
4939 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4940 ADD_INSNL(ret, node, branchunless, then_label);
4941 ADD_INSN1(ret, node, putobject, Qfalse);
4942 ADD_INSN1(ret, node, setspecial, key);
4943 ADD_INSNL(ret, node, jump, then_label);
4944
4945 return COMPILE_OK;
4946}
4947
4948static int
4949compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4950 LABEL *then_label, LABEL *else_label);
4951
4952#define COMPILE_SINGLE 2
4953static int
4954compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4955 LABEL *then_label, LABEL *else_label)
4956{
4957 DECL_ANCHOR(seq);
4958 INIT_ANCHOR(seq);
4959 LABEL *label = NEW_LABEL(nd_line(cond));
4960 if (!then_label) then_label = label;
4961 else if (!else_label) else_label = label;
4962
4963 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4964
4965 if (LIST_INSN_SIZE_ONE(seq)) {
4966 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4967 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4968 return COMPILE_OK;
4969 }
4970 if (!label->refcnt) {
4971 return COMPILE_SINGLE;
4972 }
4973 ADD_LABEL(seq, label);
4974 ADD_SEQ(ret, seq);
4975 return COMPILE_OK;
4976}
4977
4978static int
4979compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4980 LABEL *then_label, LABEL *else_label)
4981{
4982 int ok;
4983 DECL_ANCHOR(ignore);
4984
4985 again:
4986 switch (nd_type(cond)) {
4987 case NODE_AND:
4988 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4989 cond = RNODE_AND(cond)->nd_2nd;
4990 if (ok == COMPILE_SINGLE) {
4991 ADD_INSNL(ret, cond, jump, else_label);
4992 INIT_ANCHOR(ignore);
4993 ret = ignore;
4994 then_label = NEW_LABEL(nd_line(cond));
4995 }
4996 goto again;
4997 case NODE_OR:
4998 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4999 cond = RNODE_OR(cond)->nd_2nd;
5000 if (ok == COMPILE_SINGLE) {
5001 ADD_INSNL(ret, cond, jump, then_label);
5002 INIT_ANCHOR(ignore);
5003 ret = ignore;
5004 else_label = NEW_LABEL(nd_line(cond));
5005 }
5006 goto again;
5007 case NODE_SYM:
5008 case NODE_LINE:
5009 case NODE_FILE:
5010 case NODE_ENCODING:
5011 case NODE_INTEGER: /* NODE_INTEGER is always true */
5012 case NODE_FLOAT: /* NODE_FLOAT is always true */
5013 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
5014 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
5015 case NODE_TRUE:
5016 case NODE_STR:
5017 case NODE_REGX:
5018 case NODE_ZLIST:
5019 case NODE_LAMBDA:
5020 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5021 ADD_INSNL(ret, cond, jump, then_label);
5022 return COMPILE_OK;
5023 case NODE_FALSE:
5024 case NODE_NIL:
5025 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5026 ADD_INSNL(ret, cond, jump, else_label);
5027 return COMPILE_OK;
5028 case NODE_LIST:
5029 case NODE_ARGSCAT:
5030 case NODE_DREGX:
5031 case NODE_DSTR:
5032 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
5033 ADD_INSNL(ret, cond, jump, then_label);
5034 return COMPILE_OK;
5035 case NODE_FLIP2:
5036 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
5037 return COMPILE_OK;
5038 case NODE_FLIP3:
5039 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
5040 return COMPILE_OK;
5041 case NODE_DEFINED:
5042 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
5043 break;
5044 default:
5045 {
5046 DECL_ANCHOR(cond_seq);
5047 INIT_ANCHOR(cond_seq);
5048
5049 CHECK(COMPILE(cond_seq, "branch condition", cond));
5050
5051 if (LIST_INSN_SIZE_ONE(cond_seq)) {
5052 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
5053 if (insn->insn_id == BIN(putobject)) {
5054 if (RTEST(insn->operands[0])) {
5055 ADD_INSNL(ret, cond, jump, then_label);
5056 // maybe unreachable
5057 return COMPILE_OK;
5058 }
5059 else {
5060 ADD_INSNL(ret, cond, jump, else_label);
5061 return COMPILE_OK;
5062 }
5063 }
5064 }
5065 ADD_SEQ(ret, cond_seq);
5066 }
5067 break;
5068 }
5069
5070 ADD_INSNL(ret, cond, branchunless, else_label);
5071 ADD_INSNL(ret, cond, jump, then_label);
5072 return COMPILE_OK;
5073}
5074
5075#define HASH_BRACE 1
5076
5077static int
5078keyword_node_p(const NODE *const node)
5079{
5080 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
5081}
5082
5083static VALUE
5084get_symbol_value(rb_iseq_t *iseq, const NODE *node)
5085{
5086 switch (nd_type(node)) {
5087 case NODE_SYM:
5088 return rb_node_sym_string_val(node);
5089 default:
5090 UNKNOWN_NODE("get_symbol_value", node, Qnil);
5091 }
5092}
5093
5094static VALUE
5095node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
5096{
5097 NODE *node = node_hash->nd_head;
5098 VALUE hash = rb_hash_new();
5099 VALUE ary = rb_ary_new();
5100
5101 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5102 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
5103 VALUE idx = rb_hash_aref(hash, key);
5104 if (!NIL_P(idx)) {
5105 rb_ary_store(ary, FIX2INT(idx), Qfalse);
5106 (*count_ptr)--;
5107 }
5108 rb_hash_aset(hash, key, INT2FIX(i));
5109 rb_ary_store(ary, i, Qtrue);
5110 (*count_ptr)++;
5111 }
5112
5113 return ary;
5114}
5115
5116static int
5117compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5118 const NODE *const root_node,
5119 struct rb_callinfo_kwarg **const kw_arg_ptr,
5120 unsigned int *flag)
5121{
5122 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5123 RUBY_ASSERT(kw_arg_ptr != NULL);
5124 RUBY_ASSERT(flag != NULL);
5125
5126 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5127 const NODE *node = RNODE_HASH(root_node)->nd_head;
5128 int seen_nodes = 0;
5129
5130 while (node) {
5131 const NODE *key_node = RNODE_LIST(node)->nd_head;
5132 seen_nodes++;
5133
5134 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5135 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5136 /* can be keywords */
5137 }
5138 else {
5139 if (flag) {
5140 *flag |= VM_CALL_KW_SPLAT;
5141 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5142 /* A new hash will be created for the keyword arguments
5143 * in this case, so mark the method as passing mutable
5144 * keyword splat.
5145 */
5146 *flag |= VM_CALL_KW_SPLAT_MUT;
5147 }
5148 }
5149 return FALSE;
5150 }
5151 node = RNODE_LIST(node)->nd_next; /* skip value node */
5152 node = RNODE_LIST(node)->nd_next;
5153 }
5154
5155 /* may be keywords */
5156 node = RNODE_HASH(root_node)->nd_head;
5157 {
5158 int len = 0;
5159 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5160
5161 if (len > VM_CALL_KW_LEN_MAX) {
5162 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5163 len, (int)VM_CALL_KW_LEN_MAX);
5164 }
5165
5166 struct rb_callinfo_kwarg *kw_arg =
5167 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5168 VALUE *keywords = kw_arg->keywords;
5169 int i = 0;
5170 int j = 0;
5171 kw_arg->references = 0;
5172 kw_arg->keyword_len = len;
5173
5174 *kw_arg_ptr = kw_arg;
5175
5176 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5177 const NODE *key_node = RNODE_LIST(node)->nd_head;
5178 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5179 int popped = TRUE;
5180 if (rb_ary_entry(key_index, i)) {
5181 keywords[j] = get_symbol_value(iseq, key_node);
5182 j++;
5183 popped = FALSE;
5184 }
5185 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5186 }
5187 RUBY_ASSERT(j == len);
5188 return TRUE;
5189 }
5190 }
5191 return FALSE;
5192}
5193
5194static int
5195compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5196{
5197 int len = 0;
5198
5199 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5200 if (CPDEBUG > 0) {
5201 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5202 }
5203
5204 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5205 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5206 }
5207 else {
5208 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5209 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5210 }
5211 }
5212
5213 return len;
5214}
5215
5216static inline bool
5217frozen_string_literal_p(const rb_iseq_t *iseq)
5218{
5219 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5220}
5221
5222static inline bool
5223static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5224{
5225 switch (nd_type(node)) {
5226 case NODE_SYM:
5227 case NODE_REGX:
5228 case NODE_LINE:
5229 case NODE_ENCODING:
5230 case NODE_INTEGER:
5231 case NODE_FLOAT:
5232 case NODE_RATIONAL:
5233 case NODE_IMAGINARY:
5234 case NODE_NIL:
5235 case NODE_TRUE:
5236 case NODE_FALSE:
5237 return TRUE;
5238 case NODE_STR:
5239 case NODE_FILE:
5240 return hash_key || frozen_string_literal_p(iseq);
5241 default:
5242 return FALSE;
5243 }
5244}
5245
5246static inline VALUE
5247static_literal_value(const NODE *node, rb_iseq_t *iseq)
5248{
5249 switch (nd_type(node)) {
5250 case NODE_INTEGER:
5251 {
5252 VALUE lit = rb_node_integer_literal_val(node);
5253 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5254 return lit;
5255 }
5256 case NODE_FLOAT:
5257 {
5258 VALUE lit = rb_node_float_literal_val(node);
5259 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5260 return lit;
5261 }
5262 case NODE_RATIONAL:
5263 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5264 case NODE_IMAGINARY:
5265 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5266 case NODE_NIL:
5267 return Qnil;
5268 case NODE_TRUE:
5269 return Qtrue;
5270 case NODE_FALSE:
5271 return Qfalse;
5272 case NODE_SYM:
5273 return rb_node_sym_string_val(node);
5274 case NODE_REGX:
5275 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5276 case NODE_LINE:
5277 return rb_node_line_lineno_val(node);
5278 case NODE_ENCODING:
5279 return rb_node_encoding_val(node);
5280 case NODE_FILE:
5281 case NODE_STR:
5282 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5283 VALUE lit = get_string_value(node);
5284 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5285 RB_OBJ_SET_SHAREABLE(str);
5286 return str;
5287 }
5288 else {
5289 return get_string_value(node);
5290 }
5291 default:
5292 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5293 }
5294}
5295
5296static int
5297compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5298{
5299 const NODE *line_node = node;
5300
5301 if (nd_type_p(node, NODE_ZLIST)) {
5302 if (!popped) {
5303 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5304 }
5305 return 0;
5306 }
5307
5308 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5309
5310 if (popped) {
5311 for (; node; node = RNODE_LIST(node)->nd_next) {
5312 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5313 }
5314 return 1;
5315 }
5316
5317 /* Compilation of an array literal.
5318 * The following code is essentially the same as:
5319 *
5320 * for (int count = 0; node; count++; node->nd_next) {
5321 * compile(node->nd_head);
5322 * }
5323 * ADD_INSN(newarray, count);
5324 *
5325 * However, there are three points.
5326 *
5327 * - The code above causes stack overflow for a big string literal.
5328 * The following limits the stack length up to max_stack_len.
5329 *
5330 * [x1,x2,...,x10000] =>
5331 * push x1 ; push x2 ; ...; push x256; newarray 256;
5332 * push x257; push x258; ...; push x512; pushtoarray 256;
5333 * push x513; push x514; ...; push x768; pushtoarray 256;
5334 * ...
5335 *
5336 * - Long subarray can be optimized by pre-allocating a hidden array.
5337 *
5338 * [1,2,3,...,100] =>
5339 * duparray [1,2,3,...,100]
5340 *
5341 * [x, 1,2,3,...,100, z] =>
5342 * push x; newarray 1;
5343 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5344 * push z; pushtoarray 1;
5345 *
5346 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5347 * to only push it onto the array if it is not empty
5348 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5349 *
5350 * [1,2,3,**kw] =>
5351 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5352 */
5353
5354 const int max_stack_len = 0x100;
5355 const int min_tmp_ary_len = 0x40;
5356 int stack_len = 0;
5357
5358 /* Either create a new array, or push to the existing array */
5359#define FLUSH_CHUNK \
5360 if (stack_len) { \
5361 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5362 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5363 first_chunk = FALSE; \
5364 stack_len = 0; \
5365 }
5366
5367 while (node) {
5368 int count = 1;
5369
5370 /* pre-allocation check (this branch can be omittable) */
5371 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5372 /* count the elements that are optimizable */
5373 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5374 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5375 count++;
5376
5377 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5378 /* The literal contains only optimizable elements, or the subarray is long enough */
5379 VALUE ary = rb_ary_hidden_new(count);
5380
5381 /* Create a hidden array */
5382 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5383 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5384 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5385
5386 /* Emit optimized code */
5387 FLUSH_CHUNK;
5388 if (first_chunk) {
5389 ADD_INSN1(ret, line_node, duparray, ary);
5390 first_chunk = FALSE;
5391 }
5392 else {
5393 ADD_INSN1(ret, line_node, putobject, ary);
5394 ADD_INSN(ret, line_node, concattoarray);
5395 }
5396 RB_OBJ_SET_SHAREABLE(ary);
5397 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5398 }
5399 }
5400
5401 /* Base case: Compile "count" elements */
5402 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5403 if (CPDEBUG > 0) {
5404 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5405 }
5406
5407 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5408 /* Create array or push existing non-keyword elements onto array */
5409 if (stack_len == 0 && first_chunk) {
5410 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5411 }
5412 else {
5413 FLUSH_CHUNK;
5414 }
5415 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5416 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5417 return 1;
5418 }
5419 else {
5420 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5421 stack_len++;
5422 }
5423
5424 /* If there are many pushed elements, flush them to avoid stack overflow */
5425 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5426 }
5427 }
5428
5429 FLUSH_CHUNK;
5430#undef FLUSH_CHUNK
5431 return 1;
5432}
5433
5434static inline int
5435static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5436{
5437 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);
5438}
5439
5440static int
5441compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5442{
5443 const NODE *line_node = node;
5444
5445 node = RNODE_HASH(node)->nd_head;
5446
5447 if (!node || nd_type_p(node, NODE_ZLIST)) {
5448 if (!popped) {
5449 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5450 }
5451 return 0;
5452 }
5453
5454 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5455
5456 if (popped) {
5457 for (; node; node = RNODE_LIST(node)->nd_next) {
5458 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5459 }
5460 return 1;
5461 }
5462
5463 /* Compilation of a hash literal (or keyword arguments).
5464 * This is very similar to compile_array, but there are some differences:
5465 *
5466 * - It contains key-value pairs. So we need to take every two elements.
5467 * We can assume that the length is always even.
5468 *
5469 * - Merging is done by a method call (id_core_hash_merge_bang_ptr).
5470 * Sometimes we need to insert the receiver, so "anchor" is needed.
5471 * In addition, a method call is much slower than concatarray.
5472 * So it pays only when the subsequence is really long.
5473 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5474 *
5475 * - We need to handle keyword splat: **kw.
5476 * For **kw, the key part (node->nd_head) is NULL, and the value part
5477 * (node->nd_next->nd_head) is "kw".
5478 * The code is a bit difficult to avoid hash allocation for **{}.
5479 */
5480
5481 const int max_stack_len = 0x100;
5482 const int min_tmp_hash_len = 0x800;
5483 int stack_len = 0;
5484 int first_chunk = 1;
5485 DECL_ANCHOR(anchor);
5486 INIT_ANCHOR(anchor);
5487
5488 /* Convert pushed elements to a hash, and merge if needed */
5489#define FLUSH_CHUNK() \
5490 if (stack_len) { \
5491 if (first_chunk) { \
5492 APPEND_LIST(ret, anchor); \
5493 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5494 } \
5495 else { \
5496 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5497 ADD_INSN(ret, line_node, swap); \
5498 APPEND_LIST(ret, anchor); \
5499 ADD_SEND(ret, line_node, id_core_hash_merge_bang_ptr, INT2FIX(stack_len + 1)); \
5500 } \
5501 INIT_ANCHOR(anchor); \
5502 first_chunk = stack_len = 0; \
5503 }
5504
5505 while (node) {
5506 int count = 1;
5507
5508 /* pre-allocation check (this branch can be omittable) */
5509 if (static_literal_node_pair_p(node, iseq)) {
5510 /* count the elements that are optimizable */
5511 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5512 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5513 count++;
5514
5515 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5516 /* The literal contains only optimizable elements, or the subsequence is long enough */
5517 VALUE ary = rb_ary_hidden_new(count);
5518
5519 /* Create a hidden hash */
5520 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5521 VALUE elem[2];
5522 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5523 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5524 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5525 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5526 rb_ary_cat(ary, elem, 2);
5527 }
5528 VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
5529 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5530 RB_GC_GUARD(ary);
5531 hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
5532
5533 /* Emit optimized code */
5534 FLUSH_CHUNK();
5535 if (first_chunk) {
5536 ADD_INSN1(ret, line_node, duphash, hash);
5537 first_chunk = 0;
5538 }
5539 else {
5540 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5541 ADD_INSN(ret, line_node, swap);
5542
5543 ADD_INSN1(ret, line_node, putobject, hash);
5544
5545 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5546 }
5547 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5548 }
5549 }
5550
5551 /* Base case: Compile "count" elements */
5552 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5553
5554 if (CPDEBUG > 0) {
5555 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5556 }
5557
5558 if (RNODE_LIST(node)->nd_head) {
5559 /* Normal key-value pair */
5560 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5561 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5562 stack_len += 2;
5563
5564 /* If there are many pushed elements, flush them to avoid stack overflow */
5565 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5566 }
5567 else {
5568 /* kwsplat case: foo(..., **kw, ...) */
5569 FLUSH_CHUNK();
5570
5571 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5572 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5573 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5574 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5575 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5576
5577 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5578 if (empty_kw) {
5579 if (only_kw && method_call_keywords) {
5580 /* **{} appears at the only keyword argument in method call,
5581 * so it won't be modified.
5582 * kw is a special NODE_LIT that contains a special empty hash,
5583 * so this emits: putobject {}.
5584 * This is only done for method calls and not for literal hashes,
5585 * because literal hashes should always result in a new hash.
5586 */
5587 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5588 }
5589 else if (first_kw) {
5590 /* **{} appears as the first keyword argument, so it may be modified.
5591 * We need to create a fresh hash object.
5592 */
5593 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5594 }
5595 /* Any empty keyword splats that are not the first can be ignored.
5596 * since merging an empty hash into the existing hash is the same
5597 * as not merging it. */
5598 }
5599 else {
5600 if (only_kw && method_call_keywords) {
5601 /* **kw is only keyword argument in method call.
5602 * Use directly. This will be not be flagged as mutable.
5603 * This is only done for method calls and not for literal hashes,
5604 * because literal hashes should always result in a new hash.
5605 */
5606 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5607 }
5608 else {
5609 /* There is more than one keyword argument, or this is not a method
5610 * call. In that case, we need to add an empty hash (if first keyword),
5611 * or merge the hash to the accumulated hash (if not the first keyword).
5612 */
5613 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5614 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5615 else ADD_INSN(ret, line_node, swap);
5616
5617 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5618
5619 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5620 }
5621 }
5622
5623 first_chunk = 0;
5624 }
5625 }
5626 }
5627
5628 FLUSH_CHUNK();
5629#undef FLUSH_CHUNK
5630 return 1;
5631}
5632
5633static VALUE
5634rb_node_case_when_optimizable_literal(const NODE *const node)
5635{
5636 switch (nd_type(node)) {
5637 case NODE_INTEGER:
5638 return rb_node_integer_literal_val(node);
5639 case NODE_FLOAT: {
5640 VALUE v = rb_node_float_literal_val(node);
5641 double ival;
5642
5643 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5644 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5645 }
5646 return v;
5647 }
5648 case NODE_RATIONAL:
5649 case NODE_IMAGINARY:
5650 return Qundef;
5651 case NODE_NIL:
5652 return Qnil;
5653 case NODE_TRUE:
5654 return Qtrue;
5655 case NODE_FALSE:
5656 return Qfalse;
5657 case NODE_SYM:
5658 return rb_node_sym_string_val(node);
5659 case NODE_LINE:
5660 return rb_node_line_lineno_val(node);
5661 case NODE_STR:
5662 return rb_node_str_string_val(node);
5663 case NODE_FILE:
5664 return rb_node_file_path_val(node);
5665 }
5666 return Qundef;
5667}
5668
5669static int
5670when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5671 LABEL *l1, int only_special_literals, VALUE literals)
5672{
5673 while (vals) {
5674 const NODE *val = RNODE_LIST(vals)->nd_head;
5675 VALUE lit = rb_node_case_when_optimizable_literal(val);
5676
5677 if (UNDEF_P(lit)) {
5678 only_special_literals = 0;
5679 }
5680 else {
5681 cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
5682 }
5683
5684 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5685 debugp_param("nd_lit", get_string_value(val));
5686 lit = get_string_value(val);
5687 ADD_INSN1(cond_seq, val, putobject, lit);
5688 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5689 }
5690 else {
5691 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5692 }
5693
5694 // Emit pattern === target
5695 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5696 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5697 ADD_INSNL(cond_seq, val, branchif, l1);
5698 vals = RNODE_LIST(vals)->nd_next;
5699 }
5700 return only_special_literals;
5701}
5702
5703static int
5704when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5705 LABEL *l1, int only_special_literals, VALUE literals)
5706{
5707 const NODE *line_node = vals;
5708
5709 switch (nd_type(vals)) {
5710 case NODE_LIST:
5711 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5712 return COMPILE_NG;
5713 break;
5714 case NODE_SPLAT:
5715 ADD_INSN (cond_seq, line_node, dup);
5716 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5717 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5718 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5719 ADD_INSNL(cond_seq, line_node, branchif, l1);
5720 break;
5721 case NODE_ARGSCAT:
5722 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5723 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5724 break;
5725 case NODE_ARGSPUSH:
5726 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5727 ADD_INSN (cond_seq, line_node, dup);
5728 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5729 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5730 ADD_INSNL(cond_seq, line_node, branchif, l1);
5731 break;
5732 default:
5733 ADD_INSN (cond_seq, line_node, dup);
5734 CHECK(COMPILE(cond_seq, "when val", vals));
5735 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5736 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5737 ADD_INSNL(cond_seq, line_node, branchif, l1);
5738 break;
5739 }
5740 return COMPILE_OK;
5741}
5742
5743/* Multiple Assignment Handling
5744 *
5745 * In order to handle evaluation of multiple assignment such that the left hand side
5746 * is evaluated before the right hand side, we need to process the left hand side
5747 * and see if there are any attributes that need to be assigned, or constants set
5748 * on explicit objects. If so, we add instructions to evaluate the receiver of
5749 * any assigned attributes or constants before we process the right hand side.
5750 *
5751 * For a multiple assignment such as:
5752 *
5753 * l1.m1, l2[0] = r3, r4
5754 *
5755 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5756 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5757 * On the VM stack, this looks like:
5758 *
5759 * self # putself
5760 * l1 # send
5761 * l1, self # putself
5762 * l1, l2 # send
5763 * l1, l2, 0 # putobject 0
5764 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5765 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5766 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5767 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5768 * l1, l2, 0, [r3, r4], r4, m1= # send
5769 * l1, l2, 0, [r3, r4], r4 # pop
5770 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5771 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5772 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5773 * l1, l2, 0, [r3, r4], r4, []= # send
5774 * l1, l2, 0, [r3, r4], r4 # pop
5775 * l1, l2, 0, [r3, r4] # pop
5776 * [r3, r4], l2, 0, [r3, r4] # setn 3
5777 * [r3, r4], l2, 0 # pop
5778 * [r3, r4], l2 # pop
5779 * [r3, r4] # pop
5780 *
5781 * This is made more complex when you have to handle splats, post args,
5782 * and arbitrary levels of nesting. You need to keep track of the total
5783 * number of attributes to set, and for each attribute, how many entries
5784 * are on the stack before the final attribute, in order to correctly
5785 * calculate the topn value to use to get the receiver of the attribute
5786 * setter method.
5787 *
5788 * A brief description of the VM stack for simple multiple assignment
5789 * with no splat (rhs_array will not be present if the return value of
5790 * the multiple assignment is not needed):
5791 *
5792 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5793 *
5794 * For multiple assignment with splats, while processing the part before
5795 * the splat (splat+post here is an array of the splat and the post arguments):
5796 *
5797 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5798 *
5799 * When processing the splat and post arguments:
5800 *
5801 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5802 *
5803 * When processing nested multiple assignment, existing values on the stack
5804 * are kept. So for:
5805 *
5806 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5807 *
5808 * The stack layout would be the following before processing the nested
5809 * multiple assignment:
5810 *
5811 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5812 *
5813 * In order to handle this correctly, we need to keep track of the nesting
5814 * level for each attribute assignment, as well as the attribute number
5815 * (left hand side attributes are processed left to right) and number of
5816 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5817 * this information.
5818 *
5819 * We also need to track information for the entire multiple assignment, such
5820 * as the total number of arguments, and the current nesting level, to
5821 * handle both nested multiple assignment as well as cases where the
5822 * rhs is not needed. We also need to keep track of all attribute
5823 * assignments in this, which we do using a linked listed. struct masgn_state
5824 * tracks this information.
5825 */
5826
5828 INSN *before_insn;
5829 struct masgn_lhs_node *next;
5830 const NODE *line_node;
5831 int argn;
5832 int num_args;
5833 int lhs_pos;
5834};
5835
5837 struct masgn_lhs_node *first_memo;
5838 struct masgn_lhs_node *last_memo;
5839 int lhs_level;
5840 int num_args;
5841 bool nested;
5842};
5843
5844static int
5845add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5846{
5847 if (!state) {
5848 rb_bug("no masgn_state");
5849 }
5850
5851 struct masgn_lhs_node *memo;
5852 memo = malloc(sizeof(struct masgn_lhs_node));
5853 if (!memo) {
5854 return COMPILE_NG;
5855 }
5856
5857 memo->before_insn = before_insn;
5858 memo->line_node = line_node;
5859 memo->argn = state->num_args + 1;
5860 memo->num_args = argc;
5861 state->num_args += argc;
5862 memo->lhs_pos = lhs_pos;
5863 memo->next = NULL;
5864 if (!state->first_memo) {
5865 state->first_memo = memo;
5866 }
5867 else {
5868 state->last_memo->next = memo;
5869 }
5870 state->last_memo = memo;
5871
5872 return COMPILE_OK;
5873}
5874
5875static 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);
5876
5877static int
5878compile_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)
5879{
5880 switch (nd_type(node)) {
5881 case NODE_ATTRASGN: {
5882 INSN *iobj;
5883 const NODE *line_node = node;
5884
5885 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5886
5887 bool safenav_call = false;
5888 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5889 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5890 ASSUME(iobj);
5891 ELEM_REMOVE(insn_element);
5892 if (!IS_INSN_ID(iobj, send)) {
5893 safenav_call = true;
5894 iobj = (INSN *)get_prev_insn(iobj);
5895 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5896 }
5897 (pre->last = iobj->link.prev)->next = 0;
5898
5899 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5900 int argc = vm_ci_argc(ci) + 1;
5901 ci = ci_argc_set(iseq, ci, argc);
5902 OPERAND_AT(iobj, 0) = (VALUE)ci;
5903 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5904
5905 if (argc == 1) {
5906 ADD_INSN(lhs, line_node, swap);
5907 }
5908 else {
5909 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5910 }
5911
5912 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5913 return COMPILE_NG;
5914 }
5915
5916 iobj->link.prev = lhs->last;
5917 lhs->last->next = &iobj->link;
5918 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5919 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5920 int argc = vm_ci_argc(ci);
5921 bool dupsplat = false;
5922 ci = ci_argc_set(iseq, ci, argc - 1);
5923 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5924 /* Given h[*a], _ = ary
5925 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5926 * `a` must be dupped, because it will be appended with ary[0]
5927 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5928 */
5929 dupsplat = true;
5930 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5931 }
5932 OPERAND_AT(iobj, 0) = (VALUE)ci;
5933 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5934
5935 /* Given: h[*a], h[*b, 1] = ary
5936 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5937 * so this uses splatarray true on a to dup it before using pushtoarray
5938 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5939 * so you can use pushtoarray directly
5940 */
5941 int line_no = nd_line(line_node);
5942 int node_id = nd_node_id(line_node);
5943
5944 if (dupsplat) {
5945 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5946 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5947 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5948 }
5949 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5950 }
5951 if (!safenav_call) {
5952 ADD_INSN(lhs, line_node, pop);
5953 if (argc != 1) {
5954 ADD_INSN(lhs, line_node, pop);
5955 }
5956 }
5957 for (int i=0; i < argc; i++) {
5958 ADD_INSN(post, line_node, pop);
5959 }
5960 break;
5961 }
5962 case NODE_MASGN: {
5963 DECL_ANCHOR(nest_rhs);
5964 INIT_ANCHOR(nest_rhs);
5965 DECL_ANCHOR(nest_lhs);
5966 INIT_ANCHOR(nest_lhs);
5967
5968 int prev_level = state->lhs_level;
5969 bool prev_nested = state->nested;
5970 state->nested = 1;
5971 state->lhs_level = lhs_pos - 1;
5972 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5973 state->lhs_level = prev_level;
5974 state->nested = prev_nested;
5975
5976 ADD_SEQ(lhs, nest_rhs);
5977 ADD_SEQ(lhs, nest_lhs);
5978 break;
5979 }
5980 case NODE_CDECL:
5981 if (!RNODE_CDECL(node)->nd_vid) {
5982 /* Special handling only needed for expr::C, not for C */
5983 INSN *iobj;
5984
5985 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5986
5987 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5988 iobj = (INSN *)insn_element; /* setconstant insn */
5989 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5990 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5991 ELEM_REMOVE(insn_element);
5992 pre->last = iobj->link.prev;
5993 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5994
5995 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5996 return COMPILE_NG;
5997 }
5998
5999 ADD_INSN(post, node, pop);
6000 break;
6001 }
6002 /* Fallthrough */
6003 default: {
6004 DECL_ANCHOR(anchor);
6005 INIT_ANCHOR(anchor);
6006 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
6007 ELEM_REMOVE(FIRST_ELEMENT(anchor));
6008 ADD_SEQ(lhs, anchor);
6009 }
6010 }
6011
6012 return COMPILE_OK;
6013}
6014
6015static int
6016compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
6017{
6018 if (lhsn) {
6019 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
6020 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
6021 }
6022 return COMPILE_OK;
6023}
6024
6025static int
6026compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6027 const NODE *rhsn, const NODE *orig_lhsn)
6028{
6029 VALUE mem[64];
6030 const int memsize = numberof(mem);
6031 int memindex = 0;
6032 int llen = 0, rlen = 0;
6033 int i;
6034 const NODE *lhsn = orig_lhsn;
6035
6036#define MEMORY(v) { \
6037 int i; \
6038 if (memindex == memsize) return 0; \
6039 for (i=0; i<memindex; i++) { \
6040 if (mem[i] == (v)) return 0; \
6041 } \
6042 mem[memindex++] = (v); \
6043}
6044
6045 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
6046 return 0;
6047 }
6048
6049 while (lhsn) {
6050 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
6051 switch (nd_type(ln)) {
6052 case NODE_LASGN:
6053 case NODE_DASGN:
6054 case NODE_IASGN:
6055 case NODE_CVASGN:
6056 MEMORY(get_nd_vid(ln));
6057 break;
6058 default:
6059 return 0;
6060 }
6061 lhsn = RNODE_LIST(lhsn)->nd_next;
6062 llen++;
6063 }
6064
6065 while (rhsn) {
6066 if (llen <= rlen) {
6067 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
6068 }
6069 else {
6070 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
6071 }
6072 rhsn = RNODE_LIST(rhsn)->nd_next;
6073 rlen++;
6074 }
6075
6076 if (llen > rlen) {
6077 for (i=0; i<llen-rlen; i++) {
6078 ADD_INSN(ret, orig_lhsn, putnil);
6079 }
6080 }
6081
6082 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
6083 return 1;
6084}
6085
6086static int
6087compile_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)
6088{
6089 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
6090 const NODE *splatn = RNODE_MASGN(node)->nd_args;
6091 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
6092 const NODE *lhsn_count = lhsn;
6093 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
6094
6095 int llen = 0;
6096 int lpos = 0;
6097
6098 while (lhsn_count) {
6099 llen++;
6100 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
6101 }
6102 while (lhsn) {
6103 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
6104 lpos++;
6105 lhsn = RNODE_LIST(lhsn)->nd_next;
6106 }
6107
6108 if (lhs_splat) {
6109 if (nd_type_p(splatn, NODE_POSTARG)) {
6110 /*a, b, *r, p1, p2 */
6111 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
6112 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
6113 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
6114 int ppos = 0;
6115 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
6116
6117 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6118
6119 if (NODE_NAMED_REST_P(restn)) {
6120 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6121 }
6122 while (postn) {
6123 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6124 ppos++;
6125 postn = RNODE_LIST(postn)->nd_next;
6126 }
6127 }
6128 else {
6129 /* a, b, *r */
6130 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6131 }
6132 }
6133
6134 if (!state->nested) {
6135 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6136 }
6137
6138 if (!popped) {
6139 ADD_INSN(rhs, node, dup);
6140 }
6141 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6142 return COMPILE_OK;
6143}
6144
6145static int
6146compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6147{
6148 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6149 struct masgn_state state;
6150 state.lhs_level = popped ? 0 : 1;
6151 state.nested = 0;
6152 state.num_args = 0;
6153 state.first_memo = NULL;
6154 state.last_memo = NULL;
6155
6156 DECL_ANCHOR(pre);
6157 INIT_ANCHOR(pre);
6158 DECL_ANCHOR(rhs);
6159 INIT_ANCHOR(rhs);
6160 DECL_ANCHOR(lhs);
6161 INIT_ANCHOR(lhs);
6162 DECL_ANCHOR(post);
6163 INIT_ANCHOR(post);
6164 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6165
6166 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6167 while (memo) {
6168 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6169 for (int i = 0; i < memo->num_args; i++) {
6170 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6171 }
6172 tmp_memo = memo->next;
6173 free(memo);
6174 memo = tmp_memo;
6175 }
6176 CHECK(ok);
6177
6178 ADD_SEQ(ret, pre);
6179 ADD_SEQ(ret, rhs);
6180 ADD_SEQ(ret, lhs);
6181 if (!popped && state.num_args >= 1) {
6182 /* make sure rhs array is returned before popping */
6183 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6184 }
6185 ADD_SEQ(ret, post);
6186 }
6187 return COMPILE_OK;
6188}
6189
6190static VALUE
6191collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6192{
6193 VALUE arr = rb_ary_new();
6194 for (;;) {
6195 switch (nd_type(node)) {
6196 case NODE_CONST:
6197 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6198 RB_OBJ_SET_SHAREABLE(arr);
6199 return arr;
6200 case NODE_COLON3:
6201 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6202 rb_ary_unshift(arr, ID2SYM(idNULL));
6203 RB_OBJ_SET_SHAREABLE(arr);
6204 return arr;
6205 case NODE_COLON2:
6206 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6207 node = RNODE_COLON2(node)->nd_head;
6208 break;
6209 default:
6210 return Qfalse;
6211 }
6212 }
6213}
6214
6215static int
6216compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6217 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6218{
6219 switch (nd_type(node)) {
6220 case NODE_CONST:
6221 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6222 ADD_INSN1(body, node, putobject, Qtrue);
6223 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6224 break;
6225 case NODE_COLON3:
6226 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6227 ADD_INSN(body, node, pop);
6228 ADD_INSN1(body, node, putobject, rb_cObject);
6229 ADD_INSN1(body, node, putobject, Qtrue);
6230 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6231 break;
6232 case NODE_COLON2:
6233 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6234 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6235 ADD_INSN1(body, node, putobject, Qfalse);
6236 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6237 break;
6238 default:
6239 CHECK(COMPILE(pref, "const colon2 prefix", node));
6240 break;
6241 }
6242 return COMPILE_OK;
6243}
6244
6245static int
6246cpath_const_p(const NODE *node)
6247{
6248 switch (nd_type(node)) {
6249 case NODE_CONST:
6250 case NODE_COLON3:
6251 return TRUE;
6252 case NODE_COLON2:
6253 if (RNODE_COLON2(node)->nd_head) {
6254 return cpath_const_p(RNODE_COLON2(node)->nd_head);
6255 }
6256 return TRUE;
6257 default:
6258 return FALSE;
6259 }
6260}
6261
6262static int
6263compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6264{
6265 if (nd_type_p(cpath, NODE_COLON3)) {
6266 /* toplevel class ::Foo */
6267 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6268 return VM_DEFINECLASS_FLAG_SCOPED;
6269 }
6270 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6271 /* Bar::Foo or expr::Foo */
6272 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6273 int flags = VM_DEFINECLASS_FLAG_SCOPED;
6274 if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
6275 flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
6276 }
6277 return flags;
6278 }
6279 else {
6280 /* class at cbase Foo */
6281 ADD_INSN1(ret, cpath, putspecialobject,
6282 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6283 return 0;
6284 }
6285}
6286
6287static inline int
6288private_recv_p(const NODE *node)
6289{
6290 NODE *recv = get_nd_recv(node);
6291 if (recv && nd_type_p(recv, NODE_SELF)) {
6292 return RNODE_SELF(recv)->nd_state != 0;
6293 }
6294 return 0;
6295}
6296
6297static void
6298defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6299 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6300
6301static int
6302compile_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);
6303
6304static void
6305defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6306 const NODE *const node, LABEL **lfinish, VALUE needstr,
6307 bool keep_result)
6308{
6309 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6310 enum node_type type;
6311 const int line = nd_line(node);
6312 const NODE *line_node = node;
6313
6314 switch (type = nd_type(node)) {
6315
6316 /* easy literals */
6317 case NODE_NIL:
6318 expr_type = DEFINED_NIL;
6319 break;
6320 case NODE_SELF:
6321 expr_type = DEFINED_SELF;
6322 break;
6323 case NODE_TRUE:
6324 expr_type = DEFINED_TRUE;
6325 break;
6326 case NODE_FALSE:
6327 expr_type = DEFINED_FALSE;
6328 break;
6329
6330 case NODE_HASH:
6331 case NODE_LIST:{
6332 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6333
6334 if (vals) {
6335 do {
6336 if (RNODE_LIST(vals)->nd_head) {
6337 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6338
6339 if (!lfinish[1]) {
6340 lfinish[1] = NEW_LABEL(line);
6341 }
6342 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6343 }
6344 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6345 }
6346 }
6347 /* fall through */
6348 case NODE_STR:
6349 case NODE_SYM:
6350 case NODE_REGX:
6351 case NODE_LINE:
6352 case NODE_FILE:
6353 case NODE_ENCODING:
6354 case NODE_INTEGER:
6355 case NODE_FLOAT:
6356 case NODE_RATIONAL:
6357 case NODE_IMAGINARY:
6358 case NODE_ZLIST:
6359 case NODE_AND:
6360 case NODE_OR:
6361 default:
6362 expr_type = DEFINED_EXPR;
6363 break;
6364
6365 case NODE_SPLAT:
6366 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6367 if (!lfinish[1]) {
6368 lfinish[1] = NEW_LABEL(line);
6369 }
6370 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6371 expr_type = DEFINED_EXPR;
6372 break;
6373
6374 /* variables */
6375 case NODE_LVAR:
6376 case NODE_DVAR:
6377 expr_type = DEFINED_LVAR;
6378 break;
6379
6380#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6381 case NODE_IVAR:
6382 ADD_INSN3(ret, line_node, definedivar,
6383 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6384 return;
6385
6386 case NODE_GVAR:
6387 ADD_INSN(ret, line_node, putnil);
6388 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6389 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6390 return;
6391
6392 case NODE_CVAR:
6393 ADD_INSN(ret, line_node, putnil);
6394 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6395 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6396 return;
6397
6398 case NODE_CONST:
6399 ADD_INSN(ret, line_node, putnil);
6400 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6401 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6402 return;
6403 case NODE_COLON2:
6404 if (!lfinish[1]) {
6405 lfinish[1] = NEW_LABEL(line);
6406 }
6407 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6408 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6409 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6410
6411 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6412 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6413 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6414 }
6415 else {
6416 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6417 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6418 }
6419 return;
6420 case NODE_COLON3:
6421 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6422 ADD_INSN3(ret, line_node, defined,
6423 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6424 return;
6425
6426 /* method dispatch */
6427 case NODE_CALL:
6428 case NODE_OPCALL:
6429 case NODE_VCALL:
6430 case NODE_FCALL:
6431 case NODE_ATTRASGN:{
6432 const int explicit_receiver =
6433 (type == NODE_CALL || type == NODE_OPCALL ||
6434 (type == NODE_ATTRASGN && !private_recv_p(node)));
6435
6436 if (get_nd_args(node) || explicit_receiver) {
6437 if (!lfinish[1]) {
6438 lfinish[1] = NEW_LABEL(line);
6439 }
6440 if (!lfinish[2]) {
6441 lfinish[2] = NEW_LABEL(line);
6442 }
6443 }
6444 if (get_nd_args(node)) {
6445 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6446 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6447 }
6448 if (explicit_receiver) {
6449 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6450 switch (nd_type(get_nd_recv(node))) {
6451 case NODE_CALL:
6452 case NODE_OPCALL:
6453 case NODE_VCALL:
6454 case NODE_FCALL:
6455 case NODE_ATTRASGN:
6456 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6457 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6458 break;
6459 default:
6460 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6461 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6462 break;
6463 }
6464 if (keep_result) {
6465 ADD_INSN(ret, line_node, dup);
6466 }
6467 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6468 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6469 }
6470 else {
6471 ADD_INSN(ret, line_node, putself);
6472 if (keep_result) {
6473 ADD_INSN(ret, line_node, dup);
6474 }
6475 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6476 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6477 }
6478 return;
6479 }
6480
6481 case NODE_YIELD:
6482 ADD_INSN(ret, line_node, putnil);
6483 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6484 PUSH_VAL(DEFINED_YIELD));
6485 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6486 return;
6487
6488 case NODE_BACK_REF:
6489 case NODE_NTH_REF:
6490 ADD_INSN(ret, line_node, putnil);
6491 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6492 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6493 PUSH_VAL(DEFINED_GVAR));
6494 return;
6495
6496 case NODE_SUPER:
6497 case NODE_ZSUPER:
6498 ADD_INSN(ret, line_node, putnil);
6499 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6500 PUSH_VAL(DEFINED_ZSUPER));
6501 return;
6502
6503#undef PUSH_VAL
6504 case NODE_OP_ASGN1:
6505 case NODE_OP_ASGN2:
6506 case NODE_OP_ASGN_OR:
6507 case NODE_OP_ASGN_AND:
6508 case NODE_MASGN:
6509 case NODE_LASGN:
6510 case NODE_DASGN:
6511 case NODE_GASGN:
6512 case NODE_IASGN:
6513 case NODE_CDECL:
6514 case NODE_CVASGN:
6515 case NODE_OP_CDECL:
6516 expr_type = DEFINED_ASGN;
6517 break;
6518 }
6519
6520 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6521
6522 if (needstr != Qfalse) {
6523 VALUE str = rb_iseq_defined_string(expr_type);
6524 ADD_INSN1(ret, line_node, putobject, str);
6525 }
6526 else {
6527 ADD_INSN1(ret, line_node, putobject, Qtrue);
6528 }
6529}
6530
6531static void
6532build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6533{
6534 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6535 iseq_set_exception_local_table(iseq);
6536}
6537
6538static void
6539defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6540 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6541{
6542 LINK_ELEMENT *lcur = ret->last;
6543 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6544 if (lfinish[1]) {
6545 int line = nd_line(node);
6546 LABEL *lstart = NEW_LABEL(line);
6547 LABEL *lend = NEW_LABEL(line);
6548 const rb_iseq_t *rescue;
6550 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6551 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6552 rb_str_concat(rb_str_new2("defined guard in "),
6553 ISEQ_BODY(iseq)->location.label),
6554 ISEQ_TYPE_RESCUE, 0);
6555 lstart->rescued = LABEL_RESCUE_BEG;
6556 lend->rescued = LABEL_RESCUE_END;
6557 APPEND_LABEL(ret, lcur, lstart);
6558 ADD_LABEL(ret, lend);
6559 if (!ignore) {
6560 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6561 }
6562 }
6563}
6564
6565static int
6566compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6567{
6568 const int line = nd_line(node);
6569 const NODE *line_node = node;
6570 if (!RNODE_DEFINED(node)->nd_head) {
6571 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6572 ADD_INSN1(ret, line_node, putobject, str);
6573 }
6574 else {
6575 LABEL *lfinish[3];
6576 LINK_ELEMENT *last = ret->last;
6577 lfinish[0] = NEW_LABEL(line);
6578 lfinish[1] = 0;
6579 lfinish[2] = 0;
6580 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6581 if (lfinish[1]) {
6582 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6583 ADD_INSN(ret, line_node, swap);
6584 if (lfinish[2]) {
6585 ADD_LABEL(ret, lfinish[2]);
6586 }
6587 ADD_INSN(ret, line_node, pop);
6588 ADD_LABEL(ret, lfinish[1]);
6589 }
6590 ADD_LABEL(ret, lfinish[0]);
6591 }
6592 return COMPILE_OK;
6593}
6594
6595static VALUE
6596make_name_for_block(const rb_iseq_t *orig_iseq)
6597{
6598 int level = 1;
6599 const rb_iseq_t *iseq = orig_iseq;
6600
6601 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6602 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6603 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6604 level++;
6605 }
6606 iseq = ISEQ_BODY(iseq)->parent_iseq;
6607 }
6608 }
6609
6610 if (level == 1) {
6611 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6612 }
6613 else {
6614 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6615 }
6616}
6617
6618static void
6619push_ensure_entry(rb_iseq_t *iseq,
6621 struct ensure_range *er, const void *const node)
6622{
6623 enl->ensure_node = node;
6624 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6625 enl->erange = er;
6626 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6627}
6628
6629static void
6630add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6631 LABEL *lstart, LABEL *lend)
6632{
6633 struct ensure_range *ne =
6634 compile_data_alloc_type(iseq, struct ensure_range);
6635
6636 while (erange->next != 0) {
6637 erange = erange->next;
6638 }
6639 ne->next = 0;
6640 ne->begin = lend;
6641 ne->end = erange->end;
6642 erange->end = lstart;
6643
6644 erange->next = ne;
6645}
6646
6647static bool
6648can_add_ensure_iseq(const rb_iseq_t *iseq)
6649{
6651 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6652 while (e) {
6653 if (e->ensure_node) return false;
6654 e = e->prev;
6655 }
6656 }
6657 return true;
6658}
6659
6660static void
6661add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6662{
6663 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6664
6666 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6667 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6668 DECL_ANCHOR(ensure);
6669
6670 INIT_ANCHOR(ensure);
6671 while (enlp) {
6672 if (enlp->erange != NULL) {
6673 DECL_ANCHOR(ensure_part);
6674 LABEL *lstart = NEW_LABEL(0);
6675 LABEL *lend = NEW_LABEL(0);
6676 INIT_ANCHOR(ensure_part);
6677
6678 add_ensure_range(iseq, enlp->erange, lstart, lend);
6679
6680 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6681 ADD_LABEL(ensure_part, lstart);
6682 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6683 ADD_LABEL(ensure_part, lend);
6684 ADD_SEQ(ensure, ensure_part);
6685 }
6686 else {
6687 if (!is_return) {
6688 break;
6689 }
6690 }
6691 enlp = enlp->prev;
6692 }
6693 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6694 ADD_SEQ(ret, ensure);
6695}
6696
6697#if RUBY_DEBUG
6698static int
6699check_keyword(const NODE *node)
6700{
6701 /* This check is essentially a code clone of compile_keyword_arg. */
6702
6703 if (nd_type_p(node, NODE_LIST)) {
6704 while (RNODE_LIST(node)->nd_next) {
6705 node = RNODE_LIST(node)->nd_next;
6706 }
6707 node = RNODE_LIST(node)->nd_head;
6708 }
6709
6710 return keyword_node_p(node);
6711}
6712#endif
6713
6714static bool
6715keyword_node_single_splat_p(NODE *kwnode)
6716{
6717 RUBY_ASSERT(keyword_node_p(kwnode));
6718
6719 NODE *node = RNODE_HASH(kwnode)->nd_head;
6720 return RNODE_LIST(node)->nd_head == NULL &&
6721 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6722}
6723
6724static void
6725compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6726 NODE *kwnode, unsigned int *flag_ptr)
6727{
6728 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6729 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6730 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6731 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6732 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6733}
6734
6735#define SPLATARRAY_FALSE 0
6736#define SPLATARRAY_TRUE 1
6737#define DUP_SINGLE_KW_SPLAT 2
6738
6739static int
6740setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6741 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6742{
6743 if (!argn) return 0;
6744
6745 NODE *kwnode = NULL;
6746
6747 switch (nd_type(argn)) {
6748 case NODE_LIST: {
6749 // f(x, y, z)
6750 int len = compile_args(iseq, args, argn, &kwnode);
6751 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6752
6753 if (kwnode) {
6754 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6755 len -= 1;
6756 }
6757 else {
6758 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6759 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6760 }
6761 else {
6762 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6763 }
6764 }
6765 }
6766
6767 return len;
6768 }
6769 case NODE_SPLAT: {
6770 // f(*a)
6771 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6772 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6773 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6774 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6775 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6776 return 1;
6777 }
6778 case NODE_ARGSCAT: {
6779 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6780 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6781 bool args_pushed = false;
6782
6783 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6784 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6785 if (kwnode) rest_len--;
6786 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6787 args_pushed = true;
6788 }
6789 else {
6790 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6791 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6792 }
6793
6794 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6795 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6796 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6797 argc += 1;
6798 }
6799 else if (!args_pushed) {
6800 ADD_INSN(args, argn, concattoarray);
6801 }
6802
6803 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6804 if (kwnode) {
6805 // kwsplat
6806 *flag_ptr |= VM_CALL_KW_SPLAT;
6807 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6808 argc += 1;
6809 }
6810
6811 return argc;
6812 }
6813 case NODE_ARGSPUSH: {
6814 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6815 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6816
6817 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6818 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6819 if (kwnode) rest_len--;
6820 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6821 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6822 }
6823 else {
6824 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6825 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6826 }
6827 else {
6828 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6829 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6830 }
6831 }
6832
6833 if (kwnode) {
6834 // f(*a, k:1)
6835 *flag_ptr |= VM_CALL_KW_SPLAT;
6836 if (!keyword_node_single_splat_p(kwnode)) {
6837 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6838 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6839 }
6840 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6841 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6842 }
6843 else {
6844 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6845 }
6846 argc += 1;
6847 }
6848
6849 return argc;
6850 }
6851 default: {
6852 UNKNOWN_NODE("setup_arg", argn, Qnil);
6853 }
6854 }
6855}
6856
6857static void
6858setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6859{
6860 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6861 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6862 }
6863}
6864
6865static bool
6866setup_args_dup_rest_p(const NODE *argn)
6867{
6868 switch(nd_type(argn)) {
6869 case NODE_LVAR:
6870 case NODE_DVAR:
6871 case NODE_GVAR:
6872 case NODE_IVAR:
6873 case NODE_CVAR:
6874 case NODE_CONST:
6875 case NODE_COLON3:
6876 case NODE_INTEGER:
6877 case NODE_FLOAT:
6878 case NODE_RATIONAL:
6879 case NODE_IMAGINARY:
6880 case NODE_STR:
6881 case NODE_SYM:
6882 case NODE_REGX:
6883 case NODE_SELF:
6884 case NODE_NIL:
6885 case NODE_TRUE:
6886 case NODE_FALSE:
6887 case NODE_LAMBDA:
6888 case NODE_NTH_REF:
6889 case NODE_BACK_REF:
6890 return false;
6891 case NODE_COLON2:
6892 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6893 case NODE_LIST:
6894 while (argn) {
6895 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6896 return true;
6897 }
6898 argn = RNODE_LIST(argn)->nd_next;
6899 }
6900 return false;
6901 default:
6902 return true;
6903 }
6904}
6905
6906static VALUE
6907setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6908 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6909{
6910 VALUE ret;
6911 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6912
6913 if (argn) {
6914 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6915 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6916
6917 if (check_arg) {
6918 switch(nd_type(check_arg)) {
6919 case(NODE_SPLAT):
6920 // avoid caller side array allocation for f(*arg)
6921 dup_rest = SPLATARRAY_FALSE;
6922 break;
6923 case(NODE_ARGSCAT):
6924 // avoid caller side array allocation for f(1, *arg)
6925 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6926 break;
6927 case(NODE_ARGSPUSH):
6928 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6929 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6930 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6931 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6932 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6933 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6934
6935 if (dup_rest == SPLATARRAY_FALSE) {
6936 // require allocation for keyword key/value/splat that may modify splatted argument
6937 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6938 while (node) {
6939 NODE *key_node = RNODE_LIST(node)->nd_head;
6940 if (key_node && setup_args_dup_rest_p(key_node)) {
6941 dup_rest = SPLATARRAY_TRUE;
6942 break;
6943 }
6944
6945 node = RNODE_LIST(node)->nd_next;
6946 NODE *value_node = RNODE_LIST(node)->nd_head;
6947 if (setup_args_dup_rest_p(value_node)) {
6948 dup_rest = SPLATARRAY_TRUE;
6949 break;
6950 }
6951
6952 node = RNODE_LIST(node)->nd_next;
6953 }
6954 }
6955 break;
6956 default:
6957 break;
6958 }
6959 }
6960
6961 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6962 // for block pass that may modify splatted argument, dup rest and kwrest if given
6963 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6964 }
6965 }
6966 initial_dup_rest = dup_rest;
6967
6968 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6969 DECL_ANCHOR(arg_block);
6970 INIT_ANCHOR(arg_block);
6971
6972 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6973 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6974
6975 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6976 const NODE * arg_node =
6977 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6978
6979 int argc = 0;
6980
6981 // Only compile leading args:
6982 // foo(x, y, ...)
6983 // ^^^^
6984 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6985 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6986 }
6987
6988 *flag |= VM_CALL_FORWARDING;
6989
6990 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6991 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6992 return INT2FIX(argc);
6993 }
6994 else {
6995 *flag |= VM_CALL_ARGS_BLOCKARG;
6996
6997 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6998 }
6999
7000 if (LIST_INSN_SIZE_ONE(arg_block)) {
7001 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
7002 if (IS_INSN(elem)) {
7003 INSN *iobj = (INSN *)elem;
7004 if (iobj->insn_id == BIN(getblockparam)) {
7005 iobj->insn_id = BIN(getblockparamproxy);
7006 }
7007 }
7008 }
7009 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
7010 ADD_SEQ(args, arg_block);
7011 }
7012 else {
7013 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
7014 }
7015 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7016 return ret;
7017}
7018
7019static void
7020build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
7021{
7022 const NODE *body = ptr;
7023 int line = nd_line(body);
7024 VALUE argc = INT2FIX(0);
7025 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
7026
7027 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7028 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
7029 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
7030 iseq_set_local_table(iseq, 0, 0);
7031}
7032
7033static void
7034compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
7035{
7036 const NODE *vars;
7037 LINK_ELEMENT *last;
7038 int line = nd_line(node);
7039 const NODE *line_node = node;
7040 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
7041
7042#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
7043 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
7044#else
7045 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
7046#endif
7047 ADD_INSN(ret, line_node, dup);
7048 ADD_INSNL(ret, line_node, branchunless, fail_label);
7049
7050 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7051 INSN *cap;
7052 if (RNODE_BLOCK(vars)->nd_next) {
7053 ADD_INSN(ret, line_node, dup);
7054 }
7055 last = ret->last;
7056 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7057 last = last->next; /* putobject :var */
7058 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
7059 NULL, INT2FIX(0), NULL);
7060 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
7061#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
7062 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
7063 /* only one name */
7064 DECL_ANCHOR(nom);
7065
7066 INIT_ANCHOR(nom);
7067 ADD_INSNL(nom, line_node, jump, end_label);
7068 ADD_LABEL(nom, fail_label);
7069# if 0 /* $~ must be MatchData or nil */
7070 ADD_INSN(nom, line_node, pop);
7071 ADD_INSN(nom, line_node, putnil);
7072# endif
7073 ADD_LABEL(nom, end_label);
7074 (nom->last->next = cap->link.next)->prev = nom->last;
7075 (cap->link.next = nom->anchor.next)->prev = &cap->link;
7076 return;
7077 }
7078#endif
7079 }
7080 ADD_INSNL(ret, line_node, jump, end_label);
7081 ADD_LABEL(ret, fail_label);
7082 ADD_INSN(ret, line_node, pop);
7083 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7084 last = ret->last;
7085 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7086 last = last->next; /* putobject :var */
7087 ((INSN*)last)->insn_id = BIN(putnil);
7088 ((INSN*)last)->operand_size = 0;
7089 }
7090 ADD_LABEL(ret, end_label);
7091}
7092
7093static int
7094optimizable_range_item_p(const NODE *n)
7095{
7096 if (!n) return FALSE;
7097 switch (nd_type(n)) {
7098 case NODE_LINE:
7099 return TRUE;
7100 case NODE_INTEGER:
7101 return TRUE;
7102 case NODE_NIL:
7103 return TRUE;
7104 default:
7105 return FALSE;
7106 }
7107}
7108
7109static VALUE
7110optimized_range_item(const NODE *n)
7111{
7112 switch (nd_type(n)) {
7113 case NODE_LINE:
7114 return rb_node_line_lineno_val(n);
7115 case NODE_INTEGER:
7116 return rb_node_integer_literal_val(n);
7117 case NODE_FLOAT:
7118 return rb_node_float_literal_val(n);
7119 case NODE_RATIONAL:
7120 return rb_node_rational_literal_val(n);
7121 case NODE_IMAGINARY:
7122 return rb_node_imaginary_literal_val(n);
7123 case NODE_NIL:
7124 return Qnil;
7125 default:
7126 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
7127 }
7128}
7129
7130static int
7131compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7132{
7133 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
7134 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
7135
7136 const int line = nd_line(node);
7137 const NODE *line_node = node;
7138 DECL_ANCHOR(cond_seq);
7139 LABEL *then_label, *else_label, *end_label;
7140 VALUE branches = Qfalse;
7141
7142 INIT_ANCHOR(cond_seq);
7143 then_label = NEW_LABEL(line);
7144 else_label = NEW_LABEL(line);
7145 end_label = 0;
7146
7147 NODE *cond = RNODE_IF(node)->nd_cond;
7148 if (nd_type(cond) == NODE_BLOCK) {
7149 cond = RNODE_BLOCK(cond)->nd_head;
7150 }
7151
7152 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7153 ADD_SEQ(ret, cond_seq);
7154
7155 if (then_label->refcnt && else_label->refcnt) {
7156 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7157 }
7158
7159 if (then_label->refcnt) {
7160 ADD_LABEL(ret, then_label);
7161
7162 DECL_ANCHOR(then_seq);
7163 INIT_ANCHOR(then_seq);
7164 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7165
7166 if (else_label->refcnt) {
7167 const NODE *const coverage_node = node_body ? node_body : node;
7168 add_trace_branch_coverage(
7169 iseq,
7170 ret,
7171 nd_code_loc(coverage_node),
7172 nd_node_id(coverage_node),
7173 0,
7174 type == NODE_IF ? "then" : "else",
7175 branches);
7176 end_label = NEW_LABEL(line);
7177 ADD_INSNL(then_seq, line_node, jump, end_label);
7178 if (!popped) {
7179 ADD_INSN(then_seq, line_node, pop);
7180 }
7181 }
7182 ADD_SEQ(ret, then_seq);
7183 }
7184
7185 if (else_label->refcnt) {
7186 ADD_LABEL(ret, else_label);
7187
7188 DECL_ANCHOR(else_seq);
7189 INIT_ANCHOR(else_seq);
7190 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7191
7192 if (then_label->refcnt) {
7193 const NODE *const coverage_node = node_else ? node_else : node;
7194 add_trace_branch_coverage(
7195 iseq,
7196 ret,
7197 nd_code_loc(coverage_node),
7198 nd_node_id(coverage_node),
7199 1,
7200 type == NODE_IF ? "else" : "then",
7201 branches);
7202 }
7203 ADD_SEQ(ret, else_seq);
7204 }
7205
7206 if (end_label) {
7207 ADD_LABEL(ret, end_label);
7208 }
7209
7210 return COMPILE_OK;
7211}
7212
7213static int
7214compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7215{
7216 const NODE *vals;
7217 const NODE *node = orig_node;
7218 LABEL *endlabel, *elselabel;
7219 DECL_ANCHOR(head);
7220 DECL_ANCHOR(body_seq);
7221 DECL_ANCHOR(cond_seq);
7222 int only_special_literals = 1;
7223 VALUE literals = cdhash_new(0);
7224 int line;
7225 enum node_type type;
7226 const NODE *line_node;
7227 VALUE branches = Qfalse;
7228 int branch_id = 0;
7229
7230 INIT_ANCHOR(head);
7231 INIT_ANCHOR(body_seq);
7232 INIT_ANCHOR(cond_seq);
7233
7234 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7235
7236 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
7237
7238 node = RNODE_CASE(node)->nd_body;
7239 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7240 type = nd_type(node);
7241 line = nd_line(node);
7242 line_node = node;
7243
7244 endlabel = NEW_LABEL(line);
7245 elselabel = NEW_LABEL(line);
7246
7247 ADD_SEQ(ret, head); /* case VAL */
7248
7249 while (type == NODE_WHEN) {
7250 LABEL *l1;
7251
7252 l1 = NEW_LABEL(line);
7253 ADD_LABEL(body_seq, l1);
7254 ADD_INSN(body_seq, line_node, pop);
7255
7256 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7257 add_trace_branch_coverage(
7258 iseq,
7259 body_seq,
7260 nd_code_loc(coverage_node),
7261 nd_node_id(coverage_node),
7262 branch_id++,
7263 "when",
7264 branches);
7265
7266 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7267 ADD_INSNL(body_seq, line_node, jump, endlabel);
7268
7269 vals = RNODE_WHEN(node)->nd_head;
7270 if (vals) {
7271 switch (nd_type(vals)) {
7272 case NODE_LIST:
7273 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7274 if (only_special_literals < 0) return COMPILE_NG;
7275 break;
7276 case NODE_SPLAT:
7277 case NODE_ARGSCAT:
7278 case NODE_ARGSPUSH:
7279 only_special_literals = 0;
7280 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7281 break;
7282 default:
7283 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7284 }
7285 }
7286 else {
7287 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7288 }
7289
7290 node = RNODE_WHEN(node)->nd_next;
7291 if (!node) {
7292 break;
7293 }
7294 type = nd_type(node);
7295 line = nd_line(node);
7296 line_node = node;
7297 }
7298 /* else */
7299 if (node) {
7300 ADD_LABEL(cond_seq, elselabel);
7301 ADD_INSN(cond_seq, line_node, pop);
7302 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7303 CHECK(COMPILE_(cond_seq, "else", node, popped));
7304 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7305 }
7306 else {
7307 debugs("== else (implicit)\n");
7308 ADD_LABEL(cond_seq, elselabel);
7309 ADD_INSN(cond_seq, orig_node, pop);
7310 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7311 if (!popped) {
7312 ADD_INSN(cond_seq, orig_node, putnil);
7313 }
7314 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7315 }
7316
7317 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7318 ADD_INSN(ret, orig_node, dup);
7319 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7320 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7321 LABEL_REF(elselabel);
7322 }
7323
7324 ADD_SEQ(ret, cond_seq);
7325 ADD_SEQ(ret, body_seq);
7326 ADD_LABEL(ret, endlabel);
7327 return COMPILE_OK;
7328}
7329
7330static int
7331compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7332{
7333 const NODE *vals;
7334 const NODE *val;
7335 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7336 LABEL *endlabel;
7337 DECL_ANCHOR(body_seq);
7338 VALUE branches = Qfalse;
7339 int branch_id = 0;
7340
7341 branches = decl_branch_base(iseq, nd_node_id(orig_node), nd_code_loc(orig_node), "case");
7342
7343 INIT_ANCHOR(body_seq);
7344 endlabel = NEW_LABEL(nd_line(node));
7345
7346 while (node && nd_type_p(node, NODE_WHEN)) {
7347 const int line = nd_line(node);
7348 LABEL *l1 = NEW_LABEL(line);
7349 ADD_LABEL(body_seq, l1);
7350
7351 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7352 add_trace_branch_coverage(
7353 iseq,
7354 body_seq,
7355 nd_code_loc(coverage_node),
7356 nd_node_id(coverage_node),
7357 branch_id++,
7358 "when",
7359 branches);
7360
7361 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7362 ADD_INSNL(body_seq, node, jump, endlabel);
7363
7364 vals = RNODE_WHEN(node)->nd_head;
7365 if (!vals) {
7366 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7367 }
7368 switch (nd_type(vals)) {
7369 case NODE_LIST:
7370 while (vals) {
7371 LABEL *lnext;
7372 val = RNODE_LIST(vals)->nd_head;
7373 lnext = NEW_LABEL(nd_line(val));
7374 debug_compile("== when2\n", (void)0);
7375 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7376 ADD_LABEL(ret, lnext);
7377 vals = RNODE_LIST(vals)->nd_next;
7378 }
7379 break;
7380 case NODE_SPLAT:
7381 case NODE_ARGSCAT:
7382 case NODE_ARGSPUSH:
7383 ADD_INSN(ret, vals, putnil);
7384 CHECK(COMPILE(ret, "when2/cond splat", vals));
7385 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7386 ADD_INSNL(ret, vals, branchif, l1);
7387 break;
7388 default:
7389 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7390 }
7391 node = RNODE_WHEN(node)->nd_next;
7392 }
7393 /* else */
7394 const NODE *const coverage_node = node ? node : orig_node;
7395 add_trace_branch_coverage(
7396 iseq,
7397 ret,
7398 nd_code_loc(coverage_node),
7399 nd_node_id(coverage_node),
7400 branch_id,
7401 "else",
7402 branches);
7403 CHECK(COMPILE_(ret, "else", node, popped));
7404 ADD_INSNL(ret, orig_node, jump, endlabel);
7405
7406 ADD_SEQ(ret, body_seq);
7407 ADD_LABEL(ret, endlabel);
7408 return COMPILE_OK;
7409}
7410
7411static 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);
7412
7413static 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);
7414static 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);
7415static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7416static 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);
7417static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7418
7419#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7420#define CASE3_BI_OFFSET_ERROR_STRING 1
7421#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7422#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7423#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7424
7425static int
7426iseq_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)
7427{
7428 const int line = nd_line(node);
7429 const NODE *line_node = node;
7430
7431 switch (nd_type(node)) {
7432 case NODE_ARYPTN: {
7433 /*
7434 * if pattern.use_rest_num?
7435 * rest_num = 0
7436 * end
7437 * if pattern.has_constant_node?
7438 * unless pattern.constant === obj
7439 * goto match_failed
7440 * end
7441 * end
7442 * unless obj.respond_to?(:deconstruct)
7443 * goto match_failed
7444 * end
7445 * d = obj.deconstruct
7446 * unless Array === d
7447 * goto type_error
7448 * end
7449 * min_argc = pattern.pre_args_num + pattern.post_args_num
7450 * if pattern.has_rest_arg?
7451 * unless d.length >= min_argc
7452 * goto match_failed
7453 * end
7454 * else
7455 * unless d.length == min_argc
7456 * goto match_failed
7457 * end
7458 * end
7459 * pattern.pre_args_num.each do |i|
7460 * unless pattern.pre_args[i].match?(d[i])
7461 * goto match_failed
7462 * end
7463 * end
7464 * if pattern.use_rest_num?
7465 * rest_num = d.length - min_argc
7466 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7467 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7468 * goto match_failed
7469 * end
7470 * end
7471 * end
7472 * pattern.post_args_num.each do |i|
7473 * j = pattern.pre_args_num + i
7474 * j += rest_num
7475 * unless pattern.post_args[i].match?(d[j])
7476 * goto match_failed
7477 * end
7478 * end
7479 * goto matched
7480 * type_error:
7481 * FrozenCore.raise TypeError
7482 * match_failed:
7483 * goto unmatched
7484 */
7485 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7486 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7487 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7488
7489 const int min_argc = pre_args_num + post_args_num;
7490 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7491 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7492
7493 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7494 int i;
7495 match_failed = NEW_LABEL(line);
7496 type_error = NEW_LABEL(line);
7497 deconstruct = NEW_LABEL(line);
7498 deconstructed = NEW_LABEL(line);
7499
7500 if (use_rest_num) {
7501 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7502 ADD_INSN(ret, line_node, swap);
7503 if (base_index) {
7504 base_index++;
7505 }
7506 }
7507
7508 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7509
7510 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7511
7512 ADD_INSN(ret, line_node, dup);
7513 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7514 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7515 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7516 if (in_single_pattern) {
7517 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7518 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7519 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7520 INT2FIX(min_argc), base_index + 1 /* (1) */));
7521 }
7522 ADD_INSNL(ret, line_node, branchunless, match_failed);
7523
7524 for (i = 0; i < pre_args_num; i++) {
7525 ADD_INSN(ret, line_node, dup);
7526 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7527 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7528 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));
7529 args = RNODE_LIST(args)->nd_next;
7530 }
7531
7532 if (RNODE_ARYPTN(node)->rest_arg) {
7533 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7534 ADD_INSN(ret, line_node, dup);
7535 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7536 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7537 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7538 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7539 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7540 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7541 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7542
7543 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));
7544 }
7545 else {
7546 if (post_args_num > 0) {
7547 ADD_INSN(ret, line_node, dup);
7548 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7549 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7550 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7551 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7552 ADD_INSN(ret, line_node, pop);
7553 }
7554 }
7555 }
7556
7557 args = RNODE_ARYPTN(node)->post_args;
7558 for (i = 0; i < post_args_num; i++) {
7559 ADD_INSN(ret, line_node, dup);
7560
7561 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7562 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7563 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7564
7565 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7566 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));
7567 args = RNODE_LIST(args)->nd_next;
7568 }
7569
7570 ADD_INSN(ret, line_node, pop);
7571 if (use_rest_num) {
7572 ADD_INSN(ret, line_node, pop);
7573 }
7574 ADD_INSNL(ret, line_node, jump, matched);
7575 ADD_INSN(ret, line_node, putnil);
7576 if (use_rest_num) {
7577 ADD_INSN(ret, line_node, putnil);
7578 }
7579
7580 ADD_LABEL(ret, type_error);
7581 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7582 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7583 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7584 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7585 ADD_INSN(ret, line_node, pop);
7586
7587 ADD_LABEL(ret, match_failed);
7588 ADD_INSN(ret, line_node, pop);
7589 if (use_rest_num) {
7590 ADD_INSN(ret, line_node, pop);
7591 }
7592 ADD_INSNL(ret, line_node, jump, unmatched);
7593
7594 break;
7595 }
7596 case NODE_FNDPTN: {
7597 /*
7598 * if pattern.has_constant_node?
7599 * unless pattern.constant === obj
7600 * goto match_failed
7601 * end
7602 * end
7603 * unless obj.respond_to?(:deconstruct)
7604 * goto match_failed
7605 * end
7606 * d = obj.deconstruct
7607 * unless Array === d
7608 * goto type_error
7609 * end
7610 * unless d.length >= pattern.args_num
7611 * goto match_failed
7612 * end
7613 *
7614 * begin
7615 * len = d.length
7616 * limit = d.length - pattern.args_num
7617 * i = 0
7618 * while i <= limit
7619 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7620 * if pattern.has_pre_rest_arg_id
7621 * unless pattern.pre_rest_arg.match?(d[0, i])
7622 * goto find_failed
7623 * end
7624 * end
7625 * if pattern.has_post_rest_arg_id
7626 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7627 * goto find_failed
7628 * end
7629 * end
7630 * goto find_succeeded
7631 * end
7632 * i+=1
7633 * end
7634 * find_failed:
7635 * goto match_failed
7636 * find_succeeded:
7637 * end
7638 *
7639 * goto matched
7640 * type_error:
7641 * FrozenCore.raise TypeError
7642 * match_failed:
7643 * goto unmatched
7644 */
7645 const NODE *args = RNODE_FNDPTN(node)->args;
7646 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7647
7648 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7649 match_failed = NEW_LABEL(line);
7650 type_error = NEW_LABEL(line);
7651 deconstruct = NEW_LABEL(line);
7652 deconstructed = NEW_LABEL(line);
7653
7654 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7655
7656 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7657
7658 ADD_INSN(ret, line_node, dup);
7659 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7660 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7661 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7662 if (in_single_pattern) {
7663 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) */));
7664 }
7665 ADD_INSNL(ret, line_node, branchunless, match_failed);
7666
7667 {
7668 LABEL *while_begin = NEW_LABEL(nd_line(node));
7669 LABEL *next_loop = NEW_LABEL(nd_line(node));
7670 LABEL *find_succeeded = NEW_LABEL(line);
7671 LABEL *find_failed = NEW_LABEL(nd_line(node));
7672 int j;
7673
7674 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7675 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7676
7677 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7678 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7679 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7680
7681 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7682
7683 ADD_LABEL(ret, while_begin);
7684
7685 ADD_INSN(ret, line_node, dup);
7686 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7687 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7688 ADD_INSNL(ret, line_node, branchunless, find_failed);
7689
7690 for (j = 0; j < args_num; j++) {
7691 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7692 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7693 if (j != 0) {
7694 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7695 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7696 }
7697 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7698
7699 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));
7700 args = RNODE_LIST(args)->nd_next;
7701 }
7702
7703 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7704 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7705 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7706 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7707 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7708 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));
7709 }
7710 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7711 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7712 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7713 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7714 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7715 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7716 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7717 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));
7718 }
7719 ADD_INSNL(ret, line_node, jump, find_succeeded);
7720
7721 ADD_LABEL(ret, next_loop);
7722 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7723 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7724 ADD_INSNL(ret, line_node, jump, while_begin);
7725
7726 ADD_LABEL(ret, find_failed);
7727 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7728 if (in_single_pattern) {
7729 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7730 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7731 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7732 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7733 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7734
7735 ADD_INSN1(ret, line_node, putobject, Qfalse);
7736 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7737
7738 ADD_INSN(ret, line_node, pop);
7739 ADD_INSN(ret, line_node, pop);
7740 }
7741 ADD_INSNL(ret, line_node, jump, match_failed);
7742 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7743
7744 ADD_LABEL(ret, find_succeeded);
7745 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7746 }
7747
7748 ADD_INSN(ret, line_node, pop);
7749 ADD_INSNL(ret, line_node, jump, matched);
7750 ADD_INSN(ret, line_node, putnil);
7751
7752 ADD_LABEL(ret, type_error);
7753 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7754 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7755 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7756 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7757 ADD_INSN(ret, line_node, pop);
7758
7759 ADD_LABEL(ret, match_failed);
7760 ADD_INSN(ret, line_node, pop);
7761 ADD_INSNL(ret, line_node, jump, unmatched);
7762
7763 break;
7764 }
7765 case NODE_HSHPTN: {
7766 /*
7767 * keys = nil
7768 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7769 * keys = pattern.kw_args_node.keys
7770 * end
7771 * if pattern.has_constant_node?
7772 * unless pattern.constant === obj
7773 * goto match_failed
7774 * end
7775 * end
7776 * unless obj.respond_to?(:deconstruct_keys)
7777 * goto match_failed
7778 * end
7779 * d = obj.deconstruct_keys(keys)
7780 * unless Hash === d
7781 * goto type_error
7782 * end
7783 * if pattern.has_kw_rest_arg_node?
7784 * d = d.dup
7785 * end
7786 * if pattern.has_kw_args_node?
7787 * pattern.kw_args_node.each |k,|
7788 * unless d.key?(k)
7789 * goto match_failed
7790 * end
7791 * end
7792 * pattern.kw_args_node.each |k, pat|
7793 * if pattern.has_kw_rest_arg_node?
7794 * unless pat.match?(d.delete(k))
7795 * goto match_failed
7796 * end
7797 * else
7798 * unless pat.match?(d[k])
7799 * goto match_failed
7800 * end
7801 * end
7802 * end
7803 * else
7804 * unless d.empty?
7805 * goto match_failed
7806 * end
7807 * end
7808 * if pattern.has_kw_rest_arg_node?
7809 * if pattern.no_rest_keyword?
7810 * unless d.empty?
7811 * goto match_failed
7812 * end
7813 * else
7814 * unless pattern.kw_rest_arg_node.match?(d)
7815 * goto match_failed
7816 * end
7817 * end
7818 * end
7819 * goto matched
7820 * type_error:
7821 * FrozenCore.raise TypeError
7822 * match_failed:
7823 * goto unmatched
7824 */
7825 LABEL *match_failed, *type_error;
7826 VALUE keys = Qnil;
7827
7828 match_failed = NEW_LABEL(line);
7829 type_error = NEW_LABEL(line);
7830
7831 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7832 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7833 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7834 while (kw_args) {
7835 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7836 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7837 }
7838 }
7839
7840 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7841
7842 ADD_INSN(ret, line_node, dup);
7843 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7844 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7845 if (in_single_pattern) {
7846 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7847 }
7848 ADD_INSNL(ret, line_node, branchunless, match_failed);
7849
7850 if (NIL_P(keys)) {
7851 ADD_INSN(ret, line_node, putnil);
7852 }
7853 else {
7854 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7855 ADD_INSN1(ret, line_node, duparray, keys);
7856 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7857 }
7858 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7859
7860 ADD_INSN(ret, line_node, dup);
7861 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7862 ADD_INSNL(ret, line_node, branchunless, type_error);
7863
7864 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7865 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7866 }
7867
7868 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7869 int i;
7870 int keys_num;
7871 const NODE *args;
7872 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7873 if (args) {
7874 DECL_ANCHOR(match_values);
7875 INIT_ANCHOR(match_values);
7876 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7877 for (i = 0; i < keys_num; i++) {
7878 NODE *key_node = RNODE_LIST(args)->nd_head;
7879 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7880 VALUE key = get_symbol_value(iseq, key_node);
7881
7882 ADD_INSN(ret, line_node, dup);
7883 ADD_INSN1(ret, line_node, putobject, key);
7884 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7885 if (in_single_pattern) {
7886 LABEL *match_succeeded;
7887 match_succeeded = NEW_LABEL(line);
7888
7889 ADD_INSN(ret, line_node, dup);
7890 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7891
7892 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7893 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7894 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7895 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7896 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7897 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7898 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7899 ADD_INSN1(ret, line_node, putobject, key); // (7)
7900 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7901
7902 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7903
7904 ADD_LABEL(ret, match_succeeded);
7905 }
7906 ADD_INSNL(ret, line_node, branchunless, match_failed);
7907
7908 ADD_INSN(match_values, line_node, dup);
7909 ADD_INSN1(match_values, line_node, putobject, key);
7910 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7911 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7912 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7913 }
7914 ADD_SEQ(ret, match_values);
7915 }
7916 }
7917 else {
7918 ADD_INSN(ret, line_node, dup);
7919 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7920 if (in_single_pattern) {
7921 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7922 }
7923 ADD_INSNL(ret, line_node, branchunless, match_failed);
7924 }
7925
7926 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7927 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7928 ADD_INSN(ret, line_node, dup);
7929 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7930 if (in_single_pattern) {
7931 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7932 }
7933 ADD_INSNL(ret, line_node, branchunless, match_failed);
7934 }
7935 else {
7936 ADD_INSN(ret, line_node, dup); // (11)
7937 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));
7938 }
7939 }
7940
7941 ADD_INSN(ret, line_node, pop);
7942 ADD_INSNL(ret, line_node, jump, matched);
7943 ADD_INSN(ret, line_node, putnil);
7944
7945 ADD_LABEL(ret, type_error);
7946 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7947 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7948 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7949 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7950 ADD_INSN(ret, line_node, pop);
7951
7952 ADD_LABEL(ret, match_failed);
7953 ADD_INSN(ret, line_node, pop);
7954 ADD_INSNL(ret, line_node, jump, unmatched);
7955 break;
7956 }
7957 case NODE_SYM:
7958 case NODE_REGX:
7959 case NODE_LINE:
7960 case NODE_INTEGER:
7961 case NODE_FLOAT:
7962 case NODE_RATIONAL:
7963 case NODE_IMAGINARY:
7964 case NODE_FILE:
7965 case NODE_ENCODING:
7966 case NODE_STR:
7967 case NODE_XSTR:
7968 case NODE_DSTR:
7969 case NODE_DSYM:
7970 case NODE_DREGX:
7971 case NODE_LIST:
7972 case NODE_ZLIST:
7973 case NODE_LAMBDA:
7974 case NODE_DOT2:
7975 case NODE_DOT3:
7976 case NODE_CONST:
7977 case NODE_LVAR:
7978 case NODE_DVAR:
7979 case NODE_IVAR:
7980 case NODE_CVAR:
7981 case NODE_GVAR:
7982 case NODE_TRUE:
7983 case NODE_FALSE:
7984 case NODE_SELF:
7985 case NODE_NIL:
7986 case NODE_COLON2:
7987 case NODE_COLON3:
7988 case NODE_BEGIN:
7989 case NODE_BLOCK:
7990 case NODE_ONCE:
7991 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7992 if (in_single_pattern) {
7993 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7994 }
7995 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7996 if (in_single_pattern) {
7997 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7998 }
7999 ADD_INSNL(ret, line_node, branchif, matched);
8000 ADD_INSNL(ret, line_node, jump, unmatched);
8001 break;
8002 case NODE_LASGN: {
8003 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8004 ID id = RNODE_LASGN(node)->nd_vid;
8005 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8006
8007 if (in_alt_pattern) {
8008 const char *name = rb_id2name(id);
8009 if (name && strlen(name) > 0 && name[0] != '_') {
8010 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8011 rb_id2str(id));
8012 return COMPILE_NG;
8013 }
8014 }
8015
8016 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8017 ADD_INSNL(ret, line_node, jump, matched);
8018 break;
8019 }
8020 case NODE_DASGN: {
8021 int idx, lv, ls;
8022 ID id = RNODE_DASGN(node)->nd_vid;
8023
8024 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
8025
8026 if (in_alt_pattern) {
8027 const char *name = rb_id2name(id);
8028 if (name && strlen(name) > 0 && name[0] != '_') {
8029 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8030 rb_id2str(id));
8031 return COMPILE_NG;
8032 }
8033 }
8034
8035 if (idx < 0) {
8036 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
8037 rb_id2str(id));
8038 return COMPILE_NG;
8039 }
8040 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
8041 ADD_INSNL(ret, line_node, jump, matched);
8042 break;
8043 }
8044 case NODE_IF:
8045 case NODE_UNLESS: {
8046 LABEL *match_failed;
8047 match_failed = unmatched;
8048 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8049 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
8050 if (in_single_pattern) {
8051 LABEL *match_succeeded;
8052 match_succeeded = NEW_LABEL(line);
8053
8054 ADD_INSN(ret, line_node, dup);
8055 if (nd_type_p(node, NODE_IF)) {
8056 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8057 }
8058 else {
8059 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
8060 }
8061
8062 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
8063 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8064 ADD_INSN1(ret, line_node, putobject, Qfalse);
8065 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8066
8067 ADD_INSN(ret, line_node, pop);
8068 ADD_INSN(ret, line_node, pop);
8069
8070 ADD_LABEL(ret, match_succeeded);
8071 }
8072 if (nd_type_p(node, NODE_IF)) {
8073 ADD_INSNL(ret, line_node, branchunless, match_failed);
8074 }
8075 else {
8076 ADD_INSNL(ret, line_node, branchif, match_failed);
8077 }
8078 ADD_INSNL(ret, line_node, jump, matched);
8079 break;
8080 }
8081 case NODE_HASH: {
8082 NODE *n;
8083 LABEL *match_failed;
8084 match_failed = NEW_LABEL(line);
8085
8086 n = RNODE_HASH(node)->nd_head;
8087 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
8088 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8089 return COMPILE_NG;
8090 }
8091
8092 ADD_INSN(ret, line_node, dup); // (1)
8093 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));
8094 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));
8095 ADD_INSN(ret, line_node, putnil);
8096
8097 ADD_LABEL(ret, match_failed);
8098 ADD_INSN(ret, line_node, pop);
8099 ADD_INSNL(ret, line_node, jump, unmatched);
8100 break;
8101 }
8102 case NODE_OR: {
8103 LABEL *match_succeeded, *fin;
8104 match_succeeded = NEW_LABEL(line);
8105 fin = NEW_LABEL(line);
8106
8107 ADD_INSN(ret, line_node, dup); // (1)
8108 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));
8109 ADD_LABEL(ret, match_succeeded);
8110 ADD_INSN(ret, line_node, pop);
8111 ADD_INSNL(ret, line_node, jump, matched);
8112 ADD_INSN(ret, line_node, putnil);
8113 ADD_LABEL(ret, fin);
8114 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
8115 break;
8116 }
8117 default:
8118 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
8119 }
8120 return COMPILE_OK;
8121}
8122
8123static int
8124iseq_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)
8125{
8126 LABEL *fin = NEW_LABEL(nd_line(node));
8127 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8128 ADD_LABEL(ret, fin);
8129 return COMPILE_OK;
8130}
8131
8132static int
8133iseq_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)
8134{
8135 const NODE *line_node = node;
8136
8137 if (RNODE_ARYPTN(node)->nd_pconst) {
8138 ADD_INSN(ret, line_node, dup); // (1)
8139 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8140 if (in_single_pattern) {
8141 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8142 }
8143 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8144 if (in_single_pattern) {
8145 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8146 }
8147 ADD_INSNL(ret, line_node, branchunless, match_failed);
8148 }
8149 return COMPILE_OK;
8150}
8151
8152
8153static int
8154iseq_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)
8155{
8156 const NODE *line_node = node;
8157
8158 // NOTE: this optimization allows us to re-use the #deconstruct value
8159 // (or its absence).
8160 if (use_deconstructed_cache) {
8161 // If value is nil then we haven't tried to deconstruct
8162 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8163 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8164
8165 // If false then the value is not deconstructable
8166 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8167 ADD_INSNL(ret, line_node, branchunless, match_failed);
8168
8169 // Drop value, add deconstructed to the stack and jump
8170 ADD_INSN(ret, line_node, pop); // (1)
8171 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8172 ADD_INSNL(ret, line_node, jump, deconstructed);
8173 }
8174 else {
8175 ADD_INSNL(ret, line_node, jump, deconstruct);
8176 }
8177
8178 ADD_LABEL(ret, deconstruct);
8179 ADD_INSN(ret, line_node, dup);
8180 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8181 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8182
8183 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8184 if (use_deconstructed_cache) {
8185 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8186 }
8187
8188 if (in_single_pattern) {
8189 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8190 }
8191
8192 ADD_INSNL(ret, line_node, branchunless, match_failed);
8193
8194 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8195
8196 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8197 if (use_deconstructed_cache) {
8198 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8199 }
8200
8201 ADD_INSN(ret, line_node, dup);
8202 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8203 ADD_INSNL(ret, line_node, branchunless, type_error);
8204
8205 ADD_LABEL(ret, deconstructed);
8206
8207 return COMPILE_OK;
8208}
8209
8210static int
8211iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8212{
8213 /*
8214 * if match_succeeded?
8215 * goto match_succeeded
8216 * end
8217 * error_string = FrozenCore.sprintf(errmsg, matchee)
8218 * key_error_p = false
8219 * match_succeeded:
8220 */
8221 const int line = nd_line(node);
8222 const NODE *line_node = node;
8223 LABEL *match_succeeded = NEW_LABEL(line);
8224
8225 ADD_INSN(ret, line_node, dup);
8226 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8227
8228 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8229 ADD_INSN1(ret, line_node, putobject, errmsg);
8230 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8231 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8232 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8233
8234 ADD_INSN1(ret, line_node, putobject, Qfalse);
8235 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8236
8237 ADD_INSN(ret, line_node, pop);
8238 ADD_INSN(ret, line_node, pop);
8239 ADD_LABEL(ret, match_succeeded);
8240
8241 return COMPILE_OK;
8242}
8243
8244static int
8245iseq_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)
8246{
8247 /*
8248 * if match_succeeded?
8249 * goto match_succeeded
8250 * end
8251 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8252 * key_error_p = false
8253 * match_succeeded:
8254 */
8255 const int line = nd_line(node);
8256 const NODE *line_node = node;
8257 LABEL *match_succeeded = NEW_LABEL(line);
8258
8259 ADD_INSN(ret, line_node, dup);
8260 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8261
8262 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8263 ADD_INSN1(ret, line_node, putobject, errmsg);
8264 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8265 ADD_INSN(ret, line_node, dup);
8266 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8267 ADD_INSN1(ret, line_node, putobject, pattern_length);
8268 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8269 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8270
8271 ADD_INSN1(ret, line_node, putobject, Qfalse);
8272 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8273
8274 ADD_INSN(ret, line_node, pop);
8275 ADD_INSN(ret, line_node, pop);
8276 ADD_LABEL(ret, match_succeeded);
8277
8278 return COMPILE_OK;
8279}
8280
8281static int
8282iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8283{
8284 /*
8285 * if match_succeeded?
8286 * goto match_succeeded
8287 * end
8288 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8289 * key_error_p = false
8290 * match_succeeded:
8291 */
8292 const int line = nd_line(node);
8293 const NODE *line_node = node;
8294 LABEL *match_succeeded = NEW_LABEL(line);
8295
8296 ADD_INSN(ret, line_node, dup);
8297 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8298
8299 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8300 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8301 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8302 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8303 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8304 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8305
8306 ADD_INSN1(ret, line_node, putobject, Qfalse);
8307 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8308
8309 ADD_INSN(ret, line_node, pop);
8310 ADD_INSN(ret, line_node, pop);
8311
8312 ADD_LABEL(ret, match_succeeded);
8313 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8314 ADD_INSN(ret, line_node, pop);
8315 ADD_INSN(ret, line_node, pop);
8316
8317 return COMPILE_OK;
8318}
8319
8320static int
8321compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8322{
8323 const NODE *pattern;
8324 const NODE *node = orig_node;
8325 LABEL *endlabel, *elselabel;
8326 DECL_ANCHOR(head);
8327 DECL_ANCHOR(body_seq);
8328 DECL_ANCHOR(cond_seq);
8329 int line;
8330 enum node_type type;
8331 const NODE *line_node;
8332 VALUE branches = 0;
8333 int branch_id = 0;
8334 bool single_pattern;
8335
8336 INIT_ANCHOR(head);
8337 INIT_ANCHOR(body_seq);
8338 INIT_ANCHOR(cond_seq);
8339
8340 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
8341
8342 node = RNODE_CASE3(node)->nd_body;
8343 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8344 type = nd_type(node);
8345 line = nd_line(node);
8346 line_node = node;
8347 single_pattern = !RNODE_IN(node)->nd_next;
8348
8349 endlabel = NEW_LABEL(line);
8350 elselabel = NEW_LABEL(line);
8351
8352 if (single_pattern) {
8353 /* allocate stack for ... */
8354 ADD_INSN(head, line_node, putnil); /* key_error_key */
8355 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8356 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8357 ADD_INSN(head, line_node, putnil); /* error_string */
8358 }
8359 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8360
8361 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8362
8363 ADD_SEQ(ret, head); /* case VAL */
8364
8365 while (type == NODE_IN) {
8366 LABEL *l1;
8367
8368 if (branch_id) {
8369 ADD_INSN(body_seq, line_node, putnil);
8370 }
8371 l1 = NEW_LABEL(line);
8372 ADD_LABEL(body_seq, l1);
8373 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8374
8375 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8376 add_trace_branch_coverage(
8377 iseq,
8378 body_seq,
8379 nd_code_loc(coverage_node),
8380 nd_node_id(coverage_node),
8381 branch_id++,
8382 "in",
8383 branches);
8384
8385 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8386 ADD_INSNL(body_seq, line_node, jump, endlabel);
8387
8388 pattern = RNODE_IN(node)->nd_head;
8389 if (pattern) {
8390 int pat_line = nd_line(pattern);
8391 LABEL *next_pat = NEW_LABEL(pat_line);
8392 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8393 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8394 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8395 ADD_LABEL(cond_seq, next_pat);
8396 LABEL_UNREMOVABLE(next_pat);
8397 }
8398 else {
8399 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8400 return COMPILE_NG;
8401 }
8402
8403 node = RNODE_IN(node)->nd_next;
8404 if (!node) {
8405 break;
8406 }
8407 type = nd_type(node);
8408 line = nd_line(node);
8409 line_node = node;
8410 }
8411 /* else */
8412 if (node) {
8413 ADD_LABEL(cond_seq, elselabel);
8414 ADD_INSN(cond_seq, line_node, pop);
8415 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8416 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8417 CHECK(COMPILE_(cond_seq, "else", node, popped));
8418 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8419 ADD_INSN(cond_seq, line_node, putnil);
8420 if (popped) {
8421 ADD_INSN(cond_seq, line_node, putnil);
8422 }
8423 }
8424 else {
8425 debugs("== else (implicit)\n");
8426 ADD_LABEL(cond_seq, elselabel);
8427 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8428 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8429
8430 if (single_pattern) {
8431 /*
8432 * if key_error_p
8433 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8434 * else
8435 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8436 * end
8437 */
8438 LABEL *key_error, *fin;
8439 struct rb_callinfo_kwarg *kw_arg;
8440
8441 key_error = NEW_LABEL(line);
8442 fin = NEW_LABEL(line);
8443
8444 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8445 kw_arg->references = 0;
8446 kw_arg->keyword_len = 2;
8447 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8448 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8449
8450 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8451 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8452 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8453 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8454 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8455 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8456 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8457 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8458 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8459 ADD_INSNL(cond_seq, orig_node, jump, fin);
8460
8461 ADD_LABEL(cond_seq, key_error);
8462 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8463 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8464 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8465 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8466 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8467 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8468 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8469 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8470 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8471 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8472
8473 ADD_LABEL(cond_seq, fin);
8474 }
8475 else {
8476 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8477 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8478 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8479 }
8480 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8481 if (!popped) {
8482 ADD_INSN(cond_seq, orig_node, putnil);
8483 }
8484 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8485 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8486 if (popped) {
8487 ADD_INSN(cond_seq, line_node, putnil);
8488 }
8489 }
8490
8491 ADD_SEQ(ret, cond_seq);
8492 ADD_SEQ(ret, body_seq);
8493 ADD_LABEL(ret, endlabel);
8494 return COMPILE_OK;
8495}
8496
8497#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8498#undef CASE3_BI_OFFSET_ERROR_STRING
8499#undef CASE3_BI_OFFSET_KEY_ERROR_P
8500#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8501#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8502
8503static int
8504compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8505{
8506 const int line = (int)nd_line(node);
8507 const NODE *line_node = node;
8508
8509 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8510 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8511 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8512 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8513 VALUE branches = Qfalse;
8514
8516
8517 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8518 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8519 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8520 LABEL *end_label = NEW_LABEL(line);
8521 LABEL *adjust_label = NEW_LABEL(line);
8522
8523 LABEL *next_catch_label = NEW_LABEL(line);
8524 LABEL *tmp_label = NULL;
8525
8526 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8527 push_ensure_entry(iseq, &enl, NULL, NULL);
8528
8529 if (RNODE_WHILE(node)->nd_state == 1) {
8530 ADD_INSNL(ret, line_node, jump, next_label);
8531 }
8532 else {
8533 tmp_label = NEW_LABEL(line);
8534 ADD_INSNL(ret, line_node, jump, tmp_label);
8535 }
8536 ADD_LABEL(ret, adjust_label);
8537 ADD_INSN(ret, line_node, putnil);
8538 ADD_LABEL(ret, next_catch_label);
8539 ADD_INSN(ret, line_node, pop);
8540 ADD_INSNL(ret, line_node, jump, next_label);
8541 if (tmp_label) ADD_LABEL(ret, tmp_label);
8542
8543 ADD_LABEL(ret, redo_label);
8544 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8545
8546 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8547 add_trace_branch_coverage(
8548 iseq,
8549 ret,
8550 nd_code_loc(coverage_node),
8551 nd_node_id(coverage_node),
8552 0,
8553 "body",
8554 branches);
8555
8556 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8557 ADD_LABEL(ret, next_label); /* next */
8558
8559 if (type == NODE_WHILE) {
8560 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8561 redo_label, end_label));
8562 }
8563 else {
8564 /* until */
8565 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8566 end_label, redo_label));
8567 }
8568
8569 ADD_LABEL(ret, end_label);
8570 ADD_ADJUST_RESTORE(ret, adjust_label);
8571
8572 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8573 /* ADD_INSN(ret, line_node, putundef); */
8574 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8575 return COMPILE_NG;
8576 }
8577 else {
8578 ADD_INSN(ret, line_node, putnil);
8579 }
8580
8581 ADD_LABEL(ret, break_label); /* break */
8582
8583 if (popped) {
8584 ADD_INSN(ret, line_node, pop);
8585 }
8586
8587 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8588 break_label);
8589 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8590 next_catch_label);
8591 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8592 ISEQ_COMPILE_DATA(iseq)->redo_label);
8593
8594 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8595 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8596 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8597 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8598 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8599 return COMPILE_OK;
8600}
8601
8602static int
8603compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8604{
8605 const int line = nd_line(node);
8606 const NODE *line_node = node;
8607 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8608 LABEL *retry_label = NEW_LABEL(line);
8609 LABEL *retry_end_l = NEW_LABEL(line);
8610 const rb_iseq_t *child_iseq;
8611
8612 ADD_LABEL(ret, retry_label);
8613 if (nd_type_p(node, NODE_FOR)) {
8614 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8615
8616 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8617 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8618 ISEQ_TYPE_BLOCK, line);
8619 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8620 }
8621 else {
8622 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8623 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8624 ISEQ_TYPE_BLOCK, line);
8625 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8626 }
8627
8628 {
8629 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8630 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8631 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8632 //
8633 // Normally, "send" instruction is at the last.
8634 // However, qcall under branch coverage measurement adds some instructions after the "send".
8635 //
8636 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8637 INSN *iobj;
8638 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8639 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8640 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8641 iobj = (INSN*) get_prev_insn(iobj);
8642 }
8643 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8644
8645 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8646 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8647 if (&iobj->link == LAST_ELEMENT(ret)) {
8648 ret->last = (LINK_ELEMENT*) retry_end_l;
8649 }
8650 }
8651
8652 if (popped) {
8653 ADD_INSN(ret, line_node, pop);
8654 }
8655
8656 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8657
8658 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8659 return COMPILE_OK;
8660}
8661
8662static int
8663compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8664{
8665 /* massign to var in "for"
8666 * (args.length == 1 && Array.try_convert(args[0])) || args
8667 */
8668 const NODE *line_node = node;
8669 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8670 LABEL *not_single = NEW_LABEL(nd_line(var));
8671 LABEL *not_ary = NEW_LABEL(nd_line(var));
8672 CHECK(COMPILE(ret, "for var", var));
8673 ADD_INSN(ret, line_node, dup);
8674 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8675 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8676 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8677 ADD_INSNL(ret, line_node, branchunless, not_single);
8678 ADD_INSN(ret, line_node, dup);
8679 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8680 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8681 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8682 ADD_INSN(ret, line_node, swap);
8683 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8684 ADD_INSN(ret, line_node, dup);
8685 ADD_INSNL(ret, line_node, branchunless, not_ary);
8686 ADD_INSN(ret, line_node, swap);
8687 ADD_LABEL(ret, not_ary);
8688 ADD_INSN(ret, line_node, pop);
8689 ADD_LABEL(ret, not_single);
8690 return COMPILE_OK;
8691}
8692
8693static int
8694compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8695{
8696 const NODE *line_node = node;
8697 unsigned long throw_flag = 0;
8698
8699 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8700 /* while/until */
8701 LABEL *splabel = NEW_LABEL(0);
8702 ADD_LABEL(ret, splabel);
8703 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8704 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8705 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8706 add_ensure_iseq(ret, iseq, 0);
8707 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8708 ADD_ADJUST_RESTORE(ret, splabel);
8709
8710 if (!popped) {
8711 ADD_INSN(ret, line_node, putnil);
8712 }
8713 }
8714 else {
8715 const rb_iseq_t *ip = iseq;
8716
8717 while (ip) {
8718 if (!ISEQ_COMPILE_DATA(ip)) {
8719 ip = 0;
8720 break;
8721 }
8722
8723 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8724 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8725 }
8726 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8727 throw_flag = 0;
8728 }
8729 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8730 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8731 return COMPILE_NG;
8732 }
8733 else {
8734 ip = ISEQ_BODY(ip)->parent_iseq;
8735 continue;
8736 }
8737
8738 /* escape from block */
8739 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8740 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8741 if (popped) {
8742 ADD_INSN(ret, line_node, pop);
8743 }
8744 return COMPILE_OK;
8745 }
8746 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8747 return COMPILE_NG;
8748 }
8749 return COMPILE_OK;
8750}
8751
8752static int
8753compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8754{
8755 const NODE *line_node = node;
8756 unsigned long throw_flag = 0;
8757
8758 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8759 LABEL *splabel = NEW_LABEL(0);
8760 debugs("next in while loop\n");
8761 ADD_LABEL(ret, splabel);
8762 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8763 add_ensure_iseq(ret, iseq, 0);
8764 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8765 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8766 ADD_ADJUST_RESTORE(ret, splabel);
8767 if (!popped) {
8768 ADD_INSN(ret, line_node, putnil);
8769 }
8770 }
8771 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8772 LABEL *splabel = NEW_LABEL(0);
8773 debugs("next in block\n");
8774 ADD_LABEL(ret, splabel);
8775 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8776 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8777 add_ensure_iseq(ret, iseq, 0);
8778 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8779 ADD_ADJUST_RESTORE(ret, splabel);
8780
8781 if (!popped) {
8782 ADD_INSN(ret, line_node, putnil);
8783 }
8784 }
8785 else {
8786 const rb_iseq_t *ip = iseq;
8787
8788 while (ip) {
8789 if (!ISEQ_COMPILE_DATA(ip)) {
8790 ip = 0;
8791 break;
8792 }
8793
8794 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8795 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8796 /* while loop */
8797 break;
8798 }
8799 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8800 break;
8801 }
8802 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8803 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8804 return COMPILE_NG;
8805 }
8806
8807 ip = ISEQ_BODY(ip)->parent_iseq;
8808 }
8809 if (ip != 0) {
8810 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8811 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8812
8813 if (popped) {
8814 ADD_INSN(ret, line_node, pop);
8815 }
8816 }
8817 else {
8818 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8819 return COMPILE_NG;
8820 }
8821 }
8822 return COMPILE_OK;
8823}
8824
8825static int
8826compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8827{
8828 const NODE *line_node = node;
8829
8830 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8831 LABEL *splabel = NEW_LABEL(0);
8832 debugs("redo in while");
8833 ADD_LABEL(ret, splabel);
8834 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8835 add_ensure_iseq(ret, iseq, 0);
8836 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8837 ADD_ADJUST_RESTORE(ret, splabel);
8838 if (!popped) {
8839 ADD_INSN(ret, line_node, putnil);
8840 }
8841 }
8842 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8843 LABEL *splabel = NEW_LABEL(0);
8844
8845 debugs("redo in block");
8846 ADD_LABEL(ret, splabel);
8847 add_ensure_iseq(ret, iseq, 0);
8848 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8849 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8850 ADD_ADJUST_RESTORE(ret, splabel);
8851
8852 if (!popped) {
8853 ADD_INSN(ret, line_node, putnil);
8854 }
8855 }
8856 else {
8857 const rb_iseq_t *ip = iseq;
8858
8859 while (ip) {
8860 if (!ISEQ_COMPILE_DATA(ip)) {
8861 ip = 0;
8862 break;
8863 }
8864
8865 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8866 break;
8867 }
8868 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8869 break;
8870 }
8871 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8872 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8873 return COMPILE_NG;
8874 }
8875
8876 ip = ISEQ_BODY(ip)->parent_iseq;
8877 }
8878 if (ip != 0) {
8879 ADD_INSN(ret, line_node, putnil);
8880 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8881
8882 if (popped) {
8883 ADD_INSN(ret, line_node, pop);
8884 }
8885 }
8886 else {
8887 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8888 return COMPILE_NG;
8889 }
8890 }
8891 return COMPILE_OK;
8892}
8893
8894static int
8895compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8896{
8897 const NODE *line_node = node;
8898
8899 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8900 ADD_INSN(ret, line_node, putnil);
8901 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8902
8903 if (popped) {
8904 ADD_INSN(ret, line_node, pop);
8905 }
8906 }
8907 else {
8908 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8909 return COMPILE_NG;
8910 }
8911 return COMPILE_OK;
8912}
8913
8914static int
8915compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8916{
8917 const int line = nd_line(node);
8918 const NODE *line_node = node;
8919 LABEL *lstart = NEW_LABEL(line);
8920 LABEL *lend = NEW_LABEL(line);
8921 LABEL *lcont = NEW_LABEL(line);
8922 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8923 rb_str_concat(rb_str_new2("rescue in "),
8924 ISEQ_BODY(iseq)->location.label),
8925 ISEQ_TYPE_RESCUE, line);
8926
8927 lstart->rescued = LABEL_RESCUE_BEG;
8928 lend->rescued = LABEL_RESCUE_END;
8929 ADD_LABEL(ret, lstart);
8930
8931 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8932 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8933 {
8934 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8935 }
8936 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8937
8938 ADD_LABEL(ret, lend);
8939 if (RNODE_RESCUE(node)->nd_else) {
8940 ADD_INSN(ret, line_node, pop);
8941 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8942 }
8943 ADD_INSN(ret, line_node, nop);
8944 ADD_LABEL(ret, lcont);
8945
8946 if (popped) {
8947 ADD_INSN(ret, line_node, pop);
8948 }
8949
8950 /* register catch entry */
8951 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8952 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8953 return COMPILE_OK;
8954}
8955
8956static int
8957compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8958{
8959 const int line = nd_line(node);
8960 const NODE *line_node = node;
8961 const NODE *resq = node;
8962 const NODE *narg;
8963 LABEL *label_miss, *label_hit;
8964
8965 while (resq) {
8966 label_miss = NEW_LABEL(line);
8967 label_hit = NEW_LABEL(line);
8968
8969 narg = RNODE_RESBODY(resq)->nd_args;
8970 if (narg) {
8971 switch (nd_type(narg)) {
8972 case NODE_LIST:
8973 while (narg) {
8974 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8975 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8976 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8977 ADD_INSNL(ret, line_node, branchif, label_hit);
8978 narg = RNODE_LIST(narg)->nd_next;
8979 }
8980 break;
8981 case NODE_SPLAT:
8982 case NODE_ARGSCAT:
8983 case NODE_ARGSPUSH:
8984 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8985 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8986 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8987 ADD_INSNL(ret, line_node, branchif, label_hit);
8988 break;
8989 default:
8990 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8991 }
8992 }
8993 else {
8994 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8995 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8996 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8997 ADD_INSNL(ret, line_node, branchif, label_hit);
8998 }
8999 ADD_INSNL(ret, line_node, jump, label_miss);
9000 ADD_LABEL(ret, label_hit);
9001 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
9002
9003 if (RNODE_RESBODY(resq)->nd_exc_var) {
9004 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
9005 }
9006
9007 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) {
9008 // empty body
9009 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
9010 }
9011 else {
9012 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
9013 }
9014
9015 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
9016 ADD_INSN(ret, line_node, nop);
9017 }
9018 ADD_INSN(ret, line_node, leave);
9019 ADD_LABEL(ret, label_miss);
9020 resq = RNODE_RESBODY(resq)->nd_next;
9021 }
9022 return COMPILE_OK;
9023}
9024
9025static int
9026compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9027{
9028 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
9029 const NODE *line_node = node;
9030 DECL_ANCHOR(ensr);
9031 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
9032 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
9033 ISEQ_TYPE_ENSURE, line);
9034 LABEL *lstart = NEW_LABEL(line);
9035 LABEL *lend = NEW_LABEL(line);
9036 LABEL *lcont = NEW_LABEL(line);
9037 LINK_ELEMENT *last;
9038 int last_leave = 0;
9039 struct ensure_range er;
9041 struct ensure_range *erange;
9042
9043 INIT_ANCHOR(ensr);
9044 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
9045 last = ensr->last;
9046 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
9047
9048 er.begin = lstart;
9049 er.end = lend;
9050 er.next = 0;
9051 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
9052
9053 ADD_LABEL(ret, lstart);
9054 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
9055 ADD_LABEL(ret, lend);
9056 ADD_SEQ(ret, ensr);
9057 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
9058 ADD_LABEL(ret, lcont);
9059 if (last_leave) ADD_INSN(ret, line_node, pop);
9060
9061 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
9062 if (lstart->link.next != &lend->link) {
9063 while (erange) {
9064 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
9065 ensure, lcont);
9066 erange = erange->next;
9067 }
9068 }
9069
9070 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
9071 return COMPILE_OK;
9072}
9073
9074static int
9075compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9076{
9077 const NODE *line_node = node;
9078
9079 if (iseq) {
9080 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
9081 const rb_iseq_t *is = iseq;
9082 enum rb_iseq_type t = type;
9083 const NODE *retval = RNODE_RETURN(node)->nd_stts;
9084 LABEL *splabel = 0;
9085
9086 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
9087 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
9088 t = ISEQ_BODY(is)->type;
9089 }
9090 switch (t) {
9091 case ISEQ_TYPE_TOP:
9092 case ISEQ_TYPE_MAIN:
9093 if (retval) {
9094 rb_warn("argument of top-level return is ignored");
9095 }
9096 if (is == iseq) {
9097 /* plain top-level, leave directly */
9098 type = ISEQ_TYPE_METHOD;
9099 }
9100 break;
9101 default:
9102 break;
9103 }
9104
9105 if (type == ISEQ_TYPE_METHOD) {
9106 splabel = NEW_LABEL(0);
9107 ADD_LABEL(ret, splabel);
9108 ADD_ADJUST(ret, line_node, 0);
9109 }
9110
9111 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
9112
9113 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
9114 add_ensure_iseq(ret, iseq, 1);
9115 ADD_TRACE(ret, RUBY_EVENT_RETURN);
9116 ADD_INSN(ret, line_node, leave);
9117 ADD_ADJUST_RESTORE(ret, splabel);
9118
9119 if (!popped) {
9120 ADD_INSN(ret, line_node, putnil);
9121 }
9122 }
9123 else {
9124 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
9125 if (popped) {
9126 ADD_INSN(ret, line_node, pop);
9127 }
9128 }
9129 }
9130 return COMPILE_OK;
9131}
9132
9133static bool
9134drop_unreachable_return(LINK_ANCHOR *ret)
9135{
9136 LINK_ELEMENT *i = ret->last, *last;
9137 if (!i) return false;
9138 if (IS_TRACE(i)) i = i->prev;
9139 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9140 last = i = i->prev;
9141 if (IS_ADJUST(i)) i = i->prev;
9142 if (!IS_INSN(i)) return false;
9143 switch (INSN_OF(i)) {
9144 case BIN(leave):
9145 case BIN(jump):
9146 break;
9147 default:
9148 return false;
9149 }
9150 (ret->last = last->prev)->next = NULL;
9151 return true;
9152}
9153
9154static int
9155compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9156{
9157 CHECK(COMPILE_(ret, "nd_body", node, popped));
9158
9159 if (!popped && !all_string_result_p(node)) {
9160 const NODE *line_node = node;
9161 const unsigned int flag = VM_CALL_FCALL;
9162
9163 // Note, this dup could be removed if we are willing to change anytostring. It pops
9164 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9165 ADD_INSN(ret, line_node, dup);
9166 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9167 ADD_INSN(ret, line_node, anytostring);
9168 }
9169 return COMPILE_OK;
9170}
9171
9172static void
9173compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9174{
9175 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9176
9177 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9178 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9179}
9180
9181static LABEL *
9182qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9183{
9184 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9185 VALUE br = 0;
9186
9187 br = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "&.");
9188 *branches = br;
9189 ADD_INSN(recv, line_node, dup);
9190 ADD_INSNL(recv, line_node, branchnil, else_label);
9191 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9192 return else_label;
9193}
9194
9195static void
9196qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9197{
9198 LABEL *end_label;
9199 if (!else_label) return;
9200 end_label = NEW_LABEL(nd_line(line_node));
9201 ADD_INSNL(ret, line_node, jump, end_label);
9202 ADD_LABEL(ret, else_label);
9203 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9204 ADD_LABEL(ret, end_label);
9205}
9206
9207static int
9208compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9209{
9210 /* optimization shortcut
9211 * "literal".freeze -> opt_str_freeze("literal")
9212 */
9213 if (get_nd_recv(node) &&
9214 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9215 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9216 get_nd_args(node) == NULL &&
9217 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9218 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9219 VALUE str = get_string_value(get_nd_recv(node));
9220 if (get_node_call_nd_mid(node) == idUMinus) {
9221 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9222 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9223 }
9224 else {
9225 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9226 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9227 }
9228 RB_OBJ_WRITTEN(iseq, Qundef, str);
9229 if (popped) {
9230 ADD_INSN(ret, line_node, pop);
9231 }
9232 return TRUE;
9233 }
9234 return FALSE;
9235}
9236
9237static int
9238iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9239{
9240 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9241}
9242
9243static const struct rb_builtin_function *
9244iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9245{
9246 int i;
9247 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9248 for (i=0; table[i].index != -1; i++) {
9249 if (strcmp(table[i].name, name) == 0) {
9250 return &table[i];
9251 }
9252 }
9253 return NULL;
9254}
9255
9256static const char *
9257iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9258{
9259 const char *name = rb_id2name(mid);
9260 static const char prefix[] = "__builtin_";
9261 const size_t prefix_len = sizeof(prefix) - 1;
9262
9263 switch (type) {
9264 case NODE_CALL:
9265 if (recv) {
9266 switch (nd_type(recv)) {
9267 case NODE_VCALL:
9268 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9269 return name;
9270 }
9271 break;
9272 case NODE_CONST:
9273 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9274 return name;
9275 }
9276 break;
9277 default: break;
9278 }
9279 }
9280 break;
9281 case NODE_VCALL:
9282 case NODE_FCALL:
9283 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9284 return &name[prefix_len];
9285 }
9286 break;
9287 default: break;
9288 }
9289 return NULL;
9290}
9291
9292static int
9293delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9294{
9295
9296 if (argc == 0) {
9297 *pstart_index = 0;
9298 return TRUE;
9299 }
9300 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9301 unsigned int start=0;
9302
9303 // local_table: [p1, p2, p3, l1, l2, l3]
9304 // arguments: [p3, l1, l2] -> 2
9305 for (start = 0;
9306 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9307 start++) {
9308 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9309
9310 for (unsigned int i=start; i-start<argc; i++) {
9311 if (IS_INSN(elem) &&
9312 INSN_OF(elem) == BIN(getlocal)) {
9313 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9314 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9315
9316 if (local_level == 0) {
9317 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9318 if (0) { // for debug
9319 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9320 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9321 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9322 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9323 }
9324 if (i == index) {
9325 elem = elem->next;
9326 continue; /* for */
9327 }
9328 else {
9329 goto next;
9330 }
9331 }
9332 else {
9333 goto fail; // level != 0 is unsupported
9334 }
9335 }
9336 else {
9337 goto fail; // insn is not a getlocal
9338 }
9339 }
9340 goto success;
9341 next:;
9342 }
9343 fail:
9344 return FALSE;
9345 success:
9346 *pstart_index = start;
9347 return TRUE;
9348 }
9349 else {
9350 return FALSE;
9351 }
9352}
9353
9354static int
9355compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
9356{
9357 VALUE string = rb_sym2str(symbol);
9358 if (rb_streql_lit(string, "leaf")) {
9359 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9360 }
9361 else if (rb_streql_lit(string, "inline_block")) {
9362 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9363 }
9364 else if (rb_streql_lit(string, "use_block")) {
9365 iseq_set_use_block(iseq);
9366 }
9367 else if (rb_streql_lit(string, "c_trace")) {
9368 // Let the iseq act like a C method in backtraces
9369 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9370 }
9371 else if (rb_streql_lit(string, "without_interrupts")) {
9372 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9373 }
9374 else {
9375 return COMPILE_NG;
9376 }
9377 return COMPILE_OK;
9378}
9379
9380// Compile Primitive.attr! :leaf, ...
9381static int
9382compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9383{
9384 VALUE symbol;
9385 if (!node) goto no_arg;
9386 while (node) {
9387 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9388 const NODE *next = RNODE_LIST(node)->nd_next;
9389
9390 node = RNODE_LIST(node)->nd_head;
9391 if (!node) goto no_arg;
9392 switch (nd_type(node)) {
9393 case NODE_SYM:
9394 symbol = rb_node_sym_string_val(node);
9395 break;
9396 default:
9397 goto bad_arg;
9398 }
9399
9400 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9401 if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
9402 node = next;
9403 }
9404 return COMPILE_OK;
9405 no_arg:
9406 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9407 return COMPILE_NG;
9408 non_symbol_arg:
9409 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9410 return COMPILE_NG;
9411 unknown_arg:
9412 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
9413 return COMPILE_NG;
9414 bad_arg:
9415 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9416}
9417
9418static int
9419compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9420{
9421 VALUE name;
9422
9423 if (!node) goto no_arg;
9424 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9425 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9426 node = RNODE_LIST(node)->nd_head;
9427 if (!node) goto no_arg;
9428 switch (nd_type(node)) {
9429 case NODE_SYM:
9430 name = rb_node_sym_string_val(node);
9431 break;
9432 default:
9433 goto bad_arg;
9434 }
9435 if (!SYMBOL_P(name)) goto non_symbol_arg;
9436 if (!popped) {
9437 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9438 }
9439 return COMPILE_OK;
9440 no_arg:
9441 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9442 return COMPILE_NG;
9443 too_many_arg:
9444 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9445 return COMPILE_NG;
9446 non_symbol_arg:
9447 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9448 rb_builtin_class_name(name));
9449 return COMPILE_NG;
9450 bad_arg:
9451 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9452}
9453
9454static NODE *
9455mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9456{
9457 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9458 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9459 return RNODE_IF(node)->nd_body;
9460 }
9461 else {
9462 rb_bug("mandatory_node: can't find mandatory node");
9463 }
9464}
9465
9466static int
9467compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9468{
9469 // arguments
9470 struct rb_args_info args = {
9471 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9472 };
9473 rb_node_args_t args_node;
9474 rb_node_init(RNODE(&args_node), NODE_ARGS);
9475 args_node.nd_ainfo = args;
9476
9477 // local table without non-mandatory parameters
9478 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9479 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9480
9481 VALUE idtmp = 0;
9482 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9483 tbl->size = table_size;
9484
9485 int i;
9486
9487 // lead parameters
9488 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9489 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9490 }
9491 // local variables
9492 for (; i<table_size; i++) {
9493 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9494 }
9495
9496 rb_node_scope_t scope_node;
9497 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9498 scope_node.nd_tbl = tbl;
9499 scope_node.nd_body = mandatory_node(iseq, node);
9500 scope_node.nd_parent = NULL;
9501 scope_node.nd_args = &args_node;
9502
9503 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9504
9505 const rb_iseq_t *mandatory_only_iseq =
9506 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9507 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9508 nd_line(line_node), NULL, 0,
9509 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9510 ISEQ_SCRIPT_LINES(iseq));
9511 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9512
9513 ALLOCV_END(idtmp);
9514 return COMPILE_OK;
9515}
9516
9517static int
9518compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9519 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9520{
9521 NODE *args_node = get_nd_args(node);
9522
9523 if (parent_block != NULL) {
9524 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9525 return COMPILE_NG;
9526 }
9527 else {
9528# define BUILTIN_INLINE_PREFIX "_bi"
9529 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9530 bool cconst = false;
9531 retry:;
9532 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9533
9534 if (bf == NULL) {
9535 if (strcmp("cstmt!", builtin_func) == 0 ||
9536 strcmp("cexpr!", builtin_func) == 0) {
9537 // ok
9538 }
9539 else if (strcmp("cconst!", builtin_func) == 0) {
9540 cconst = true;
9541 }
9542 else if (strcmp("cinit!", builtin_func) == 0) {
9543 // ignore
9544 return COMPILE_OK;
9545 }
9546 else if (strcmp("attr!", builtin_func) == 0) {
9547 return compile_builtin_attr(iseq, args_node);
9548 }
9549 else if (strcmp("arg!", builtin_func) == 0) {
9550 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9551 }
9552 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9553 if (popped) {
9554 rb_bug("mandatory_only? should be in if condition");
9555 }
9556 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9557 rb_bug("mandatory_only? should be put on top");
9558 }
9559
9560 ADD_INSN1(ret, line_node, putobject, Qfalse);
9561 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9562 }
9563 else if (1) {
9564 rb_bug("can't find builtin function:%s", builtin_func);
9565 }
9566 else {
9567 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9568 return COMPILE_NG;
9569 }
9570
9571 int inline_index = nd_line(node);
9572 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9573 builtin_func = inline_func;
9574 args_node = NULL;
9575 goto retry;
9576 }
9577
9578 if (cconst) {
9579 typedef VALUE(*builtin_func0)(void *, VALUE);
9580 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9581 ADD_INSN1(ret, line_node, putobject, const_val);
9582 return COMPILE_OK;
9583 }
9584
9585 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9586
9587 unsigned int flag = 0;
9588 struct rb_callinfo_kwarg *keywords = NULL;
9589 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9590
9591 if (FIX2INT(argc) != bf->argc) {
9592 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9593 builtin_func, bf->argc, FIX2INT(argc));
9594 return COMPILE_NG;
9595 }
9596
9597 unsigned int start_index;
9598 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9599 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9600 }
9601 else {
9602 ADD_SEQ(ret, args);
9603 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9604 }
9605
9606 if (popped) ADD_INSN(ret, line_node, pop);
9607 return COMPILE_OK;
9608 }
9609}
9610
9611static int
9612compile_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)
9613{
9614 /* call: obj.method(...)
9615 * fcall: func(...)
9616 * vcall: func
9617 */
9618 DECL_ANCHOR(recv);
9619 DECL_ANCHOR(args);
9620 ID mid = get_node_call_nd_mid(node);
9621 VALUE argc;
9622 unsigned int flag = 0;
9623 struct rb_callinfo_kwarg *keywords = NULL;
9624 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9625 LABEL *else_label = NULL;
9626 VALUE branches = Qfalse;
9627
9628 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9629
9630 INIT_ANCHOR(recv);
9631 INIT_ANCHOR(args);
9632
9633#if OPT_SUPPORT_JOKE
9634 if (nd_type_p(node, NODE_VCALL)) {
9635 ID id_bitblt;
9636 ID id_answer;
9637
9638 CONST_ID(id_bitblt, "bitblt");
9639 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9640
9641 if (mid == id_bitblt) {
9642 ADD_INSN(ret, line_node, bitblt);
9643 return COMPILE_OK;
9644 }
9645 else if (mid == id_answer) {
9646 ADD_INSN(ret, line_node, answer);
9647 return COMPILE_OK;
9648 }
9649 }
9650 /* only joke */
9651 {
9652 ID goto_id;
9653 ID label_id;
9654
9655 CONST_ID(goto_id, "__goto__");
9656 CONST_ID(label_id, "__label__");
9657
9658 if (nd_type_p(node, NODE_FCALL) &&
9659 (mid == goto_id || mid == label_id)) {
9660 LABEL *label;
9661 st_data_t data;
9662 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9663 VALUE label_name;
9664
9665 if (!labels_table) {
9666 labels_table = st_init_numtable();
9667 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9668 }
9669 {
9670 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9671 return COMPILE_NG;
9672 }
9673
9674 if (mid == goto_id) {
9675 ADD_INSNL(ret, line_node, jump, label);
9676 }
9677 else {
9678 ADD_LABEL(ret, label);
9679 }
9680 return COMPILE_OK;
9681 }
9682 }
9683#endif
9684
9685 const char *builtin_func;
9686 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9687 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9688 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9689 }
9690
9691 /* receiver */
9692 if (!assume_receiver) {
9693 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9694 int idx, level;
9695
9696 if ((mid == idCall || mid == idAREF || mid == idYield || mid == idEqq) &&
9697 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9698 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9699 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9700 }
9701 else if (private_recv_p(node)) {
9702 ADD_INSN(recv, node, putself);
9703 flag |= VM_CALL_FCALL;
9704 }
9705 else {
9706 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9707 }
9708
9709 if (type == NODE_QCALL) {
9710 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9711 }
9712 }
9713 else if (type == NODE_FCALL || type == NODE_VCALL) {
9714 ADD_CALL_RECEIVER(recv, line_node);
9715 }
9716 }
9717
9718 /* args */
9719 if (type != NODE_VCALL) {
9720 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9721 CHECK(!NIL_P(argc));
9722 }
9723 else {
9724 argc = INT2FIX(0);
9725 }
9726
9727 ADD_SEQ(ret, recv);
9728
9729 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9730 mid == rb_intern("new") &&
9731 parent_block == NULL &&
9732 !(flag & VM_CALL_ARGS_BLOCKARG);
9733
9734 if (inline_new) {
9735 ADD_INSN(ret, node, putnil);
9736 ADD_INSN(ret, node, swap);
9737 }
9738
9739 ADD_SEQ(ret, args);
9740
9741 debugp_param("call args argc", argc);
9742 debugp_param("call method", ID2SYM(mid));
9743
9744 switch ((int)type) {
9745 case NODE_VCALL:
9746 flag |= VM_CALL_VCALL;
9747 /* VCALL is funcall, so fall through */
9748 case NODE_FCALL:
9749 flag |= VM_CALL_FCALL;
9750 }
9751
9752 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9753 ADD_INSN(ret, line_node, splatkw);
9754 }
9755
9756 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9757 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9758
9759 if (inline_new) {
9760 // Jump unless the receiver uses the "basic" implementation of "new"
9761 VALUE ci;
9762 if (flag & VM_CALL_FORWARDING) {
9763 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9764 }
9765 else {
9766 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9767 }
9768 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9769 LABEL_REF(not_basic_new);
9770
9771 // optimized path
9772 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9773 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9774
9775 ADD_LABEL(ret, not_basic_new);
9776 // Fall back to normal send
9777 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9778 ADD_INSN(ret, line_node, swap);
9779
9780 ADD_LABEL(ret, not_basic_new_finish);
9781 ADD_INSN(ret, line_node, pop);
9782 }
9783 else {
9784 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9785 }
9786
9787 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9788 if (popped) {
9789 ADD_INSN(ret, line_node, pop);
9790 }
9791 return COMPILE_OK;
9792}
9793
9794static int
9795compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9796{
9797 const int line = nd_line(node);
9798 VALUE argc;
9799 unsigned int flag = 0;
9800 int asgnflag = 0;
9801 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9802
9803 /*
9804 * a[x] (op)= y
9805 *
9806 * nil # nil
9807 * eval a # nil a
9808 * eval x # nil a x
9809 * dupn 2 # nil a x a x
9810 * send :[] # nil a x a[x]
9811 * eval y # nil a x a[x] y
9812 * send op # nil a x ret
9813 * setn 3 # ret a x ret
9814 * send []= # ret ?
9815 * pop # ret
9816 */
9817
9818 /*
9819 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9820 * NODE_OP_ASGN nd_recv
9821 * nd_args->nd_head
9822 * nd_args->nd_body
9823 * nd_mid
9824 */
9825
9826 if (!popped) {
9827 ADD_INSN(ret, node, putnil);
9828 }
9829 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9830 CHECK(asgnflag != -1);
9831 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9832 case NODE_ZLIST:
9833 argc = INT2FIX(0);
9834 break;
9835 default:
9836 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9837 CHECK(!NIL_P(argc));
9838 }
9839 int dup_argn = FIX2INT(argc) + 1;
9840 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9841 flag |= asgnflag;
9842 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9843
9844 if (id == idOROP || id == idANDOP) {
9845 /* a[x] ||= y or a[x] &&= y
9846
9847 unless/if a[x]
9848 a[x]= y
9849 else
9850 nil
9851 end
9852 */
9853 LABEL *label = NEW_LABEL(line);
9854 LABEL *lfin = NEW_LABEL(line);
9855
9856 ADD_INSN(ret, node, dup);
9857 if (id == idOROP) {
9858 ADD_INSNL(ret, node, branchif, label);
9859 }
9860 else { /* idANDOP */
9861 ADD_INSNL(ret, node, branchunless, label);
9862 }
9863 ADD_INSN(ret, node, pop);
9864
9865 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9866 if (!popped) {
9867 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9868 }
9869 if (flag & VM_CALL_ARGS_SPLAT) {
9870 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9871 ADD_INSN(ret, node, swap);
9872 ADD_INSN1(ret, node, splatarray, Qtrue);
9873 ADD_INSN(ret, node, swap);
9874 flag |= VM_CALL_ARGS_SPLAT_MUT;
9875 }
9876 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9877 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9878 }
9879 else {
9880 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9881 }
9882 ADD_INSN(ret, node, pop);
9883 ADD_INSNL(ret, node, jump, lfin);
9884 ADD_LABEL(ret, label);
9885 if (!popped) {
9886 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9887 }
9888 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9889 ADD_LABEL(ret, lfin);
9890 }
9891 else {
9892 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9893 ADD_SEND(ret, node, id, INT2FIX(1));
9894 if (!popped) {
9895 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9896 }
9897 if (flag & VM_CALL_ARGS_SPLAT) {
9898 if (flag & VM_CALL_KW_SPLAT) {
9899 ADD_INSN1(ret, node, topn, INT2FIX(2));
9900 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9901 ADD_INSN1(ret, node, splatarray, Qtrue);
9902 flag |= VM_CALL_ARGS_SPLAT_MUT;
9903 }
9904 ADD_INSN(ret, node, swap);
9905 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9906 ADD_INSN1(ret, node, setn, INT2FIX(2));
9907 ADD_INSN(ret, node, pop);
9908 }
9909 else {
9910 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9911 ADD_INSN(ret, node, swap);
9912 ADD_INSN1(ret, node, splatarray, Qtrue);
9913 ADD_INSN(ret, node, swap);
9914 flag |= VM_CALL_ARGS_SPLAT_MUT;
9915 }
9916 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9917 }
9918 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9919 }
9920 else {
9921 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9922 }
9923 ADD_INSN(ret, node, pop);
9924 }
9925 return COMPILE_OK;
9926}
9927
9928static int
9929compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9930{
9931 const int line = nd_line(node);
9932 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9933 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9934 int asgnflag;
9935 LABEL *lfin = NEW_LABEL(line);
9936 LABEL *lcfin = NEW_LABEL(line);
9937 LABEL *lskip = 0;
9938 /*
9939 class C; attr_accessor :c; end
9940 r = C.new
9941 r.a &&= v # asgn2
9942
9943 eval r # r
9944 dup # r r
9945 eval r.a # r o
9946
9947 # or
9948 dup # r o o
9949 if lcfin # r o
9950 pop # r
9951 eval v # r v
9952 swap # v r
9953 topn 1 # v r v
9954 send a= # v ?
9955 jump lfin # v ?
9956
9957 lcfin: # r o
9958 swap # o r
9959
9960 lfin: # o ?
9961 pop # o
9962
9963 # or (popped)
9964 if lcfin # r
9965 eval v # r v
9966 send a= # ?
9967 jump lfin # ?
9968
9969 lcfin: # r
9970
9971 lfin: # ?
9972 pop #
9973
9974 # and
9975 dup # r o o
9976 unless lcfin
9977 pop # r
9978 eval v # r v
9979 swap # v r
9980 topn 1 # v r v
9981 send a= # v ?
9982 jump lfin # v ?
9983
9984 # others
9985 eval v # r o v
9986 send ?? # r w
9987 send a= # w
9988
9989 */
9990
9991 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9992 CHECK(asgnflag != -1);
9993 if (RNODE_OP_ASGN2(node)->nd_aid) {
9994 lskip = NEW_LABEL(line);
9995 ADD_INSN(ret, node, dup);
9996 ADD_INSNL(ret, node, branchnil, lskip);
9997 }
9998 ADD_INSN(ret, node, dup);
9999 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
10000
10001 if (atype == idOROP || atype == idANDOP) {
10002 if (!popped) {
10003 ADD_INSN(ret, node, dup);
10004 }
10005 if (atype == idOROP) {
10006 ADD_INSNL(ret, node, branchif, lcfin);
10007 }
10008 else { /* idANDOP */
10009 ADD_INSNL(ret, node, branchunless, lcfin);
10010 }
10011 if (!popped) {
10012 ADD_INSN(ret, node, pop);
10013 }
10014 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10015 if (!popped) {
10016 ADD_INSN(ret, node, swap);
10017 ADD_INSN1(ret, node, topn, INT2FIX(1));
10018 }
10019 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10020 ADD_INSNL(ret, node, jump, lfin);
10021
10022 ADD_LABEL(ret, lcfin);
10023 if (!popped) {
10024 ADD_INSN(ret, node, swap);
10025 }
10026
10027 ADD_LABEL(ret, lfin);
10028 }
10029 else {
10030 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10031 ADD_SEND(ret, node, atype, INT2FIX(1));
10032 if (!popped) {
10033 ADD_INSN(ret, node, swap);
10034 ADD_INSN1(ret, node, topn, INT2FIX(1));
10035 }
10036 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10037 }
10038 if (lskip && popped) {
10039 ADD_LABEL(ret, lskip);
10040 }
10041 ADD_INSN(ret, node, pop);
10042 if (lskip && !popped) {
10043 ADD_LABEL(ret, lskip);
10044 }
10045 return COMPILE_OK;
10046}
10047
10048static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
10049
10050static int
10051compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10052{
10053 const int line = nd_line(node);
10054 LABEL *lfin = 0;
10055 LABEL *lassign = 0;
10056 ID mid;
10057
10058 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
10059 case NODE_COLON3:
10060 ADD_INSN1(ret, node, putobject, rb_cObject);
10061 break;
10062 case NODE_COLON2:
10063 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
10064 break;
10065 default:
10066 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
10067 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
10068 return COMPILE_NG;
10069 }
10070 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
10071 /* cref */
10072 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
10073 lassign = NEW_LABEL(line);
10074 ADD_INSN(ret, node, dup); /* cref cref */
10075 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
10076 ID2SYM(mid), Qtrue); /* cref bool */
10077 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
10078 }
10079 ADD_INSN(ret, node, dup); /* cref cref */
10080 ADD_INSN1(ret, node, putobject, Qtrue);
10081 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
10082
10083 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
10084 lfin = NEW_LABEL(line);
10085 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
10086 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
10087 ADD_INSNL(ret, node, branchif, lfin);
10088 else /* idANDOP */
10089 ADD_INSNL(ret, node, branchunless, lfin);
10090 /* cref [obj] */
10091 if (!popped) ADD_INSN(ret, node, pop); /* cref */
10092 if (lassign) ADD_LABEL(ret, lassign);
10093 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10094 /* cref value */
10095 if (popped)
10096 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
10097 else {
10098 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
10099 ADD_INSN(ret, node, swap); /* cref value value cref */
10100 }
10101 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
10102 ADD_LABEL(ret, lfin); /* cref [value] */
10103 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
10104 ADD_INSN(ret, node, pop); /* [value] */
10105 }
10106 else {
10107 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10108 /* cref obj value */
10109 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
10110 /* cref value */
10111 ADD_INSN(ret, node, swap); /* value cref */
10112 if (!popped) {
10113 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
10114 ADD_INSN(ret, node, swap); /* value value cref */
10115 }
10116 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
10117 }
10118 return COMPILE_OK;
10119}
10120
10121static int
10122compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10123{
10124 const int line = nd_line(node);
10125 LABEL *lfin = NEW_LABEL(line);
10126 LABEL *lassign;
10127
10128 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
10129 LABEL *lfinish[2];
10130 lfinish[0] = lfin;
10131 lfinish[1] = 0;
10132 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
10133 lassign = lfinish[1];
10134 if (!lassign) {
10135 lassign = NEW_LABEL(line);
10136 }
10137 ADD_INSNL(ret, node, branchunless, lassign);
10138 }
10139 else {
10140 lassign = NEW_LABEL(line);
10141 }
10142
10143 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10144
10145 if (!popped) {
10146 ADD_INSN(ret, node, dup);
10147 }
10148
10149 if (type == NODE_OP_ASGN_AND) {
10150 ADD_INSNL(ret, node, branchunless, lfin);
10151 }
10152 else {
10153 ADD_INSNL(ret, node, branchif, lfin);
10154 }
10155
10156 if (!popped) {
10157 ADD_INSN(ret, node, pop);
10158 }
10159
10160 ADD_LABEL(ret, lassign);
10161 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10162 ADD_LABEL(ret, lfin);
10163 return COMPILE_OK;
10164}
10165
10166static int
10167compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10168{
10169 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10170 DECL_ANCHOR(args);
10171 int argc;
10172 unsigned int flag = 0;
10173 struct rb_callinfo_kwarg *keywords = NULL;
10174 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10175 int use_block = 1;
10176
10177 INIT_ANCHOR(args);
10178 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10179
10180 if (type == NODE_SUPER) {
10181 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10182 CHECK(!NIL_P(vargc));
10183 argc = FIX2INT(vargc);
10184 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10185 ADD_INSN(args, node, splatkw);
10186 }
10187
10188 if (flag & VM_CALL_ARGS_BLOCKARG) {
10189 use_block = 0;
10190 }
10191 }
10192 else {
10193 /* NODE_ZSUPER */
10194 int i;
10195 const rb_iseq_t *liseq = body->local_iseq;
10196 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10197 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10198 int lvar_level = get_lvar_level(iseq);
10199
10200 argc = local_body->param.lead_num;
10201
10202 /* normal arguments */
10203 for (i = 0; i < local_body->param.lead_num; i++) {
10204 int idx = local_body->local_table_size - i;
10205 ADD_GETLOCAL(args, node, idx, lvar_level);
10206 }
10207
10208 /* forward ... */
10209 if (local_body->param.flags.forwardable) {
10210 flag |= VM_CALL_FORWARDING;
10211 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10212 ADD_GETLOCAL(args, node, idx, lvar_level);
10213 }
10214
10215 if (local_body->param.flags.has_opt) {
10216 /* optional arguments */
10217 int j;
10218 for (j = 0; j < local_body->param.opt_num; j++) {
10219 int idx = local_body->local_table_size - (i + j);
10220 ADD_GETLOCAL(args, node, idx, lvar_level);
10221 }
10222 i += j;
10223 argc = i;
10224 }
10225 if (local_body->param.flags.has_rest) {
10226 /* rest argument */
10227 int idx = local_body->local_table_size - local_body->param.rest_start;
10228 ADD_GETLOCAL(args, node, idx, lvar_level);
10229 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10230
10231 argc = local_body->param.rest_start + 1;
10232 flag |= VM_CALL_ARGS_SPLAT;
10233 }
10234 if (local_body->param.flags.has_post) {
10235 /* post arguments */
10236 int post_len = local_body->param.post_num;
10237 int post_start = local_body->param.post_start;
10238
10239 if (local_body->param.flags.has_rest) {
10240 int j;
10241 for (j=0; j<post_len; j++) {
10242 int idx = local_body->local_table_size - (post_start + j);
10243 ADD_GETLOCAL(args, node, idx, lvar_level);
10244 }
10245 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10246 flag |= VM_CALL_ARGS_SPLAT_MUT;
10247 /* argc is settled at above */
10248 }
10249 else {
10250 int j;
10251 for (j=0; j<post_len; j++) {
10252 int idx = local_body->local_table_size - (post_start + j);
10253 ADD_GETLOCAL(args, node, idx, lvar_level);
10254 }
10255 argc = post_len + post_start;
10256 }
10257 }
10258
10259 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10260 int local_size = local_body->local_table_size;
10261 argc++;
10262
10263 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10264
10265 if (local_body->param.flags.has_kwrest) {
10266 int idx = local_body->local_table_size - local_kwd->rest_start;
10267 ADD_GETLOCAL(args, node, idx, lvar_level);
10268 RUBY_ASSERT(local_kwd->num > 0);
10269 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10270 }
10271 else {
10272 ADD_INSN1(args, node, newhash, INT2FIX(0));
10273 }
10274 for (i = 0; i < local_kwd->num; ++i) {
10275 ID id = local_kwd->table[i];
10276 int idx = local_size - get_local_var_idx(liseq, id);
10277 ADD_INSN1(args, node, putobject, ID2SYM(id));
10278 ADD_GETLOCAL(args, node, idx, lvar_level);
10279 }
10280 ADD_SEND(args, node, id_core_hash_merge_bang_ptr, INT2FIX(i * 2 + 1));
10281 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10282 }
10283 else if (local_body->param.flags.has_kwrest) {
10284 int idx = local_body->local_table_size - local_kwd->rest_start;
10285 ADD_GETLOCAL(args, node, idx, lvar_level);
10286 argc++;
10287 flag |= VM_CALL_KW_SPLAT;
10288 }
10289 }
10290
10291 if (use_block && parent_block == NULL) {
10292 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10293 }
10294
10295 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10296 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10297 ADD_INSN(ret, node, putself);
10298 ADD_SEQ(ret, args);
10299
10300 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10301
10302 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10303 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10304 }
10305 else {
10306 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10307 }
10308
10309 if (popped) {
10310 ADD_INSN(ret, node, pop);
10311 }
10312 return COMPILE_OK;
10313}
10314
10315static int
10316compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10317{
10318 DECL_ANCHOR(args);
10319 VALUE argc;
10320 unsigned int flag = 0;
10321 struct rb_callinfo_kwarg *keywords = NULL;
10322
10323 INIT_ANCHOR(args);
10324
10325 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10326 case ISEQ_TYPE_TOP:
10327 case ISEQ_TYPE_MAIN:
10328 case ISEQ_TYPE_CLASS:
10329 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10330 return COMPILE_NG;
10331 default: /* valid */;
10332 }
10333
10334 if (RNODE_YIELD(node)->nd_head) {
10335 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10336 CHECK(!NIL_P(argc));
10337 }
10338 else {
10339 argc = INT2FIX(0);
10340 }
10341
10342 ADD_SEQ(ret, args);
10343 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10344 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10345
10346 if (popped) {
10347 ADD_INSN(ret, node, pop);
10348 }
10349
10350 int level = 0;
10351 const rb_iseq_t *tmp_iseq = iseq;
10352 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10353 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10354 }
10355 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10356
10357 return COMPILE_OK;
10358}
10359
10360static int
10361compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10362{
10363 DECL_ANCHOR(recv);
10364 DECL_ANCHOR(val);
10365
10366 INIT_ANCHOR(recv);
10367 INIT_ANCHOR(val);
10368 switch ((int)type) {
10369 case NODE_MATCH:
10370 {
10371 VALUE re = rb_node_regx_string_val(node);
10372 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10373 ADD_INSN1(recv, node, putobject, re);
10374 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10375 INT2FIX(0));
10376 }
10377 break;
10378 case NODE_MATCH2:
10379 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10380 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10381 break;
10382 case NODE_MATCH3:
10383 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10384 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10385 break;
10386 }
10387
10388 ADD_SEQ(ret, recv);
10389 ADD_SEQ(ret, val);
10390 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10391
10392 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10393 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10394 }
10395
10396 if (popped) {
10397 ADD_INSN(ret, node, pop);
10398 }
10399 return COMPILE_OK;
10400}
10401
10402static int
10403compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10404{
10405 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10406 /* constant */
10407 VALUE segments;
10408 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10409 (segments = collect_const_segments(iseq, node))) {
10410 ISEQ_BODY(iseq)->ic_size++;
10411 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10412 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10413 }
10414 else {
10415 /* constant */
10416 DECL_ANCHOR(pref);
10417 DECL_ANCHOR(body);
10418
10419 INIT_ANCHOR(pref);
10420 INIT_ANCHOR(body);
10421 CHECK(compile_const_prefix(iseq, node, pref, body));
10422 if (LIST_INSN_SIZE_ZERO(pref)) {
10423 ADD_INSN(ret, node, putnil);
10424 ADD_SEQ(ret, body);
10425 }
10426 else {
10427 ADD_SEQ(ret, pref);
10428 ADD_SEQ(ret, body);
10429 }
10430 }
10431 }
10432 else {
10433 /* function call */
10434 ADD_CALL_RECEIVER(ret, node);
10435 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10436 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10437 }
10438 if (popped) {
10439 ADD_INSN(ret, node, pop);
10440 }
10441 return COMPILE_OK;
10442}
10443
10444static int
10445compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10446{
10447 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10448
10449 /* add cache insn */
10450 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10451 ISEQ_BODY(iseq)->ic_size++;
10452 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10453 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10454 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10455 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10456 }
10457 else {
10458 ADD_INSN1(ret, node, putobject, rb_cObject);
10459 ADD_INSN1(ret, node, putobject, Qtrue);
10460 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10461 }
10462
10463 if (popped) {
10464 ADD_INSN(ret, node, pop);
10465 }
10466 return COMPILE_OK;
10467}
10468
10469static int
10470compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10471{
10472 VALUE flag = INT2FIX(excl);
10473 const NODE *b = RNODE_DOT2(node)->nd_beg;
10474 const NODE *e = RNODE_DOT2(node)->nd_end;
10475
10476 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10477 if (!popped) {
10478 VALUE bv = optimized_range_item(b);
10479 VALUE ev = optimized_range_item(e);
10480 VALUE val = rb_range_new(bv, ev, excl);
10482 ADD_INSN1(ret, node, putobject, val);
10483 RB_OBJ_WRITTEN(iseq, Qundef, val);
10484 }
10485 }
10486 else {
10487 CHECK(COMPILE_(ret, "min", b, popped));
10488 CHECK(COMPILE_(ret, "max", e, popped));
10489 if (!popped) {
10490 ADD_INSN1(ret, node, newrange, flag);
10491 }
10492 }
10493 return COMPILE_OK;
10494}
10495
10496static int
10497compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10498{
10499 if (!popped) {
10500 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10501 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10502 }
10503 else {
10504 const rb_iseq_t *ip = iseq;
10505 int level = 0;
10506 while (ip) {
10507 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10508 break;
10509 }
10510 ip = ISEQ_BODY(ip)->parent_iseq;
10511 level++;
10512 }
10513 if (ip) {
10514 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10515 }
10516 else {
10517 ADD_INSN(ret, node, putnil);
10518 }
10519 }
10520 }
10521 return COMPILE_OK;
10522}
10523
10524static int
10525compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10526{
10527 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10528 LABEL *end_label = NEW_LABEL(nd_line(node));
10529 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10530
10531 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10532 /* required argument. do nothing */
10533 COMPILE_ERROR(ERROR_ARGS "unreachable");
10534 return COMPILE_NG;
10535 }
10536 else if (nd_type_p(default_value, NODE_SYM) ||
10537 nd_type_p(default_value, NODE_REGX) ||
10538 nd_type_p(default_value, NODE_LINE) ||
10539 nd_type_p(default_value, NODE_INTEGER) ||
10540 nd_type_p(default_value, NODE_FLOAT) ||
10541 nd_type_p(default_value, NODE_RATIONAL) ||
10542 nd_type_p(default_value, NODE_IMAGINARY) ||
10543 nd_type_p(default_value, NODE_NIL) ||
10544 nd_type_p(default_value, NODE_TRUE) ||
10545 nd_type_p(default_value, NODE_FALSE)) {
10546 COMPILE_ERROR(ERROR_ARGS "unreachable");
10547 return COMPILE_NG;
10548 }
10549 else {
10550 /* if keywordcheck(_kw_bits, nth_keyword)
10551 * kw = default_value
10552 * end
10553 */
10554 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10555 int keyword_idx = body->param.keyword->num;
10556
10557 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10558 ADD_INSNL(ret, node, branchif, end_label);
10559 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10560 ADD_LABEL(ret, end_label);
10561 }
10562 return COMPILE_OK;
10563}
10564
10565static int
10566compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10567{
10568 DECL_ANCHOR(recv);
10569 DECL_ANCHOR(args);
10570 unsigned int flag = 0;
10571 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10572 VALUE argc;
10573 LABEL *else_label = NULL;
10574 VALUE branches = Qfalse;
10575
10576 INIT_ANCHOR(recv);
10577 INIT_ANCHOR(args);
10578 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10579 CHECK(!NIL_P(argc));
10580
10581 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10582 CHECK(asgnflag != -1);
10583 flag |= (unsigned int)asgnflag;
10584
10585 debugp_param("argc", argc);
10586 debugp_param("nd_mid", ID2SYM(mid));
10587
10588 if (!rb_is_attrset_id(mid)) {
10589 /* safe nav attr */
10590 mid = rb_id_attrset(mid);
10591 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10592 }
10593 if (!popped) {
10594 ADD_INSN(ret, node, putnil);
10595 ADD_SEQ(ret, recv);
10596 ADD_SEQ(ret, args);
10597
10598 if (flag & VM_CALL_ARGS_SPLAT) {
10599 ADD_INSN(ret, node, dup);
10600 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10601 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10602 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10603 ADD_INSN (ret, node, pop);
10604 }
10605 else {
10606 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10607 }
10608 }
10609 else {
10610 ADD_SEQ(ret, recv);
10611 ADD_SEQ(ret, args);
10612 }
10613 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10614 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10615 ADD_INSN(ret, node, pop);
10616 return COMPILE_OK;
10617}
10618
10619static int
10620compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10621{
10622 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10623 ADD_SEQ(ret, sub);
10624
10625 if (copy) {
10626 /*
10627 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10628 * NEW_LIST(value, loc), loc);
10629 */
10630 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10631 }
10632 else {
10633 /*
10634 * NEW_CALL(fcore, rb_intern("make_shareable"),
10635 * NEW_LIST(value, loc), loc);
10636 */
10637 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10638 }
10639
10640 return COMPILE_OK;
10641}
10642
10643static VALUE
10644node_const_decl_val(const NODE *node)
10645{
10646 VALUE path;
10647 switch (nd_type(node)) {
10648 case NODE_CDECL:
10649 if (RNODE_CDECL(node)->nd_vid) {
10650 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10651 goto end;
10652 }
10653 else {
10654 node = RNODE_CDECL(node)->nd_else;
10655 }
10656 break;
10657 case NODE_COLON2:
10658 break;
10659 case NODE_COLON3:
10660 // ::Const
10661 path = rb_str_new_cstr("::");
10662 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10663 goto end;
10664 default:
10665 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10667 }
10668
10669 path = rb_ary_new();
10670 if (node) {
10671 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10672 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10673 }
10674 if (node && nd_type_p(node, NODE_CONST)) {
10675 // Const::Name
10676 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10677 }
10678 else if (node && nd_type_p(node, NODE_COLON3)) {
10679 // ::Const::Name
10680 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10681 rb_ary_push(path, rb_str_new(0, 0));
10682 }
10683 else {
10684 // expression::Name
10685 rb_ary_push(path, rb_str_new_cstr("..."));
10686 }
10687 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10688 }
10689 end:
10690 path = rb_fstring(path);
10691 return path;
10692}
10693
10694static VALUE
10695const_decl_path(NODE *dest)
10696{
10697 VALUE path = Qnil;
10698 if (!nd_type_p(dest, NODE_CALL)) {
10699 path = node_const_decl_val(dest);
10700 }
10701 return path;
10702}
10703
10704static int
10705compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10706{
10707 /*
10708 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10709 */
10710 VALUE path = const_decl_path(dest);
10711 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10712 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10713 ADD_INSN1(ret, value, putobject, path);
10714 RB_OBJ_WRITTEN(iseq, Qundef, path);
10715 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10716
10717 return COMPILE_OK;
10718}
10719
10720#ifndef SHAREABLE_BARE_EXPRESSION
10721#define SHAREABLE_BARE_EXPRESSION 1
10722#endif
10723
10724static int
10725compile_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)
10726{
10727# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10728 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10729 VALUE lit = Qnil;
10730 DECL_ANCHOR(anchor);
10731
10732 enum node_type type = node ? nd_type(node) : NODE_NIL;
10733 switch (type) {
10734 case NODE_TRUE:
10735 *value_p = Qtrue;
10736 goto compile;
10737 case NODE_FALSE:
10738 *value_p = Qfalse;
10739 goto compile;
10740 case NODE_NIL:
10741 *value_p = Qnil;
10742 goto compile;
10743 case NODE_SYM:
10744 *value_p = rb_node_sym_string_val(node);
10745 goto compile;
10746 case NODE_REGX:
10747 *value_p = rb_node_regx_string_val(node);
10748 goto compile;
10749 case NODE_LINE:
10750 *value_p = rb_node_line_lineno_val(node);
10751 goto compile;
10752 case NODE_INTEGER:
10753 *value_p = rb_node_integer_literal_val(node);
10754 goto compile;
10755 case NODE_FLOAT:
10756 *value_p = rb_node_float_literal_val(node);
10757 goto compile;
10758 case NODE_RATIONAL:
10759 *value_p = rb_node_rational_literal_val(node);
10760 goto compile;
10761 case NODE_IMAGINARY:
10762 *value_p = rb_node_imaginary_literal_val(node);
10763 goto compile;
10764 case NODE_ENCODING:
10765 *value_p = rb_node_encoding_val(node);
10766
10767 compile:
10768 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10769 *shareable_literal_p = 1;
10770 return COMPILE_OK;
10771
10772 case NODE_DSTR:
10773 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10774 if (shareable == rb_parser_shareable_literal) {
10775 /*
10776 * NEW_CALL(node, idUMinus, 0, loc);
10777 *
10778 * -"#{var}"
10779 */
10780 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10781 }
10782 *value_p = Qundef;
10783 *shareable_literal_p = 1;
10784 return COMPILE_OK;
10785
10786 case NODE_STR:{
10787 VALUE lit = rb_node_str_string_val(node);
10788 ADD_INSN1(ret, node, putobject, lit);
10789 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10790 *value_p = lit;
10791 *shareable_literal_p = 1;
10792
10793 return COMPILE_OK;
10794 }
10795
10796 case NODE_FILE:{
10797 VALUE lit = rb_node_file_path_val(node);
10798 ADD_INSN1(ret, node, putobject, lit);
10799 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10800 *value_p = lit;
10801 *shareable_literal_p = 1;
10802
10803 return COMPILE_OK;
10804 }
10805
10806 case NODE_ZLIST:{
10807 VALUE lit = rb_ary_new();
10808 OBJ_FREEZE(lit);
10809 ADD_INSN1(ret, node, putobject, lit);
10810 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10811 *value_p = lit;
10812 *shareable_literal_p = 1;
10813
10814 return COMPILE_OK;
10815 }
10816
10817 case NODE_LIST:{
10818 INIT_ANCHOR(anchor);
10819 lit = rb_ary_new();
10820 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10821 VALUE val;
10822 int shareable_literal_p2;
10823 NODE *elt = RNODE_LIST(n)->nd_head;
10824 if (elt) {
10825 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10826 if (shareable_literal_p2) {
10827 /* noop */
10828 }
10829 else if (RTEST(lit)) {
10830 rb_ary_clear(lit);
10831 lit = Qfalse;
10832 }
10833 }
10834 if (RTEST(lit)) {
10835 if (!UNDEF_P(val)) {
10836 rb_ary_push(lit, val);
10837 }
10838 else {
10839 rb_ary_clear(lit);
10840 lit = Qnil; /* make shareable at runtime */
10841 }
10842 }
10843 }
10844 break;
10845 }
10846 case NODE_HASH:{
10847 if (!RNODE_HASH(node)->nd_brace) {
10848 *value_p = Qundef;
10849 *shareable_literal_p = 0;
10850 return COMPILE_OK;
10851 }
10852 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10853 if (!RNODE_LIST(n)->nd_head) {
10854 // If the hash node have a keyword splat, fall back to the default case.
10855 goto compile_shareable;
10856 }
10857 }
10858
10859 INIT_ANCHOR(anchor);
10860 lit = rb_hash_new();
10861 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10862 VALUE key_val = 0;
10863 VALUE value_val = 0;
10864 int shareable_literal_p2;
10865 NODE *key = RNODE_LIST(n)->nd_head;
10866 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10867 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10868 if (shareable_literal_p2) {
10869 /* noop */
10870 }
10871 else if (RTEST(lit)) {
10872 rb_hash_clear(lit);
10873 lit = Qfalse;
10874 }
10875 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10876 if (shareable_literal_p2) {
10877 /* noop */
10878 }
10879 else if (RTEST(lit)) {
10880 rb_hash_clear(lit);
10881 lit = Qfalse;
10882 }
10883 if (RTEST(lit)) {
10884 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10885 rb_hash_aset(lit, key_val, value_val);
10886 }
10887 else {
10888 rb_hash_clear(lit);
10889 lit = Qnil; /* make shareable at runtime */
10890 }
10891 }
10892 }
10893 break;
10894 }
10895
10896 default:
10897
10898 compile_shareable:
10899 if (shareable == rb_parser_shareable_literal &&
10900 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10901 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10902 *value_p = Qundef;
10903 *shareable_literal_p = 1;
10904 return COMPILE_OK;
10905 }
10906 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10907 *value_p = Qundef;
10908 *shareable_literal_p = 0;
10909 return COMPILE_OK;
10910 }
10911
10912 /* Array or Hash that does not have keyword splat */
10913 if (!lit) {
10914 if (nd_type(node) == NODE_LIST) {
10915 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10916 }
10917 else if (nd_type(node) == NODE_HASH) {
10918 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10921 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10922 }
10923 *value_p = Qundef;
10924 *shareable_literal_p = 0;
10925 ADD_SEQ(ret, anchor);
10926 return COMPILE_OK;
10927 }
10928 if (NIL_P(lit)) {
10929 // if shareable_literal, all elements should have been ensured
10930 // as shareable
10931 if (nd_type(node) == NODE_LIST) {
10932 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10933 }
10934 else if (nd_type(node) == NODE_HASH) {
10935 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10938 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10939 }
10940 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10941 *value_p = Qundef;
10942 *shareable_literal_p = 1;
10943 }
10944 else {
10946 ADD_INSN1(ret, node, putobject, val);
10947 RB_OBJ_WRITTEN(iseq, Qundef, val);
10948 *value_p = val;
10949 *shareable_literal_p = 1;
10950 }
10951
10952 return COMPILE_OK;
10953}
10954
10955static int
10956compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10957{
10958 int literal_p = 0;
10959 VALUE val;
10960 DECL_ANCHOR(anchor);
10961 INIT_ANCHOR(anchor);
10962
10963 switch (shareable) {
10964 case rb_parser_shareable_none:
10965 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10966 return COMPILE_OK;
10967
10968 case rb_parser_shareable_literal:
10969 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10970 ADD_SEQ(ret, anchor);
10971 return COMPILE_OK;
10972
10973 case rb_parser_shareable_copy:
10974 case rb_parser_shareable_everything:
10975 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10976 if (!literal_p) {
10977 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10978 }
10979 else {
10980 ADD_SEQ(ret, anchor);
10981 }
10982 return COMPILE_OK;
10983 default:
10984 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10985 }
10986}
10987
10988static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10996static int
10997iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10998{
10999 if (node == 0) {
11000 if (!popped) {
11001 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11002 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11003 debugs("node: NODE_NIL(implicit)\n");
11004 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11005 }
11006 return COMPILE_OK;
11007 }
11008 return iseq_compile_each0(iseq, ret, node, popped);
11009}
11010
11011static int
11012iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11013{
11014 const int line = (int)nd_line(node);
11015 const enum node_type type = nd_type(node);
11016 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11017
11018 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11019 /* ignore */
11020 }
11021 else {
11022 if (nd_fl_newline(node)) {
11023 int event = RUBY_EVENT_LINE;
11024 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11025 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11026 event |= RUBY_EVENT_COVERAGE_LINE;
11027 }
11028 ADD_TRACE(ret, event);
11029 }
11030 }
11031
11032 debug_node_start(node);
11033#undef BEFORE_RETURN
11034#define BEFORE_RETURN debug_node_end()
11035
11036 switch (type) {
11037 case NODE_BLOCK:
11038 CHECK(compile_block(iseq, ret, node, popped));
11039 break;
11040 case NODE_IF:
11041 case NODE_UNLESS:
11042 CHECK(compile_if(iseq, ret, node, popped, type));
11043 break;
11044 case NODE_CASE:
11045 CHECK(compile_case(iseq, ret, node, popped));
11046 break;
11047 case NODE_CASE2:
11048 CHECK(compile_case2(iseq, ret, node, popped));
11049 break;
11050 case NODE_CASE3:
11051 CHECK(compile_case3(iseq, ret, node, popped));
11052 break;
11053 case NODE_WHILE:
11054 case NODE_UNTIL:
11055 CHECK(compile_loop(iseq, ret, node, popped, type));
11056 break;
11057 case NODE_FOR:
11058 case NODE_ITER:
11059 CHECK(compile_iter(iseq, ret, node, popped));
11060 break;
11061 case NODE_FOR_MASGN:
11062 CHECK(compile_for_masgn(iseq, ret, node, popped));
11063 break;
11064 case NODE_BREAK:
11065 CHECK(compile_break(iseq, ret, node, popped));
11066 break;
11067 case NODE_NEXT:
11068 CHECK(compile_next(iseq, ret, node, popped));
11069 break;
11070 case NODE_REDO:
11071 CHECK(compile_redo(iseq, ret, node, popped));
11072 break;
11073 case NODE_RETRY:
11074 CHECK(compile_retry(iseq, ret, node, popped));
11075 break;
11076 case NODE_BEGIN:{
11077 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11078 break;
11079 }
11080 case NODE_RESCUE:
11081 CHECK(compile_rescue(iseq, ret, node, popped));
11082 break;
11083 case NODE_RESBODY:
11084 CHECK(compile_resbody(iseq, ret, node, popped));
11085 break;
11086 case NODE_ENSURE:
11087 CHECK(compile_ensure(iseq, ret, node, popped));
11088 break;
11089
11090 case NODE_AND:
11091 case NODE_OR:{
11092 LABEL *end_label = NEW_LABEL(line);
11093 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
11094 if (!popped) {
11095 ADD_INSN(ret, node, dup);
11096 }
11097 if (type == NODE_AND) {
11098 ADD_INSNL(ret, node, branchunless, end_label);
11099 }
11100 else {
11101 ADD_INSNL(ret, node, branchif, end_label);
11102 }
11103 if (!popped) {
11104 ADD_INSN(ret, node, pop);
11105 }
11106 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
11107 ADD_LABEL(ret, end_label);
11108 break;
11109 }
11110
11111 case NODE_MASGN:{
11112 compile_massign(iseq, ret, node, popped);
11113 break;
11114 }
11115
11116 case NODE_LASGN:{
11117 ID id = RNODE_LASGN(node)->nd_vid;
11118 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11119
11120 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11121 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11122
11123 if (!popped) {
11124 ADD_INSN(ret, node, dup);
11125 }
11126 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11127 break;
11128 }
11129 case NODE_DASGN: {
11130 int idx, lv, ls;
11131 ID id = RNODE_DASGN(node)->nd_vid;
11132 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11133 debugi("dassn id", rb_id2str(id) ? id : '*');
11134
11135 if (!popped) {
11136 ADD_INSN(ret, node, dup);
11137 }
11138
11139 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11140
11141 if (idx < 0) {
11142 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11143 rb_id2str(id));
11144 goto ng;
11145 }
11146 ADD_SETLOCAL(ret, node, ls - idx, lv);
11147 break;
11148 }
11149 case NODE_GASGN:{
11150 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11151
11152 if (!popped) {
11153 ADD_INSN(ret, node, dup);
11154 }
11155 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11156 break;
11157 }
11158 case NODE_IASGN:{
11159 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11160 if (!popped) {
11161 ADD_INSN(ret, node, dup);
11162 }
11163 ADD_INSN2(ret, node, setinstancevariable,
11164 ID2SYM(RNODE_IASGN(node)->nd_vid),
11165 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11166 break;
11167 }
11168 case NODE_CDECL:{
11169 if (RNODE_CDECL(node)->nd_vid) {
11170 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11171
11172 if (!popped) {
11173 ADD_INSN(ret, node, dup);
11174 }
11175
11176 ADD_INSN1(ret, node, putspecialobject,
11177 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11178 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11179 }
11180 else {
11181 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11182 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11183 ADD_INSN(ret, node, swap);
11184
11185 if (!popped) {
11186 ADD_INSN1(ret, node, topn, INT2FIX(1));
11187 ADD_INSN(ret, node, swap);
11188 }
11189
11190 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11191 }
11192 break;
11193 }
11194 case NODE_CVASGN:{
11195 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11196 if (!popped) {
11197 ADD_INSN(ret, node, dup);
11198 }
11199 ADD_INSN2(ret, node, setclassvariable,
11200 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11201 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11202 break;
11203 }
11204 case NODE_OP_ASGN1:
11205 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11206 break;
11207 case NODE_OP_ASGN2:
11208 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11209 break;
11210 case NODE_OP_CDECL:
11211 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11212 break;
11213 case NODE_OP_ASGN_AND:
11214 case NODE_OP_ASGN_OR:
11215 CHECK(compile_op_log(iseq, ret, node, popped, type));
11216 break;
11217 case NODE_CALL: /* obj.foo */
11218 case NODE_OPCALL: /* foo[] */
11219 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11220 break;
11221 }
11222 case NODE_QCALL: /* obj&.foo */
11223 case NODE_FCALL: /* foo() */
11224 case NODE_VCALL: /* foo (variable or call) */
11225 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11226 goto ng;
11227 }
11228 break;
11229 case NODE_SUPER:
11230 case NODE_ZSUPER:
11231 CHECK(compile_super(iseq, ret, node, popped, type));
11232 break;
11233 case NODE_LIST:{
11234 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11235 break;
11236 }
11237 case NODE_ZLIST:{
11238 if (!popped) {
11239 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11240 }
11241 break;
11242 }
11243 case NODE_HASH:
11244 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11245 break;
11246 case NODE_RETURN:
11247 CHECK(compile_return(iseq, ret, node, popped));
11248 break;
11249 case NODE_YIELD:
11250 CHECK(compile_yield(iseq, ret, node, popped));
11251 break;
11252 case NODE_LVAR:{
11253 if (!popped) {
11254 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11255 }
11256 break;
11257 }
11258 case NODE_DVAR:{
11259 int lv, idx, ls;
11260 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11261 if (!popped) {
11262 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11263 if (idx < 0) {
11264 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11265 rb_id2str(RNODE_DVAR(node)->nd_vid));
11266 goto ng;
11267 }
11268 ADD_GETLOCAL(ret, node, ls - idx, lv);
11269 }
11270 break;
11271 }
11272 case NODE_GVAR:{
11273 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11274 if (popped) {
11275 ADD_INSN(ret, node, pop);
11276 }
11277 break;
11278 }
11279 case NODE_IVAR:{
11280 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11281 if (!popped) {
11282 ADD_INSN2(ret, node, getinstancevariable,
11283 ID2SYM(RNODE_IVAR(node)->nd_vid),
11284 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11285 }
11286 break;
11287 }
11288 case NODE_CONST:{
11289 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11290
11291 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11292 body->ic_size++;
11293 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11294 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11295 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11296 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11297 }
11298 else {
11299 ADD_INSN(ret, node, putnil);
11300 ADD_INSN1(ret, node, putobject, Qtrue);
11301 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11302 }
11303
11304 if (popped) {
11305 ADD_INSN(ret, node, pop);
11306 }
11307 break;
11308 }
11309 case NODE_CVAR:{
11310 if (!popped) {
11311 ADD_INSN2(ret, node, getclassvariable,
11312 ID2SYM(RNODE_CVAR(node)->nd_vid),
11313 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11314 }
11315 break;
11316 }
11317 case NODE_NTH_REF:{
11318 if (!popped) {
11319 if (!RNODE_NTH_REF(node)->nd_nth) {
11320 ADD_INSN(ret, node, putnil);
11321 break;
11322 }
11323 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11324 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11325 }
11326 break;
11327 }
11328 case NODE_BACK_REF:{
11329 if (!popped) {
11330 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11331 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11332 }
11333 break;
11334 }
11335 case NODE_MATCH:
11336 case NODE_MATCH2:
11337 case NODE_MATCH3:
11338 CHECK(compile_match(iseq, ret, node, popped, type));
11339 break;
11340 case NODE_SYM:{
11341 if (!popped) {
11342 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11343 }
11344 break;
11345 }
11346 case NODE_LINE:{
11347 if (!popped) {
11348 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11349 }
11350 break;
11351 }
11352 case NODE_ENCODING:{
11353 if (!popped) {
11354 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11355 }
11356 break;
11357 }
11358 case NODE_INTEGER:{
11359 VALUE lit = rb_node_integer_literal_val(node);
11360 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11361 debugp_param("integer", lit);
11362 if (!popped) {
11363 ADD_INSN1(ret, node, putobject, lit);
11364 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11365 }
11366 break;
11367 }
11368 case NODE_FLOAT:{
11369 VALUE lit = rb_node_float_literal_val(node);
11370 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11371 debugp_param("float", lit);
11372 if (!popped) {
11373 ADD_INSN1(ret, node, putobject, lit);
11374 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11375 }
11376 break;
11377 }
11378 case NODE_RATIONAL:{
11379 VALUE lit = rb_node_rational_literal_val(node);
11381 debugp_param("rational", lit);
11382 if (!popped) {
11383 ADD_INSN1(ret, node, putobject, lit);
11384 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11385 }
11386 break;
11387 }
11388 case NODE_IMAGINARY:{
11389 VALUE lit = rb_node_imaginary_literal_val(node);
11391 debugp_param("imaginary", lit);
11392 if (!popped) {
11393 ADD_INSN1(ret, node, putobject, lit);
11394 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11395 }
11396 break;
11397 }
11398 case NODE_FILE:
11399 case NODE_STR:{
11400 debugp_param("nd_lit", get_string_value(node));
11401 if (!popped) {
11402 VALUE lit = get_string_value(node);
11403 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11404 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11405 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11406 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11407 RB_OBJ_SET_SHAREABLE(lit);
11408 }
11409 switch (option->frozen_string_literal) {
11410 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11411 ADD_INSN1(ret, node, dupchilledstring, lit);
11412 break;
11413 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11414 ADD_INSN1(ret, node, dupstring, lit);
11415 break;
11416 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11417 ADD_INSN1(ret, node, putobject, lit);
11418 break;
11419 default:
11420 rb_bug("invalid frozen_string_literal");
11421 }
11422 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11423 }
11424 break;
11425 }
11426 case NODE_DSTR:{
11427 compile_dstr(iseq, ret, node);
11428
11429 if (popped) {
11430 ADD_INSN(ret, node, pop);
11431 }
11432 break;
11433 }
11434 case NODE_XSTR:{
11435 ADD_CALL_RECEIVER(ret, node);
11436 VALUE str = rb_node_str_string_val(node);
11437 ADD_INSN1(ret, node, putobject, str);
11438 RB_OBJ_WRITTEN(iseq, Qundef, str);
11439 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11440
11441 if (popped) {
11442 ADD_INSN(ret, node, pop);
11443 }
11444 break;
11445 }
11446 case NODE_DXSTR:{
11447 ADD_CALL_RECEIVER(ret, node);
11448 compile_dstr(iseq, ret, node);
11449 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11450
11451 if (popped) {
11452 ADD_INSN(ret, node, pop);
11453 }
11454 break;
11455 }
11456 case NODE_EVSTR:
11457 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11458 break;
11459 case NODE_REGX:{
11460 if (!popped) {
11461 VALUE lit = rb_node_regx_string_val(node);
11462 RB_OBJ_SET_SHAREABLE(lit);
11463 ADD_INSN1(ret, node, putobject, lit);
11464 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11465 }
11466 break;
11467 }
11468 case NODE_DREGX:
11469 compile_dregx(iseq, ret, node, popped);
11470 break;
11471 case NODE_ONCE:{
11472 int ic_index = body->ise_size++;
11473 const rb_iseq_t *block_iseq;
11474 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11475
11476 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11477 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11478
11479 if (popped) {
11480 ADD_INSN(ret, node, pop);
11481 }
11482 break;
11483 }
11484 case NODE_ARGSCAT:{
11485 if (popped) {
11486 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11487 ADD_INSN1(ret, node, splatarray, Qfalse);
11488 ADD_INSN(ret, node, pop);
11489 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11490 ADD_INSN1(ret, node, splatarray, Qfalse);
11491 ADD_INSN(ret, node, pop);
11492 }
11493 else {
11494 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11495 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11496 if (nd_type_p(body_node, NODE_LIST)) {
11497 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11498 }
11499 else {
11500 CHECK(COMPILE(ret, "argscat body", body_node));
11501 ADD_INSN(ret, node, concattoarray);
11502 }
11503 }
11504 break;
11505 }
11506 case NODE_ARGSPUSH:{
11507 if (popped) {
11508 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11509 ADD_INSN1(ret, node, splatarray, Qfalse);
11510 ADD_INSN(ret, node, pop);
11511 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11512 }
11513 else {
11514 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11515 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11516 if (keyword_node_p(body_node)) {
11517 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11518 ADD_INSN(ret, node, pushtoarraykwsplat);
11519 }
11520 else if (static_literal_node_p(body_node, iseq, false)) {
11521 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11522 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11523 }
11524 else {
11525 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11526 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11527 }
11528 }
11529 break;
11530 }
11531 case NODE_SPLAT:{
11532 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11533 ADD_INSN1(ret, node, splatarray, Qtrue);
11534
11535 if (popped) {
11536 ADD_INSN(ret, node, pop);
11537 }
11538 break;
11539 }
11540 case NODE_DEFN:{
11541 ID mid = RNODE_DEFN(node)->nd_mid;
11542 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11543 rb_id2str(mid),
11544 ISEQ_TYPE_METHOD, line);
11545
11546 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11547 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11548 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11549
11550 if (!popped) {
11551 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11552 }
11553
11554 break;
11555 }
11556 case NODE_DEFS:{
11557 ID mid = RNODE_DEFS(node)->nd_mid;
11558 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11559 rb_id2str(mid),
11560 ISEQ_TYPE_METHOD, line);
11561
11562 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11563 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11564 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11565 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11566
11567 if (!popped) {
11568 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11569 }
11570 break;
11571 }
11572 case NODE_ALIAS:{
11573 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11574 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11575 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11576 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11577 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11578
11579 if (popped) {
11580 ADD_INSN(ret, node, pop);
11581 }
11582 break;
11583 }
11584 case NODE_VALIAS:{
11585 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11586 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11587 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11588 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11589
11590 if (popped) {
11591 ADD_INSN(ret, node, pop);
11592 }
11593 break;
11594 }
11595 case NODE_UNDEF:{
11596 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11597
11598 for (long i = 0; i < ary->len; i++) {
11599 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11600 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11601 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11602 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11603
11604 if (i < ary->len - 1) {
11605 ADD_INSN(ret, node, pop);
11606 }
11607 }
11608
11609 if (popped) {
11610 ADD_INSN(ret, node, pop);
11611 }
11612 break;
11613 }
11614 case NODE_CLASS:{
11615 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11616 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11617 ISEQ_TYPE_CLASS, line);
11618 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11619 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11620 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11621
11622 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11623 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11624 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11625
11626 if (popped) {
11627 ADD_INSN(ret, node, pop);
11628 }
11629 break;
11630 }
11631 case NODE_MODULE:{
11632 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11633 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11634 ISEQ_TYPE_CLASS, line);
11635 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11636 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11637
11638 ADD_INSN (ret, node, putnil); /* dummy */
11639 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11640 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11641
11642 if (popped) {
11643 ADD_INSN(ret, node, pop);
11644 }
11645 break;
11646 }
11647 case NODE_SCLASS:{
11648 ID singletonclass;
11649 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11650 ISEQ_TYPE_CLASS, line);
11651
11652 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11653 ADD_INSN (ret, node, putnil);
11654 CONST_ID(singletonclass, "singletonclass");
11655
11656 /* `class << self` in a class body and `class << Foo` (constant
11657 receiver) are stable. All other forms are potentially dynamic. */
11658 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11659 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11660 if (!(nd_type_p(recv, NODE_SELF) &&
11661 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11662 !cpath_const_p(recv)) {
11663 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11664 }
11665
11666 ADD_INSN3(ret, node, defineclass,
11667 ID2SYM(singletonclass), singleton_class,
11668 INT2FIX(sclass_flags));
11669 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11670
11671 if (popped) {
11672 ADD_INSN(ret, node, pop);
11673 }
11674 break;
11675 }
11676 case NODE_COLON2:
11677 CHECK(compile_colon2(iseq, ret, node, popped));
11678 break;
11679 case NODE_COLON3:
11680 CHECK(compile_colon3(iseq, ret, node, popped));
11681 break;
11682 case NODE_DOT2:
11683 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11684 break;
11685 case NODE_DOT3:
11686 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11687 break;
11688 case NODE_FLIP2:
11689 case NODE_FLIP3:{
11690 LABEL *lend = NEW_LABEL(line);
11691 LABEL *ltrue = NEW_LABEL(line);
11692 LABEL *lfalse = NEW_LABEL(line);
11693 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11694 ltrue, lfalse));
11695 ADD_LABEL(ret, ltrue);
11696 ADD_INSN1(ret, node, putobject, Qtrue);
11697 ADD_INSNL(ret, node, jump, lend);
11698 ADD_LABEL(ret, lfalse);
11699 ADD_INSN1(ret, node, putobject, Qfalse);
11700 ADD_LABEL(ret, lend);
11701 break;
11702 }
11703 case NODE_SELF:{
11704 if (!popped) {
11705 ADD_INSN(ret, node, putself);
11706 }
11707 break;
11708 }
11709 case NODE_NIL:{
11710 if (!popped) {
11711 ADD_INSN(ret, node, putnil);
11712 }
11713 break;
11714 }
11715 case NODE_TRUE:{
11716 if (!popped) {
11717 ADD_INSN1(ret, node, putobject, Qtrue);
11718 }
11719 break;
11720 }
11721 case NODE_FALSE:{
11722 if (!popped) {
11723 ADD_INSN1(ret, node, putobject, Qfalse);
11724 }
11725 break;
11726 }
11727 case NODE_ERRINFO:
11728 CHECK(compile_errinfo(iseq, ret, node, popped));
11729 break;
11730 case NODE_DEFINED:
11731 if (!popped) {
11732 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11733 }
11734 break;
11735 case NODE_POSTEXE:{
11736 /* compiled to:
11737 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11738 */
11739 int is_index = body->ise_size++;
11741 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11742 const rb_iseq_t *once_iseq =
11743 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11744
11745 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11746 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11747
11748 if (popped) {
11749 ADD_INSN(ret, node, pop);
11750 }
11751 break;
11752 }
11753 case NODE_KW_ARG:
11754 CHECK(compile_kw_arg(iseq, ret, node, popped));
11755 break;
11756 case NODE_DSYM:{
11757 compile_dstr(iseq, ret, node);
11758 if (!popped) {
11759 ADD_INSN(ret, node, intern);
11760 }
11761 else {
11762 ADD_INSN(ret, node, pop);
11763 }
11764 break;
11765 }
11766 case NODE_ATTRASGN:
11767 CHECK(compile_attrasgn(iseq, ret, node, popped));
11768 break;
11769 case NODE_LAMBDA:{
11770 /* compile same as lambda{...} */
11771 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11772 VALUE argc = INT2FIX(0);
11773
11774 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11775 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11776 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11777
11778 if (popped) {
11779 ADD_INSN(ret, node, pop);
11780 }
11781 break;
11782 }
11783 default:
11784 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11785 ng:
11786 debug_node_end();
11787 return COMPILE_NG;
11788 }
11789
11790 debug_node_end();
11791 return COMPILE_OK;
11792}
11793
11794/***************************/
11795/* instruction information */
11796/***************************/
11797
11798static int
11799insn_data_length(INSN *iobj)
11800{
11801 return insn_len(iobj->insn_id);
11802}
11803
11804static int
11805calc_sp_depth(int depth, INSN *insn)
11806{
11807 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11808}
11809
11810static VALUE
11811opobj_inspect(VALUE obj)
11812{
11813 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11814 switch (BUILTIN_TYPE(obj)) {
11815 case T_STRING:
11816 obj = rb_str_resurrect(obj);
11817 break;
11818 case T_ARRAY:
11819 obj = rb_ary_resurrect(obj);
11820 break;
11821 default:
11822 break;
11823 }
11824 }
11825 return rb_inspect(obj);
11826}
11827
11828
11829
11830static VALUE
11831insn_data_to_s_detail(INSN *iobj)
11832{
11833 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11834
11835 if (iobj->operands) {
11836 const char *types = insn_op_types(iobj->insn_id);
11837 int j;
11838
11839 for (j = 0; types[j]; j++) {
11840 char type = types[j];
11841
11842 switch (type) {
11843 case TS_OFFSET: /* label(destination position) */
11844 {
11845 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11846 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11847 break;
11848 }
11849 break;
11850 case TS_ISEQ: /* iseq */
11851 {
11852 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11853 VALUE val = Qnil;
11854 if (0 && iseq) { /* TODO: invalidate now */
11855 val = (VALUE)iseq;
11856 }
11857 rb_str_concat(str, opobj_inspect(val));
11858 }
11859 break;
11860 case TS_LINDEX:
11861 case TS_NUM: /* ulong */
11862 case TS_VALUE: /* VALUE */
11863 {
11864 VALUE v = OPERAND_AT(iobj, j);
11865 if (!CLASS_OF(v))
11866 rb_str_cat2(str, "<hidden>");
11867 else {
11868 rb_str_concat(str, opobj_inspect(v));
11869 }
11870 break;
11871 }
11872 case TS_ID: /* ID */
11873 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11874 break;
11875 case TS_IC: /* inline cache */
11876 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11877 break;
11878 case TS_IVC: /* inline ivar cache */
11879 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11880 break;
11881 case TS_ICVARC: /* inline cvar cache */
11882 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11883 break;
11884 case TS_ISE: /* inline storage entry */
11885 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11886 break;
11887 case TS_CALLDATA: /* we store these as call infos at compile time */
11888 {
11889 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11890 rb_str_cat2(str, "<calldata:");
11891 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
11892 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11893 break;
11894 }
11895 case TS_CDHASH: /* case/when condition cache */
11896 rb_str_cat2(str, "<ch>");
11897 break;
11898 case TS_FUNCPTR:
11899 {
11900 void *func = (void *)OPERAND_AT(iobj, j);
11901#ifdef HAVE_DLADDR
11902 Dl_info info;
11903 if (dladdr(func, &info) && info.dli_sname) {
11904 rb_str_cat2(str, info.dli_sname);
11905 break;
11906 }
11907#endif
11908 rb_str_catf(str, "<%p>", func);
11909 }
11910 break;
11911 case TS_BUILTIN:
11912 rb_str_cat2(str, "<TS_BUILTIN>");
11913 break;
11914 default:{
11915 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11916 }
11917 }
11918 if (types[j + 1]) {
11919 rb_str_cat2(str, ", ");
11920 }
11921 }
11922 }
11923 return str;
11924}
11925
11926static void
11927dump_disasm_list(const LINK_ELEMENT *link)
11928{
11929 dump_disasm_list_with_cursor(link, NULL, NULL);
11930}
11931
11932static void
11933dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11934{
11935 int pos = 0;
11936 INSN *iobj;
11937 LABEL *lobj;
11938 VALUE str;
11939
11940 printf("-- raw disasm--------\n");
11941
11942 while (link) {
11943 if (curr) printf(curr == link ? "*" : " ");
11944 switch (link->type) {
11945 case ISEQ_ELEMENT_INSN:
11946 {
11947 iobj = (INSN *)link;
11948 str = insn_data_to_s_detail(iobj);
11949 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11950 pos += insn_data_length(iobj);
11951 break;
11952 }
11953 case ISEQ_ELEMENT_LABEL:
11954 {
11955 lobj = (LABEL *)link;
11956 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11957 dest == lobj ? " <---" : "");
11958 break;
11959 }
11960 case ISEQ_ELEMENT_TRACE:
11961 {
11962 TRACE *trace = (TRACE *)link;
11963 printf(" trace: %0x\n", trace->event);
11964 break;
11965 }
11966 case ISEQ_ELEMENT_ADJUST:
11967 {
11968 ADJUST *adjust = (ADJUST *)link;
11969 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11970 break;
11971 }
11972 default:
11973 /* ignore */
11974 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11975 }
11976 link = link->next;
11977 }
11978 printf("---------------------\n");
11979 fflush(stdout);
11980}
11981
11982int
11983rb_insn_len(VALUE insn)
11984{
11985 return insn_len(insn);
11986}
11987
11988const char *
11989rb_insns_name(int i)
11990{
11991 return insn_name(i);
11992}
11993
11994VALUE
11995rb_insns_name_array(void)
11996{
11997 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11998 int i;
11999 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12000 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12001 }
12002 return rb_ary_freeze(ary);
12003}
12004
12005static LABEL *
12006register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12007{
12008 LABEL *label = 0;
12009 st_data_t tmp;
12010 obj = rb_to_symbol_type(obj);
12011
12012 if (st_lookup(labels_table, obj, &tmp) == 0) {
12013 label = NEW_LABEL(0);
12014 st_insert(labels_table, obj, (st_data_t)label);
12015 }
12016 else {
12017 label = (LABEL *)tmp;
12018 }
12019 LABEL_REF(label);
12020 return label;
12021}
12022
12023static VALUE
12024get_exception_sym2type(VALUE sym)
12025{
12026 static VALUE symRescue, symEnsure, symRetry;
12027 static VALUE symBreak, symRedo, symNext;
12028
12029 if (symRescue == 0) {
12030 symRescue = ID2SYM(rb_intern_const("rescue"));
12031 symEnsure = ID2SYM(rb_intern_const("ensure"));
12032 symRetry = ID2SYM(rb_intern_const("retry"));
12033 symBreak = ID2SYM(rb_intern_const("break"));
12034 symRedo = ID2SYM(rb_intern_const("redo"));
12035 symNext = ID2SYM(rb_intern_const("next"));
12036 }
12037
12038 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12039 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12040 if (sym == symRetry) return CATCH_TYPE_RETRY;
12041 if (sym == symBreak) return CATCH_TYPE_BREAK;
12042 if (sym == symRedo) return CATCH_TYPE_REDO;
12043 if (sym == symNext) return CATCH_TYPE_NEXT;
12044 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12045 return 0;
12046}
12047
12048static int
12049iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12050 VALUE exception)
12051{
12052 int i;
12053
12054 for (i=0; i<RARRAY_LEN(exception); i++) {
12055 const rb_iseq_t *eiseq;
12056 VALUE v, type;
12057 LABEL *lstart, *lend, *lcont;
12058 unsigned int sp;
12059
12060 v = rb_to_array_type(RARRAY_AREF(exception, i));
12061 if (RARRAY_LEN(v) != 6) {
12062 rb_raise(rb_eSyntaxError, "wrong exception entry");
12063 }
12064 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12065 if (NIL_P(RARRAY_AREF(v, 1))) {
12066 eiseq = NULL;
12067 }
12068 else {
12069 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12070 }
12071
12072 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12073 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12074 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12075 sp = NUM2UINT(RARRAY_AREF(v, 5));
12076
12077 /* TODO: Dirty Hack! Fix me */
12078 if (type == CATCH_TYPE_RESCUE ||
12079 type == CATCH_TYPE_BREAK ||
12080 type == CATCH_TYPE_NEXT) {
12081 ++sp;
12082 }
12083
12084 lcont->sp = sp;
12085
12086 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12087
12088 RB_GC_GUARD(v);
12089 }
12090 return COMPILE_OK;
12091}
12092
12093static struct st_table *
12094insn_make_insn_table(void)
12095{
12096 struct st_table *table;
12097 int i;
12098 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12099
12100 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12101 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12102 }
12103
12104 return table;
12105}
12106
12107static const rb_iseq_t *
12108iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12109{
12110 VALUE iseqw;
12111 const rb_iseq_t *loaded_iseq;
12112
12113 if (RB_TYPE_P(op, T_ARRAY)) {
12114 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12115 }
12116 else if (CLASS_OF(op) == rb_cISeq) {
12117 iseqw = op;
12118 }
12119 else {
12120 rb_raise(rb_eSyntaxError, "ISEQ is required");
12121 }
12122
12123 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12124 return loaded_iseq;
12125}
12126
12127static VALUE
12128iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12129{
12130 ID mid = 0;
12131 int orig_argc = 0;
12132 unsigned int flag = 0;
12133 struct rb_callinfo_kwarg *kw_arg = 0;
12134
12135 if (!NIL_P(op)) {
12136 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12137 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12138 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12139 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12140
12141 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12142 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12143 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12144
12145 if (!NIL_P(vkw_arg)) {
12146 int i;
12147 int len = RARRAY_LENINT(vkw_arg);
12148 size_t n = rb_callinfo_kwarg_bytes(len);
12149
12150 kw_arg = xmalloc(n);
12151 kw_arg->references = 0;
12152 kw_arg->keyword_len = len;
12153 for (i = 0; i < len; i++) {
12154 VALUE kw = RARRAY_AREF(vkw_arg, i);
12155 SYM2ID(kw); /* make immortal */
12156 kw_arg->keywords[i] = kw;
12157 }
12158 }
12159 }
12160
12161 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12162 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12163 return (VALUE)ci;
12164}
12165
12166static rb_event_flag_t
12167event_name_to_flag(VALUE sym)
12168{
12169#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12170 CHECK_EVENT(RUBY_EVENT_LINE);
12171 CHECK_EVENT(RUBY_EVENT_CLASS);
12172 CHECK_EVENT(RUBY_EVENT_END);
12173 CHECK_EVENT(RUBY_EVENT_CALL);
12174 CHECK_EVENT(RUBY_EVENT_RETURN);
12175 CHECK_EVENT(RUBY_EVENT_B_CALL);
12176 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12177 CHECK_EVENT(RUBY_EVENT_RESCUE);
12178#undef CHECK_EVENT
12179 return RUBY_EVENT_NONE;
12180}
12181
12182static int
12183iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12184 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12185{
12186 /* TODO: body should be frozen */
12187 long i, len = RARRAY_LEN(body);
12188 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12189 int j;
12190 int line_no = 0, node_id = -1, insn_idx = 0;
12191 int ret = COMPILE_OK;
12192
12193 /*
12194 * index -> LABEL *label
12195 */
12196 static struct st_table *insn_table;
12197
12198 if (insn_table == 0) {
12199 insn_table = insn_make_insn_table();
12200 }
12201
12202 for (i=0; i<len; i++) {
12203 VALUE obj = RARRAY_AREF(body, i);
12204
12205 if (SYMBOL_P(obj)) {
12206 rb_event_flag_t event;
12207 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12208 ADD_TRACE(anchor, event);
12209 }
12210 else {
12211 LABEL *label = register_label(iseq, labels_table, obj);
12212 ADD_LABEL(anchor, label);
12213 }
12214 }
12215 else if (FIXNUM_P(obj)) {
12216 line_no = NUM2INT(obj);
12217 }
12218 else if (RB_TYPE_P(obj, T_ARRAY)) {
12219 VALUE *argv = 0;
12220 int argc = RARRAY_LENINT(obj) - 1;
12221 st_data_t insn_id;
12222 VALUE insn;
12223
12224 if (node_ids) {
12225 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12226 }
12227
12228 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12229 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12230 /* TODO: exception */
12231 COMPILE_ERROR(iseq, line_no,
12232 "unknown instruction: %+"PRIsVALUE, insn);
12233 ret = COMPILE_NG;
12234 break;
12235 }
12236
12237 if (argc != insn_len((VALUE)insn_id)-1) {
12238 COMPILE_ERROR(iseq, line_no,
12239 "operand size mismatch");
12240 ret = COMPILE_NG;
12241 break;
12242 }
12243
12244 if (argc > 0) {
12245 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12246
12247 // add element before operand setup to make GC root
12248 ADD_ELEM(anchor,
12249 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12250 (enum ruby_vminsn_type)insn_id, argc, argv));
12251
12252 for (j=0; j<argc; j++) {
12253 VALUE op = rb_ary_entry(obj, j+1);
12254 switch (insn_op_type((VALUE)insn_id, j)) {
12255 case TS_OFFSET: {
12256 LABEL *label = register_label(iseq, labels_table, op);
12257 argv[j] = (VALUE)label;
12258 break;
12259 }
12260 case TS_LINDEX:
12261 case TS_NUM:
12262 (void)NUM2INT(op);
12263 argv[j] = op;
12264 break;
12265 case TS_VALUE:
12266 argv[j] = op;
12267 RB_OBJ_WRITTEN(iseq, Qundef, op);
12268 break;
12269 case TS_ISEQ:
12270 {
12271 if (op != Qnil) {
12272 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12273 argv[j] = v;
12274 RB_OBJ_WRITTEN(iseq, Qundef, v);
12275 }
12276 else {
12277 argv[j] = 0;
12278 }
12279 }
12280 break;
12281 case TS_ISE:
12282 argv[j] = op;
12283 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12284 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12285 }
12286 break;
12287 case TS_IC:
12288 {
12289 VALUE segments = rb_ary_new();
12290 op = rb_to_array_type(op);
12291
12292 for (int i = 0; i < RARRAY_LEN(op); i++) {
12293 VALUE sym = RARRAY_AREF(op, i);
12294 sym = rb_to_symbol_type(sym);
12295 rb_ary_push(segments, sym);
12296 }
12297
12298 RB_GC_GUARD(op);
12299 argv[j] = segments;
12300 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12301 ISEQ_BODY(iseq)->ic_size++;
12302 }
12303 break;
12304 case TS_IVC: /* inline ivar cache */
12305 argv[j] = op;
12306 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12307 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12308 }
12309 break;
12310 case TS_ICVARC: /* inline cvar cache */
12311 argv[j] = op;
12312 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12313 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12314 }
12315 break;
12316 case TS_CALLDATA:
12317 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12318 break;
12319 case TS_ID:
12320 argv[j] = rb_to_symbol_type(op);
12321 break;
12322 case TS_CDHASH:
12323 {
12324 int i;
12325 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12326
12327 op = rb_to_array_type(op);
12328 for (i=0; i<RARRAY_LEN(op); i+=2) {
12329 VALUE key = RARRAY_AREF(op, i);
12330 VALUE sym = RARRAY_AREF(op, i+1);
12331 LABEL *label =
12332 register_label(iseq, labels_table, sym);
12333 cdhash_aset(map, key, (VALUE)label);
12334 }
12335 RB_GC_GUARD(op);
12336 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12337 argv[j] = map;
12338 RB_OBJ_WRITTEN(iseq, Qundef, map);
12339 }
12340 break;
12341 case TS_FUNCPTR:
12342 {
12343#if SIZEOF_VALUE <= SIZEOF_LONG
12344 long funcptr = NUM2LONG(op);
12345#else
12346 LONG_LONG funcptr = NUM2LL(op);
12347#endif
12348 argv[j] = (VALUE)funcptr;
12349 }
12350 break;
12351 default:
12352 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12353 }
12354 }
12355 }
12356 else {
12357 ADD_ELEM(anchor,
12358 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12359 (enum ruby_vminsn_type)insn_id, argc, NULL));
12360 }
12361 }
12362 else {
12363 rb_raise(rb_eTypeError, "unexpected object for instruction");
12364 }
12365 }
12366 RTYPEDDATA_DATA(labels_wrapper) = 0;
12367 RB_GC_GUARD(labels_wrapper);
12368 validate_labels(iseq, labels_table);
12369 if (!ret) return ret;
12370 return iseq_setup(iseq, anchor);
12371}
12372
12373#define CHECK_ARRAY(v) rb_to_array_type(v)
12374#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12375
12376static int
12377int_param(int *dst, VALUE param, VALUE sym)
12378{
12379 VALUE val = rb_hash_aref(param, sym);
12380 if (FIXNUM_P(val)) {
12381 *dst = FIX2INT(val);
12382 return TRUE;
12383 }
12384 else if (!NIL_P(val)) {
12385 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12386 sym, val);
12387 }
12388 return FALSE;
12389}
12390
12391static const struct rb_iseq_param_keyword *
12392iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12393{
12394 int i, j;
12395 int len = RARRAY_LENINT(keywords);
12396 int default_len;
12397 VALUE key, sym, default_val;
12398 VALUE *dvs;
12399 ID *ids;
12400 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12401
12402 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12403
12404 keyword->num = len;
12405#define SYM(s) ID2SYM(rb_intern_const(#s))
12406 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12407 i = keyword->bits_start - keyword->num;
12408 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12409#undef SYM
12410
12411 /* required args */
12412 for (i = 0; i < len; i++) {
12413 VALUE val = RARRAY_AREF(keywords, i);
12414
12415 if (!SYMBOL_P(val)) {
12416 goto default_values;
12417 }
12418 ids[i] = SYM2ID(val);
12419 keyword->required_num++;
12420 }
12421
12422 default_values: /* note: we intentionally preserve `i' from previous loop */
12423 default_len = len - i;
12424 if (default_len == 0) {
12425 keyword->table = ids;
12426 return keyword;
12427 }
12428 else if (default_len < 0) {
12430 }
12431
12432 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12433
12434 for (j = 0; i < len; i++, j++) {
12435 key = RARRAY_AREF(keywords, i);
12436 CHECK_ARRAY(key);
12437
12438 switch (RARRAY_LEN(key)) {
12439 case 1:
12440 sym = RARRAY_AREF(key, 0);
12441 default_val = Qundef;
12442 break;
12443 case 2:
12444 sym = RARRAY_AREF(key, 0);
12445 default_val = RARRAY_AREF(key, 1);
12446 break;
12447 default:
12448 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12449 }
12450 ids[i] = SYM2ID(sym);
12451 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12452 }
12453
12454 keyword->table = ids;
12455 keyword->default_values = dvs;
12456
12457 return keyword;
12458}
12459
12460static void
12461iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12462{
12463 rb_gc_mark_and_move(obj);
12464}
12465
12466void
12467rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12468{
12469 INSN *iobj = 0;
12470 size_t size = sizeof(INSN);
12471 size_t align = ALIGNMENT_SIZE_OF(INSN);
12472 unsigned int pos = 0;
12473
12474 while (storage) {
12475 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12476 size_t offset = pos + size + padding;
12477 if (offset > storage->size || offset > storage->pos) {
12478 pos = 0;
12479 storage = storage->next;
12480 }
12481 else {
12482 pos += (int)padding;
12483
12484 iobj = (INSN *)&storage->buff[pos];
12485
12486 if (iobj->operands) {
12487 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12488 }
12489 pos += (int)size;
12490 }
12491 }
12492}
12493
12494static const rb_data_type_t labels_wrapper_type = {
12495 .wrap_struct_name = "compiler/labels_wrapper",
12496 .function = {
12497 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12498 .dfree = (RUBY_DATA_FUNC)st_free_table,
12499 },
12500 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12501};
12502
12503void
12504rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12505 VALUE exception, VALUE body)
12506{
12507#define SYM(s) ID2SYM(rb_intern_const(#s))
12508 int i, len;
12509 unsigned int arg_size, local_size, stack_max;
12510 ID *tbl;
12511 struct st_table *labels_table = st_init_numtable();
12512 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12513 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12514 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12515 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12516 DECL_ANCHOR(anchor);
12517 INIT_ANCHOR(anchor);
12518
12519 len = RARRAY_LENINT(locals);
12520 ISEQ_BODY(iseq)->local_table_size = len;
12521 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12522
12523 for (i = 0; i < len; i++) {
12524 VALUE lv = RARRAY_AREF(locals, i);
12525
12526 if (sym_arg_rest == lv) {
12527 tbl[i] = 0;
12528 }
12529 else {
12530 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12531 }
12532 }
12533
12534#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12535 if (INT_PARAM(lead_num)) {
12536 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12537 }
12538 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12539 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12540 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12541 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12542#undef INT_PARAM
12543 {
12544#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12545 int x;
12546 INT_PARAM(arg_size);
12547 INT_PARAM(local_size);
12548 INT_PARAM(stack_max);
12549#undef INT_PARAM
12550 }
12551
12552 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12553 if (!NIL_P(source_hash)) {
12554 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12555 }
12556
12557 VALUE node_ids = Qfalse;
12558#ifdef USE_ISEQ_NODE_ID
12559 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12560 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12561 rb_raise(rb_eTypeError, "node_ids is not an array");
12562 }
12563#endif
12564
12565 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12566 len = RARRAY_LENINT(arg_opt_labels);
12567 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12568
12569 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12570 VALUE *opt_table = ALLOC_N(VALUE, len);
12571
12572 for (i = 0; i < len; i++) {
12573 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12574 LABEL *label = register_label(iseq, labels_table, ent);
12575 opt_table[i] = (VALUE)label;
12576 }
12577
12578 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12579 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12580 }
12581 }
12582 else if (!NIL_P(arg_opt_labels)) {
12583 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12584 arg_opt_labels);
12585 }
12586
12587 if (RB_TYPE_P(keywords, T_ARRAY)) {
12588 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12589 }
12590 else if (!NIL_P(keywords)) {
12591 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12592 keywords);
12593 }
12594
12595 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12596 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12597 }
12598
12599 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12600 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12601 }
12602
12603 if (int_param(&i, params, SYM(kwrest))) {
12604 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12605 if (keyword == NULL) {
12606 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12607 }
12608 keyword->rest_start = i;
12609 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12610 }
12611#undef SYM
12612 iseq_calc_param_size(iseq);
12613
12614 /* exception */
12615 iseq_build_from_ary_exception(iseq, labels_table, exception);
12616
12617 /* body */
12618 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12619
12620 ISEQ_BODY(iseq)->param.size = arg_size;
12621 ISEQ_BODY(iseq)->local_table_size = local_size;
12622 ISEQ_BODY(iseq)->stack_max = stack_max;
12623}
12624
12625/* for parser */
12626
12627int
12628rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12629{
12630 if (iseq) {
12631 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12632 while (body->type == ISEQ_TYPE_BLOCK ||
12633 body->type == ISEQ_TYPE_RESCUE ||
12634 body->type == ISEQ_TYPE_ENSURE ||
12635 body->type == ISEQ_TYPE_EVAL ||
12636 body->type == ISEQ_TYPE_MAIN
12637 ) {
12638 unsigned int i;
12639
12640 for (i = 0; i < body->local_table_size; i++) {
12641 if (body->local_table[i] == id) {
12642 return 1;
12643 }
12644 }
12645 iseq = body->parent_iseq;
12646 body = ISEQ_BODY(iseq);
12647 }
12648 }
12649 return 0;
12650}
12651
12652int
12653rb_local_defined(ID id, const rb_iseq_t *iseq)
12654{
12655 if (iseq) {
12656 unsigned int i;
12657 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12658
12659 for (i=0; i<body->local_table_size; i++) {
12660 if (body->local_table[i] == id) {
12661 return 1;
12662 }
12663 }
12664 }
12665 return 0;
12666}
12667
12668/* ISeq binary format */
12669
12670#ifndef IBF_ISEQ_DEBUG
12671#define IBF_ISEQ_DEBUG 0
12672#endif
12673
12674#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12675#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12676#endif
12677
12678typedef uint32_t ibf_offset_t;
12679#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12680
12681#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12682#ifdef RUBY_DEVEL
12683#define IBF_DEVEL_VERSION 7
12684#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12685#else
12686#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12687#endif
12688
12689static const char IBF_ENDIAN_MARK =
12690#ifdef WORDS_BIGENDIAN
12691 'b'
12692#else
12693 'l'
12694#endif
12695 ;
12696
12698 char magic[4]; /* YARB */
12699 uint32_t major_version;
12700 uint32_t minor_version;
12701 uint32_t size;
12702 uint32_t extra_size;
12703
12704 uint32_t iseq_list_size;
12705 uint32_t global_object_list_size;
12706 ibf_offset_t iseq_list_offset;
12707 ibf_offset_t global_object_list_offset;
12708 uint8_t endian;
12709 uint8_t wordsize; /* assume no 2048-bit CPU */
12710};
12711
12713 VALUE str;
12714 st_table *obj_table; /* obj -> obj number */
12715};
12716
12717struct ibf_dump {
12718 st_table *iseq_table; /* iseq -> iseq number */
12719 struct ibf_dump_buffer global_buffer;
12720 struct ibf_dump_buffer *current_buffer;
12721};
12722
12724 const char *buff;
12725 ibf_offset_t size;
12726
12727 VALUE obj_list; /* [obj0, ...] */
12728 unsigned int obj_list_size;
12729 ibf_offset_t obj_list_offset;
12730};
12731
12732struct ibf_load {
12733 const struct ibf_header *header;
12734 VALUE iseq_list; /* [iseq0, ...] */
12735 struct ibf_load_buffer global_buffer;
12736 VALUE loader_obj;
12737 rb_iseq_t *iseq;
12738 VALUE str;
12739 struct ibf_load_buffer *current_buffer;
12740};
12741
12743 long size;
12744 VALUE buffer[1];
12745};
12746
12747static void
12748pinned_list_mark(void *ptr)
12749{
12750 long i;
12751 struct pinned_list *list = (struct pinned_list *)ptr;
12752 for (i = 0; i < list->size; i++) {
12753 if (list->buffer[i]) {
12754 rb_gc_mark(list->buffer[i]);
12755 }
12756 }
12757}
12758
12759static const rb_data_type_t pinned_list_type = {
12760 "pinned_list",
12761 {
12762 pinned_list_mark,
12764 NULL, // No external memory to report,
12765 },
12766 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12767};
12768
12769static VALUE
12770pinned_list_fetch(VALUE list, long offset)
12771{
12772 struct pinned_list * ptr;
12773
12774 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12775
12776 if (offset < 0 || offset >= ptr->size) {
12777 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12778 }
12779
12780 return ptr->buffer[offset];
12781}
12782
12783static void
12784pinned_list_store(VALUE list, long offset, VALUE object)
12785{
12786 struct pinned_list * ptr;
12787
12788 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12789
12790 if (offset < 0 || offset >= ptr->size) {
12791 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12792 }
12793
12794 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12795}
12796
12797static VALUE
12798pinned_list_new(long size)
12799{
12800 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12801 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12802 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12803 ptr->size = size;
12804 return obj_list;
12805}
12806
12807static ibf_offset_t
12808ibf_dump_pos(struct ibf_dump *dump)
12809{
12810 long pos = RSTRING_LEN(dump->current_buffer->str);
12811#if SIZEOF_LONG > SIZEOF_INT
12812 if (pos >= UINT_MAX) {
12813 rb_raise(rb_eRuntimeError, "dump size exceeds");
12814 }
12815#endif
12816 return (unsigned int)pos;
12817}
12818
12819static void
12820ibf_dump_align(struct ibf_dump *dump, size_t align)
12821{
12822 ibf_offset_t pos = ibf_dump_pos(dump);
12823 if (pos % align) {
12824 static const char padding[sizeof(VALUE)];
12825 size_t size = align - ((size_t)pos % align);
12826#if SIZEOF_LONG > SIZEOF_INT
12827 if (pos + size >= UINT_MAX) {
12828 rb_raise(rb_eRuntimeError, "dump size exceeds");
12829 }
12830#endif
12831 for (; size > sizeof(padding); size -= sizeof(padding)) {
12832 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12833 }
12834 rb_str_cat(dump->current_buffer->str, padding, size);
12835 }
12836}
12837
12838static ibf_offset_t
12839ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12840{
12841 ibf_offset_t pos = ibf_dump_pos(dump);
12842#if SIZEOF_LONG > SIZEOF_INT
12843 /* ensure the resulting dump does not exceed UINT_MAX */
12844 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12845 rb_raise(rb_eRuntimeError, "dump size exceeds");
12846 }
12847#endif
12848 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12849 return pos;
12850}
12851
12852static ibf_offset_t
12853ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12854{
12855 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12856}
12857
12858static void
12859ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12860{
12861 VALUE str = dump->current_buffer->str;
12862 char *ptr = RSTRING_PTR(str);
12863 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12864 rb_bug("ibf_dump_overwrite: overflow");
12865 memcpy(ptr + offset, buff, size);
12866}
12867
12868static const void *
12869ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12870{
12871 ibf_offset_t beg = *offset;
12872 *offset += size;
12873 return load->current_buffer->buff + beg;
12874}
12875
12876static void *
12877ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12878{
12879 void *buff = ruby_xmalloc2(x, y);
12880 size_t size = x * y;
12881 memcpy(buff, load->current_buffer->buff + offset, size);
12882 return buff;
12883}
12884
12885#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12886
12887#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12888#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12889#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12890#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12891#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12892
12893static int
12894ibf_table_lookup(struct st_table *table, st_data_t key)
12895{
12896 st_data_t val;
12897
12898 if (st_lookup(table, key, &val)) {
12899 return (int)val;
12900 }
12901 else {
12902 return -1;
12903 }
12904}
12905
12906static int
12907ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12908{
12909 int index = ibf_table_lookup(table, key);
12910
12911 if (index < 0) { /* not found */
12912 index = (int)table->num_entries;
12913 st_insert(table, key, (st_data_t)index);
12914 }
12915
12916 return index;
12917}
12918
12919/* dump/load generic */
12920
12921static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12922
12923static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12924static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12925
12926static st_table *
12927ibf_dump_object_table_new(void)
12928{
12929 st_table *obj_table = st_init_numtable(); /* need free */
12930 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12931
12932 return obj_table;
12933}
12934
12935static VALUE
12936ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12937{
12938 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12939}
12940
12941static VALUE
12942ibf_dump_id(struct ibf_dump *dump, ID id)
12943{
12944 if (id == 0 || rb_id2name(id) == NULL) {
12945 return 0;
12946 }
12947 return ibf_dump_object(dump, rb_id2sym(id));
12948}
12949
12950static ID
12951ibf_load_id(const struct ibf_load *load, const ID id_index)
12952{
12953 if (id_index == 0) {
12954 return 0;
12955 }
12956 VALUE sym = ibf_load_object(load, id_index);
12957 if (rb_integer_type_p(sym)) {
12958 /* Load hidden local variables as indexes */
12959 return NUM2ULONG(sym);
12960 }
12961 return rb_sym2id(sym);
12962}
12963
12964/* dump/load: code */
12965
12966static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12967
12968static int
12969ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12970{
12971 if (iseq == NULL) {
12972 return -1;
12973 }
12974 else {
12975 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12976 }
12977}
12978
12979static unsigned char
12980ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12981{
12982 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12983 return (unsigned char)load->current_buffer->buff[(*offset)++];
12984}
12985
12986/*
12987 * Small uint serialization
12988 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12989 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12990 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12991 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12992 * ...
12993 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12994 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12995 */
12996static void
12997ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12998{
12999 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13000 ibf_dump_write(dump, &x, sizeof(VALUE));
13001 return;
13002 }
13003
13004 enum { max_byte_length = sizeof(VALUE) + 1 };
13005
13006 unsigned char bytes[max_byte_length];
13007 ibf_offset_t n;
13008
13009 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13010 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13011 }
13012
13013 x <<= 1;
13014 x |= 1;
13015 x <<= n;
13016 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13017 n++;
13018
13019 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13020}
13021
13022static VALUE
13023ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13024{
13025 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13026 union { char s[sizeof(VALUE)]; VALUE v; } x;
13027
13028 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13029 *offset += sizeof(VALUE);
13030
13031 return x.v;
13032 }
13033
13034 enum { max_byte_length = sizeof(VALUE) + 1 };
13035
13036 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13037 const unsigned char c = buffer[*offset];
13038
13039 ibf_offset_t n =
13040 c & 1 ? 1 :
13041 c == 0 ? 9 : ntz_int32(c) + 1;
13042 VALUE x = (VALUE)c >> n;
13043
13044 if (*offset + n > load->current_buffer->size) {
13045 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13046 }
13047
13048 ibf_offset_t i;
13049 for (i = 1; i < n; i++) {
13050 x <<= 8;
13051 x |= (VALUE)buffer[*offset + i];
13052 }
13053
13054 *offset += n;
13055 return x;
13056}
13057
13058static void
13059ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13060{
13061 // short: index
13062 // short: name.length
13063 // bytes: name
13064 // // omit argc (only verify with name)
13065 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13066
13067 size_t len = strlen(bf->name);
13068 ibf_dump_write_small_value(dump, (VALUE)len);
13069 ibf_dump_write(dump, bf->name, len);
13070}
13071
13072static const struct rb_builtin_function *
13073ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13074{
13075 int i = (int)ibf_load_small_value(load, offset);
13076 int len = (int)ibf_load_small_value(load, offset);
13077 const char *name = (char *)ibf_load_ptr(load, offset, len);
13078
13079 if (0) {
13080 fprintf(stderr, "%.*s!!\n", len, name);
13081 }
13082
13083 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13084 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13085 if (strncmp(table[i].name, name, len) != 0) {
13086 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13087 i, len, name, table[i].name);
13088 }
13089 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13090
13091 return &table[i];
13092}
13093
13094static ibf_offset_t
13095ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13096{
13097 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13098 const int iseq_size = body->iseq_size;
13099 int code_index;
13100 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13101
13102 ibf_offset_t offset = ibf_dump_pos(dump);
13103
13104 for (code_index=0; code_index<iseq_size;) {
13105 const VALUE insn = orig_code[code_index++];
13106 const char *types = insn_op_types(insn);
13107 int op_index;
13108
13109 /* opcode */
13110 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13111 ibf_dump_write_small_value(dump, insn);
13112
13113 /* operands */
13114 for (op_index=0; types[op_index]; op_index++, code_index++) {
13115 VALUE op = orig_code[code_index];
13116 VALUE wv;
13117
13118 switch (types[op_index]) {
13119 case TS_CDHASH:
13120 case TS_VALUE:
13121 wv = ibf_dump_object(dump, op);
13122 break;
13123 case TS_ISEQ:
13124 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13125 break;
13126 case TS_IC:
13127 {
13128 IC ic = (IC)op;
13129 VALUE arr = idlist_to_array(ic->segments);
13130 wv = ibf_dump_object(dump, arr);
13131 }
13132 break;
13133 case TS_ISE:
13134 case TS_IVC:
13135 case TS_ICVARC:
13136 {
13138 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13139 }
13140 break;
13141 case TS_CALLDATA:
13142 {
13143 goto skip_wv;
13144 }
13145 case TS_ID:
13146 wv = ibf_dump_id(dump, (ID)op);
13147 break;
13148 case TS_FUNCPTR:
13149 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13150 goto skip_wv;
13151 case TS_BUILTIN:
13152 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13153 goto skip_wv;
13154 default:
13155 wv = op;
13156 break;
13157 }
13158 ibf_dump_write_small_value(dump, wv);
13159 skip_wv:;
13160 }
13161 RUBY_ASSERT(insn_len(insn) == op_index+1);
13162 }
13163
13164 return offset;
13165}
13166
13167static VALUE *
13168ibf_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)
13169{
13170 VALUE iseqv = (VALUE)iseq;
13171 unsigned int code_index;
13172 ibf_offset_t reading_pos = bytecode_offset;
13173 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13174
13175 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13176 struct rb_call_data *cd_entries = load_body->call_data;
13177 int ic_index = 0;
13178
13179 load_body->iseq_encoded = code;
13180 load_body->iseq_size = iseq_size;
13181
13182 iseq_bits_t * mark_offset_bits;
13183 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13184 load_body->mark_bits.single = 0;
13185 mark_offset_bits = &load_body->mark_bits.single;
13186 }
13187 else {
13188 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13189 mark_offset_bits = load_body->mark_bits.list;
13190 }
13191 bool needs_bitmap = false;
13192
13193 for (code_index=0; code_index<iseq_size;) {
13194 /* opcode */
13195 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13196 const char *types = insn_op_types(insn);
13197 int op_index;
13198
13199 code_index++;
13200
13201 /* operands */
13202 for (op_index=0; types[op_index]; op_index++, code_index++) {
13203 const char operand_type = types[op_index];
13204 switch (operand_type) {
13205 case TS_VALUE:
13206 {
13207 VALUE op = ibf_load_small_value(load, &reading_pos);
13208 VALUE v = ibf_load_object(load, op);
13209 code[code_index] = v;
13210 if (!SPECIAL_CONST_P(v)) {
13211 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13212 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13213 needs_bitmap = true;
13214 }
13215 break;
13216 }
13217 case TS_CDHASH:
13218 {
13219 VALUE op = ibf_load_small_value(load, &reading_pos);
13220 VALUE v = ibf_load_object(load, op);
13221
13222 // Overwrite the existing hash in the object list. This
13223 // is to keep the object alive during load time.
13224 // [Bug #17984] [ruby-core:104259]
13225 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13226
13227 code[code_index] = v;
13228 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13229 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13230 needs_bitmap = true;
13231 break;
13232 }
13233 case TS_ISEQ:
13234 {
13235 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13236 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13237 code[code_index] = v;
13238 if (!SPECIAL_CONST_P(v)) {
13239 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13240 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13241 needs_bitmap = true;
13242 }
13243 break;
13244 }
13245 case TS_IC:
13246 {
13247 VALUE op = ibf_load_small_value(load, &reading_pos);
13248 VALUE arr = ibf_load_object(load, op);
13249
13250 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13251 ic->segments = array_to_idlist(arr);
13252
13253 code[code_index] = (VALUE)ic;
13254 }
13255 break;
13256 case TS_ISE:
13257 case TS_ICVARC:
13258 case TS_IVC:
13259 {
13260 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13261
13262 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13263 code[code_index] = (VALUE)ic;
13264
13265 if (operand_type == TS_IVC) {
13266 IVC cache = (IVC)ic;
13267
13268 if (insn == BIN(setinstancevariable)) {
13269 ID iv_name = (ID)code[code_index - 1];
13270 cache->iv_set_name = iv_name;
13271 cache->value = IVAR_CACHE_INIT;
13272 }
13273 else {
13274 cache->iv_set_name = 0;
13275 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13276 }
13277 }
13278
13279 }
13280 break;
13281 case TS_CALLDATA:
13282 {
13283 code[code_index] = (VALUE)cd_entries++;
13284 }
13285 break;
13286 case TS_ID:
13287 {
13288 VALUE op = ibf_load_small_value(load, &reading_pos);
13289 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13290 }
13291 break;
13292 case TS_FUNCPTR:
13293 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13294 break;
13295 case TS_BUILTIN:
13296 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13297 break;
13298 default:
13299 code[code_index] = ibf_load_small_value(load, &reading_pos);
13300 continue;
13301 }
13302 }
13303 if (insn_len(insn) != op_index+1) {
13304 rb_raise(rb_eRuntimeError, "operand size mismatch");
13305 }
13306 }
13307
13308 if (!needs_bitmap) {
13309 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13310 load_body->mark_bits.list = NULL;
13311 }
13312
13313 RUBY_ASSERT(code_index == iseq_size);
13314 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13315 return code;
13316}
13317
13318static ibf_offset_t
13319ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13320{
13321 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13322
13323 if (opt_num > 0) {
13324 IBF_W_ALIGN(VALUE);
13325 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13326 }
13327 else {
13328 return ibf_dump_pos(dump);
13329 }
13330}
13331
13332static VALUE *
13333ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13334{
13335 if (opt_num > 0) {
13336 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13337 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13338 return table;
13339 }
13340 else {
13341 return NULL;
13342 }
13343}
13344
13345static ibf_offset_t
13346ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13347{
13348 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13349
13350 if (kw) {
13351 struct rb_iseq_param_keyword dump_kw = *kw;
13352 int dv_num = kw->num - kw->required_num;
13353 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13354 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13355 int i;
13356
13357 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13358 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13359
13360 dump_kw.table = IBF_W(ids, ID, kw->num);
13361 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13362 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13363 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13364 }
13365 else {
13366 return 0;
13367 }
13368}
13369
13370static const struct rb_iseq_param_keyword *
13371ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13372{
13373 if (param_keyword_offset) {
13374 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13375 int dv_num = kw->num - kw->required_num;
13376 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13377
13378 int i;
13379 for (i=0; i<dv_num; i++) {
13380 dvs[i] = ibf_load_object(load, dvs[i]);
13381 }
13382
13383 // Will be set once the local table is loaded.
13384 kw->table = NULL;
13385
13386 kw->default_values = dvs;
13387 return kw;
13388 }
13389 else {
13390 return NULL;
13391 }
13392}
13393
13394static ibf_offset_t
13395ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13396{
13397 ibf_offset_t offset = ibf_dump_pos(dump);
13398 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13399
13400 unsigned int i;
13401 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13402 ibf_dump_write_small_value(dump, entries[i].line_no);
13403#ifdef USE_ISEQ_NODE_ID
13404 ibf_dump_write_small_value(dump, entries[i].node_id);
13405#endif
13406 ibf_dump_write_small_value(dump, entries[i].events);
13407 }
13408
13409 return offset;
13410}
13411
13412static struct iseq_insn_info_entry *
13413ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13414{
13415 ibf_offset_t reading_pos = body_offset;
13416 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13417
13418 unsigned int i;
13419 for (i = 0; i < size; i++) {
13420 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13421#ifdef USE_ISEQ_NODE_ID
13422 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13423#endif
13424 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13425 }
13426
13427 return entries;
13428}
13429
13430static ibf_offset_t
13431ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13432{
13433 ibf_offset_t offset = ibf_dump_pos(dump);
13434
13435 unsigned int last = 0;
13436 unsigned int i;
13437 for (i = 0; i < size; i++) {
13438 ibf_dump_write_small_value(dump, positions[i] - last);
13439 last = positions[i];
13440 }
13441
13442 return offset;
13443}
13444
13445static unsigned int *
13446ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13447{
13448 ibf_offset_t reading_pos = positions_offset;
13449 unsigned int *positions = ALLOC_N(unsigned int, size);
13450
13451 unsigned int last = 0;
13452 unsigned int i;
13453 for (i = 0; i < size; i++) {
13454 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13455 last = positions[i];
13456 }
13457
13458 return positions;
13459}
13460
13461static ibf_offset_t
13462ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13463{
13464 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13465 const int size = body->local_table_size;
13466 ID *table = ALLOCA_N(ID, size);
13467 int i;
13468
13469 for (i=0; i<size; i++) {
13470 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13471 if (v == 0) {
13472 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13473 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13474 }
13475 table[i] = v;
13476 }
13477
13478 IBF_W_ALIGN(ID);
13479 return ibf_dump_write(dump, table, sizeof(ID) * size);
13480}
13481
13482static const ID *
13483ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13484{
13485 if (size > 0) {
13486 ID *table = IBF_R(local_table_offset, ID, size);
13487 int i;
13488
13489 for (i=0; i<size; i++) {
13490 table[i] = ibf_load_id(load, table[i]);
13491 }
13492
13493 if (size == 1 && table[0] == idERROR_INFO) {
13494 ruby_xfree_sized(table, sizeof(ID) * size);
13495 return rb_iseq_shared_exc_local_tbl;
13496 }
13497 else {
13498 return table;
13499 }
13500 }
13501 else {
13502 return NULL;
13503 }
13504}
13505
13506static ibf_offset_t
13507ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13508{
13509 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13510 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13511 IBF_W_ALIGN(uint8_t);
13512 return ibf_dump_write(dump, body->lvar_states, sizeof(uint8_t) * (body->lvar_states ? size : 0));
13513}
13514
13515static uint8_t *
13516ibf_load_lvar_states(const struct ibf_load *load, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13517{
13518 if (local_table == rb_iseq_shared_exc_local_tbl ||
13519 size <= 0) {
13520 return NULL;
13521 }
13522 else {
13523 uint8_t *states = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13524 return states;
13525 }
13526}
13527
13528static ibf_offset_t
13529ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13530{
13531 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13532
13533 if (table) {
13534 int *iseq_indices = ALLOCA_N(int, table->size);
13535 unsigned int i;
13536
13537 for (i=0; i<table->size; i++) {
13538 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13539 }
13540
13541 const ibf_offset_t offset = ibf_dump_pos(dump);
13542
13543 for (i=0; i<table->size; i++) {
13544 ibf_dump_write_small_value(dump, iseq_indices[i]);
13545 ibf_dump_write_small_value(dump, table->entries[i].type);
13546 ibf_dump_write_small_value(dump, table->entries[i].start);
13547 ibf_dump_write_small_value(dump, table->entries[i].end);
13548 ibf_dump_write_small_value(dump, table->entries[i].cont);
13549 ibf_dump_write_small_value(dump, table->entries[i].sp);
13550 }
13551 return offset;
13552 }
13553 else {
13554 return ibf_dump_pos(dump);
13555 }
13556}
13557
13558static void
13559ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13560{
13561 if (size) {
13562 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13563 table->size = size;
13564 ISEQ_BODY(parent_iseq)->catch_table = table;
13565
13566 ibf_offset_t reading_pos = catch_table_offset;
13567
13568 unsigned int i;
13569 for (i=0; i<table->size; i++) {
13570 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13571 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13572 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13573 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13574 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13575 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13576
13577 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13578 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13579 }
13580 }
13581 else {
13582 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13583 }
13584}
13585
13586static ibf_offset_t
13587ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13588{
13589 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13590 const unsigned int ci_size = body->ci_size;
13591 const struct rb_call_data *cds = body->call_data;
13592
13593 ibf_offset_t offset = ibf_dump_pos(dump);
13594
13595 unsigned int i;
13596
13597 for (i = 0; i < ci_size; i++) {
13598 const struct rb_callinfo *ci = cds[i].ci;
13599 if (ci != NULL) {
13600 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13601 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13602 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13603
13604 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13605 if (kwarg) {
13606 int len = kwarg->keyword_len;
13607 ibf_dump_write_small_value(dump, len);
13608 for (int j=0; j<len; j++) {
13609 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13610 ibf_dump_write_small_value(dump, keyword);
13611 }
13612 }
13613 else {
13614 ibf_dump_write_small_value(dump, 0);
13615 }
13616 }
13617 else {
13618 // TODO: truncate NULL ci from call_data.
13619 ibf_dump_write_small_value(dump, (VALUE)-1);
13620 }
13621 }
13622
13623 return offset;
13624}
13625
13627 ID id;
13628 VALUE name;
13629 VALUE val;
13630};
13631
13633 size_t num;
13634 struct outer_variable_pair pairs[1];
13635};
13636
13637static enum rb_id_table_iterator_result
13638store_outer_variable(ID id, VALUE val, void *dump)
13639{
13640 struct outer_variable_list *ovlist = dump;
13641 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13642 pair->id = id;
13643 pair->name = rb_id2str(id);
13644 pair->val = val;
13645 return ID_TABLE_CONTINUE;
13646}
13647
13648static int
13649outer_variable_cmp(const void *a, const void *b, void *arg)
13650{
13651 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13652 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13653
13654 if (!ap->name) {
13655 return -1;
13656 }
13657 else if (!bp->name) {
13658 return 1;
13659 }
13660
13661 return rb_str_cmp(ap->name, bp->name);
13662}
13663
13664static ibf_offset_t
13665ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13666{
13667 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13668
13669 ibf_offset_t offset = ibf_dump_pos(dump);
13670
13671 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13672 ibf_dump_write_small_value(dump, (VALUE)size);
13673 if (size > 0) {
13674 VALUE buff;
13675 size_t buffsize =
13676 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13677 offsetof(struct outer_variable_list, pairs),
13678 rb_eArgError);
13679 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13680 ovlist->num = 0;
13681 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13682 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13683 for (size_t i = 0; i < size; ++i) {
13684 ID id = ovlist->pairs[i].id;
13685 ID val = ovlist->pairs[i].val;
13686 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13687 ibf_dump_write_small_value(dump, val);
13688 }
13689 }
13690
13691 return offset;
13692}
13693
13694/* note that we dump out rb_call_info but load back rb_call_data */
13695static void
13696ibf_load_ci_entries(const struct ibf_load *load,
13697 ibf_offset_t ci_entries_offset,
13698 unsigned int ci_size,
13699 struct rb_call_data **cd_ptr)
13700{
13701 if (!ci_size) {
13702 *cd_ptr = NULL;
13703 return;
13704 }
13705
13706 ibf_offset_t reading_pos = ci_entries_offset;
13707
13708 unsigned int i;
13709
13710 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13711 *cd_ptr = cds;
13712
13713 for (i = 0; i < ci_size; i++) {
13714 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13715 if (mid_index != (VALUE)-1) {
13716 ID mid = ibf_load_id(load, mid_index);
13717 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13718 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13719
13720 struct rb_callinfo_kwarg *kwarg = NULL;
13721 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13722 if (kwlen > 0) {
13723 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13724 kwarg->references = 0;
13725 kwarg->keyword_len = kwlen;
13726 for (int j=0; j<kwlen; j++) {
13727 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13728 kwarg->keywords[j] = ibf_load_object(load, keyword);
13729 }
13730 }
13731
13732 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13733 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13734 cds[i].cc = vm_cc_empty();
13735 }
13736 else {
13737 // NULL ci
13738 cds[i].ci = NULL;
13739 cds[i].cc = NULL;
13740 }
13741 }
13742}
13743
13744static struct rb_id_table *
13745ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13746{
13747 ibf_offset_t reading_pos = outer_variables_offset;
13748
13749 struct rb_id_table *tbl = NULL;
13750
13751 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13752
13753 if (table_size > 0) {
13754 tbl = rb_id_table_create(table_size);
13755 }
13756
13757 for (size_t i = 0; i < table_size; i++) {
13758 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13759 VALUE value = ibf_load_small_value(load, &reading_pos);
13760 if (!key) key = rb_make_temporary_id(i);
13761 rb_id_table_insert(tbl, key, value);
13762 }
13763
13764 return tbl;
13765}
13766
13767static ibf_offset_t
13768ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13769{
13770 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13771
13772 unsigned int *positions;
13773
13774 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13775
13776 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13777 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13778 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13779
13780#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13781 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13782
13783 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13784 struct ibf_dump_buffer buffer;
13785 buffer.str = rb_str_new(0, 0);
13786 buffer.obj_table = ibf_dump_object_table_new();
13787 dump->current_buffer = &buffer;
13788#endif
13789
13790 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13791 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13792 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13793 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13794 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13795
13796 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13797 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13798 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13799
13800 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13801 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13802 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13803 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13804 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13805 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13806 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13807 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13808 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13809 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13810
13811#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13812 ibf_offset_t local_obj_list_offset;
13813 unsigned int local_obj_list_size;
13814
13815 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13816#endif
13817
13818 ibf_offset_t body_offset = ibf_dump_pos(dump);
13819
13820 /* dump the constant body */
13821 unsigned int param_flags =
13822 (body->param.flags.has_lead << 0) |
13823 (body->param.flags.has_opt << 1) |
13824 (body->param.flags.has_rest << 2) |
13825 (body->param.flags.has_post << 3) |
13826 (body->param.flags.has_kw << 4) |
13827 (body->param.flags.has_kwrest << 5) |
13828 (body->param.flags.has_block << 6) |
13829 (body->param.flags.ambiguous_param0 << 7) |
13830 (body->param.flags.accepts_no_kwarg << 8) |
13831 (body->param.flags.ruby2_keywords << 9) |
13832 (body->param.flags.anon_rest << 10) |
13833 (body->param.flags.anon_kwrest << 11) |
13834 (body->param.flags.use_block << 12) |
13835 (body->param.flags.forwardable << 13) |
13836 (body->param.flags.accepts_no_block << 14);
13837
13838#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13839# define IBF_BODY_OFFSET(x) (x)
13840#else
13841# define IBF_BODY_OFFSET(x) (body_offset - (x))
13842#endif
13843
13844 ibf_dump_write_small_value(dump, body->type);
13845 ibf_dump_write_small_value(dump, body->iseq_size);
13846 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13847 ibf_dump_write_small_value(dump, bytecode_size);
13848 ibf_dump_write_small_value(dump, param_flags);
13849 ibf_dump_write_small_value(dump, body->param.size);
13850 ibf_dump_write_small_value(dump, body->param.lead_num);
13851 ibf_dump_write_small_value(dump, body->param.opt_num);
13852 ibf_dump_write_small_value(dump, body->param.rest_start);
13853 ibf_dump_write_small_value(dump, body->param.post_start);
13854 ibf_dump_write_small_value(dump, body->param.post_num);
13855 ibf_dump_write_small_value(dump, body->param.block_start);
13856 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13857 ibf_dump_write_small_value(dump, param_keyword_offset);
13858 ibf_dump_write_small_value(dump, location_pathobj_index);
13859 ibf_dump_write_small_value(dump, location_base_label_index);
13860 ibf_dump_write_small_value(dump, location_label_index);
13861 ibf_dump_write_small_value(dump, body->location.first_lineno);
13862 ibf_dump_write_small_value(dump, body->location.node_id);
13863 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
13864 * VALUE may be 32 bits wide. */
13865 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
13866 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
13867 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13868 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13869 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13870 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13871 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13872 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13873 ibf_dump_write_small_value(dump, body->insns_info.size);
13874 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13875 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13876 ibf_dump_write_small_value(dump, catch_table_size);
13877 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13878 ibf_dump_write_small_value(dump, parent_iseq_index);
13879 ibf_dump_write_small_value(dump, local_iseq_index);
13880 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13881 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13882 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13883 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
13884 ibf_dump_write_small_value(dump, body->local_table_size);
13885 ibf_dump_write_small_value(dump, body->ivc_size);
13886 ibf_dump_write_small_value(dump, body->icvarc_size);
13887 ibf_dump_write_small_value(dump, body->ise_size);
13888 ibf_dump_write_small_value(dump, body->ic_size);
13889 ibf_dump_write_small_value(dump, body->ci_size);
13890 ibf_dump_write_small_value(dump, body->stack_max);
13891 ibf_dump_write_small_value(dump, body->builtin_attrs);
13892 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13893
13894#undef IBF_BODY_OFFSET
13895
13896#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13897 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13898
13899 dump->current_buffer = saved_buffer;
13900 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13901
13902 ibf_offset_t offset = ibf_dump_pos(dump);
13903 ibf_dump_write_small_value(dump, iseq_start);
13904 ibf_dump_write_small_value(dump, iseq_length_bytes);
13905 ibf_dump_write_small_value(dump, body_offset);
13906
13907 ibf_dump_write_small_value(dump, local_obj_list_offset);
13908 ibf_dump_write_small_value(dump, local_obj_list_size);
13909
13910 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13911
13912 return offset;
13913#else
13914 return body_offset;
13915#endif
13916}
13917
13918static VALUE
13919ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13920{
13921 VALUE str = ibf_load_object(load, str_index);
13922 if (str != Qnil) {
13923 str = rb_fstring(str);
13924 }
13925 return str;
13926}
13927
13928static void
13929ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13930{
13931 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13932
13933 ibf_offset_t reading_pos = offset;
13934
13935#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13936 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13937 load->current_buffer = &load->global_buffer;
13938
13939 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13940 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13941 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13942
13943 struct ibf_load_buffer buffer;
13944 buffer.buff = load->global_buffer.buff + iseq_start;
13945 buffer.size = iseq_length_bytes;
13946 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13947 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13948 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13949
13950 load->current_buffer = &buffer;
13951 reading_pos = body_offset;
13952#endif
13953
13954#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13955# define IBF_BODY_OFFSET(x) (x)
13956#else
13957# define IBF_BODY_OFFSET(x) (offset - (x))
13958#endif
13959
13960 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13961 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13962 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13963 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13964 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13965 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13966 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13967 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13968 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13969 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13970 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13971 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13972 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13973 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13974 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13975 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13976 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13977 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13978 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13979 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
13980 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
13981 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
13982 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13983 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13984 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13985 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13986 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13987 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13988 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13989 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13990 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13991 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13992 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13993 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13994 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13995 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13996 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13997 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13998 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13999 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14000
14001 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14002 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14003 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14004 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14005
14006 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14007 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14008 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14009 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14010
14011 // setup fname and dummy frame
14012 VALUE path = ibf_load_object(load, location_pathobj_index);
14013 {
14014 VALUE realpath = Qnil;
14015
14016 if (RB_TYPE_P(path, T_STRING)) {
14017 realpath = path = rb_fstring(path);
14018 }
14019 else if (RB_TYPE_P(path, T_ARRAY)) {
14020 VALUE pathobj = path;
14021 if (RARRAY_LEN(pathobj) != 2) {
14022 rb_raise(rb_eRuntimeError, "path object size mismatch");
14023 }
14024 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14025 realpath = RARRAY_AREF(pathobj, 1);
14026 if (!NIL_P(realpath)) {
14027 if (!RB_TYPE_P(realpath, T_STRING)) {
14028 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14029 "(%x), path=%+"PRIsVALUE,
14030 realpath, TYPE(realpath), path);
14031 }
14032 realpath = rb_fstring(realpath);
14033 }
14034 }
14035 else {
14036 rb_raise(rb_eRuntimeError, "unexpected path object");
14037 }
14038 rb_iseq_pathobj_set(iseq, path, realpath);
14039 }
14040
14041 // push dummy frame
14042 rb_execution_context_t *ec = GET_EC();
14043 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14044
14045#undef IBF_BODY_OFFSET
14046
14047 load_body->type = type;
14048 load_body->stack_max = stack_max;
14049 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14050 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14051 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14052 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14053 load_body->param.flags.has_kw = FALSE;
14054 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14055 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14056 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14057 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14058 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14059 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14060 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14061 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14062 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14063 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14064 load_body->param.size = param_size;
14065 load_body->param.lead_num = param_lead_num;
14066 load_body->param.opt_num = param_opt_num;
14067 load_body->param.rest_start = param_rest_start;
14068 load_body->param.post_start = param_post_start;
14069 load_body->param.post_num = param_post_num;
14070 load_body->param.block_start = param_block_start;
14071 load_body->local_table_size = local_table_size;
14072 load_body->ci_size = ci_size;
14073 load_body->insns_info.size = insns_info_size;
14074
14075 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14076 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14077 if (variable_flip_count) {
14078 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14079 v->flip_count = variable_flip_count;
14080 }
14081
14082 load_body->location.first_lineno = location_first_lineno;
14083 load_body->location.node_id = location_node_id;
14084 load_body->source_hash = source_hash;
14085 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14086 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14087 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14088 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14089 load_body->builtin_attrs = builtin_attrs;
14090 load_body->prism = prism;
14091
14092 load_body->ivc_size = ivc_size;
14093 load_body->icvarc_size = icvarc_size;
14094 load_body->ise_size = ise_size;
14095 load_body->ic_size = ic_size;
14096
14097 if (ISEQ_IS_SIZE(load_body)) {
14098 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14099 }
14100 else {
14101 load_body->is_entries = NULL;
14102 }
14103 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14104 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14105 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14106 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14107 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14108 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
14109 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14110 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14111 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
14112 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14113
14114 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14115 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14116 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14117
14118 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14119 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14120 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14121
14122 // This must be done after the local table is loaded.
14123 if (load_body->param.keyword != NULL) {
14124 RUBY_ASSERT(load_body->local_table);
14125 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14126 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14127 }
14128
14129 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14130#if VM_INSN_INFO_TABLE_IMPL == 2
14131 rb_iseq_insns_info_encode_positions(iseq);
14132#endif
14133
14134 rb_iseq_translate_threaded_code(iseq);
14135
14136#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14137 load->current_buffer = &load->global_buffer;
14138#endif
14139
14140 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
14141 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14142
14143#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14144 load->current_buffer = saved_buffer;
14145#endif
14146 verify_call_cache(iseq);
14147
14148 RB_GC_GUARD(dummy_frame);
14149 rb_vm_pop_frame_no_int(ec);
14150}
14151
14153{
14154 struct ibf_dump *dump;
14155 VALUE offset_list;
14156};
14157
14158static int
14159ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14160{
14161 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14162 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14163
14164 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14165 rb_ary_push(args->offset_list, UINT2NUM(offset));
14166
14167 return ST_CONTINUE;
14168}
14169
14170static void
14171ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14172{
14173 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14174
14175 struct ibf_dump_iseq_list_arg args;
14176 args.dump = dump;
14177 args.offset_list = offset_list;
14178
14179 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14180
14181 st_index_t i;
14182 st_index_t size = dump->iseq_table->num_entries;
14183 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14184
14185 for (i = 0; i < size; i++) {
14186 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14187 }
14188
14189 ibf_dump_align(dump, sizeof(ibf_offset_t));
14190 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14191 header->iseq_list_size = (unsigned int)size;
14192}
14193
14194/*
14195 * Binary format
14196 * - ibf_object_header
14197 * - ibf_object_xxx (xxx is type)
14198 */
14199
14201 unsigned int type: 5;
14202 unsigned int special_const: 1;
14203 unsigned int frozen: 1;
14204 unsigned int internal: 1;
14205};
14206
14207enum ibf_object_class_index {
14208 IBF_OBJECT_CLASS_OBJECT,
14209 IBF_OBJECT_CLASS_ARRAY,
14210 IBF_OBJECT_CLASS_STANDARD_ERROR,
14211 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14212 IBF_OBJECT_CLASS_TYPE_ERROR,
14213 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14214};
14215
14217 long srcstr;
14218 char option;
14219};
14220
14222 long len;
14223 long keyval[FLEX_ARY_LEN];
14224};
14225
14227 long class_index;
14228 long len;
14229 long beg;
14230 long end;
14231 int excl;
14232};
14233
14235 ssize_t slen;
14236 BDIGIT digits[FLEX_ARY_LEN];
14237};
14238
14239enum ibf_object_data_type {
14240 IBF_OBJECT_DATA_ENCODING,
14241};
14242
14244 long a, b;
14245};
14246
14248 long str;
14249};
14250
14251#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14252 ((((offset) - 1) / (align) + 1) * (align))
14253/* No cast, since it's UB to create an unaligned pointer.
14254 * Leave as void* for use with memcpy in those cases.
14255 * We align the offset, but the buffer pointer is only VALUE aligned,
14256 * so the returned pointer may be unaligned for `type` .*/
14257#define IBF_OBJBODY(type, offset) \
14258 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14259
14260static const void *
14261ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14262{
14263 if (offset >= load->current_buffer->size) {
14264 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14265 }
14266 return load->current_buffer->buff + offset;
14267}
14268
14269NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14270
14271static void
14272ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14273{
14274 char buff[0x100];
14275 rb_raw_obj_info(buff, sizeof(buff), obj);
14276 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14277}
14278
14279NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14280
14281static VALUE
14282ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14283{
14284 rb_raise(rb_eArgError, "unsupported");
14286}
14287
14288static void
14289ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14290{
14291 enum ibf_object_class_index cindex;
14292 if (obj == rb_cObject) {
14293 cindex = IBF_OBJECT_CLASS_OBJECT;
14294 }
14295 else if (obj == rb_cArray) {
14296 cindex = IBF_OBJECT_CLASS_ARRAY;
14297 }
14298 else if (obj == rb_eStandardError) {
14299 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14300 }
14301 else if (obj == rb_eNoMatchingPatternError) {
14302 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14303 }
14304 else if (obj == rb_eTypeError) {
14305 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14306 }
14307 else if (obj == rb_eNoMatchingPatternKeyError) {
14308 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14309 }
14310 else {
14311 rb_obj_info_dump(obj);
14312 rb_p(obj);
14313 rb_bug("unsupported class");
14314 }
14315 ibf_dump_write_small_value(dump, (VALUE)cindex);
14316}
14317
14318static VALUE
14319ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14320{
14321 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14322
14323 switch (cindex) {
14324 case IBF_OBJECT_CLASS_OBJECT:
14325 return rb_cObject;
14326 case IBF_OBJECT_CLASS_ARRAY:
14327 return rb_cArray;
14328 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14329 return rb_eStandardError;
14330 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14332 case IBF_OBJECT_CLASS_TYPE_ERROR:
14333 return rb_eTypeError;
14334 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14336 }
14337
14338 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14339}
14340
14341
14342static void
14343ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14344{
14345 double dbl = RFLOAT_VALUE(obj);
14346 (void)IBF_W(&dbl, double, 1);
14347}
14348
14349static VALUE
14350ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14351{
14352 double d;
14353 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14354 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14355 VALUE f = DBL2NUM(d);
14356 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14357 return f;
14358}
14359
14360static void
14361ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14362{
14363 long encindex = (long)rb_enc_get_index(obj);
14364 long len = RSTRING_LEN(obj);
14365 const char *ptr = RSTRING_PTR(obj);
14366
14367 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14368 rb_encoding *enc = rb_enc_from_index((int)encindex);
14369 const char *enc_name = rb_enc_name(enc);
14370 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14371 }
14372
14373 ibf_dump_write_small_value(dump, encindex);
14374 ibf_dump_write_small_value(dump, len);
14375 IBF_WP(ptr, char, len);
14376}
14377
14378static VALUE
14379ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14380{
14381 ibf_offset_t reading_pos = offset;
14382
14383 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14384 const long len = (long)ibf_load_small_value(load, &reading_pos);
14385 const char *ptr = load->current_buffer->buff + reading_pos;
14386
14387 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14388 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14389 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14390 }
14391
14392 VALUE str;
14393 if (header->frozen && !header->internal) {
14394 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14395 }
14396 else {
14397 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14398
14399 if (header->internal) rb_obj_hide(str);
14400 if (header->frozen) str = rb_fstring(str);
14401 }
14402 return str;
14403}
14404
14405static void
14406ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14407{
14408 VALUE srcstr = RREGEXP_SRC(obj);
14409 struct ibf_object_regexp regexp;
14410 regexp.option = (char)rb_reg_options(obj);
14411 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14412
14413 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14414 ibf_dump_write_small_value(dump, regexp.srcstr);
14415}
14416
14417static VALUE
14418ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14419{
14420 struct ibf_object_regexp regexp;
14421 regexp.option = ibf_load_byte(load, &offset);
14422 regexp.srcstr = ibf_load_small_value(load, &offset);
14423
14424 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14425 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14426
14427 if (header->internal) rb_obj_hide(reg);
14428 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14429
14430 return reg;
14431}
14432
14433static void
14434ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14435{
14436 long i, len = RARRAY_LEN(obj);
14437 ibf_dump_write_small_value(dump, len);
14438 for (i=0; i<len; i++) {
14439 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14440 ibf_dump_write_small_value(dump, index);
14441 }
14442}
14443
14444static VALUE
14445ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14446{
14447 ibf_offset_t reading_pos = offset;
14448
14449 const long len = (long)ibf_load_small_value(load, &reading_pos);
14450
14451 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14452 int i;
14453
14454 for (i=0; i<len; i++) {
14455 const VALUE index = ibf_load_small_value(load, &reading_pos);
14456 rb_ary_push(ary, ibf_load_object(load, index));
14457 }
14458
14459 if (header->frozen) {
14460 rb_ary_freeze(ary);
14461 rb_ractor_make_shareable(ary); // TODO: check elements
14462 }
14463
14464 return ary;
14465}
14466
14467static int
14468ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14469{
14470 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14471
14472 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14473 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14474
14475 ibf_dump_write_small_value(dump, key_index);
14476 ibf_dump_write_small_value(dump, val_index);
14477 return ST_CONTINUE;
14478}
14479
14480static void
14481ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14482{
14483 long len = RHASH_SIZE(obj);
14484 ibf_dump_write_small_value(dump, (VALUE)len);
14485
14486 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14487}
14488
14489static VALUE
14490ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14491{
14492 long len = (long)ibf_load_small_value(load, &offset);
14493 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14494 int i;
14495
14496 for (i = 0; i < len; i++) {
14497 VALUE key_index = ibf_load_small_value(load, &offset);
14498 VALUE val_index = ibf_load_small_value(load, &offset);
14499
14500 VALUE key = ibf_load_object(load, key_index);
14501 VALUE val = ibf_load_object(load, val_index);
14502 rb_hash_aset(obj, key, val);
14503 }
14504
14505 if (header->internal) rb_obj_hide(obj);
14506 if (header->frozen) {
14507 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14508 }
14509
14510 return obj;
14511}
14512
14513static int
14514ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14515{
14516 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14517
14518 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14519
14520 ibf_dump_write_small_value(dump, key_index);
14521 ibf_dump_write_small_value(dump, val);
14522 return ST_CONTINUE;
14523}
14524
14525static void
14526ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14527{
14528 switch (imemo_type(obj)) {
14529 case imemo_cdhash: {
14530 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14531
14532 long len = tbl->num_entries;
14533 ibf_dump_write_small_value(dump, (VALUE)len);
14534 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14535 break;
14536 }
14537 default:
14538 ibf_dump_object_unsupported(dump, obj);
14539 break;
14540 }
14541}
14542
14543static VALUE
14544ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14545{
14546 long len = (long)ibf_load_small_value(load, &offset);
14547 VALUE obj = cdhash_new(len);
14548
14549 int i;
14550 for (i = 0; i < len; i++) {
14551 VALUE key_index = ibf_load_small_value(load, &offset);
14552 VALUE val = ibf_load_small_value(load, &offset);
14553
14554 VALUE key = ibf_load_object(load, key_index);
14555 cdhash_aset(obj, key, val);
14556 }
14557
14558 return obj;
14559}
14560
14561static void
14562ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14563{
14564 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14565 struct ibf_object_struct_range range;
14566 VALUE beg, end;
14567 IBF_ZERO(range);
14568 range.len = 3;
14569 range.class_index = 0;
14570
14571 rb_range_values(obj, &beg, &end, &range.excl);
14572 range.beg = (long)ibf_dump_object(dump, beg);
14573 range.end = (long)ibf_dump_object(dump, end);
14574
14575 IBF_W_ALIGN(struct ibf_object_struct_range);
14576 IBF_WV(range);
14577 }
14578 else {
14579 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14580 rb_class_name(CLASS_OF(obj)));
14581 }
14582}
14583
14584static VALUE
14585ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14586{
14587 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14588 VALUE beg = ibf_load_object(load, range->beg);
14589 VALUE end = ibf_load_object(load, range->end);
14590 VALUE obj = rb_range_new(beg, end, range->excl);
14591 if (header->internal) rb_obj_hide(obj);
14592 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14593 return obj;
14594}
14595
14596static void
14597ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14598{
14599 ssize_t len = BIGNUM_LEN(obj);
14600 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14601 BDIGIT *d = BIGNUM_DIGITS(obj);
14602
14603 (void)IBF_W(&slen, ssize_t, 1);
14604 IBF_WP(d, BDIGIT, len);
14605}
14606
14607static VALUE
14608ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14609{
14610 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14611 int sign = bignum->slen > 0;
14612 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14613 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14616 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14617 big_unpack_flags |
14618 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14619 if (header->internal) rb_obj_hide(obj);
14620 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14621 return obj;
14622}
14623
14624static void
14625ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14626{
14627 if (rb_data_is_encoding(obj)) {
14628 rb_encoding *enc = rb_to_encoding(obj);
14629 const char *name = rb_enc_name(enc);
14630 long len = strlen(name) + 1;
14631 long data[2];
14632 data[0] = IBF_OBJECT_DATA_ENCODING;
14633 data[1] = len;
14634 (void)IBF_W(data, long, 2);
14635 IBF_WP(name, char, len);
14636 }
14637 else {
14638 ibf_dump_object_unsupported(dump, obj);
14639 }
14640}
14641
14642static VALUE
14643ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14644{
14645 const long *body = IBF_OBJBODY(long, offset);
14646 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14647 /* const long len = body[1]; */
14648 const char *data = (const char *)&body[2];
14649
14650 switch (type) {
14651 case IBF_OBJECT_DATA_ENCODING:
14652 {
14653 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14654 return encobj;
14655 }
14656 }
14657
14658 return ibf_load_object_unsupported(load, header, offset);
14659}
14660
14661static void
14662ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14663{
14664 long data[2];
14665 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14666 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14667
14668 (void)IBF_W(data, long, 2);
14669}
14670
14671static VALUE
14672ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14673{
14674 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14675 VALUE a = ibf_load_object(load, nums->a);
14676 VALUE b = ibf_load_object(load, nums->b);
14677 VALUE obj = header->type == T_COMPLEX ?
14678 rb_complex_new(a, b) : rb_rational_new(a, b);
14679
14680 if (header->internal) rb_obj_hide(obj);
14681 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14682 return obj;
14683}
14684
14685static void
14686ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14687{
14688 ibf_dump_object_string(dump, rb_sym2str(obj));
14689}
14690
14691static VALUE
14692ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14693{
14694 ibf_offset_t reading_pos = offset;
14695
14696 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14697 const long len = (long)ibf_load_small_value(load, &reading_pos);
14698 const char *ptr = load->current_buffer->buff + reading_pos;
14699
14700 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14701 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14702 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14703 }
14704
14705 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14706 return ID2SYM(id);
14707}
14708
14709typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14710static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14711 ibf_dump_object_unsupported, /* T_NONE */
14712 ibf_dump_object_unsupported, /* T_OBJECT */
14713 ibf_dump_object_class, /* T_CLASS */
14714 ibf_dump_object_unsupported, /* T_MODULE */
14715 ibf_dump_object_float, /* T_FLOAT */
14716 ibf_dump_object_string, /* T_STRING */
14717 ibf_dump_object_regexp, /* T_REGEXP */
14718 ibf_dump_object_array, /* T_ARRAY */
14719 ibf_dump_object_hash, /* T_HASH */
14720 ibf_dump_object_struct, /* T_STRUCT */
14721 ibf_dump_object_bignum, /* T_BIGNUM */
14722 ibf_dump_object_unsupported, /* T_FILE */
14723 ibf_dump_object_data, /* T_DATA */
14724 ibf_dump_object_unsupported, /* T_MATCH */
14725 ibf_dump_object_complex_rational, /* T_COMPLEX */
14726 ibf_dump_object_complex_rational, /* T_RATIONAL */
14727 ibf_dump_object_unsupported, /* 0x10 */
14728 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14729 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14730 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14731 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14732 ibf_dump_object_unsupported, /* T_FIXNUM */
14733 ibf_dump_object_unsupported, /* T_UNDEF */
14734 ibf_dump_object_unsupported, /* 0x17 */
14735 ibf_dump_object_unsupported, /* 0x18 */
14736 ibf_dump_object_unsupported, /* 0x19 */
14737 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14738 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14739 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14740 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14741 ibf_dump_object_unsupported, /* 0x1e */
14742 ibf_dump_object_unsupported, /* 0x1f */
14743};
14744
14745static void
14746ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14747{
14748 unsigned char byte =
14749 (header.type << 0) |
14750 (header.special_const << 5) |
14751 (header.frozen << 6) |
14752 (header.internal << 7);
14753
14754 IBF_WV(byte);
14755}
14756
14757static struct ibf_object_header
14758ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14759{
14760 unsigned char byte = ibf_load_byte(load, offset);
14761
14762 struct ibf_object_header header;
14763 header.type = (byte >> 0) & 0x1f;
14764 header.special_const = (byte >> 5) & 0x01;
14765 header.frozen = (byte >> 6) & 0x01;
14766 header.internal = (byte >> 7) & 0x01;
14767
14768 return header;
14769}
14770
14771static ibf_offset_t
14772ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14773{
14774 struct ibf_object_header obj_header;
14775 ibf_offset_t current_offset;
14776 IBF_ZERO(obj_header);
14777 obj_header.type = TYPE(obj);
14778
14779 IBF_W_ALIGN(ibf_offset_t);
14780 current_offset = ibf_dump_pos(dump);
14781
14782 if (SPECIAL_CONST_P(obj) &&
14783 ! (SYMBOL_P(obj) ||
14784 RB_FLOAT_TYPE_P(obj))) {
14785 obj_header.special_const = TRUE;
14786 obj_header.frozen = TRUE;
14787 obj_header.internal = TRUE;
14788 ibf_dump_object_object_header(dump, obj_header);
14789 ibf_dump_write_small_value(dump, obj);
14790 }
14791 else {
14792 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14793 obj_header.special_const = FALSE;
14794 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14795 ibf_dump_object_object_header(dump, obj_header);
14796 (*dump_object_functions[obj_header.type])(dump, obj);
14797 }
14798
14799 return current_offset;
14800}
14801
14802typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14803static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14804 ibf_load_object_unsupported, /* T_NONE */
14805 ibf_load_object_unsupported, /* T_OBJECT */
14806 ibf_load_object_class, /* T_CLASS */
14807 ibf_load_object_unsupported, /* T_MODULE */
14808 ibf_load_object_float, /* T_FLOAT */
14809 ibf_load_object_string, /* T_STRING */
14810 ibf_load_object_regexp, /* T_REGEXP */
14811 ibf_load_object_array, /* T_ARRAY */
14812 ibf_load_object_hash, /* T_HASH */
14813 ibf_load_object_struct, /* T_STRUCT */
14814 ibf_load_object_bignum, /* T_BIGNUM */
14815 ibf_load_object_unsupported, /* T_FILE */
14816 ibf_load_object_data, /* T_DATA */
14817 ibf_load_object_unsupported, /* T_MATCH */
14818 ibf_load_object_complex_rational, /* T_COMPLEX */
14819 ibf_load_object_complex_rational, /* T_RATIONAL */
14820 ibf_load_object_unsupported, /* 0x10 */
14821 ibf_load_object_unsupported, /* T_NIL */
14822 ibf_load_object_unsupported, /* T_TRUE */
14823 ibf_load_object_unsupported, /* T_FALSE */
14824 ibf_load_object_symbol,
14825 ibf_load_object_unsupported, /* T_FIXNUM */
14826 ibf_load_object_unsupported, /* T_UNDEF */
14827 ibf_load_object_unsupported, /* 0x17 */
14828 ibf_load_object_unsupported, /* 0x18 */
14829 ibf_load_object_unsupported, /* 0x19 */
14830 ibf_load_object_imemo, /* T_IMEMO 0x1a */
14831 ibf_load_object_unsupported, /* T_NODE 0x1b */
14832 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14833 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14834 ibf_load_object_unsupported, /* 0x1e */
14835 ibf_load_object_unsupported, /* 0x1f */
14836};
14837
14838static VALUE
14839ibf_load_object(const struct ibf_load *load, VALUE object_index)
14840{
14841 if (object_index == 0) {
14842 return Qnil;
14843 }
14844 else {
14845 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14846 if (!obj) {
14847 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14848 ibf_offset_t offset = offsets[object_index];
14849 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14850
14851#if IBF_ISEQ_DEBUG
14852 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14853 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14854 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14855 header.type, header.special_const, header.frozen, header.internal);
14856#endif
14857 if (offset >= load->current_buffer->size) {
14858 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14859 }
14860
14861 if (header.special_const) {
14862 ibf_offset_t reading_pos = offset;
14863
14864 obj = ibf_load_small_value(load, &reading_pos);
14865 }
14866 else {
14867 obj = (*load_object_functions[header.type])(load, &header, offset);
14868 }
14869
14870 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14871 }
14872#if IBF_ISEQ_DEBUG
14873 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14874 object_index, obj);
14875#endif
14876 return obj;
14877 }
14878}
14879
14881{
14882 struct ibf_dump *dump;
14883 VALUE offset_list;
14884};
14885
14886static int
14887ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14888{
14889 VALUE obj = (VALUE)key;
14890 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14891
14892 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14893 rb_ary_push(args->offset_list, UINT2NUM(offset));
14894
14895 return ST_CONTINUE;
14896}
14897
14898static void
14899ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14900{
14901 st_table *obj_table = dump->current_buffer->obj_table;
14902 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14903
14904 struct ibf_dump_object_list_arg args;
14905 args.dump = dump;
14906 args.offset_list = offset_list;
14907
14908 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14909
14910 IBF_W_ALIGN(ibf_offset_t);
14911 *obj_list_offset = ibf_dump_pos(dump);
14912
14913 st_index_t size = obj_table->num_entries;
14914 st_index_t i;
14915
14916 for (i=0; i<size; i++) {
14917 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14918 IBF_WV(offset);
14919 }
14920
14921 *obj_list_size = (unsigned int)size;
14922}
14923
14924static void
14925ibf_dump_mark(void *ptr)
14926{
14927 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14928 rb_gc_mark(dump->global_buffer.str);
14929
14930 rb_mark_set(dump->global_buffer.obj_table);
14931 rb_mark_set(dump->iseq_table);
14932}
14933
14934static void
14935ibf_dump_free(void *ptr)
14936{
14937 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14938 if (dump->global_buffer.obj_table) {
14939 st_free_table(dump->global_buffer.obj_table);
14940 dump->global_buffer.obj_table = 0;
14941 }
14942 if (dump->iseq_table) {
14943 st_free_table(dump->iseq_table);
14944 dump->iseq_table = 0;
14945 }
14946}
14947
14948static size_t
14949ibf_dump_memsize(const void *ptr)
14950{
14951 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14952 size_t size = 0;
14953 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14954 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14955 return size;
14956}
14957
14958static const rb_data_type_t ibf_dump_type = {
14959 "ibf_dump",
14960 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14961 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
14962};
14963
14964static void
14965ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14966{
14967 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14968 dump->iseq_table = NULL;
14969
14970 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14971 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14972 dump->iseq_table = st_init_numtable(); /* need free */
14973
14974 dump->current_buffer = &dump->global_buffer;
14975}
14976
14977static VALUE
14978iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
14979{
14980 struct ibf_header header = {{0}};
14981
14982 ibf_dump_write(dump, &header, sizeof(header));
14983 ibf_dump_iseq(dump, iseq);
14984
14985 header.magic[0] = 'Y'; /* YARB */
14986 header.magic[1] = 'A';
14987 header.magic[2] = 'R';
14988 header.magic[3] = 'B';
14989 header.major_version = IBF_MAJOR_VERSION;
14990 header.minor_version = IBF_MINOR_VERSION;
14991 header.endian = IBF_ENDIAN_MARK;
14992 header.wordsize = (uint8_t)SIZEOF_VALUE;
14993 ibf_dump_iseq_list(dump, &header);
14994 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14995 header.size = ibf_dump_pos(dump);
14996
14997 if (RTEST(opt)) {
14998 VALUE opt_str = opt;
14999 const char *ptr = StringValuePtr(opt_str);
15000 header.extra_size = RSTRING_LENINT(opt_str);
15001 ibf_dump_write(dump, ptr, header.extra_size);
15002 }
15003 else {
15004 header.extra_size = 0;
15005 }
15006
15007 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15008
15009 return dump->global_buffer.str;
15010}
15011
15012VALUE
15013rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15014{
15015 struct ibf_dump *dump;
15016 VALUE dump_obj;
15017 VALUE str;
15018
15019 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15020 ISEQ_BODY(iseq)->local_iseq != iseq) {
15021 rb_raise(rb_eRuntimeError, "should be top of iseq");
15022 }
15023 if (RTEST(ISEQ_COVERAGE(iseq))) {
15024 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15025 }
15026
15027 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15028 ibf_dump_setup(dump, dump_obj);
15029
15030 str = iseq_ibf_dump_0(dump, iseq, opt);
15031 RB_GC_GUARD(dump_obj);
15032 return str;
15033}
15034
15035static const ibf_offset_t *
15036ibf_iseq_list(const struct ibf_load *load)
15037{
15038 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15039}
15040
15041void
15042rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15043{
15044 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15045 rb_iseq_t *prev_src_iseq = load->iseq;
15046 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15047 load->iseq = iseq;
15048#if IBF_ISEQ_DEBUG
15049 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15050 iseq->aux.loader.index, offset,
15051 load->header->size);
15052#endif
15053 ibf_load_iseq_each(load, iseq, offset);
15054 ISEQ_COMPILE_DATA_CLEAR(iseq);
15055 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15056 rb_iseq_init_trace(iseq);
15057 load->iseq = prev_src_iseq;
15058}
15059
15060#if USE_LAZY_LOAD
15061const rb_iseq_t *
15062rb_iseq_complete(const rb_iseq_t *iseq)
15063{
15064 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15065 return iseq;
15066}
15067#endif
15068
15069static rb_iseq_t *
15070ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15071{
15072 int iseq_index = (int)(VALUE)index_iseq;
15073
15074#if IBF_ISEQ_DEBUG
15075 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15076 (void *)index_iseq, (void *)load->iseq_list);
15077#endif
15078 if (iseq_index == -1) {
15079 return NULL;
15080 }
15081 else {
15082 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15083
15084#if IBF_ISEQ_DEBUG
15085 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15086#endif
15087 if (iseqv) {
15088 return (rb_iseq_t *)iseqv;
15089 }
15090 else {
15091 rb_iseq_t *iseq = iseq_imemo_alloc();
15092#if IBF_ISEQ_DEBUG
15093 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15094#endif
15095 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15096 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15097 iseq->aux.loader.index = iseq_index;
15098#if IBF_ISEQ_DEBUG
15099 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15100 (void *)iseq, (void *)load->loader_obj, iseq_index);
15101#endif
15102 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15103
15104 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15105#if IBF_ISEQ_DEBUG
15106 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15107#endif
15108 rb_ibf_load_iseq_complete(iseq);
15109 }
15110
15111#if IBF_ISEQ_DEBUG
15112 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15113 (void *)iseq, (void *)load->iseq);
15114#endif
15115 return iseq;
15116 }
15117 }
15118}
15119
15120static void
15121ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15122{
15123 struct ibf_header *header = (struct ibf_header *)bytes;
15124 load->loader_obj = loader_obj;
15125 load->global_buffer.buff = bytes;
15126 load->header = header;
15127 load->global_buffer.size = header->size;
15128 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15129 load->global_buffer.obj_list_size = header->global_object_list_size;
15130 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15131 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15132 load->iseq = NULL;
15133
15134 load->current_buffer = &load->global_buffer;
15135
15136 if (size < header->size) {
15137 rb_raise(rb_eRuntimeError, "broken binary format");
15138 }
15139 if (strncmp(header->magic, "YARB", 4) != 0) {
15140 rb_raise(rb_eRuntimeError, "unknown binary format");
15141 }
15142 if (header->major_version != IBF_MAJOR_VERSION ||
15143 header->minor_version != IBF_MINOR_VERSION) {
15144 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15145 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15146 }
15147 if (header->endian != IBF_ENDIAN_MARK) {
15148 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15149 }
15150 if (header->wordsize != SIZEOF_VALUE) {
15151 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15152 }
15153 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15154 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15155 header->iseq_list_offset);
15156 }
15157 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15158 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15159 load->global_buffer.obj_list_offset);
15160 }
15161}
15162
15163static void
15164ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15165{
15166 StringValue(str);
15167
15168 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15169 rb_raise(rb_eRuntimeError, "broken binary format");
15170 }
15171
15172 if (USE_LAZY_LOAD) {
15173 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15174 }
15175
15176 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15177 RB_OBJ_WRITE(loader_obj, &load->str, str);
15178}
15179
15180static void
15181ibf_loader_mark(void *ptr)
15182{
15183 struct ibf_load *load = (struct ibf_load *)ptr;
15184 rb_gc_mark(load->str);
15185 rb_gc_mark(load->iseq_list);
15186 rb_gc_mark(load->global_buffer.obj_list);
15187}
15188
15189static void
15190ibf_loader_free(void *ptr)
15191{
15192 struct ibf_load *load = (struct ibf_load *)ptr;
15193 SIZED_FREE(load);
15194}
15195
15196static size_t
15197ibf_loader_memsize(const void *ptr)
15198{
15199 return sizeof(struct ibf_load);
15200}
15201
15202static const rb_data_type_t ibf_load_type = {
15203 "ibf_loader",
15204 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15205 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15206};
15207
15208const rb_iseq_t *
15209rb_iseq_ibf_load(VALUE str)
15210{
15211 struct ibf_load *load;
15212 rb_iseq_t *iseq;
15213 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15214
15215 ibf_load_setup(load, loader_obj, str);
15216 iseq = ibf_load_iseq(load, 0);
15217
15218 RB_GC_GUARD(loader_obj);
15219 return iseq;
15220}
15221
15222const rb_iseq_t *
15223rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15224{
15225 struct ibf_load *load;
15226 rb_iseq_t *iseq;
15227 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15228
15229 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15230 iseq = ibf_load_iseq(load, 0);
15231
15232 RB_GC_GUARD(loader_obj);
15233 return iseq;
15234}
15235
15236/* collect the iseq table into an array indexed by iseq-list index */
15237static int
15238ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15239{
15240 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15241 srcs[(int)val] = (const rb_iseq_t *)key;
15242 return ST_CONTINUE;
15243}
15244
15245/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15246 * source by list index */
15247static void
15248iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15249{
15250 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15251 VALUE srcs_buf;
15252 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15253 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15254
15255 for (unsigned int i = 0; i < iseq_count; i++) {
15256 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15257 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15258 if (pc2branchindex != Qnil) {
15259 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15260 }
15261 }
15262
15263 ALLOCV_END(srcs_buf);
15264}
15265
15266/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15267const rb_iseq_t *
15268rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15269{
15270 struct ibf_dump *dump;
15271 VALUE dump_obj;
15272 VALUE str;
15273
15274 /* --- dump the subtree --- */
15275 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15276 ibf_dump_setup(dump, dump_obj);
15277
15278 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15279
15280 /* --- load it back --- */
15281 struct ibf_load *load;
15282 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15283 ibf_load_setup(load, loader_obj, str);
15284
15285 /* What the loader could not reconstruct is the same for every iseq in
15286 * the subtree: the only absent parent is the top's, every absent
15287 * local_iseq is the source's local root (runtime walks compare it
15288 * against the original frames, so a copy must not stand in), and
15289 * pathobj/script_lines/coverage are per-file values. */
15290 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15291 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15292 const rb_iseq_t *result = NULL;
15293 for (unsigned int i = 0; i < iseq_count; i++) {
15294 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15295 /* force completion even under USE_LAZY_LOAD */
15296 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15297 rb_ibf_load_iseq_complete(copy);
15298 }
15299
15300 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15301
15302 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15303 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15304 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15305 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15306 VALUE cov = ISEQ_COVERAGE(src_root);
15307 if (!NIL_P(sl) || !NIL_P(cov)) {
15308 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15309 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15310 RB_OBJ_WRITE(copy, &v->coverage, cov);
15311 }
15312
15313 if (i == 0) {
15314 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15315 result = copy;
15316 }
15317
15318 /* Shared across Ractors through the Proc#refined memo; the duplicated
15319 * subtree is self-contained, so mark each copy shareable. */
15320 RB_OBJ_SET_SHAREABLE((VALUE)copy);
15321 }
15322
15323 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15324 iseq_subtree_copy_pc2branchindex(dump, load);
15325 }
15326
15327 RB_GC_GUARD(dump_obj);
15328 RB_GC_GUARD(loader_obj);
15329 return result;
15330}
15331
15332VALUE
15333rb_iseq_ibf_load_extra_data(VALUE str)
15334{
15335 struct ibf_load *load;
15336 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15337 VALUE extra_str;
15338
15339 ibf_load_setup(load, loader_obj, str);
15340 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15341 RB_GC_GUARD(loader_obj);
15342 return extra_str;
15343}
15344
15345#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:1441
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1444
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:688
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
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:1445
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1448
@ 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:122
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:668
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:905
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1308
#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:468
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:456
#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:1234
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1258
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1882
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:3897
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1782
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4260
#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:4246
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3665
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:2040
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:3863
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4314
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:4134
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3375
#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:514
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_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1945
#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:9083
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:350
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:321
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:245
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145