Ruby 4.1.0dev (2026-09-21 revision 61de3dd727146cfcf24e8051595bb2fb842f37aa)
compile.c (61de3dd727146cfcf24e8051595bb2fb842f37aa)
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 if (IS_INSN(first) && IS_INSN(second)) {
1270 INSN *first_insn = (INSN*)first;
1271 INSN *second_insn = (INSN*)second;
1272
1273 // [Bug #22299] If both instructions are on the same line and the first one carries
1274 // a line event we need to swap the event as well.
1275 if (first_insn->insn_info.line_no == second_insn->insn_info.line_no) {
1276 rb_event_flag_t mask = (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE);
1277 rb_event_flag_t first_events = first_insn->insn_info.events & mask;
1278 rb_event_flag_t second_events = second_insn->insn_info.events & mask;
1279 first_insn->insn_info.events = (first_insn->insn_info.events & ~mask) | second_events;
1280 second_insn->insn_info.events = (second_insn->insn_info.events & ~mask) | first_events;
1281 }
1282 }
1283}
1284
1285static LINK_ELEMENT *
1286FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1287{
1288 return anchor->anchor.next;
1289}
1290
1291static LINK_ELEMENT *
1292LAST_ELEMENT(LINK_ANCHOR *const anchor)
1293{
1294 return anchor->last;
1295}
1296
1297static LINK_ELEMENT *
1298ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1299{
1300 while (elem) {
1301 switch (elem->type) {
1302 case ISEQ_ELEMENT_INSN:
1303 case ISEQ_ELEMENT_ADJUST:
1304 return elem;
1305 default:
1306 elem = elem->next;
1307 }
1308 }
1309 return NULL;
1310}
1311
1312static int
1313LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1314{
1315 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1316 if (first_insn != NULL &&
1317 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1318 return TRUE;
1319 }
1320 else {
1321 return FALSE;
1322 }
1323}
1324
1325static int
1326LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1327{
1328 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1329 return TRUE;
1330 }
1331 else {
1332 return FALSE;
1333 }
1334}
1335
1336/*
1337 * anc1: e1, e2, e3
1338 * anc2: e4, e5
1339 *#=>
1340 * anc1: e1, e2, e3, e4, e5
1341 * anc2: e4, e5 (broken)
1342 */
1343static void
1344APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1345{
1346 if (anc2->anchor.next) {
1347 /* LINK_ANCHOR must not loop */
1348 RUBY_ASSERT(anc2->last != &anc2->anchor);
1349 anc1->last->next = anc2->anchor.next;
1350 anc2->anchor.next->prev = anc1->last;
1351 anc1->last = anc2->last;
1352 }
1353 else {
1354 RUBY_ASSERT(anc2->last == &anc2->anchor);
1355 }
1356 verify_list("append", anc1);
1357}
1358#if CPDEBUG < 0
1359#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1360#endif
1361
1362#if CPDEBUG && 0
1363static void
1364debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1365{
1366 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1367 printf("----\n");
1368 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1369 (void *)anchor->anchor.next, (void *)anchor->last);
1370 while (list) {
1371 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1372 (void *)list->prev, (int)list->type);
1373 list = list->next;
1374 }
1375 printf("----\n");
1376
1377 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1378 verify_list("debug list", anchor);
1379}
1380#if CPDEBUG < 0
1381#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1382#endif
1383#else
1384#define debug_list(anc, cur) ((void)0)
1385#endif
1386
1387static TRACE *
1388new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1389{
1390 TRACE *trace = compile_data_alloc_trace(iseq);
1391
1392 trace->link.type = ISEQ_ELEMENT_TRACE;
1393 trace->link.next = NULL;
1394 trace->event = event;
1395 trace->data = data;
1396
1397 return trace;
1398}
1399
1400static LABEL *
1401new_label_body(rb_iseq_t *iseq, long line)
1402{
1403 LABEL *labelobj = compile_data_alloc_label(iseq);
1404
1405 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1406 labelobj->link.next = 0;
1407
1408 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1409 labelobj->sc_state = 0;
1410 labelobj->sp = -1;
1411 labelobj->refcnt = 0;
1412 labelobj->set = 0;
1413 labelobj->rescued = LABEL_RESCUE_NONE;
1414 labelobj->unremovable = 0;
1415 labelobj->position = -1;
1416 return labelobj;
1417}
1418
1419static ADJUST *
1420new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1421{
1422 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1423 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1424 adjust->link.next = 0;
1425 adjust->label = label;
1426 adjust->line_no = line;
1427 LABEL_UNREMOVABLE(label);
1428 return adjust;
1429}
1430
1431static void
1432iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1433{
1434 const char *types = insn_op_types(insn->insn_id);
1435 for (int j = 0; types[j]; j++) {
1436 char type = types[j];
1437 switch (type) {
1438 case TS_CDHASH:
1439 case TS_ISEQ:
1440 case TS_VALUE:
1441 case TS_IC: // constant path array
1442 case TS_CALLDATA: // ci is stored.
1443 func(&OPERAND_AT(insn, j), data);
1444 break;
1445 default:
1446 break;
1447 }
1448 }
1449}
1450
1451static void
1452iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1453{
1454 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1456 RBASIC_CLASS(*obj) == 0 || // hidden
1457 RB_OBJ_SHAREABLE_P(*obj));
1458}
1459
1460static INSN *
1461new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1462{
1463 INSN *iobj = compile_data_alloc_insn(iseq);
1464
1465 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1466
1467 iobj->link.type = ISEQ_ELEMENT_INSN;
1468 iobj->link.next = 0;
1469 iobj->insn_id = insn_id;
1470 iobj->insn_info.line_no = line_no;
1471 iobj->insn_info.node_id = node_id;
1472 iobj->insn_info.events = 0;
1473 iobj->operands = argv;
1474 iobj->operand_size = argc;
1475 iobj->sc_state = 0;
1476
1477 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1478
1479 return iobj;
1480}
1481
1482static INSN *
1483new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1484{
1485 VALUE *operands = 0;
1486 va_list argv;
1487 if (argc > 0) {
1488 int i;
1489 va_start(argv, argc);
1490 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1491 for (i = 0; i < argc; i++) {
1492 VALUE v = va_arg(argv, VALUE);
1493 operands[i] = v;
1494 }
1495 va_end(argv);
1496 }
1497 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1498}
1499
1500static INSN *
1501insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1502{
1503 VALUE *operands = 0;
1504 va_list argv;
1505 if (argc > 0) {
1506 int i;
1507 va_start(argv, argc);
1508 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1509 for (i = 0; i < argc; i++) {
1510 VALUE v = va_arg(argv, VALUE);
1511 operands[i] = v;
1512 }
1513 va_end(argv);
1514 }
1515
1516 iobj->insn_id = insn_id;
1517 iobj->operand_size = argc;
1518 iobj->operands = operands;
1519 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1520
1521 return iobj;
1522}
1523
1524static const struct rb_callinfo *
1525new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1526{
1527 VM_ASSERT(argc >= 0);
1528
1529 if (kw_arg) {
1530 flag |= VM_CALL_KWARG;
1531 argc += kw_arg->keyword_len;
1532 }
1533
1534 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1535 && !has_blockiseq) {
1536 flag |= VM_CALL_ARGS_SIMPLE;
1537 }
1538
1539 ISEQ_BODY(iseq)->ci_size++;
1540 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1541 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1542 return ci;
1543}
1544
1545static INSN *
1546new_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)
1547{
1548 VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
1549 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1550 operands[0] = ci;
1551 operands[1] = (VALUE)blockiseq;
1552 if (blockiseq) {
1553 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1554 }
1555
1556 INSN *insn;
1557
1558 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1559 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1560 }
1561 else {
1562 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1563 }
1564
1565 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1566 RB_GC_GUARD(ci);
1567 return insn;
1568}
1569
1570static rb_iseq_t *
1571new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1572 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1573{
1574 rb_iseq_t *ret_iseq;
1575 VALUE ast_value = rb_ruby_ast_new(node);
1576
1577 // The child AST wrapper does not carry the source hash, so copy it from
1578 // the enclosing iseq before compiling, for grandchildren to inherit it.
1579 if (ISEQ_BODY(iseq)->source_hash) {
1580 rb_ast_t *child_ast = rb_ruby_ast_data_get(ast_value);
1581 child_ast->body.source_hash = ISEQ_BODY(iseq)->source_hash;
1582 child_ast->body.has_source_hash = 1;
1583 }
1584
1585 debugs("[new_child_iseq]> ---------------------------------------\n");
1586 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1587 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1588 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1589 line_no, parent,
1590 isolated_depth ? isolated_depth + 1 : 0,
1591 type, ISEQ_COMPILE_DATA(iseq)->option,
1592 ISEQ_SCRIPT_LINES(iseq));
1593 debugs("[new_child_iseq]< ---------------------------------------\n");
1594 return ret_iseq;
1595}
1596
1597static rb_iseq_t *
1598new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1599 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1600{
1601 rb_iseq_t *ret_iseq;
1602
1603 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1604 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1605 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1606 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1607 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1608 return ret_iseq;
1609}
1610
1611static void
1612set_catch_except_p(rb_iseq_t *iseq)
1613{
1614 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1615 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1616 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1617 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1618 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1619 }
1620 }
1621}
1622
1623/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1624 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1625 if catch table exists. But we want to optimize while loop, which always has catch
1626 table entries for break/next/redo.
1627
1628 So this function sets true for limited ISeqs with break/next/redo catch table entries
1629 whose child ISeq would really raise an exception. */
1630static void
1631update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1632{
1633 unsigned int pos;
1634 size_t i;
1635 int insn;
1636 const struct iseq_catch_table *ct = body->catch_table;
1637
1638 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1639 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1640 pos = 0;
1641 while (pos < body->iseq_size) {
1642 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1643 if (insn == BIN(throw)) {
1644 set_catch_except_p(iseq);
1645 break;
1646 }
1647 pos += insn_len(insn);
1648 }
1649
1650 if (ct == NULL)
1651 return;
1652
1653 for (i = 0; i < ct->size; i++) {
1654 const struct iseq_catch_table_entry *entry =
1655 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1656 if (entry->type != CATCH_TYPE_BREAK
1657 && entry->type != CATCH_TYPE_NEXT
1658 && entry->type != CATCH_TYPE_REDO) {
1659 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1660 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1661 break;
1662 }
1663 }
1664}
1665
1666static void
1667iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1668{
1669 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1670 if (NIL_P(catch_table_ary)) return;
1671 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1672 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1673 for (i = 0; i < tlen; i++) {
1674 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1675 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1676 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1677 LINK_ELEMENT *e;
1678
1679 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1680
1681 if (ct != CATCH_TYPE_BREAK
1682 && ct != CATCH_TYPE_NEXT
1683 && ct != CATCH_TYPE_REDO) {
1684
1685 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1686 if (e == cont) {
1687 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1688 ELEM_INSERT_NEXT(end, &nop->link);
1689 break;
1690 }
1691 }
1692 }
1693 }
1694
1695 RB_GC_GUARD(catch_table_ary);
1696}
1697
1698static int
1699iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1700{
1701 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1702 return COMPILE_NG;
1703
1704 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1705
1706 if (compile_debug > 5)
1707 dump_disasm_list(FIRST_ELEMENT(anchor));
1708
1709 debugs("[compile step 3.1 (iseq_optimize)]\n");
1710 iseq_optimize(iseq, anchor);
1711
1712 if (compile_debug > 5)
1713 dump_disasm_list(FIRST_ELEMENT(anchor));
1714
1715 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1716 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1717 iseq_insns_unification(iseq, anchor);
1718 if (compile_debug > 5)
1719 dump_disasm_list(FIRST_ELEMENT(anchor));
1720 }
1721
1722 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1723 iseq_insert_nop_between_end_and_cont(iseq);
1724 if (compile_debug > 5)
1725 dump_disasm_list(FIRST_ELEMENT(anchor));
1726
1727 return COMPILE_OK;
1728}
1729
1730static int
1731iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1732{
1733 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1734 return COMPILE_NG;
1735
1736 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1737 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1738 if (compile_debug > 5)
1739 dump_disasm_list(FIRST_ELEMENT(anchor));
1740
1741 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1742 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1743
1744 debugs("[compile step 4.3 (set_optargs_table)] \n");
1745 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1746
1747 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1748 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1749
1750 debugs("[compile step 6 (update_catch_except_flags)] \n");
1751 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1752 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1753
1754 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1755 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1756 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1757 ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
1758 ISEQ_BODY(iseq)->catch_table = NULL;
1759 }
1760
1761#if VM_INSN_INFO_TABLE_IMPL == 2
1762 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1763 rb_iseq_insns_info_encode_positions(iseq);
1764#endif
1765
1766 if (compile_debug > 1) {
1767 VALUE str = rb_iseq_disasm(iseq);
1768 printf("%s\n", StringValueCStr(str));
1769 }
1770 verify_call_cache(iseq);
1771 debugs("[compile step: finish]\n");
1772
1773 return COMPILE_OK;
1774}
1775
1776static int
1777iseq_set_exception_local_table(rb_iseq_t *iseq)
1778{
1779 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1780 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1781 ISEQ_BODY(iseq)->lvar_states.list = NULL; // $! is read-only, so don't need lvar_states
1782 return COMPILE_OK;
1783}
1784
1785static int
1786get_lvar_level(const rb_iseq_t *iseq)
1787{
1788 int lev = 0;
1789 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1790 lev++;
1791 iseq = ISEQ_BODY(iseq)->parent_iseq;
1792 }
1793 return lev;
1794}
1795
1796static int
1797get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1798{
1799 unsigned int i;
1800
1801 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1802 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1803 return (int)i;
1804 }
1805 }
1806 return -1;
1807}
1808
1809static int
1810get_local_var_idx(const rb_iseq_t *iseq, ID id)
1811{
1812 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1813
1814 if (idx < 0) {
1815 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1816 "get_local_var_idx: %d", idx);
1817 }
1818
1819 return idx;
1820}
1821
1822static int
1823get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1824{
1825 int lv = 0, idx = -1;
1826 const rb_iseq_t *const topmost_iseq = iseq;
1827
1828 while (iseq) {
1829 idx = get_dyna_var_idx_at_raw(iseq, id);
1830 if (idx >= 0) {
1831 break;
1832 }
1833 iseq = ISEQ_BODY(iseq)->parent_iseq;
1834 lv++;
1835 }
1836
1837 if (idx < 0) {
1838 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1839 "get_dyna_var_idx: -1");
1840 }
1841
1842 *level = lv;
1843 *ls = ISEQ_BODY(iseq)->local_table_size;
1844 return idx;
1845}
1846
1847static int
1848iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1849{
1850 const struct rb_iseq_constant_body *body;
1851 while (level > 0) {
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1853 level--;
1854 }
1855 body = ISEQ_BODY(iseq);
1856 if (body->local_iseq == iseq && /* local variables */
1857 body->param.flags.has_block &&
1858 body->local_table_size - body->param.block_start == idx) {
1859 return TRUE;
1860 }
1861 else {
1862 return FALSE;
1863 }
1864}
1865
1866static int
1867iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1868{
1869 int level, ls;
1870 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1871 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1872 *pidx = ls - idx;
1873 *plevel = level;
1874 return TRUE;
1875 }
1876 else {
1877 return FALSE;
1878 }
1879}
1880
1881static void
1882access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1883{
1884 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1885
1886 if (isolated_depth && level >= isolated_depth) {
1887 if (id == rb_intern("yield")) {
1888 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1889 }
1890 else {
1891 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1892 }
1893 }
1894
1895 for (int i=0; i<level; i++) {
1896 VALUE val;
1897 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1898
1899 if (!ovs) {
1900 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1901 }
1902
1903 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1904 if (write && !val) {
1905 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1906 }
1907 }
1908 else {
1909 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1910 }
1911
1912 iseq = ISEQ_BODY(iseq)->parent_iseq;
1913 }
1914}
1915
1916static ID
1917iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1918{
1919 for (int i=0; i<level; i++) {
1920 iseq = ISEQ_BODY(iseq)->parent_iseq;
1921 }
1922
1923 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1924 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1925 return id;
1926}
1927
1928static void
1929update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1930{
1931 for (int i=0; i<level; i++) {
1932 iseq = ISEQ_BODY(iseq)->parent_iseq;
1933 }
1934
1935 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1936 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1937 switch (iseq_lvar_state_get(states, table_idx)) {
1938 case lvar_uninitialized:
1939 iseq_lvar_state_set(states, table_idx, lvar_initialized);
1940 break;
1941 case lvar_initialized:
1942 iseq_lvar_state_set(states, table_idx, lvar_reassigned);
1943 break;
1944 case lvar_reassigned:
1945 /* nothing */
1946 break;
1947 default:
1948 rb_bug("unreachable");
1949 }
1950}
1951
1952static int
1953iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1954{
1955 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1956
1957 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1958 iseq_lvar_state_set(states, i, lvar_initialized);
1959 }
1960
1961 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1962 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1963 for (int i=0; i<opt_num; i++) {
1964 iseq_lvar_state_set(states, lead_num + i, lvar_uninitialized);
1965 }
1966
1967 return COMPILE_OK;
1968}
1969
1970static void
1971iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1972{
1973 if (iseq_local_block_param_p(iseq, idx, level)) {
1974 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1975 }
1976 else {
1977 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1978 }
1979 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1980}
1981
1982static void
1983iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1984{
1985 if (iseq_local_block_param_p(iseq, idx, level)) {
1986 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1987 }
1988 else {
1989 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1990 }
1991 update_lvar_state(iseq, level, idx);
1992 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1993}
1994
1995
1996
1997static void
1998iseq_calc_param_size(rb_iseq_t *iseq)
1999{
2000 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2001 if (body->param.flags.has_opt ||
2002 body->param.flags.has_post ||
2003 body->param.flags.has_rest ||
2004 body->param.flags.has_block ||
2005 body->param.flags.has_kw ||
2006 body->param.flags.has_kwrest) {
2007
2008 if (body->param.flags.has_block) {
2009 body->param.size = body->param.block_start + 1;
2010 }
2011 else if (body->param.flags.has_kwrest) {
2012 body->param.size = body->param.keyword->rest_start + 1;
2013 }
2014 else if (body->param.flags.has_kw) {
2015 body->param.size = body->param.keyword->bits_start + 1;
2016 }
2017 else if (body->param.flags.has_post) {
2018 body->param.size = body->param.post_start + body->param.post_num;
2019 }
2020 else if (body->param.flags.has_rest) {
2021 body->param.size = body->param.rest_start + 1;
2022 }
2023 else if (body->param.flags.has_opt) {
2024 body->param.size = body->param.lead_num + body->param.opt_num;
2025 }
2026 else {
2028 }
2029 }
2030 else {
2031 body->param.size = body->param.lead_num;
2032 }
2033}
2034
2035static int
2036iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
2037 const struct rb_args_info *args, int arg_size)
2038{
2039 const rb_node_kw_arg_t *node = args->kw_args;
2040 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2041 struct rb_iseq_param_keyword *keyword;
2042 const VALUE default_values = rb_ary_hidden_new(1);
2043 const VALUE complex_mark = rb_str_tmp_new(0);
2044 int kw = 0, rkw = 0, di = 0, i;
2045
2046 body->param.flags.has_kw = TRUE;
2047 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2048
2049 while (node) {
2050 kw++;
2051 node = node->nd_next;
2052 }
2053 if (kw > VM_CALL_KW_LEN_MAX) {
2054 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args)) "too many keyword parameters (%d, maximum is %d)",
2055 kw, (int)VM_CALL_KW_LEN_MAX);
2056 }
2057 arg_size += kw;
2058 keyword->bits_start = arg_size++;
2059
2060 node = args->kw_args;
2061 while (node) {
2062 const NODE *val_node = get_nd_value(node->nd_body);
2063 VALUE dv;
2064
2065 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2066 ++rkw;
2067 }
2068 else {
2069 switch (nd_type(val_node)) {
2070 case NODE_SYM:
2071 dv = rb_node_sym_string_val(val_node);
2072 break;
2073 case NODE_REGX:
2074 dv = rb_node_regx_string_val(val_node);
2075 break;
2076 case NODE_LINE:
2077 dv = rb_node_line_lineno_val(val_node);
2078 break;
2079 case NODE_INTEGER:
2080 dv = rb_node_integer_literal_val(val_node);
2081 break;
2082 case NODE_FLOAT:
2083 dv = rb_node_float_literal_val(val_node);
2084 break;
2085 case NODE_RATIONAL:
2086 dv = rb_node_rational_literal_val(val_node);
2087 break;
2088 case NODE_IMAGINARY:
2089 dv = rb_node_imaginary_literal_val(val_node);
2090 break;
2091 case NODE_ENCODING:
2092 dv = rb_node_encoding_val(val_node);
2093 break;
2094 case NODE_NIL:
2095 dv = Qnil;
2096 break;
2097 case NODE_TRUE:
2098 dv = Qtrue;
2099 break;
2100 case NODE_FALSE:
2101 dv = Qfalse;
2102 break;
2103 default:
2104 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2105 dv = complex_mark;
2106 }
2107
2108 keyword->num = ++di;
2109 rb_ary_push(default_values, dv);
2110 }
2111
2112 node = node->nd_next;
2113 }
2114
2115 keyword->num = kw;
2116
2117 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2118 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2119 keyword->rest_start = arg_size++;
2120 body->param.flags.has_kwrest = TRUE;
2121
2122 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2123 }
2124 keyword->required_num = rkw;
2125 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2126
2127 if (RARRAY_LEN(default_values)) {
2128 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2129
2130 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2131 VALUE dv = RARRAY_AREF(default_values, i);
2132 if (dv == complex_mark) dv = Qundef;
2134 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2135 }
2136
2137 keyword->default_values = dvs;
2138 }
2139 return arg_size;
2140}
2141
2142static void
2143iseq_set_use_block(rb_iseq_t *iseq)
2144{
2145 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2146 if (!body->param.flags.use_block) {
2147 body->param.flags.use_block = 1;
2148
2149 rb_vm_t *vm = GET_VM();
2150
2151 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2152 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2153 set_insert(&vm->unused_block_warning_table, key);
2154 }
2155 }
2156}
2157
2158static int
2159iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2160{
2161 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2162
2163 if (node_args) {
2164 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2165 const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
2166 ID rest_id = 0;
2167 int last_comma = 0;
2168 ID block_id = 0;
2169 int arg_size;
2170
2171 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2172
2173 body->param.lead_num = arg_size = (int)args->pre_args_num;
2174 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2175 debugs(" - argc: %d\n", body->param.lead_num);
2176
2177 rest_id = args->rest_arg;
2178 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2179 last_comma = 1;
2180 rest_id = 0;
2181 }
2182 block_id = args->block_arg;
2183
2184 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2185
2186 if (optimized_forward) {
2187 rest_id = 0;
2188 block_id = 0;
2189 }
2190
2191 if (args->opt_args) {
2192 const rb_node_opt_arg_t *node = args->opt_args;
2193 LABEL *label;
2194 VALUE labels = rb_ary_hidden_new(1);
2195 VALUE *opt_table;
2196 int i = 0, j;
2197
2198 while (node) {
2199 label = NEW_LABEL(nd_line(RNODE(node)));
2200 rb_ary_push(labels, (VALUE)label | 1);
2201 ADD_LABEL(optargs, label);
2202 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2203 node = node->nd_next;
2204 i += 1;
2205 }
2206
2207 /* last label */
2208 label = NEW_LABEL(nd_line(node_args));
2209 rb_ary_push(labels, (VALUE)label | 1);
2210 ADD_LABEL(optargs, label);
2211
2212 opt_table = ALLOC_N(VALUE, i+1);
2213
2214 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2215 for (j = 0; j < i+1; j++) {
2216 opt_table[j] &= ~1;
2217 }
2218 rb_ary_clear(labels);
2219
2220 body->param.flags.has_opt = TRUE;
2221 body->param.opt_num = i;
2222 body->param.opt_table = opt_table;
2223 arg_size += i;
2224 }
2225
2226 if (rest_id) {
2227 body->param.rest_start = arg_size++;
2228 body->param.flags.has_rest = TRUE;
2229 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2230 RUBY_ASSERT(body->param.rest_start != -1);
2231 }
2232
2233 if (args->first_post_arg) {
2234 body->param.post_start = arg_size;
2235 body->param.post_num = args->post_args_num;
2236 body->param.flags.has_post = TRUE;
2237 arg_size += args->post_args_num;
2238
2239 if (body->param.flags.has_rest) { /* TODO: why that? */
2240 body->param.post_start = body->param.rest_start + 1;
2241 }
2242 }
2243
2244 if (args->kw_args) {
2245 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2246 }
2247 else if (args->kw_rest_arg && !optimized_forward) {
2248 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2249 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2250 keyword->rest_start = arg_size++;
2251 body->param.keyword = keyword;
2252 body->param.flags.has_kwrest = TRUE;
2253
2254 static ID anon_kwrest = 0;
2255 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2256 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2257 }
2258 else if (args->no_kwarg) {
2259 body->param.flags.accepts_no_kwarg = TRUE;
2260 }
2261
2262 if (args->no_blockarg) {
2263 body->param.flags.accepts_no_block = TRUE;
2264 }
2265 else if (block_id) {
2266 body->param.block_start = arg_size++;
2267 body->param.flags.has_block = TRUE;
2268 iseq_set_use_block(iseq);
2269 }
2270
2271 // Only optimize specifically methods like this: `foo(...)`
2272 if (optimized_forward) {
2273 body->param.flags.use_block = 1;
2274 body->param.flags.forwardable = TRUE;
2275 arg_size = 1;
2276 }
2277
2278 iseq_calc_param_size(iseq);
2279 body->param.size = arg_size;
2280
2281 if (args->pre_init) { /* m_init */
2282 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2283 }
2284 if (args->post_init) { /* p_init */
2285 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2286 }
2287
2288 if (body->type == ISEQ_TYPE_BLOCK) {
2289 if (body->param.flags.has_opt == FALSE &&
2290 body->param.flags.has_post == FALSE &&
2291 body->param.flags.has_rest == FALSE &&
2292 body->param.flags.has_kw == FALSE &&
2293 body->param.flags.has_kwrest == FALSE) {
2294
2295 if (body->param.lead_num == 1 && last_comma == 0) {
2296 /* {|a|} */
2297 body->param.flags.ambiguous_param0 = TRUE;
2298 }
2299 }
2300 }
2301 }
2302
2303 return COMPILE_OK;
2304}
2305
2306static int
2307iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2308{
2309 unsigned int size = tbl ? tbl->size : 0;
2310 unsigned int offset = 0;
2311
2312 if (node_args) {
2313 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2314
2315 // If we have a function that only has `...` as the parameter,
2316 // then its local table should only be `...`
2317 // FIXME: I think this should be fixed in the AST rather than special case here.
2318 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2319 CHECK(size >= 3);
2320 size -= 3;
2321 offset += 3;
2322 }
2323 }
2324
2325 if (size > 0) {
2326 ID *ids = ALLOC_N(ID, size);
2327 MEMCPY(ids, tbl->ids + offset, ID, size);
2328 ISEQ_BODY(iseq)->local_table = ids;
2329
2330 if (ISEQ_LVAR_STATES_EMBED_P(size)) {
2331 /* states are embedded in the body; zero them out */
2332 memset(ISEQ_BODY(iseq)->lvar_states.single, 0, sizeof(ISEQ_BODY(iseq)->lvar_states.single));
2333 }
2334 else {
2335 ISEQ_BODY(iseq)->lvar_states.list = ZALLOC_N(uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
2336 }
2337 }
2338 ISEQ_BODY(iseq)->local_table_size = size;
2339
2340 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2341 return COMPILE_OK;
2342}
2343
2344int
2345rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2346{
2347 int tval, tlit;
2348
2349 if (val == lit) {
2350 return 0;
2351 }
2352 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2353 return val != lit;
2354 }
2355 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2356 return -1;
2357 }
2358 else if (tlit != tval) {
2359 return -1;
2360 }
2361 else if (tlit == T_SYMBOL) {
2362 return val != lit;
2363 }
2364 else if (tlit == T_STRING) {
2365 return rb_str_hash_cmp(lit, val);
2366 }
2367 else if (tlit == T_BIGNUM) {
2368 long x = FIX2LONG(rb_big_cmp(lit, val));
2369
2370 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2371 * There is no need to call rb_fix2int here. */
2372 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2373 return (int)x;
2374 }
2375 else if (tlit == T_FLOAT) {
2376 return rb_float_cmp(lit, val);
2377 }
2378 else if (tlit == T_RATIONAL) {
2379 const struct RRational *rat1 = RRATIONAL(val);
2380 const struct RRational *rat2 = RRATIONAL(lit);
2381 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2382 }
2383 else if (tlit == T_COMPLEX) {
2384 const struct RComplex *comp1 = RCOMPLEX(val);
2385 const struct RComplex *comp2 = RCOMPLEX(lit);
2386 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2387 }
2388 else if (tlit == T_REGEXP) {
2389 return rb_reg_equal(val, lit) ? 0 : -1;
2390 }
2391 else {
2393 }
2394}
2395
2396st_index_t
2397rb_iseq_cdhash_hash(VALUE a)
2398{
2399 switch (OBJ_BUILTIN_TYPE(a)) {
2400 case -1:
2401 case T_SYMBOL:
2402 return (st_index_t)a;
2403 case T_STRING:
2404 return rb_str_hash(a);
2405 case T_BIGNUM:
2406 return FIX2LONG(rb_big_hash(a));
2407 case T_FLOAT:
2408 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2409 case T_RATIONAL:
2410 return rb_rational_hash(a);
2411 case T_COMPLEX:
2412 return rb_complex_hash(a);
2413 case T_REGEXP:
2414 return NUM2LONG(rb_reg_hash(a));
2415 default:
2417 }
2418}
2419
2420static const struct st_hash_type cdhash_type = {
2421 rb_iseq_cdhash_cmp,
2422 rb_iseq_cdhash_hash,
2423};
2424
2425static VALUE
2426cdhash_new(size_t size)
2427{
2428 VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
2429 RB_OBJ_SET_SHAREABLE(cdhash);
2430 return cdhash;
2431}
2432
2433static void
2434cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
2435{
2436 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2437 st_insert(tbl, key, val);
2438 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2439}
2440
2441static void
2442cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
2443{
2444 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2445 VALUE dontcare;
2446 if (!st_lookup(tbl, key, &dontcare)) {
2447 st_insert(tbl, key, val);
2448 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2449 }
2450}
2451
2453 VALUE hash;
2454 int pos;
2455 int len;
2456};
2457
2458static int
2459cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
2460{
2461 return ST_REPLACE;
2462}
2463
2464static int
2465cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
2466{
2467 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2468 LABEL *lobj = (LABEL *)(*value & ~1);
2469 *value = lobj->position - (data->pos+data->len);
2470 return ST_CONTINUE;
2471}
2472
2473static inline VALUE
2474get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2475{
2476 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2477}
2478
2479static inline VALUE
2480get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2481{
2482 VALUE val;
2483 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2484 if (tbl) {
2485 if (rb_id_table_lookup(tbl,id,&val)) {
2486 return val;
2487 }
2488 }
2489 else {
2490 tbl = rb_id_table_create(1);
2491 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2492 }
2493 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2494 rb_id_table_insert(tbl,id,val);
2495 return val;
2496}
2497
2498#define BADINSN_DUMP(anchor, list, dest) \
2499 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2500
2501#define BADINSN_ERROR \
2502 (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
2503 SIZED_FREE_N(insns_info, insns_info_size), \
2504 BADINSN_DUMP(anchor, list, NULL), \
2505 COMPILE_ERROR)
2506
2507static int
2508fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2509{
2510 int stack_max = 0, sp = 0, line = 0;
2511 LINK_ELEMENT *list;
2512
2513 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2514 if (IS_LABEL(list)) {
2515 LABEL *lobj = (LABEL *)list;
2516 lobj->set = TRUE;
2517 }
2518 }
2519
2520 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2521 switch (list->type) {
2522 case ISEQ_ELEMENT_INSN:
2523 {
2524 int j, len, insn;
2525 const char *types;
2526 VALUE *operands;
2527 INSN *iobj = (INSN *)list;
2528
2529 /* update sp */
2530 sp = calc_sp_depth(sp, iobj);
2531 if (sp < 0) {
2532 BADINSN_DUMP(anchor, list, NULL);
2533 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2534 "argument stack underflow (%d)", sp);
2535 return -1;
2536 }
2537 if (sp > stack_max) {
2538 stack_max = sp;
2539 }
2540
2541 line = iobj->insn_info.line_no;
2542 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2543 operands = iobj->operands;
2544 insn = iobj->insn_id;
2545 types = insn_op_types(insn);
2546 len = insn_len(insn);
2547
2548 /* operand check */
2549 if (iobj->operand_size != len - 1) {
2550 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2551 BADINSN_DUMP(anchor, list, NULL);
2552 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2553 "operand size miss! (%d for %d)",
2554 iobj->operand_size, len - 1);
2555 return -1;
2556 }
2557
2558 for (j = 0; types[j]; j++) {
2559 if (types[j] == TS_OFFSET) {
2560 /* label(destination position) */
2561 LABEL *lobj = (LABEL *)operands[j];
2562 if (!lobj->set) {
2563 BADINSN_DUMP(anchor, list, NULL);
2564 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2565 "unknown label: "LABEL_FORMAT, lobj->label_no);
2566 return -1;
2567 }
2568 if (lobj->sp == -1) {
2569 lobj->sp = sp;
2570 }
2571 else if (lobj->sp != sp) {
2572 VALUE path = rb_iseq_path(iseq);
2573 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2574 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2575 lobj->label_no, lobj->sp, sp);
2576 }
2577 }
2578 }
2579 break;
2580 }
2581 case ISEQ_ELEMENT_LABEL:
2582 {
2583 LABEL *lobj = (LABEL *)list;
2584 if (lobj->sp == -1) {
2585 lobj->sp = sp;
2586 }
2587 else {
2588 if (lobj->sp != sp) {
2589 VALUE path = rb_iseq_path(iseq);
2590 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2591 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2592 lobj->label_no, lobj->sp, sp);
2593 }
2594 sp = lobj->sp;
2595 }
2596 break;
2597 }
2598 case ISEQ_ELEMENT_TRACE:
2599 {
2600 /* ignore */
2601 break;
2602 }
2603 case ISEQ_ELEMENT_ADJUST:
2604 {
2605 ADJUST *adjust = (ADJUST *)list;
2606 int orig_sp = sp;
2607
2608 sp = adjust->label ? adjust->label->sp : 0;
2609 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2610 BADINSN_DUMP(anchor, list, NULL);
2611 COMPILE_ERROR(iseq, adjust->line_no,
2612 "iseq_set_sequence: adjust bug %d < %d",
2613 orig_sp, sp);
2614 return -1;
2615 }
2616 break;
2617 }
2618 default:
2619 BADINSN_DUMP(anchor, list, NULL);
2620 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2621 return -1;
2622 }
2623 }
2624 return stack_max;
2625}
2626
2627static int
2628add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2629 int insns_info_index, int code_index, const INSN *iobj)
2630{
2631 if (insns_info_index == 0 ||
2632 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2633#ifdef USE_ISEQ_NODE_ID
2634 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2635#endif
2636 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2637 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2638#ifdef USE_ISEQ_NODE_ID
2639 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2640#endif
2641 insns_info[insns_info_index].events = iobj->insn_info.events;
2642 positions[insns_info_index] = code_index;
2643 return TRUE;
2644 }
2645 return FALSE;
2646}
2647
2648static int
2649add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2650 int insns_info_index, int code_index, const ADJUST *adjust)
2651{
2652 insns_info[insns_info_index].line_no = adjust->line_no;
2653 insns_info[insns_info_index].node_id = -1;
2654 insns_info[insns_info_index].events = 0;
2655 positions[insns_info_index] = code_index;
2656 return TRUE;
2657}
2658
2659static ID *
2660array_to_idlist(VALUE arr)
2661{
2663 long size = RARRAY_LEN(arr);
2664 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2665 for (long i = 0; i < size; i++) {
2666 VALUE sym = RARRAY_AREF(arr, i);
2667 ids[i] = SYM2ID(sym);
2668 }
2669 ids[size] = 0;
2670 return ids;
2671}
2672
2673static VALUE
2674idlist_to_array(const ID *ids)
2675{
2676 VALUE arr = rb_ary_new();
2677 while (*ids) {
2678 rb_ary_push(arr, ID2SYM(*ids++));
2679 }
2680 return arr;
2681}
2682
2686static int
2687iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2688{
2689 struct iseq_insn_info_entry *insns_info;
2690 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2691 unsigned int *positions;
2692 LINK_ELEMENT *list;
2693 VALUE *generated_iseq;
2694 rb_event_flag_t events = 0;
2695 long data = 0;
2696
2697 int insn_num, code_index, insns_info_index, sp = 0;
2698 int stack_max = fix_sp_depth(iseq, anchor);
2699
2700 if (stack_max < 0) return COMPILE_NG;
2701
2702 /* fix label position */
2703 insn_num = code_index = 0;
2704 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2705 switch (list->type) {
2706 case ISEQ_ELEMENT_INSN:
2707 {
2708 INSN *iobj = (INSN *)list;
2709 /* update sp */
2710 sp = calc_sp_depth(sp, iobj);
2711 insn_num++;
2712 events = iobj->insn_info.events |= events;
2713 if (ISEQ_COVERAGE(iseq)) {
2714 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2715 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2716 int line = iobj->insn_info.line_no - 1;
2717 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2718 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2719 }
2720 }
2721 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2722 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2723 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2724 }
2725 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2726 }
2727 }
2728 code_index += insn_data_length(iobj);
2729 events = 0;
2730 data = 0;
2731 break;
2732 }
2733 case ISEQ_ELEMENT_LABEL:
2734 {
2735 LABEL *lobj = (LABEL *)list;
2736 lobj->position = code_index;
2737 if (lobj->sp != sp) {
2738 VALUE path = rb_iseq_path(iseq);
2739 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2740 RSTRING_LENINT(path), RSTRING_PTR(path),
2741 lobj->label_no, lobj->sp, sp);
2742 }
2743 sp = lobj->sp;
2744 break;
2745 }
2746 case ISEQ_ELEMENT_TRACE:
2747 {
2748 TRACE *trace = (TRACE *)list;
2749 events |= trace->event;
2750 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2751 break;
2752 }
2753 case ISEQ_ELEMENT_ADJUST:
2754 {
2755 ADJUST *adjust = (ADJUST *)list;
2756 if (adjust->line_no != -1) {
2757 int orig_sp = sp;
2758 sp = adjust->label ? adjust->label->sp : 0;
2759 if (orig_sp - sp > 0) {
2760 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2761 code_index++; /* insn */
2762 insn_num++;
2763 }
2764 }
2765 break;
2766 }
2767 default: break;
2768 }
2769 }
2770
2771 /* make instruction sequence */
2772 const int generated_iseq_size = code_index;
2773 generated_iseq = ALLOC_N(VALUE, code_index);
2774
2775 const int insns_info_size = insn_num;
2776 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2777
2778 const int positions_size = insn_num;
2779 positions = ALLOC_N(unsigned int, insn_num);
2780 if (ISEQ_IS_SIZE(body)) {
2781 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2782 }
2783 else {
2784 body->is_entries = NULL;
2785 }
2786
2787 if (body->ci_size) {
2788 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2789 }
2790 else {
2791 body->call_data = NULL;
2792 }
2793 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2794
2795 // Calculate the bitmask buffer size.
2796 // Round the generated_iseq size up to the nearest multiple
2797 // of the number of bits in an unsigned long.
2798
2799 // Allocate enough room for the bitmask list
2800 iseq_bits_t * mark_offset_bits;
2801 int code_size = code_index;
2802
2803 bool needs_bitmap = false;
2804
2805 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2806 if (mark_offset_bits_size == 1) {
2807 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2808 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2809 }
2810 else {
2811 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2812 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2813 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2814 }
2815
2816 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2817 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2818
2819 list = FIRST_ELEMENT(anchor);
2820 insns_info_index = code_index = sp = 0;
2821
2822 while (list) {
2823 switch (list->type) {
2824 case ISEQ_ELEMENT_INSN:
2825 {
2826 int j, len, insn;
2827 const char *types;
2828 VALUE *operands;
2829 INSN *iobj = (INSN *)list;
2830
2831 /* update sp */
2832 sp = calc_sp_depth(sp, iobj);
2833 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2834 operands = iobj->operands;
2835 insn = iobj->insn_id;
2836 generated_iseq[code_index] = insn;
2837 types = insn_op_types(insn);
2838 len = insn_len(insn);
2839
2840 for (j = 0; types[j]; j++) {
2841 char type = types[j];
2842
2843 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2844 switch (type) {
2845 case TS_OFFSET:
2846 {
2847 /* label(destination position) */
2848 LABEL *lobj = (LABEL *)operands[j];
2849 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2850 break;
2851 }
2852 case TS_CDHASH:
2853 {
2854 VALUE map = operands[j];
2855 struct cdhash_set_label_struct data;
2856 data.hash = map;
2857 data.pos = code_index;
2858 data.len = len;
2859 st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
2860
2861 generated_iseq[code_index + 1 + j] = map;
2862 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2863 RB_OBJ_WRITTEN(iseq, Qundef, map);
2864 needs_bitmap = true;
2865 break;
2866 }
2867 case TS_LINDEX:
2868 case TS_NUM: /* ulong */
2869 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2870 break;
2871 case TS_ISEQ: /* iseq */
2872 case TS_VALUE: /* VALUE */
2873 {
2874 VALUE v = operands[j];
2875 generated_iseq[code_index + 1 + j] = v;
2876 /* to mark ruby object */
2877 if (!SPECIAL_CONST_P(v)) {
2878 RB_OBJ_WRITTEN(iseq, Qundef, v);
2879 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2880 needs_bitmap = true;
2881 }
2882 break;
2883 }
2884 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2885 case TS_IC: /* inline cache: constants */
2886 {
2887 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2888 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2889 if (UNLIKELY(ic_index >= body->ic_size)) {
2890 BADINSN_DUMP(anchor, &iobj->link, 0);
2891 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2892 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2893 ic_index, ISEQ_IS_SIZE(body));
2894 }
2895
2896 ic->segments = array_to_idlist(operands[j]);
2897
2898 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2899 }
2900 break;
2901 case TS_IVC: /* inline ivar cache */
2902 {
2903 unsigned int ic_index = FIX2UINT(operands[j]);
2904
2905 IVC cache = ((IVC)&body->is_entries[ic_index]);
2906
2907 if (insn == BIN(setinstancevariable)) {
2908 cache->iv_set_name = SYM2ID(operands[j - 1]);
2909 cache->value = IVAR_CACHE_INIT;
2910 }
2911 else {
2912 cache->iv_set_name = 0;
2913 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
2914 }
2915 }
2916 case TS_ISE: /* inline storage entry: `once` insn */
2917 case TS_ICVARC: /* inline cvar cache */
2918 {
2919 unsigned int ic_index = FIX2UINT(operands[j]);
2920 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2921 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2922 BADINSN_DUMP(anchor, &iobj->link, 0);
2923 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2924 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2925 ic_index, ISEQ_IS_SIZE(body));
2926 }
2927 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2928
2929 break;
2930 }
2931 case TS_CALLDATA:
2932 {
2933 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2934 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2935 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2936 cd->ci = source_ci;
2937 cd->cc = vm_cc_empty();
2938 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2939 break;
2940 }
2941 case TS_ID: /* ID */
2942 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2943 break;
2944 case TS_FUNCPTR:
2945 generated_iseq[code_index + 1 + j] = operands[j];
2946 break;
2947 case TS_BUILTIN:
2948 generated_iseq[code_index + 1 + j] = operands[j];
2949 break;
2950 default:
2951 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2952 "unknown operand type: %c", type);
2953 return COMPILE_NG;
2954 }
2955 }
2956 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2957 code_index += len;
2958 break;
2959 }
2960 case ISEQ_ELEMENT_LABEL:
2961 {
2962 LABEL *lobj = (LABEL *)list;
2963 if (lobj->sp != sp) {
2964 VALUE path = rb_iseq_path(iseq);
2965 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2966 RSTRING_LENINT(path), RSTRING_PTR(path),
2967 lobj->label_no, lobj->sp, sp);
2968 }
2969 sp = lobj->sp;
2970 break;
2971 }
2972 case ISEQ_ELEMENT_ADJUST:
2973 {
2974 ADJUST *adjust = (ADJUST *)list;
2975 int orig_sp = sp;
2976
2977 if (adjust->label) {
2978 sp = adjust->label->sp;
2979 }
2980 else {
2981 sp = 0;
2982 }
2983
2984 if (adjust->line_no != -1) {
2985 const int diff = orig_sp - sp;
2986 if (diff > 0) {
2987 if (insns_info_index == 0) {
2988 COMPILE_ERROR(iseq, adjust->line_no,
2989 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2990 }
2991 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2992 }
2993 if (diff > 1) {
2994 generated_iseq[code_index++] = BIN(adjuststack);
2995 generated_iseq[code_index++] = orig_sp - sp;
2996 }
2997 else if (diff == 1) {
2998 generated_iseq[code_index++] = BIN(pop);
2999 }
3000 else if (diff < 0) {
3001 int label_no = adjust->label ? adjust->label->label_no : -1;
3002 SIZED_FREE_N(generated_iseq, generated_iseq_size);
3003 SIZED_FREE_N(insns_info, insns_info_size);
3004 SIZED_FREE_N(positions, positions_size);
3005 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
3006 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
3007 }
3008 debug_list(anchor, list);
3009 COMPILE_ERROR(iseq, adjust->line_no,
3010 "iseq_set_sequence: adjust bug to %d %d < %d",
3011 label_no, orig_sp, sp);
3012 return COMPILE_NG;
3013 }
3014 }
3015 break;
3016 }
3017 default:
3018 /* ignore */
3019 break;
3020 }
3021 list = list->next;
3022 }
3023
3024 body->iseq_encoded = (void *)generated_iseq;
3025 body->iseq_size = code_index;
3026 body->stack_max = stack_max;
3027
3028 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
3029 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
3030 }
3031 else {
3032 if (needs_bitmap) {
3033 body->mark_bits.list = mark_offset_bits;
3034 }
3035 else {
3036 body->mark_bits.list = NULL;
3037 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
3038 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
3039 }
3040 }
3041
3042 /* get rid of memory leak when REALLOC failed */
3043 body->insns_info.body = insns_info;
3044 body->insns_info.positions_or_succ_index_table.positions = positions;
3045
3046 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
3047 body->insns_info.body = insns_info;
3048 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
3049 body->insns_info.positions_or_succ_index_table.positions = positions;
3050 body->insns_info.size = insns_info_index;
3051
3052 return COMPILE_OK;
3053}
3054
3055static int
3056label_get_position(LABEL *lobj)
3057{
3058 return lobj->position;
3059}
3060
3061static int
3062label_get_sp(LABEL *lobj)
3063{
3064 return lobj->sp;
3065}
3066
3067static int
3068iseq_set_exception_table(rb_iseq_t *iseq)
3069{
3070 const VALUE *tptr, *ptr;
3071 unsigned int tlen, i;
3072 struct iseq_catch_table_entry *entry;
3073
3074 ISEQ_BODY(iseq)->catch_table = NULL;
3075
3076 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
3077 if (NIL_P(catch_table_ary)) return COMPILE_OK;
3078 tlen = (int)RARRAY_LEN(catch_table_ary);
3079 tptr = RARRAY_CONST_PTR(catch_table_ary);
3080
3081 if (tlen > 0) {
3082 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
3083 table->size = tlen;
3084
3085 for (i = 0; i < table->size; i++) {
3086 int pos;
3087 ptr = RARRAY_CONST_PTR(tptr[i]);
3088 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
3089 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
3090 pos = label_get_position((LABEL *)(ptr[1] & ~1));
3091 RUBY_ASSERT(pos >= 0);
3092 entry->start = (unsigned int)pos;
3093 pos = label_get_position((LABEL *)(ptr[2] & ~1));
3094 RUBY_ASSERT(pos >= 0);
3095 entry->end = (unsigned int)pos;
3096 entry->iseq = (rb_iseq_t *)ptr[3];
3097 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
3098
3099 /* stack depth */
3100 if (ptr[4]) {
3101 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3102 entry->cont = label_get_position(lobj);
3103 entry->sp = label_get_sp(lobj);
3104
3105 /* TODO: Dirty Hack! Fix me */
3106 if (entry->type == CATCH_TYPE_RESCUE ||
3107 entry->type == CATCH_TYPE_BREAK ||
3108 entry->type == CATCH_TYPE_NEXT) {
3109 RUBY_ASSERT(entry->sp > 0);
3110 entry->sp--;
3111 }
3112 }
3113 else {
3114 entry->cont = 0;
3115 }
3116 }
3117 ISEQ_BODY(iseq)->catch_table = table;
3118 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3119 }
3120
3121 RB_GC_GUARD(catch_table_ary);
3122
3123 return COMPILE_OK;
3124}
3125
3126/*
3127 * set optional argument table
3128 * def foo(a, b=expr1, c=expr2)
3129 * =>
3130 * b:
3131 * expr1
3132 * c:
3133 * expr2
3134 */
3135static int
3136iseq_set_optargs_table(rb_iseq_t *iseq)
3137{
3138 int i;
3139 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3140
3141 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3142 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3143 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3144 }
3145 }
3146 return COMPILE_OK;
3147}
3148
3149static LINK_ELEMENT *
3150get_destination_insn(INSN *iobj)
3151{
3152 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3153 LINK_ELEMENT *list;
3154 rb_event_flag_t events = 0;
3155
3156 list = lobj->link.next;
3157 while (list) {
3158 switch (list->type) {
3159 case ISEQ_ELEMENT_INSN:
3160 case ISEQ_ELEMENT_ADJUST:
3161 goto found;
3162 case ISEQ_ELEMENT_LABEL:
3163 /* ignore */
3164 break;
3165 case ISEQ_ELEMENT_TRACE:
3166 {
3167 TRACE *trace = (TRACE *)list;
3168 events |= trace->event;
3169 }
3170 break;
3171 default: break;
3172 }
3173 list = list->next;
3174 }
3175 found:
3176 if (list && IS_INSN(list)) {
3177 INSN *iobj = (INSN *)list;
3178 iobj->insn_info.events |= events;
3179 }
3180 return list;
3181}
3182
3183static LINK_ELEMENT *
3184get_next_insn(INSN *iobj)
3185{
3186 LINK_ELEMENT *list = iobj->link.next;
3187
3188 while (list) {
3189 if (IS_INSN(list) || IS_ADJUST(list)) {
3190 return list;
3191 }
3192 list = list->next;
3193 }
3194 return 0;
3195}
3196
3197static LINK_ELEMENT *
3198get_prev_insn(INSN *iobj)
3199{
3200 LINK_ELEMENT *list = iobj->link.prev;
3201
3202 while (list) {
3203 if (IS_INSN(list) || IS_ADJUST(list)) {
3204 return list;
3205 }
3206 list = list->prev;
3207 }
3208 return 0;
3209}
3210
3211static void
3212unref_destination(INSN *iobj, int pos)
3213{
3214 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3215 --lobj->refcnt;
3216 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3217}
3218
3219static bool
3220replace_destination(INSN *dobj, INSN *nobj)
3221{
3222 VALUE n = OPERAND_AT(nobj, 0);
3223 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3224 LABEL *nl = (LABEL *)n;
3225 if (dl == nl) return false;
3226 --dl->refcnt;
3227 ++nl->refcnt;
3228 OPERAND_AT(dobj, 0) = n;
3229 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3230 return true;
3231}
3232
3233static LABEL*
3234find_destination(INSN *i)
3235{
3236 int pos, len = insn_len(i->insn_id);
3237 for (pos = 0; pos < len; ++pos) {
3238 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3239 return (LABEL *)OPERAND_AT(i, pos);
3240 }
3241 }
3242 return 0;
3243}
3244
3245static int
3246remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3247{
3248 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3249 LABEL *pending = 0;
3250 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3251
3252 if (!i) return 0;
3253 unref_counts = ALLOCA_N(int, nlabels);
3254 MEMZERO(unref_counts, int, nlabels);
3255
3256 end = i;
3257 scan = i;
3258 do {
3259 LABEL *lab;
3260 if (IS_INSN(scan)) {
3261 if (IS_INSN_ID(scan, leave)) {
3262 if (pending) break;
3263 end = scan;
3264 break;
3265 }
3266 else if ((lab = find_destination((INSN *)scan)) != 0) {
3267 unref_counts[lab->label_no]++;
3268 if (lab == pending && lab->refcnt <= unref_counts[lab->label_no]) {
3269 pending = 0;
3270 }
3271 }
3272 }
3273 else if (IS_LABEL(scan)) {
3274 lab = (LABEL *)scan;
3275 if (lab->unremovable) {
3276 if (pending) break;
3277 return 0;
3278 }
3279 if (lab->refcnt > unref_counts[lab->label_no]) {
3280 if (pending) break;
3281 pending = lab;
3282 pending_end = (scan == first) ? 0 : end;
3283 }
3284 continue;
3285 }
3286 else if (IS_ADJUST(scan)) {
3287 if (pending) break;
3288 return 0;
3289 }
3290 if (!pending) end = scan;
3291 } while ((scan = scan->next) != 0);
3292
3293 if (pending) {
3294 if (!pending_end) return 0;
3295 end = pending_end;
3296 }
3297 i = first;
3298 do {
3299 if (IS_INSN(i)) {
3300 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3301 VALUE insn = INSN_OF(i);
3302 int pos, len = insn_len(insn);
3303 for (pos = 0; pos < len; ++pos) {
3304 switch (insn_op_types(insn)[pos]) {
3305 case TS_OFFSET:
3306 unref_destination((INSN *)i, pos);
3307 break;
3308 case TS_CALLDATA:
3309 --(body->ci_size);
3310 break;
3311 }
3312 }
3313 }
3314 ELEM_REMOVE(i);
3315 } while ((i != end) && (i = i->next) != 0);
3316 return 1;
3317}
3318
3319static int
3320iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3321{
3322 switch (OPERAND_AT(iobj, 0)) {
3323 case INT2FIX(0): /* empty array */
3324 ELEM_REMOVE(&iobj->link);
3325 return TRUE;
3326 case INT2FIX(1): /* single element array */
3327 ELEM_REMOVE(&iobj->link);
3328 return FALSE;
3329 default:
3330 iobj->insn_id = BIN(adjuststack);
3331 return TRUE;
3332 }
3333}
3334
3335static int
3336is_frozen_putstring(INSN *insn, VALUE *op)
3337{
3338 if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
3339 *op = OPERAND_AT(insn, 0);
3340 return 1;
3341 }
3342 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3343 *op = OPERAND_AT(insn, 0);
3344 return RB_TYPE_P(*op, T_STRING);
3345 }
3346 return 0;
3347}
3348
3349static int
3350insn_has_label_before(LINK_ELEMENT *elem)
3351{
3352 LINK_ELEMENT *prev = elem->prev;
3353 while (prev) {
3354 if (prev->type == ISEQ_ELEMENT_LABEL) {
3355 LABEL *label = (LABEL *)prev;
3356 if (label->refcnt > 0) {
3357 return 1;
3358 }
3359 }
3360 else if (prev->type == ISEQ_ELEMENT_INSN) {
3361 break;
3362 }
3363 prev = prev->prev;
3364 }
3365 return 0;
3366}
3367
3368static int
3369optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3370{
3371 /*
3372 * putobject obj
3373 * dup
3374 * checktype T_XXX
3375 * branchif l1
3376 * l2:
3377 * ...
3378 * l1:
3379 *
3380 * => obj is a T_XXX
3381 *
3382 * putobject obj (T_XXX)
3383 * jump L1
3384 * L1:
3385 *
3386 * => obj is not a T_XXX
3387 *
3388 * putobject obj (T_XXX)
3389 * jump L2
3390 * L2:
3391 */
3392 int line, node_id;
3393 INSN *niobj, *ciobj, *dup = 0;
3394 LABEL *dest = 0;
3395 VALUE type;
3396
3397 switch (INSN_OF(iobj)) {
3398 case BIN(dupstring):
3399 case BIN(dupchilledstring):
3401 break;
3402 case BIN(putnil):
3403 type = INT2FIX(T_NIL);
3404 break;
3405 case BIN(putobject):
3406 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3407 break;
3408 default: return FALSE;
3409 }
3410
3411 ciobj = (INSN *)get_next_insn(iobj);
3412 if (IS_INSN_ID(ciobj, jump)) {
3413 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3414 }
3415 if (IS_INSN_ID(ciobj, dup)) {
3416 ciobj = (INSN *)get_next_insn(dup = ciobj);
3417 }
3418 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3419 niobj = (INSN *)get_next_insn(ciobj);
3420 if (!niobj) {
3421 /* TODO: putobject true/false */
3422 return FALSE;
3423 }
3424 switch (INSN_OF(niobj)) {
3425 case BIN(branchif):
3426 if (OPERAND_AT(ciobj, 0) == type) {
3427 dest = (LABEL *)OPERAND_AT(niobj, 0);
3428 }
3429 break;
3430 case BIN(branchunless):
3431 if (OPERAND_AT(ciobj, 0) != type) {
3432 dest = (LABEL *)OPERAND_AT(niobj, 0);
3433 }
3434 break;
3435 default:
3436 return FALSE;
3437 }
3438 line = ciobj->insn_info.line_no;
3439 node_id = ciobj->insn_info.node_id;
3440 if (!dest) {
3441 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3442 dest = (LABEL *)niobj->link.next; /* reuse label */
3443 }
3444 else {
3445 dest = NEW_LABEL(line);
3446 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3447 }
3448 }
3449 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3450 LABEL_REF(dest);
3451 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3452 return TRUE;
3453}
3454
3455static const struct rb_callinfo *
3456ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3457{
3458 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3459 vm_ci_flag(ci) | add,
3460 vm_ci_argc(ci),
3461 vm_ci_kwarg(ci));
3462 RB_OBJ_WRITTEN(iseq, ci, nci);
3463 return nci;
3464}
3465
3466static const struct rb_callinfo *
3467ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3468{
3469 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3470 vm_ci_flag(ci),
3471 argc,
3472 vm_ci_kwarg(ci));
3473 RB_OBJ_WRITTEN(iseq, ci, nci);
3474 return nci;
3475}
3476
3477#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3478
3479static VALUE
3480iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3481{
3482 VALUE errinfo = rb_errinfo();
3483 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3484 if (NIL_P(re)) {
3485 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3486 rb_set_errinfo(errinfo);
3487 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3488 }
3489 else {
3491 }
3492 return re;
3493}
3494
3495static int
3496iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3497{
3498 INSN *const iobj = (INSN *)list;
3499
3500 again:
3501 optimize_checktype(iseq, iobj);
3502
3503 if (IS_INSN_ID(iobj, jump)) {
3504 INSN *niobj, *diobj, *piobj;
3505 diobj = (INSN *)get_destination_insn(iobj);
3506 niobj = (INSN *)get_next_insn(iobj);
3507
3508 if (diobj == niobj) {
3509 /*
3510 * jump LABEL
3511 * LABEL:
3512 * =>
3513 * LABEL:
3514 */
3515 unref_destination(iobj, 0);
3516 ELEM_REMOVE(&iobj->link);
3517 return COMPILE_OK;
3518 }
3519 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3520 IS_INSN_ID(diobj, jump) &&
3521 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3522 diobj->insn_info.events == 0) {
3523 /*
3524 * useless jump elimination:
3525 * jump LABEL1
3526 * ...
3527 * LABEL1:
3528 * jump LABEL2
3529 *
3530 * => in this case, first jump instruction should jump to
3531 * LABEL2 directly
3532 */
3533 if (replace_destination(iobj, diobj)) {
3534 remove_unreachable_chunk(iseq, iobj->link.next);
3535 goto again;
3536 }
3537 }
3538 else if (IS_INSN_ID(diobj, leave)) {
3539 /*
3540 * jump LABEL
3541 * ...
3542 * LABEL:
3543 * leave
3544 * =>
3545 * leave
3546 * ...
3547 * LABEL:
3548 * leave
3549 */
3550 /* replace */
3551 unref_destination(iobj, 0);
3552 iobj->insn_id = BIN(leave);
3553 iobj->operand_size = 0;
3554 iobj->insn_info = diobj->insn_info;
3555 goto again;
3556 }
3557 else if (IS_INSN(iobj->link.prev) &&
3558 (piobj = (INSN *)iobj->link.prev) &&
3559 (IS_INSN_ID(piobj, branchif) ||
3560 IS_INSN_ID(piobj, branchunless))) {
3561 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3562 if (niobj == pdiobj) {
3563 int refcnt = IS_LABEL(piobj->link.next) ?
3564 ((LABEL *)piobj->link.next)->refcnt : 0;
3565 /*
3566 * useless jump elimination (if/unless destination):
3567 * if L1
3568 * jump L2
3569 * L1:
3570 * ...
3571 * L2:
3572 *
3573 * ==>
3574 * unless L2
3575 * L1:
3576 * ...
3577 * L2:
3578 */
3579 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3580 ? BIN(branchunless) : BIN(branchif);
3581 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3582 ELEM_REMOVE(&iobj->link);
3583 }
3584 else {
3585 /* TODO: replace other branch destinations too */
3586 }
3587 return COMPILE_OK;
3588 }
3589 else if (diobj == pdiobj) {
3590 /*
3591 * useless jump elimination (if/unless before jump):
3592 * L1:
3593 * ...
3594 * if L1
3595 * jump L1
3596 *
3597 * ==>
3598 * L1:
3599 * ...
3600 * pop
3601 * jump L1
3602 */
3603 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3604 ELEM_REPLACE(&piobj->link, &popiobj->link);
3605 }
3606 }
3607 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3608 goto again;
3609 }
3610 }
3611
3612 /*
3613 * dupstring "beg"
3614 * dupstring "end"
3615 * newrange excl
3616 *
3617 * ==>
3618 *
3619 * putobject "beg".."end"
3620 */
3621 if (IS_INSN_ID(iobj, newrange)) {
3622 INSN *const range = iobj;
3623 INSN *beg, *end;
3624 VALUE str_beg, str_end;
3625
3626 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3627 is_frozen_putstring(end, &str_end) &&
3628 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3629 is_frozen_putstring(beg, &str_beg) &&
3630 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3631 int excl = FIX2INT(OPERAND_AT(range, 0));
3632 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3633
3634 ELEM_REMOVE(&beg->link);
3635 ELEM_REMOVE(&end->link);
3636 range->insn_id = BIN(putobject);
3637 OPERAND_AT(range, 0) = lit_range;
3638 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3639 }
3640 }
3641
3642 if (IS_INSN_ID(iobj, leave)) {
3643 remove_unreachable_chunk(iseq, iobj->link.next);
3644 }
3645
3646 /*
3647 * ...
3648 * duparray [...]
3649 * concatarray | concattoarray
3650 * =>
3651 * ...
3652 * putobject [...]
3653 * concatarray | concattoarray
3654 */
3655 if (IS_INSN_ID(iobj, duparray)) {
3656 LINK_ELEMENT *next = iobj->link.next;
3657 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3658 iobj->insn_id = BIN(putobject);
3659 }
3660 }
3661
3662 /*
3663 * duparray [...]
3664 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3665 * =>
3666 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3667 */
3668 if (IS_INSN_ID(iobj, duparray)) {
3669 LINK_ELEMENT *next = iobj->link.next;
3670 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3671 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3672 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3673
3674 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3675 VALUE ary = iobj->operands[0];
3677
3678 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3679 ELEM_REMOVE(next);
3680 }
3681 }
3682 }
3683
3684 /*
3685 * duphash {...}
3686 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3687 * =>
3688 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3689 */
3690 if (IS_INSN_ID(iobj, duphash)) {
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 VALUE hash = iobj->operands[0];
3698 rb_obj_reveal(hash, rb_cHash);
3700
3701 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3702 ELEM_REMOVE(next);
3703 }
3704 }
3705 }
3706
3707 /*
3708 * newarray 0
3709 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3710 * =>
3711 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3712 */
3713 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3714 LINK_ELEMENT *next = iobj->link.next;
3715 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3716 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3717 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3718
3719 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3720 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3721 ELEM_REMOVE(next);
3722 }
3723 }
3724 }
3725
3726 /*
3727 * newhash 0
3728 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3729 * =>
3730 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3731 */
3732 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3733 LINK_ELEMENT *next = iobj->link.next;
3734 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3735 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3736 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3737
3738 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3739 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3740 ELEM_REMOVE(next);
3741 }
3742 }
3743 }
3744
3745 if (IS_INSN_ID(iobj, branchif) ||
3746 IS_INSN_ID(iobj, branchnil) ||
3747 IS_INSN_ID(iobj, branchunless)) {
3748 /*
3749 * if L1
3750 * ...
3751 * L1:
3752 * jump L2
3753 * =>
3754 * if L2
3755 */
3756 INSN *nobj = (INSN *)get_destination_insn(iobj);
3757
3758 /* This jump-jump optimization may ignore line events on the jump
3759 * instruction being skipped. For example, the Line 2 TracePoint
3760 * event would otherwise never fire in the following code:
3761 *
3762 * 1: raise if 1 == 2
3763 * 2: while true
3764 * 3: break
3765 * 4: end
3766 *
3767 * Do not skip a jump that carries a line event. This applies even
3768 * when coverage is disabled because TracePoint consumes the same
3769 * event. [Bug #15980]
3770 */
3771 int stop_optimization =
3772 nobj->link.type == ISEQ_ELEMENT_INSN &&
3773 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3774 if (!stop_optimization) {
3775 INSN *pobj = (INSN *)iobj->link.prev;
3776 int prev_dup = 0;
3777 if (pobj) {
3778 if (!IS_INSN(&pobj->link))
3779 pobj = 0;
3780 else if (IS_INSN_ID(pobj, dup))
3781 prev_dup = 1;
3782 }
3783
3784 for (;;) {
3785 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3786 if (!replace_destination(iobj, nobj)) break;
3787 }
3788 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3789 !!(nobj = (INSN *)nobj->link.next) &&
3790 IS_INSN(&nobj->link) &&
3791 /* basic blocks, with no labels in the middle */
3792 nobj->insn_id == iobj->insn_id) {
3793 /*
3794 * dup
3795 * if L1
3796 * ...
3797 * L1:
3798 * dup
3799 * if L2
3800 * =>
3801 * dup
3802 * if L2
3803 * ...
3804 * L1:
3805 * dup
3806 * if L2
3807 */
3808 if (!replace_destination(iobj, nobj)) break;
3809 }
3810 else if (pobj) {
3811 /*
3812 * putnil
3813 * if L1
3814 * =>
3815 * # nothing
3816 *
3817 * putobject true
3818 * if L1
3819 * =>
3820 * jump L1
3821 *
3822 * dupstring ".."
3823 * if L1
3824 * =>
3825 * jump L1
3826 *
3827 * dupstring ".."
3828 * dup
3829 * if L1
3830 * =>
3831 * dupstring ".."
3832 * jump L1
3833 *
3834 */
3835 int cond;
3836 if (prev_dup && IS_INSN(pobj->link.prev)) {
3837 pobj = (INSN *)pobj->link.prev;
3838 }
3839 if (IS_INSN_ID(pobj, putobject)) {
3840 cond = (IS_INSN_ID(iobj, branchif) ?
3841 OPERAND_AT(pobj, 0) != Qfalse :
3842 IS_INSN_ID(iobj, branchunless) ?
3843 OPERAND_AT(pobj, 0) == Qfalse :
3844 FALSE);
3845 }
3846 else if (IS_INSN_ID(pobj, dupstring) ||
3847 IS_INSN_ID(pobj, duparray) ||
3848 IS_INSN_ID(pobj, newarray)) {
3849 cond = IS_INSN_ID(iobj, branchif);
3850 }
3851 else if (IS_INSN_ID(pobj, putnil)) {
3852 cond = !IS_INSN_ID(iobj, branchif);
3853 }
3854 else break;
3855 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3856 ELEM_REMOVE(iobj->link.prev);
3857 }
3858 else if (!iseq_pop_newarray(iseq, pobj)) {
3859 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3860 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3861 }
3862 if (cond) {
3863 if (prev_dup) {
3864 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3865 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3866 }
3867 iobj->insn_id = BIN(jump);
3868 goto again;
3869 }
3870 else {
3871 unref_destination(iobj, 0);
3872 ELEM_REMOVE(&iobj->link);
3873 }
3874 break;
3875 }
3876 else break;
3877 {
3878 LINK_ELEMENT *dest = get_destination_insn(nobj);
3879 if (!dest || !IS_INSN(dest)) break;
3880 nobj = (INSN *)dest;
3881 }
3882 }
3883 }
3884 }
3885
3886 if (IS_INSN_ID(iobj, pop)) {
3887 /*
3888 * putself / putnil / putobject obj / dupstring "..."
3889 * pop
3890 * =>
3891 * # do nothing
3892 */
3893 LINK_ELEMENT *prev = iobj->link.prev;
3894 if (IS_INSN(prev)) {
3895 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3896 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3897 previ == BIN(putself) || previ == BIN(dupstring) ||
3898 previ == BIN(dupchilledstring) ||
3899 previ == BIN(dup) ||
3900 previ == BIN(getlocal) ||
3901 previ == BIN(getblockparam) ||
3902 previ == BIN(getblockparamproxy) ||
3903 previ == BIN(getinstancevariable) ||
3904 previ == BIN(duparray)) {
3905 /* just push operand or static value and pop soon, no
3906 * side effects */
3907 ELEM_REMOVE(prev);
3908 ELEM_REMOVE(&iobj->link);
3909 }
3910 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3911 ELEM_REMOVE(&iobj->link);
3912 }
3913 else if (previ == BIN(concatarray)) {
3914 INSN *piobj = (INSN *)prev;
3915 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3916 INSN_OF(piobj) = BIN(pop);
3917 }
3918 else if (previ == BIN(concatstrings)) {
3919 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3920 ELEM_REMOVE(prev);
3921 }
3922 else {
3923 ELEM_REMOVE(&iobj->link);
3924 INSN_OF(prev) = BIN(adjuststack);
3925 }
3926 }
3927 }
3928 }
3929
3930 if (IS_INSN_ID(iobj, newarray) ||
3931 IS_INSN_ID(iobj, duparray) ||
3932 IS_INSN_ID(iobj, concatarray) ||
3933 IS_INSN_ID(iobj, splatarray) ||
3934 0) {
3935 /*
3936 * newarray N
3937 * splatarray
3938 * =>
3939 * newarray N
3940 * newarray always puts an array
3941 */
3942 LINK_ELEMENT *next = iobj->link.next;
3943 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3944 /* remove splatarray following always-array insn */
3945 ELEM_REMOVE(next);
3946 }
3947 }
3948
3949 if (IS_INSN_ID(iobj, newarray)) {
3950 LINK_ELEMENT *next = iobj->link.next;
3951 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3952 OPERAND_AT(next, 1) == INT2FIX(0)) {
3953 VALUE op1, op2;
3954 op1 = OPERAND_AT(iobj, 0);
3955 op2 = OPERAND_AT(next, 0);
3956 ELEM_REMOVE(next);
3957
3958 if (op1 == op2) {
3959 /*
3960 * newarray 2
3961 * expandarray 2, 0
3962 * =>
3963 * swap
3964 */
3965 if (op1 == INT2FIX(2)) {
3966 INSN_OF(iobj) = BIN(swap);
3967 iobj->operand_size = 0;
3968 }
3969 /*
3970 * newarray X
3971 * expandarray X, 0
3972 * =>
3973 * opt_reverse X
3974 */
3975 else {
3976 INSN_OF(iobj) = BIN(opt_reverse);
3977 }
3978 }
3979 else {
3980 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3981 INSN_OF(iobj) = BIN(opt_reverse);
3982 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3983
3984 if (op1 > op2) {
3985 /* X > Y
3986 * newarray X
3987 * expandarray Y, 0
3988 * =>
3989 * pop * (Y-X)
3990 * opt_reverse Y
3991 */
3992 for (; diff > 0; diff--) {
3993 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3994 }
3995 }
3996 else { /* (op1 < op2) */
3997 /* X < Y
3998 * newarray X
3999 * expandarray Y, 0
4000 * =>
4001 * putnil * (Y-X)
4002 * opt_reverse Y
4003 */
4004 for (; diff < 0; diff++) {
4005 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
4006 }
4007 }
4008 }
4009 }
4010 }
4011
4012 if (IS_INSN_ID(iobj, duparray)) {
4013 LINK_ELEMENT *next = iobj->link.next;
4014 /*
4015 * duparray obj
4016 * expandarray X, 0
4017 * =>
4018 * putobject obj
4019 * expandarray X, 0
4020 */
4021 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
4022 INSN_OF(iobj) = BIN(putobject);
4023 }
4024 }
4025
4026 if (IS_INSN_ID(iobj, anytostring)) {
4027 LINK_ELEMENT *next = iobj->link.next;
4028 /*
4029 * anytostring
4030 * concatstrings 1
4031 * =>
4032 * anytostring
4033 */
4034 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
4035 OPERAND_AT(next, 0) == INT2FIX(1)) {
4036 ELEM_REMOVE(next);
4037 }
4038 }
4039
4040 if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
4041 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
4042 /*
4043 * dupstring ""
4044 * concatstrings N
4045 * =>
4046 * concatstrings N-1
4047 */
4048 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
4049 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
4050 INSN *next = (INSN *)iobj->link.next;
4051 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
4052 ELEM_REMOVE(&next->link);
4053 }
4054 ELEM_REMOVE(&iobj->link);
4055 }
4056 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
4057 INSN *next = (INSN *)iobj->link.next;
4058 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
4059 VALUE src = OPERAND_AT(iobj, 0);
4060 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
4061 VALUE path = rb_iseq_path(iseq);
4062 int line = iobj->insn_info.line_no;
4063 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
4064 /* The folded operand is a Regexp, so the instruction must be
4065 * putobject: dupstring/dupchilledstring would resurrect the
4066 * Regexp as a String at run time (e.g. for a /o regexp whose
4067 * interpolation folds to a constant, such as /#{"a"}/o). */
4068 iobj->insn_id = BIN(putobject);
4069 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
4070 ELEM_REMOVE(iobj->link.next);
4071 }
4072 }
4073 }
4074
4075 if (IS_INSN_ID(iobj, concatstrings)) {
4076 /*
4077 * concatstrings N
4078 * concatstrings M
4079 * =>
4080 * concatstrings N+M-1
4081 */
4082 LINK_ELEMENT *next = iobj->link.next;
4083 INSN *jump = 0;
4084 if (IS_INSN(next) && IS_INSN_ID(next, jump))
4085 next = get_destination_insn(jump = (INSN *)next);
4086 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
4087 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
4088 OPERAND_AT(iobj, 0) = INT2FIX(n);
4089 if (jump) {
4090 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
4091 if (!--label->refcnt) {
4092 ELEM_REMOVE(&label->link);
4093 }
4094 else {
4095 label = NEW_LABEL(0);
4096 OPERAND_AT(jump, 0) = (VALUE)label;
4097 }
4098 label->refcnt++;
4099 ELEM_INSERT_NEXT(next, &label->link);
4100 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
4101 }
4102 else {
4103 ELEM_REMOVE(next);
4104 }
4105 }
4106 }
4107
4108 if (do_tailcallopt &&
4109 (IS_INSN_ID(iobj, send) ||
4110 IS_INSN_ID(iobj, invokesuper))) {
4111 /*
4112 * send ...
4113 * leave
4114 * =>
4115 * send ..., ... | VM_CALL_TAILCALL, ...
4116 * leave # unreachable
4117 */
4118 INSN *piobj = NULL;
4119 if (iobj->link.next) {
4120 LINK_ELEMENT *next = iobj->link.next;
4121 do {
4122 if (!IS_INSN(next)) {
4123 next = next->next;
4124 continue;
4125 }
4126 switch (INSN_OF(next)) {
4127 case BIN(nop):
4128 next = next->next;
4129 break;
4130 case BIN(jump):
4131 /* if cond
4132 * return tailcall
4133 * end
4134 */
4135 next = get_destination_insn((INSN *)next);
4136 break;
4137 case BIN(leave):
4138 piobj = iobj;
4139 /* fall through */
4140 default:
4141 next = NULL;
4142 break;
4143 }
4144 } while (next);
4145 }
4146
4147 if (piobj) {
4148 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4149 if (IS_INSN_ID(piobj, send) ||
4150 IS_INSN_ID(piobj, invokesuper)) {
4151 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4152 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4153 OPERAND_AT(piobj, 0) = (VALUE)ci;
4154 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4155 }
4156 }
4157 else {
4158 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4159 OPERAND_AT(piobj, 0) = (VALUE)ci;
4160 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4161 }
4162 }
4163 }
4164
4165 if (IS_INSN_ID(iobj, dup)) {
4166 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4167 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4168
4169 /*
4170 * dup
4171 * setlocal x, y
4172 * setlocal x, y
4173 * =>
4174 * dup
4175 * setlocal x, y
4176 */
4177 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4178 set2 = set1->next;
4179 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4180 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4181 ELEM_REMOVE(set1);
4182 ELEM_REMOVE(&iobj->link);
4183 }
4184 }
4185
4186 /*
4187 * dup
4188 * setlocal x, y
4189 * dup
4190 * setlocal x, y
4191 * =>
4192 * dup
4193 * setlocal x, y
4194 */
4195 else if (IS_NEXT_INSN_ID(set1, dup) &&
4196 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4197 set2 = set1->next->next;
4198 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4199 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4200 ELEM_REMOVE(set1->next);
4201 ELEM_REMOVE(set2);
4202 }
4203 }
4204 }
4205 }
4206
4207 /*
4208 * getlocal x, y
4209 * dup
4210 * setlocal x, y
4211 * =>
4212 * dup
4213 */
4214 if (IS_INSN_ID(iobj, getlocal)) {
4215 LINK_ELEMENT *niobj = &iobj->link;
4216 if (IS_NEXT_INSN_ID(niobj, dup)) {
4217 niobj = niobj->next;
4218 }
4219 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4220 LINK_ELEMENT *set1 = niobj->next;
4221 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4222 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4223 ELEM_REMOVE(set1);
4224 ELEM_REMOVE(niobj);
4225 }
4226 }
4227 }
4228
4229 /*
4230 * opt_invokebuiltin_delegate
4231 * trace
4232 * leave
4233 * =>
4234 * opt_invokebuiltin_delegate_leave
4235 * trace
4236 * leave
4237 */
4238 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4239 if (IS_TRACE(iobj->link.next)) {
4240 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4241 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4242 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4243 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4244 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4245 }
4246 }
4247 }
4248 }
4249
4250 /*
4251 * getblockparam
4252 * branchif / branchunless
4253 * =>
4254 * getblockparamproxy
4255 * branchif / branchunless
4256 */
4257 if (IS_INSN_ID(iobj, getblockparam)) {
4258 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4259 iobj->insn_id = BIN(getblockparamproxy);
4260 }
4261 }
4262
4263 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4264 LINK_ELEMENT *niobj = &iobj->link;
4265 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4266 niobj = niobj->next;
4267 LINK_ELEMENT *siobj;
4268 unsigned int set_flags = 0, unset_flags = 0;
4269
4270 /*
4271 * Eliminate hash allocation for f(*a, kw: 1)
4272 *
4273 * splatarray false
4274 * duphash
4275 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4276 * =>
4277 * splatarray false
4278 * putobject
4279 * send ARGS_SPLAT|KW_SPLAT
4280 */
4281 if (IS_NEXT_INSN_ID(niobj, send)) {
4282 siobj = niobj->next;
4283 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4284 unset_flags = VM_CALL_ARGS_BLOCKARG;
4285 }
4286 /*
4287 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4288 *
4289 * splatarray false
4290 * duphash
4291 * getlocal / getinstancevariable / getblockparamproxy
4292 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4293 * =>
4294 * splatarray false
4295 * putobject
4296 * getlocal / getinstancevariable / getblockparamproxy
4297 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4298 */
4299 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4300 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4301 siobj = niobj->next->next;
4302 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4303 }
4304
4305 if (set_flags) {
4306 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4307 unsigned int flags = vm_ci_flag(ci);
4308 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4309 ((INSN*)niobj)->insn_id = BIN(putobject);
4310 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4311
4312 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4313 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4314 RB_OBJ_WRITTEN(iseq, ci, nci);
4315 OPERAND_AT(siobj, 0) = (VALUE)nci;
4316 }
4317 }
4318 }
4319 }
4320
4321 /*
4322 * putself / (or any other independent instruction)
4323 * putnil / (or any other independent instruction)
4324 * swap
4325 * =>
4326 * putnil / (or any other independent instruction)
4327 * putself / (or any other independent instruction)
4328 */
4329 if (IS_NEXT_NEXT_INSN_ID(&iobj->link, swap)) {
4330 LINK_ELEMENT *first = &iobj->link;
4331 LINK_ELEMENT *second = first->next;
4332 LINK_ELEMENT *swap = second->next;
4333 if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) {
4334 ELEM_REMOVE(swap);
4335 ELEM_SWAP(first, second);
4336 }
4337 }
4338
4339 return COMPILE_OK;
4340}
4341
4342static int
4343insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4344{
4345 if (insn_id == BIN(opt_neq)) {
4346 VALUE original_ci = iobj->operands[0];
4347 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4348 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4349 }
4350 else {
4351 iobj->insn_id = insn_id;
4352 iobj->operand_size = insn_len(insn_id) - 1;
4353 }
4354 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4355
4356 return COMPILE_OK;
4357}
4358
4359static int
4360iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4361{
4362 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4363 IS_INSN(iobj->link.next)) {
4364 /*
4365 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4366 */
4367 INSN *niobj = (INSN *)iobj->link.next;
4368 if (IS_INSN_ID(niobj, send)) {
4369 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4370 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4371 VALUE method = INT2FIX(0);
4372 switch (vm_ci_mid(ci)) {
4373 case idMax:
4374 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4375 break;
4376 case idMin:
4377 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4378 break;
4379 case idHash:
4380 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4381 break;
4382 }
4383
4384 if (method != INT2FIX(0)) {
4385 VALUE num = iobj->operands[0];
4386 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4387 ELEM_REMOVE(&niobj->link);
4388 return COMPILE_OK;
4389 }
4390 }
4391 }
4392 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4393 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4394 IS_NEXT_INSN_ID(&niobj->link, send)) {
4395 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4396 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4397 VALUE num = iobj->operands[0];
4398 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4399 ELEM_REMOVE(&iobj->link);
4400 ELEM_REMOVE(niobj->link.next);
4401 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4402 return COMPILE_OK;
4403 }
4404 }
4405 // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
4406 // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4407 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4408 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4409 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4410 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4411 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4412 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4413 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4414 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4415 VALUE num = iobj->operands[0];
4416 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4417 // Remove the "send" insn.
4418 ELEM_REMOVE((niobj->link.next)->next);
4419 // Remove the modified insn from its original "newarray" position...
4420 ELEM_REMOVE(&iobj->link);
4421 // and insert it after the buffer insn.
4422 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4423 return COMPILE_OK;
4424 }
4425 }
4426
4427 // Break the "else if" chain since some prior checks abort after sub-ifs.
4428 // We already found "newarray". To match `[...].include?(arg)` we look for
4429 // the instruction(s) representing the argument followed by a "send".
4430 if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4431 IS_INSN_ID(niobj, putobject) ||
4432 IS_INSN_ID(niobj, putself) ||
4433 IS_INSN_ID(niobj, getlocal) ||
4434 IS_INSN_ID(niobj, getinstancevariable)) &&
4435 IS_NEXT_INSN_ID(&niobj->link, send)) {
4436
4437 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4438 const struct rb_callinfo *ci;
4439 // Allow any number (0 or more) of simple method calls on the argument
4440 // (as in `[...].include?(arg.method1.method2)`.
4441 do {
4442 sendobj = sendobj->next;
4443 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4444 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4445
4446 // If this send is for .include? with one arg we can do our opt.
4447 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4448 VALUE num = iobj->operands[0];
4449 INSN *sendins = (INSN *)sendobj;
4450 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4451 // Remove the original "newarray" insn.
4452 ELEM_REMOVE(&iobj->link);
4453 return COMPILE_OK;
4454 }
4455 }
4456 }
4457
4458 /*
4459 * duparray [...]
4460 * some insn for the arg...
4461 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4462 * =>
4463 * arg insn...
4464 * opt_duparray_send [...], :include?, 1
4465 */
4466 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4467 INSN *niobj = (INSN *)iobj->link.next;
4468 if ((IS_INSN_ID(niobj, getlocal) ||
4469 IS_INSN_ID(niobj, getinstancevariable) ||
4470 IS_INSN_ID(niobj, putself) ||
4471 IS_INSN_ID(niobj, putobject) ||
4472 IS_INSN_ID(niobj, putnil)) &&
4473 IS_NEXT_INSN_ID(&niobj->link, send)) {
4474
4475 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4476 const struct rb_callinfo *ci;
4477 // Allow any number (0 or more) of simple method calls on the argument
4478 // (as in `[...].include?(arg.method1.method2)`.
4479 do {
4480 sendobj = sendobj->next;
4481 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4482 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4483
4484 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4485 // Move the array arg from duparray to opt_duparray_send.
4486 VALUE ary = iobj->operands[0];
4488
4489 INSN *sendins = (INSN *)sendobj;
4490 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4491
4492 // Remove the duparray insn.
4493 ELEM_REMOVE(&iobj->link);
4494 return COMPILE_OK;
4495 }
4496 }
4497 }
4498
4499
4500 if (IS_INSN_ID(iobj, send)) {
4501 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4502 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4503
4504#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4505 if (vm_ci_simple(ci)) {
4506 switch (vm_ci_argc(ci)) {
4507 case 0:
4508 switch (vm_ci_mid(ci)) {
4509 case idLength: SP_INSN(length); return COMPILE_OK;
4510 case idSize: SP_INSN(size); return COMPILE_OK;
4511 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4512 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4513 case idSucc: SP_INSN(succ); return COMPILE_OK;
4514 case idNot: SP_INSN(not); return COMPILE_OK;
4515 }
4516 break;
4517 case 1:
4518 switch (vm_ci_mid(ci)) {
4519 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4520 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4521 case idMULT: SP_INSN(mult); return COMPILE_OK;
4522 case idDIV: SP_INSN(div); return COMPILE_OK;
4523 case idMOD: SP_INSN(mod); return COMPILE_OK;
4524 case idEq: SP_INSN(eq); return COMPILE_OK;
4525 case idNeq: SP_INSN(neq); return COMPILE_OK;
4526 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4527 case idLT: SP_INSN(lt); return COMPILE_OK;
4528 case idLE: SP_INSN(le); return COMPILE_OK;
4529 case idGT: SP_INSN(gt); return COMPILE_OK;
4530 case idGE: SP_INSN(ge); return COMPILE_OK;
4531 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4532 case idAREF: SP_INSN(aref); return COMPILE_OK;
4533 case idAnd: SP_INSN(and); return COMPILE_OK;
4534 case idOr: SP_INSN(or); return COMPILE_OK;
4535 }
4536 break;
4537 case 2:
4538 switch (vm_ci_mid(ci)) {
4539 case idASET: SP_INSN(aset); return COMPILE_OK;
4540 }
4541 break;
4542 }
4543 }
4544
4545 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4546 iobj->insn_id = BIN(opt_send_without_block);
4547 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4548 }
4549 }
4550#undef SP_INSN
4551
4552 return COMPILE_OK;
4553}
4554
4555static inline int
4556tailcallable_p(rb_iseq_t *iseq)
4557{
4558 switch (ISEQ_BODY(iseq)->type) {
4559 case ISEQ_TYPE_TOP:
4560 case ISEQ_TYPE_EVAL:
4561 case ISEQ_TYPE_MAIN:
4562 /* not tail callable because cfp will be over popped */
4563 case ISEQ_TYPE_RESCUE:
4564 case ISEQ_TYPE_ENSURE:
4565 /* rescue block can't tail call because of errinfo */
4566 return FALSE;
4567 default:
4568 return TRUE;
4569 }
4570}
4571
4572static int
4573iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4574{
4575 LINK_ELEMENT *list;
4576 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4577 const int do_tailcallopt = tailcallable_p(iseq) &&
4578 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4579 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4580 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4581 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4582 int rescue_level = 0;
4583 int tailcallopt = do_tailcallopt;
4584
4585 list = FIRST_ELEMENT(anchor);
4586
4587 int do_block_optimization = 0;
4588 LABEL * block_loop_label = NULL;
4589
4590 // If we're optimizing a block
4591 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4592 do_block_optimization = 1;
4593
4594 // If the block starts with a nop and a label,
4595 // record the label so we can detect if it's a jump target
4596 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4597 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4598 block_loop_label = (LABEL *)le->next;
4599 }
4600 }
4601
4602 while (list) {
4603 if (IS_INSN(list)) {
4604 if (do_peepholeopt) {
4605 iseq_peephole_optimize(iseq, list, tailcallopt);
4606 }
4607 if (do_si) {
4608 iseq_specialized_instruction(iseq, (INSN *)list);
4609 }
4610 if (do_ou) {
4611 insn_operands_unification((INSN *)list);
4612 }
4613
4614 if (do_without_ints) {
4615 INSN *item = (INSN *)list;
4616 if (IS_INSN_ID(item, jump)) {
4617 item->insn_id = BIN(jump_without_ints);
4618 }
4619 else if (IS_INSN_ID(item, branchif)) {
4620 item->insn_id = BIN(branchif_without_ints);
4621 }
4622 else if (IS_INSN_ID(item, branchunless)) {
4623 item->insn_id = BIN(branchunless_without_ints);
4624 }
4625 else if (IS_INSN_ID(item, branchnil)) {
4626 item->insn_id = BIN(branchnil_without_ints);
4627 }
4628 }
4629
4630 if (do_block_optimization) {
4631 INSN * item = (INSN *)list;
4632 // Give up if there is a throw
4633 if (IS_INSN_ID(item, throw)) {
4634 do_block_optimization = 0;
4635 }
4636 else {
4637 // If the instruction has a jump target, check if the
4638 // jump target is the block loop label
4639 const char *types = insn_op_types(item->insn_id);
4640 for (int j = 0; types[j]; j++) {
4641 if (types[j] == TS_OFFSET) {
4642 // If the jump target is equal to the block loop
4643 // label, then we can't do the optimization because
4644 // the leading `nop` instruction fires the block
4645 // entry tracepoint
4646 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4647 if (target == block_loop_label) {
4648 do_block_optimization = 0;
4649 }
4650 }
4651 }
4652 }
4653 }
4654 }
4655 if (IS_LABEL(list)) {
4656 switch (((LABEL *)list)->rescued) {
4657 case LABEL_RESCUE_BEG:
4658 rescue_level++;
4659 tailcallopt = FALSE;
4660 break;
4661 case LABEL_RESCUE_END:
4662 if (!--rescue_level) tailcallopt = do_tailcallopt;
4663 break;
4664 }
4665 }
4666 list = list->next;
4667 }
4668
4669 if (do_block_optimization) {
4670 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4671 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4672 ELEM_REMOVE(le);
4673 }
4674 }
4675 return COMPILE_OK;
4676}
4677
4678#if OPT_INSTRUCTIONS_UNIFICATION
4679static INSN *
4680new_unified_insn(rb_iseq_t *iseq,
4681 int insn_id, int size, LINK_ELEMENT *seq_list)
4682{
4683 INSN *iobj = 0;
4684 LINK_ELEMENT *list = seq_list;
4685 int i, argc = 0;
4686 VALUE *operands = 0, *ptr = 0;
4687
4688
4689 /* count argc */
4690 for (i = 0; i < size; i++) {
4691 iobj = (INSN *)list;
4692 argc += iobj->operand_size;
4693 list = list->next;
4694 }
4695
4696 if (argc > 0) {
4697 ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
4698 }
4699
4700 /* copy operands */
4701 list = seq_list;
4702 for (i = 0; i < size; i++) {
4703 iobj = (INSN *)list;
4704 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4705 ptr += iobj->operand_size;
4706 list = list->next;
4707 }
4708
4709 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4710}
4711#endif
4712
4713/*
4714 * This scheme can get more performance if do this optimize with
4715 * label address resolving.
4716 * It's future work (if compile time was bottle neck).
4717 */
4718static int
4719iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4720{
4721#if OPT_INSTRUCTIONS_UNIFICATION
4722 LINK_ELEMENT *list;
4723 INSN *iobj, *niobj;
4724 int id, k;
4725 intptr_t j;
4726
4727 list = FIRST_ELEMENT(anchor);
4728 while (list) {
4729 if (IS_INSN(list)) {
4730 iobj = (INSN *)list;
4731 id = iobj->insn_id;
4732 if (unified_insns_data[id] != 0) {
4733 const int *const *entry = unified_insns_data[id];
4734 for (j = 1; j < (intptr_t)entry[0]; j++) {
4735 const int *unified = entry[j];
4736 LINK_ELEMENT *li = list->next;
4737 for (k = 2; k < unified[1]; k++) {
4738 if (!IS_INSN(li) ||
4739 ((INSN *)li)->insn_id != unified[k]) {
4740 goto miss;
4741 }
4742 li = li->next;
4743 }
4744 /* matched */
4745 niobj =
4746 new_unified_insn(iseq, unified[0], unified[1] - 1,
4747 list);
4748
4749 /* insert to list */
4750 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4751 niobj->link.next = li;
4752 if (li) {
4753 li->prev = (LINK_ELEMENT *)niobj;
4754 }
4755
4756 list->prev->next = (LINK_ELEMENT *)niobj;
4757 list = (LINK_ELEMENT *)niobj;
4758 break;
4759 miss:;
4760 }
4761 }
4762 }
4763 list = list->next;
4764 }
4765#endif
4766 return COMPILE_OK;
4767}
4768
4769static int
4770all_string_result_p(const NODE *node)
4771{
4772 if (!node) return FALSE;
4773 switch (nd_type(node)) {
4774 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4775 return TRUE;
4776 case NODE_IF: case NODE_UNLESS:
4777 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4778 if (all_string_result_p(RNODE_IF(node)->nd_body))
4779 return all_string_result_p(RNODE_IF(node)->nd_else);
4780 return FALSE;
4781 case NODE_AND: case NODE_OR:
4782 if (!RNODE_AND(node)->nd_2nd)
4783 return all_string_result_p(RNODE_AND(node)->nd_1st);
4784 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4785 return FALSE;
4786 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4787 default:
4788 return FALSE;
4789 }
4790}
4791
4793 rb_iseq_t *const iseq;
4794 LINK_ANCHOR *const ret;
4795 VALUE lit;
4796 const NODE *lit_node;
4797 int cnt;
4798 int dregx;
4799};
4800
4801static int
4802append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4803{
4804 VALUE s = rb_str_new_mutable_parser_string(str);
4805 if (args->dregx) {
4806 VALUE error = rb_reg_check_preprocess(s);
4807 if (!NIL_P(error)) {
4808 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4809 return COMPILE_NG;
4810 }
4811 }
4812 if (NIL_P(args->lit)) {
4813 args->lit = s;
4814 args->lit_node = node;
4815 }
4816 else {
4817 rb_str_buf_append(args->lit, s);
4818 }
4819 return COMPILE_OK;
4820}
4821
4822static void
4823flush_dstr_fragment(struct dstr_ctxt *args)
4824{
4825 if (!NIL_P(args->lit)) {
4826 rb_iseq_t *iseq = args->iseq;
4827 VALUE lit = args->lit;
4828 args->lit = Qnil;
4829 lit = rb_fstring(lit);
4830 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4831 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4832 args->cnt++;
4833 }
4834}
4835
4836static int
4837compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4838{
4839 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4840 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4841
4842 if (str) {
4843 CHECK(append_dstr_fragment(args, node, str));
4844 }
4845
4846 while (list) {
4847 const NODE *const head = list->nd_head;
4848 if (nd_type_p(head, NODE_STR)) {
4849 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4850 }
4851 else if (nd_type_p(head, NODE_DSTR)) {
4852 CHECK(compile_dstr_fragments_0(args, head));
4853 }
4854 else {
4855 flush_dstr_fragment(args);
4856 rb_iseq_t *iseq = args->iseq;
4857 CHECK(COMPILE(args->ret, "each string", head));
4858 args->cnt++;
4859 }
4860 list = (struct RNode_LIST *)list->nd_next;
4861 }
4862 return COMPILE_OK;
4863}
4864
4865static int
4866compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4867{
4868 struct dstr_ctxt args = {
4869 .iseq = iseq, .ret = ret,
4870 .lit = Qnil, .lit_node = NULL,
4871 .cnt = 0, .dregx = dregx,
4872 };
4873 CHECK(compile_dstr_fragments_0(&args, node));
4874 flush_dstr_fragment(&args);
4875
4876 *cntp = args.cnt;
4877
4878 return COMPILE_OK;
4879}
4880
4881static int
4882compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4883{
4884 while (node && nd_type_p(node, NODE_BLOCK)) {
4885 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4886 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4887 node = RNODE_BLOCK(node)->nd_next;
4888 }
4889 if (node) {
4890 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4891 }
4892 return COMPILE_OK;
4893}
4894
4895static int
4896compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4897{
4898 int cnt;
4899 if (!RNODE_DSTR(node)->nd_next) {
4900 VALUE lit = rb_node_dstr_string_val(node);
4901 ADD_INSN1(ret, node, dupstring, lit);
4903 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4904 }
4905 else {
4906 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4907 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4908 }
4909 return COMPILE_OK;
4910}
4911
4912static int
4913compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4914{
4915 int cnt;
4916 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4917
4918 if (!RNODE_DREGX(node)->nd_next) {
4919 if (!popped) {
4920 VALUE src = rb_node_dregx_string_val(node);
4921 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4922 ADD_INSN1(ret, node, putobject, match);
4923 RB_OBJ_WRITTEN(iseq, Qundef, match);
4924 }
4925 return COMPILE_OK;
4926 }
4927
4928 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4929 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4930
4931 if (popped) {
4932 ADD_INSN(ret, node, pop);
4933 }
4934
4935 return COMPILE_OK;
4936}
4937
4938static int
4939compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4940 LABEL *then_label, LABEL *else_label)
4941{
4942 const int line = nd_line(node);
4943 LABEL *lend = NEW_LABEL(line);
4944 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4945 + VM_SVAR_FLIPFLOP_START;
4946 VALUE key = INT2FIX(cnt);
4947
4948 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4949 ADD_INSNL(ret, node, branchif, lend);
4950
4951 /* *flip == 0 */
4952 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4953 ADD_INSNL(ret, node, branchunless, else_label);
4954 ADD_INSN1(ret, node, putobject, Qtrue);
4955 ADD_INSN1(ret, node, setspecial, key);
4956 if (!again) {
4957 ADD_INSNL(ret, node, jump, then_label);
4958 }
4959
4960 /* *flip == 1 */
4961 ADD_LABEL(ret, lend);
4962 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4963 ADD_INSNL(ret, node, branchunless, then_label);
4964 ADD_INSN1(ret, node, putobject, Qfalse);
4965 ADD_INSN1(ret, node, setspecial, key);
4966 ADD_INSNL(ret, node, jump, then_label);
4967
4968 return COMPILE_OK;
4969}
4970
4971static int
4972compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4973 LABEL *then_label, LABEL *else_label);
4974
4975#define COMPILE_SINGLE 2
4976static int
4977compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4978 LABEL *then_label, LABEL *else_label)
4979{
4980 DECL_ANCHOR(seq);
4981 INIT_ANCHOR(seq);
4982 LABEL *label = NEW_LABEL(nd_line(cond));
4983 if (!then_label) then_label = label;
4984 else if (!else_label) else_label = label;
4985
4986 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4987
4988 if (LIST_INSN_SIZE_ONE(seq)) {
4989 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4990 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4991 return COMPILE_OK;
4992 }
4993 if (!label->refcnt) {
4994 return COMPILE_SINGLE;
4995 }
4996 ADD_LABEL(seq, label);
4997 ADD_SEQ(ret, seq);
4998 return COMPILE_OK;
4999}
5000
5001static int
5002compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
5003 LABEL *then_label, LABEL *else_label)
5004{
5005 int ok;
5006 DECL_ANCHOR(ignore);
5007
5008 again:
5009 switch (nd_type(cond)) {
5010 case NODE_AND:
5011 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
5012 cond = RNODE_AND(cond)->nd_2nd;
5013 if (ok == COMPILE_SINGLE) {
5014 ADD_INSNL(ret, cond, jump, else_label);
5015 INIT_ANCHOR(ignore);
5016 ret = ignore;
5017 then_label = NEW_LABEL(nd_line(cond));
5018 }
5019 goto again;
5020 case NODE_OR:
5021 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
5022 cond = RNODE_OR(cond)->nd_2nd;
5023 if (ok == COMPILE_SINGLE) {
5024 ADD_INSNL(ret, cond, jump, then_label);
5025 INIT_ANCHOR(ignore);
5026 ret = ignore;
5027 else_label = NEW_LABEL(nd_line(cond));
5028 }
5029 goto again;
5030 case NODE_SYM:
5031 case NODE_LINE:
5032 case NODE_FILE:
5033 case NODE_ENCODING:
5034 case NODE_INTEGER: /* NODE_INTEGER is always true */
5035 case NODE_FLOAT: /* NODE_FLOAT is always true */
5036 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
5037 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
5038 case NODE_TRUE:
5039 case NODE_STR:
5040 case NODE_REGX:
5041 case NODE_ZLIST:
5042 case NODE_LAMBDA:
5043 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5044 ADD_INSNL(ret, cond, jump, then_label);
5045 return COMPILE_OK;
5046 case NODE_FALSE:
5047 case NODE_NIL:
5048 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5049 ADD_INSNL(ret, cond, jump, else_label);
5050 return COMPILE_OK;
5051 case NODE_LIST:
5052 case NODE_ARGSCAT:
5053 case NODE_DREGX:
5054 case NODE_DSTR:
5055 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
5056 ADD_INSNL(ret, cond, jump, then_label);
5057 return COMPILE_OK;
5058 case NODE_FLIP2:
5059 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
5060 return COMPILE_OK;
5061 case NODE_FLIP3:
5062 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
5063 return COMPILE_OK;
5064 case NODE_DEFINED:
5065 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
5066 break;
5067 default:
5068 {
5069 DECL_ANCHOR(cond_seq);
5070 INIT_ANCHOR(cond_seq);
5071
5072 CHECK(COMPILE(cond_seq, "branch condition", cond));
5073
5074 if (LIST_INSN_SIZE_ONE(cond_seq)) {
5075 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
5076 if (insn->insn_id == BIN(putobject)) {
5077 if (RTEST(insn->operands[0])) {
5078 ADD_INSNL(ret, cond, jump, then_label);
5079 // maybe unreachable
5080 return COMPILE_OK;
5081 }
5082 else {
5083 ADD_INSNL(ret, cond, jump, else_label);
5084 return COMPILE_OK;
5085 }
5086 }
5087 }
5088 ADD_SEQ(ret, cond_seq);
5089 }
5090 break;
5091 }
5092
5093 ADD_INSNL(ret, cond, branchunless, else_label);
5094 ADD_INSNL(ret, cond, jump, then_label);
5095 return COMPILE_OK;
5096}
5097
5098#define HASH_BRACE 1
5099
5100static int
5101keyword_node_p(const NODE *const node)
5102{
5103 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
5104}
5105
5106static VALUE
5107get_symbol_value(rb_iseq_t *iseq, const NODE *node)
5108{
5109 switch (nd_type(node)) {
5110 case NODE_SYM:
5111 return rb_node_sym_string_val(node);
5112 default:
5113 UNKNOWN_NODE("get_symbol_value", node, Qnil);
5114 }
5115}
5116
5117static VALUE
5118node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
5119{
5120 NODE *node = node_hash->nd_head;
5121 VALUE hash = rb_hash_new();
5122 VALUE ary = rb_ary_new();
5123
5124 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5125 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
5126 VALUE idx = rb_hash_aref(hash, key);
5127 if (!NIL_P(idx)) {
5128 rb_ary_store(ary, FIX2INT(idx), Qfalse);
5129 (*count_ptr)--;
5130 }
5131 rb_hash_aset(hash, key, INT2FIX(i));
5132 rb_ary_store(ary, i, Qtrue);
5133 (*count_ptr)++;
5134 }
5135
5136 return ary;
5137}
5138
5139static int
5140compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5141 const NODE *const root_node,
5142 struct rb_callinfo_kwarg **const kw_arg_ptr,
5143 unsigned int *flag)
5144{
5145 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5146 RUBY_ASSERT(kw_arg_ptr != NULL);
5147 RUBY_ASSERT(flag != NULL);
5148
5149 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5150 const NODE *node = RNODE_HASH(root_node)->nd_head;
5151 int seen_nodes = 0;
5152
5153 while (node) {
5154 const NODE *key_node = RNODE_LIST(node)->nd_head;
5155 seen_nodes++;
5156
5157 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5158 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5159 /* can be keywords */
5160 }
5161 else {
5162 if (flag) {
5163 *flag |= VM_CALL_KW_SPLAT;
5164 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5165 /* A new hash will be created for the keyword arguments
5166 * in this case, so mark the method as passing mutable
5167 * keyword splat.
5168 */
5169 *flag |= VM_CALL_KW_SPLAT_MUT;
5170 }
5171 }
5172 return FALSE;
5173 }
5174 node = RNODE_LIST(node)->nd_next; /* skip value node */
5175 node = RNODE_LIST(node)->nd_next;
5176 }
5177
5178 /* may be keywords */
5179 node = RNODE_HASH(root_node)->nd_head;
5180 {
5181 int len = 0;
5182 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5183
5184 if (len > VM_CALL_KW_LEN_MAX) {
5185 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5186 len, (int)VM_CALL_KW_LEN_MAX);
5187 }
5188
5189 struct rb_callinfo_kwarg *kw_arg =
5190 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5191 VALUE *keywords = kw_arg->keywords;
5192 int i = 0;
5193 int j = 0;
5194 kw_arg->references = 0;
5195 kw_arg->keyword_len = len;
5196
5197 *kw_arg_ptr = kw_arg;
5198
5199 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5200 const NODE *key_node = RNODE_LIST(node)->nd_head;
5201 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5202 int popped = TRUE;
5203 if (rb_ary_entry(key_index, i)) {
5204 keywords[j] = get_symbol_value(iseq, key_node);
5205 j++;
5206 popped = FALSE;
5207 }
5208 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5209 }
5210 RUBY_ASSERT(j == len);
5211 return TRUE;
5212 }
5213 }
5214 return FALSE;
5215}
5216
5217static int
5218compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5219{
5220 int len = 0;
5221
5222 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5223 if (CPDEBUG > 0) {
5224 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5225 }
5226
5227 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5228 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5229 }
5230 else {
5231 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5232 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5233 }
5234 }
5235
5236 return len;
5237}
5238
5239static inline bool
5240frozen_string_literal_p(const rb_iseq_t *iseq)
5241{
5242 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5243}
5244
5245static inline bool
5246static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5247{
5248 switch (nd_type(node)) {
5249 case NODE_SYM:
5250 case NODE_REGX:
5251 case NODE_LINE:
5252 case NODE_ENCODING:
5253 case NODE_INTEGER:
5254 case NODE_FLOAT:
5255 case NODE_RATIONAL:
5256 case NODE_IMAGINARY:
5257 case NODE_NIL:
5258 case NODE_TRUE:
5259 case NODE_FALSE:
5260 return TRUE;
5261 case NODE_STR:
5262 case NODE_FILE:
5263 return hash_key || frozen_string_literal_p(iseq);
5264 default:
5265 return FALSE;
5266 }
5267}
5268
5269static inline VALUE
5270static_literal_value(const NODE *node, rb_iseq_t *iseq)
5271{
5272 switch (nd_type(node)) {
5273 case NODE_INTEGER:
5274 {
5275 VALUE lit = rb_node_integer_literal_val(node);
5276 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5277 return lit;
5278 }
5279 case NODE_FLOAT:
5280 {
5281 VALUE lit = rb_node_float_literal_val(node);
5282 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5283 return lit;
5284 }
5285 case NODE_RATIONAL:
5286 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5287 case NODE_IMAGINARY:
5288 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5289 case NODE_NIL:
5290 return Qnil;
5291 case NODE_TRUE:
5292 return Qtrue;
5293 case NODE_FALSE:
5294 return Qfalse;
5295 case NODE_SYM:
5296 return rb_node_sym_string_val(node);
5297 case NODE_REGX:
5298 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5299 case NODE_LINE:
5300 return rb_node_line_lineno_val(node);
5301 case NODE_ENCODING:
5302 return rb_node_encoding_val(node);
5303 case NODE_FILE:
5304 case NODE_STR:
5305 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5306 VALUE lit = get_string_value(node);
5307 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5309 return str;
5310 }
5311 else {
5312 return get_string_value(node);
5313 }
5314 default:
5315 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5316 }
5317}
5318
5319static int
5320compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5321{
5322 const NODE *line_node = node;
5323
5324 if (nd_type_p(node, NODE_ZLIST)) {
5325 if (!popped) {
5326 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5327 }
5328 return 0;
5329 }
5330
5331 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5332
5333 if (popped) {
5334 for (; node; node = RNODE_LIST(node)->nd_next) {
5335 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5336 }
5337 return 1;
5338 }
5339
5340 /* Compilation of an array literal.
5341 * The following code is essentially the same as:
5342 *
5343 * for (int count = 0; node; count++; node->nd_next) {
5344 * compile(node->nd_head);
5345 * }
5346 * ADD_INSN(newarray, count);
5347 *
5348 * However, there are three points.
5349 *
5350 * - The code above causes stack overflow for a big string literal.
5351 * The following limits the stack length up to max_stack_len.
5352 *
5353 * [x1,x2,...,x10000] =>
5354 * push x1 ; push x2 ; ...; push x256; newarray 256;
5355 * push x257; push x258; ...; push x512; pushtoarray 256;
5356 * push x513; push x514; ...; push x768; pushtoarray 256;
5357 * ...
5358 *
5359 * - Long subarray can be optimized by pre-allocating a hidden array.
5360 *
5361 * [1,2,3,...,100] =>
5362 * duparray [1,2,3,...,100]
5363 *
5364 * [x, 1,2,3,...,100, z] =>
5365 * push x; newarray 1;
5366 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5367 * push z; pushtoarray 1;
5368 *
5369 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5370 * to only push it onto the array if it is not empty
5371 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5372 *
5373 * [1,2,3,**kw] =>
5374 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5375 */
5376
5377 const int max_stack_len = 0x100;
5378 const int min_tmp_ary_len = 0x40;
5379 int stack_len = 0;
5380
5381 /* Either create a new array, or push to the existing array */
5382#define FLUSH_CHUNK \
5383 if (stack_len) { \
5384 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5385 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5386 first_chunk = FALSE; \
5387 stack_len = 0; \
5388 }
5389
5390 while (node) {
5391 int count = 1;
5392
5393 /* pre-allocation check (this branch can be omittable) */
5394 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5395 /* count the elements that are optimizable */
5396 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5397 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5398 count++;
5399
5400 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5401 /* The literal contains only optimizable elements, or the subarray is long enough */
5402 VALUE ary = rb_ary_hidden_new(count);
5403
5404 /* Create a hidden array */
5405 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5406 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5408
5409 /* Emit optimized code */
5410 FLUSH_CHUNK;
5411 if (first_chunk) {
5412 ADD_INSN1(ret, line_node, duparray, ary);
5413 first_chunk = FALSE;
5414 }
5415 else {
5416 ADD_INSN1(ret, line_node, putobject, ary);
5417 ADD_INSN(ret, line_node, concattoarray);
5418 }
5420 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5421 }
5422 }
5423
5424 /* Base case: Compile "count" elements */
5425 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5426 if (CPDEBUG > 0) {
5427 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5428 }
5429
5430 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5431 /* Create array or push existing non-keyword elements onto array */
5432 if (stack_len == 0 && first_chunk) {
5433 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5434 }
5435 else {
5436 FLUSH_CHUNK;
5437 }
5438 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5439 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5440 return 1;
5441 }
5442 else {
5443 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5444 stack_len++;
5445 }
5446
5447 /* If there are many pushed elements, flush them to avoid stack overflow */
5448 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5449 }
5450 }
5451
5452 FLUSH_CHUNK;
5453#undef FLUSH_CHUNK
5454 return 1;
5455}
5456
5457static inline int
5458static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5459{
5460 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);
5461}
5462
5463static int
5464compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5465{
5466 const NODE *line_node = node;
5467
5468 node = RNODE_HASH(node)->nd_head;
5469
5470 if (!node || nd_type_p(node, NODE_ZLIST)) {
5471 if (!popped) {
5472 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5473 }
5474 return 0;
5475 }
5476
5477 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5478
5479 if (popped) {
5480 for (; node; node = RNODE_LIST(node)->nd_next) {
5481 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5482 }
5483 return 1;
5484 }
5485
5486 /* Compilation of a hash literal (or keyword arguments).
5487 * This is very similar to compile_array, but there are some differences:
5488 *
5489 * - It contains key-value pairs. So we need to take every two elements.
5490 * We can assume that the length is always even.
5491 *
5492 * - Merging is done by a method call (id_core_hash_merge_bang_ptr).
5493 * Sometimes we need to insert the receiver, so "anchor" is needed.
5494 * In addition, a method call is much slower than concatarray.
5495 * So it pays only when the subsequence is really long.
5496 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5497 *
5498 * - We need to handle keyword splat: **kw.
5499 * For **kw, the key part (node->nd_head) is NULL, and the value part
5500 * (node->nd_next->nd_head) is "kw".
5501 * The code is a bit difficult to avoid hash allocation for **{}.
5502 */
5503
5504 const int max_stack_len = 0x100;
5505 const int min_tmp_hash_len = 0x800;
5506 int stack_len = 0;
5507 int first_chunk = 1;
5508 DECL_ANCHOR(anchor);
5509 INIT_ANCHOR(anchor);
5510
5511 /* Convert pushed elements to a hash, and merge if needed */
5512#define FLUSH_CHUNK() \
5513 if (stack_len) { \
5514 if (first_chunk) { \
5515 APPEND_LIST(ret, anchor); \
5516 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5517 } \
5518 else { \
5519 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5520 ADD_INSN(ret, line_node, swap); \
5521 APPEND_LIST(ret, anchor); \
5522 ADD_SEND(ret, line_node, id_core_hash_merge_bang_ptr, INT2FIX(stack_len + 1)); \
5523 } \
5524 INIT_ANCHOR(anchor); \
5525 first_chunk = stack_len = 0; \
5526 }
5527
5528 while (node) {
5529 int count = 1;
5530
5531 /* pre-allocation check (this branch can be omittable) */
5532 if (static_literal_node_pair_p(node, iseq)) {
5533 /* count the elements that are optimizable */
5534 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5535 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5536 count++;
5537
5538 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5539 /* The literal contains only optimizable elements, or the subsequence is long enough */
5540 VALUE ary = rb_ary_hidden_new(count);
5541
5542 /* Create a hidden hash */
5543 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5544 VALUE elem[2];
5545 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5546 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5547 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5548 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5549 rb_ary_cat(ary, elem, 2);
5550 }
5551 VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
5552 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5553 RB_GC_GUARD(ary);
5554 hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
5555
5556 /* Emit optimized code */
5557 FLUSH_CHUNK();
5558 if (first_chunk) {
5559 ADD_INSN1(ret, line_node, duphash, hash);
5560 first_chunk = 0;
5561 }
5562 else {
5563 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5564 ADD_INSN(ret, line_node, swap);
5565
5566 ADD_INSN1(ret, line_node, putobject, hash);
5567
5568 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5569 }
5570 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5571 }
5572 }
5573
5574 /* Base case: Compile "count" elements */
5575 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5576
5577 if (CPDEBUG > 0) {
5578 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5579 }
5580
5581 if (RNODE_LIST(node)->nd_head) {
5582 /* Normal key-value pair */
5583 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5584 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5585 stack_len += 2;
5586
5587 /* If there are many pushed elements, flush them to avoid stack overflow */
5588 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5589 }
5590 else {
5591 /* kwsplat case: foo(..., **kw, ...) */
5592 FLUSH_CHUNK();
5593
5594 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5595 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5596 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5597 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5598 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5599
5600 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5601 if (empty_kw) {
5602 if (only_kw && method_call_keywords) {
5603 /* **{} appears at the only keyword argument in method call,
5604 * so it won't be modified.
5605 * kw is a special NODE_LIT that contains a special empty hash,
5606 * so this emits: putobject {}.
5607 * This is only done for method calls and not for literal hashes,
5608 * because literal hashes should always result in a new hash.
5609 */
5610 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5611 }
5612 else if (first_kw) {
5613 /* **{} appears as the first keyword argument, so it may be modified.
5614 * We need to create a fresh hash object.
5615 */
5616 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5617 }
5618 /* Any empty keyword splats that are not the first can be ignored.
5619 * since merging an empty hash into the existing hash is the same
5620 * as not merging it. */
5621 }
5622 else {
5623 if (only_kw && method_call_keywords) {
5624 /* **kw is only keyword argument in method call.
5625 * Use directly. This will be not be flagged as mutable.
5626 * This is only done for method calls and not for literal hashes,
5627 * because literal hashes should always result in a new hash.
5628 */
5629 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5630 }
5631 else {
5632 /* There is more than one keyword argument, or this is not a method
5633 * call. In that case, we need to add an empty hash (if first keyword),
5634 * or merge the hash to the accumulated hash (if not the first keyword).
5635 */
5636 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5637 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5638 else ADD_INSN(ret, line_node, swap);
5639
5640 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5641
5642 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5643 }
5644 }
5645
5646 first_chunk = 0;
5647 }
5648 }
5649 }
5650
5651 FLUSH_CHUNK();
5652#undef FLUSH_CHUNK
5653 return 1;
5654}
5655
5656static VALUE
5657rb_node_case_when_optimizable_literal(const NODE *const node)
5658{
5659 switch (nd_type(node)) {
5660 case NODE_INTEGER:
5661 return rb_node_integer_literal_val(node);
5662 case NODE_FLOAT: {
5663 VALUE v = rb_node_float_literal_val(node);
5664 double ival;
5665
5666 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5667 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5668 }
5669 return v;
5670 }
5671 case NODE_RATIONAL:
5672 case NODE_IMAGINARY:
5673 return Qundef;
5674 case NODE_NIL:
5675 return Qnil;
5676 case NODE_TRUE:
5677 return Qtrue;
5678 case NODE_FALSE:
5679 return Qfalse;
5680 case NODE_SYM:
5681 return rb_node_sym_string_val(node);
5682 case NODE_LINE:
5683 return rb_node_line_lineno_val(node);
5684 case NODE_STR:
5685 return rb_node_str_string_val(node);
5686 case NODE_FILE:
5687 return rb_node_file_path_val(node);
5688 }
5689 return Qundef;
5690}
5691
5692static int
5693when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5694 LABEL *l1, int only_special_literals, VALUE literals)
5695{
5696 while (vals) {
5697 const NODE *val = RNODE_LIST(vals)->nd_head;
5698 VALUE lit = rb_node_case_when_optimizable_literal(val);
5699
5700 if (UNDEF_P(lit)) {
5701 only_special_literals = 0;
5702 }
5703 else {
5704 cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
5705 }
5706
5707 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5708 debugp_param("nd_lit", get_string_value(val));
5709 lit = get_string_value(val);
5710 ADD_INSN1(cond_seq, val, putobject, lit);
5711 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5712 }
5713 else {
5714 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5715 }
5716
5717 // Emit pattern === target
5718 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5719 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5720 ADD_INSNL(cond_seq, val, branchif, l1);
5721 vals = RNODE_LIST(vals)->nd_next;
5722 }
5723 return only_special_literals;
5724}
5725
5726static int
5727when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5728 LABEL *l1, int only_special_literals, VALUE literals)
5729{
5730 const NODE *line_node = vals;
5731
5732 switch (nd_type(vals)) {
5733 case NODE_LIST:
5734 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5735 return COMPILE_NG;
5736 break;
5737 case NODE_SPLAT:
5738 ADD_INSN (cond_seq, line_node, dup);
5739 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5740 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5741 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5742 ADD_INSNL(cond_seq, line_node, branchif, l1);
5743 break;
5744 case NODE_ARGSCAT:
5745 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5746 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5747 break;
5748 case NODE_ARGSPUSH:
5749 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5750 ADD_INSN (cond_seq, line_node, dup);
5751 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5752 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5753 ADD_INSNL(cond_seq, line_node, branchif, l1);
5754 break;
5755 default:
5756 ADD_INSN (cond_seq, line_node, dup);
5757 CHECK(COMPILE(cond_seq, "when val", vals));
5758 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5759 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5760 ADD_INSNL(cond_seq, line_node, branchif, l1);
5761 break;
5762 }
5763 return COMPILE_OK;
5764}
5765
5766/* Multiple Assignment Handling
5767 *
5768 * In order to handle evaluation of multiple assignment such that the left hand side
5769 * is evaluated before the right hand side, we need to process the left hand side
5770 * and see if there are any attributes that need to be assigned, or constants set
5771 * on explicit objects. If so, we add instructions to evaluate the receiver of
5772 * any assigned attributes or constants before we process the right hand side.
5773 *
5774 * For a multiple assignment such as:
5775 *
5776 * l1.m1, l2[0] = r3, r4
5777 *
5778 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5779 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5780 * On the VM stack, this looks like:
5781 *
5782 * self # putself
5783 * l1 # send
5784 * l1, self # putself
5785 * l1, l2 # send
5786 * l1, l2, 0 # putobject 0
5787 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5788 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5789 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5790 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5791 * l1, l2, 0, [r3, r4], r4, m1= # send
5792 * l1, l2, 0, [r3, r4], r4 # pop
5793 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5794 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5795 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5796 * l1, l2, 0, [r3, r4], r4, []= # send
5797 * l1, l2, 0, [r3, r4], r4 # pop
5798 * l1, l2, 0, [r3, r4] # pop
5799 * [r3, r4], l2, 0, [r3, r4] # setn 3
5800 * [r3, r4], l2, 0 # pop
5801 * [r3, r4], l2 # pop
5802 * [r3, r4] # pop
5803 *
5804 * This is made more complex when you have to handle splats, post args,
5805 * and arbitrary levels of nesting. You need to keep track of the total
5806 * number of attributes to set, and for each attribute, how many entries
5807 * are on the stack before the final attribute, in order to correctly
5808 * calculate the topn value to use to get the receiver of the attribute
5809 * setter method.
5810 *
5811 * A brief description of the VM stack for simple multiple assignment
5812 * with no splat (rhs_array will not be present if the return value of
5813 * the multiple assignment is not needed):
5814 *
5815 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5816 *
5817 * For multiple assignment with splats, while processing the part before
5818 * the splat (splat+post here is an array of the splat and the post arguments):
5819 *
5820 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5821 *
5822 * When processing the splat and post arguments:
5823 *
5824 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5825 *
5826 * When processing nested multiple assignment, existing values on the stack
5827 * are kept. So for:
5828 *
5829 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5830 *
5831 * The stack layout would be the following before processing the nested
5832 * multiple assignment:
5833 *
5834 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5835 *
5836 * In order to handle this correctly, we need to keep track of the nesting
5837 * level for each attribute assignment, as well as the attribute number
5838 * (left hand side attributes are processed left to right) and number of
5839 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5840 * this information.
5841 *
5842 * We also need to track information for the entire multiple assignment, such
5843 * as the total number of arguments, and the current nesting level, to
5844 * handle both nested multiple assignment as well as cases where the
5845 * rhs is not needed. We also need to keep track of all attribute
5846 * assignments in this, which we do using a linked listed. struct masgn_state
5847 * tracks this information.
5848 */
5849
5851 INSN *before_insn;
5852 struct masgn_lhs_node *next;
5853 const NODE *line_node;
5854 int argn;
5855 int num_args;
5856 int lhs_pos;
5857};
5858
5860 struct masgn_lhs_node *first_memo;
5861 struct masgn_lhs_node *last_memo;
5862 int lhs_level;
5863 int num_args;
5864 bool nested;
5865};
5866
5867static int
5868add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5869{
5870 if (!state) {
5871 rb_bug("no masgn_state");
5872 }
5873
5874 struct masgn_lhs_node *memo;
5875 memo = malloc(sizeof(struct masgn_lhs_node));
5876 if (!memo) {
5877 return COMPILE_NG;
5878 }
5879
5880 memo->before_insn = before_insn;
5881 memo->line_node = line_node;
5882 memo->argn = state->num_args + 1;
5883 memo->num_args = argc;
5884 state->num_args += argc;
5885 memo->lhs_pos = lhs_pos;
5886 memo->next = NULL;
5887 if (!state->first_memo) {
5888 state->first_memo = memo;
5889 }
5890 else {
5891 state->last_memo->next = memo;
5892 }
5893 state->last_memo = memo;
5894
5895 return COMPILE_OK;
5896}
5897
5898static 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);
5899
5900static int
5901compile_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)
5902{
5903 switch (nd_type(node)) {
5904 case NODE_ATTRASGN: {
5905 INSN *iobj;
5906 const NODE *line_node = node;
5907
5908 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5909
5910 bool safenav_call = false;
5911 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5912 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5913 ASSUME(iobj);
5914 ELEM_REMOVE(insn_element);
5915 if (!IS_INSN_ID(iobj, send)) {
5916 safenav_call = true;
5917 iobj = (INSN *)get_prev_insn(iobj);
5918 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5919 }
5920 (pre->last = iobj->link.prev)->next = 0;
5921
5922 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5923 int argc = vm_ci_argc(ci) + 1;
5924 ci = ci_argc_set(iseq, ci, argc);
5925 OPERAND_AT(iobj, 0) = (VALUE)ci;
5926 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5927
5928 if (argc == 1) {
5929 ADD_INSN(lhs, line_node, swap);
5930 }
5931 else {
5932 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5933 }
5934
5935 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5936 return COMPILE_NG;
5937 }
5938
5939 iobj->link.prev = lhs->last;
5940 lhs->last->next = &iobj->link;
5941 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5942 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5943 int argc = vm_ci_argc(ci);
5944 bool dupsplat = false;
5945 ci = ci_argc_set(iseq, ci, argc - 1);
5946 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5947 /* Given h[*a], _ = ary
5948 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5949 * `a` must be dupped, because it will be appended with ary[0]
5950 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5951 */
5952 dupsplat = true;
5953 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5954 }
5955 OPERAND_AT(iobj, 0) = (VALUE)ci;
5956 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5957
5958 /* Given: h[*a], h[*b, 1] = ary
5959 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5960 * so this uses splatarray true on a to dup it before using pushtoarray
5961 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5962 * so you can use pushtoarray directly
5963 */
5964 int line_no = nd_line(line_node);
5965 int node_id = nd_node_id(line_node);
5966
5967 if (dupsplat) {
5968 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5969 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5970 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5971 }
5972 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5973 }
5974 if (!safenav_call) {
5975 ADD_INSN(lhs, line_node, pop);
5976 if (argc != 1) {
5977 ADD_INSN(lhs, line_node, pop);
5978 }
5979 }
5980 for (int i=0; i < argc; i++) {
5981 ADD_INSN(post, line_node, pop);
5982 }
5983 break;
5984 }
5985 case NODE_MASGN: {
5986 DECL_ANCHOR(nest_rhs);
5987 INIT_ANCHOR(nest_rhs);
5988 DECL_ANCHOR(nest_lhs);
5989 INIT_ANCHOR(nest_lhs);
5990
5991 int prev_level = state->lhs_level;
5992 bool prev_nested = state->nested;
5993 state->nested = 1;
5994 state->lhs_level = lhs_pos - 1;
5995 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5996 state->lhs_level = prev_level;
5997 state->nested = prev_nested;
5998
5999 ADD_SEQ(lhs, nest_rhs);
6000 ADD_SEQ(lhs, nest_lhs);
6001 break;
6002 }
6003 case NODE_CDECL:
6004 if (!RNODE_CDECL(node)->nd_vid) {
6005 /* Special handling only needed for expr::C, not for C */
6006 INSN *iobj;
6007
6008 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
6009
6010 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
6011 iobj = (INSN *)insn_element; /* setconstant insn */
6012 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
6013 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
6014 ELEM_REMOVE(insn_element);
6015 pre->last = iobj->link.prev;
6016 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
6017
6018 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
6019 return COMPILE_NG;
6020 }
6021
6022 ADD_INSN(post, node, pop);
6023 break;
6024 }
6025 /* Fallthrough */
6026 default: {
6027 DECL_ANCHOR(anchor);
6028 INIT_ANCHOR(anchor);
6029 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
6030 ELEM_REMOVE(FIRST_ELEMENT(anchor));
6031 ADD_SEQ(lhs, anchor);
6032 }
6033 }
6034
6035 return COMPILE_OK;
6036}
6037
6038static int
6039compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
6040{
6041 if (lhsn) {
6042 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
6043 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
6044 }
6045 return COMPILE_OK;
6046}
6047
6048static int
6049compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6050 const NODE *rhsn, const NODE *orig_lhsn)
6051{
6052 VALUE mem[64];
6053 const int memsize = numberof(mem);
6054 int memindex = 0;
6055 int llen = 0, rlen = 0;
6056 int i;
6057 const NODE *lhsn = orig_lhsn;
6058
6059#define MEMORY(v) { \
6060 int i; \
6061 if (memindex == memsize) return 0; \
6062 for (i=0; i<memindex; i++) { \
6063 if (mem[i] == (v)) return 0; \
6064 } \
6065 mem[memindex++] = (v); \
6066}
6067
6068 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
6069 return 0;
6070 }
6071
6072 while (lhsn) {
6073 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
6074 switch (nd_type(ln)) {
6075 case NODE_LASGN:
6076 case NODE_DASGN:
6077 case NODE_IASGN:
6078 case NODE_CVASGN:
6079 MEMORY(get_nd_vid(ln));
6080 break;
6081 default:
6082 return 0;
6083 }
6084 lhsn = RNODE_LIST(lhsn)->nd_next;
6085 llen++;
6086 }
6087
6088 while (rhsn) {
6089 if (llen <= rlen) {
6090 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
6091 }
6092 else {
6093 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
6094 }
6095 rhsn = RNODE_LIST(rhsn)->nd_next;
6096 rlen++;
6097 }
6098
6099 if (llen > rlen) {
6100 for (i=0; i<llen-rlen; i++) {
6101 ADD_INSN(ret, orig_lhsn, putnil);
6102 }
6103 }
6104
6105 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
6106 return 1;
6107}
6108
6109static int
6110compile_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)
6111{
6112 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
6113 const NODE *splatn = RNODE_MASGN(node)->nd_args;
6114 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
6115 const NODE *lhsn_count = lhsn;
6116 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
6117
6118 int llen = 0;
6119 int lpos = 0;
6120
6121 while (lhsn_count) {
6122 llen++;
6123 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
6124 }
6125 while (lhsn) {
6126 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
6127 lpos++;
6128 lhsn = RNODE_LIST(lhsn)->nd_next;
6129 }
6130
6131 if (lhs_splat) {
6132 if (nd_type_p(splatn, NODE_POSTARG)) {
6133 /*a, b, *r, p1, p2 */
6134 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
6135 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
6136 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
6137 int ppos = 0;
6138 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
6139
6140 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6141
6142 if (NODE_NAMED_REST_P(restn)) {
6143 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6144 }
6145 while (postn) {
6146 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6147 ppos++;
6148 postn = RNODE_LIST(postn)->nd_next;
6149 }
6150 }
6151 else {
6152 /* a, b, *r */
6153 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6154 }
6155 }
6156
6157 if (!state->nested) {
6158 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6159 }
6160
6161 if (!popped) {
6162 ADD_INSN(rhs, node, dup);
6163 }
6164 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6165 return COMPILE_OK;
6166}
6167
6168static int
6169compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6170{
6171 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6172 struct masgn_state state;
6173 state.lhs_level = popped ? 0 : 1;
6174 state.nested = 0;
6175 state.num_args = 0;
6176 state.first_memo = NULL;
6177 state.last_memo = NULL;
6178
6179 DECL_ANCHOR(pre);
6180 INIT_ANCHOR(pre);
6181 DECL_ANCHOR(rhs);
6182 INIT_ANCHOR(rhs);
6183 DECL_ANCHOR(lhs);
6184 INIT_ANCHOR(lhs);
6185 DECL_ANCHOR(post);
6186 INIT_ANCHOR(post);
6187 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6188
6189 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6190 while (memo) {
6191 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6192 for (int i = 0; i < memo->num_args; i++) {
6193 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6194 }
6195 tmp_memo = memo->next;
6196 free(memo);
6197 memo = tmp_memo;
6198 }
6199 CHECK(ok);
6200
6201 ADD_SEQ(ret, pre);
6202 ADD_SEQ(ret, rhs);
6203 ADD_SEQ(ret, lhs);
6204 if (!popped && state.num_args >= 1) {
6205 /* make sure rhs array is returned before popping */
6206 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6207 }
6208 ADD_SEQ(ret, post);
6209 }
6210 return COMPILE_OK;
6211}
6212
6213static VALUE
6214collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6215{
6216 VALUE arr = rb_ary_new();
6217 for (;;) {
6218 switch (nd_type(node)) {
6219 case NODE_CONST:
6220 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6222 return arr;
6223 case NODE_COLON3:
6224 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6225 rb_ary_unshift(arr, ID2SYM(idNULL));
6227 return arr;
6228 case NODE_COLON2:
6229 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6230 node = RNODE_COLON2(node)->nd_head;
6231 break;
6232 default:
6233 return Qfalse;
6234 }
6235 }
6236}
6237
6238static int
6239compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6240 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6241{
6242 switch (nd_type(node)) {
6243 case NODE_CONST:
6244 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6245 ADD_INSN1(body, node, putobject, Qtrue);
6246 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6247 break;
6248 case NODE_COLON3:
6249 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6250 ADD_INSN(body, node, pop);
6251 ADD_INSN1(body, node, putobject, rb_cObject);
6252 ADD_INSN1(body, node, putobject, Qtrue);
6253 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6254 break;
6255 case NODE_COLON2:
6256 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6257 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6258 ADD_INSN1(body, node, putobject, Qfalse);
6259 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6260 break;
6261 default:
6262 CHECK(COMPILE(pref, "const colon2 prefix", node));
6263 break;
6264 }
6265 return COMPILE_OK;
6266}
6267
6268static int
6269cpath_const_p(const NODE *node)
6270{
6271 switch (nd_type(node)) {
6272 case NODE_CONST:
6273 case NODE_COLON3:
6274 return TRUE;
6275 case NODE_COLON2:
6276 if (RNODE_COLON2(node)->nd_head) {
6277 return cpath_const_p(RNODE_COLON2(node)->nd_head);
6278 }
6279 return TRUE;
6280 default:
6281 return FALSE;
6282 }
6283}
6284
6285static int
6286compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6287{
6288 if (nd_type_p(cpath, NODE_COLON3)) {
6289 /* toplevel class ::Foo */
6290 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6291 return VM_DEFINECLASS_FLAG_SCOPED;
6292 }
6293 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6294 /* Bar::Foo or expr::Foo */
6295 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6296 int flags = VM_DEFINECLASS_FLAG_SCOPED;
6297 if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
6298 flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
6299 }
6300 return flags;
6301 }
6302 else {
6303 /* class at cbase Foo */
6304 ADD_INSN1(ret, cpath, putspecialobject,
6305 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6306 return 0;
6307 }
6308}
6309
6310static inline int
6311private_recv_p(const NODE *node)
6312{
6313 NODE *recv = get_nd_recv(node);
6314 if (recv && nd_type_p(recv, NODE_SELF)) {
6315 return RNODE_SELF(recv)->nd_state != 0;
6316 }
6317 return 0;
6318}
6319
6320static void
6321defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6322 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6323
6324static int
6325compile_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);
6326
6327static void
6328defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6329 const NODE *const node, LABEL **lfinish, VALUE needstr,
6330 bool keep_result)
6331{
6332 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6333 enum node_type type;
6334 const int line = nd_line(node);
6335 const NODE *line_node = node;
6336
6337 switch (type = nd_type(node)) {
6338
6339 /* easy literals */
6340 case NODE_NIL:
6341 expr_type = DEFINED_NIL;
6342 break;
6343 case NODE_SELF:
6344 expr_type = DEFINED_SELF;
6345 break;
6346 case NODE_TRUE:
6347 expr_type = DEFINED_TRUE;
6348 break;
6349 case NODE_FALSE:
6350 expr_type = DEFINED_FALSE;
6351 break;
6352
6353 case NODE_HASH:
6354 case NODE_LIST:{
6355 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6356
6357 if (vals) {
6358 do {
6359 if (RNODE_LIST(vals)->nd_head) {
6360 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6361
6362 if (!lfinish[1]) {
6363 lfinish[1] = NEW_LABEL(line);
6364 }
6365 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6366 }
6367 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6368 }
6369 }
6370 /* fall through */
6371 case NODE_STR:
6372 case NODE_SYM:
6373 case NODE_REGX:
6374 case NODE_LINE:
6375 case NODE_FILE:
6376 case NODE_ENCODING:
6377 case NODE_INTEGER:
6378 case NODE_FLOAT:
6379 case NODE_RATIONAL:
6380 case NODE_IMAGINARY:
6381 case NODE_ZLIST:
6382 case NODE_AND:
6383 case NODE_OR:
6384 default:
6385 expr_type = DEFINED_EXPR;
6386 break;
6387
6388 case NODE_SPLAT:
6389 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6390 if (!lfinish[1]) {
6391 lfinish[1] = NEW_LABEL(line);
6392 }
6393 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6394 expr_type = DEFINED_EXPR;
6395 break;
6396
6397 /* variables */
6398 case NODE_LVAR:
6399 case NODE_DVAR:
6400 expr_type = DEFINED_LVAR;
6401 break;
6402
6403#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6404 case NODE_IVAR:
6405 ADD_INSN3(ret, line_node, definedivar,
6406 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6407 return;
6408
6409 case NODE_GVAR:
6410 ADD_INSN(ret, line_node, putnil);
6411 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6412 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6413 return;
6414
6415 case NODE_CVAR:
6416 ADD_INSN(ret, line_node, putnil);
6417 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6418 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6419 return;
6420
6421 case NODE_CONST:
6422 ADD_INSN(ret, line_node, putnil);
6423 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6424 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6425 return;
6426 case NODE_COLON2:
6427 if (!lfinish[1]) {
6428 lfinish[1] = NEW_LABEL(line);
6429 }
6430 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6431 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6432 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6433
6434 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6435 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6436 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6437 }
6438 else {
6439 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6440 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6441 }
6442 return;
6443 case NODE_COLON3:
6444 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6445 ADD_INSN3(ret, line_node, defined,
6446 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6447 return;
6448
6449 /* method dispatch */
6450 case NODE_CALL:
6451 case NODE_OPCALL:
6452 case NODE_VCALL:
6453 case NODE_FCALL:
6454 case NODE_ATTRASGN:{
6455 const int explicit_receiver =
6456 (type == NODE_CALL || type == NODE_OPCALL ||
6457 (type == NODE_ATTRASGN && !private_recv_p(node)));
6458
6459 if (get_nd_args(node) || explicit_receiver) {
6460 if (!lfinish[1]) {
6461 lfinish[1] = NEW_LABEL(line);
6462 }
6463 if (!lfinish[2]) {
6464 lfinish[2] = NEW_LABEL(line);
6465 }
6466 }
6467 if (get_nd_args(node)) {
6468 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6469 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6470 }
6471 if (explicit_receiver) {
6472 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6473 switch (nd_type(get_nd_recv(node))) {
6474 case NODE_CALL:
6475 case NODE_OPCALL:
6476 case NODE_VCALL:
6477 case NODE_FCALL:
6478 case NODE_ATTRASGN:
6479 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6480 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6481 break;
6482 default:
6483 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6484 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6485 break;
6486 }
6487 if (keep_result) {
6488 ADD_INSN(ret, line_node, dup);
6489 }
6490 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6491 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6492 }
6493 else {
6494 ADD_INSN(ret, line_node, putself);
6495 if (keep_result) {
6496 ADD_INSN(ret, line_node, dup);
6497 }
6498 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6499 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6500 }
6501 return;
6502 }
6503
6504 case NODE_YIELD:
6505 ADD_INSN(ret, line_node, putnil);
6506 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6507 PUSH_VAL(DEFINED_YIELD));
6508 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6509 return;
6510
6511 case NODE_BACK_REF:
6512 case NODE_NTH_REF:
6513 ADD_INSN(ret, line_node, putnil);
6514 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6515 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6516 PUSH_VAL(DEFINED_GVAR));
6517 return;
6518
6519 case NODE_SUPER:
6520 case NODE_ZSUPER:
6521 ADD_INSN(ret, line_node, putnil);
6522 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6523 PUSH_VAL(DEFINED_ZSUPER));
6524 return;
6525
6526#undef PUSH_VAL
6527 case NODE_OP_ASGN1:
6528 case NODE_OP_ASGN2:
6529 case NODE_OP_ASGN_OR:
6530 case NODE_OP_ASGN_AND:
6531 case NODE_MASGN:
6532 case NODE_LASGN:
6533 case NODE_DASGN:
6534 case NODE_GASGN:
6535 case NODE_IASGN:
6536 case NODE_CDECL:
6537 case NODE_CVASGN:
6538 case NODE_OP_CDECL:
6539 expr_type = DEFINED_ASGN;
6540 break;
6541 }
6542
6543 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6544
6545 if (needstr != Qfalse) {
6546 VALUE str = rb_iseq_defined_string(expr_type);
6547 ADD_INSN1(ret, line_node, putobject, str);
6548 }
6549 else {
6550 ADD_INSN1(ret, line_node, putobject, Qtrue);
6551 }
6552}
6553
6554static void
6555build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6556{
6557 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6558 iseq_set_exception_local_table(iseq);
6559}
6560
6561static void
6562defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6563 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6564{
6565 LINK_ELEMENT *lcur = ret->last;
6566 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6567 if (lfinish[1]) {
6568 int line = nd_line(node);
6569 LABEL *lstart = NEW_LABEL(line);
6570 LABEL *lend = NEW_LABEL(line);
6571 const rb_iseq_t *rescue;
6573 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6574 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6575 rb_str_concat(rb_str_new2("defined guard in "),
6576 ISEQ_BODY(iseq)->location.label),
6577 ISEQ_TYPE_RESCUE, 0);
6578 lstart->rescued = LABEL_RESCUE_BEG;
6579 lend->rescued = LABEL_RESCUE_END;
6580 APPEND_LABEL(ret, lcur, lstart);
6581 ADD_LABEL(ret, lend);
6582 if (!ignore) {
6583 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6584 }
6585 }
6586}
6587
6588static int
6589compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6590{
6591 const int line = nd_line(node);
6592 const NODE *line_node = node;
6593 if (!RNODE_DEFINED(node)->nd_head) {
6594 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6595 ADD_INSN1(ret, line_node, putobject, str);
6596 }
6597 else {
6598 LABEL *lfinish[3];
6599 LINK_ELEMENT *last = ret->last;
6600 lfinish[0] = NEW_LABEL(line);
6601 lfinish[1] = 0;
6602 lfinish[2] = 0;
6603 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6604 if (lfinish[1]) {
6605 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6606 ADD_INSN(ret, line_node, swap);
6607 if (lfinish[2]) {
6608 ADD_LABEL(ret, lfinish[2]);
6609 }
6610 ADD_INSN(ret, line_node, pop);
6611 ADD_LABEL(ret, lfinish[1]);
6612 }
6613 ADD_LABEL(ret, lfinish[0]);
6614 }
6615 return COMPILE_OK;
6616}
6617
6618static VALUE
6619make_name_for_block(const rb_iseq_t *orig_iseq)
6620{
6621 int level = 1;
6622 const rb_iseq_t *iseq = orig_iseq;
6623
6624 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6625 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6626 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6627 level++;
6628 }
6629 iseq = ISEQ_BODY(iseq)->parent_iseq;
6630 }
6631 }
6632
6633 if (level == 1) {
6634 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6635 }
6636 else {
6637 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6638 }
6639}
6640
6641static void
6642push_ensure_entry(rb_iseq_t *iseq,
6644 struct ensure_range *er, const void *const node)
6645{
6646 enl->ensure_node = node;
6647 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6648 enl->erange = er;
6649 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6650}
6651
6652static void
6653add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6654 LABEL *lstart, LABEL *lend)
6655{
6656 struct ensure_range *ne =
6657 compile_data_alloc_type(iseq, struct ensure_range);
6658
6659 while (erange->next != 0) {
6660 erange = erange->next;
6661 }
6662 ne->next = 0;
6663 ne->begin = lend;
6664 ne->end = erange->end;
6665 erange->end = lstart;
6666
6667 erange->next = ne;
6668}
6669
6670static bool
6671can_add_ensure_iseq(const rb_iseq_t *iseq)
6672{
6674 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6675 while (e) {
6676 if (e->ensure_node) return false;
6677 e = e->prev;
6678 }
6679 }
6680 return true;
6681}
6682
6683static void
6684add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6685{
6686 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6687
6689 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6690 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6691 DECL_ANCHOR(ensure);
6692
6693 INIT_ANCHOR(ensure);
6694 while (enlp) {
6695 if (enlp->erange != NULL) {
6696 DECL_ANCHOR(ensure_part);
6697 LABEL *lstart = NEW_LABEL(0);
6698 LABEL *lend = NEW_LABEL(0);
6699 INIT_ANCHOR(ensure_part);
6700
6701 add_ensure_range(iseq, enlp->erange, lstart, lend);
6702
6703 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6704 ADD_LABEL(ensure_part, lstart);
6705 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6706 ADD_LABEL(ensure_part, lend);
6707 ADD_SEQ(ensure, ensure_part);
6708 }
6709 else {
6710 if (!is_return) {
6711 break;
6712 }
6713 }
6714 enlp = enlp->prev;
6715 }
6716 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6717 ADD_SEQ(ret, ensure);
6718}
6719
6720#if RUBY_DEBUG
6721static int
6722check_keyword(const NODE *node)
6723{
6724 /* This check is essentially a code clone of compile_keyword_arg. */
6725
6726 if (nd_type_p(node, NODE_LIST)) {
6727 while (RNODE_LIST(node)->nd_next) {
6728 node = RNODE_LIST(node)->nd_next;
6729 }
6730 node = RNODE_LIST(node)->nd_head;
6731 }
6732
6733 return keyword_node_p(node);
6734}
6735#endif
6736
6737static bool
6738keyword_node_single_splat_p(NODE *kwnode)
6739{
6740 RUBY_ASSERT(keyword_node_p(kwnode));
6741
6742 NODE *node = RNODE_HASH(kwnode)->nd_head;
6743 return RNODE_LIST(node)->nd_head == NULL &&
6744 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6745}
6746
6747static void
6748compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6749 NODE *kwnode, unsigned int *flag_ptr)
6750{
6751 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6752 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6753 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6754 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6755 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6756}
6757
6758#define SPLATARRAY_FALSE 0
6759#define SPLATARRAY_TRUE 1
6760#define DUP_SINGLE_KW_SPLAT 2
6761
6762static int
6763setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6764 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6765{
6766 if (!argn) return 0;
6767
6768 NODE *kwnode = NULL;
6769
6770 switch (nd_type(argn)) {
6771 case NODE_LIST: {
6772 // f(x, y, z)
6773 int len = compile_args(iseq, args, argn, &kwnode);
6774 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6775
6776 if (kwnode) {
6777 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6778 len -= 1;
6779 }
6780 else {
6781 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6782 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6783 }
6784 else {
6785 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6786 }
6787 }
6788 }
6789
6790 return len;
6791 }
6792 case NODE_SPLAT: {
6793 // f(*a)
6794 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6795 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6796 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6797 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6798 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6799 return 1;
6800 }
6801 case NODE_ARGSCAT: {
6802 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6803 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6804 bool args_pushed = false;
6805
6806 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6807 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6808 if (kwnode) rest_len--;
6809 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6810 args_pushed = true;
6811 }
6812 else {
6813 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6814 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6815 }
6816
6817 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6818 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6819 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6820 argc += 1;
6821 }
6822 else if (!args_pushed) {
6823 ADD_INSN(args, argn, concattoarray);
6824 }
6825
6826 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6827 if (kwnode) {
6828 // kwsplat
6829 *flag_ptr |= VM_CALL_KW_SPLAT;
6830 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6831 argc += 1;
6832 }
6833
6834 return argc;
6835 }
6836 case NODE_ARGSPUSH: {
6837 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6838 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6839
6840 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6841 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6842 if (kwnode) rest_len--;
6843 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6844 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6845 }
6846 else {
6847 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6848 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6849 }
6850 else {
6851 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6852 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6853 }
6854 }
6855
6856 if (kwnode) {
6857 // f(*a, k:1)
6858 *flag_ptr |= VM_CALL_KW_SPLAT;
6859 if (!keyword_node_single_splat_p(kwnode)) {
6860 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6861 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6862 }
6863 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6864 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6865 }
6866 else {
6867 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6868 }
6869 argc += 1;
6870 }
6871
6872 return argc;
6873 }
6874 default: {
6875 UNKNOWN_NODE("setup_arg", argn, Qnil);
6876 }
6877 }
6878}
6879
6880static void
6881setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6882{
6883 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6884 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6885 }
6886}
6887
6888static bool
6889setup_args_dup_rest_p(const NODE *argn)
6890{
6891 switch(nd_type(argn)) {
6892 case NODE_LVAR:
6893 case NODE_DVAR:
6894 case NODE_GVAR:
6895 case NODE_IVAR:
6896 case NODE_CVAR:
6897 case NODE_CONST:
6898 case NODE_COLON3:
6899 case NODE_INTEGER:
6900 case NODE_FLOAT:
6901 case NODE_RATIONAL:
6902 case NODE_IMAGINARY:
6903 case NODE_STR:
6904 case NODE_SYM:
6905 case NODE_REGX:
6906 case NODE_SELF:
6907 case NODE_NIL:
6908 case NODE_TRUE:
6909 case NODE_FALSE:
6910 case NODE_LAMBDA:
6911 case NODE_NTH_REF:
6912 case NODE_BACK_REF:
6913 return false;
6914 case NODE_COLON2:
6915 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6916 case NODE_LIST:
6917 while (argn) {
6918 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6919 return true;
6920 }
6921 argn = RNODE_LIST(argn)->nd_next;
6922 }
6923 return false;
6924 default:
6925 return true;
6926 }
6927}
6928
6929static VALUE
6930setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6931 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6932{
6933 VALUE ret;
6934 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6935
6936 if (argn) {
6937 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6938 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6939
6940 if (check_arg) {
6941 switch(nd_type(check_arg)) {
6942 case(NODE_SPLAT):
6943 // avoid caller side array allocation for f(*arg)
6944 dup_rest = SPLATARRAY_FALSE;
6945 break;
6946 case(NODE_ARGSCAT):
6947 // avoid caller side array allocation for f(1, *arg)
6948 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6949 break;
6950 case(NODE_ARGSPUSH):
6951 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6952 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6953 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6954 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6955 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6956 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6957
6958 if (dup_rest == SPLATARRAY_FALSE) {
6959 // require allocation for keyword key/value/splat that may modify splatted argument
6960 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6961 while (node) {
6962 NODE *key_node = RNODE_LIST(node)->nd_head;
6963 if (key_node && setup_args_dup_rest_p(key_node)) {
6964 dup_rest = SPLATARRAY_TRUE;
6965 break;
6966 }
6967
6968 node = RNODE_LIST(node)->nd_next;
6969 NODE *value_node = RNODE_LIST(node)->nd_head;
6970 if (setup_args_dup_rest_p(value_node)) {
6971 dup_rest = SPLATARRAY_TRUE;
6972 break;
6973 }
6974
6975 node = RNODE_LIST(node)->nd_next;
6976 }
6977 }
6978 break;
6979 default:
6980 break;
6981 }
6982 }
6983
6984 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6985 // for block pass that may modify splatted argument, dup rest and kwrest if given
6986 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6987 }
6988 }
6989 initial_dup_rest = dup_rest;
6990
6991 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6992 DECL_ANCHOR(arg_block);
6993 INIT_ANCHOR(arg_block);
6994
6995 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6996 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6997
6998 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6999 const NODE * arg_node =
7000 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
7001
7002 int argc = 0;
7003
7004 // Only compile leading args:
7005 // foo(x, y, ...)
7006 // ^^^^
7007 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
7008 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
7009 }
7010
7011 *flag |= VM_CALL_FORWARDING;
7012
7013 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
7014 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7015 return INT2FIX(argc);
7016 }
7017 else {
7018 *flag |= VM_CALL_ARGS_BLOCKARG;
7019
7020 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
7021 }
7022
7023 if (LIST_INSN_SIZE_ONE(arg_block)) {
7024 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
7025 if (IS_INSN(elem)) {
7026 INSN *iobj = (INSN *)elem;
7027 if (iobj->insn_id == BIN(getblockparam)) {
7028 iobj->insn_id = BIN(getblockparamproxy);
7029 }
7030 }
7031 }
7032 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
7033 ADD_SEQ(args, arg_block);
7034 }
7035 else {
7036 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
7037 }
7038 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7039 return ret;
7040}
7041
7042static void
7043build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
7044{
7045 const NODE *body = ptr;
7046 int line = nd_line(body);
7047 VALUE argc = INT2FIX(0);
7048 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
7049
7050 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7051 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
7052 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
7053 iseq_set_local_table(iseq, 0, 0);
7054}
7055
7056static void
7057compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
7058{
7059 const NODE *vars;
7060 LINK_ELEMENT *last;
7061 int line = nd_line(node);
7062 const NODE *line_node = node;
7063 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
7064
7065#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
7066 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
7067#else
7068 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
7069#endif
7070 ADD_INSN(ret, line_node, dup);
7071 ADD_INSNL(ret, line_node, branchunless, fail_label);
7072
7073 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7074 INSN *cap;
7075 if (RNODE_BLOCK(vars)->nd_next) {
7076 ADD_INSN(ret, line_node, dup);
7077 }
7078 last = ret->last;
7079 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7080 last = last->next; /* putobject :var */
7081 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
7082 NULL, INT2FIX(0), NULL);
7083 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
7084#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
7085 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
7086 /* only one name */
7087 DECL_ANCHOR(nom);
7088
7089 INIT_ANCHOR(nom);
7090 ADD_INSNL(nom, line_node, jump, end_label);
7091 ADD_LABEL(nom, fail_label);
7092# if 0 /* $~ must be MatchData or nil */
7093 ADD_INSN(nom, line_node, pop);
7094 ADD_INSN(nom, line_node, putnil);
7095# endif
7096 ADD_LABEL(nom, end_label);
7097 (nom->last->next = cap->link.next)->prev = nom->last;
7098 (cap->link.next = nom->anchor.next)->prev = &cap->link;
7099 return;
7100 }
7101#endif
7102 }
7103 ADD_INSNL(ret, line_node, jump, end_label);
7104 ADD_LABEL(ret, fail_label);
7105 ADD_INSN(ret, line_node, pop);
7106 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7107 last = ret->last;
7108 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7109 last = last->next; /* putobject :var */
7110 ((INSN*)last)->insn_id = BIN(putnil);
7111 ((INSN*)last)->operand_size = 0;
7112 }
7113 ADD_LABEL(ret, end_label);
7114}
7115
7116static int
7117optimizable_range_item_p(const NODE *n)
7118{
7119 if (!n) return FALSE;
7120 switch (nd_type(n)) {
7121 case NODE_LINE:
7122 return TRUE;
7123 case NODE_INTEGER:
7124 return TRUE;
7125 case NODE_NIL:
7126 return TRUE;
7127 default:
7128 return FALSE;
7129 }
7130}
7131
7132static VALUE
7133optimized_range_item(const NODE *n)
7134{
7135 switch (nd_type(n)) {
7136 case NODE_LINE:
7137 return rb_node_line_lineno_val(n);
7138 case NODE_INTEGER:
7139 return rb_node_integer_literal_val(n);
7140 case NODE_FLOAT:
7141 return rb_node_float_literal_val(n);
7142 case NODE_RATIONAL:
7143 return rb_node_rational_literal_val(n);
7144 case NODE_IMAGINARY:
7145 return rb_node_imaginary_literal_val(n);
7146 case NODE_NIL:
7147 return Qnil;
7148 default:
7149 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
7150 }
7151}
7152
7153static int
7154compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7155{
7156 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
7157 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
7158
7159 const int line = nd_line(node);
7160 const NODE *line_node = node;
7161 DECL_ANCHOR(cond_seq);
7162 LABEL *then_label, *else_label, *end_label;
7163 VALUE branches = Qfalse;
7164
7165 INIT_ANCHOR(cond_seq);
7166 then_label = NEW_LABEL(line);
7167 else_label = NEW_LABEL(line);
7168 end_label = 0;
7169
7170 NODE *cond = RNODE_IF(node)->nd_cond;
7171 if (nd_type(cond) == NODE_BLOCK) {
7172 cond = RNODE_BLOCK(cond)->nd_head;
7173 }
7174
7175 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7176 ADD_SEQ(ret, cond_seq);
7177
7178 if (then_label->refcnt && else_label->refcnt) {
7179 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7180 }
7181
7182 if (then_label->refcnt) {
7183 ADD_LABEL(ret, then_label);
7184
7185 DECL_ANCHOR(then_seq);
7186 INIT_ANCHOR(then_seq);
7187 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7188
7189 if (else_label->refcnt) {
7190 const NODE *const coverage_node = node_body ? node_body : node;
7191 add_trace_branch_coverage(
7192 iseq,
7193 ret,
7194 nd_code_loc(coverage_node),
7195 nd_node_id(coverage_node),
7196 0,
7197 type == NODE_IF ? "then" : "else",
7198 branches);
7199 end_label = NEW_LABEL(line);
7200 ADD_INSNL(then_seq, line_node, jump, end_label);
7201 if (!popped) {
7202 ADD_INSN(then_seq, line_node, pop);
7203 }
7204 }
7205 ADD_SEQ(ret, then_seq);
7206 }
7207
7208 if (else_label->refcnt) {
7209 ADD_LABEL(ret, else_label);
7210
7211 DECL_ANCHOR(else_seq);
7212 INIT_ANCHOR(else_seq);
7213 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7214
7215 if (then_label->refcnt) {
7216 const NODE *const coverage_node = node_else ? node_else : node;
7217 add_trace_branch_coverage(
7218 iseq,
7219 ret,
7220 nd_code_loc(coverage_node),
7221 nd_node_id(coverage_node),
7222 1,
7223 type == NODE_IF ? "else" : "then",
7224 branches);
7225 }
7226 ADD_SEQ(ret, else_seq);
7227 }
7228
7229 if (end_label) {
7230 ADD_LABEL(ret, end_label);
7231 }
7232
7233 return COMPILE_OK;
7234}
7235
7236static int
7237compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7238{
7239 const NODE *vals;
7240 const NODE *node = orig_node;
7241 LABEL *endlabel, *elselabel;
7242 DECL_ANCHOR(head);
7243 DECL_ANCHOR(body_seq);
7244 DECL_ANCHOR(cond_seq);
7245 int only_special_literals = 1;
7246 VALUE literals = cdhash_new(0);
7247 int line;
7248 enum node_type type;
7249 const NODE *line_node;
7250 VALUE branches = Qfalse;
7251 int branch_id = 0;
7252
7253 INIT_ANCHOR(head);
7254 INIT_ANCHOR(body_seq);
7255 INIT_ANCHOR(cond_seq);
7256
7257 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7258
7259 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
7260
7261 node = RNODE_CASE(node)->nd_body;
7262 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7263 type = nd_type(node);
7264 line = nd_line(node);
7265 line_node = node;
7266
7267 endlabel = NEW_LABEL(line);
7268 elselabel = NEW_LABEL(line);
7269
7270 ADD_SEQ(ret, head); /* case VAL */
7271
7272 while (type == NODE_WHEN) {
7273 LABEL *l1;
7274
7275 l1 = NEW_LABEL(line);
7276 ADD_LABEL(body_seq, l1);
7277 ADD_INSN(body_seq, line_node, pop);
7278
7279 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7280 add_trace_branch_coverage(
7281 iseq,
7282 body_seq,
7283 nd_code_loc(coverage_node),
7284 nd_node_id(coverage_node),
7285 branch_id++,
7286 "when",
7287 branches);
7288
7289 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7290 ADD_INSNL(body_seq, line_node, jump, endlabel);
7291
7292 vals = RNODE_WHEN(node)->nd_head;
7293 if (vals) {
7294 switch (nd_type(vals)) {
7295 case NODE_LIST:
7296 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7297 if (only_special_literals < 0) return COMPILE_NG;
7298 break;
7299 case NODE_SPLAT:
7300 case NODE_ARGSCAT:
7301 case NODE_ARGSPUSH:
7302 only_special_literals = 0;
7303 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7304 break;
7305 default:
7306 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7307 }
7308 }
7309 else {
7310 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7311 }
7312
7313 node = RNODE_WHEN(node)->nd_next;
7314 if (!node) {
7315 break;
7316 }
7317 type = nd_type(node);
7318 line = nd_line(node);
7319 line_node = node;
7320 }
7321 /* else */
7322 if (node) {
7323 ADD_LABEL(cond_seq, elselabel);
7324 ADD_INSN(cond_seq, line_node, pop);
7325 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7326 CHECK(COMPILE_(cond_seq, "else", node, popped));
7327 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7328 }
7329 else {
7330 debugs("== else (implicit)\n");
7331 ADD_LABEL(cond_seq, elselabel);
7332 ADD_INSN(cond_seq, orig_node, pop);
7333 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7334 if (!popped) {
7335 ADD_INSN(cond_seq, orig_node, putnil);
7336 }
7337 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7338 }
7339
7340 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7341 ADD_INSN(ret, orig_node, dup);
7342 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7343 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7344 LABEL_REF(elselabel);
7345 }
7346
7347 ADD_SEQ(ret, cond_seq);
7348 ADD_SEQ(ret, body_seq);
7349 ADD_LABEL(ret, endlabel);
7350 return COMPILE_OK;
7351}
7352
7353static int
7354compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7355{
7356 const NODE *vals;
7357 const NODE *val;
7358 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7359 LABEL *endlabel;
7360 DECL_ANCHOR(body_seq);
7361 VALUE branches = Qfalse;
7362 int branch_id = 0;
7363
7364 branches = decl_branch_base(iseq, nd_node_id(orig_node), nd_code_loc(orig_node), "case");
7365
7366 INIT_ANCHOR(body_seq);
7367 endlabel = NEW_LABEL(nd_line(node));
7368
7369 while (node && nd_type_p(node, NODE_WHEN)) {
7370 const int line = nd_line(node);
7371 LABEL *l1 = NEW_LABEL(line);
7372 ADD_LABEL(body_seq, l1);
7373
7374 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7375 add_trace_branch_coverage(
7376 iseq,
7377 body_seq,
7378 nd_code_loc(coverage_node),
7379 nd_node_id(coverage_node),
7380 branch_id++,
7381 "when",
7382 branches);
7383
7384 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7385 ADD_INSNL(body_seq, node, jump, endlabel);
7386
7387 vals = RNODE_WHEN(node)->nd_head;
7388 if (!vals) {
7389 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7390 }
7391 switch (nd_type(vals)) {
7392 case NODE_LIST:
7393 while (vals) {
7394 LABEL *lnext;
7395 val = RNODE_LIST(vals)->nd_head;
7396 lnext = NEW_LABEL(nd_line(val));
7397 debug_compile("== when2\n", (void)0);
7398 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7399 ADD_LABEL(ret, lnext);
7400 vals = RNODE_LIST(vals)->nd_next;
7401 }
7402 break;
7403 case NODE_SPLAT:
7404 case NODE_ARGSCAT:
7405 case NODE_ARGSPUSH:
7406 ADD_INSN(ret, vals, putnil);
7407 CHECK(COMPILE(ret, "when2/cond splat", vals));
7408 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7409 ADD_INSNL(ret, vals, branchif, l1);
7410 break;
7411 default:
7412 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7413 }
7414 node = RNODE_WHEN(node)->nd_next;
7415 }
7416 /* else */
7417 const NODE *const coverage_node = node ? node : orig_node;
7418 add_trace_branch_coverage(
7419 iseq,
7420 ret,
7421 nd_code_loc(coverage_node),
7422 nd_node_id(coverage_node),
7423 branch_id,
7424 "else",
7425 branches);
7426 CHECK(COMPILE_(ret, "else", node, popped));
7427 ADD_INSNL(ret, orig_node, jump, endlabel);
7428
7429 ADD_SEQ(ret, body_seq);
7430 ADD_LABEL(ret, endlabel);
7431 return COMPILE_OK;
7432}
7433
7434static 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);
7435
7436static 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);
7437static 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);
7438static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7439static 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);
7440static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7441
7442#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7443#define CASE3_BI_OFFSET_ERROR_STRING 1
7444#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7445#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7446#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7447
7448static int
7449iseq_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)
7450{
7451 const int line = nd_line(node);
7452 const NODE *line_node = node;
7453
7454 switch (nd_type(node)) {
7455 case NODE_ARYPTN: {
7456 /*
7457 * if pattern.use_rest_num?
7458 * rest_num = 0
7459 * end
7460 * if pattern.has_constant_node?
7461 * unless pattern.constant === obj
7462 * goto match_failed
7463 * end
7464 * end
7465 * unless obj.respond_to?(:deconstruct)
7466 * goto match_failed
7467 * end
7468 * d = obj.deconstruct
7469 * unless Array === d
7470 * goto type_error
7471 * end
7472 * min_argc = pattern.pre_args_num + pattern.post_args_num
7473 * if pattern.has_rest_arg?
7474 * unless d.length >= min_argc
7475 * goto match_failed
7476 * end
7477 * else
7478 * unless d.length == min_argc
7479 * goto match_failed
7480 * end
7481 * end
7482 * pattern.pre_args_num.each do |i|
7483 * unless pattern.pre_args[i].match?(d[i])
7484 * goto match_failed
7485 * end
7486 * end
7487 * if pattern.use_rest_num?
7488 * rest_num = d.length - min_argc
7489 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7490 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7491 * goto match_failed
7492 * end
7493 * end
7494 * end
7495 * pattern.post_args_num.each do |i|
7496 * j = pattern.pre_args_num + i
7497 * j += rest_num
7498 * unless pattern.post_args[i].match?(d[j])
7499 * goto match_failed
7500 * end
7501 * end
7502 * goto matched
7503 * type_error:
7504 * FrozenCore.raise TypeError
7505 * match_failed:
7506 * goto unmatched
7507 */
7508 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7509 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7510 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7511
7512 const int min_argc = pre_args_num + post_args_num;
7513 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7514 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7515
7516 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7517 int i;
7518 match_failed = NEW_LABEL(line);
7519 type_error = NEW_LABEL(line);
7520 deconstruct = NEW_LABEL(line);
7521 deconstructed = NEW_LABEL(line);
7522
7523 if (use_rest_num) {
7524 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7525 ADD_INSN(ret, line_node, swap);
7526 if (base_index) {
7527 base_index++;
7528 }
7529 }
7530
7531 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7532
7533 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7534
7535 ADD_INSN(ret, line_node, dup);
7536 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7537 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7538 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7539 if (in_single_pattern) {
7540 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7541 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7542 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7543 INT2FIX(min_argc), base_index + 1 /* (1) */));
7544 }
7545 ADD_INSNL(ret, line_node, branchunless, match_failed);
7546
7547 for (i = 0; i < pre_args_num; i++) {
7548 ADD_INSN(ret, line_node, dup);
7549 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7550 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7551 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));
7552 args = RNODE_LIST(args)->nd_next;
7553 }
7554
7555 if (RNODE_ARYPTN(node)->rest_arg) {
7556 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7557 ADD_INSN(ret, line_node, dup);
7558 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7559 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7560 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7561 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7562 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7563 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7564 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7565
7566 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));
7567 }
7568 else {
7569 if (post_args_num > 0) {
7570 ADD_INSN(ret, line_node, dup);
7571 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7572 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7573 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7574 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7575 ADD_INSN(ret, line_node, pop);
7576 }
7577 }
7578 }
7579
7580 args = RNODE_ARYPTN(node)->post_args;
7581 for (i = 0; i < post_args_num; i++) {
7582 ADD_INSN(ret, line_node, dup);
7583
7584 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7585 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7586 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7587
7588 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7589 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));
7590 args = RNODE_LIST(args)->nd_next;
7591 }
7592
7593 ADD_INSN(ret, line_node, pop);
7594 if (use_rest_num) {
7595 ADD_INSN(ret, line_node, pop);
7596 }
7597 ADD_INSNL(ret, line_node, jump, matched);
7598 ADD_INSN(ret, line_node, putnil);
7599 if (use_rest_num) {
7600 ADD_INSN(ret, line_node, putnil);
7601 }
7602
7603 ADD_LABEL(ret, type_error);
7604 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7605 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7606 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7607 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7608 ADD_INSN(ret, line_node, pop);
7609
7610 ADD_LABEL(ret, match_failed);
7611 ADD_INSN(ret, line_node, pop);
7612 if (use_rest_num) {
7613 ADD_INSN(ret, line_node, pop);
7614 }
7615 ADD_INSNL(ret, line_node, jump, unmatched);
7616
7617 break;
7618 }
7619 case NODE_FNDPTN: {
7620 /*
7621 * if pattern.has_constant_node?
7622 * unless pattern.constant === obj
7623 * goto match_failed
7624 * end
7625 * end
7626 * unless obj.respond_to?(:deconstruct)
7627 * goto match_failed
7628 * end
7629 * d = obj.deconstruct
7630 * unless Array === d
7631 * goto type_error
7632 * end
7633 * unless d.length >= pattern.args_num
7634 * goto match_failed
7635 * end
7636 *
7637 * begin
7638 * len = d.length
7639 * limit = d.length - pattern.args_num
7640 * i = 0
7641 * while i <= limit
7642 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7643 * if pattern.has_pre_rest_arg_id
7644 * unless pattern.pre_rest_arg.match?(d[0, i])
7645 * goto find_failed
7646 * end
7647 * end
7648 * if pattern.has_post_rest_arg_id
7649 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7650 * goto find_failed
7651 * end
7652 * end
7653 * goto find_succeeded
7654 * end
7655 * i+=1
7656 * end
7657 * find_failed:
7658 * goto match_failed
7659 * find_succeeded:
7660 * end
7661 *
7662 * goto matched
7663 * type_error:
7664 * FrozenCore.raise TypeError
7665 * match_failed:
7666 * goto unmatched
7667 */
7668 const NODE *args = RNODE_FNDPTN(node)->args;
7669 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7670
7671 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7672 match_failed = NEW_LABEL(line);
7673 type_error = NEW_LABEL(line);
7674 deconstruct = NEW_LABEL(line);
7675 deconstructed = NEW_LABEL(line);
7676
7677 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7678
7679 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7680
7681 ADD_INSN(ret, line_node, dup);
7682 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7683 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7684 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7685 if (in_single_pattern) {
7686 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) */));
7687 }
7688 ADD_INSNL(ret, line_node, branchunless, match_failed);
7689
7690 {
7691 LABEL *while_begin = NEW_LABEL(nd_line(node));
7692 LABEL *next_loop = NEW_LABEL(nd_line(node));
7693 LABEL *find_succeeded = NEW_LABEL(line);
7694 LABEL *find_failed = NEW_LABEL(nd_line(node));
7695 int j;
7696
7697 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7698 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7699
7700 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7701 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7702 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7703
7704 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7705
7706 ADD_LABEL(ret, while_begin);
7707
7708 ADD_INSN(ret, line_node, dup);
7709 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7710 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7711 ADD_INSNL(ret, line_node, branchunless, find_failed);
7712
7713 for (j = 0; j < args_num; j++) {
7714 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7715 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7716 if (j != 0) {
7717 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7718 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7719 }
7720 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7721
7722 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));
7723 args = RNODE_LIST(args)->nd_next;
7724 }
7725
7726 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7727 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7728 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7729 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7730 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7731 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));
7732 }
7733 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7734 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7735 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7736 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7737 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7738 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7739 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7740 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));
7741 }
7742 ADD_INSNL(ret, line_node, jump, find_succeeded);
7743
7744 ADD_LABEL(ret, next_loop);
7745 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7746 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7747 ADD_INSNL(ret, line_node, jump, while_begin);
7748
7749 ADD_LABEL(ret, find_failed);
7750 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7751 if (in_single_pattern) {
7752 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7753 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7754 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7755 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7756 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7757
7758 ADD_INSN1(ret, line_node, putobject, Qfalse);
7759 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7760
7761 ADD_INSN(ret, line_node, pop);
7762 ADD_INSN(ret, line_node, pop);
7763 }
7764 ADD_INSNL(ret, line_node, jump, match_failed);
7765 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7766
7767 ADD_LABEL(ret, find_succeeded);
7768 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7769 }
7770
7771 ADD_INSN(ret, line_node, pop);
7772 ADD_INSNL(ret, line_node, jump, matched);
7773 ADD_INSN(ret, line_node, putnil);
7774
7775 ADD_LABEL(ret, type_error);
7776 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7777 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7778 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7779 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7780 ADD_INSN(ret, line_node, pop);
7781
7782 ADD_LABEL(ret, match_failed);
7783 ADD_INSN(ret, line_node, pop);
7784 ADD_INSNL(ret, line_node, jump, unmatched);
7785
7786 break;
7787 }
7788 case NODE_HSHPTN: {
7789 /*
7790 * keys = nil
7791 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7792 * keys = pattern.kw_args_node.keys
7793 * end
7794 * if pattern.has_constant_node?
7795 * unless pattern.constant === obj
7796 * goto match_failed
7797 * end
7798 * end
7799 * unless obj.respond_to?(:deconstruct_keys)
7800 * goto match_failed
7801 * end
7802 * d = obj.deconstruct_keys(keys)
7803 * unless Hash === d
7804 * goto type_error
7805 * end
7806 * if pattern.has_kw_rest_arg_node?
7807 * d = d.dup
7808 * end
7809 * if pattern.has_kw_args_node?
7810 * pattern.kw_args_node.each |k,|
7811 * unless d.key?(k)
7812 * goto match_failed
7813 * end
7814 * end
7815 * pattern.kw_args_node.each |k, pat|
7816 * if pattern.has_kw_rest_arg_node?
7817 * unless pat.match?(d.delete(k))
7818 * goto match_failed
7819 * end
7820 * else
7821 * unless pat.match?(d[k])
7822 * goto match_failed
7823 * end
7824 * end
7825 * end
7826 * else
7827 * unless d.empty?
7828 * goto match_failed
7829 * end
7830 * end
7831 * if pattern.has_kw_rest_arg_node?
7832 * if pattern.no_rest_keyword?
7833 * unless d.empty?
7834 * goto match_failed
7835 * end
7836 * else
7837 * unless pattern.kw_rest_arg_node.match?(d)
7838 * goto match_failed
7839 * end
7840 * end
7841 * end
7842 * goto matched
7843 * type_error:
7844 * FrozenCore.raise TypeError
7845 * match_failed:
7846 * goto unmatched
7847 */
7848 LABEL *match_failed, *type_error;
7849 VALUE keys = Qnil;
7850
7851 match_failed = NEW_LABEL(line);
7852 type_error = NEW_LABEL(line);
7853
7854 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7855 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7856 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7857 while (kw_args) {
7858 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7859 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7860 }
7861 }
7862
7863 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7864
7865 ADD_INSN(ret, line_node, dup);
7866 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7867 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7868 if (in_single_pattern) {
7869 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7870 }
7871 ADD_INSNL(ret, line_node, branchunless, match_failed);
7872
7873 if (NIL_P(keys)) {
7874 ADD_INSN(ret, line_node, putnil);
7875 }
7876 else {
7878 ADD_INSN1(ret, line_node, duparray, keys);
7879 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7880 }
7881 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7882
7883 ADD_INSN(ret, line_node, dup);
7884 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7885 ADD_INSNL(ret, line_node, branchunless, type_error);
7886
7887 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7888 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7889 }
7890
7891 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7892 int i;
7893 int keys_num;
7894 const NODE *args;
7895 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7896 if (args) {
7897 DECL_ANCHOR(match_values);
7898 INIT_ANCHOR(match_values);
7899 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7900 for (i = 0; i < keys_num; i++) {
7901 NODE *key_node = RNODE_LIST(args)->nd_head;
7902 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7903 VALUE key = get_symbol_value(iseq, key_node);
7904
7905 ADD_INSN(ret, line_node, dup);
7906 ADD_INSN1(ret, line_node, putobject, key);
7907 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7908 if (in_single_pattern) {
7909 LABEL *match_succeeded;
7910 match_succeeded = NEW_LABEL(line);
7911
7912 ADD_INSN(ret, line_node, dup);
7913 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7914
7915 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7916 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7917 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7918 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7919 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7920 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7921 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7922 ADD_INSN1(ret, line_node, putobject, key); // (7)
7923 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7924
7925 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7926
7927 ADD_LABEL(ret, match_succeeded);
7928 }
7929 ADD_INSNL(ret, line_node, branchunless, match_failed);
7930
7931 ADD_INSN(match_values, line_node, dup);
7932 ADD_INSN1(match_values, line_node, putobject, key);
7933 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7934 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7935 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7936 }
7937 ADD_SEQ(ret, match_values);
7938 }
7939 }
7940 else {
7941 ADD_INSN(ret, line_node, dup);
7942 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7943 if (in_single_pattern) {
7944 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7945 }
7946 ADD_INSNL(ret, line_node, branchunless, match_failed);
7947 }
7948
7949 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7950 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7951 ADD_INSN(ret, line_node, dup);
7952 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7953 if (in_single_pattern) {
7954 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7955 }
7956 ADD_INSNL(ret, line_node, branchunless, match_failed);
7957 }
7958 else {
7959 ADD_INSN(ret, line_node, dup); // (11)
7960 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));
7961 }
7962 }
7963
7964 ADD_INSN(ret, line_node, pop);
7965 ADD_INSNL(ret, line_node, jump, matched);
7966 ADD_INSN(ret, line_node, putnil);
7967
7968 ADD_LABEL(ret, type_error);
7969 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7970 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7971 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7972 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7973 ADD_INSN(ret, line_node, pop);
7974
7975 ADD_LABEL(ret, match_failed);
7976 ADD_INSN(ret, line_node, pop);
7977 ADD_INSNL(ret, line_node, jump, unmatched);
7978 break;
7979 }
7980 case NODE_SYM:
7981 case NODE_REGX:
7982 case NODE_LINE:
7983 case NODE_INTEGER:
7984 case NODE_FLOAT:
7985 case NODE_RATIONAL:
7986 case NODE_IMAGINARY:
7987 case NODE_FILE:
7988 case NODE_ENCODING:
7989 case NODE_STR:
7990 case NODE_XSTR:
7991 case NODE_DSTR:
7992 case NODE_DSYM:
7993 case NODE_DREGX:
7994 case NODE_LIST:
7995 case NODE_ZLIST:
7996 case NODE_LAMBDA:
7997 case NODE_DOT2:
7998 case NODE_DOT3:
7999 case NODE_CONST:
8000 case NODE_LVAR:
8001 case NODE_DVAR:
8002 case NODE_IVAR:
8003 case NODE_CVAR:
8004 case NODE_GVAR:
8005 case NODE_TRUE:
8006 case NODE_FALSE:
8007 case NODE_SELF:
8008 case NODE_NIL:
8009 case NODE_COLON2:
8010 case NODE_COLON3:
8011 case NODE_BEGIN:
8012 case NODE_BLOCK:
8013 case NODE_ONCE:
8014 CHECK(COMPILE(ret, "case in literal", node)); // (1)
8015 if (in_single_pattern) {
8016 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8017 }
8018 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
8019 if (in_single_pattern) {
8020 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
8021 }
8022 ADD_INSNL(ret, line_node, branchif, matched);
8023 ADD_INSNL(ret, line_node, jump, unmatched);
8024 break;
8025 case NODE_LASGN: {
8026 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8027 ID id = RNODE_LASGN(node)->nd_vid;
8028 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8029
8030 if (in_alt_pattern) {
8031 const char *name = rb_id2name(id);
8032 if (name && strlen(name) > 0 && name[0] != '_') {
8033 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8034 rb_id2str(id));
8035 return COMPILE_NG;
8036 }
8037 }
8038
8039 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8040 ADD_INSNL(ret, line_node, jump, matched);
8041 break;
8042 }
8043 case NODE_DASGN: {
8044 int idx, lv, ls;
8045 ID id = RNODE_DASGN(node)->nd_vid;
8046
8047 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
8048
8049 if (in_alt_pattern) {
8050 const char *name = rb_id2name(id);
8051 if (name && strlen(name) > 0 && name[0] != '_') {
8052 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8053 rb_id2str(id));
8054 return COMPILE_NG;
8055 }
8056 }
8057
8058 if (idx < 0) {
8059 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
8060 rb_id2str(id));
8061 return COMPILE_NG;
8062 }
8063 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
8064 ADD_INSNL(ret, line_node, jump, matched);
8065 break;
8066 }
8067 case NODE_IF:
8068 case NODE_UNLESS: {
8069 LABEL *match_failed;
8070 match_failed = unmatched;
8071 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8072 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
8073 if (in_single_pattern) {
8074 LABEL *match_succeeded;
8075 match_succeeded = NEW_LABEL(line);
8076
8077 ADD_INSN(ret, line_node, dup);
8078 if (nd_type_p(node, NODE_IF)) {
8079 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8080 }
8081 else {
8082 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
8083 }
8084
8085 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
8086 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8087 ADD_INSN1(ret, line_node, putobject, Qfalse);
8088 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8089
8090 ADD_INSN(ret, line_node, pop);
8091 ADD_INSN(ret, line_node, pop);
8092
8093 ADD_LABEL(ret, match_succeeded);
8094 }
8095 if (nd_type_p(node, NODE_IF)) {
8096 ADD_INSNL(ret, line_node, branchunless, match_failed);
8097 }
8098 else {
8099 ADD_INSNL(ret, line_node, branchif, match_failed);
8100 }
8101 ADD_INSNL(ret, line_node, jump, matched);
8102 break;
8103 }
8104 case NODE_HASH: {
8105 NODE *n;
8106 LABEL *match_failed;
8107 match_failed = NEW_LABEL(line);
8108
8109 n = RNODE_HASH(node)->nd_head;
8110 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
8111 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8112 return COMPILE_NG;
8113 }
8114
8115 ADD_INSN(ret, line_node, dup); // (1)
8116 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));
8117 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));
8118 ADD_INSN(ret, line_node, putnil);
8119
8120 ADD_LABEL(ret, match_failed);
8121 ADD_INSN(ret, line_node, pop);
8122 ADD_INSNL(ret, line_node, jump, unmatched);
8123 break;
8124 }
8125 case NODE_OR: {
8126 LABEL *match_succeeded, *fin;
8127 match_succeeded = NEW_LABEL(line);
8128 fin = NEW_LABEL(line);
8129
8130 ADD_INSN(ret, line_node, dup); // (1)
8131 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));
8132 ADD_LABEL(ret, match_succeeded);
8133 ADD_INSN(ret, line_node, pop);
8134 ADD_INSNL(ret, line_node, jump, matched);
8135 ADD_INSN(ret, line_node, putnil);
8136 ADD_LABEL(ret, fin);
8137 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
8138 break;
8139 }
8140 default:
8141 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
8142 }
8143 return COMPILE_OK;
8144}
8145
8146static int
8147iseq_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)
8148{
8149 LABEL *fin = NEW_LABEL(nd_line(node));
8150 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8151 ADD_LABEL(ret, fin);
8152 return COMPILE_OK;
8153}
8154
8155static int
8156iseq_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)
8157{
8158 const NODE *line_node = node;
8159
8160 if (RNODE_ARYPTN(node)->nd_pconst) {
8161 ADD_INSN(ret, line_node, dup); // (1)
8162 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8163 if (in_single_pattern) {
8164 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8165 }
8166 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8167 if (in_single_pattern) {
8168 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8169 }
8170 ADD_INSNL(ret, line_node, branchunless, match_failed);
8171 }
8172 return COMPILE_OK;
8173}
8174
8175
8176static int
8177iseq_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)
8178{
8179 const NODE *line_node = node;
8180
8181 // NOTE: this optimization allows us to re-use the #deconstruct value
8182 // (or its absence).
8183 if (use_deconstructed_cache) {
8184 // If value is nil then we haven't tried to deconstruct
8185 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8186 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8187
8188 // If false then the value is not deconstructable
8189 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8190 ADD_INSNL(ret, line_node, branchunless, match_failed);
8191
8192 // Drop value, add deconstructed to the stack and jump
8193 ADD_INSN(ret, line_node, pop); // (1)
8194 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8195 ADD_INSNL(ret, line_node, jump, deconstructed);
8196 }
8197 else {
8198 ADD_INSNL(ret, line_node, jump, deconstruct);
8199 }
8200
8201 ADD_LABEL(ret, deconstruct);
8202 ADD_INSN(ret, line_node, dup);
8203 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8204 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8205
8206 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8207 if (use_deconstructed_cache) {
8208 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8209 }
8210
8211 if (in_single_pattern) {
8212 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8213 }
8214
8215 ADD_INSNL(ret, line_node, branchunless, match_failed);
8216
8217 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8218
8219 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8220 if (use_deconstructed_cache) {
8221 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8222 }
8223
8224 ADD_INSN(ret, line_node, dup);
8225 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8226 ADD_INSNL(ret, line_node, branchunless, type_error);
8227
8228 ADD_LABEL(ret, deconstructed);
8229
8230 return COMPILE_OK;
8231}
8232
8233static int
8234iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8235{
8236 /*
8237 * if match_succeeded?
8238 * goto match_succeeded
8239 * end
8240 * error_string = FrozenCore.sprintf(errmsg, matchee)
8241 * key_error_p = false
8242 * match_succeeded:
8243 */
8244 const int line = nd_line(node);
8245 const NODE *line_node = node;
8246 LABEL *match_succeeded = NEW_LABEL(line);
8247
8248 ADD_INSN(ret, line_node, dup);
8249 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8250
8251 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8252 ADD_INSN1(ret, line_node, putobject, errmsg);
8253 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8254 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8255 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8256
8257 ADD_INSN1(ret, line_node, putobject, Qfalse);
8258 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8259
8260 ADD_INSN(ret, line_node, pop);
8261 ADD_INSN(ret, line_node, pop);
8262 ADD_LABEL(ret, match_succeeded);
8263
8264 return COMPILE_OK;
8265}
8266
8267static int
8268iseq_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)
8269{
8270 /*
8271 * if match_succeeded?
8272 * goto match_succeeded
8273 * end
8274 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8275 * key_error_p = false
8276 * match_succeeded:
8277 */
8278 const int line = nd_line(node);
8279 const NODE *line_node = node;
8280 LABEL *match_succeeded = NEW_LABEL(line);
8281
8282 ADD_INSN(ret, line_node, dup);
8283 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8284
8285 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8286 ADD_INSN1(ret, line_node, putobject, errmsg);
8287 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8288 ADD_INSN(ret, line_node, dup);
8289 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8290 ADD_INSN1(ret, line_node, putobject, pattern_length);
8291 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8292 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8293
8294 ADD_INSN1(ret, line_node, putobject, Qfalse);
8295 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8296
8297 ADD_INSN(ret, line_node, pop);
8298 ADD_INSN(ret, line_node, pop);
8299 ADD_LABEL(ret, match_succeeded);
8300
8301 return COMPILE_OK;
8302}
8303
8304static int
8305iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8306{
8307 /*
8308 * if match_succeeded?
8309 * goto match_succeeded
8310 * end
8311 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8312 * key_error_p = false
8313 * match_succeeded:
8314 */
8315 const int line = nd_line(node);
8316 const NODE *line_node = node;
8317 LABEL *match_succeeded = NEW_LABEL(line);
8318
8319 ADD_INSN(ret, line_node, dup);
8320 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8321
8322 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8323 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8324 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8325 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8326 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8327 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8328
8329 ADD_INSN1(ret, line_node, putobject, Qfalse);
8330 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8331
8332 ADD_INSN(ret, line_node, pop);
8333 ADD_INSN(ret, line_node, pop);
8334
8335 ADD_LABEL(ret, match_succeeded);
8336 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8337 ADD_INSN(ret, line_node, pop);
8338 ADD_INSN(ret, line_node, pop);
8339
8340 return COMPILE_OK;
8341}
8342
8343static int
8344compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8345{
8346 const NODE *pattern;
8347 const NODE *node = orig_node;
8348 LABEL *endlabel, *elselabel;
8349 DECL_ANCHOR(head);
8350 DECL_ANCHOR(body_seq);
8351 DECL_ANCHOR(cond_seq);
8352 int line;
8353 enum node_type type;
8354 const NODE *line_node;
8355 VALUE branches = 0;
8356 int branch_id = 0;
8357 bool single_pattern;
8358
8359 INIT_ANCHOR(head);
8360 INIT_ANCHOR(body_seq);
8361 INIT_ANCHOR(cond_seq);
8362
8363 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
8364
8365 node = RNODE_CASE3(node)->nd_body;
8366 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8367 type = nd_type(node);
8368 line = nd_line(node);
8369 line_node = node;
8370 single_pattern = !RNODE_IN(node)->nd_next;
8371
8372 endlabel = NEW_LABEL(line);
8373 elselabel = NEW_LABEL(line);
8374
8375 if (single_pattern) {
8376 /* allocate stack for ... */
8377 ADD_INSN(head, line_node, putnil); /* key_error_key */
8378 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8379 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8380 ADD_INSN(head, line_node, putnil); /* error_string */
8381 }
8382 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8383
8384 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8385
8386 ADD_SEQ(ret, head); /* case VAL */
8387
8388 while (type == NODE_IN) {
8389 LABEL *l1;
8390
8391 if (branch_id) {
8392 ADD_INSN(body_seq, line_node, putnil);
8393 }
8394 l1 = NEW_LABEL(line);
8395 ADD_LABEL(body_seq, l1);
8396 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8397
8398 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8399 add_trace_branch_coverage(
8400 iseq,
8401 body_seq,
8402 nd_code_loc(coverage_node),
8403 nd_node_id(coverage_node),
8404 branch_id++,
8405 "in",
8406 branches);
8407
8408 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8409 ADD_INSNL(body_seq, line_node, jump, endlabel);
8410
8411 pattern = RNODE_IN(node)->nd_head;
8412 if (pattern) {
8413 int pat_line = nd_line(pattern);
8414 LABEL *next_pat = NEW_LABEL(pat_line);
8415 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8416 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8417 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8418 ADD_LABEL(cond_seq, next_pat);
8419 LABEL_UNREMOVABLE(next_pat);
8420 }
8421 else {
8422 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8423 return COMPILE_NG;
8424 }
8425
8426 node = RNODE_IN(node)->nd_next;
8427 if (!node) {
8428 break;
8429 }
8430 type = nd_type(node);
8431 line = nd_line(node);
8432 line_node = node;
8433 }
8434 /* else */
8435 if (node) {
8436 ADD_LABEL(cond_seq, elselabel);
8437 ADD_INSN(cond_seq, line_node, pop);
8438 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8439 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8440 CHECK(COMPILE_(cond_seq, "else", node, popped));
8441 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8442 ADD_INSN(cond_seq, line_node, putnil);
8443 if (popped) {
8444 ADD_INSN(cond_seq, line_node, putnil);
8445 }
8446 }
8447 else {
8448 debugs("== else (implicit)\n");
8449 ADD_LABEL(cond_seq, elselabel);
8450 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8451 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8452
8453 if (single_pattern) {
8454 /*
8455 * if key_error_p
8456 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8457 * else
8458 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8459 * end
8460 */
8461 LABEL *key_error, *fin;
8462 struct rb_callinfo_kwarg *kw_arg;
8463
8464 key_error = NEW_LABEL(line);
8465 fin = NEW_LABEL(line);
8466
8467 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8468 kw_arg->references = 0;
8469 kw_arg->keyword_len = 2;
8470 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8471 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8472
8473 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8474 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8475 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8476 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8477 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8478 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8479 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8480 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8481 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8482 ADD_INSNL(cond_seq, orig_node, jump, fin);
8483
8484 ADD_LABEL(cond_seq, key_error);
8485 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8486 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8487 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8488 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8489 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8490 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8491 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8492 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8493 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8494 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8495
8496 ADD_LABEL(cond_seq, fin);
8497 }
8498 else {
8499 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8500 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8501 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8502 }
8503 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8504 if (!popped) {
8505 ADD_INSN(cond_seq, orig_node, putnil);
8506 }
8507 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8508 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8509 if (popped) {
8510 ADD_INSN(cond_seq, line_node, putnil);
8511 }
8512 }
8513
8514 ADD_SEQ(ret, cond_seq);
8515 ADD_SEQ(ret, body_seq);
8516 ADD_LABEL(ret, endlabel);
8517 return COMPILE_OK;
8518}
8519
8520#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8521#undef CASE3_BI_OFFSET_ERROR_STRING
8522#undef CASE3_BI_OFFSET_KEY_ERROR_P
8523#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8524#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8525
8526static int
8527compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8528{
8529 const int line = (int)nd_line(node);
8530 const NODE *line_node = node;
8531
8532 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8533 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8534 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8535 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8536 VALUE branches = Qfalse;
8537
8539
8540 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8541 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8542 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8543 LABEL *end_label = NEW_LABEL(line);
8544 LABEL *adjust_label = NEW_LABEL(line);
8545
8546 LABEL *next_catch_label = NEW_LABEL(line);
8547 LABEL *tmp_label = NULL;
8548
8549 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8550 push_ensure_entry(iseq, &enl, NULL, NULL);
8551
8552 if (RNODE_WHILE(node)->nd_state == 1) {
8553 ADD_INSNL(ret, line_node, jump, next_label);
8554 }
8555 else {
8556 tmp_label = NEW_LABEL(line);
8557 ADD_INSNL(ret, line_node, jump, tmp_label);
8558 }
8559 ADD_LABEL(ret, adjust_label);
8560 ADD_INSN(ret, line_node, putnil);
8561 ADD_LABEL(ret, next_catch_label);
8562 ADD_INSN(ret, line_node, pop);
8563 ADD_INSNL(ret, line_node, jump, next_label);
8564 if (tmp_label) ADD_LABEL(ret, tmp_label);
8565
8566 ADD_LABEL(ret, redo_label);
8567 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8568
8569 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8570 add_trace_branch_coverage(
8571 iseq,
8572 ret,
8573 nd_code_loc(coverage_node),
8574 nd_node_id(coverage_node),
8575 0,
8576 "body",
8577 branches);
8578
8579 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8580 ADD_LABEL(ret, next_label); /* next */
8581
8582 if (type == NODE_WHILE) {
8583 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8584 redo_label, end_label));
8585 }
8586 else {
8587 /* until */
8588 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8589 end_label, redo_label));
8590 }
8591
8592 ADD_LABEL(ret, end_label);
8593 ADD_ADJUST_RESTORE(ret, adjust_label);
8594
8595 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8596 /* ADD_INSN(ret, line_node, putundef); */
8597 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8598 return COMPILE_NG;
8599 }
8600 else {
8601 ADD_INSN(ret, line_node, putnil);
8602 }
8603
8604 ADD_LABEL(ret, break_label); /* break */
8605
8606 if (popped) {
8607 ADD_INSN(ret, line_node, pop);
8608 }
8609
8610 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8611 break_label);
8612 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8613 next_catch_label);
8614 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8615 ISEQ_COMPILE_DATA(iseq)->redo_label);
8616
8617 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8618 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8619 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8620 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8621 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8622 return COMPILE_OK;
8623}
8624
8625static int
8626compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8627{
8628 const int line = nd_line(node);
8629 const NODE *line_node = node;
8630 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8631 LABEL *retry_label = NEW_LABEL(line);
8632 LABEL *retry_end_l = NEW_LABEL(line);
8633 const rb_iseq_t *child_iseq;
8634
8635 ADD_LABEL(ret, retry_label);
8636 if (nd_type_p(node, NODE_FOR)) {
8637 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8638
8639 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8640 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8641 ISEQ_TYPE_BLOCK, line);
8642 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8643 }
8644 else {
8645 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8646 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8647 ISEQ_TYPE_BLOCK, line);
8648 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8649 }
8650
8651 {
8652 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8653 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8654 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8655 //
8656 // Normally, "send" instruction is at the last.
8657 // However, qcall under branch coverage measurement adds some instructions after the "send".
8658 //
8659 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8660 INSN *iobj;
8661 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8662 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8663 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8664 iobj = (INSN*) get_prev_insn(iobj);
8665 }
8666 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8667
8668 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8669 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8670 if (&iobj->link == LAST_ELEMENT(ret)) {
8671 ret->last = (LINK_ELEMENT*) retry_end_l;
8672 }
8673 }
8674
8675 if (popped) {
8676 ADD_INSN(ret, line_node, pop);
8677 }
8678
8679 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8680
8681 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8682 return COMPILE_OK;
8683}
8684
8685static int
8686compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8687{
8688 /* massign to var in "for"
8689 * (args.length == 1 && Array.try_convert(args[0])) || args
8690 */
8691 const NODE *line_node = node;
8692 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8693 LABEL *not_single = NEW_LABEL(nd_line(var));
8694 LABEL *not_ary = NEW_LABEL(nd_line(var));
8695 CHECK(COMPILE(ret, "for var", var));
8696 ADD_INSN(ret, line_node, dup);
8697 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8698 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8699 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8700 ADD_INSNL(ret, line_node, branchunless, not_single);
8701 ADD_INSN(ret, line_node, dup);
8702 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8703 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8704 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8705 ADD_INSN(ret, line_node, swap);
8706 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8707 ADD_INSN(ret, line_node, dup);
8708 ADD_INSNL(ret, line_node, branchunless, not_ary);
8709 ADD_INSN(ret, line_node, swap);
8710 ADD_LABEL(ret, not_ary);
8711 ADD_INSN(ret, line_node, pop);
8712 ADD_LABEL(ret, not_single);
8713 return COMPILE_OK;
8714}
8715
8716static int
8717compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8718{
8719 const NODE *line_node = node;
8720 unsigned long throw_flag = 0;
8721
8722 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8723 /* while/until */
8724 LABEL *splabel = NEW_LABEL(0);
8725 ADD_LABEL(ret, splabel);
8726 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8727 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8728 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8729 add_ensure_iseq(ret, iseq, 0);
8730 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8731 ADD_ADJUST_RESTORE(ret, splabel);
8732
8733 if (!popped) {
8734 ADD_INSN(ret, line_node, putnil);
8735 }
8736 }
8737 else {
8738 const rb_iseq_t *ip = iseq;
8739
8740 while (ip) {
8741 if (!ISEQ_COMPILE_DATA(ip)) {
8742 ip = 0;
8743 break;
8744 }
8745
8746 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8747 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8748 }
8749 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8750 throw_flag = 0;
8751 }
8752 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8753 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8754 return COMPILE_NG;
8755 }
8756 else {
8757 ip = ISEQ_BODY(ip)->parent_iseq;
8758 continue;
8759 }
8760
8761 /* escape from block */
8762 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8763 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8764 if (popped) {
8765 ADD_INSN(ret, line_node, pop);
8766 }
8767 return COMPILE_OK;
8768 }
8769 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8770 return COMPILE_NG;
8771 }
8772 return COMPILE_OK;
8773}
8774
8775static int
8776compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8777{
8778 const NODE *line_node = node;
8779 unsigned long throw_flag = 0;
8780
8781 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8782 LABEL *splabel = NEW_LABEL(0);
8783 debugs("next in while loop\n");
8784 ADD_LABEL(ret, splabel);
8785 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8786 add_ensure_iseq(ret, iseq, 0);
8787 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8788 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8789 ADD_ADJUST_RESTORE(ret, splabel);
8790 if (!popped) {
8791 ADD_INSN(ret, line_node, putnil);
8792 }
8793 }
8794 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8795 LABEL *splabel = NEW_LABEL(0);
8796 debugs("next in block\n");
8797 ADD_LABEL(ret, splabel);
8798 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8799 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8800 add_ensure_iseq(ret, iseq, 0);
8801 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8802 ADD_ADJUST_RESTORE(ret, splabel);
8803
8804 if (!popped) {
8805 ADD_INSN(ret, line_node, putnil);
8806 }
8807 }
8808 else {
8809 const rb_iseq_t *ip = iseq;
8810
8811 while (ip) {
8812 if (!ISEQ_COMPILE_DATA(ip)) {
8813 ip = 0;
8814 break;
8815 }
8816
8817 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8818 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8819 /* while loop */
8820 break;
8821 }
8822 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8823 break;
8824 }
8825 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8826 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8827 return COMPILE_NG;
8828 }
8829
8830 ip = ISEQ_BODY(ip)->parent_iseq;
8831 }
8832 if (ip != 0) {
8833 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8834 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8835
8836 if (popped) {
8837 ADD_INSN(ret, line_node, pop);
8838 }
8839 }
8840 else {
8841 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8842 return COMPILE_NG;
8843 }
8844 }
8845 return COMPILE_OK;
8846}
8847
8848static int
8849compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8850{
8851 const NODE *line_node = node;
8852
8853 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8854 LABEL *splabel = NEW_LABEL(0);
8855 debugs("redo in while");
8856 ADD_LABEL(ret, splabel);
8857 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8858 add_ensure_iseq(ret, iseq, 0);
8859 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8860 ADD_ADJUST_RESTORE(ret, splabel);
8861 if (!popped) {
8862 ADD_INSN(ret, line_node, putnil);
8863 }
8864 }
8865 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8866 LABEL *splabel = NEW_LABEL(0);
8867
8868 debugs("redo in block");
8869 ADD_LABEL(ret, splabel);
8870 add_ensure_iseq(ret, iseq, 0);
8871 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8872 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8873 ADD_ADJUST_RESTORE(ret, splabel);
8874
8875 if (!popped) {
8876 ADD_INSN(ret, line_node, putnil);
8877 }
8878 }
8879 else {
8880 const rb_iseq_t *ip = iseq;
8881
8882 while (ip) {
8883 if (!ISEQ_COMPILE_DATA(ip)) {
8884 ip = 0;
8885 break;
8886 }
8887
8888 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8889 break;
8890 }
8891 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8892 break;
8893 }
8894 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8895 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8896 return COMPILE_NG;
8897 }
8898
8899 ip = ISEQ_BODY(ip)->parent_iseq;
8900 }
8901 if (ip != 0) {
8902 ADD_INSN(ret, line_node, putnil);
8903 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8904
8905 if (popped) {
8906 ADD_INSN(ret, line_node, pop);
8907 }
8908 }
8909 else {
8910 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8911 return COMPILE_NG;
8912 }
8913 }
8914 return COMPILE_OK;
8915}
8916
8917static int
8918compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8919{
8920 const NODE *line_node = node;
8921
8922 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8923 ADD_INSN(ret, line_node, putnil);
8924 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8925
8926 if (popped) {
8927 ADD_INSN(ret, line_node, pop);
8928 }
8929 }
8930 else {
8931 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8932 return COMPILE_NG;
8933 }
8934 return COMPILE_OK;
8935}
8936
8937static int
8938compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8939{
8940 const int line = nd_line(node);
8941 const NODE *line_node = node;
8942 LABEL *lstart = NEW_LABEL(line);
8943 LABEL *lend = NEW_LABEL(line);
8944 LABEL *lcont = NEW_LABEL(line);
8945 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8946 rb_str_concat(rb_str_new2("rescue in "),
8947 ISEQ_BODY(iseq)->location.label),
8948 ISEQ_TYPE_RESCUE, line);
8949
8950 lstart->rescued = LABEL_RESCUE_BEG;
8951 lend->rescued = LABEL_RESCUE_END;
8952 ADD_LABEL(ret, lstart);
8953
8954 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8955 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8956 {
8957 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8958 }
8959 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8960
8961 ADD_LABEL(ret, lend);
8962 if (RNODE_RESCUE(node)->nd_else) {
8963 ADD_INSN(ret, line_node, pop);
8964 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8965 }
8966 ADD_INSN(ret, line_node, nop);
8967 ADD_LABEL(ret, lcont);
8968
8969 if (popped) {
8970 ADD_INSN(ret, line_node, pop);
8971 }
8972
8973 /* register catch entry */
8974 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8975 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8976 return COMPILE_OK;
8977}
8978
8979static int
8980compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8981{
8982 const int line = nd_line(node);
8983 const NODE *line_node = node;
8984 const NODE *resq = node;
8985 const NODE *narg;
8986 LABEL *label_miss, *label_hit;
8987
8988 while (resq) {
8989 label_miss = NEW_LABEL(line);
8990 label_hit = NEW_LABEL(line);
8991
8992 narg = RNODE_RESBODY(resq)->nd_args;
8993 if (narg) {
8994 switch (nd_type(narg)) {
8995 case NODE_LIST:
8996 while (narg) {
8997 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8998 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8999 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9000 ADD_INSNL(ret, line_node, branchif, label_hit);
9001 narg = RNODE_LIST(narg)->nd_next;
9002 }
9003 break;
9004 case NODE_SPLAT:
9005 case NODE_ARGSCAT:
9006 case NODE_ARGSPUSH:
9007 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9008 CHECK(COMPILE(ret, "rescue/cond splat", narg));
9009 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
9010 ADD_INSNL(ret, line_node, branchif, label_hit);
9011 break;
9012 default:
9013 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
9014 }
9015 }
9016 else {
9017 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9018 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
9019 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9020 ADD_INSNL(ret, line_node, branchif, label_hit);
9021 }
9022 ADD_INSNL(ret, line_node, jump, label_miss);
9023 ADD_LABEL(ret, label_hit);
9024 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
9025
9026 if (RNODE_RESBODY(resq)->nd_exc_var) {
9027 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
9028 }
9029
9030 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) {
9031 // empty body
9032 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
9033 }
9034 else {
9035 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
9036 }
9037
9038 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
9039 ADD_INSN(ret, line_node, nop);
9040 }
9041 ADD_INSN(ret, line_node, leave);
9042 ADD_LABEL(ret, label_miss);
9043 resq = RNODE_RESBODY(resq)->nd_next;
9044 }
9045 return COMPILE_OK;
9046}
9047
9048static int
9049compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9050{
9051 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
9052 const NODE *line_node = node;
9053 DECL_ANCHOR(ensr);
9054 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
9055 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
9056 ISEQ_TYPE_ENSURE, line);
9057 LABEL *lstart = NEW_LABEL(line);
9058 LABEL *lend = NEW_LABEL(line);
9059 LABEL *lcont = NEW_LABEL(line);
9060 LINK_ELEMENT *last;
9061 int last_leave = 0;
9062 struct ensure_range er;
9064 struct ensure_range *erange;
9065
9066 INIT_ANCHOR(ensr);
9067 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
9068 last = ensr->last;
9069 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
9070
9071 er.begin = lstart;
9072 er.end = lend;
9073 er.next = 0;
9074 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
9075
9076 ADD_LABEL(ret, lstart);
9077 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
9078 ADD_LABEL(ret, lend);
9079 ADD_SEQ(ret, ensr);
9080 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
9081 ADD_LABEL(ret, lcont);
9082 if (last_leave) ADD_INSN(ret, line_node, pop);
9083
9084 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
9085 if (lstart->link.next != &lend->link) {
9086 while (erange) {
9087 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
9088 ensure, lcont);
9089 erange = erange->next;
9090 }
9091 }
9092
9093 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
9094 return COMPILE_OK;
9095}
9096
9097static int
9098compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9099{
9100 const NODE *line_node = node;
9101
9102 if (iseq) {
9103 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
9104 const rb_iseq_t *is = iseq;
9105 enum rb_iseq_type t = type;
9106 const NODE *retval = RNODE_RETURN(node)->nd_stts;
9107 LABEL *splabel = 0;
9108
9109 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
9110 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
9111 t = ISEQ_BODY(is)->type;
9112 }
9113 switch (t) {
9114 case ISEQ_TYPE_TOP:
9115 case ISEQ_TYPE_MAIN:
9116 if (retval) {
9117 rb_warn("argument of top-level return is ignored");
9118 }
9119 if (is == iseq) {
9120 /* plain top-level, leave directly */
9121 type = ISEQ_TYPE_METHOD;
9122 }
9123 break;
9124 default:
9125 break;
9126 }
9127
9128 if (type == ISEQ_TYPE_METHOD) {
9129 splabel = NEW_LABEL(0);
9130 ADD_LABEL(ret, splabel);
9131 ADD_ADJUST(ret, line_node, 0);
9132 }
9133
9134 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
9135
9136 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
9137 add_ensure_iseq(ret, iseq, 1);
9138 ADD_TRACE(ret, RUBY_EVENT_RETURN);
9139 ADD_INSN(ret, line_node, leave);
9140 ADD_ADJUST_RESTORE(ret, splabel);
9141
9142 if (!popped) {
9143 ADD_INSN(ret, line_node, putnil);
9144 }
9145 }
9146 else {
9147 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
9148 if (popped) {
9149 ADD_INSN(ret, line_node, pop);
9150 }
9151 }
9152 }
9153 return COMPILE_OK;
9154}
9155
9156static bool
9157drop_unreachable_return(LINK_ANCHOR *ret)
9158{
9159 LINK_ELEMENT *i = ret->last, *last;
9160 if (!i) return false;
9161 if (IS_TRACE(i)) i = i->prev;
9162 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9163 last = i = i->prev;
9164 if (IS_ADJUST(i)) i = i->prev;
9165 if (!IS_INSN(i)) return false;
9166 switch (INSN_OF(i)) {
9167 case BIN(leave):
9168 case BIN(jump):
9169 break;
9170 default:
9171 return false;
9172 }
9173 (ret->last = last->prev)->next = NULL;
9174 return true;
9175}
9176
9177static int
9178compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9179{
9180 CHECK(COMPILE_(ret, "nd_body", node, popped));
9181
9182 if (!popped && !all_string_result_p(node)) {
9183 const NODE *line_node = node;
9184 const unsigned int flag = VM_CALL_FCALL;
9185
9186 // Note, this dup could be removed if we are willing to change anytostring. It pops
9187 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9188 ADD_INSN(ret, line_node, dup);
9189 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9190 ADD_INSN(ret, line_node, anytostring);
9191 }
9192 return COMPILE_OK;
9193}
9194
9195static void
9196compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9197{
9198 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9199
9200 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9201 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9202}
9203
9204static LABEL *
9205qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9206{
9207 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9208 VALUE br = 0;
9209
9210 br = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "&.");
9211 *branches = br;
9212 ADD_INSN(recv, line_node, dup);
9213 ADD_INSNL(recv, line_node, branchnil, else_label);
9214 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9215 return else_label;
9216}
9217
9218static void
9219qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9220{
9221 LABEL *end_label;
9222 if (!else_label) return;
9223 end_label = NEW_LABEL(nd_line(line_node));
9224 ADD_INSNL(ret, line_node, jump, end_label);
9225 ADD_LABEL(ret, else_label);
9226 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9227 ADD_LABEL(ret, end_label);
9228}
9229
9230static int
9231compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9232{
9233 /* optimization shortcut
9234 * "literal".freeze -> opt_str_freeze("literal")
9235 */
9236 if (get_nd_recv(node) &&
9237 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9238 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9239 get_nd_args(node) == NULL &&
9240 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9241 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9242 VALUE str = get_string_value(get_nd_recv(node));
9243 if (get_node_call_nd_mid(node) == idUMinus) {
9244 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9245 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9246 }
9247 else {
9248 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9249 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9250 }
9251 RB_OBJ_WRITTEN(iseq, Qundef, str);
9252 if (popped) {
9253 ADD_INSN(ret, line_node, pop);
9254 }
9255 return TRUE;
9256 }
9257 return FALSE;
9258}
9259
9260static int
9261iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9262{
9263 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9264}
9265
9266static const struct rb_builtin_function *
9267iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9268{
9269 int i;
9270 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9271 for (i=0; table[i].index != -1; i++) {
9272 if (strcmp(table[i].name, name) == 0) {
9273 return &table[i];
9274 }
9275 }
9276 return NULL;
9277}
9278
9279static const char *
9280iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9281{
9282 const char *name = rb_id2name(mid);
9283 static const char prefix[] = "__builtin_";
9284 const size_t prefix_len = sizeof(prefix) - 1;
9285
9286 switch (type) {
9287 case NODE_CALL:
9288 if (recv) {
9289 switch (nd_type(recv)) {
9290 case NODE_VCALL:
9291 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9292 return name;
9293 }
9294 break;
9295 case NODE_CONST:
9296 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9297 return name;
9298 }
9299 break;
9300 default: break;
9301 }
9302 }
9303 break;
9304 case NODE_VCALL:
9305 case NODE_FCALL:
9306 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9307 return &name[prefix_len];
9308 }
9309 break;
9310 default: break;
9311 }
9312 return NULL;
9313}
9314
9315static int
9316delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9317{
9318
9319 if (argc == 0) {
9320 *pstart_index = 0;
9321 return TRUE;
9322 }
9323 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9324 unsigned int start=0;
9325
9326 // local_table: [p1, p2, p3, l1, l2, l3]
9327 // arguments: [p3, l1, l2] -> 2
9328 for (start = 0;
9329 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9330 start++) {
9331 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9332
9333 for (unsigned int i=start; i-start<argc; i++) {
9334 if (IS_INSN(elem) &&
9335 INSN_OF(elem) == BIN(getlocal)) {
9336 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9337 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9338
9339 if (local_level == 0) {
9340 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9341 if (0) { // for debug
9342 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9343 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9344 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9345 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9346 }
9347 if (i == index) {
9348 elem = elem->next;
9349 continue; /* for */
9350 }
9351 else {
9352 goto next;
9353 }
9354 }
9355 else {
9356 goto fail; // level != 0 is unsupported
9357 }
9358 }
9359 else {
9360 goto fail; // insn is not a getlocal
9361 }
9362 }
9363 goto success;
9364 next:;
9365 }
9366 fail:
9367 return FALSE;
9368 success:
9369 *pstart_index = start;
9370 return TRUE;
9371 }
9372 else {
9373 return FALSE;
9374 }
9375}
9376
9377static int
9378compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
9379{
9380 VALUE string = rb_sym2str(symbol);
9381 if (rb_streql_lit(string, "leaf")) {
9382 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9383 }
9384 else if (rb_streql_lit(string, "inline_block")) {
9385 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9386 }
9387 else if (rb_streql_lit(string, "use_block")) {
9388 iseq_set_use_block(iseq);
9389 }
9390 else if (rb_streql_lit(string, "c_trace")) {
9391 // Let the iseq act like a C method in backtraces
9392 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9393 }
9394 else if (rb_streql_lit(string, "without_interrupts")) {
9395 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9396 }
9397 else if (rb_streql_lit(string, "caller_user_box")) {
9398 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_CALLER_USER_BOX;
9399 }
9400 else {
9401 return COMPILE_NG;
9402 }
9403 return COMPILE_OK;
9404}
9405
9406// Compile Primitive.attr! :leaf, ...
9407static int
9408compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9409{
9410 VALUE symbol;
9411 if (!node) goto no_arg;
9412 while (node) {
9413 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9414 const NODE *next = RNODE_LIST(node)->nd_next;
9415
9416 node = RNODE_LIST(node)->nd_head;
9417 if (!node) goto no_arg;
9418 switch (nd_type(node)) {
9419 case NODE_SYM:
9420 symbol = rb_node_sym_string_val(node);
9421 break;
9422 default:
9423 goto bad_arg;
9424 }
9425
9426 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9427 if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
9428 node = next;
9429 }
9430 return COMPILE_OK;
9431 no_arg:
9432 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9433 return COMPILE_NG;
9434 non_symbol_arg:
9435 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9436 return COMPILE_NG;
9437 unknown_arg:
9438 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
9439 return COMPILE_NG;
9440 bad_arg:
9441 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9442}
9443
9444static int
9445compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9446{
9447 VALUE name;
9448
9449 if (!node) goto no_arg;
9450 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9451 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9452 node = RNODE_LIST(node)->nd_head;
9453 if (!node) goto no_arg;
9454 switch (nd_type(node)) {
9455 case NODE_SYM:
9456 name = rb_node_sym_string_val(node);
9457 break;
9458 default:
9459 goto bad_arg;
9460 }
9461 if (!SYMBOL_P(name)) goto non_symbol_arg;
9462 if (!popped) {
9463 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9464 }
9465 return COMPILE_OK;
9466 no_arg:
9467 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9468 return COMPILE_NG;
9469 too_many_arg:
9470 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9471 return COMPILE_NG;
9472 non_symbol_arg:
9473 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9474 rb_builtin_class_name(name));
9475 return COMPILE_NG;
9476 bad_arg:
9477 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9478}
9479
9480static NODE *
9481mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9482{
9483 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9484 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9485 return RNODE_IF(node)->nd_body;
9486 }
9487 else {
9488 rb_bug("mandatory_node: can't find mandatory node");
9489 }
9490}
9491
9492static int
9493compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9494{
9495 // arguments
9496 struct rb_args_info args = {
9497 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9498 };
9499 rb_node_args_t args_node;
9500 rb_node_init(RNODE(&args_node), NODE_ARGS);
9501 args_node.nd_ainfo = args;
9502
9503 // local table without non-mandatory parameters
9504 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9505 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9506
9507 VALUE idtmp = 0;
9508 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9509 tbl->size = table_size;
9510
9511 int i;
9512
9513 // lead parameters
9514 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9515 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9516 }
9517 // local variables
9518 for (; i<table_size; i++) {
9519 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9520 }
9521
9522 rb_node_scope_t scope_node;
9523 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9524 scope_node.nd_tbl = tbl;
9525 scope_node.nd_body = mandatory_node(iseq, node);
9526 scope_node.nd_parent = NULL;
9527 scope_node.nd_args = &args_node;
9528
9529 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9530
9531 const rb_iseq_t *mandatory_only_iseq =
9532 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9533 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9534 nd_line(line_node), NULL, 0,
9535 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9536 ISEQ_SCRIPT_LINES(iseq));
9537 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9538
9539 ALLOCV_END(idtmp);
9540 return COMPILE_OK;
9541}
9542
9543static int
9544compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9545 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9546{
9547 NODE *args_node = get_nd_args(node);
9548
9549 if (parent_block != NULL) {
9550 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9551 return COMPILE_NG;
9552 }
9553 else {
9554# define BUILTIN_INLINE_PREFIX "_bi"
9555 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9556 bool cconst = false;
9557 retry:;
9558 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9559
9560 if (bf == NULL) {
9561 if (strcmp("cstmt!", builtin_func) == 0 ||
9562 strcmp("cexpr!", builtin_func) == 0) {
9563 // ok
9564 }
9565 else if (strcmp("cconst!", builtin_func) == 0) {
9566 cconst = true;
9567 }
9568 else if (strcmp("cinit!", builtin_func) == 0) {
9569 // ignore
9570 return COMPILE_OK;
9571 }
9572 else if (strcmp("attr!", builtin_func) == 0) {
9573 return compile_builtin_attr(iseq, args_node);
9574 }
9575 else if (strcmp("arg!", builtin_func) == 0) {
9576 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9577 }
9578 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9579 if (popped) {
9580 rb_bug("mandatory_only? should be in if condition");
9581 }
9582 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9583 rb_bug("mandatory_only? should be put on top");
9584 }
9585
9586 ADD_INSN1(ret, line_node, putobject, Qfalse);
9587 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9588 }
9589 else if (1) {
9590 rb_bug("can't find builtin function:%s", builtin_func);
9591 }
9592 else {
9593 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9594 return COMPILE_NG;
9595 }
9596
9597 int inline_index = nd_line(node);
9598 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9599 builtin_func = inline_func;
9600 args_node = NULL;
9601 goto retry;
9602 }
9603
9604 if (cconst) {
9605 typedef VALUE(*builtin_func0)(void *, VALUE);
9606 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9607 ADD_INSN1(ret, line_node, putobject, const_val);
9608 return COMPILE_OK;
9609 }
9610
9611 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9612
9613 unsigned int flag = 0;
9614 struct rb_callinfo_kwarg *keywords = NULL;
9615 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9616
9617 if (FIX2INT(argc) != bf->argc) {
9618 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9619 builtin_func, bf->argc, FIX2INT(argc));
9620 return COMPILE_NG;
9621 }
9622
9623 unsigned int start_index;
9624 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9625 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9626 }
9627 else {
9628 ADD_SEQ(ret, args);
9629 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9630 }
9631
9632 if (popped) ADD_INSN(ret, line_node, pop);
9633 return COMPILE_OK;
9634 }
9635}
9636
9637static int
9638compile_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)
9639{
9640 /* call: obj.method(...)
9641 * fcall: func(...)
9642 * vcall: func
9643 */
9644 DECL_ANCHOR(recv);
9645 DECL_ANCHOR(args);
9646 ID mid = get_node_call_nd_mid(node);
9647 VALUE argc;
9648 unsigned int flag = 0;
9649 struct rb_callinfo_kwarg *keywords = NULL;
9650 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9651 LABEL *else_label = NULL;
9652 VALUE branches = Qfalse;
9653
9654 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9655
9656 INIT_ANCHOR(recv);
9657 INIT_ANCHOR(args);
9658
9659#if OPT_SUPPORT_JOKE
9660 if (nd_type_p(node, NODE_VCALL)) {
9661 ID id_bitblt;
9662 ID id_answer;
9663
9664 CONST_ID(id_bitblt, "bitblt");
9665 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9666
9667 if (mid == id_bitblt) {
9668 ADD_INSN(ret, line_node, bitblt);
9669 return COMPILE_OK;
9670 }
9671 else if (mid == id_answer) {
9672 ADD_INSN(ret, line_node, answer);
9673 return COMPILE_OK;
9674 }
9675 }
9676 /* only joke */
9677 {
9678 ID goto_id;
9679 ID label_id;
9680
9681 CONST_ID(goto_id, "__goto__");
9682 CONST_ID(label_id, "__label__");
9683
9684 if (nd_type_p(node, NODE_FCALL) &&
9685 (mid == goto_id || mid == label_id)) {
9686 LABEL *label;
9687 st_data_t data;
9688 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9689 VALUE label_name;
9690
9691 if (!labels_table) {
9692 labels_table = st_init_numtable();
9693 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9694 }
9695 {
9696 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9697 return COMPILE_NG;
9698 }
9699
9700 if (mid == goto_id) {
9701 ADD_INSNL(ret, line_node, jump, label);
9702 }
9703 else {
9704 ADD_LABEL(ret, label);
9705 }
9706 return COMPILE_OK;
9707 }
9708 }
9709#endif
9710
9711 const char *builtin_func;
9712 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9713 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9714 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9715 }
9716
9717 /* receiver */
9718 if (!assume_receiver) {
9719 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9720 int idx, level;
9721
9722 if ((mid == idCall || mid == idAREF || mid == idYield || mid == idEqq) &&
9723 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9724 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9725 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9726 }
9727 else if (private_recv_p(node)) {
9728 ADD_INSN(recv, node, putself);
9729 flag |= VM_CALL_FCALL;
9730 }
9731 else {
9732 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9733 }
9734
9735 if (type == NODE_QCALL) {
9736 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9737 }
9738 }
9739 else if (type == NODE_FCALL || type == NODE_VCALL) {
9740 ADD_CALL_RECEIVER(recv, line_node);
9741 }
9742 }
9743
9744 /* args */
9745 if (type != NODE_VCALL) {
9746 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9747 CHECK(!NIL_P(argc));
9748 }
9749 else {
9750 argc = INT2FIX(0);
9751 }
9752
9753 ADD_SEQ(ret, recv);
9754
9755 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9756 mid == rb_intern("new") &&
9757 parent_block == NULL &&
9758 !(flag & VM_CALL_ARGS_BLOCKARG);
9759
9760 if (inline_new) {
9761 ADD_INSN(ret, node, putnil);
9762 ADD_INSN(ret, node, swap);
9763 }
9764
9765 ADD_SEQ(ret, args);
9766
9767 debugp_param("call args argc", argc);
9768 debugp_param("call method", ID2SYM(mid));
9769
9770 switch ((int)type) {
9771 case NODE_VCALL:
9772 flag |= VM_CALL_VCALL;
9773 /* VCALL is funcall, so fall through */
9774 case NODE_FCALL:
9775 flag |= VM_CALL_FCALL;
9776 }
9777
9778 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9779 ADD_INSN(ret, line_node, splatkw);
9780 }
9781
9782 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9783 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9784
9785 if (inline_new) {
9786 // Jump unless the receiver uses the "basic" implementation of "new"
9787 VALUE ci;
9788 if (flag & VM_CALL_FORWARDING) {
9789 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9790 }
9791 else {
9792 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9793 }
9794 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9795 LABEL_REF(not_basic_new);
9796
9797 // optimized path
9798 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9799 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9800
9801 ADD_LABEL(ret, not_basic_new);
9802 // Fall back to normal send
9803 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9804 ADD_INSN(ret, line_node, swap);
9805
9806 ADD_LABEL(ret, not_basic_new_finish);
9807 ADD_INSN(ret, line_node, pop);
9808 }
9809 else {
9810 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9811 }
9812
9813 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9814 if (popped) {
9815 ADD_INSN(ret, line_node, pop);
9816 }
9817 return COMPILE_OK;
9818}
9819
9820static int
9821compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9822{
9823 const int line = nd_line(node);
9824 VALUE argc;
9825 unsigned int flag = 0;
9826 int asgnflag = 0;
9827 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9828
9829 /*
9830 * a[x] (op)= y
9831 *
9832 * nil # nil
9833 * eval a # nil a
9834 * eval x # nil a x
9835 * dupn 2 # nil a x a x
9836 * send :[] # nil a x a[x]
9837 * eval y # nil a x a[x] y
9838 * send op # nil a x ret
9839 * setn 3 # ret a x ret
9840 * send []= # ret ?
9841 * pop # ret
9842 */
9843
9844 /*
9845 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9846 * NODE_OP_ASGN nd_recv
9847 * nd_args->nd_head
9848 * nd_args->nd_body
9849 * nd_mid
9850 */
9851
9852 if (!popped) {
9853 ADD_INSN(ret, node, putnil);
9854 }
9855 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9856 CHECK(asgnflag != -1);
9857 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9858 case NODE_ZLIST:
9859 argc = INT2FIX(0);
9860 break;
9861 default:
9862 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9863 CHECK(!NIL_P(argc));
9864 }
9865 int dup_argn = FIX2INT(argc) + 1;
9866 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9867 flag |= asgnflag;
9868 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9869
9870 if (id == idOROP || id == idANDOP) {
9871 /* a[x] ||= y or a[x] &&= y
9872
9873 unless/if a[x]
9874 a[x]= y
9875 else
9876 nil
9877 end
9878 */
9879 LABEL *label = NEW_LABEL(line);
9880 LABEL *lfin = NEW_LABEL(line);
9881
9882 ADD_INSN(ret, node, dup);
9883 if (id == idOROP) {
9884 ADD_INSNL(ret, node, branchif, label);
9885 }
9886 else { /* idANDOP */
9887 ADD_INSNL(ret, node, branchunless, label);
9888 }
9889 ADD_INSN(ret, node, pop);
9890
9891 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9892 if (!popped) {
9893 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9894 }
9895 if (flag & VM_CALL_ARGS_SPLAT) {
9896 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9897 ADD_INSN(ret, node, swap);
9898 ADD_INSN1(ret, node, splatarray, Qtrue);
9899 ADD_INSN(ret, node, swap);
9900 flag |= VM_CALL_ARGS_SPLAT_MUT;
9901 }
9902 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9903 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9904 }
9905 else {
9906 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9907 }
9908 ADD_INSN(ret, node, pop);
9909 ADD_INSNL(ret, node, jump, lfin);
9910 ADD_LABEL(ret, label);
9911 if (!popped) {
9912 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9913 }
9914 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9915 ADD_LABEL(ret, lfin);
9916 }
9917 else {
9918 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9919 ADD_SEND(ret, node, id, INT2FIX(1));
9920 if (!popped) {
9921 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9922 }
9923 if (flag & VM_CALL_ARGS_SPLAT) {
9924 if (flag & VM_CALL_KW_SPLAT) {
9925 ADD_INSN1(ret, node, topn, INT2FIX(2));
9926 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9927 ADD_INSN1(ret, node, splatarray, Qtrue);
9928 flag |= VM_CALL_ARGS_SPLAT_MUT;
9929 }
9930 ADD_INSN(ret, node, swap);
9931 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9932 ADD_INSN1(ret, node, setn, INT2FIX(2));
9933 ADD_INSN(ret, node, pop);
9934 }
9935 else {
9936 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9937 ADD_INSN(ret, node, swap);
9938 ADD_INSN1(ret, node, splatarray, Qtrue);
9939 ADD_INSN(ret, node, swap);
9940 flag |= VM_CALL_ARGS_SPLAT_MUT;
9941 }
9942 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9943 }
9944 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9945 }
9946 else {
9947 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9948 }
9949 ADD_INSN(ret, node, pop);
9950 }
9951 return COMPILE_OK;
9952}
9953
9954static int
9955compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9956{
9957 const int line = nd_line(node);
9958 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9959 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9960 int asgnflag;
9961 LABEL *lfin = NEW_LABEL(line);
9962 LABEL *lcfin = NEW_LABEL(line);
9963 LABEL *lskip = 0;
9964 /*
9965 class C; attr_accessor :c; end
9966 r = C.new
9967 r.a &&= v # asgn2
9968
9969 eval r # r
9970 dup # r r
9971 eval r.a # r o
9972
9973 # or
9974 dup # r o o
9975 if lcfin # r o
9976 pop # r
9977 eval v # r v
9978 swap # v r
9979 topn 1 # v r v
9980 send a= # v ?
9981 jump lfin # v ?
9982
9983 lcfin: # r o
9984 swap # o r
9985
9986 lfin: # o ?
9987 pop # o
9988
9989 # or (popped)
9990 if lcfin # r
9991 eval v # r v
9992 send a= # ?
9993 jump lfin # ?
9994
9995 lcfin: # r
9996
9997 lfin: # ?
9998 pop #
9999
10000 # and
10001 dup # r o o
10002 unless lcfin
10003 pop # r
10004 eval v # r v
10005 swap # v r
10006 topn 1 # v r v
10007 send a= # v ?
10008 jump lfin # v ?
10009
10010 # others
10011 eval v # r o v
10012 send ?? # r w
10013 send a= # w
10014
10015 */
10016
10017 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
10018 CHECK(asgnflag != -1);
10019 if (RNODE_OP_ASGN2(node)->nd_aid) {
10020 lskip = NEW_LABEL(line);
10021 ADD_INSN(ret, node, dup);
10022 ADD_INSNL(ret, node, branchnil, lskip);
10023 }
10024 ADD_INSN(ret, node, dup);
10025 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
10026
10027 if (atype == idOROP || atype == idANDOP) {
10028 if (!popped) {
10029 ADD_INSN(ret, node, dup);
10030 }
10031 if (atype == idOROP) {
10032 ADD_INSNL(ret, node, branchif, lcfin);
10033 }
10034 else { /* idANDOP */
10035 ADD_INSNL(ret, node, branchunless, lcfin);
10036 }
10037 if (!popped) {
10038 ADD_INSN(ret, node, pop);
10039 }
10040 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10041 if (!popped) {
10042 ADD_INSN(ret, node, swap);
10043 ADD_INSN1(ret, node, topn, INT2FIX(1));
10044 }
10045 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10046 ADD_INSNL(ret, node, jump, lfin);
10047
10048 ADD_LABEL(ret, lcfin);
10049 if (!popped) {
10050 ADD_INSN(ret, node, swap);
10051 }
10052
10053 ADD_LABEL(ret, lfin);
10054 }
10055 else {
10056 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10057 ADD_SEND(ret, node, atype, INT2FIX(1));
10058 if (!popped) {
10059 ADD_INSN(ret, node, swap);
10060 ADD_INSN1(ret, node, topn, INT2FIX(1));
10061 }
10062 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10063 }
10064 if (lskip && popped) {
10065 ADD_LABEL(ret, lskip);
10066 }
10067 ADD_INSN(ret, node, pop);
10068 if (lskip && !popped) {
10069 ADD_LABEL(ret, lskip);
10070 }
10071 return COMPILE_OK;
10072}
10073
10074static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
10075
10076static int
10077compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10078{
10079 const int line = nd_line(node);
10080 LABEL *lfin = 0;
10081 LABEL *lassign = 0;
10082 ID mid;
10083
10084 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
10085 case NODE_COLON3:
10086 ADD_INSN1(ret, node, putobject, rb_cObject);
10087 break;
10088 case NODE_COLON2:
10089 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
10090 break;
10091 default:
10092 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
10093 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
10094 return COMPILE_NG;
10095 }
10096 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
10097 /* cref */
10098 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
10099 lassign = NEW_LABEL(line);
10100 ADD_INSN(ret, node, dup); /* cref cref */
10101 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
10102 ID2SYM(mid), Qtrue); /* cref bool */
10103 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
10104 }
10105 ADD_INSN(ret, node, dup); /* cref cref */
10106 ADD_INSN1(ret, node, putobject, Qtrue);
10107 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
10108
10109 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
10110 lfin = NEW_LABEL(line);
10111 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
10112 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
10113 ADD_INSNL(ret, node, branchif, lfin);
10114 else /* idANDOP */
10115 ADD_INSNL(ret, node, branchunless, lfin);
10116 /* cref [obj] */
10117 if (!popped) ADD_INSN(ret, node, pop); /* cref */
10118 if (lassign) ADD_LABEL(ret, lassign);
10119 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10120 /* cref value */
10121 if (popped)
10122 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
10123 else {
10124 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
10125 ADD_INSN(ret, node, swap); /* cref value value cref */
10126 }
10127 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
10128 ADD_LABEL(ret, lfin); /* cref [value] */
10129 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
10130 ADD_INSN(ret, node, pop); /* [value] */
10131 }
10132 else {
10133 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10134 /* cref obj value */
10135 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
10136 /* cref value */
10137 ADD_INSN(ret, node, swap); /* value cref */
10138 if (!popped) {
10139 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
10140 ADD_INSN(ret, node, swap); /* value value cref */
10141 }
10142 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
10143 }
10144 return COMPILE_OK;
10145}
10146
10147static int
10148compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10149{
10150 const int line = nd_line(node);
10151 LABEL *lfin = NEW_LABEL(line);
10152 LABEL *lassign;
10153
10154 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
10155 LABEL *lfinish[2];
10156 lfinish[0] = lfin;
10157 lfinish[1] = 0;
10158 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
10159 lassign = lfinish[1];
10160 if (!lassign) {
10161 lassign = NEW_LABEL(line);
10162 }
10163 ADD_INSNL(ret, node, branchunless, lassign);
10164 }
10165 else {
10166 lassign = NEW_LABEL(line);
10167 }
10168
10169 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10170
10171 if (!popped) {
10172 ADD_INSN(ret, node, dup);
10173 }
10174
10175 if (type == NODE_OP_ASGN_AND) {
10176 ADD_INSNL(ret, node, branchunless, lfin);
10177 }
10178 else {
10179 ADD_INSNL(ret, node, branchif, lfin);
10180 }
10181
10182 if (!popped) {
10183 ADD_INSN(ret, node, pop);
10184 }
10185
10186 ADD_LABEL(ret, lassign);
10187 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10188 ADD_LABEL(ret, lfin);
10189 return COMPILE_OK;
10190}
10191
10192static int
10193compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10194{
10195 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10196 DECL_ANCHOR(args);
10197 int argc;
10198 unsigned int flag = 0;
10199 struct rb_callinfo_kwarg *keywords = NULL;
10200 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10201 int use_block = 1;
10202
10203 INIT_ANCHOR(args);
10204 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10205
10206 if (type == NODE_SUPER) {
10207 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10208 CHECK(!NIL_P(vargc));
10209 argc = FIX2INT(vargc);
10210 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10211 ADD_INSN(args, node, splatkw);
10212 }
10213
10214 if (flag & VM_CALL_ARGS_BLOCKARG) {
10215 use_block = 0;
10216 }
10217 }
10218 else {
10219 /* NODE_ZSUPER */
10220 int i;
10221 const rb_iseq_t *liseq = body->local_iseq;
10222 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10223 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10224 int lvar_level = get_lvar_level(iseq);
10225
10226 argc = local_body->param.lead_num;
10227
10228 /* normal arguments */
10229 for (i = 0; i < local_body->param.lead_num; i++) {
10230 int idx = local_body->local_table_size - i;
10231 ADD_GETLOCAL(args, node, idx, lvar_level);
10232 }
10233
10234 /* forward ... */
10235 if (local_body->param.flags.forwardable) {
10236 flag |= VM_CALL_FORWARDING;
10237 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10238 ADD_GETLOCAL(args, node, idx, lvar_level);
10239 }
10240
10241 if (local_body->param.flags.has_opt) {
10242 /* optional arguments */
10243 int j;
10244 for (j = 0; j < local_body->param.opt_num; j++) {
10245 int idx = local_body->local_table_size - (i + j);
10246 ADD_GETLOCAL(args, node, idx, lvar_level);
10247 }
10248 i += j;
10249 argc = i;
10250 }
10251 if (local_body->param.flags.has_rest) {
10252 /* rest argument */
10253 int idx = local_body->local_table_size - local_body->param.rest_start;
10254 ADD_GETLOCAL(args, node, idx, lvar_level);
10255 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10256
10257 argc = local_body->param.rest_start + 1;
10258 flag |= VM_CALL_ARGS_SPLAT;
10259 }
10260 if (local_body->param.flags.has_post) {
10261 /* post arguments */
10262 int post_len = local_body->param.post_num;
10263 int post_start = local_body->param.post_start;
10264
10265 if (local_body->param.flags.has_rest) {
10266 int j;
10267 for (j=0; j<post_len; j++) {
10268 int idx = local_body->local_table_size - (post_start + j);
10269 ADD_GETLOCAL(args, node, idx, lvar_level);
10270 }
10271 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10272 flag |= VM_CALL_ARGS_SPLAT_MUT;
10273 /* argc is settled at above */
10274 }
10275 else {
10276 int j;
10277 for (j=0; j<post_len; j++) {
10278 int idx = local_body->local_table_size - (post_start + j);
10279 ADD_GETLOCAL(args, node, idx, lvar_level);
10280 }
10281 argc = post_len + post_start;
10282 }
10283 }
10284
10285 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10286 int local_size = local_body->local_table_size;
10287 argc++;
10288
10289 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10290
10291 if (local_body->param.flags.has_kwrest) {
10292 int idx = local_body->local_table_size - local_kwd->rest_start;
10293 ADD_GETLOCAL(args, node, idx, lvar_level);
10294 RUBY_ASSERT(local_kwd->num > 0);
10295 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10296 }
10297 else {
10298 ADD_INSN1(args, node, newhash, INT2FIX(0));
10299 }
10300 for (i = 0; i < local_kwd->num; ++i) {
10301 ID id = local_kwd->table[i];
10302 int idx = local_size - get_local_var_idx(liseq, id);
10303 ADD_INSN1(args, node, putobject, ID2SYM(id));
10304 ADD_GETLOCAL(args, node, idx, lvar_level);
10305 }
10306 ADD_SEND(args, node, id_core_hash_merge_bang_ptr, INT2FIX(i * 2 + 1));
10307 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10308 }
10309 else if (local_body->param.flags.has_kwrest) {
10310 int idx = local_body->local_table_size - local_kwd->rest_start;
10311 ADD_GETLOCAL(args, node, idx, lvar_level);
10312 argc++;
10313 flag |= VM_CALL_KW_SPLAT;
10314 }
10315 }
10316
10317 if (use_block && parent_block == NULL) {
10318 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10319 }
10320
10321 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10322 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10323 ADD_INSN(ret, node, putself);
10324 ADD_SEQ(ret, args);
10325
10326 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10327
10328 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10329 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10330 }
10331 else {
10332 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10333 }
10334
10335 if (popped) {
10336 ADD_INSN(ret, node, pop);
10337 }
10338 return COMPILE_OK;
10339}
10340
10341static int
10342compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10343{
10344 DECL_ANCHOR(args);
10345 VALUE argc;
10346 unsigned int flag = 0;
10347 struct rb_callinfo_kwarg *keywords = NULL;
10348
10349 INIT_ANCHOR(args);
10350
10351 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10352 case ISEQ_TYPE_TOP:
10353 case ISEQ_TYPE_MAIN:
10354 case ISEQ_TYPE_CLASS:
10355 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10356 return COMPILE_NG;
10357 default: /* valid */;
10358 }
10359
10360 if (RNODE_YIELD(node)->nd_head) {
10361 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10362 CHECK(!NIL_P(argc));
10363 }
10364 else {
10365 argc = INT2FIX(0);
10366 }
10367
10368 ADD_SEQ(ret, args);
10369 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10370 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10371
10372 if (popped) {
10373 ADD_INSN(ret, node, pop);
10374 }
10375
10376 int level = 0;
10377 const rb_iseq_t *tmp_iseq = iseq;
10378 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10379 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10380 }
10381 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10382
10383 return COMPILE_OK;
10384}
10385
10386static int
10387compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10388{
10389 DECL_ANCHOR(recv);
10390 DECL_ANCHOR(val);
10391
10392 INIT_ANCHOR(recv);
10393 INIT_ANCHOR(val);
10394 switch ((int)type) {
10395 case NODE_MATCH:
10396 {
10397 VALUE re = rb_node_regx_string_val(node);
10399 ADD_INSN1(recv, node, putobject, re);
10400 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10401 INT2FIX(0));
10402 }
10403 break;
10404 case NODE_MATCH2:
10405 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10406 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10407 break;
10408 case NODE_MATCH3:
10409 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10410 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10411 break;
10412 }
10413
10414 ADD_SEQ(ret, recv);
10415 ADD_SEQ(ret, val);
10416 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10417
10418 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10419 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10420 }
10421
10422 if (popped) {
10423 ADD_INSN(ret, node, pop);
10424 }
10425 return COMPILE_OK;
10426}
10427
10428static int
10429compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10430{
10431 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10432 /* constant */
10433 VALUE segments;
10434 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10435 (segments = collect_const_segments(iseq, node))) {
10436 ISEQ_BODY(iseq)->ic_size++;
10437 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10438 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10439 }
10440 else {
10441 /* constant */
10442 DECL_ANCHOR(pref);
10443 DECL_ANCHOR(body);
10444
10445 INIT_ANCHOR(pref);
10446 INIT_ANCHOR(body);
10447 CHECK(compile_const_prefix(iseq, node, pref, body));
10448 if (LIST_INSN_SIZE_ZERO(pref)) {
10449 ADD_INSN(ret, node, putnil);
10450 ADD_SEQ(ret, body);
10451 }
10452 else {
10453 ADD_SEQ(ret, pref);
10454 ADD_SEQ(ret, body);
10455 }
10456 }
10457 }
10458 else {
10459 /* function call */
10460 ADD_CALL_RECEIVER(ret, node);
10461 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10462 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10463 }
10464 if (popped) {
10465 ADD_INSN(ret, node, pop);
10466 }
10467 return COMPILE_OK;
10468}
10469
10470static int
10471compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10472{
10473 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10474
10475 /* add cache insn */
10476 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10477 ISEQ_BODY(iseq)->ic_size++;
10478 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10480 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10481 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10482 }
10483 else {
10484 ADD_INSN1(ret, node, putobject, rb_cObject);
10485 ADD_INSN1(ret, node, putobject, Qtrue);
10486 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10487 }
10488
10489 if (popped) {
10490 ADD_INSN(ret, node, pop);
10491 }
10492 return COMPILE_OK;
10493}
10494
10495static int
10496compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10497{
10498 VALUE flag = INT2FIX(excl);
10499 const NODE *b = RNODE_DOT2(node)->nd_beg;
10500 const NODE *e = RNODE_DOT2(node)->nd_end;
10501
10502 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10503 if (!popped) {
10504 VALUE bv = optimized_range_item(b);
10505 VALUE ev = optimized_range_item(e);
10506 VALUE val = rb_range_new(bv, ev, excl);
10508 ADD_INSN1(ret, node, putobject, val);
10509 RB_OBJ_WRITTEN(iseq, Qundef, val);
10510 }
10511 }
10512 else {
10513 CHECK(COMPILE_(ret, "min", b, popped));
10514 CHECK(COMPILE_(ret, "max", e, popped));
10515 if (!popped) {
10516 ADD_INSN1(ret, node, newrange, flag);
10517 }
10518 }
10519 return COMPILE_OK;
10520}
10521
10522static int
10523compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10524{
10525 if (!popped) {
10526 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10527 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10528 }
10529 else {
10530 const rb_iseq_t *ip = iseq;
10531 int level = 0;
10532 while (ip) {
10533 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10534 break;
10535 }
10536 ip = ISEQ_BODY(ip)->parent_iseq;
10537 level++;
10538 }
10539 if (ip) {
10540 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10541 }
10542 else {
10543 ADD_INSN(ret, node, putnil);
10544 }
10545 }
10546 }
10547 return COMPILE_OK;
10548}
10549
10550static int
10551compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10552{
10553 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10554 LABEL *end_label = NEW_LABEL(nd_line(node));
10555 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10556
10557 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10558 /* required argument. do nothing */
10559 COMPILE_ERROR(ERROR_ARGS "unreachable");
10560 return COMPILE_NG;
10561 }
10562 else if (nd_type_p(default_value, NODE_SYM) ||
10563 nd_type_p(default_value, NODE_REGX) ||
10564 nd_type_p(default_value, NODE_LINE) ||
10565 nd_type_p(default_value, NODE_INTEGER) ||
10566 nd_type_p(default_value, NODE_FLOAT) ||
10567 nd_type_p(default_value, NODE_RATIONAL) ||
10568 nd_type_p(default_value, NODE_IMAGINARY) ||
10569 nd_type_p(default_value, NODE_NIL) ||
10570 nd_type_p(default_value, NODE_TRUE) ||
10571 nd_type_p(default_value, NODE_FALSE)) {
10572 COMPILE_ERROR(ERROR_ARGS "unreachable");
10573 return COMPILE_NG;
10574 }
10575 else {
10576 /* if keywordcheck(_kw_bits, nth_keyword)
10577 * kw = default_value
10578 * end
10579 */
10580 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10581 int keyword_idx = body->param.keyword->num;
10582
10583 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10584 ADD_INSNL(ret, node, branchif, end_label);
10585 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10586 ADD_LABEL(ret, end_label);
10587 }
10588 return COMPILE_OK;
10589}
10590
10591static int
10592compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10593{
10594 DECL_ANCHOR(recv);
10595 DECL_ANCHOR(args);
10596 unsigned int flag = 0;
10597 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10598 VALUE argc;
10599 LABEL *else_label = NULL;
10600 VALUE branches = Qfalse;
10601
10602 INIT_ANCHOR(recv);
10603 INIT_ANCHOR(args);
10604 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10605 CHECK(!NIL_P(argc));
10606
10607 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10608 CHECK(asgnflag != -1);
10609 flag |= (unsigned int)asgnflag;
10610
10611 debugp_param("argc", argc);
10612 debugp_param("nd_mid", ID2SYM(mid));
10613
10614 if (!rb_is_attrset_id(mid)) {
10615 /* safe nav attr */
10616 mid = rb_id_attrset(mid);
10617 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10618 }
10619 if (!popped) {
10620 ADD_INSN(ret, node, putnil);
10621 ADD_SEQ(ret, recv);
10622 ADD_SEQ(ret, args);
10623
10624 if (flag & VM_CALL_ARGS_SPLAT) {
10625 ADD_INSN(ret, node, dup);
10626 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10627 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10628 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10629 ADD_INSN (ret, node, pop);
10630 }
10631 else {
10632 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10633 }
10634 }
10635 else {
10636 ADD_SEQ(ret, recv);
10637 ADD_SEQ(ret, args);
10638 }
10639 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10640 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10641 ADD_INSN(ret, node, pop);
10642 return COMPILE_OK;
10643}
10644
10645static int
10646compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10647{
10648 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10649 ADD_SEQ(ret, sub);
10650
10651 if (copy) {
10652 /*
10653 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10654 * NEW_LIST(value, loc), loc);
10655 */
10656 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10657 }
10658 else {
10659 /*
10660 * NEW_CALL(fcore, rb_intern("make_shareable"),
10661 * NEW_LIST(value, loc), loc);
10662 */
10663 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10664 }
10665
10666 return COMPILE_OK;
10667}
10668
10669static VALUE
10670node_const_decl_val(const NODE *node)
10671{
10672 VALUE path;
10673 switch (nd_type(node)) {
10674 case NODE_CDECL:
10675 if (RNODE_CDECL(node)->nd_vid) {
10676 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10677 goto end;
10678 }
10679 else {
10680 node = RNODE_CDECL(node)->nd_else;
10681 }
10682 break;
10683 case NODE_COLON2:
10684 break;
10685 case NODE_COLON3:
10686 // ::Const
10687 path = rb_str_new_cstr("::");
10688 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10689 goto end;
10690 default:
10691 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10693 }
10694
10695 path = rb_ary_new();
10696 if (node) {
10697 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10698 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10699 }
10700 if (node && nd_type_p(node, NODE_CONST)) {
10701 // Const::Name
10702 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10703 }
10704 else if (node && nd_type_p(node, NODE_COLON3)) {
10705 // ::Const::Name
10706 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10707 rb_ary_push(path, rb_str_new(0, 0));
10708 }
10709 else {
10710 // expression::Name
10711 rb_ary_push(path, rb_str_new_cstr("..."));
10712 }
10713 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10714 }
10715 end:
10716 path = rb_fstring(path);
10717 return path;
10718}
10719
10720static VALUE
10721const_decl_path(NODE *dest)
10722{
10723 VALUE path = Qnil;
10724 if (!nd_type_p(dest, NODE_CALL)) {
10725 path = node_const_decl_val(dest);
10726 }
10727 return path;
10728}
10729
10730static int
10731compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10732{
10733 /*
10734 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10735 */
10736 VALUE path = const_decl_path(dest);
10737 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10738 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10739 ADD_INSN1(ret, value, putobject, path);
10740 RB_OBJ_WRITTEN(iseq, Qundef, path);
10741 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10742
10743 return COMPILE_OK;
10744}
10745
10746#ifndef SHAREABLE_BARE_EXPRESSION
10747#define SHAREABLE_BARE_EXPRESSION 1
10748#endif
10749
10750static int
10751compile_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)
10752{
10753# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10754 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10755 VALUE lit = Qnil;
10756 DECL_ANCHOR(anchor);
10757
10758 enum node_type type = node ? nd_type(node) : NODE_NIL;
10759 switch (type) {
10760 case NODE_TRUE:
10761 *value_p = Qtrue;
10762 goto compile;
10763 case NODE_FALSE:
10764 *value_p = Qfalse;
10765 goto compile;
10766 case NODE_NIL:
10767 *value_p = Qnil;
10768 goto compile;
10769 case NODE_SYM:
10770 *value_p = rb_node_sym_string_val(node);
10771 goto compile;
10772 case NODE_REGX:
10773 *value_p = rb_node_regx_string_val(node);
10774 goto compile;
10775 case NODE_LINE:
10776 *value_p = rb_node_line_lineno_val(node);
10777 goto compile;
10778 case NODE_INTEGER:
10779 *value_p = rb_node_integer_literal_val(node);
10780 goto compile;
10781 case NODE_FLOAT:
10782 *value_p = rb_node_float_literal_val(node);
10783 goto compile;
10784 case NODE_RATIONAL:
10785 *value_p = rb_node_rational_literal_val(node);
10786 goto compile;
10787 case NODE_IMAGINARY:
10788 *value_p = rb_node_imaginary_literal_val(node);
10789 goto compile;
10790 case NODE_ENCODING:
10791 *value_p = rb_node_encoding_val(node);
10792
10793 compile:
10794 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10795 *shareable_literal_p = 1;
10796 return COMPILE_OK;
10797
10798 case NODE_DSTR:
10799 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10800 if (shareable == rb_parser_shareable_literal) {
10801 /*
10802 * NEW_CALL(node, idUMinus, 0, loc);
10803 *
10804 * -"#{var}"
10805 */
10806 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10807 }
10808 *value_p = Qundef;
10809 *shareable_literal_p = 1;
10810 return COMPILE_OK;
10811
10812 case NODE_STR:{
10813 VALUE lit = rb_node_str_string_val(node);
10814 ADD_INSN1(ret, node, putobject, lit);
10815 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10816 *value_p = lit;
10817 *shareable_literal_p = 1;
10818
10819 return COMPILE_OK;
10820 }
10821
10822 case NODE_FILE:{
10823 VALUE lit = rb_node_file_path_val(node);
10824 ADD_INSN1(ret, node, putobject, lit);
10825 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10826 *value_p = lit;
10827 *shareable_literal_p = 1;
10828
10829 return COMPILE_OK;
10830 }
10831
10832 case NODE_ZLIST:{
10833 VALUE lit = rb_ary_new();
10834 OBJ_FREEZE(lit);
10835 ADD_INSN1(ret, node, putobject, lit);
10836 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10837 *value_p = lit;
10838 *shareable_literal_p = 1;
10839
10840 return COMPILE_OK;
10841 }
10842
10843 case NODE_LIST:{
10844 INIT_ANCHOR(anchor);
10845 lit = rb_ary_new();
10846 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10847 VALUE val;
10848 int shareable_literal_p2;
10849 NODE *elt = RNODE_LIST(n)->nd_head;
10850 if (elt) {
10851 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10852 if (shareable_literal_p2) {
10853 /* noop */
10854 }
10855 else if (RTEST(lit)) {
10856 rb_ary_clear(lit);
10857 lit = Qfalse;
10858 }
10859 }
10860 if (RTEST(lit)) {
10861 if (!UNDEF_P(val)) {
10862 rb_ary_push(lit, val);
10863 }
10864 else {
10865 rb_ary_clear(lit);
10866 lit = Qnil; /* make shareable at runtime */
10867 }
10868 }
10869 }
10870 break;
10871 }
10872 case NODE_HASH:{
10873 if (!RNODE_HASH(node)->nd_brace) {
10874 *value_p = Qundef;
10875 *shareable_literal_p = 0;
10876 return COMPILE_OK;
10877 }
10878 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10879 if (!RNODE_LIST(n)->nd_head) {
10880 // If the hash node have a keyword splat, fall back to the default case.
10881 goto compile_shareable;
10882 }
10883 }
10884
10885 INIT_ANCHOR(anchor);
10886 lit = rb_hash_new();
10887 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10888 VALUE key_val = 0;
10889 VALUE value_val = 0;
10890 int shareable_literal_p2;
10891 NODE *key = RNODE_LIST(n)->nd_head;
10892 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10893 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10894 if (shareable_literal_p2) {
10895 /* noop */
10896 }
10897 else if (RTEST(lit)) {
10898 rb_hash_clear(lit);
10899 lit = Qfalse;
10900 }
10901 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10902 if (shareable_literal_p2) {
10903 /* noop */
10904 }
10905 else if (RTEST(lit)) {
10906 rb_hash_clear(lit);
10907 lit = Qfalse;
10908 }
10909 if (RTEST(lit)) {
10910 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10911 rb_hash_aset(lit, key_val, value_val);
10912 }
10913 else {
10914 rb_hash_clear(lit);
10915 lit = Qnil; /* make shareable at runtime */
10916 }
10917 }
10918 }
10919 break;
10920 }
10921
10922 default:
10923
10924 compile_shareable:
10925 if (shareable == rb_parser_shareable_literal &&
10926 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10927 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10928 *value_p = Qundef;
10929 *shareable_literal_p = 1;
10930 return COMPILE_OK;
10931 }
10932 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10933 *value_p = Qundef;
10934 *shareable_literal_p = 0;
10935 return COMPILE_OK;
10936 }
10937
10938 /* Array or Hash that does not have keyword splat */
10939 if (!lit) {
10940 if (nd_type(node) == NODE_LIST) {
10941 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10942 }
10943 else if (nd_type(node) == NODE_HASH) {
10944 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10947 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10948 }
10949 *value_p = Qundef;
10950 *shareable_literal_p = 0;
10951 ADD_SEQ(ret, anchor);
10952 return COMPILE_OK;
10953 }
10954 if (NIL_P(lit)) {
10955 // if shareable_literal, all elements should have been ensured
10956 // as shareable
10957 if (nd_type(node) == NODE_LIST) {
10958 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10959 }
10960 else if (nd_type(node) == NODE_HASH) {
10961 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10964 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10965 }
10966 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10967 *value_p = Qundef;
10968 *shareable_literal_p = 1;
10969 }
10970 else {
10972 ADD_INSN1(ret, node, putobject, val);
10973 RB_OBJ_WRITTEN(iseq, Qundef, val);
10974 *value_p = val;
10975 *shareable_literal_p = 1;
10976 }
10977
10978 return COMPILE_OK;
10979}
10980
10981static int
10982compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10983{
10984 int literal_p = 0;
10985 VALUE val;
10986 DECL_ANCHOR(anchor);
10987 INIT_ANCHOR(anchor);
10988
10989 switch (shareable) {
10990 case rb_parser_shareable_none:
10991 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10992 return COMPILE_OK;
10993
10994 case rb_parser_shareable_literal:
10995 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10996 ADD_SEQ(ret, anchor);
10997 return COMPILE_OK;
10998
10999 case rb_parser_shareable_copy:
11000 case rb_parser_shareable_everything:
11001 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
11002 if (!literal_p) {
11003 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
11004 }
11005 else {
11006 ADD_SEQ(ret, anchor);
11007 }
11008 return COMPILE_OK;
11009 default:
11010 rb_bug("unexpected rb_parser_shareability: %d", shareable);
11011 }
11012}
11013
11014static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
11022static int
11023iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
11024{
11025 if (node == 0) {
11026 if (!popped) {
11027 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11028 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11029 debugs("node: NODE_NIL(implicit)\n");
11030 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11031 }
11032 return COMPILE_OK;
11033 }
11034 return iseq_compile_each0(iseq, ret, node, popped);
11035}
11036
11037static int
11038iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11039{
11040 const int line = (int)nd_line(node);
11041 const enum node_type type = nd_type(node);
11042 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11043
11044 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11045 /* ignore */
11046 }
11047 else {
11048 if (nd_fl_newline(node)) {
11049 int event = RUBY_EVENT_LINE;
11050 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11051 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11052 event |= RUBY_EVENT_COVERAGE_LINE;
11053 }
11054 ADD_TRACE(ret, event);
11055 }
11056 }
11057
11058 debug_node_start(node);
11059#undef BEFORE_RETURN
11060#define BEFORE_RETURN debug_node_end()
11061
11062 switch (type) {
11063 case NODE_BLOCK:
11064 CHECK(compile_block(iseq, ret, node, popped));
11065 break;
11066 case NODE_IF:
11067 case NODE_UNLESS:
11068 CHECK(compile_if(iseq, ret, node, popped, type));
11069 break;
11070 case NODE_CASE:
11071 CHECK(compile_case(iseq, ret, node, popped));
11072 break;
11073 case NODE_CASE2:
11074 CHECK(compile_case2(iseq, ret, node, popped));
11075 break;
11076 case NODE_CASE3:
11077 CHECK(compile_case3(iseq, ret, node, popped));
11078 break;
11079 case NODE_WHILE:
11080 case NODE_UNTIL:
11081 CHECK(compile_loop(iseq, ret, node, popped, type));
11082 break;
11083 case NODE_FOR:
11084 case NODE_ITER:
11085 CHECK(compile_iter(iseq, ret, node, popped));
11086 break;
11087 case NODE_FOR_MASGN:
11088 CHECK(compile_for_masgn(iseq, ret, node, popped));
11089 break;
11090 case NODE_BREAK:
11091 CHECK(compile_break(iseq, ret, node, popped));
11092 break;
11093 case NODE_NEXT:
11094 CHECK(compile_next(iseq, ret, node, popped));
11095 break;
11096 case NODE_REDO:
11097 CHECK(compile_redo(iseq, ret, node, popped));
11098 break;
11099 case NODE_RETRY:
11100 CHECK(compile_retry(iseq, ret, node, popped));
11101 break;
11102 case NODE_BEGIN:{
11103 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11104 break;
11105 }
11106 case NODE_RESCUE:
11107 CHECK(compile_rescue(iseq, ret, node, popped));
11108 break;
11109 case NODE_RESBODY:
11110 CHECK(compile_resbody(iseq, ret, node, popped));
11111 break;
11112 case NODE_ENSURE:
11113 CHECK(compile_ensure(iseq, ret, node, popped));
11114 break;
11115
11116 case NODE_AND:
11117 case NODE_OR:{
11118 LABEL *end_label = NEW_LABEL(line);
11119 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
11120 if (!popped) {
11121 ADD_INSN(ret, node, dup);
11122 }
11123 if (type == NODE_AND) {
11124 ADD_INSNL(ret, node, branchunless, end_label);
11125 }
11126 else {
11127 ADD_INSNL(ret, node, branchif, end_label);
11128 }
11129 if (!popped) {
11130 ADD_INSN(ret, node, pop);
11131 }
11132 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
11133 ADD_LABEL(ret, end_label);
11134 break;
11135 }
11136
11137 case NODE_MASGN:{
11138 compile_massign(iseq, ret, node, popped);
11139 break;
11140 }
11141
11142 case NODE_LASGN:{
11143 ID id = RNODE_LASGN(node)->nd_vid;
11144 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11145
11146 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11147 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11148
11149 if (!popped) {
11150 ADD_INSN(ret, node, dup);
11151 }
11152 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11153 break;
11154 }
11155 case NODE_DASGN: {
11156 int idx, lv, ls;
11157 ID id = RNODE_DASGN(node)->nd_vid;
11158 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11159 debugi("dassn id", rb_id2str(id) ? id : '*');
11160
11161 if (!popped) {
11162 ADD_INSN(ret, node, dup);
11163 }
11164
11165 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11166
11167 if (idx < 0) {
11168 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11169 rb_id2str(id));
11170 goto ng;
11171 }
11172 ADD_SETLOCAL(ret, node, ls - idx, lv);
11173 break;
11174 }
11175 case NODE_GASGN:{
11176 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11177
11178 if (!popped) {
11179 ADD_INSN(ret, node, dup);
11180 }
11181 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11182 break;
11183 }
11184 case NODE_IASGN:{
11185 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11186 if (!popped) {
11187 ADD_INSN(ret, node, dup);
11188 }
11189 ADD_INSN2(ret, node, setinstancevariable,
11190 ID2SYM(RNODE_IASGN(node)->nd_vid),
11191 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11192 break;
11193 }
11194 case NODE_CDECL:{
11195 if (RNODE_CDECL(node)->nd_vid) {
11196 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11197
11198 if (!popped) {
11199 ADD_INSN(ret, node, dup);
11200 }
11201
11202 ADD_INSN1(ret, node, putspecialobject,
11203 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11204 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11205 }
11206 else {
11207 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11208 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11209 ADD_INSN(ret, node, swap);
11210
11211 if (!popped) {
11212 ADD_INSN1(ret, node, topn, INT2FIX(1));
11213 ADD_INSN(ret, node, swap);
11214 }
11215
11216 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11217 }
11218 break;
11219 }
11220 case NODE_CVASGN:{
11221 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11222 if (!popped) {
11223 ADD_INSN(ret, node, dup);
11224 }
11225 ADD_INSN2(ret, node, setclassvariable,
11226 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11227 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11228 break;
11229 }
11230 case NODE_OP_ASGN1:
11231 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11232 break;
11233 case NODE_OP_ASGN2:
11234 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11235 break;
11236 case NODE_OP_CDECL:
11237 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11238 break;
11239 case NODE_OP_ASGN_AND:
11240 case NODE_OP_ASGN_OR:
11241 CHECK(compile_op_log(iseq, ret, node, popped, type));
11242 break;
11243 case NODE_CALL: /* obj.foo */
11244 case NODE_OPCALL: /* foo[] */
11245 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11246 break;
11247 }
11248 case NODE_QCALL: /* obj&.foo */
11249 case NODE_FCALL: /* foo() */
11250 case NODE_VCALL: /* foo (variable or call) */
11251 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11252 goto ng;
11253 }
11254 break;
11255 case NODE_SUPER:
11256 case NODE_ZSUPER:
11257 CHECK(compile_super(iseq, ret, node, popped, type));
11258 break;
11259 case NODE_LIST:{
11260 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11261 break;
11262 }
11263 case NODE_ZLIST:{
11264 if (!popped) {
11265 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11266 }
11267 break;
11268 }
11269 case NODE_HASH:
11270 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11271 break;
11272 case NODE_RETURN:
11273 CHECK(compile_return(iseq, ret, node, popped));
11274 break;
11275 case NODE_YIELD:
11276 CHECK(compile_yield(iseq, ret, node, popped));
11277 break;
11278 case NODE_LVAR:{
11279 if (!popped) {
11280 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11281 }
11282 break;
11283 }
11284 case NODE_DVAR:{
11285 int lv, idx, ls;
11286 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11287 if (!popped) {
11288 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11289 if (idx < 0) {
11290 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11291 rb_id2str(RNODE_DVAR(node)->nd_vid));
11292 goto ng;
11293 }
11294 ADD_GETLOCAL(ret, node, ls - idx, lv);
11295 }
11296 break;
11297 }
11298 case NODE_GVAR:{
11299 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11300 if (popped) {
11301 ADD_INSN(ret, node, pop);
11302 }
11303 break;
11304 }
11305 case NODE_IVAR:{
11306 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11307 if (!popped) {
11308 ADD_INSN2(ret, node, getinstancevariable,
11309 ID2SYM(RNODE_IVAR(node)->nd_vid),
11310 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11311 }
11312 break;
11313 }
11314 case NODE_CONST:{
11315 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11316
11317 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11318 body->ic_size++;
11319 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11321 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11322 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11323 }
11324 else {
11325 ADD_INSN(ret, node, putnil);
11326 ADD_INSN1(ret, node, putobject, Qtrue);
11327 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11328 }
11329
11330 if (popped) {
11331 ADD_INSN(ret, node, pop);
11332 }
11333 break;
11334 }
11335 case NODE_CVAR:{
11336 if (!popped) {
11337 ADD_INSN2(ret, node, getclassvariable,
11338 ID2SYM(RNODE_CVAR(node)->nd_vid),
11339 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11340 }
11341 break;
11342 }
11343 case NODE_NTH_REF:{
11344 if (!popped) {
11345 if (!RNODE_NTH_REF(node)->nd_nth) {
11346 ADD_INSN(ret, node, putnil);
11347 break;
11348 }
11349 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11350 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11351 }
11352 break;
11353 }
11354 case NODE_BACK_REF:{
11355 if (!popped) {
11356 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11357 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11358 }
11359 break;
11360 }
11361 case NODE_MATCH:
11362 case NODE_MATCH2:
11363 case NODE_MATCH3:
11364 CHECK(compile_match(iseq, ret, node, popped, type));
11365 break;
11366 case NODE_SYM:{
11367 if (!popped) {
11368 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11369 }
11370 break;
11371 }
11372 case NODE_LINE:{
11373 if (!popped) {
11374 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11375 }
11376 break;
11377 }
11378 case NODE_ENCODING:{
11379 if (!popped) {
11380 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11381 }
11382 break;
11383 }
11384 case NODE_INTEGER:{
11385 VALUE lit = rb_node_integer_literal_val(node);
11386 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11387 debugp_param("integer", lit);
11388 if (!popped) {
11389 ADD_INSN1(ret, node, putobject, lit);
11390 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11391 }
11392 break;
11393 }
11394 case NODE_FLOAT:{
11395 VALUE lit = rb_node_float_literal_val(node);
11396 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11397 debugp_param("float", lit);
11398 if (!popped) {
11399 ADD_INSN1(ret, node, putobject, lit);
11400 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11401 }
11402 break;
11403 }
11404 case NODE_RATIONAL:{
11405 VALUE lit = rb_node_rational_literal_val(node);
11407 debugp_param("rational", lit);
11408 if (!popped) {
11409 ADD_INSN1(ret, node, putobject, lit);
11410 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11411 }
11412 break;
11413 }
11414 case NODE_IMAGINARY:{
11415 VALUE lit = rb_node_imaginary_literal_val(node);
11417 debugp_param("imaginary", lit);
11418 if (!popped) {
11419 ADD_INSN1(ret, node, putobject, lit);
11420 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11421 }
11422 break;
11423 }
11424 case NODE_FILE:
11425 case NODE_STR:{
11426 debugp_param("nd_lit", get_string_value(node));
11427 if (!popped) {
11428 VALUE lit = get_string_value(node);
11429 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11430 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11431 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11432 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11434 }
11435 switch (option->frozen_string_literal) {
11436 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11437 ADD_INSN1(ret, node, dupchilledstring, lit);
11438 break;
11439 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11440 ADD_INSN1(ret, node, dupstring, lit);
11441 break;
11442 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11443 ADD_INSN1(ret, node, putobject, lit);
11444 break;
11445 default:
11446 rb_bug("invalid frozen_string_literal");
11447 }
11448 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11449 }
11450 break;
11451 }
11452 case NODE_DSTR:{
11453 compile_dstr(iseq, ret, node);
11454
11455 if (popped) {
11456 ADD_INSN(ret, node, pop);
11457 }
11458 break;
11459 }
11460 case NODE_XSTR:{
11461 ADD_CALL_RECEIVER(ret, node);
11462 VALUE str = rb_node_str_string_val(node);
11463 ADD_INSN1(ret, node, putobject, str);
11464 RB_OBJ_WRITTEN(iseq, Qundef, str);
11465 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11466
11467 if (popped) {
11468 ADD_INSN(ret, node, pop);
11469 }
11470 break;
11471 }
11472 case NODE_DXSTR:{
11473 ADD_CALL_RECEIVER(ret, node);
11474 compile_dstr(iseq, ret, node);
11475 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11476
11477 if (popped) {
11478 ADD_INSN(ret, node, pop);
11479 }
11480 break;
11481 }
11482 case NODE_EVSTR:
11483 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11484 break;
11485 case NODE_REGX:{
11486 if (!popped) {
11487 VALUE lit = rb_node_regx_string_val(node);
11489 ADD_INSN1(ret, node, putobject, lit);
11490 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11491 }
11492 break;
11493 }
11494 case NODE_DREGX:
11495 compile_dregx(iseq, ret, node, popped);
11496 break;
11497 case NODE_ONCE:{
11498 int ic_index = body->ise_size++;
11499 const rb_iseq_t *block_iseq;
11500 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11501
11502 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11503 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11504
11505 if (popped) {
11506 ADD_INSN(ret, node, pop);
11507 }
11508 break;
11509 }
11510 case NODE_ARGSCAT:{
11511 if (popped) {
11512 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11513 ADD_INSN1(ret, node, splatarray, Qfalse);
11514 ADD_INSN(ret, node, pop);
11515 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11516 ADD_INSN1(ret, node, splatarray, Qfalse);
11517 ADD_INSN(ret, node, pop);
11518 }
11519 else {
11520 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11521 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11522 if (nd_type_p(body_node, NODE_LIST)) {
11523 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11524 }
11525 else {
11526 CHECK(COMPILE(ret, "argscat body", body_node));
11527 ADD_INSN(ret, node, concattoarray);
11528 }
11529 }
11530 break;
11531 }
11532 case NODE_ARGSPUSH:{
11533 if (popped) {
11534 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11535 ADD_INSN1(ret, node, splatarray, Qfalse);
11536 ADD_INSN(ret, node, pop);
11537 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11538 }
11539 else {
11540 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11541 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11542 if (keyword_node_p(body_node)) {
11543 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11544 ADD_INSN(ret, node, pushtoarraykwsplat);
11545 }
11546 else if (static_literal_node_p(body_node, iseq, false)) {
11547 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11548 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11549 }
11550 else {
11551 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11552 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11553 }
11554 }
11555 break;
11556 }
11557 case NODE_SPLAT:{
11558 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11559 ADD_INSN1(ret, node, splatarray, Qtrue);
11560
11561 if (popped) {
11562 ADD_INSN(ret, node, pop);
11563 }
11564 break;
11565 }
11566 case NODE_DEFN:{
11567 ID mid = RNODE_DEFN(node)->nd_mid;
11568 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11569 rb_id2str(mid),
11570 ISEQ_TYPE_METHOD, line);
11571
11572 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11573 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11574 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11575
11576 if (!popped) {
11577 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11578 }
11579
11580 break;
11581 }
11582 case NODE_DEFS:{
11583 ID mid = RNODE_DEFS(node)->nd_mid;
11584 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11585 rb_id2str(mid),
11586 ISEQ_TYPE_METHOD, line);
11587
11588 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11589 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11590 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11591 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11592
11593 if (!popped) {
11594 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11595 }
11596 break;
11597 }
11598 case NODE_ALIAS:{
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, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11602 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11603 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11604
11605 if (popped) {
11606 ADD_INSN(ret, node, pop);
11607 }
11608 break;
11609 }
11610 case NODE_VALIAS:{
11611 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11612 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11613 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11614 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11615
11616 if (popped) {
11617 ADD_INSN(ret, node, pop);
11618 }
11619 break;
11620 }
11621 case NODE_UNDEF:{
11622 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11623
11624 for (long i = 0; i < ary->len; i++) {
11625 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11626 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11627 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11628 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11629
11630 if (i < ary->len - 1) {
11631 ADD_INSN(ret, node, pop);
11632 }
11633 }
11634
11635 if (popped) {
11636 ADD_INSN(ret, node, pop);
11637 }
11638 break;
11639 }
11640 case NODE_CLASS:{
11641 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11642 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11643 ISEQ_TYPE_CLASS, line);
11644 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11645 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11646 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11647
11648 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11649 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11650 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11651
11652 if (popped) {
11653 ADD_INSN(ret, node, pop);
11654 }
11655 break;
11656 }
11657 case NODE_MODULE:{
11658 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11659 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11660 ISEQ_TYPE_CLASS, line);
11661 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11662 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11663
11664 ADD_INSN (ret, node, putnil); /* dummy */
11665 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11666 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11667
11668 if (popped) {
11669 ADD_INSN(ret, node, pop);
11670 }
11671 break;
11672 }
11673 case NODE_SCLASS:{
11674 ID singletonclass;
11675 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11676 ISEQ_TYPE_CLASS, line);
11677
11678 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11679 ADD_INSN (ret, node, putnil);
11680 CONST_ID(singletonclass, "singletonclass");
11681
11682 /* `class << self` in a class body and `class << Foo` (constant
11683 receiver) are stable. All other forms are potentially dynamic. */
11684 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11685 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11686 if (!(nd_type_p(recv, NODE_SELF) &&
11687 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11688 !cpath_const_p(recv)) {
11689 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11690 }
11691
11692 ADD_INSN3(ret, node, defineclass,
11693 ID2SYM(singletonclass), singleton_class,
11694 INT2FIX(sclass_flags));
11695 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11696
11697 if (popped) {
11698 ADD_INSN(ret, node, pop);
11699 }
11700 break;
11701 }
11702 case NODE_COLON2:
11703 CHECK(compile_colon2(iseq, ret, node, popped));
11704 break;
11705 case NODE_COLON3:
11706 CHECK(compile_colon3(iseq, ret, node, popped));
11707 break;
11708 case NODE_DOT2:
11709 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11710 break;
11711 case NODE_DOT3:
11712 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11713 break;
11714 case NODE_FLIP2:
11715 case NODE_FLIP3:{
11716 LABEL *lend = NEW_LABEL(line);
11717 LABEL *ltrue = NEW_LABEL(line);
11718 LABEL *lfalse = NEW_LABEL(line);
11719 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11720 ltrue, lfalse));
11721 ADD_LABEL(ret, ltrue);
11722 ADD_INSN1(ret, node, putobject, Qtrue);
11723 ADD_INSNL(ret, node, jump, lend);
11724 ADD_LABEL(ret, lfalse);
11725 ADD_INSN1(ret, node, putobject, Qfalse);
11726 ADD_LABEL(ret, lend);
11727 break;
11728 }
11729 case NODE_SELF:{
11730 if (!popped) {
11731 ADD_INSN(ret, node, putself);
11732 }
11733 break;
11734 }
11735 case NODE_NIL:{
11736 if (!popped) {
11737 ADD_INSN(ret, node, putnil);
11738 }
11739 break;
11740 }
11741 case NODE_TRUE:{
11742 if (!popped) {
11743 ADD_INSN1(ret, node, putobject, Qtrue);
11744 }
11745 break;
11746 }
11747 case NODE_FALSE:{
11748 if (!popped) {
11749 ADD_INSN1(ret, node, putobject, Qfalse);
11750 }
11751 break;
11752 }
11753 case NODE_ERRINFO:
11754 CHECK(compile_errinfo(iseq, ret, node, popped));
11755 break;
11756 case NODE_DEFINED:
11757 if (!popped) {
11758 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11759 }
11760 break;
11761 case NODE_POSTEXE:{
11762 /* compiled to:
11763 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11764 */
11765 int is_index = body->ise_size++;
11767 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11768 const rb_iseq_t *once_iseq =
11769 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11770
11771 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11772 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11773
11774 if (popped) {
11775 ADD_INSN(ret, node, pop);
11776 }
11777 break;
11778 }
11779 case NODE_KW_ARG:
11780 CHECK(compile_kw_arg(iseq, ret, node, popped));
11781 break;
11782 case NODE_DSYM:{
11783 compile_dstr(iseq, ret, node);
11784 if (!popped) {
11785 ADD_INSN(ret, node, intern);
11786 }
11787 else {
11788 ADD_INSN(ret, node, pop);
11789 }
11790 break;
11791 }
11792 case NODE_ATTRASGN:
11793 CHECK(compile_attrasgn(iseq, ret, node, popped));
11794 break;
11795 case NODE_LAMBDA:{
11796 /* compile same as lambda{...} */
11797 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11798 VALUE argc = INT2FIX(0);
11799
11800 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11801 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11802 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11803
11804 if (popped) {
11805 ADD_INSN(ret, node, pop);
11806 }
11807 break;
11808 }
11809 default:
11810 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11811 ng:
11812 debug_node_end();
11813 return COMPILE_NG;
11814 }
11815
11816 debug_node_end();
11817 return COMPILE_OK;
11818}
11819
11820/***************************/
11821/* instruction information */
11822/***************************/
11823
11824static int
11825insn_data_length(INSN *iobj)
11826{
11827 return insn_len(iobj->insn_id);
11828}
11829
11830static int
11831calc_sp_depth(int depth, INSN *insn)
11832{
11833 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11834}
11835
11836static VALUE
11837opobj_inspect(VALUE obj)
11838{
11839 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11840 switch (BUILTIN_TYPE(obj)) {
11841 case T_STRING:
11842 obj = rb_str_resurrect(obj);
11843 break;
11844 case T_ARRAY:
11845 obj = rb_ary_resurrect(obj);
11846 break;
11847 default:
11848 break;
11849 }
11850 }
11851 return rb_inspect(obj);
11852}
11853
11854
11855
11856static VALUE
11857insn_data_to_s_detail(INSN *iobj)
11858{
11859 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11860
11861 if (iobj->operands) {
11862 const char *types = insn_op_types(iobj->insn_id);
11863 int j;
11864
11865 for (j = 0; types[j]; j++) {
11866 char type = types[j];
11867
11868 switch (type) {
11869 case TS_OFFSET: /* label(destination position) */
11870 {
11871 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11872 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11873 break;
11874 }
11875 break;
11876 case TS_ISEQ: /* iseq */
11877 {
11878 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11879 VALUE val = Qnil;
11880 if (0 && iseq) { /* TODO: invalidate now */
11881 val = (VALUE)iseq;
11882 }
11883 rb_str_concat(str, opobj_inspect(val));
11884 }
11885 break;
11886 case TS_LINDEX:
11887 case TS_NUM: /* ulong */
11888 case TS_VALUE: /* VALUE */
11889 {
11890 VALUE v = OPERAND_AT(iobj, j);
11891 if (!CLASS_OF(v))
11892 rb_str_cat2(str, "<hidden>");
11893 else {
11894 rb_str_concat(str, opobj_inspect(v));
11895 }
11896 break;
11897 }
11898 case TS_ID: /* ID */
11899 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11900 break;
11901 case TS_IC: /* inline cache */
11902 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11903 break;
11904 case TS_IVC: /* inline ivar cache */
11905 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11906 break;
11907 case TS_ICVARC: /* inline cvar cache */
11908 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11909 break;
11910 case TS_ISE: /* inline storage entry */
11911 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11912 break;
11913 case TS_CALLDATA: /* we store these as call infos at compile time */
11914 {
11915 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11916 rb_str_cat2(str, "<calldata:");
11917 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
11918 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11919 break;
11920 }
11921 case TS_CDHASH: /* case/when condition cache */
11922 rb_str_cat2(str, "<ch>");
11923 break;
11924 case TS_FUNCPTR:
11925 {
11926 void *func = (void *)OPERAND_AT(iobj, j);
11927#ifdef HAVE_DLADDR
11928 Dl_info info;
11929 if (dladdr(func, &info) && info.dli_sname) {
11930 rb_str_cat2(str, info.dli_sname);
11931 break;
11932 }
11933#endif
11934 rb_str_catf(str, "<%p>", func);
11935 }
11936 break;
11937 case TS_BUILTIN:
11938 rb_str_cat2(str, "<TS_BUILTIN>");
11939 break;
11940 default:{
11941 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11942 }
11943 }
11944 if (types[j + 1]) {
11945 rb_str_cat2(str, ", ");
11946 }
11947 }
11948 }
11949 return str;
11950}
11951
11952static void
11953dump_disasm_list(const LINK_ELEMENT *link)
11954{
11955 dump_disasm_list_with_cursor(link, NULL, NULL);
11956}
11957
11958static void
11959dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11960{
11961 int pos = 0;
11962 INSN *iobj;
11963 LABEL *lobj;
11964 VALUE str;
11965
11966 printf("-- raw disasm--------\n");
11967
11968 while (link) {
11969 if (curr) printf(curr == link ? "*" : " ");
11970 switch (link->type) {
11971 case ISEQ_ELEMENT_INSN:
11972 {
11973 iobj = (INSN *)link;
11974 str = insn_data_to_s_detail(iobj);
11975 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11976 pos += insn_data_length(iobj);
11977 break;
11978 }
11979 case ISEQ_ELEMENT_LABEL:
11980 {
11981 lobj = (LABEL *)link;
11982 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11983 dest == lobj ? " <---" : "");
11984 break;
11985 }
11986 case ISEQ_ELEMENT_TRACE:
11987 {
11988 TRACE *trace = (TRACE *)link;
11989 printf(" trace: %0x\n", trace->event);
11990 break;
11991 }
11992 case ISEQ_ELEMENT_ADJUST:
11993 {
11994 ADJUST *adjust = (ADJUST *)link;
11995 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11996 break;
11997 }
11998 default:
11999 /* ignore */
12000 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
12001 }
12002 link = link->next;
12003 }
12004 printf("---------------------\n");
12005 fflush(stdout);
12006}
12007
12008int
12009rb_insn_len(VALUE insn)
12010{
12011 return insn_len(insn);
12012}
12013
12014const char *
12015rb_insns_name(int i)
12016{
12017 return insn_name(i);
12018}
12019
12020VALUE
12021rb_insns_name_array(void)
12022{
12023 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
12024 int i;
12025 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12026 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12027 }
12028 return rb_ary_freeze(ary);
12029}
12030
12031static LABEL *
12032register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12033{
12034 LABEL *label = 0;
12035 st_data_t tmp;
12036 obj = rb_to_symbol_type(obj);
12037
12038 if (st_lookup(labels_table, obj, &tmp) == 0) {
12039 label = NEW_LABEL(0);
12040 st_insert(labels_table, obj, (st_data_t)label);
12041 }
12042 else {
12043 label = (LABEL *)tmp;
12044 }
12045 LABEL_REF(label);
12046 return label;
12047}
12048
12049static VALUE
12050get_exception_sym2type(VALUE sym)
12051{
12052 static VALUE symRescue, symEnsure, symRetry;
12053 static VALUE symBreak, symRedo, symNext;
12054
12055 if (symRescue == 0) {
12056 symRescue = ID2SYM(rb_intern_const("rescue"));
12057 symEnsure = ID2SYM(rb_intern_const("ensure"));
12058 symRetry = ID2SYM(rb_intern_const("retry"));
12059 symBreak = ID2SYM(rb_intern_const("break"));
12060 symRedo = ID2SYM(rb_intern_const("redo"));
12061 symNext = ID2SYM(rb_intern_const("next"));
12062 }
12063
12064 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12065 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12066 if (sym == symRetry) return CATCH_TYPE_RETRY;
12067 if (sym == symBreak) return CATCH_TYPE_BREAK;
12068 if (sym == symRedo) return CATCH_TYPE_REDO;
12069 if (sym == symNext) return CATCH_TYPE_NEXT;
12070 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12071 return 0;
12072}
12073
12074static int
12075iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12076 VALUE exception)
12077{
12078 int i;
12079
12080 for (i=0; i<RARRAY_LEN(exception); i++) {
12081 const rb_iseq_t *eiseq;
12082 VALUE v, type;
12083 LABEL *lstart, *lend, *lcont;
12084 unsigned int sp;
12085
12086 v = rb_to_array_type(RARRAY_AREF(exception, i));
12087 if (RARRAY_LEN(v) != 6) {
12088 rb_raise(rb_eSyntaxError, "wrong exception entry");
12089 }
12090 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12091 if (NIL_P(RARRAY_AREF(v, 1))) {
12092 eiseq = NULL;
12093 }
12094 else {
12095 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12096 }
12097
12098 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12099 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12100 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12101 sp = NUM2UINT(RARRAY_AREF(v, 5));
12102
12103 /* TODO: Dirty Hack! Fix me */
12104 if (type == CATCH_TYPE_RESCUE ||
12105 type == CATCH_TYPE_BREAK ||
12106 type == CATCH_TYPE_NEXT) {
12107 ++sp;
12108 }
12109
12110 lcont->sp = sp;
12111
12112 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12113
12114 RB_GC_GUARD(v);
12115 }
12116 return COMPILE_OK;
12117}
12118
12119static struct st_table *
12120insn_make_insn_table(void)
12121{
12122 struct st_table *table;
12123 int i;
12124 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12125
12126 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12127 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12128 }
12129
12130 return table;
12131}
12132
12133static const rb_iseq_t *
12134iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12135{
12136 VALUE iseqw;
12137 const rb_iseq_t *loaded_iseq;
12138
12139 if (RB_TYPE_P(op, T_ARRAY)) {
12140 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12141 }
12142 else if (CLASS_OF(op) == rb_cISeq) {
12143 iseqw = op;
12144 }
12145 else {
12146 rb_raise(rb_eSyntaxError, "ISEQ is required");
12147 }
12148
12149 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12150 return loaded_iseq;
12151}
12152
12153static VALUE
12154iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12155{
12156 ID mid = 0;
12157 int orig_argc = 0;
12158 unsigned int flag = 0;
12159 struct rb_callinfo_kwarg *kw_arg = 0;
12160
12161 if (!NIL_P(op)) {
12162 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12163 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12164 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12165 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12166
12167 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12168 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12169 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12170
12171 if (!NIL_P(vkw_arg)) {
12172 int i;
12173 int len = RARRAY_LENINT(vkw_arg);
12174 size_t n = rb_callinfo_kwarg_bytes(len);
12175
12176 kw_arg = xmalloc(n);
12177 kw_arg->references = 0;
12178 kw_arg->keyword_len = len;
12179 for (i = 0; i < len; i++) {
12180 VALUE kw = RARRAY_AREF(vkw_arg, i);
12181 SYM2ID(kw); /* make immortal */
12182 kw_arg->keywords[i] = kw;
12183 }
12184 }
12185 }
12186
12187 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12188 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12189 return (VALUE)ci;
12190}
12191
12192static rb_event_flag_t
12193event_name_to_flag(VALUE sym)
12194{
12195#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12196 CHECK_EVENT(RUBY_EVENT_LINE);
12197 CHECK_EVENT(RUBY_EVENT_CLASS);
12198 CHECK_EVENT(RUBY_EVENT_END);
12199 CHECK_EVENT(RUBY_EVENT_CALL);
12200 CHECK_EVENT(RUBY_EVENT_RETURN);
12201 CHECK_EVENT(RUBY_EVENT_B_CALL);
12202 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12203 CHECK_EVENT(RUBY_EVENT_RESCUE);
12204#undef CHECK_EVENT
12205 return RUBY_EVENT_NONE;
12206}
12207
12208static int
12209iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12210 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12211{
12212 /* TODO: body should be frozen */
12213 long i, len = RARRAY_LEN(body);
12214 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12215 int j;
12216 int line_no = 0, node_id = -1, insn_idx = 0;
12217 int ret = COMPILE_OK;
12218
12219 /*
12220 * index -> LABEL *label
12221 */
12222 static struct st_table *insn_table;
12223
12224 if (insn_table == 0) {
12225 insn_table = insn_make_insn_table();
12226 }
12227
12228 for (i=0; i<len; i++) {
12229 VALUE obj = RARRAY_AREF(body, i);
12230
12231 if (SYMBOL_P(obj)) {
12232 rb_event_flag_t event;
12233 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12234 ADD_TRACE(anchor, event);
12235 }
12236 else {
12237 LABEL *label = register_label(iseq, labels_table, obj);
12238 ADD_LABEL(anchor, label);
12239 }
12240 }
12241 else if (FIXNUM_P(obj)) {
12242 line_no = NUM2INT(obj);
12243 }
12244 else if (RB_TYPE_P(obj, T_ARRAY)) {
12245 VALUE *argv = 0;
12246 int argc = RARRAY_LENINT(obj) - 1;
12247 st_data_t insn_id;
12248 VALUE insn;
12249
12250 if (node_ids) {
12251 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12252 }
12253
12254 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12255 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12256 /* TODO: exception */
12257 COMPILE_ERROR(iseq, line_no,
12258 "unknown instruction: %+"PRIsVALUE, insn);
12259 ret = COMPILE_NG;
12260 break;
12261 }
12262
12263 if (argc != insn_len((VALUE)insn_id)-1) {
12264 COMPILE_ERROR(iseq, line_no,
12265 "operand size mismatch");
12266 ret = COMPILE_NG;
12267 break;
12268 }
12269
12270 if (argc > 0) {
12271 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12272
12273 // add element before operand setup to make GC root
12274 ADD_ELEM(anchor,
12275 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12276 (enum ruby_vminsn_type)insn_id, argc, argv));
12277
12278 for (j=0; j<argc; j++) {
12279 VALUE op = rb_ary_entry(obj, j+1);
12280 switch (insn_op_type((VALUE)insn_id, j)) {
12281 case TS_OFFSET: {
12282 LABEL *label = register_label(iseq, labels_table, op);
12283 argv[j] = (VALUE)label;
12284 break;
12285 }
12286 case TS_LINDEX:
12287 case TS_NUM:
12288 (void)NUM2INT(op);
12289 argv[j] = op;
12290 break;
12291 case TS_VALUE:
12292 argv[j] = op;
12293 RB_OBJ_WRITTEN(iseq, Qundef, op);
12294 break;
12295 case TS_ISEQ:
12296 {
12297 if (op != Qnil) {
12298 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12299 argv[j] = v;
12300 RB_OBJ_WRITTEN(iseq, Qundef, v);
12301 }
12302 else {
12303 argv[j] = 0;
12304 }
12305 }
12306 break;
12307 case TS_ISE:
12308 argv[j] = op;
12309 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12310 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12311 }
12312 break;
12313 case TS_IC:
12314 {
12315 VALUE segments = rb_ary_new();
12316 op = rb_to_array_type(op);
12317
12318 for (int i = 0; i < RARRAY_LEN(op); i++) {
12319 VALUE sym = RARRAY_AREF(op, i);
12320 sym = rb_to_symbol_type(sym);
12321 rb_ary_push(segments, sym);
12322 }
12323
12324 RB_GC_GUARD(op);
12325 argv[j] = segments;
12326 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12327 ISEQ_BODY(iseq)->ic_size++;
12328 }
12329 break;
12330 case TS_IVC: /* inline ivar cache */
12331 argv[j] = op;
12332 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12333 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12334 }
12335 break;
12336 case TS_ICVARC: /* inline cvar cache */
12337 argv[j] = op;
12338 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12339 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12340 }
12341 break;
12342 case TS_CALLDATA:
12343 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12344 break;
12345 case TS_ID:
12346 argv[j] = rb_to_symbol_type(op);
12347 break;
12348 case TS_CDHASH:
12349 {
12350 int i;
12351 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12352
12353 op = rb_to_array_type(op);
12354 for (i=0; i<RARRAY_LEN(op); i+=2) {
12355 VALUE key = RARRAY_AREF(op, i);
12356 VALUE sym = RARRAY_AREF(op, i+1);
12357 LABEL *label =
12358 register_label(iseq, labels_table, sym);
12359 cdhash_aset(map, key, (VALUE)label);
12360 }
12361 RB_GC_GUARD(op);
12362 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12363 argv[j] = map;
12364 RB_OBJ_WRITTEN(iseq, Qundef, map);
12365 }
12366 break;
12367 case TS_FUNCPTR:
12368 {
12369#if SIZEOF_VALUE <= SIZEOF_LONG
12370 long funcptr = NUM2LONG(op);
12371#else
12372 LONG_LONG funcptr = NUM2LL(op);
12373#endif
12374 argv[j] = (VALUE)funcptr;
12375 }
12376 break;
12377 default:
12378 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12379 }
12380 }
12381 }
12382 else {
12383 ADD_ELEM(anchor,
12384 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12385 (enum ruby_vminsn_type)insn_id, argc, NULL));
12386 }
12387 }
12388 else {
12389 rb_raise(rb_eTypeError, "unexpected object for instruction");
12390 }
12391 }
12392 RTYPEDDATA_DATA(labels_wrapper) = 0;
12393 RB_GC_GUARD(labels_wrapper);
12394 validate_labels(iseq, labels_table);
12395 if (!ret) return ret;
12396 return iseq_setup(iseq, anchor);
12397}
12398
12399#define CHECK_ARRAY(v) rb_to_array_type(v)
12400#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12401
12402static int
12403int_param(int *dst, VALUE param, VALUE sym)
12404{
12405 VALUE val = rb_hash_aref(param, sym);
12406 if (FIXNUM_P(val)) {
12407 *dst = FIX2INT(val);
12408 return TRUE;
12409 }
12410 else if (!NIL_P(val)) {
12411 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12412 sym, val);
12413 }
12414 return FALSE;
12415}
12416
12417static const struct rb_iseq_param_keyword *
12418iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12419{
12420 int i, j;
12421 int len = RARRAY_LENINT(keywords);
12422 int default_len;
12423 VALUE key, sym, default_val;
12424 VALUE *dvs;
12425 ID *ids;
12426 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12427
12428 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12429
12430 keyword->num = len;
12431#define SYM(s) ID2SYM(rb_intern_const(#s))
12432 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12433 i = keyword->bits_start - keyword->num;
12434 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12435#undef SYM
12436
12437 /* required args */
12438 for (i = 0; i < len; i++) {
12439 VALUE val = RARRAY_AREF(keywords, i);
12440
12441 if (!SYMBOL_P(val)) {
12442 goto default_values;
12443 }
12444 ids[i] = SYM2ID(val);
12445 keyword->required_num++;
12446 }
12447
12448 default_values: /* note: we intentionally preserve `i' from previous loop */
12449 default_len = len - i;
12450 if (default_len == 0) {
12451 keyword->table = ids;
12452 return keyword;
12453 }
12454 else if (default_len < 0) {
12456 }
12457
12458 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12459
12460 for (j = 0; i < len; i++, j++) {
12461 key = RARRAY_AREF(keywords, i);
12462 CHECK_ARRAY(key);
12463
12464 switch (RARRAY_LEN(key)) {
12465 case 1:
12466 sym = RARRAY_AREF(key, 0);
12467 default_val = Qundef;
12468 break;
12469 case 2:
12470 sym = RARRAY_AREF(key, 0);
12471 default_val = RARRAY_AREF(key, 1);
12472 break;
12473 default:
12474 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12475 }
12476 ids[i] = SYM2ID(sym);
12477 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12478 }
12479
12480 keyword->table = ids;
12481 keyword->default_values = dvs;
12482
12483 return keyword;
12484}
12485
12486static void
12487iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12488{
12489 rb_gc_mark_and_move(obj);
12490}
12491
12492void
12493rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12494{
12495 INSN *iobj = 0;
12496 size_t size = sizeof(INSN);
12497 size_t align = ALIGNMENT_SIZE_OF(INSN);
12498 unsigned int pos = 0;
12499
12500 while (storage) {
12501 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12502 size_t offset = pos + size + padding;
12503 if (offset > storage->size || offset > storage->pos) {
12504 pos = 0;
12505 storage = storage->next;
12506 }
12507 else {
12508 pos += (int)padding;
12509
12510 iobj = (INSN *)&storage->buff[pos];
12511
12512 if (iobj->operands) {
12513 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12514 }
12515 pos += (int)size;
12516 }
12517 }
12518}
12519
12520static const rb_data_type_t labels_wrapper_type = {
12521 .wrap_struct_name = "compiler/labels_wrapper",
12522 .function = {
12523 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12524 .dfree = (RUBY_DATA_FUNC)st_free_table,
12525 },
12526 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12527};
12528
12529void
12530rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12531 VALUE exception, VALUE body)
12532{
12533#define SYM(s) ID2SYM(rb_intern_const(#s))
12534 int i, len;
12535 unsigned int arg_size, local_size, stack_max;
12536 ID *tbl;
12537 struct st_table *labels_table = st_init_numtable();
12538 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12539 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12540 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12541 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12542 DECL_ANCHOR(anchor);
12543 INIT_ANCHOR(anchor);
12544
12545 len = RARRAY_LENINT(locals);
12546 ISEQ_BODY(iseq)->local_table_size = len;
12547 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12548
12549 for (i = 0; i < len; i++) {
12550 VALUE lv = RARRAY_AREF(locals, i);
12551
12552 if (sym_arg_rest == lv) {
12553 tbl[i] = 0;
12554 }
12555 else {
12556 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12557 }
12558 }
12559
12560#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12561 if (INT_PARAM(lead_num)) {
12562 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12563 }
12564 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12565 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12566 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12567 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12568#undef INT_PARAM
12569 {
12570#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12571 int x;
12572 INT_PARAM(arg_size);
12573 INT_PARAM(local_size);
12574 INT_PARAM(stack_max);
12575#undef INT_PARAM
12576 }
12577
12578 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12579 if (!NIL_P(source_hash)) {
12580 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12581 }
12582
12583 VALUE node_ids = Qfalse;
12584#ifdef USE_ISEQ_NODE_ID
12585 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12586 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12587 rb_raise(rb_eTypeError, "node_ids is not an array");
12588 }
12589#endif
12590
12591 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12592 len = RARRAY_LENINT(arg_opt_labels);
12593 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12594
12595 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12596 VALUE *opt_table = ALLOC_N(VALUE, len);
12597
12598 for (i = 0; i < len; i++) {
12599 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12600 LABEL *label = register_label(iseq, labels_table, ent);
12601 opt_table[i] = (VALUE)label;
12602 }
12603
12604 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12605 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12606 }
12607 }
12608 else if (!NIL_P(arg_opt_labels)) {
12609 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12610 arg_opt_labels);
12611 }
12612
12613 if (RB_TYPE_P(keywords, T_ARRAY)) {
12614 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12615 }
12616 else if (!NIL_P(keywords)) {
12617 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12618 keywords);
12619 }
12620
12621 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12622 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12623 }
12624
12625 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12626 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12627 }
12628
12629 if (int_param(&i, params, SYM(kwrest))) {
12630 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12631 if (keyword == NULL) {
12632 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12633 }
12634 keyword->rest_start = i;
12635 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12636 }
12637#undef SYM
12638 iseq_calc_param_size(iseq);
12639
12640 /* exception */
12641 iseq_build_from_ary_exception(iseq, labels_table, exception);
12642
12643 /* body */
12644 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12645
12646 ISEQ_BODY(iseq)->param.size = arg_size;
12647 ISEQ_BODY(iseq)->local_table_size = local_size;
12648 ISEQ_BODY(iseq)->stack_max = stack_max;
12649}
12650
12651/* for parser */
12652
12653int
12654rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12655{
12656 if (iseq) {
12657 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12658 while (body->type == ISEQ_TYPE_BLOCK ||
12659 body->type == ISEQ_TYPE_RESCUE ||
12660 body->type == ISEQ_TYPE_ENSURE ||
12661 body->type == ISEQ_TYPE_EVAL ||
12662 body->type == ISEQ_TYPE_MAIN
12663 ) {
12664 unsigned int i;
12665
12666 for (i = 0; i < body->local_table_size; i++) {
12667 if (body->local_table[i] == id) {
12668 return 1;
12669 }
12670 }
12671 iseq = body->parent_iseq;
12672 body = ISEQ_BODY(iseq);
12673 }
12674 }
12675 return 0;
12676}
12677
12678int
12679rb_local_defined(ID id, const rb_iseq_t *iseq)
12680{
12681 if (iseq) {
12682 unsigned int i;
12683 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12684
12685 for (i=0; i<body->local_table_size; i++) {
12686 if (body->local_table[i] == id) {
12687 return 1;
12688 }
12689 }
12690 }
12691 return 0;
12692}
12693
12694/* ISeq binary format */
12695
12696#ifndef IBF_ISEQ_DEBUG
12697#define IBF_ISEQ_DEBUG 0
12698#endif
12699
12700#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12701#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12702#endif
12703
12704typedef uint32_t ibf_offset_t;
12705#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12706
12707#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12708#ifdef RUBY_DEVEL
12709#define IBF_DEVEL_VERSION 8
12710#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12711#else
12712#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12713#endif
12714
12715static const char IBF_ENDIAN_MARK =
12716#ifdef WORDS_BIGENDIAN
12717 'b'
12718#else
12719 'l'
12720#endif
12721 ;
12722
12724 char magic[4]; /* YARB */
12725 uint32_t major_version;
12726 uint32_t minor_version;
12727 uint32_t size;
12728 uint32_t extra_size;
12729
12730 uint32_t iseq_list_size;
12731 uint32_t global_object_list_size;
12732 ibf_offset_t iseq_list_offset;
12733 ibf_offset_t global_object_list_offset;
12734 uint8_t endian;
12735 uint8_t wordsize; /* assume no 2048-bit CPU */
12736};
12737
12739 VALUE str;
12740 st_table *obj_table; /* obj -> obj number */
12741};
12742
12743struct ibf_dump {
12744 st_table *iseq_table; /* iseq -> iseq number */
12745 struct ibf_dump_buffer global_buffer;
12746 struct ibf_dump_buffer *current_buffer;
12747};
12748
12750 const char *buff;
12751 ibf_offset_t size;
12752
12753 VALUE obj_list; /* [obj0, ...] */
12754 unsigned int obj_list_size;
12755 ibf_offset_t obj_list_offset;
12756};
12757
12758struct ibf_load {
12759 const struct ibf_header *header;
12760 VALUE iseq_list; /* [iseq0, ...] */
12761 struct ibf_load_buffer global_buffer;
12762 VALUE loader_obj;
12763 rb_iseq_t *iseq;
12764 VALUE str;
12765 struct ibf_load_buffer *current_buffer;
12766};
12767
12769 long size;
12770 VALUE buffer[1];
12771};
12772
12773static void
12774pinned_list_mark(void *ptr)
12775{
12776 long i;
12777 struct pinned_list *list = (struct pinned_list *)ptr;
12778 for (i = 0; i < list->size; i++) {
12779 if (list->buffer[i]) {
12780 rb_gc_mark(list->buffer[i]);
12781 }
12782 }
12783}
12784
12785static const rb_data_type_t pinned_list_type = {
12786 "pinned_list",
12787 {
12788 pinned_list_mark,
12790 NULL, // No external memory to report,
12791 },
12792 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12793};
12794
12795static VALUE
12796pinned_list_fetch(VALUE list, long offset)
12797{
12798 struct pinned_list * ptr;
12799
12800 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12801
12802 if (offset < 0 || offset >= ptr->size) {
12803 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12804 }
12805
12806 return ptr->buffer[offset];
12807}
12808
12809static void
12810pinned_list_store(VALUE list, long offset, VALUE object)
12811{
12812 struct pinned_list * ptr;
12813
12814 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12815
12816 if (offset < 0 || offset >= ptr->size) {
12817 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12818 }
12819
12820 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12821}
12822
12823static VALUE
12824pinned_list_new(long size)
12825{
12826 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12827 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12828 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12829 ptr->size = size;
12830 return obj_list;
12831}
12832
12833static ibf_offset_t
12834ibf_dump_pos(struct ibf_dump *dump)
12835{
12836 long pos = RSTRING_LEN(dump->current_buffer->str);
12837#if SIZEOF_LONG > SIZEOF_INT
12838 if (pos >= UINT_MAX) {
12839 rb_raise(rb_eRuntimeError, "dump size exceeds");
12840 }
12841#endif
12842 return (unsigned int)pos;
12843}
12844
12845static void
12846ibf_dump_align(struct ibf_dump *dump, size_t align)
12847{
12848 ibf_offset_t pos = ibf_dump_pos(dump);
12849 if (pos % align) {
12850 static const char padding[sizeof(VALUE)];
12851 size_t size = align - ((size_t)pos % align);
12852#if SIZEOF_LONG > SIZEOF_INT
12853 if (pos + size >= UINT_MAX) {
12854 rb_raise(rb_eRuntimeError, "dump size exceeds");
12855 }
12856#endif
12857 for (; size > sizeof(padding); size -= sizeof(padding)) {
12858 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12859 }
12860 rb_str_cat(dump->current_buffer->str, padding, size);
12861 }
12862}
12863
12864static ibf_offset_t
12865ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12866{
12867 ibf_offset_t pos = ibf_dump_pos(dump);
12868#if SIZEOF_LONG > SIZEOF_INT
12869 /* ensure the resulting dump does not exceed UINT_MAX */
12870 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12871 rb_raise(rb_eRuntimeError, "dump size exceeds");
12872 }
12873#endif
12874 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12875 return pos;
12876}
12877
12878static ibf_offset_t
12879ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12880{
12881 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12882}
12883
12884static void
12885ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12886{
12887 VALUE str = dump->current_buffer->str;
12888 char *ptr = RSTRING_PTR(str);
12889 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12890 rb_bug("ibf_dump_overwrite: overflow");
12891 memcpy(ptr + offset, buff, size);
12892}
12893
12894static const void *
12895ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12896{
12897 ibf_offset_t beg = *offset;
12898 *offset += size;
12899 return load->current_buffer->buff + beg;
12900}
12901
12902static void *
12903ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12904{
12905 void *buff = ruby_xmalloc2(x, y);
12906 size_t size = x * y;
12907 memcpy(buff, load->current_buffer->buff + offset, size);
12908 return buff;
12909}
12910
12911#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12912
12913#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12914#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12915#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12916#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12917#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12918
12919static int
12920ibf_table_lookup(struct st_table *table, st_data_t key)
12921{
12922 st_data_t val;
12923
12924 if (st_lookup(table, key, &val)) {
12925 return (int)val;
12926 }
12927 else {
12928 return -1;
12929 }
12930}
12931
12932static int
12933ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12934{
12935 int index = ibf_table_lookup(table, key);
12936
12937 if (index < 0) { /* not found */
12938 index = (int)table->num_entries;
12939 st_insert(table, key, (st_data_t)index);
12940 }
12941
12942 return index;
12943}
12944
12945/* dump/load generic */
12946
12947static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12948
12949static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12950static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12951
12952static st_table *
12953ibf_dump_object_table_new(void)
12954{
12955 st_table *obj_table = st_init_numtable(); /* need free */
12956 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12957
12958 return obj_table;
12959}
12960
12961static VALUE
12962ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12963{
12964 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12965}
12966
12967static VALUE
12968ibf_dump_id(struct ibf_dump *dump, ID id)
12969{
12970 if (id == 0 || rb_id2name(id) == NULL) {
12971 return 0;
12972 }
12973 return ibf_dump_object(dump, rb_id2sym(id));
12974}
12975
12976static ID
12977ibf_load_id(const struct ibf_load *load, const ID id_index)
12978{
12979 if (id_index == 0) {
12980 return 0;
12981 }
12982 VALUE sym = ibf_load_object(load, id_index);
12983 if (rb_integer_type_p(sym)) {
12984 /* Load hidden local variables as indexes */
12985 return NUM2ULONG(sym);
12986 }
12987 return rb_sym2id(sym);
12988}
12989
12990/* dump/load: code */
12991
12992static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12993
12994static int
12995ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12996{
12997 if (iseq == NULL) {
12998 return -1;
12999 }
13000 else {
13001 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
13002 }
13003}
13004
13005static unsigned char
13006ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
13007{
13008 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
13009 return (unsigned char)load->current_buffer->buff[(*offset)++];
13010}
13011
13012/*
13013 * Small uint serialization
13014 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
13015 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
13016 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
13017 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13018 * ...
13019 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13020 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13021 */
13022static void
13023ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
13024{
13025 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13026 ibf_dump_write(dump, &x, sizeof(VALUE));
13027 return;
13028 }
13029
13030 enum { max_byte_length = sizeof(VALUE) + 1 };
13031
13032 unsigned char bytes[max_byte_length];
13033 ibf_offset_t n;
13034
13035 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13036 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13037 }
13038
13039 x <<= 1;
13040 x |= 1;
13041 x <<= n;
13042 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13043 n++;
13044
13045 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13046}
13047
13048static VALUE
13049ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13050{
13051 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13052 union { char s[sizeof(VALUE)]; VALUE v; } x;
13053
13054 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13055 *offset += sizeof(VALUE);
13056
13057 return x.v;
13058 }
13059
13060 enum { max_byte_length = sizeof(VALUE) + 1 };
13061
13062 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13063 const unsigned char c = buffer[*offset];
13064
13065 ibf_offset_t n =
13066 c & 1 ? 1 :
13067 c == 0 ? 9 : ntz_int32(c) + 1;
13068 VALUE x = (VALUE)c >> n;
13069
13070 if (*offset + n > load->current_buffer->size) {
13071 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13072 }
13073
13074 ibf_offset_t i;
13075 for (i = 1; i < n; i++) {
13076 x <<= 8;
13077 x |= (VALUE)buffer[*offset + i];
13078 }
13079
13080 *offset += n;
13081 return x;
13082}
13083
13084static void
13085ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13086{
13087 // short: index
13088 // short: name.length
13089 // bytes: name
13090 // // omit argc (only verify with name)
13091 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13092
13093 size_t len = strlen(bf->name);
13094 ibf_dump_write_small_value(dump, (VALUE)len);
13095 ibf_dump_write(dump, bf->name, len);
13096}
13097
13098static const struct rb_builtin_function *
13099ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13100{
13101 int i = (int)ibf_load_small_value(load, offset);
13102 int len = (int)ibf_load_small_value(load, offset);
13103 const char *name = (char *)ibf_load_ptr(load, offset, len);
13104
13105 if (0) {
13106 fprintf(stderr, "%.*s!!\n", len, name);
13107 }
13108
13109 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13110 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13111 if (strncmp(table[i].name, name, len) != 0) {
13112 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13113 i, len, name, table[i].name);
13114 }
13115 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13116
13117 return &table[i];
13118}
13119
13120static ibf_offset_t
13121ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13122{
13123 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13124 const int iseq_size = body->iseq_size;
13125 int code_index;
13126 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13127
13128 ibf_offset_t offset = ibf_dump_pos(dump);
13129
13130 for (code_index=0; code_index<iseq_size;) {
13131 const VALUE insn = orig_code[code_index++];
13132 const char *types = insn_op_types(insn);
13133 int op_index;
13134
13135 /* opcode */
13136 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13137 ibf_dump_write_small_value(dump, insn);
13138
13139 /* operands */
13140 for (op_index=0; types[op_index]; op_index++, code_index++) {
13141 VALUE op = orig_code[code_index];
13142 VALUE wv;
13143
13144 switch (types[op_index]) {
13145 case TS_CDHASH:
13146 case TS_VALUE:
13147 wv = ibf_dump_object(dump, op);
13148 break;
13149 case TS_ISEQ:
13150 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13151 break;
13152 case TS_IC:
13153 {
13154 IC ic = (IC)op;
13155 VALUE arr = idlist_to_array(ic->segments);
13156 wv = ibf_dump_object(dump, arr);
13157 }
13158 break;
13159 case TS_ISE:
13160 case TS_IVC:
13161 case TS_ICVARC:
13162 {
13164 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13165 }
13166 break;
13167 case TS_CALLDATA:
13168 {
13169 goto skip_wv;
13170 }
13171 case TS_ID:
13172 wv = ibf_dump_id(dump, (ID)op);
13173 break;
13174 case TS_FUNCPTR:
13175 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13176 goto skip_wv;
13177 case TS_BUILTIN:
13178 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13179 goto skip_wv;
13180 default:
13181 wv = op;
13182 break;
13183 }
13184 ibf_dump_write_small_value(dump, wv);
13185 skip_wv:;
13186 }
13187 RUBY_ASSERT(insn_len(insn) == op_index+1);
13188 }
13189
13190 return offset;
13191}
13192
13193static VALUE *
13194ibf_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)
13195{
13196 VALUE iseqv = (VALUE)iseq;
13197 unsigned int code_index;
13198 ibf_offset_t reading_pos = bytecode_offset;
13199 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13200
13201 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13202 struct rb_call_data *cd_entries = load_body->call_data;
13203 int ic_index = 0;
13204
13205 load_body->iseq_encoded = code;
13206 load_body->iseq_size = iseq_size;
13207
13208 iseq_bits_t * mark_offset_bits;
13209 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13210 load_body->mark_bits.single = 0;
13211 mark_offset_bits = &load_body->mark_bits.single;
13212 }
13213 else {
13214 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13215 mark_offset_bits = load_body->mark_bits.list;
13216 }
13217 bool needs_bitmap = false;
13218
13219 for (code_index=0; code_index<iseq_size;) {
13220 /* opcode */
13221 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13222 const char *types = insn_op_types(insn);
13223 int op_index;
13224
13225 code_index++;
13226
13227 /* operands */
13228 for (op_index=0; types[op_index]; op_index++, code_index++) {
13229 const char operand_type = types[op_index];
13230 switch (operand_type) {
13231 case TS_VALUE:
13232 {
13233 VALUE op = ibf_load_small_value(load, &reading_pos);
13234 VALUE v = ibf_load_object(load, op);
13235 code[code_index] = v;
13236 if (!SPECIAL_CONST_P(v)) {
13237 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13238 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13239 needs_bitmap = true;
13240 }
13241 break;
13242 }
13243 case TS_CDHASH:
13244 {
13245 VALUE op = ibf_load_small_value(load, &reading_pos);
13246 VALUE v = ibf_load_object(load, op);
13247
13248 // Overwrite the existing hash in the object list. This
13249 // is to keep the object alive during load time.
13250 // [Bug #17984] [ruby-core:104259]
13251 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13252
13253 code[code_index] = v;
13254 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13255 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13256 needs_bitmap = true;
13257 break;
13258 }
13259 case TS_ISEQ:
13260 {
13261 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13262 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13263 code[code_index] = v;
13264 if (!SPECIAL_CONST_P(v)) {
13265 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13266 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13267 needs_bitmap = true;
13268 }
13269 break;
13270 }
13271 case TS_IC:
13272 {
13273 VALUE op = ibf_load_small_value(load, &reading_pos);
13274 VALUE arr = ibf_load_object(load, op);
13275
13276 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13277 ic->segments = array_to_idlist(arr);
13278
13279 code[code_index] = (VALUE)ic;
13280 }
13281 break;
13282 case TS_ISE:
13283 case TS_ICVARC:
13284 case TS_IVC:
13285 {
13286 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13287
13288 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13289 code[code_index] = (VALUE)ic;
13290
13291 if (operand_type == TS_IVC) {
13292 IVC cache = (IVC)ic;
13293
13294 if (insn == BIN(setinstancevariable)) {
13295 ID iv_name = (ID)code[code_index - 1];
13296 cache->iv_set_name = iv_name;
13297 cache->value = IVAR_CACHE_INIT;
13298 }
13299 else {
13300 cache->iv_set_name = 0;
13301 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13302 }
13303 }
13304
13305 }
13306 break;
13307 case TS_CALLDATA:
13308 {
13309 code[code_index] = (VALUE)cd_entries++;
13310 }
13311 break;
13312 case TS_ID:
13313 {
13314 VALUE op = ibf_load_small_value(load, &reading_pos);
13315 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13316 }
13317 break;
13318 case TS_FUNCPTR:
13319 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13320 break;
13321 case TS_BUILTIN:
13322 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13323 break;
13324 default:
13325 code[code_index] = ibf_load_small_value(load, &reading_pos);
13326 continue;
13327 }
13328 }
13329 if (insn_len(insn) != op_index+1) {
13330 rb_raise(rb_eRuntimeError, "operand size mismatch");
13331 }
13332 }
13333
13334 if (!needs_bitmap) {
13335 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13336 load_body->mark_bits.list = NULL;
13337 }
13338
13339 RUBY_ASSERT(code_index == iseq_size);
13340 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13341 return code;
13342}
13343
13344static ibf_offset_t
13345ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13346{
13347 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13348
13349 if (opt_num > 0) {
13350 IBF_W_ALIGN(VALUE);
13351 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13352 }
13353 else {
13354 return ibf_dump_pos(dump);
13355 }
13356}
13357
13358static VALUE *
13359ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13360{
13361 if (opt_num > 0) {
13362 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13363 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13364 return table;
13365 }
13366 else {
13367 return NULL;
13368 }
13369}
13370
13371static ibf_offset_t
13372ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13373{
13374 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13375
13376 if (kw) {
13377 struct rb_iseq_param_keyword dump_kw = *kw;
13378 int dv_num = kw->num - kw->required_num;
13379 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13380 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13381 int i;
13382
13383 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13384 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13385
13386 dump_kw.table = IBF_W(ids, ID, kw->num);
13387 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13388 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13389 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13390 }
13391 else {
13392 return 0;
13393 }
13394}
13395
13396static const struct rb_iseq_param_keyword *
13397ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13398{
13399 if (param_keyword_offset) {
13400 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13401 int dv_num = kw->num - kw->required_num;
13402 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13403
13404 int i;
13405 for (i=0; i<dv_num; i++) {
13406 dvs[i] = ibf_load_object(load, dvs[i]);
13407 }
13408
13409 // Will be set once the local table is loaded.
13410 kw->table = NULL;
13411
13412 kw->default_values = dvs;
13413 return kw;
13414 }
13415 else {
13416 return NULL;
13417 }
13418}
13419
13420static ibf_offset_t
13421ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13422{
13423 ibf_offset_t offset = ibf_dump_pos(dump);
13424 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13425
13426 unsigned int i;
13427 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13428 ibf_dump_write_small_value(dump, entries[i].line_no);
13429#ifdef USE_ISEQ_NODE_ID
13430 ibf_dump_write_small_value(dump, entries[i].node_id);
13431#endif
13432 ibf_dump_write_small_value(dump, entries[i].events);
13433 }
13434
13435 return offset;
13436}
13437
13438static struct iseq_insn_info_entry *
13439ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13440{
13441 ibf_offset_t reading_pos = body_offset;
13442 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13443
13444 unsigned int i;
13445 for (i = 0; i < size; i++) {
13446 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13447#ifdef USE_ISEQ_NODE_ID
13448 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13449#endif
13450 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13451 }
13452
13453 return entries;
13454}
13455
13456static ibf_offset_t
13457ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13458{
13459 ibf_offset_t offset = ibf_dump_pos(dump);
13460
13461 unsigned int last = 0;
13462 unsigned int i;
13463 for (i = 0; i < size; i++) {
13464 ibf_dump_write_small_value(dump, positions[i] - last);
13465 last = positions[i];
13466 }
13467
13468 return offset;
13469}
13470
13471static unsigned int *
13472ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13473{
13474 ibf_offset_t reading_pos = positions_offset;
13475 unsigned int *positions = ALLOC_N(unsigned int, size);
13476
13477 unsigned int last = 0;
13478 unsigned int i;
13479 for (i = 0; i < size; i++) {
13480 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13481 last = positions[i];
13482 }
13483
13484 return positions;
13485}
13486
13487static ibf_offset_t
13488ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13489{
13490 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13491 const int size = body->local_table_size;
13492 ID *table = ALLOCA_N(ID, size);
13493 int i;
13494
13495 for (i=0; i<size; i++) {
13496 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13497 if (v == 0) {
13498 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13499 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13500 }
13501 table[i] = v;
13502 }
13503
13504 IBF_W_ALIGN(ID);
13505 return ibf_dump_write(dump, table, sizeof(ID) * size);
13506}
13507
13508static const ID *
13509ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13510{
13511 if (size > 0) {
13512 ID *table = IBF_R(local_table_offset, ID, size);
13513 int i;
13514
13515 for (i=0; i<size; i++) {
13516 table[i] = ibf_load_id(load, table[i]);
13517 }
13518
13519 if (size == 1 && table[0] == idERROR_INFO) {
13520 ruby_xfree_sized(table, sizeof(ID) * size);
13521 return rb_iseq_shared_exc_local_tbl;
13522 }
13523 else {
13524 return table;
13525 }
13526 }
13527 else {
13528 return NULL;
13529 }
13530}
13531
13532static ibf_offset_t
13533ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13534{
13535 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13536 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13537 IBF_W_ALIGN(uint8_t);
13538 if (iseq_has_lvar_states_p(body)) {
13539 return ibf_dump_write(dump, iseq_lvar_states(body), sizeof(uint8_t) * size);
13540 }
13541 else {
13542 return ibf_dump_write(dump, NULL, 0);
13543 }
13544}
13545
13546static void
13547ibf_load_lvar_states(const struct ibf_load *load, struct rb_iseq_constant_body *load_body, ibf_offset_t lvar_states_offset, int size, const ID *local_table)
13548{
13549 if (local_table == rb_iseq_shared_exc_local_tbl ||
13550 size <= 0) {
13551 load_body->lvar_states.list = NULL;
13552 }
13553 else if (ISEQ_LVAR_STATES_EMBED_P((unsigned int)size)) {
13554 ibf_offset_t pos = lvar_states_offset;
13555 const int len = sizeof(uint8_t) * ISEQ_LVAR_STATES_BUFLEN(size);
13556 memcpy(load_body->lvar_states.single, ibf_load_ptr(load, &pos, len), len);
13557 }
13558 else {
13559 load_body->lvar_states.list = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13560 }
13561}
13562
13563static ibf_offset_t
13564ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13565{
13566 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13567
13568 if (table) {
13569 int *iseq_indices = ALLOCA_N(int, table->size);
13570 unsigned int i;
13571
13572 for (i=0; i<table->size; i++) {
13573 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13574 }
13575
13576 const ibf_offset_t offset = ibf_dump_pos(dump);
13577
13578 for (i=0; i<table->size; i++) {
13579 ibf_dump_write_small_value(dump, iseq_indices[i]);
13580 ibf_dump_write_small_value(dump, table->entries[i].type);
13581 ibf_dump_write_small_value(dump, table->entries[i].start);
13582 ibf_dump_write_small_value(dump, table->entries[i].end);
13583 ibf_dump_write_small_value(dump, table->entries[i].cont);
13584 ibf_dump_write_small_value(dump, table->entries[i].sp);
13585 }
13586 return offset;
13587 }
13588 else {
13589 return ibf_dump_pos(dump);
13590 }
13591}
13592
13593static void
13594ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13595{
13596 if (size) {
13597 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13598 table->size = size;
13599 ISEQ_BODY(parent_iseq)->catch_table = table;
13600
13601 ibf_offset_t reading_pos = catch_table_offset;
13602
13603 unsigned int i;
13604 for (i=0; i<table->size; i++) {
13605 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13606 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13607 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13608 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13609 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13610 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13611
13612 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13613 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13614 }
13615 }
13616 else {
13617 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13618 }
13619}
13620
13621static ibf_offset_t
13622ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13623{
13624 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13625 const unsigned int ci_size = body->ci_size;
13626 const struct rb_call_data *cds = body->call_data;
13627
13628 ibf_offset_t offset = ibf_dump_pos(dump);
13629
13630 unsigned int i;
13631
13632 for (i = 0; i < ci_size; i++) {
13633 const struct rb_callinfo *ci = cds[i].ci;
13634 if (ci != NULL) {
13635 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13636 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13637 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13638
13639 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13640 if (kwarg) {
13641 int len = kwarg->keyword_len;
13642 ibf_dump_write_small_value(dump, len);
13643 for (int j=0; j<len; j++) {
13644 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13645 ibf_dump_write_small_value(dump, keyword);
13646 }
13647 }
13648 else {
13649 ibf_dump_write_small_value(dump, 0);
13650 }
13651 }
13652 else {
13653 // TODO: truncate NULL ci from call_data.
13654 ibf_dump_write_small_value(dump, (VALUE)-1);
13655 }
13656 }
13657
13658 return offset;
13659}
13660
13662 ID id;
13663 VALUE name;
13664 VALUE val;
13665};
13666
13668 size_t num;
13669 struct outer_variable_pair pairs[1];
13670};
13671
13672static enum rb_id_table_iterator_result
13673store_outer_variable(ID id, VALUE val, void *dump)
13674{
13675 struct outer_variable_list *ovlist = dump;
13676 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13677 pair->id = id;
13678 pair->name = rb_id2str(id);
13679 pair->val = val;
13680 return ID_TABLE_CONTINUE;
13681}
13682
13683static int
13684outer_variable_cmp(const void *a, const void *b, void *arg)
13685{
13686 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13687 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13688
13689 if (!ap->name) {
13690 return -1;
13691 }
13692 else if (!bp->name) {
13693 return 1;
13694 }
13695
13696 return rb_str_cmp(ap->name, bp->name);
13697}
13698
13699static ibf_offset_t
13700ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13701{
13702 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13703
13704 ibf_offset_t offset = ibf_dump_pos(dump);
13705
13706 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13707 ibf_dump_write_small_value(dump, (VALUE)size);
13708 if (size > 0) {
13709 VALUE buff;
13710 size_t buffsize =
13711 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13712 offsetof(struct outer_variable_list, pairs),
13713 rb_eArgError);
13714 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13715 ovlist->num = 0;
13716 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13717 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13718 for (size_t i = 0; i < size; ++i) {
13719 ID id = ovlist->pairs[i].id;
13720 ID val = ovlist->pairs[i].val;
13721 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13722 ibf_dump_write_small_value(dump, val);
13723 }
13724 }
13725
13726 return offset;
13727}
13728
13729/* note that we dump out rb_call_info but load back rb_call_data */
13730static void
13731ibf_load_ci_entries(const struct ibf_load *load,
13732 ibf_offset_t ci_entries_offset,
13733 unsigned int ci_size,
13734 struct rb_call_data **cd_ptr)
13735{
13736 if (!ci_size) {
13737 *cd_ptr = NULL;
13738 return;
13739 }
13740
13741 ibf_offset_t reading_pos = ci_entries_offset;
13742
13743 unsigned int i;
13744
13745 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13746 *cd_ptr = cds;
13747
13748 for (i = 0; i < ci_size; i++) {
13749 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13750 if (mid_index != (VALUE)-1) {
13751 ID mid = ibf_load_id(load, mid_index);
13752 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13753 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13754
13755 struct rb_callinfo_kwarg *kwarg = NULL;
13756 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13757 if (kwlen > 0) {
13758 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13759 kwarg->references = 0;
13760 kwarg->keyword_len = kwlen;
13761 for (int j=0; j<kwlen; j++) {
13762 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13763 kwarg->keywords[j] = ibf_load_object(load, keyword);
13764 }
13765 }
13766
13767 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13768 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13769 cds[i].cc = vm_cc_empty();
13770 }
13771 else {
13772 // NULL ci
13773 cds[i].ci = NULL;
13774 cds[i].cc = NULL;
13775 }
13776 }
13777}
13778
13779static struct rb_id_table *
13780ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13781{
13782 ibf_offset_t reading_pos = outer_variables_offset;
13783
13784 struct rb_id_table *tbl = NULL;
13785
13786 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13787
13788 if (table_size > 0) {
13789 tbl = rb_id_table_create(table_size);
13790 }
13791
13792 for (size_t i = 0; i < table_size; i++) {
13793 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13794 VALUE value = ibf_load_small_value(load, &reading_pos);
13795 if (!key) key = rb_make_temporary_id(i);
13796 rb_id_table_insert(tbl, key, value);
13797 }
13798
13799 return tbl;
13800}
13801
13802static ibf_offset_t
13803ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13804{
13805 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13806
13807 unsigned int *positions;
13808
13809 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13810
13811 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13812 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13813
13814#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13815 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13816
13817 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13818 struct ibf_dump_buffer buffer;
13819 buffer.str = rb_str_new(0, 0);
13820 buffer.obj_table = ibf_dump_object_table_new();
13821 dump->current_buffer = &buffer;
13822#endif
13823
13824 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13825 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13826 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13827 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13828 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13829
13830 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13831 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13832 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13833
13834 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13835 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13836 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13837 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13838 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13839 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13840 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13841 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13842 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13843 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13844
13845#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13846 ibf_offset_t local_obj_list_offset;
13847 unsigned int local_obj_list_size;
13848
13849 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13850#endif
13851
13852 ibf_offset_t body_offset = ibf_dump_pos(dump);
13853
13854 /* dump the constant body */
13855 unsigned int param_flags =
13856 (body->param.flags.has_lead << 0) |
13857 (body->param.flags.has_opt << 1) |
13858 (body->param.flags.has_rest << 2) |
13859 (body->param.flags.has_post << 3) |
13860 (body->param.flags.has_kw << 4) |
13861 (body->param.flags.has_kwrest << 5) |
13862 (body->param.flags.has_block << 6) |
13863 (body->param.flags.ambiguous_param0 << 7) |
13864 (body->param.flags.accepts_no_kwarg << 8) |
13865 (body->param.flags.ruby2_keywords << 9) |
13866 (body->param.flags.anon_rest << 10) |
13867 (body->param.flags.anon_kwrest << 11) |
13868 (body->param.flags.use_block << 12) |
13869 (body->param.flags.forwardable << 13) |
13870 (body->param.flags.accepts_no_block << 14);
13871
13872#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13873# define IBF_BODY_OFFSET(x) (x)
13874#else
13875# define IBF_BODY_OFFSET(x) (body_offset - (x))
13876#endif
13877
13878 ibf_dump_write_small_value(dump, body->type);
13879 ibf_dump_write_small_value(dump, body->iseq_size);
13880 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13881 ibf_dump_write_small_value(dump, bytecode_size);
13882 ibf_dump_write_small_value(dump, param_flags);
13883 ibf_dump_write_small_value(dump, body->param.size);
13884 ibf_dump_write_small_value(dump, body->param.lead_num);
13885 ibf_dump_write_small_value(dump, body->param.opt_num);
13886 ibf_dump_write_small_value(dump, body->param.rest_start);
13887 ibf_dump_write_small_value(dump, body->param.post_start);
13888 ibf_dump_write_small_value(dump, body->param.post_num);
13889 ibf_dump_write_small_value(dump, body->param.block_start);
13890 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13891 ibf_dump_write_small_value(dump, param_keyword_offset);
13892 ibf_dump_write_small_value(dump, location_pathobj_index);
13893 ibf_dump_write_small_value(dump, location_label_index);
13894 ibf_dump_write_small_value(dump, body->location.first_lineno);
13895 ibf_dump_write_small_value(dump, body->location.node_id);
13896 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
13897 * VALUE may be 32 bits wide. */
13898 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
13899 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
13900 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13901 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13902 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13903 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13904 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13905 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13906 ibf_dump_write_small_value(dump, body->insns_info.size);
13907 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13908 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13909 ibf_dump_write_small_value(dump, catch_table_size);
13910 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13911 ibf_dump_write_small_value(dump, parent_iseq_index);
13912 ibf_dump_write_small_value(dump, local_iseq_index);
13913 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13914 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13915 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13916 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
13917 ibf_dump_write_small_value(dump, body->local_table_size);
13918 ibf_dump_write_small_value(dump, body->ivc_size);
13919 ibf_dump_write_small_value(dump, body->icvarc_size);
13920 ibf_dump_write_small_value(dump, body->ise_size);
13921 ibf_dump_write_small_value(dump, body->ic_size);
13922 ibf_dump_write_small_value(dump, body->ci_size);
13923 ibf_dump_write_small_value(dump, body->stack_max);
13924 ibf_dump_write_small_value(dump, body->builtin_attrs);
13925 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13926
13927#undef IBF_BODY_OFFSET
13928
13929#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13930 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13931
13932 dump->current_buffer = saved_buffer;
13933 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13934
13935 ibf_offset_t offset = ibf_dump_pos(dump);
13936 ibf_dump_write_small_value(dump, iseq_start);
13937 ibf_dump_write_small_value(dump, iseq_length_bytes);
13938 ibf_dump_write_small_value(dump, body_offset);
13939
13940 ibf_dump_write_small_value(dump, local_obj_list_offset);
13941 ibf_dump_write_small_value(dump, local_obj_list_size);
13942
13943 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13944
13945 return offset;
13946#else
13947 return body_offset;
13948#endif
13949}
13950
13951static VALUE
13952ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13953{
13954 VALUE str = ibf_load_object(load, str_index);
13955 if (str != Qnil) {
13956 str = rb_fstring(str);
13957 }
13958 return str;
13959}
13960
13961static void
13962ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13963{
13964 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13965
13966 ibf_offset_t reading_pos = offset;
13967
13968#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13969 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13970 load->current_buffer = &load->global_buffer;
13971
13972 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13973 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13974 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13975
13976 struct ibf_load_buffer buffer;
13977 buffer.buff = load->global_buffer.buff + iseq_start;
13978 buffer.size = iseq_length_bytes;
13979 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13980 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13981 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13982
13983 load->current_buffer = &buffer;
13984 reading_pos = body_offset;
13985#endif
13986
13987#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13988# define IBF_BODY_OFFSET(x) (x)
13989#else
13990# define IBF_BODY_OFFSET(x) (offset - (x))
13991#endif
13992
13993 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13994 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13995 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13996 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13997 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13998 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13999 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
14000 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
14001 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
14002 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
14003 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
14004 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
14005 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14006 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
14007 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
14008 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
14009 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
14010 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
14011 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
14012 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
14013 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
14014 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14015 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14016 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
14017 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14018 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14019 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14020 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14021 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14022 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14023 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14024 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14025 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14026 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14027 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14028 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14029 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14030 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
14031 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14032
14033 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14034 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14035 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14036 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14037
14038 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14039 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14040 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14041 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14042
14043 // setup fname and dummy frame
14044 VALUE path = ibf_load_object(load, location_pathobj_index);
14045 {
14046 VALUE realpath = Qnil;
14047
14048 if (RB_TYPE_P(path, T_STRING)) {
14049 realpath = path = rb_fstring(path);
14050 }
14051 else if (RB_TYPE_P(path, T_ARRAY)) {
14052 VALUE pathobj = path;
14053 if (RARRAY_LEN(pathobj) != 2) {
14054 rb_raise(rb_eRuntimeError, "path object size mismatch");
14055 }
14056 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14057 realpath = RARRAY_AREF(pathobj, 1);
14058 if (!NIL_P(realpath)) {
14059 if (!RB_TYPE_P(realpath, T_STRING)) {
14060 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14061 "(%x), path=%+"PRIsVALUE,
14062 realpath, TYPE(realpath), path);
14063 }
14064 realpath = rb_fstring(realpath);
14065 }
14066 }
14067 else {
14068 rb_raise(rb_eRuntimeError, "unexpected path object");
14069 }
14070 rb_iseq_pathobj_set(iseq, path, realpath);
14071 }
14072
14073 // push dummy frame
14074 rb_execution_context_t *ec = GET_EC();
14075 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14076
14077#undef IBF_BODY_OFFSET
14078
14079 load_body->type = type;
14080 load_body->stack_max = stack_max;
14081 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14082 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14083 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14084 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14085 load_body->param.flags.has_kw = FALSE;
14086 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14087 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14088 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14089 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14090 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14091 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14092 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14093 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14094 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14095 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14096 load_body->param.size = param_size;
14097 load_body->param.lead_num = param_lead_num;
14098 load_body->param.opt_num = param_opt_num;
14099 load_body->param.rest_start = param_rest_start;
14100 load_body->param.post_start = param_post_start;
14101 load_body->param.post_num = param_post_num;
14102 load_body->param.block_start = param_block_start;
14103 load_body->local_table_size = local_table_size;
14104 load_body->ci_size = ci_size;
14105 load_body->insns_info.size = insns_info_size;
14106
14107 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14108 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14109 if (variable_flip_count) {
14110 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14111 v->flip_count = variable_flip_count;
14112 }
14113
14114 load_body->location.first_lineno = location_first_lineno;
14115 load_body->location.node_id = location_node_id;
14116 load_body->source_hash = source_hash;
14117 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14118 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14119 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14120 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14121 load_body->builtin_attrs = builtin_attrs;
14122 load_body->prism = prism;
14123
14124 load_body->ivc_size = ivc_size;
14125 load_body->icvarc_size = icvarc_size;
14126 load_body->ise_size = ise_size;
14127 load_body->ic_size = ic_size;
14128
14129 if (ISEQ_IS_SIZE(load_body)) {
14130 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14131 }
14132 else {
14133 load_body->is_entries = NULL;
14134 }
14135 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14136 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14137 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14138 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14139 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14140 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
14141 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14142 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14143 ibf_load_lvar_states(load, load_body, lvar_states_offset, local_table_size, load_body->local_table);
14144 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14145
14146 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14147 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14148 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14149
14150 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14151 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14152 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14153
14154 // This must be done after the local table is loaded.
14155 if (load_body->param.keyword != NULL) {
14156 RUBY_ASSERT(load_body->local_table);
14157 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14158 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14159 }
14160
14161 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14162#if VM_INSN_INFO_TABLE_IMPL == 2
14163 rb_iseq_insns_info_encode_positions(iseq);
14164#endif
14165
14166 rb_iseq_translate_threaded_code(iseq);
14167
14168#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14169 load->current_buffer = &load->global_buffer;
14170#endif
14171
14172 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14173
14174#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14175 load->current_buffer = saved_buffer;
14176#endif
14177 verify_call_cache(iseq);
14178
14179 RB_GC_GUARD(dummy_frame);
14180 rb_vm_pop_frame_no_int(ec);
14181}
14182
14184{
14185 struct ibf_dump *dump;
14186 VALUE offset_list;
14187};
14188
14189static int
14190ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14191{
14192 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14193 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14194
14195 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14196 rb_ary_push(args->offset_list, UINT2NUM(offset));
14197
14198 return ST_CONTINUE;
14199}
14200
14201static void
14202ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14203{
14204 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14205
14206 struct ibf_dump_iseq_list_arg args;
14207 args.dump = dump;
14208 args.offset_list = offset_list;
14209
14210 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14211
14212 st_index_t i;
14213 st_index_t size = dump->iseq_table->num_entries;
14214 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14215
14216 for (i = 0; i < size; i++) {
14217 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14218 }
14219
14220 ibf_dump_align(dump, sizeof(ibf_offset_t));
14221 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14222 header->iseq_list_size = (unsigned int)size;
14223}
14224
14225/*
14226 * Binary format
14227 * - ibf_object_header
14228 * - ibf_object_xxx (xxx is type)
14229 */
14230
14232 unsigned int type: 5;
14233 unsigned int special_const: 1;
14234 unsigned int frozen: 1;
14235 unsigned int internal: 1;
14236};
14237
14238enum ibf_object_class_index {
14239 IBF_OBJECT_CLASS_OBJECT,
14240 IBF_OBJECT_CLASS_ARRAY,
14241 IBF_OBJECT_CLASS_STANDARD_ERROR,
14242 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14243 IBF_OBJECT_CLASS_TYPE_ERROR,
14244 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14245};
14246
14248 long srcstr;
14249 char option;
14250};
14251
14253 long len;
14254 long keyval[FLEX_ARY_LEN];
14255};
14256
14258 long class_index;
14259 long len;
14260 long beg;
14261 long end;
14262 int excl;
14263};
14264
14266 ssize_t slen;
14267 BDIGIT digits[FLEX_ARY_LEN];
14268};
14269
14270enum ibf_object_data_type {
14271 IBF_OBJECT_DATA_ENCODING,
14272};
14273
14275 long a, b;
14276};
14277
14279 long str;
14280};
14281
14282#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14283 ((((offset) - 1) / (align) + 1) * (align))
14284/* No cast, since it's UB to create an unaligned pointer.
14285 * Leave as void* for use with memcpy in those cases.
14286 * We align the offset, but the buffer pointer is only VALUE aligned,
14287 * so the returned pointer may be unaligned for `type` .*/
14288#define IBF_OBJBODY(type, offset) \
14289 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14290
14291static const void *
14292ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14293{
14294 if (offset >= load->current_buffer->size) {
14295 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14296 }
14297 return load->current_buffer->buff + offset;
14298}
14299
14300NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14301
14302static void
14303ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14304{
14305 char buff[0x100];
14306 rb_raw_obj_info(buff, sizeof(buff), obj);
14307 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14308}
14309
14310NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14311
14312static VALUE
14313ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14314{
14315 rb_raise(rb_eArgError, "unsupported");
14317}
14318
14319static void
14320ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14321{
14322 enum ibf_object_class_index cindex;
14323 if (obj == rb_cObject) {
14324 cindex = IBF_OBJECT_CLASS_OBJECT;
14325 }
14326 else if (obj == rb_cArray) {
14327 cindex = IBF_OBJECT_CLASS_ARRAY;
14328 }
14329 else if (obj == rb_eStandardError) {
14330 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14331 }
14332 else if (obj == rb_eNoMatchingPatternError) {
14333 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14334 }
14335 else if (obj == rb_eTypeError) {
14336 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14337 }
14338 else if (obj == rb_eNoMatchingPatternKeyError) {
14339 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14340 }
14341 else {
14342 rb_obj_info_dump(obj);
14343 rb_p(obj);
14344 rb_bug("unsupported class");
14345 }
14346 ibf_dump_write_small_value(dump, (VALUE)cindex);
14347}
14348
14349static VALUE
14350ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14351{
14352 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14353
14354 switch (cindex) {
14355 case IBF_OBJECT_CLASS_OBJECT:
14356 return rb_cObject;
14357 case IBF_OBJECT_CLASS_ARRAY:
14358 return rb_cArray;
14359 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14360 return rb_eStandardError;
14361 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14363 case IBF_OBJECT_CLASS_TYPE_ERROR:
14364 return rb_eTypeError;
14365 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14367 }
14368
14369 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14370}
14371
14372
14373static void
14374ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14375{
14376 double dbl = RFLOAT_VALUE(obj);
14377 (void)IBF_W(&dbl, double, 1);
14378}
14379
14380static VALUE
14381ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14382{
14383 double d;
14384 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14385 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14386 VALUE f = DBL2NUM(d);
14387 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14388 return f;
14389}
14390
14391static void
14392ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14393{
14394 long encindex = (long)rb_enc_get_index(obj);
14395 long len = RSTRING_LEN(obj);
14396 const char *ptr = RSTRING_PTR(obj);
14397
14398 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14399 rb_encoding *enc = rb_enc_from_index((int)encindex);
14400 const char *enc_name = rb_enc_name(enc);
14401 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14402 }
14403
14404 ibf_dump_write_small_value(dump, encindex);
14405 ibf_dump_write_small_value(dump, len);
14406 IBF_WP(ptr, char, len);
14407}
14408
14409static VALUE
14410ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14411{
14412 ibf_offset_t reading_pos = offset;
14413
14414 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14415 const long len = (long)ibf_load_small_value(load, &reading_pos);
14416 const char *ptr = load->current_buffer->buff + reading_pos;
14417
14418 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14419 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14420 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14421 }
14422
14423 VALUE str;
14424 if (header->frozen && !header->internal) {
14425 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14426 }
14427 else {
14428 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14429
14430 if (header->internal) rb_obj_hide(str);
14431 if (header->frozen) str = rb_fstring(str);
14432 }
14433 return str;
14434}
14435
14436static void
14437ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14438{
14439 VALUE srcstr = RREGEXP_SRC(obj);
14440 struct ibf_object_regexp regexp;
14441 regexp.option = (char)rb_reg_options(obj);
14442 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14443
14444 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14445 ibf_dump_write_small_value(dump, regexp.srcstr);
14446}
14447
14448static VALUE
14449ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14450{
14451 struct ibf_object_regexp regexp;
14452 regexp.option = ibf_load_byte(load, &offset);
14453 regexp.srcstr = ibf_load_small_value(load, &offset);
14454
14455 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14456 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14457
14458 if (header->internal) rb_obj_hide(reg);
14459 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14460
14461 return reg;
14462}
14463
14464static void
14465ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14466{
14467 long i, len = RARRAY_LEN(obj);
14468 ibf_dump_write_small_value(dump, len);
14469 for (i=0; i<len; i++) {
14470 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14471 ibf_dump_write_small_value(dump, index);
14472 }
14473}
14474
14475static VALUE
14476ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14477{
14478 ibf_offset_t reading_pos = offset;
14479
14480 const long len = (long)ibf_load_small_value(load, &reading_pos);
14481
14482 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14483 int i;
14484
14485 for (i=0; i<len; i++) {
14486 const VALUE index = ibf_load_small_value(load, &reading_pos);
14487 rb_ary_push(ary, ibf_load_object(load, index));
14488 }
14489
14490 if (header->frozen) {
14491 rb_ary_freeze(ary);
14492 rb_ractor_make_shareable(ary); // TODO: check elements
14493 }
14494
14495 return ary;
14496}
14497
14498static int
14499ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14500{
14501 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14502
14503 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14504 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14505
14506 ibf_dump_write_small_value(dump, key_index);
14507 ibf_dump_write_small_value(dump, val_index);
14508 return ST_CONTINUE;
14509}
14510
14511static void
14512ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14513{
14514 long len = RHASH_SIZE(obj);
14515 ibf_dump_write_small_value(dump, (VALUE)len);
14516
14517 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14518}
14519
14520static VALUE
14521ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14522{
14523 long len = (long)ibf_load_small_value(load, &offset);
14524 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14525 int i;
14526
14527 for (i = 0; i < len; i++) {
14528 VALUE key_index = ibf_load_small_value(load, &offset);
14529 VALUE val_index = ibf_load_small_value(load, &offset);
14530
14531 VALUE key = ibf_load_object(load, key_index);
14532 VALUE val = ibf_load_object(load, val_index);
14533 rb_hash_aset(obj, key, val);
14534 }
14535
14536 if (header->internal) rb_obj_hide(obj);
14537 if (header->frozen) {
14539 }
14540
14541 return obj;
14542}
14543
14544static int
14545ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14546{
14547 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14548
14549 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14550
14551 ibf_dump_write_small_value(dump, key_index);
14552 ibf_dump_write_small_value(dump, val);
14553 return ST_CONTINUE;
14554}
14555
14556static void
14557ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14558{
14559 switch (imemo_type(obj)) {
14560 case imemo_cdhash: {
14561 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14562
14563 long len = tbl->num_entries;
14564 ibf_dump_write_small_value(dump, (VALUE)len);
14565 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14566 break;
14567 }
14568 default:
14569 ibf_dump_object_unsupported(dump, obj);
14570 break;
14571 }
14572}
14573
14574static VALUE
14575ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14576{
14577 long len = (long)ibf_load_small_value(load, &offset);
14578 VALUE obj = cdhash_new(len);
14579
14580 int i;
14581 for (i = 0; i < len; i++) {
14582 VALUE key_index = ibf_load_small_value(load, &offset);
14583 VALUE val = ibf_load_small_value(load, &offset);
14584
14585 VALUE key = ibf_load_object(load, key_index);
14586 cdhash_aset(obj, key, val);
14587 }
14588
14589 return obj;
14590}
14591
14592static void
14593ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14594{
14595 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14596 struct ibf_object_struct_range range;
14597 VALUE beg, end;
14598 IBF_ZERO(range);
14599 range.len = 3;
14600 range.class_index = 0;
14601
14602 rb_range_values(obj, &beg, &end, &range.excl);
14603 range.beg = (long)ibf_dump_object(dump, beg);
14604 range.end = (long)ibf_dump_object(dump, end);
14605
14606 IBF_W_ALIGN(struct ibf_object_struct_range);
14607 IBF_WV(range);
14608 }
14609 else {
14610 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14611 rb_class_name(CLASS_OF(obj)));
14612 }
14613}
14614
14615static VALUE
14616ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14617{
14618 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14619 VALUE beg = ibf_load_object(load, range->beg);
14620 VALUE end = ibf_load_object(load, range->end);
14621 VALUE obj = rb_range_new(beg, end, range->excl);
14622 if (header->internal) rb_obj_hide(obj);
14623 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14624 return obj;
14625}
14626
14627static void
14628ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14629{
14630 ssize_t len = BIGNUM_LEN(obj);
14631 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14632 BDIGIT *d = BIGNUM_DIGITS(obj);
14633
14634 (void)IBF_W(&slen, ssize_t, 1);
14635 IBF_WP(d, BDIGIT, len);
14636}
14637
14638static VALUE
14639ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14640{
14641 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14642 int sign = bignum->slen > 0;
14643 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14644 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14647 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14648 big_unpack_flags |
14649 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14650 if (header->internal) rb_obj_hide(obj);
14651 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14652 return obj;
14653}
14654
14655static void
14656ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14657{
14658 if (rb_data_is_encoding(obj)) {
14659 rb_encoding *enc = rb_to_encoding(obj);
14660 const char *name = rb_enc_name(enc);
14661 long len = strlen(name) + 1;
14662 long data[2];
14663 data[0] = IBF_OBJECT_DATA_ENCODING;
14664 data[1] = len;
14665 (void)IBF_W(data, long, 2);
14666 IBF_WP(name, char, len);
14667 }
14668 else {
14669 ibf_dump_object_unsupported(dump, obj);
14670 }
14671}
14672
14673static VALUE
14674ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14675{
14676 const long *body = IBF_OBJBODY(long, offset);
14677 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14678 /* const long len = body[1]; */
14679 const char *data = (const char *)&body[2];
14680
14681 switch (type) {
14682 case IBF_OBJECT_DATA_ENCODING:
14683 {
14684 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14685 return encobj;
14686 }
14687 }
14688
14689 return ibf_load_object_unsupported(load, header, offset);
14690}
14691
14692static void
14693ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14694{
14695 long data[2];
14696 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14697 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14698
14699 (void)IBF_W(data, long, 2);
14700}
14701
14702static VALUE
14703ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14704{
14705 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14706 VALUE a = ibf_load_object(load, nums->a);
14707 VALUE b = ibf_load_object(load, nums->b);
14708 VALUE obj = header->type == T_COMPLEX ?
14709 rb_complex_new(a, b) : rb_rational_new(a, b);
14710
14711 if (header->internal) rb_obj_hide(obj);
14712 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14713 return obj;
14714}
14715
14716static void
14717ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14718{
14719 ibf_dump_object_string(dump, rb_sym2str(obj));
14720}
14721
14722static VALUE
14723ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14724{
14725 ibf_offset_t reading_pos = offset;
14726
14727 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14728 const long len = (long)ibf_load_small_value(load, &reading_pos);
14729 const char *ptr = load->current_buffer->buff + reading_pos;
14730
14731 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14732 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14733 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14734 }
14735
14736 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14737 return ID2SYM(id);
14738}
14739
14740typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14741static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14742 ibf_dump_object_unsupported, /* T_NONE */
14743 ibf_dump_object_unsupported, /* T_OBJECT */
14744 ibf_dump_object_class, /* T_CLASS */
14745 ibf_dump_object_unsupported, /* T_MODULE */
14746 ibf_dump_object_float, /* T_FLOAT */
14747 ibf_dump_object_string, /* T_STRING */
14748 ibf_dump_object_regexp, /* T_REGEXP */
14749 ibf_dump_object_array, /* T_ARRAY */
14750 ibf_dump_object_hash, /* T_HASH */
14751 ibf_dump_object_struct, /* T_STRUCT */
14752 ibf_dump_object_bignum, /* T_BIGNUM */
14753 ibf_dump_object_unsupported, /* T_FILE */
14754 ibf_dump_object_data, /* T_DATA */
14755 ibf_dump_object_unsupported, /* T_MATCH */
14756 ibf_dump_object_complex_rational, /* T_COMPLEX */
14757 ibf_dump_object_complex_rational, /* T_RATIONAL */
14758 ibf_dump_object_unsupported, /* 0x10 */
14759 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14760 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14761 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14762 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14763 ibf_dump_object_unsupported, /* T_FIXNUM */
14764 ibf_dump_object_unsupported, /* T_UNDEF */
14765 ibf_dump_object_unsupported, /* 0x17 */
14766 ibf_dump_object_unsupported, /* 0x18 */
14767 ibf_dump_object_unsupported, /* 0x19 */
14768 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14769 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14770 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14771 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14772 ibf_dump_object_unsupported, /* 0x1e */
14773 ibf_dump_object_unsupported, /* 0x1f */
14774};
14775
14776static void
14777ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14778{
14779 unsigned char byte =
14780 (header.type << 0) |
14781 (header.special_const << 5) |
14782 (header.frozen << 6) |
14783 (header.internal << 7);
14784
14785 IBF_WV(byte);
14786}
14787
14788static struct ibf_object_header
14789ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14790{
14791 unsigned char byte = ibf_load_byte(load, offset);
14792
14793 struct ibf_object_header header;
14794 header.type = (byte >> 0) & 0x1f;
14795 header.special_const = (byte >> 5) & 0x01;
14796 header.frozen = (byte >> 6) & 0x01;
14797 header.internal = (byte >> 7) & 0x01;
14798
14799 return header;
14800}
14801
14802static ibf_offset_t
14803ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14804{
14805 struct ibf_object_header obj_header;
14806 ibf_offset_t current_offset;
14807 IBF_ZERO(obj_header);
14808 obj_header.type = TYPE(obj);
14809
14810 IBF_W_ALIGN(ibf_offset_t);
14811 current_offset = ibf_dump_pos(dump);
14812
14813 if (SPECIAL_CONST_P(obj) &&
14814 ! (SYMBOL_P(obj) ||
14815 RB_FLOAT_TYPE_P(obj))) {
14816 obj_header.special_const = TRUE;
14817 obj_header.frozen = TRUE;
14818 obj_header.internal = TRUE;
14819 ibf_dump_object_object_header(dump, obj_header);
14820 ibf_dump_write_small_value(dump, obj);
14821 }
14822 else {
14823 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14824 obj_header.special_const = FALSE;
14825 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14826 ibf_dump_object_object_header(dump, obj_header);
14827 (*dump_object_functions[obj_header.type])(dump, obj);
14828 }
14829
14830 return current_offset;
14831}
14832
14833typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14834static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14835 ibf_load_object_unsupported, /* T_NONE */
14836 ibf_load_object_unsupported, /* T_OBJECT */
14837 ibf_load_object_class, /* T_CLASS */
14838 ibf_load_object_unsupported, /* T_MODULE */
14839 ibf_load_object_float, /* T_FLOAT */
14840 ibf_load_object_string, /* T_STRING */
14841 ibf_load_object_regexp, /* T_REGEXP */
14842 ibf_load_object_array, /* T_ARRAY */
14843 ibf_load_object_hash, /* T_HASH */
14844 ibf_load_object_struct, /* T_STRUCT */
14845 ibf_load_object_bignum, /* T_BIGNUM */
14846 ibf_load_object_unsupported, /* T_FILE */
14847 ibf_load_object_data, /* T_DATA */
14848 ibf_load_object_unsupported, /* T_MATCH */
14849 ibf_load_object_complex_rational, /* T_COMPLEX */
14850 ibf_load_object_complex_rational, /* T_RATIONAL */
14851 ibf_load_object_unsupported, /* 0x10 */
14852 ibf_load_object_unsupported, /* T_NIL */
14853 ibf_load_object_unsupported, /* T_TRUE */
14854 ibf_load_object_unsupported, /* T_FALSE */
14855 ibf_load_object_symbol,
14856 ibf_load_object_unsupported, /* T_FIXNUM */
14857 ibf_load_object_unsupported, /* T_UNDEF */
14858 ibf_load_object_unsupported, /* 0x17 */
14859 ibf_load_object_unsupported, /* 0x18 */
14860 ibf_load_object_unsupported, /* 0x19 */
14861 ibf_load_object_imemo, /* T_IMEMO 0x1a */
14862 ibf_load_object_unsupported, /* T_NODE 0x1b */
14863 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14864 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14865 ibf_load_object_unsupported, /* 0x1e */
14866 ibf_load_object_unsupported, /* 0x1f */
14867};
14868
14869static VALUE
14870ibf_load_object(const struct ibf_load *load, VALUE object_index)
14871{
14872 if (object_index == 0) {
14873 return Qnil;
14874 }
14875 else {
14876 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14877 if (!obj) {
14878 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14879 ibf_offset_t offset = offsets[object_index];
14880 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14881
14882#if IBF_ISEQ_DEBUG
14883 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14884 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14885 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14886 header.type, header.special_const, header.frozen, header.internal);
14887#endif
14888 if (offset >= load->current_buffer->size) {
14889 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14890 }
14891
14892 if (header.special_const) {
14893 ibf_offset_t reading_pos = offset;
14894
14895 obj = ibf_load_small_value(load, &reading_pos);
14896 }
14897 else {
14898 obj = (*load_object_functions[header.type])(load, &header, offset);
14899 }
14900
14901 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14902 }
14903#if IBF_ISEQ_DEBUG
14904 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14905 object_index, obj);
14906#endif
14907 return obj;
14908 }
14909}
14910
14912{
14913 struct ibf_dump *dump;
14914 VALUE offset_list;
14915};
14916
14917static int
14918ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14919{
14920 VALUE obj = (VALUE)key;
14921 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14922
14923 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14924 rb_ary_push(args->offset_list, UINT2NUM(offset));
14925
14926 return ST_CONTINUE;
14927}
14928
14929static void
14930ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14931{
14932 st_table *obj_table = dump->current_buffer->obj_table;
14933 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14934
14935 struct ibf_dump_object_list_arg args;
14936 args.dump = dump;
14937 args.offset_list = offset_list;
14938
14939 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14940
14941 IBF_W_ALIGN(ibf_offset_t);
14942 *obj_list_offset = ibf_dump_pos(dump);
14943
14944 st_index_t size = obj_table->num_entries;
14945 st_index_t i;
14946
14947 for (i=0; i<size; i++) {
14948 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14949 IBF_WV(offset);
14950 }
14951
14952 *obj_list_size = (unsigned int)size;
14953}
14954
14955static void
14956ibf_dump_mark(void *ptr)
14957{
14958 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14959 rb_gc_mark(dump->global_buffer.str);
14960
14961 rb_mark_set(dump->global_buffer.obj_table);
14962 rb_mark_set(dump->iseq_table);
14963}
14964
14965static void
14966ibf_dump_free(void *ptr)
14967{
14968 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14969 if (dump->global_buffer.obj_table) {
14970 st_free_table(dump->global_buffer.obj_table);
14971 dump->global_buffer.obj_table = 0;
14972 }
14973 if (dump->iseq_table) {
14974 st_free_table(dump->iseq_table);
14975 dump->iseq_table = 0;
14976 }
14977}
14978
14979static size_t
14980ibf_dump_memsize(const void *ptr)
14981{
14982 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14983 size_t size = 0;
14984 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14985 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14986 return size;
14987}
14988
14989static const rb_data_type_t ibf_dump_type = {
14990 "ibf_dump",
14991 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14992 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
14993};
14994
14995static void
14996ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14997{
14998 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14999 dump->iseq_table = NULL;
15000
15001 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
15002 dump->global_buffer.obj_table = ibf_dump_object_table_new();
15003 dump->iseq_table = st_init_numtable(); /* need free */
15004
15005 dump->current_buffer = &dump->global_buffer;
15006}
15007
15008static VALUE
15009iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
15010{
15011 struct ibf_header header = {{0}};
15012
15013 ibf_dump_write(dump, &header, sizeof(header));
15014 ibf_dump_iseq(dump, iseq);
15015
15016 header.magic[0] = 'Y'; /* YARB */
15017 header.magic[1] = 'A';
15018 header.magic[2] = 'R';
15019 header.magic[3] = 'B';
15020 header.major_version = IBF_MAJOR_VERSION;
15021 header.minor_version = IBF_MINOR_VERSION;
15022 header.endian = IBF_ENDIAN_MARK;
15023 header.wordsize = (uint8_t)SIZEOF_VALUE;
15024 ibf_dump_iseq_list(dump, &header);
15025 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
15026 header.size = ibf_dump_pos(dump);
15027
15028 if (RTEST(opt)) {
15029 VALUE opt_str = opt;
15030 const char *ptr = StringValuePtr(opt_str);
15031 header.extra_size = RSTRING_LENINT(opt_str);
15032 ibf_dump_write(dump, ptr, header.extra_size);
15033 }
15034 else {
15035 header.extra_size = 0;
15036 }
15037
15038 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15039
15040 return dump->global_buffer.str;
15041}
15042
15043VALUE
15044rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15045{
15046 struct ibf_dump *dump;
15047 VALUE dump_obj;
15048 VALUE str;
15049
15050 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15051 ISEQ_BODY(iseq)->local_iseq != iseq) {
15052 rb_raise(rb_eRuntimeError, "should be top of iseq");
15053 }
15054 if (RTEST(ISEQ_COVERAGE(iseq))) {
15055 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15056 }
15057
15058 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15059 ibf_dump_setup(dump, dump_obj);
15060
15061 str = iseq_ibf_dump_0(dump, iseq, opt);
15062 RB_GC_GUARD(dump_obj);
15063 return str;
15064}
15065
15066static const ibf_offset_t *
15067ibf_iseq_list(const struct ibf_load *load)
15068{
15069 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15070}
15071
15072void
15073rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15074{
15075 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15076 rb_iseq_t *prev_src_iseq = load->iseq;
15077 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15078 load->iseq = iseq;
15079#if IBF_ISEQ_DEBUG
15080 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15081 iseq->aux.loader.index, offset,
15082 load->header->size);
15083#endif
15084 ibf_load_iseq_each(load, iseq, offset);
15085 ISEQ_COMPILE_DATA_CLEAR(iseq);
15086 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15087 rb_iseq_init_trace(iseq);
15088 load->iseq = prev_src_iseq;
15089}
15090
15091#if USE_LAZY_LOAD
15092const rb_iseq_t *
15093rb_iseq_complete(const rb_iseq_t *iseq)
15094{
15095 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15096 return iseq;
15097}
15098#endif
15099
15100static rb_iseq_t *
15101ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15102{
15103 int iseq_index = (int)(VALUE)index_iseq;
15104
15105#if IBF_ISEQ_DEBUG
15106 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15107 (void *)index_iseq, (void *)load->iseq_list);
15108#endif
15109 if (iseq_index == -1) {
15110 return NULL;
15111 }
15112 else {
15113 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15114
15115#if IBF_ISEQ_DEBUG
15116 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15117#endif
15118 if (iseqv) {
15119 return (rb_iseq_t *)iseqv;
15120 }
15121 else {
15122 rb_iseq_t *iseq = iseq_imemo_alloc();
15123#if IBF_ISEQ_DEBUG
15124 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15125#endif
15126 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15127 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15128 iseq->aux.loader.index = iseq_index;
15129#if IBF_ISEQ_DEBUG
15130 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15131 (void *)iseq, (void *)load->loader_obj, iseq_index);
15132#endif
15133 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15134
15135 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15136#if IBF_ISEQ_DEBUG
15137 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15138#endif
15139 rb_ibf_load_iseq_complete(iseq);
15140 }
15141
15142#if IBF_ISEQ_DEBUG
15143 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15144 (void *)iseq, (void *)load->iseq);
15145#endif
15146 return iseq;
15147 }
15148 }
15149}
15150
15151static void
15152ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15153{
15154 struct ibf_header *header = (struct ibf_header *)bytes;
15155 load->loader_obj = loader_obj;
15156 load->global_buffer.buff = bytes;
15157 load->header = header;
15158 load->global_buffer.size = header->size;
15159 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15160 load->global_buffer.obj_list_size = header->global_object_list_size;
15161 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15162 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15163 load->iseq = NULL;
15164
15165 load->current_buffer = &load->global_buffer;
15166
15167 if (size < header->size) {
15168 rb_raise(rb_eRuntimeError, "broken binary format");
15169 }
15170 if (strncmp(header->magic, "YARB", 4) != 0) {
15171 rb_raise(rb_eRuntimeError, "unknown binary format");
15172 }
15173 if (header->major_version != IBF_MAJOR_VERSION ||
15174 header->minor_version != IBF_MINOR_VERSION) {
15175 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15176 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15177 }
15178 if (header->endian != IBF_ENDIAN_MARK) {
15179 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15180 }
15181 if (header->wordsize != SIZEOF_VALUE) {
15182 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15183 }
15184 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15185 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15186 header->iseq_list_offset);
15187 }
15188 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15189 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15190 load->global_buffer.obj_list_offset);
15191 }
15192}
15193
15194static void
15195ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15196{
15197 StringValue(str);
15198
15199 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15200 rb_raise(rb_eRuntimeError, "broken binary format");
15201 }
15202
15203 if (USE_LAZY_LOAD) {
15204 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15205 }
15206
15207 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15208 RB_OBJ_WRITE(loader_obj, &load->str, str);
15209}
15210
15211static void
15212ibf_loader_mark(void *ptr)
15213{
15214 struct ibf_load *load = (struct ibf_load *)ptr;
15215 rb_gc_mark(load->str);
15216 rb_gc_mark(load->iseq_list);
15217 rb_gc_mark(load->global_buffer.obj_list);
15218}
15219
15220static void
15221ibf_loader_free(void *ptr)
15222{
15223 struct ibf_load *load = (struct ibf_load *)ptr;
15224 SIZED_FREE(load);
15225}
15226
15227static size_t
15228ibf_loader_memsize(const void *ptr)
15229{
15230 return sizeof(struct ibf_load);
15231}
15232
15233static const rb_data_type_t ibf_load_type = {
15234 "ibf_loader",
15235 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15236 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15237};
15238
15239const rb_iseq_t *
15240rb_iseq_ibf_load(VALUE str)
15241{
15242 struct ibf_load *load;
15243 rb_iseq_t *iseq;
15244 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15245
15246 ibf_load_setup(load, loader_obj, str);
15247 iseq = ibf_load_iseq(load, 0);
15248
15249 RB_GC_GUARD(loader_obj);
15250 return iseq;
15251}
15252
15253const rb_iseq_t *
15254rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15255{
15256 struct ibf_load *load;
15257 rb_iseq_t *iseq;
15258 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15259
15260 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15261 iseq = ibf_load_iseq(load, 0);
15262
15263 RB_GC_GUARD(loader_obj);
15264 return iseq;
15265}
15266
15267/* collect the iseq table into an array indexed by iseq-list index */
15268static int
15269ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15270{
15271 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15272 srcs[(int)val] = (const rb_iseq_t *)key;
15273 return ST_CONTINUE;
15274}
15275
15276/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15277 * source by list index */
15278static void
15279iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15280{
15281 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15282 VALUE srcs_buf;
15283 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15284 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15285
15286 for (unsigned int i = 0; i < iseq_count; i++) {
15287 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15288 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15289 if (pc2branchindex != Qnil) {
15290 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15291 }
15292 }
15293
15294 ALLOCV_END(srcs_buf);
15295}
15296
15297/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15298const rb_iseq_t *
15299rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15300{
15301 struct ibf_dump *dump;
15302 VALUE dump_obj;
15303 VALUE str;
15304
15305 /* --- dump the subtree --- */
15306 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15307 ibf_dump_setup(dump, dump_obj);
15308
15309 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15310
15311 /* --- load it back --- */
15312 struct ibf_load *load;
15313 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15314 ibf_load_setup(load, loader_obj, str);
15315
15316 /* What the loader could not reconstruct is the same for every iseq in
15317 * the subtree: the only absent parent is the top's, every absent
15318 * local_iseq is the source's local root (runtime walks compare it
15319 * against the original frames, so a copy must not stand in), and
15320 * pathobj/script_lines/coverage are per-file values. */
15321 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15322 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15323 const rb_iseq_t *result = NULL;
15324 for (unsigned int i = 0; i < iseq_count; i++) {
15325 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15326 /* force completion even under USE_LAZY_LOAD */
15327 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15328 rb_ibf_load_iseq_complete(copy);
15329 }
15330
15331 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15332
15333 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15334 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15335 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15336 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15337 VALUE cov = ISEQ_COVERAGE(src_root);
15338 if (!NIL_P(sl) || !NIL_P(cov)) {
15339 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15340 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15341 RB_OBJ_WRITE(copy, &v->coverage, cov);
15342 }
15343
15344 if (i == 0) {
15345 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15346 result = copy;
15347 }
15348
15349 /* Shared across Ractors through the Proc#refined memo; the duplicated
15350 * subtree is self-contained, so mark each copy shareable. */
15352 }
15353
15354 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15355 iseq_subtree_copy_pc2branchindex(dump, load);
15356 }
15357
15358 RB_GC_GUARD(dump_obj);
15359 RB_GC_GUARD(loader_obj);
15360 return result;
15361}
15362
15363VALUE
15364rb_iseq_ibf_load_extra_data(VALUE str)
15365{
15366 struct ibf_load *load;
15367 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15368 VALUE extra_str;
15369
15370 ibf_load_setup(load, loader_obj, str);
15371 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15372 RB_GC_GUARD(loader_obj);
15373 return extra_str;
15374}
15375
15376#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:1473
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1460
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1463
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1476
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:691
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1461
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:1477
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1465
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1480
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:103
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
VALUE rb_cHash
Hash class.
Definition hash.c:123
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c: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)
Same as RB_OBJ_FREEZE(), but returns the given object.
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:481
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:469
#define RB_POSFIXABLE(_)
Checks if the passed value is in range of fixnum, assuming it is a positive number.
Definition fixnum.h:43
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:33
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:550
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:568
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:532
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1235
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1259
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c: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:3898
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1783
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4261
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4247
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3666
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:2041
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3864
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4315
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4135
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3376
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:518
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:1129
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:1091
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SET_SHAREABLE(obj)
Wrapper of rb_obj_set_shareable().
Definition ractor.h:290
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:255
static VALUE RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
Freezes and marks the object as shareable.
Definition ractor.h:301
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1933
#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:9170
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:31
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:367
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:287
Definition vm_core.h:290
Definition iseq.h:338
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:242
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:249
Definition st.h:79
Definition vm_core.h:299
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145