Ruby 4.1.0dev (2026-09-05 revision a946c1bd8e5e7e03e938fe5bb4df942affa95ec6)
compile.c (a946c1bd8e5e7e03e938fe5bb4df942affa95ec6)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/coverage.h"
25#include "internal/complex.h"
26#include "internal/encoding.h"
27#include "internal/error.h"
28#include "internal/gc.h"
29#include "internal/hash.h"
30#include "internal/io.h"
31#include "internal/numeric.h"
32#include "internal/object.h"
33#include "internal/rational.h"
34#include "internal/re.h"
35#include "internal/ruby_parser.h"
36#include "internal/symbol.h"
37#include "internal/thread.h"
38#include "internal/variable.h"
39#include "iseq.h"
40#include "ruby/ractor.h"
41#include "ruby/re.h"
42#include "ruby/util.h"
43#include "vm_core.h"
44#include "vm_callinfo.h"
45#include "vm_debug.h"
46#include "yjit.h"
47
48#include "builtin.h"
49#include "insns.inc"
50#include "insns_info.inc"
51
52#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
53
54typedef struct iseq_link_element {
55 enum {
56 ISEQ_ELEMENT_ANCHOR,
57 ISEQ_ELEMENT_LABEL,
58 ISEQ_ELEMENT_INSN,
59 ISEQ_ELEMENT_ADJUST,
60 ISEQ_ELEMENT_TRACE,
61 } type;
62 struct iseq_link_element *next;
63 struct iseq_link_element *prev;
65
66typedef struct iseq_link_anchor {
67 LINK_ELEMENT anchor;
68 LINK_ELEMENT *last;
70
71typedef enum {
72 LABEL_RESCUE_NONE,
73 LABEL_RESCUE_BEG,
74 LABEL_RESCUE_END,
75 LABEL_RESCUE_TYPE_MAX
76} LABEL_RESCUE_TYPE;
77
78typedef struct iseq_label_data {
79 LINK_ELEMENT link;
80 int label_no;
81 int position;
82 int sc_state;
83 int sp;
84 int refcnt;
85 unsigned int set: 1;
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
88} LABEL;
89
90typedef struct iseq_insn_data {
91 LINK_ELEMENT link;
92 enum ruby_vminsn_type insn_id;
93 int operand_size;
94 int sc_state;
95 VALUE *operands;
96 struct {
97 int line_no;
98 int node_id;
99 rb_event_flag_t events;
100 } insn_info;
101} INSN;
102
103typedef struct iseq_adjust_data {
104 LINK_ELEMENT link;
105 LABEL *label;
106 int line_no;
107} ADJUST;
108
109typedef struct iseq_trace_data {
110 LINK_ELEMENT link;
111 rb_event_flag_t event;
112 long data;
113} TRACE;
114
116 LABEL *begin;
117 LABEL *end;
118 struct ensure_range *next;
119};
120
122 const void *ensure_node;
124 struct ensure_range *erange;
125};
126
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
128
142#ifndef CPDEBUG
143#define CPDEBUG 0
144#endif
145
146#if CPDEBUG >= 0
147#define compile_debug CPDEBUG
148#else
149#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
150#endif
151
152#if CPDEBUG
153
154#define compile_debug_print_indent(level) \
155 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156
157#define debugp(header, value) (void) \
158 (compile_debug_print_indent(1) && \
159 ruby_debug_print_value(1, compile_debug, (header), (value)))
160
161#define debugi(header, id) (void) \
162 (compile_debug_print_indent(1) && \
163 ruby_debug_print_id(1, compile_debug, (header), (id)))
164
165#define debugp_param(header, value) (void) \
166 (compile_debug_print_indent(1) && \
167 ruby_debug_print_value(1, compile_debug, (header), (value)))
168
169#define debugp_verbose(header, value) (void) \
170 (compile_debug_print_indent(2) && \
171 ruby_debug_print_value(2, compile_debug, (header), (value)))
172
173#define debugp_verbose_node(header, value) (void) \
174 (compile_debug_print_indent(10) && \
175 ruby_debug_print_value(10, compile_debug, (header), (value)))
176
177#define debug_node_start(node) ((void) \
178 (compile_debug_print_indent(1) && \
179 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
180 gl_node_level++)
181
182#define debug_node_end() gl_node_level --
183
184#else
185
186#define debugi(header, id) ((void)0)
187#define debugp(header, value) ((void)0)
188#define debugp_verbose(header, value) ((void)0)
189#define debugp_verbose_node(header, value) ((void)0)
190#define debugp_param(header, value) ((void)0)
191#define debug_node_start(node) ((void)0)
192#define debug_node_end() ((void)0)
193#endif
194
195#if CPDEBUG > 1 || CPDEBUG < 0
196#undef printf
197#define printf ruby_debug_printf
198#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#else
201#define debugs if(0)printf
202#define debug_compile(msg, v) (v)
203#endif
204
205#define LVAR_ERRINFO (1)
206
207/* create new label */
208#define NEW_LABEL(l) new_label_body(iseq, (l))
209#define LABEL_FORMAT "<L%03d>"
210
211#define NEW_ISEQ(node, name, type, line_no) \
212 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213
214#define NEW_CHILD_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216
217#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
218 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
219
220/* add instructions */
221#define ADD_SEQ(seq1, seq2) \
222 APPEND_LIST((seq1), (seq2))
223
224/* add an instruction */
225#define ADD_INSN(seq, line_node, insn) \
226 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
227
228/* add an instruction with the given line number and node id */
229#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
230 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
231
232/* insert an instruction before next */
233#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
234 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
235
236/* insert an instruction after prev */
237#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
238 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
239
240/* add an instruction with some operands (1, 2, 3, 5) */
241#define ADD_INSN1(seq, line_node, insn, op1) \
242 ADD_ELEM((seq), (LINK_ELEMENT *) \
243 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
244
245/* insert an instruction with some operands (1, 2, 3, 5) before next */
246#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
247 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
248 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
249
250/* insert an instruction with some operands (1, 2, 3, 5) after prev */
251#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
252 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
253 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
254
255#define LABEL_REF(label) ((label)->refcnt++)
256
257/* add an instruction with label operand (alias of ADD_INSN1) */
258#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
259
260#define ADD_INSN2(seq, line_node, insn, op1, op2) \
261 ADD_ELEM((seq), (LINK_ELEMENT *) \
262 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
263
264#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
265 ADD_ELEM((seq), (LINK_ELEMENT *) \
266 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
267
268/* Specific Insn factory */
269#define ADD_SEND(seq, line_node, id, argc) \
270 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
271
272#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
273 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
274
275#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
276 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
277
278#define ADD_CALL_RECEIVER(seq, line_node) \
279 ADD_INSN((seq), (line_node), putself)
280
281#define ADD_CALL(seq, line_node, id, argc) \
282 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
283
284#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
285 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
286
287#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
288 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
289
290#define ADD_TRACE(seq, event) \
291 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
292#define ADD_TRACE_WITH_DATA(seq, event, data) \
293 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
294
295static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
297
298#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
299#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
300
301/* add label */
302#define ADD_LABEL(seq, label) \
303 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
304
305#define APPEND_LABEL(seq, before, label) \
306 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
307
308#define ADD_ADJUST(seq, line_node, label) \
309 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
310
311#define ADD_ADJUST_RESTORE(seq, label) \
312 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
313
314#define LABEL_UNREMOVABLE(label) \
315 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
316#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
317 VALUE _e = rb_ary_new3(5, (type), \
318 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
319 (VALUE)(iseqv), (VALUE)(lc) | 1); \
320 LABEL_UNREMOVABLE(ls); \
321 LABEL_REF(le); \
322 LABEL_REF(lc); \
323 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
324 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
325 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
326} while (0)
327
328/* compile node */
329#define COMPILE(anchor, desc, node) \
330 (debug_compile("== " desc "\n", \
331 iseq_compile_each(iseq, (anchor), (node), 0)))
332
333/* compile node, this node's value will be popped */
334#define COMPILE_POPPED(anchor, desc, node) \
335 (debug_compile("== " desc "\n", \
336 iseq_compile_each(iseq, (anchor), (node), 1)))
337
338/* compile node, which is popped when 'popped' is true */
339#define COMPILE_(anchor, desc, node, popped) \
340 (debug_compile("== " desc "\n", \
341 iseq_compile_each(iseq, (anchor), (node), (popped))))
342
343#define COMPILE_RECV(anchor, desc, node, recv) \
344 (private_recv_p(node) ? \
345 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
346 COMPILE(anchor, desc, recv) ? 0 : -1)
347
348#define OPERAND_AT(insn, idx) \
349 (((INSN*)(insn))->operands[(idx)])
350
351#define INSN_OF(insn) \
352 (((INSN*)(insn))->insn_id)
353
354#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
355#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
356#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
357#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
358#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
359#define IS_NEXT_INSN_ID(link, insn) \
360 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
361#define IS_NEXT_NEXT_INSN_ID(link, insn) \
362 ((link)->next && IS_NEXT_INSN_ID((link)->next, insn))
363
364static inline bool
365IS_INDEPENDENT_INSN(LINK_ELEMENT *link)
366{
367 if (!IS_INSN(link)) {
368 return false;
369 }
370
371 enum ruby_vminsn_type type = INSN_OF(link);
372
373 return (
374 type == BIN(putobject) ||
375 type == BIN(putspecialobject) ||
376 type == BIN(putnil) ||
377 type == BIN(putself) ||
378 type == BIN(duphash) ||
379 type == BIN(getinstancevariable) ||
380 type == BIN(getlocal) ||
381 type == BIN(opt_getconstant_path)
382 );
383}
384
385/* error */
386#if CPDEBUG > 0
388#endif
389RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
390static void
391append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
392{
393 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
394 VALUE file = rb_iseq_path(iseq);
395 VALUE err = err_info == Qtrue ? Qfalse : err_info;
396 va_list args;
397
398 va_start(args, fmt);
399 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
400 va_end(args);
401 if (NIL_P(err_info)) {
402 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
403 rb_set_errinfo(err);
404 }
405 else if (!err_info) {
406 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
407 }
408 if (compile_debug) {
409 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
410 rb_exc_fatal(err);
411 }
412}
413
414#if 0
415static void
416compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
417{
418 va_list args;
419 va_start(args, fmt);
420 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
421 va_end(args);
422 abort();
423}
424#endif
425
426#define COMPILE_ERROR append_compile_error
427
428#define ERROR_ARGS_AT(n) iseq, nd_line(n),
429#define ERROR_ARGS ERROR_ARGS_AT(node)
430
431#define EXPECT_NODE(prefix, node, ndtype, errval) \
432do { \
433 const NODE *error_node = (node); \
434 enum node_type error_type = nd_type(error_node); \
435 if (error_type != (ndtype)) { \
436 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
437 prefix ": " #ndtype " is expected, but %s", \
438 ruby_node_name(error_type)); \
439 return errval; \
440 } \
441} while (0)
442
443#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
444do { \
445 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
446 prefix ": must be " #ndtype ", but 0"); \
447 return errval; \
448} while (0)
449
450#define UNKNOWN_NODE(prefix, node, errval) \
451do { \
452 const NODE *error_node = (node); \
453 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
454 ruby_node_name(nd_type(error_node))); \
455 return errval; \
456} while (0)
457
458#define COMPILE_OK 1
459#define COMPILE_NG 0
460
461#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
462#define NO_CHECK(sub) (void)(sub)
463#define BEFORE_RETURN
464
465#define DECL_ANCHOR(name) \
466 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
467#define INIT_ANCHOR(name) \
468 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
469
470static inline VALUE
471freeze_hide_obj(VALUE obj)
472{
473 OBJ_FREEZE(obj);
474 RBASIC_CLEAR_CLASS(obj);
475 return obj;
476}
477
478#include "optinsn.inc"
479#if OPT_INSTRUCTIONS_UNIFICATION
480#include "optunifs.inc"
481#endif
482
483/* for debug */
484#if CPDEBUG < 0
485#define ISEQ_ARG iseq,
486#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
487#else
488#define ISEQ_ARG
489#define ISEQ_ARG_DECLARE
490#endif
491
492#if CPDEBUG
493#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
494#endif
495
496static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
497static void dump_disasm_list(const LINK_ELEMENT *elem);
498
499static int insn_data_length(INSN *iobj);
500static int calc_sp_depth(int depth, INSN *iobj);
501
502static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
503static LABEL *new_label_body(rb_iseq_t *iseq, long line);
504static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
505static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
506
507
508static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
509static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
510static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
511static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
512static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
513
514static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
515static int iseq_set_exception_local_table(rb_iseq_t *iseq);
516static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
517
518static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
519static int iseq_set_exception_table(rb_iseq_t *iseq);
520static int iseq_set_optargs_table(rb_iseq_t *iseq);
521static int iseq_set_parameters_lvar_state(const rb_iseq_t *iseq);
522
523static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
524static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
525
526/*
527 * To make Array to LinkedList, use link_anchor
528 */
529
530static void
531verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
532{
533#if CPDEBUG
534 int flag = 0;
535 LINK_ELEMENT *list, *plist;
536
537 if (!compile_debug) return;
538
539 list = anchor->anchor.next;
540 plist = &anchor->anchor;
541 while (list) {
542 if (plist != list->prev) {
543 flag += 1;
544 }
545 plist = list;
546 list = list->next;
547 }
548
549 if (anchor->last != plist && anchor->last != 0) {
550 flag |= 0x70000;
551 }
552
553 if (flag != 0) {
554 rb_bug("list verify error: %08x (%s)", flag, info);
555 }
556#endif
557}
558#if CPDEBUG < 0
559#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
560#endif
561
562static void
563verify_call_cache(rb_iseq_t *iseq)
564{
565#if CPDEBUG
566 VALUE *original = rb_iseq_original_iseq(iseq);
567 size_t i = 0;
568 while (i < ISEQ_BODY(iseq)->iseq_size) {
569 VALUE insn = original[i];
570 const char *types = insn_op_types(insn);
571
572 for (int j=0; types[j]; j++) {
573 if (types[j] == TS_CALLDATA) {
574 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
575 const struct rb_callinfo *ci = cd->ci;
576 const struct rb_callcache *cc = cd->cc;
577 if (cc != vm_cc_empty()) {
578 vm_ci_dump(ci);
579 rb_bug("call cache is not initialized by vm_cc_empty()");
580 }
581 }
582 }
583 i += insn_len(insn);
584 }
585
586 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
587 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
588 const struct rb_callinfo *ci = cd->ci;
589 const struct rb_callcache *cc = cd->cc;
590 if (cc != NULL && cc != vm_cc_empty()) {
591 vm_ci_dump(ci);
592 rb_bug("call cache is not initialized by vm_cc_empty()");
593 }
594 }
595#endif
596}
597
598/*
599 * elem1, elem2 => elem1, elem2, elem
600 */
601static void
602ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
603{
604 elem->prev = anchor->last;
605 anchor->last->next = elem;
606 anchor->last = elem;
607 verify_list("add", anchor);
608}
609
610/*
611 * elem1, before, elem2 => elem1, before, elem, elem2
612 */
613static void
614APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
615{
616 elem->prev = before;
617 elem->next = before->next;
618 elem->next->prev = elem;
619 before->next = elem;
620 if (before == anchor->last) anchor->last = elem;
621 verify_list("add", anchor);
622}
623#if CPDEBUG < 0
624#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
625#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
626#endif
627
628static int
629branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
630{
631 if (!ISEQ_COVERAGE(iseq)) return 0;
632 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
633 if (first_line <= 0) return 0;
634 return 1;
635}
636
637static VALUE
638setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
639{
640 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
641 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
642 VALUE branch = rb_ary_hidden_new(6);
643
644 rb_hash_aset(structure, key, branch);
645 rb_ary_push(branch, ID2SYM(rb_intern(type)));
646 rb_ary_push(branch, INT2FIX(first_lineno));
647 rb_ary_push(branch, INT2FIX(first_column));
648 rb_ary_push(branch, INT2FIX(last_lineno));
649 rb_ary_push(branch, INT2FIX(last_column));
650 return branch;
651}
652
653static VALUE
654decl_branch_base(rb_iseq_t *iseq, int node_id, const rb_code_location_t *loc, const char *type)
655{
656 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
657
658 /*
659 * A branch base is keyed by [source_hash (in two halves), node_id, first_lineno],
660 * which identifies the branch node stably even across (re-)evals against
661 * the same path.
662 *
663 * if !structure[key]
664 * structure[key] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
665 * else
666 * branches = structure[key][5]
667 * end
668 */
669 uint64_t source_hash = ISEQ_BODY(iseq)->source_hash;
670 VALUE key = rb_ary_new_from_args(4,
671 ULONG2NUM((unsigned long)(source_hash >> 32)),
672 ULONG2NUM((unsigned long)(source_hash & 0xffffffff)),
673 INT2FIX(node_id),
674 INT2FIX(loc->beg_pos.lineno));
675 rb_ary_freeze(key);
676
677 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
678 VALUE branch_base = rb_hash_aref(structure, key);
679 VALUE branches;
680
681 if (NIL_P(branch_base)) {
682 branch_base = setup_branch(loc, type, structure, key);
683 branches = rb_hash_new();
684 rb_obj_hide(branches);
685 rb_ary_push(branch_base, branches);
686 }
687 else {
688 branches = RARRAY_AREF(branch_base, 5);
689 }
690
691 return branches;
692}
693
694static NODE
695generate_dummy_line_node(int lineno, int node_id)
696{
697 NODE dummy = { 0 };
698 nd_set_line(&dummy, lineno);
699 nd_set_node_id(&dummy, node_id);
700 return dummy;
701}
702
703static void
704add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
705{
706 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
707
708 /*
709 * if !branches[branch_id]
710 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
711 * else
712 * counter_idx= branches[branch_id][5]
713 * end
714 */
715
716 VALUE key = INT2FIX(branch_id);
717 VALUE branch = rb_hash_aref(branches, key);
718 long counter_idx;
719
720 if (NIL_P(branch)) {
721 branch = setup_branch(loc, type, branches, key);
722 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
723 counter_idx = RARRAY_LEN(counters);
724 rb_ary_push(branch, LONG2FIX(counter_idx));
725 rb_ary_push(counters, INT2FIX(0));
726 }
727 else {
728 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
729 }
730
731 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
732 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
733}
734
735#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
736
737static int
738validate_label(st_data_t name, st_data_t label, st_data_t arg)
739{
740 rb_iseq_t *iseq = (rb_iseq_t *)arg;
741 LABEL *lobj = (LABEL *)label;
742 if (!lobj->link.next) {
743 do {
744 COMPILE_ERROR(iseq, lobj->position,
745 "%"PRIsVALUE": undefined label",
746 rb_sym2str((VALUE)name));
747 } while (0);
748 }
749 return ST_CONTINUE;
750}
751
752static void
753validate_labels(rb_iseq_t *iseq, st_table *labels_table)
754{
755 st_foreach(labels_table, validate_label, (st_data_t)iseq);
756 st_free_table(labels_table);
757}
758
759static NODE *
760get_nd_recv(const NODE *node)
761{
762 switch (nd_type(node)) {
763 case NODE_CALL:
764 return RNODE_CALL(node)->nd_recv;
765 case NODE_OPCALL:
766 return RNODE_OPCALL(node)->nd_recv;
767 case NODE_FCALL:
768 return 0;
769 case NODE_QCALL:
770 return RNODE_QCALL(node)->nd_recv;
771 case NODE_VCALL:
772 return 0;
773 case NODE_ATTRASGN:
774 return RNODE_ATTRASGN(node)->nd_recv;
775 case NODE_OP_ASGN1:
776 return RNODE_OP_ASGN1(node)->nd_recv;
777 case NODE_OP_ASGN2:
778 return RNODE_OP_ASGN2(node)->nd_recv;
779 default:
780 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
781 }
782}
783
784static ID
785get_node_call_nd_mid(const NODE *node)
786{
787 switch (nd_type(node)) {
788 case NODE_CALL:
789 return RNODE_CALL(node)->nd_mid;
790 case NODE_OPCALL:
791 return RNODE_OPCALL(node)->nd_mid;
792 case NODE_FCALL:
793 return RNODE_FCALL(node)->nd_mid;
794 case NODE_QCALL:
795 return RNODE_QCALL(node)->nd_mid;
796 case NODE_VCALL:
797 return RNODE_VCALL(node)->nd_mid;
798 case NODE_ATTRASGN:
799 return RNODE_ATTRASGN(node)->nd_mid;
800 default:
801 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
802 }
803}
804
805static NODE *
806get_nd_args(const NODE *node)
807{
808 switch (nd_type(node)) {
809 case NODE_CALL:
810 return RNODE_CALL(node)->nd_args;
811 case NODE_OPCALL:
812 return RNODE_OPCALL(node)->nd_args;
813 case NODE_FCALL:
814 return RNODE_FCALL(node)->nd_args;
815 case NODE_QCALL:
816 return RNODE_QCALL(node)->nd_args;
817 case NODE_VCALL:
818 return 0;
819 case NODE_ATTRASGN:
820 return RNODE_ATTRASGN(node)->nd_args;
821 default:
822 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
823 }
824}
825
826static ID
827get_node_colon_nd_mid(const NODE *node)
828{
829 switch (nd_type(node)) {
830 case NODE_COLON2:
831 return RNODE_COLON2(node)->nd_mid;
832 case NODE_COLON3:
833 return RNODE_COLON3(node)->nd_mid;
834 default:
835 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
836 }
837}
838
839static ID
840get_nd_vid(const NODE *node)
841{
842 switch (nd_type(node)) {
843 case NODE_LASGN:
844 return RNODE_LASGN(node)->nd_vid;
845 case NODE_DASGN:
846 return RNODE_DASGN(node)->nd_vid;
847 case NODE_IASGN:
848 return RNODE_IASGN(node)->nd_vid;
849 case NODE_CVASGN:
850 return RNODE_CVASGN(node)->nd_vid;
851 default:
852 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
853 }
854}
855
856static NODE *
857get_nd_value(const NODE *node)
858{
859 switch (nd_type(node)) {
860 case NODE_LASGN:
861 return RNODE_LASGN(node)->nd_value;
862 case NODE_DASGN:
863 return RNODE_DASGN(node)->nd_value;
864 default:
865 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
866 }
867}
868
869static VALUE
870get_string_value(const NODE *node)
871{
872 switch (nd_type(node)) {
873 case NODE_STR:
874 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
875 case NODE_FILE:
876 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
877 default:
878 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
879 }
880}
881
882VALUE
883rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
884{
885 DECL_ANCHOR(ret);
886 INIT_ANCHOR(ret);
887
888 (*ifunc->func)(iseq, ret, ifunc->data);
889
890 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
891
892 CHECK(iseq_setup_insn(iseq, ret));
893 return iseq_setup(iseq, ret);
894}
895
896static bool drop_unreachable_return(LINK_ANCHOR *ret);
897
898VALUE
899rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
900{
901 DECL_ANCHOR(ret);
902 INIT_ANCHOR(ret);
903
904 if (node == 0) {
905 NO_CHECK(COMPILE(ret, "nil", node));
906 iseq_set_local_table(iseq, 0, 0);
907 }
908 /* assume node is T_NODE */
909 else if (nd_type_p(node, NODE_SCOPE)) {
910 /* iseq type of top, method, class, block */
911 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
912 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
913 iseq_set_parameters_lvar_state(iseq);
914
915 switch (ISEQ_BODY(iseq)->type) {
916 case ISEQ_TYPE_BLOCK:
917 {
918 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
919 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
920
921 start->rescued = LABEL_RESCUE_BEG;
922 end->rescued = LABEL_RESCUE_END;
923
924 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
925 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
926 ADD_LABEL(ret, start);
927 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
928 ADD_LABEL(ret, end);
929 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
930 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
931
932 /* wide range catch handler must put at last */
933 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
934 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
935 break;
936 }
937 case ISEQ_TYPE_CLASS:
938 {
939 ADD_TRACE(ret, RUBY_EVENT_CLASS);
940 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
941 ADD_TRACE(ret, RUBY_EVENT_END);
942 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
943 break;
944 }
945 case ISEQ_TYPE_METHOD:
946 {
947 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
948 ADD_TRACE(ret, RUBY_EVENT_CALL);
949 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
950 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
951 ADD_TRACE(ret, RUBY_EVENT_RETURN);
952 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
953 break;
954 }
955 default: {
956 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
957 break;
958 }
959 }
960 }
961 else {
962 const char *m;
963#define INVALID_ISEQ_TYPE(type) \
964 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
965 switch (ISEQ_BODY(iseq)->type) {
966 case INVALID_ISEQ_TYPE(METHOD);
967 case INVALID_ISEQ_TYPE(CLASS);
968 case INVALID_ISEQ_TYPE(BLOCK);
969 case INVALID_ISEQ_TYPE(EVAL);
970 case INVALID_ISEQ_TYPE(MAIN);
971 case INVALID_ISEQ_TYPE(TOP);
972#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
973 case ISEQ_TYPE_RESCUE:
974 iseq_set_exception_local_table(iseq);
975 CHECK(COMPILE(ret, "rescue", node));
976 break;
977 case ISEQ_TYPE_ENSURE:
978 iseq_set_exception_local_table(iseq);
979 CHECK(COMPILE_POPPED(ret, "ensure", node));
980 break;
981 case ISEQ_TYPE_PLAIN:
982 CHECK(COMPILE(ret, "ensure", node));
983 break;
984 default:
985 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
986 return COMPILE_NG;
987 invalid_iseq_type:
988 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
989 return COMPILE_NG;
990 }
991 }
992
993 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
994 NODE dummy_line_node = generate_dummy_line_node(0, -1);
995 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
996 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
997 }
998 else if (!drop_unreachable_return(ret)) {
999 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
1000 }
1001
1002#if OPT_SUPPORT_JOKE
1003 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
1004 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
1005 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
1006 validate_labels(iseq, labels_table);
1007 }
1008#endif
1009 CHECK(iseq_setup_insn(iseq, ret));
1010 return iseq_setup(iseq, ret);
1011}
1012
1013static int
1014rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
1015{
1016#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1017 const void * const *table = rb_vm_get_insns_address_table();
1018 unsigned int i;
1019 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
1020
1021 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1022 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
1023 int len = insn_len(insn);
1024 encoded[i] = (VALUE)table[insn];
1025 i += len;
1026 }
1027 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
1028#endif
1029
1030#if USE_YJIT
1031 rb_yjit_live_iseq_count++;
1032 rb_yjit_iseq_alloc_count++;
1033#endif
1034
1035 return COMPILE_OK;
1036}
1037
1038VALUE *
1039rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1040{
1041 struct rb_iseq_variable *v = ISEQ_VARIABLE(iseq);
1042 VALUE *original_code = v ? RUBY_ATOMIC_PTR_LOAD(v->original_iseq) : NULL;
1043
1044 if (original_code) return original_code;
1045 original_code = ALLOC_N(VALUE, ISEQ_BODY(iseq)->iseq_size);
1046 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1047
1048#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1049 {
1050 unsigned int i;
1051
1052 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1053 const void *addr = (const void *)original_code[i];
1054 const int insn = rb_vm_insn_addr2insn(addr);
1055
1056 original_code[i] = insn;
1057 i += insn_len(insn);
1058 }
1059 }
1060#endif
1061
1062 /* Concurrent callers can each build a copy; publish only fully
1063 * translated code and keep the first one. */
1064 v = rb_iseq_variable_ensure((rb_iseq_t *)iseq);
1065 VALUE *prev = ATOMIC_PTR_CAS(v->original_iseq,
1066 NULL, original_code);
1067 if (prev) {
1068 SIZED_FREE_N(original_code, ISEQ_BODY(iseq)->iseq_size);
1069 return prev;
1070 }
1071 return original_code;
1072}
1073
1074/*********************************************/
1075/* definition of data structure for compiler */
1076/*********************************************/
1077
1078#if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1079# define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1080#else
1081# define ALIGNMENT_SIZE SIZEOF_VALUE
1082#endif
1083#define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1084
1085#define ALIGNMENT_SIZE_OF(type) alignment_size_assert(RUBY_ALIGNOF(type), #type)
1086
1087static inline size_t
1088alignment_size_assert(size_t align, const char *type)
1089{
1090 RUBY_ASSERT((align & (align - 1)) == 0,
1091 "ALIGNMENT_SIZE_OF(%s):%zd == (2 ** N) is expected", type, align);
1092 return align;
1093}
1094
1095/* calculate padding size for aligned memory access */
1096static inline size_t
1097calc_padding(void *ptr, size_t align)
1098{
1099 size_t mis;
1100 size_t padding = 0;
1101
1102 mis = (size_t)ptr & (align - 1);
1103 if (mis > 0) {
1104 padding = align - mis;
1105 }
1106
1107 return padding;
1108}
1109
1110static void *
1111compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size, size_t align)
1112{
1113 void *ptr = 0;
1114 struct iseq_compile_data_storage *storage = *arena;
1115 size_t padding = calc_padding((void *)&storage->buff[storage->pos], align);
1116
1117 if (size >= INT_MAX - padding) rb_memerror();
1118 if (storage->pos + size + padding > storage->size) {
1119 unsigned int alloc_size = storage->size;
1120
1121 while (alloc_size < size + PADDING_SIZE_MAX) {
1122 if (alloc_size >= INT_MAX / 2) rb_memerror();
1123 alloc_size *= 2;
1124 }
1125 storage->next = (void *)ALLOC_N(char, alloc_size +
1126 offsetof(struct iseq_compile_data_storage, buff));
1127 storage = *arena = storage->next;
1128 storage->next = 0;
1129 storage->pos = 0;
1130 storage->size = alloc_size;
1131 padding = calc_padding((void *)&storage->buff[storage->pos], align);
1132 }
1133
1134 storage->pos += (int)padding;
1135
1136 ptr = (void *)&storage->buff[storage->pos];
1137 storage->pos += (int)size;
1138 return ptr;
1139}
1140
1141static void *
1142compile_data_alloc(rb_iseq_t *iseq, size_t size, size_t align)
1143{
1144 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1145 return compile_data_alloc_with_arena(arena, size, align);
1146}
1147
1148#define compile_data_alloc_type(iseq, type) \
1149 (type *)compile_data_alloc(iseq, sizeof(type), ALIGNMENT_SIZE_OF(type))
1150
1151static inline void *
1152compile_data_alloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1153{
1154 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1155 return compile_data_alloc(iseq, size, align);
1156}
1157
1158#define compile_data_alloc2_type(iseq, type, num) \
1159 (type *)compile_data_alloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1160
1161static inline void *
1162compile_data_calloc2(rb_iseq_t *iseq, size_t elsize, size_t num, size_t align)
1163{
1164 size_t size = rb_size_mul_or_raise(elsize, num, rb_eRuntimeError);
1165 void *p = compile_data_alloc(iseq, size, align);
1166 memset(p, 0, size);
1167 return p;
1168}
1169
1170#define compile_data_calloc2_type(iseq, type, num) \
1171 (type *)compile_data_calloc2(iseq, sizeof(type), num, ALIGNMENT_SIZE_OF(type))
1172
1173static INSN *
1174compile_data_alloc_insn(rb_iseq_t *iseq)
1175{
1176 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1177 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN), ALIGNMENT_SIZE_OF(INSN));
1178}
1179
1180static LABEL *
1181compile_data_alloc_label(rb_iseq_t *iseq)
1182{
1183 return compile_data_alloc_type(iseq, LABEL);
1184}
1185
1186static ADJUST *
1187compile_data_alloc_adjust(rb_iseq_t *iseq)
1188{
1189 return compile_data_alloc_type(iseq, ADJUST);
1190}
1191
1192static TRACE *
1193compile_data_alloc_trace(rb_iseq_t *iseq)
1194{
1195 return compile_data_alloc_type(iseq, TRACE);
1196}
1197
1198/*
1199 * elem1, elemX => elem1, elem2, elemX
1200 */
1201static void
1202ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1203{
1204 elem2->next = elem1->next;
1205 elem2->prev = elem1;
1206 elem1->next = elem2;
1207 if (elem2->next) {
1208 elem2->next->prev = elem2;
1209 }
1210}
1211
1212/*
1213 * elem1, elemX => elemX, elem2, elem1
1214 */
1215static void
1216ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1217{
1218 elem2->prev = elem1->prev;
1219 elem2->next = elem1;
1220 elem1->prev = elem2;
1221 if (elem2->prev) {
1222 elem2->prev->next = elem2;
1223 }
1224}
1225
1226/*
1227 * elemX, elem1, elemY => elemX, elem2, elemY
1228 */
1229static void
1230ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1231{
1232 elem2->prev = elem1->prev;
1233 elem2->next = elem1->next;
1234 if (elem1->prev) {
1235 elem1->prev->next = elem2;
1236 }
1237 if (elem1->next) {
1238 elem1->next->prev = elem2;
1239 }
1240}
1241
1242static void
1243ELEM_REMOVE(LINK_ELEMENT *elem)
1244{
1245 elem->prev->next = elem->next;
1246 if (elem->next) {
1247 elem->next->prev = elem->prev;
1248 }
1249}
1250
1251/*
1252 * elem1, elem2 => elem2, elem1
1253 */
1254static void
1255ELEM_SWAP(LINK_ELEMENT *first, LINK_ELEMENT *second)
1256{
1257 RUBY_ASSERT(first->next == second);
1258 RUBY_ASSERT(first == second->prev);
1259
1260 first->prev->next = second;
1261 second->next->prev = first;
1262
1263 first->next = second->next;
1264 second->next = first;
1265
1266 second->prev = first->prev;
1267 first->prev = second;
1268}
1269
1270static LINK_ELEMENT *
1271FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1272{
1273 return anchor->anchor.next;
1274}
1275
1276static LINK_ELEMENT *
1277LAST_ELEMENT(LINK_ANCHOR *const anchor)
1278{
1279 return anchor->last;
1280}
1281
1282static LINK_ELEMENT *
1283ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1284{
1285 while (elem) {
1286 switch (elem->type) {
1287 case ISEQ_ELEMENT_INSN:
1288 case ISEQ_ELEMENT_ADJUST:
1289 return elem;
1290 default:
1291 elem = elem->next;
1292 }
1293 }
1294 return NULL;
1295}
1296
1297static int
1298LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1299{
1300 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1301 if (first_insn != NULL &&
1302 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1303 return TRUE;
1304 }
1305 else {
1306 return FALSE;
1307 }
1308}
1309
1310static int
1311LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1312{
1313 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1314 return TRUE;
1315 }
1316 else {
1317 return FALSE;
1318 }
1319}
1320
1321/*
1322 * anc1: e1, e2, e3
1323 * anc2: e4, e5
1324 *#=>
1325 * anc1: e1, e2, e3, e4, e5
1326 * anc2: e4, e5 (broken)
1327 */
1328static void
1329APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1330{
1331 if (anc2->anchor.next) {
1332 /* LINK_ANCHOR must not loop */
1333 RUBY_ASSERT(anc2->last != &anc2->anchor);
1334 anc1->last->next = anc2->anchor.next;
1335 anc2->anchor.next->prev = anc1->last;
1336 anc1->last = anc2->last;
1337 }
1338 else {
1339 RUBY_ASSERT(anc2->last == &anc2->anchor);
1340 }
1341 verify_list("append", anc1);
1342}
1343#if CPDEBUG < 0
1344#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1345#endif
1346
1347#if CPDEBUG && 0
1348static void
1349debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1350{
1351 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1352 printf("----\n");
1353 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1354 (void *)anchor->anchor.next, (void *)anchor->last);
1355 while (list) {
1356 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1357 (void *)list->prev, (int)list->type);
1358 list = list->next;
1359 }
1360 printf("----\n");
1361
1362 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1363 verify_list("debug list", anchor);
1364}
1365#if CPDEBUG < 0
1366#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1367#endif
1368#else
1369#define debug_list(anc, cur) ((void)0)
1370#endif
1371
1372static TRACE *
1373new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1374{
1375 TRACE *trace = compile_data_alloc_trace(iseq);
1376
1377 trace->link.type = ISEQ_ELEMENT_TRACE;
1378 trace->link.next = NULL;
1379 trace->event = event;
1380 trace->data = data;
1381
1382 return trace;
1383}
1384
1385static LABEL *
1386new_label_body(rb_iseq_t *iseq, long line)
1387{
1388 LABEL *labelobj = compile_data_alloc_label(iseq);
1389
1390 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1391 labelobj->link.next = 0;
1392
1393 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1394 labelobj->sc_state = 0;
1395 labelobj->sp = -1;
1396 labelobj->refcnt = 0;
1397 labelobj->set = 0;
1398 labelobj->rescued = LABEL_RESCUE_NONE;
1399 labelobj->unremovable = 0;
1400 labelobj->position = -1;
1401 return labelobj;
1402}
1403
1404static ADJUST *
1405new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1406{
1407 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1408 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1409 adjust->link.next = 0;
1410 adjust->label = label;
1411 adjust->line_no = line;
1412 LABEL_UNREMOVABLE(label);
1413 return adjust;
1414}
1415
1416static void
1417iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1418{
1419 const char *types = insn_op_types(insn->insn_id);
1420 for (int j = 0; types[j]; j++) {
1421 char type = types[j];
1422 switch (type) {
1423 case TS_CDHASH:
1424 case TS_ISEQ:
1425 case TS_VALUE:
1426 case TS_IC: // constant path array
1427 case TS_CALLDATA: // ci is stored.
1428 func(&OPERAND_AT(insn, j), data);
1429 break;
1430 default:
1431 break;
1432 }
1433 }
1434}
1435
1436static void
1437iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1438{
1439 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1441 RBASIC_CLASS(*obj) == 0 || // hidden
1442 RB_OBJ_SHAREABLE_P(*obj));
1443}
1444
1445static INSN *
1446new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1447{
1448 INSN *iobj = compile_data_alloc_insn(iseq);
1449
1450 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1451
1452 iobj->link.type = ISEQ_ELEMENT_INSN;
1453 iobj->link.next = 0;
1454 iobj->insn_id = insn_id;
1455 iobj->insn_info.line_no = line_no;
1456 iobj->insn_info.node_id = node_id;
1457 iobj->insn_info.events = 0;
1458 iobj->operands = argv;
1459 iobj->operand_size = argc;
1460 iobj->sc_state = 0;
1461
1462 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1463
1464 return iobj;
1465}
1466
1467static INSN *
1468new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1469{
1470 VALUE *operands = 0;
1471 va_list argv;
1472 if (argc > 0) {
1473 int i;
1474 va_start(argv, argc);
1475 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1476 for (i = 0; i < argc; i++) {
1477 VALUE v = va_arg(argv, VALUE);
1478 operands[i] = v;
1479 }
1480 va_end(argv);
1481 }
1482 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1483}
1484
1485static INSN *
1486insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1487{
1488 VALUE *operands = 0;
1489 va_list argv;
1490 if (argc > 0) {
1491 int i;
1492 va_start(argv, argc);
1493 operands = compile_data_alloc2_type(iseq, VALUE, argc);
1494 for (i = 0; i < argc; i++) {
1495 VALUE v = va_arg(argv, VALUE);
1496 operands[i] = v;
1497 }
1498 va_end(argv);
1499 }
1500
1501 iobj->insn_id = insn_id;
1502 iobj->operand_size = argc;
1503 iobj->operands = operands;
1504 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1505
1506 return iobj;
1507}
1508
1509static const struct rb_callinfo *
1510new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1511{
1512 VM_ASSERT(argc >= 0);
1513
1514 if (kw_arg) {
1515 flag |= VM_CALL_KWARG;
1516 argc += kw_arg->keyword_len;
1517 }
1518
1519 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1520 && !has_blockiseq) {
1521 flag |= VM_CALL_ARGS_SIMPLE;
1522 }
1523
1524 ISEQ_BODY(iseq)->ci_size++;
1525 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1526 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1527 return ci;
1528}
1529
1530static INSN *
1531new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1532{
1533 VALUE *operands = compile_data_calloc2_type(iseq, VALUE, 2);
1534 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1535 operands[0] = ci;
1536 operands[1] = (VALUE)blockiseq;
1537 if (blockiseq) {
1538 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1539 }
1540
1541 INSN *insn;
1542
1543 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1544 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1545 }
1546 else {
1547 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1548 }
1549
1550 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1551 RB_GC_GUARD(ci);
1552 return insn;
1553}
1554
1555static rb_iseq_t *
1556new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1557 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1558{
1559 rb_iseq_t *ret_iseq;
1560 VALUE ast_value = rb_ruby_ast_new(node);
1561
1562 // The child AST wrapper does not carry the source hash, so copy it from
1563 // the enclosing iseq before compiling, for grandchildren to inherit it.
1564 if (ISEQ_BODY(iseq)->source_hash) {
1565 rb_ast_t *child_ast = rb_ruby_ast_data_get(ast_value);
1566 child_ast->body.source_hash = ISEQ_BODY(iseq)->source_hash;
1567 child_ast->body.has_source_hash = 1;
1568 }
1569
1570 debugs("[new_child_iseq]> ---------------------------------------\n");
1571 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1572 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1573 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1574 line_no, parent,
1575 isolated_depth ? isolated_depth + 1 : 0,
1576 type, ISEQ_COMPILE_DATA(iseq)->option,
1577 ISEQ_SCRIPT_LINES(iseq));
1578 debugs("[new_child_iseq]< ---------------------------------------\n");
1579 return ret_iseq;
1580}
1581
1582static rb_iseq_t *
1583new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1584 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1585{
1586 rb_iseq_t *ret_iseq;
1587
1588 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1589 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1590 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1591 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1592 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1593 return ret_iseq;
1594}
1595
1596static void
1597set_catch_except_p(rb_iseq_t *iseq)
1598{
1599 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1600 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1601 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1602 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1603 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1604 }
1605 }
1606}
1607
1608/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1609 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1610 if catch table exists. But we want to optimize while loop, which always has catch
1611 table entries for break/next/redo.
1612
1613 So this function sets true for limited ISeqs with break/next/redo catch table entries
1614 whose child ISeq would really raise an exception. */
1615static void
1616update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1617{
1618 unsigned int pos;
1619 size_t i;
1620 int insn;
1621 const struct iseq_catch_table *ct = body->catch_table;
1622
1623 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1624 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1625 pos = 0;
1626 while (pos < body->iseq_size) {
1627 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1628 if (insn == BIN(throw)) {
1629 set_catch_except_p(iseq);
1630 break;
1631 }
1632 pos += insn_len(insn);
1633 }
1634
1635 if (ct == NULL)
1636 return;
1637
1638 for (i = 0; i < ct->size; i++) {
1639 const struct iseq_catch_table_entry *entry =
1640 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1641 if (entry->type != CATCH_TYPE_BREAK
1642 && entry->type != CATCH_TYPE_NEXT
1643 && entry->type != CATCH_TYPE_REDO) {
1644 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1645 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1646 break;
1647 }
1648 }
1649}
1650
1651static void
1652iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1653{
1654 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1655 if (NIL_P(catch_table_ary)) return;
1656 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1657 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1658 for (i = 0; i < tlen; i++) {
1659 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1660 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1661 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1662 LINK_ELEMENT *e;
1663
1664 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1665
1666 if (ct != CATCH_TYPE_BREAK
1667 && ct != CATCH_TYPE_NEXT
1668 && ct != CATCH_TYPE_REDO) {
1669
1670 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1671 if (e == cont) {
1672 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1673 ELEM_INSERT_NEXT(end, &nop->link);
1674 break;
1675 }
1676 }
1677 }
1678 }
1679
1680 RB_GC_GUARD(catch_table_ary);
1681}
1682
1683static int
1684iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1685{
1686 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1687 return COMPILE_NG;
1688
1689 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1690
1691 if (compile_debug > 5)
1692 dump_disasm_list(FIRST_ELEMENT(anchor));
1693
1694 debugs("[compile step 3.1 (iseq_optimize)]\n");
1695 iseq_optimize(iseq, anchor);
1696
1697 if (compile_debug > 5)
1698 dump_disasm_list(FIRST_ELEMENT(anchor));
1699
1700 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1701 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1702 iseq_insns_unification(iseq, anchor);
1703 if (compile_debug > 5)
1704 dump_disasm_list(FIRST_ELEMENT(anchor));
1705 }
1706
1707 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1708 iseq_insert_nop_between_end_and_cont(iseq);
1709 if (compile_debug > 5)
1710 dump_disasm_list(FIRST_ELEMENT(anchor));
1711
1712 return COMPILE_OK;
1713}
1714
1715static int
1716iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1717{
1718 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1719 return COMPILE_NG;
1720
1721 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1722 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1723 if (compile_debug > 5)
1724 dump_disasm_list(FIRST_ELEMENT(anchor));
1725
1726 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1727 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1728
1729 debugs("[compile step 4.3 (set_optargs_table)] \n");
1730 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1731
1732 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1733 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1734
1735 debugs("[compile step 6 (update_catch_except_flags)] \n");
1736 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1737 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1738
1739 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1740 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1741 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1742 ruby_xfree_sized(ISEQ_BODY(iseq)->catch_table, iseq_catch_table_bytes(ISEQ_BODY(iseq)->catch_table->size));
1743 ISEQ_BODY(iseq)->catch_table = NULL;
1744 }
1745
1746#if VM_INSN_INFO_TABLE_IMPL == 2
1747 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1748 rb_iseq_insns_info_encode_positions(iseq);
1749#endif
1750
1751 if (compile_debug > 1) {
1752 VALUE str = rb_iseq_disasm(iseq);
1753 printf("%s\n", StringValueCStr(str));
1754 }
1755 verify_call_cache(iseq);
1756 debugs("[compile step: finish]\n");
1757
1758 return COMPILE_OK;
1759}
1760
1761static int
1762iseq_set_exception_local_table(rb_iseq_t *iseq)
1763{
1764 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1765 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1766 ISEQ_BODY(iseq)->lvar_states.list = NULL; // $! is read-only, so don't need lvar_states
1767 return COMPILE_OK;
1768}
1769
1770static int
1771get_lvar_level(const rb_iseq_t *iseq)
1772{
1773 int lev = 0;
1774 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1775 lev++;
1776 iseq = ISEQ_BODY(iseq)->parent_iseq;
1777 }
1778 return lev;
1779}
1780
1781static int
1782get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1783{
1784 unsigned int i;
1785
1786 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1787 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1788 return (int)i;
1789 }
1790 }
1791 return -1;
1792}
1793
1794static int
1795get_local_var_idx(const rb_iseq_t *iseq, ID id)
1796{
1797 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1798
1799 if (idx < 0) {
1800 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1801 "get_local_var_idx: %d", idx);
1802 }
1803
1804 return idx;
1805}
1806
1807static int
1808get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1809{
1810 int lv = 0, idx = -1;
1811 const rb_iseq_t *const topmost_iseq = iseq;
1812
1813 while (iseq) {
1814 idx = get_dyna_var_idx_at_raw(iseq, id);
1815 if (idx >= 0) {
1816 break;
1817 }
1818 iseq = ISEQ_BODY(iseq)->parent_iseq;
1819 lv++;
1820 }
1821
1822 if (idx < 0) {
1823 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1824 "get_dyna_var_idx: -1");
1825 }
1826
1827 *level = lv;
1828 *ls = ISEQ_BODY(iseq)->local_table_size;
1829 return idx;
1830}
1831
1832static int
1833iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1834{
1835 const struct rb_iseq_constant_body *body;
1836 while (level > 0) {
1837 iseq = ISEQ_BODY(iseq)->parent_iseq;
1838 level--;
1839 }
1840 body = ISEQ_BODY(iseq);
1841 if (body->local_iseq == iseq && /* local variables */
1842 body->param.flags.has_block &&
1843 body->local_table_size - body->param.block_start == idx) {
1844 return TRUE;
1845 }
1846 else {
1847 return FALSE;
1848 }
1849}
1850
1851static int
1852iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1853{
1854 int level, ls;
1855 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1856 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1857 *pidx = ls - idx;
1858 *plevel = level;
1859 return TRUE;
1860 }
1861 else {
1862 return FALSE;
1863 }
1864}
1865
1866static void
1867access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1868{
1869 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1870
1871 if (isolated_depth && level >= isolated_depth) {
1872 if (id == rb_intern("yield")) {
1873 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1874 }
1875 else {
1876 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1877 }
1878 }
1879
1880 for (int i=0; i<level; i++) {
1881 VALUE val;
1882 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1883
1884 if (!ovs) {
1885 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1886 }
1887
1888 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1889 if (write && !val) {
1890 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1891 }
1892 }
1893 else {
1894 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1895 }
1896
1897 iseq = ISEQ_BODY(iseq)->parent_iseq;
1898 }
1899}
1900
1901static ID
1902iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1903{
1904 for (int i=0; i<level; i++) {
1905 iseq = ISEQ_BODY(iseq)->parent_iseq;
1906 }
1907
1908 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1909 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1910 return id;
1911}
1912
1913static void
1914update_lvar_state(const rb_iseq_t *iseq, int level, int idx)
1915{
1916 for (int i=0; i<level; i++) {
1917 iseq = ISEQ_BODY(iseq)->parent_iseq;
1918 }
1919
1920 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1921 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1922 switch (iseq_lvar_state_get(states, table_idx)) {
1923 case lvar_uninitialized:
1924 iseq_lvar_state_set(states, table_idx, lvar_initialized);
1925 break;
1926 case lvar_initialized:
1927 iseq_lvar_state_set(states, table_idx, lvar_reassigned);
1928 break;
1929 case lvar_reassigned:
1930 /* nothing */
1931 break;
1932 default:
1933 rb_bug("unreachable");
1934 }
1935}
1936
1937static int
1938iseq_set_parameters_lvar_state(const rb_iseq_t *iseq)
1939{
1940 uint8_t *states = iseq_lvar_states(ISEQ_BODY(iseq));
1941
1942 for (unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1943 iseq_lvar_state_set(states, i, lvar_initialized);
1944 }
1945
1946 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1947 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1948 for (int i=0; i<opt_num; i++) {
1949 iseq_lvar_state_set(states, lead_num + i, lvar_uninitialized);
1950 }
1951
1952 return COMPILE_OK;
1953}
1954
1955static void
1956iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1957{
1958 if (iseq_local_block_param_p(iseq, idx, level)) {
1959 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1960 }
1961 else {
1962 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1963 }
1964 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1965}
1966
1967static void
1968iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1969{
1970 if (iseq_local_block_param_p(iseq, idx, level)) {
1971 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1972 }
1973 else {
1974 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1975 }
1976 update_lvar_state(iseq, level, idx);
1977 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1978}
1979
1980
1981
1982static void
1983iseq_calc_param_size(rb_iseq_t *iseq)
1984{
1985 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1986 if (body->param.flags.has_opt ||
1987 body->param.flags.has_post ||
1988 body->param.flags.has_rest ||
1989 body->param.flags.has_block ||
1990 body->param.flags.has_kw ||
1991 body->param.flags.has_kwrest) {
1992
1993 if (body->param.flags.has_block) {
1994 body->param.size = body->param.block_start + 1;
1995 }
1996 else if (body->param.flags.has_kwrest) {
1997 body->param.size = body->param.keyword->rest_start + 1;
1998 }
1999 else if (body->param.flags.has_kw) {
2000 body->param.size = body->param.keyword->bits_start + 1;
2001 }
2002 else if (body->param.flags.has_post) {
2003 body->param.size = body->param.post_start + body->param.post_num;
2004 }
2005 else if (body->param.flags.has_rest) {
2006 body->param.size = body->param.rest_start + 1;
2007 }
2008 else if (body->param.flags.has_opt) {
2009 body->param.size = body->param.lead_num + body->param.opt_num;
2010 }
2011 else {
2013 }
2014 }
2015 else {
2016 body->param.size = body->param.lead_num;
2017 }
2018}
2019
2020static int
2021iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
2022 const struct rb_args_info *args, int arg_size)
2023{
2024 const rb_node_kw_arg_t *node = args->kw_args;
2025 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2026 struct rb_iseq_param_keyword *keyword;
2027 const VALUE default_values = rb_ary_hidden_new(1);
2028 const VALUE complex_mark = rb_str_tmp_new(0);
2029 int kw = 0, rkw = 0, di = 0, i;
2030
2031 body->param.flags.has_kw = TRUE;
2032 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2033
2034 while (node) {
2035 kw++;
2036 node = node->nd_next;
2037 }
2038 if (kw > VM_CALL_KW_LEN_MAX) {
2039 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args)) "too many keyword parameters (%d, maximum is %d)",
2040 kw, (int)VM_CALL_KW_LEN_MAX);
2041 }
2042 arg_size += kw;
2043 keyword->bits_start = arg_size++;
2044
2045 node = args->kw_args;
2046 while (node) {
2047 const NODE *val_node = get_nd_value(node->nd_body);
2048 VALUE dv;
2049
2050 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2051 ++rkw;
2052 }
2053 else {
2054 switch (nd_type(val_node)) {
2055 case NODE_SYM:
2056 dv = rb_node_sym_string_val(val_node);
2057 break;
2058 case NODE_REGX:
2059 dv = rb_node_regx_string_val(val_node);
2060 break;
2061 case NODE_LINE:
2062 dv = rb_node_line_lineno_val(val_node);
2063 break;
2064 case NODE_INTEGER:
2065 dv = rb_node_integer_literal_val(val_node);
2066 break;
2067 case NODE_FLOAT:
2068 dv = rb_node_float_literal_val(val_node);
2069 break;
2070 case NODE_RATIONAL:
2071 dv = rb_node_rational_literal_val(val_node);
2072 break;
2073 case NODE_IMAGINARY:
2074 dv = rb_node_imaginary_literal_val(val_node);
2075 break;
2076 case NODE_ENCODING:
2077 dv = rb_node_encoding_val(val_node);
2078 break;
2079 case NODE_NIL:
2080 dv = Qnil;
2081 break;
2082 case NODE_TRUE:
2083 dv = Qtrue;
2084 break;
2085 case NODE_FALSE:
2086 dv = Qfalse;
2087 break;
2088 default:
2089 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
2090 dv = complex_mark;
2091 }
2092
2093 keyword->num = ++di;
2094 rb_ary_push(default_values, dv);
2095 }
2096
2097 node = node->nd_next;
2098 }
2099
2100 keyword->num = kw;
2101
2102 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2103 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2104 keyword->rest_start = arg_size++;
2105 body->param.flags.has_kwrest = TRUE;
2106
2107 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2108 }
2109 keyword->required_num = rkw;
2110 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2111
2112 if (RARRAY_LEN(default_values)) {
2113 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2114
2115 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2116 VALUE dv = RARRAY_AREF(default_values, i);
2117 if (dv == complex_mark) dv = Qundef;
2119 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2120 }
2121
2122 keyword->default_values = dvs;
2123 }
2124 return arg_size;
2125}
2126
2127static void
2128iseq_set_use_block(rb_iseq_t *iseq)
2129{
2130 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2131 if (!body->param.flags.use_block) {
2132 body->param.flags.use_block = 1;
2133
2134 rb_vm_t *vm = GET_VM();
2135
2136 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2137 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2138 set_insert(&vm->unused_block_warning_table, key);
2139 }
2140 }
2141}
2142
2143static int
2144iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2145{
2146 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2147
2148 if (node_args) {
2149 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2150 const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
2151 ID rest_id = 0;
2152 int last_comma = 0;
2153 ID block_id = 0;
2154 int arg_size;
2155
2156 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2157
2158 body->param.lead_num = arg_size = (int)args->pre_args_num;
2159 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2160 debugs(" - argc: %d\n", body->param.lead_num);
2161
2162 rest_id = args->rest_arg;
2163 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2164 last_comma = 1;
2165 rest_id = 0;
2166 }
2167 block_id = args->block_arg;
2168
2169 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2170
2171 if (optimized_forward) {
2172 rest_id = 0;
2173 block_id = 0;
2174 }
2175
2176 if (args->opt_args) {
2177 const rb_node_opt_arg_t *node = args->opt_args;
2178 LABEL *label;
2179 VALUE labels = rb_ary_hidden_new(1);
2180 VALUE *opt_table;
2181 int i = 0, j;
2182
2183 while (node) {
2184 label = NEW_LABEL(nd_line(RNODE(node)));
2185 rb_ary_push(labels, (VALUE)label | 1);
2186 ADD_LABEL(optargs, label);
2187 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2188 node = node->nd_next;
2189 i += 1;
2190 }
2191
2192 /* last label */
2193 label = NEW_LABEL(nd_line(node_args));
2194 rb_ary_push(labels, (VALUE)label | 1);
2195 ADD_LABEL(optargs, label);
2196
2197 opt_table = ALLOC_N(VALUE, i+1);
2198
2199 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2200 for (j = 0; j < i+1; j++) {
2201 opt_table[j] &= ~1;
2202 }
2203 rb_ary_clear(labels);
2204
2205 body->param.flags.has_opt = TRUE;
2206 body->param.opt_num = i;
2207 body->param.opt_table = opt_table;
2208 arg_size += i;
2209 }
2210
2211 if (rest_id) {
2212 body->param.rest_start = arg_size++;
2213 body->param.flags.has_rest = TRUE;
2214 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2215 RUBY_ASSERT(body->param.rest_start != -1);
2216 }
2217
2218 if (args->first_post_arg) {
2219 body->param.post_start = arg_size;
2220 body->param.post_num = args->post_args_num;
2221 body->param.flags.has_post = TRUE;
2222 arg_size += args->post_args_num;
2223
2224 if (body->param.flags.has_rest) { /* TODO: why that? */
2225 body->param.post_start = body->param.rest_start + 1;
2226 }
2227 }
2228
2229 if (args->kw_args) {
2230 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2231 }
2232 else if (args->kw_rest_arg && !optimized_forward) {
2233 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2234 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2235 keyword->rest_start = arg_size++;
2236 body->param.keyword = keyword;
2237 body->param.flags.has_kwrest = TRUE;
2238
2239 static ID anon_kwrest = 0;
2240 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2241 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2242 }
2243 else if (args->no_kwarg) {
2244 body->param.flags.accepts_no_kwarg = TRUE;
2245 }
2246
2247 if (args->no_blockarg) {
2248 body->param.flags.accepts_no_block = TRUE;
2249 }
2250 else if (block_id) {
2251 body->param.block_start = arg_size++;
2252 body->param.flags.has_block = TRUE;
2253 iseq_set_use_block(iseq);
2254 }
2255
2256 // Only optimize specifically methods like this: `foo(...)`
2257 if (optimized_forward) {
2258 body->param.flags.use_block = 1;
2259 body->param.flags.forwardable = TRUE;
2260 arg_size = 1;
2261 }
2262
2263 iseq_calc_param_size(iseq);
2264 body->param.size = arg_size;
2265
2266 if (args->pre_init) { /* m_init */
2267 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2268 }
2269 if (args->post_init) { /* p_init */
2270 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2271 }
2272
2273 if (body->type == ISEQ_TYPE_BLOCK) {
2274 if (body->param.flags.has_opt == FALSE &&
2275 body->param.flags.has_post == FALSE &&
2276 body->param.flags.has_rest == FALSE &&
2277 body->param.flags.has_kw == FALSE &&
2278 body->param.flags.has_kwrest == FALSE) {
2279
2280 if (body->param.lead_num == 1 && last_comma == 0) {
2281 /* {|a|} */
2282 body->param.flags.ambiguous_param0 = TRUE;
2283 }
2284 }
2285 }
2286 }
2287
2288 return COMPILE_OK;
2289}
2290
2291static int
2292iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2293{
2294 unsigned int size = tbl ? tbl->size : 0;
2295 unsigned int offset = 0;
2296
2297 if (node_args) {
2298 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2299
2300 // If we have a function that only has `...` as the parameter,
2301 // then its local table should only be `...`
2302 // FIXME: I think this should be fixed in the AST rather than special case here.
2303 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2304 CHECK(size >= 3);
2305 size -= 3;
2306 offset += 3;
2307 }
2308 }
2309
2310 if (size > 0) {
2311 ID *ids = ALLOC_N(ID, size);
2312 MEMCPY(ids, tbl->ids + offset, ID, size);
2313 ISEQ_BODY(iseq)->local_table = ids;
2314
2315 if (ISEQ_LVAR_STATES_EMBED_P(size)) {
2316 /* states are embedded in the body; zero them out */
2317 memset(ISEQ_BODY(iseq)->lvar_states.single, 0, sizeof(ISEQ_BODY(iseq)->lvar_states.single));
2318 }
2319 else {
2320 ISEQ_BODY(iseq)->lvar_states.list = ZALLOC_N(uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
2321 }
2322 }
2323 ISEQ_BODY(iseq)->local_table_size = size;
2324
2325 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2326 return COMPILE_OK;
2327}
2328
2329int
2330rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2331{
2332 int tval, tlit;
2333
2334 if (val == lit) {
2335 return 0;
2336 }
2337 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2338 return val != lit;
2339 }
2340 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2341 return -1;
2342 }
2343 else if (tlit != tval) {
2344 return -1;
2345 }
2346 else if (tlit == T_SYMBOL) {
2347 return val != lit;
2348 }
2349 else if (tlit == T_STRING) {
2350 return rb_str_hash_cmp(lit, val);
2351 }
2352 else if (tlit == T_BIGNUM) {
2353 long x = FIX2LONG(rb_big_cmp(lit, val));
2354
2355 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2356 * There is no need to call rb_fix2int here. */
2357 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2358 return (int)x;
2359 }
2360 else if (tlit == T_FLOAT) {
2361 return rb_float_cmp(lit, val);
2362 }
2363 else if (tlit == T_RATIONAL) {
2364 const struct RRational *rat1 = RRATIONAL(val);
2365 const struct RRational *rat2 = RRATIONAL(lit);
2366 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2367 }
2368 else if (tlit == T_COMPLEX) {
2369 const struct RComplex *comp1 = RCOMPLEX(val);
2370 const struct RComplex *comp2 = RCOMPLEX(lit);
2371 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2372 }
2373 else if (tlit == T_REGEXP) {
2374 return rb_reg_equal(val, lit) ? 0 : -1;
2375 }
2376 else {
2378 }
2379}
2380
2381st_index_t
2382rb_iseq_cdhash_hash(VALUE a)
2383{
2384 switch (OBJ_BUILTIN_TYPE(a)) {
2385 case -1:
2386 case T_SYMBOL:
2387 return (st_index_t)a;
2388 case T_STRING:
2389 return rb_str_hash(a);
2390 case T_BIGNUM:
2391 return FIX2LONG(rb_big_hash(a));
2392 case T_FLOAT:
2393 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2394 case T_RATIONAL:
2395 return rb_rational_hash(a);
2396 case T_COMPLEX:
2397 return rb_complex_hash(a);
2398 case T_REGEXP:
2399 return NUM2LONG(rb_reg_hash(a));
2400 default:
2402 }
2403}
2404
2405static const struct st_hash_type cdhash_type = {
2406 rb_iseq_cdhash_cmp,
2407 rb_iseq_cdhash_hash,
2408};
2409
2410static VALUE
2411cdhash_new(size_t size)
2412{
2413 VALUE cdhash = rb_imemo_cdhash_new(size, &cdhash_type);
2414 RB_OBJ_SET_SHAREABLE(cdhash);
2415 return cdhash;
2416}
2417
2418static void
2419cdhash_aset(VALUE cdhash, VALUE key, VALUE val)
2420{
2421 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2422 st_insert(tbl, key, val);
2423 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2424}
2425
2426static void
2427cdhash_aset_if_missing(VALUE cdhash, VALUE key, VALUE val)
2428{
2429 st_table *tbl = rb_imemo_cdhash_tbl(cdhash);
2430 VALUE dontcare;
2431 if (!st_lookup(tbl, key, &dontcare)) {
2432 st_insert(tbl, key, val);
2433 RB_OBJ_WRITTEN(cdhash, Qundef, key);
2434 }
2435}
2436
2438 VALUE hash;
2439 int pos;
2440 int len;
2441};
2442
2443static int
2444cdhash_set_label_check_i(st_data_t key, st_data_t value, st_data_t argp, int error)
2445{
2446 return ST_REPLACE;
2447}
2448
2449static int
2450cdhash_set_label_replace_i(st_data_t *key, st_data_t *value, st_data_t ptr, int existing)
2451{
2452 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2453 LABEL *lobj = (LABEL *)(*value & ~1);
2454 *value = lobj->position - (data->pos+data->len);
2455 return ST_CONTINUE;
2456}
2457
2458static inline VALUE
2459get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2460{
2461 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2462}
2463
2464static inline VALUE
2465get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2466{
2467 VALUE val;
2468 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2469 if (tbl) {
2470 if (rb_id_table_lookup(tbl,id,&val)) {
2471 return val;
2472 }
2473 }
2474 else {
2475 tbl = rb_id_table_create(1);
2476 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2477 }
2478 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2479 rb_id_table_insert(tbl,id,val);
2480 return val;
2481}
2482
2483#define BADINSN_DUMP(anchor, list, dest) \
2484 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2485
2486#define BADINSN_ERROR \
2487 (SIZED_FREE_N(generated_iseq, generated_iseq_size), \
2488 SIZED_FREE_N(insns_info, insns_info_size), \
2489 BADINSN_DUMP(anchor, list, NULL), \
2490 COMPILE_ERROR)
2491
2492static int
2493fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2494{
2495 int stack_max = 0, sp = 0, line = 0;
2496 LINK_ELEMENT *list;
2497
2498 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2499 if (IS_LABEL(list)) {
2500 LABEL *lobj = (LABEL *)list;
2501 lobj->set = TRUE;
2502 }
2503 }
2504
2505 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2506 switch (list->type) {
2507 case ISEQ_ELEMENT_INSN:
2508 {
2509 int j, len, insn;
2510 const char *types;
2511 VALUE *operands;
2512 INSN *iobj = (INSN *)list;
2513
2514 /* update sp */
2515 sp = calc_sp_depth(sp, iobj);
2516 if (sp < 0) {
2517 BADINSN_DUMP(anchor, list, NULL);
2518 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2519 "argument stack underflow (%d)", sp);
2520 return -1;
2521 }
2522 if (sp > stack_max) {
2523 stack_max = sp;
2524 }
2525
2526 line = iobj->insn_info.line_no;
2527 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2528 operands = iobj->operands;
2529 insn = iobj->insn_id;
2530 types = insn_op_types(insn);
2531 len = insn_len(insn);
2532
2533 /* operand check */
2534 if (iobj->operand_size != len - 1) {
2535 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2536 BADINSN_DUMP(anchor, list, NULL);
2537 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2538 "operand size miss! (%d for %d)",
2539 iobj->operand_size, len - 1);
2540 return -1;
2541 }
2542
2543 for (j = 0; types[j]; j++) {
2544 if (types[j] == TS_OFFSET) {
2545 /* label(destination position) */
2546 LABEL *lobj = (LABEL *)operands[j];
2547 if (!lobj->set) {
2548 BADINSN_DUMP(anchor, list, NULL);
2549 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2550 "unknown label: "LABEL_FORMAT, lobj->label_no);
2551 return -1;
2552 }
2553 if (lobj->sp == -1) {
2554 lobj->sp = sp;
2555 }
2556 else if (lobj->sp != sp) {
2557 VALUE path = rb_iseq_path(iseq);
2558 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2559 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2560 lobj->label_no, lobj->sp, sp);
2561 }
2562 }
2563 }
2564 break;
2565 }
2566 case ISEQ_ELEMENT_LABEL:
2567 {
2568 LABEL *lobj = (LABEL *)list;
2569 if (lobj->sp == -1) {
2570 lobj->sp = sp;
2571 }
2572 else {
2573 if (lobj->sp != sp) {
2574 VALUE path = rb_iseq_path(iseq);
2575 debugs("%.*s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2576 RSTRING_LENINT(path), RSTRING_PTR(path), line,
2577 lobj->label_no, lobj->sp, sp);
2578 }
2579 sp = lobj->sp;
2580 }
2581 break;
2582 }
2583 case ISEQ_ELEMENT_TRACE:
2584 {
2585 /* ignore */
2586 break;
2587 }
2588 case ISEQ_ELEMENT_ADJUST:
2589 {
2590 ADJUST *adjust = (ADJUST *)list;
2591 int orig_sp = sp;
2592
2593 sp = adjust->label ? adjust->label->sp : 0;
2594 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2595 BADINSN_DUMP(anchor, list, NULL);
2596 COMPILE_ERROR(iseq, adjust->line_no,
2597 "iseq_set_sequence: adjust bug %d < %d",
2598 orig_sp, sp);
2599 return -1;
2600 }
2601 break;
2602 }
2603 default:
2604 BADINSN_DUMP(anchor, list, NULL);
2605 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2606 return -1;
2607 }
2608 }
2609 return stack_max;
2610}
2611
2612static int
2613add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2614 int insns_info_index, int code_index, const INSN *iobj)
2615{
2616 if (insns_info_index == 0 ||
2617 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2618#ifdef USE_ISEQ_NODE_ID
2619 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2620#endif
2621 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2622 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2623#ifdef USE_ISEQ_NODE_ID
2624 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2625#endif
2626 insns_info[insns_info_index].events = iobj->insn_info.events;
2627 positions[insns_info_index] = code_index;
2628 return TRUE;
2629 }
2630 return FALSE;
2631}
2632
2633static int
2634add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2635 int insns_info_index, int code_index, const ADJUST *adjust)
2636{
2637 insns_info[insns_info_index].line_no = adjust->line_no;
2638 insns_info[insns_info_index].node_id = -1;
2639 insns_info[insns_info_index].events = 0;
2640 positions[insns_info_index] = code_index;
2641 return TRUE;
2642}
2643
2644static ID *
2645array_to_idlist(VALUE arr)
2646{
2648 long size = RARRAY_LEN(arr);
2649 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2650 for (long i = 0; i < size; i++) {
2651 VALUE sym = RARRAY_AREF(arr, i);
2652 ids[i] = SYM2ID(sym);
2653 }
2654 ids[size] = 0;
2655 return ids;
2656}
2657
2658static VALUE
2659idlist_to_array(const ID *ids)
2660{
2661 VALUE arr = rb_ary_new();
2662 while (*ids) {
2663 rb_ary_push(arr, ID2SYM(*ids++));
2664 }
2665 return arr;
2666}
2667
2671static int
2672iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2673{
2674 struct iseq_insn_info_entry *insns_info;
2675 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2676 unsigned int *positions;
2677 LINK_ELEMENT *list;
2678 VALUE *generated_iseq;
2679 rb_event_flag_t events = 0;
2680 long data = 0;
2681
2682 int insn_num, code_index, insns_info_index, sp = 0;
2683 int stack_max = fix_sp_depth(iseq, anchor);
2684
2685 if (stack_max < 0) return COMPILE_NG;
2686
2687 /* fix label position */
2688 insn_num = code_index = 0;
2689 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2690 switch (list->type) {
2691 case ISEQ_ELEMENT_INSN:
2692 {
2693 INSN *iobj = (INSN *)list;
2694 /* update sp */
2695 sp = calc_sp_depth(sp, iobj);
2696 insn_num++;
2697 events = iobj->insn_info.events |= events;
2698 if (ISEQ_COVERAGE(iseq)) {
2699 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2700 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2701 int line = iobj->insn_info.line_no - 1;
2702 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2703 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2704 }
2705 }
2706 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2707 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2708 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2709 }
2710 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2711 }
2712 }
2713 code_index += insn_data_length(iobj);
2714 events = 0;
2715 data = 0;
2716 break;
2717 }
2718 case ISEQ_ELEMENT_LABEL:
2719 {
2720 LABEL *lobj = (LABEL *)list;
2721 lobj->position = code_index;
2722 if (lobj->sp != sp) {
2723 VALUE path = rb_iseq_path(iseq);
2724 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2725 RSTRING_LENINT(path), RSTRING_PTR(path),
2726 lobj->label_no, lobj->sp, sp);
2727 }
2728 sp = lobj->sp;
2729 break;
2730 }
2731 case ISEQ_ELEMENT_TRACE:
2732 {
2733 TRACE *trace = (TRACE *)list;
2734 events |= trace->event;
2735 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2736 break;
2737 }
2738 case ISEQ_ELEMENT_ADJUST:
2739 {
2740 ADJUST *adjust = (ADJUST *)list;
2741 if (adjust->line_no != -1) {
2742 int orig_sp = sp;
2743 sp = adjust->label ? adjust->label->sp : 0;
2744 if (orig_sp - sp > 0) {
2745 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2746 code_index++; /* insn */
2747 insn_num++;
2748 }
2749 }
2750 break;
2751 }
2752 default: break;
2753 }
2754 }
2755
2756 /* make instruction sequence */
2757 const int generated_iseq_size = code_index;
2758 generated_iseq = ALLOC_N(VALUE, code_index);
2759
2760 const int insns_info_size = insn_num;
2761 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2762
2763 const int positions_size = insn_num;
2764 positions = ALLOC_N(unsigned int, insn_num);
2765 if (ISEQ_IS_SIZE(body)) {
2766 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2767 }
2768 else {
2769 body->is_entries = NULL;
2770 }
2771
2772 if (body->ci_size) {
2773 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2774 }
2775 else {
2776 body->call_data = NULL;
2777 }
2778 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2779
2780 // Calculate the bitmask buffer size.
2781 // Round the generated_iseq size up to the nearest multiple
2782 // of the number of bits in an unsigned long.
2783
2784 // Allocate enough room for the bitmask list
2785 iseq_bits_t * mark_offset_bits;
2786 int code_size = code_index;
2787
2788 bool needs_bitmap = false;
2789
2790 const size_t mark_offset_bits_size = ISEQ_MBITS_BUFLEN(code_index);
2791 if (mark_offset_bits_size == 1) {
2792 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2793 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2794 }
2795 else {
2796 mark_offset_bits = ZALLOC_N(iseq_bits_t, mark_offset_bits_size);
2797 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2798 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2799 }
2800
2801 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2802 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2803
2804 list = FIRST_ELEMENT(anchor);
2805 insns_info_index = code_index = sp = 0;
2806
2807 while (list) {
2808 switch (list->type) {
2809 case ISEQ_ELEMENT_INSN:
2810 {
2811 int j, len, insn;
2812 const char *types;
2813 VALUE *operands;
2814 INSN *iobj = (INSN *)list;
2815
2816 /* update sp */
2817 sp = calc_sp_depth(sp, iobj);
2818 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2819 operands = iobj->operands;
2820 insn = iobj->insn_id;
2821 generated_iseq[code_index] = insn;
2822 types = insn_op_types(insn);
2823 len = insn_len(insn);
2824
2825 for (j = 0; types[j]; j++) {
2826 char type = types[j];
2827
2828 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2829 switch (type) {
2830 case TS_OFFSET:
2831 {
2832 /* label(destination position) */
2833 LABEL *lobj = (LABEL *)operands[j];
2834 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2835 break;
2836 }
2837 case TS_CDHASH:
2838 {
2839 VALUE map = operands[j];
2840 struct cdhash_set_label_struct data;
2841 data.hash = map;
2842 data.pos = code_index;
2843 data.len = len;
2844 st_foreach_with_replace(rb_imemo_cdhash_tbl(map), cdhash_set_label_check_i, cdhash_set_label_replace_i, (VALUE)&data);
2845
2846 generated_iseq[code_index + 1 + j] = map;
2847 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2848 RB_OBJ_WRITTEN(iseq, Qundef, map);
2849 needs_bitmap = true;
2850 break;
2851 }
2852 case TS_LINDEX:
2853 case TS_NUM: /* ulong */
2854 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2855 break;
2856 case TS_ISEQ: /* iseq */
2857 case TS_VALUE: /* VALUE */
2858 {
2859 VALUE v = operands[j];
2860 generated_iseq[code_index + 1 + j] = v;
2861 /* to mark ruby object */
2862 if (!SPECIAL_CONST_P(v)) {
2863 RB_OBJ_WRITTEN(iseq, Qundef, v);
2864 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2865 needs_bitmap = true;
2866 }
2867 break;
2868 }
2869 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2870 case TS_IC: /* inline cache: constants */
2871 {
2872 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2873 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2874 if (UNLIKELY(ic_index >= body->ic_size)) {
2875 BADINSN_DUMP(anchor, &iobj->link, 0);
2876 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2877 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2878 ic_index, ISEQ_IS_SIZE(body));
2879 }
2880
2881 ic->segments = array_to_idlist(operands[j]);
2882
2883 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2884 }
2885 break;
2886 case TS_IVC: /* inline ivar cache */
2887 {
2888 unsigned int ic_index = FIX2UINT(operands[j]);
2889
2890 IVC cache = ((IVC)&body->is_entries[ic_index]);
2891
2892 if (insn == BIN(setinstancevariable)) {
2893 cache->iv_set_name = SYM2ID(operands[j - 1]);
2894 cache->value = IVAR_CACHE_INIT;
2895 }
2896 else {
2897 cache->iv_set_name = 0;
2898 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
2899 }
2900 }
2901 case TS_ISE: /* inline storage entry: `once` insn */
2902 case TS_ICVARC: /* inline cvar cache */
2903 {
2904 unsigned int ic_index = FIX2UINT(operands[j]);
2905 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2906 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2907 BADINSN_DUMP(anchor, &iobj->link, 0);
2908 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2909 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2910 ic_index, ISEQ_IS_SIZE(body));
2911 }
2912 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2913
2914 break;
2915 }
2916 case TS_CALLDATA:
2917 {
2918 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2919 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2920 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2921 cd->ci = source_ci;
2922 cd->cc = vm_cc_empty();
2923 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2924 break;
2925 }
2926 case TS_ID: /* ID */
2927 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2928 break;
2929 case TS_FUNCPTR:
2930 generated_iseq[code_index + 1 + j] = operands[j];
2931 break;
2932 case TS_BUILTIN:
2933 generated_iseq[code_index + 1 + j] = operands[j];
2934 break;
2935 default:
2936 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2937 "unknown operand type: %c", type);
2938 return COMPILE_NG;
2939 }
2940 }
2941 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2942 code_index += len;
2943 break;
2944 }
2945 case ISEQ_ELEMENT_LABEL:
2946 {
2947 LABEL *lobj = (LABEL *)list;
2948 if (lobj->sp != sp) {
2949 VALUE path = rb_iseq_path(iseq);
2950 debugs("%.*s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2951 RSTRING_LENINT(path), RSTRING_PTR(path),
2952 lobj->label_no, lobj->sp, sp);
2953 }
2954 sp = lobj->sp;
2955 break;
2956 }
2957 case ISEQ_ELEMENT_ADJUST:
2958 {
2959 ADJUST *adjust = (ADJUST *)list;
2960 int orig_sp = sp;
2961
2962 if (adjust->label) {
2963 sp = adjust->label->sp;
2964 }
2965 else {
2966 sp = 0;
2967 }
2968
2969 if (adjust->line_no != -1) {
2970 const int diff = orig_sp - sp;
2971 if (diff > 0) {
2972 if (insns_info_index == 0) {
2973 COMPILE_ERROR(iseq, adjust->line_no,
2974 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2975 }
2976 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2977 }
2978 if (diff > 1) {
2979 generated_iseq[code_index++] = BIN(adjuststack);
2980 generated_iseq[code_index++] = orig_sp - sp;
2981 }
2982 else if (diff == 1) {
2983 generated_iseq[code_index++] = BIN(pop);
2984 }
2985 else if (diff < 0) {
2986 int label_no = adjust->label ? adjust->label->label_no : -1;
2987 SIZED_FREE_N(generated_iseq, generated_iseq_size);
2988 SIZED_FREE_N(insns_info, insns_info_size);
2989 SIZED_FREE_N(positions, positions_size);
2990 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2991 SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index));
2992 }
2993 debug_list(anchor, list);
2994 COMPILE_ERROR(iseq, adjust->line_no,
2995 "iseq_set_sequence: adjust bug to %d %d < %d",
2996 label_no, orig_sp, sp);
2997 return COMPILE_NG;
2998 }
2999 }
3000 break;
3001 }
3002 default:
3003 /* ignore */
3004 break;
3005 }
3006 list = list->next;
3007 }
3008
3009 body->iseq_encoded = (void *)generated_iseq;
3010 body->iseq_size = code_index;
3011 body->stack_max = stack_max;
3012
3013 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
3014 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
3015 }
3016 else {
3017 if (needs_bitmap) {
3018 body->mark_bits.list = mark_offset_bits;
3019 }
3020 else {
3021 body->mark_bits.list = NULL;
3022 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
3023 SIZED_FREE_N(mark_offset_bits, mark_offset_bits_size);
3024 }
3025 }
3026
3027 /* get rid of memory leak when REALLOC failed */
3028 body->insns_info.body = insns_info;
3029 body->insns_info.positions_or_succ_index_table.positions = positions;
3030
3031 SIZED_REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index, insns_info_size);
3032 body->insns_info.body = insns_info;
3033 SIZED_REALLOC_N(positions, unsigned int, insns_info_index, positions_size);
3034 body->insns_info.positions_or_succ_index_table.positions = positions;
3035 body->insns_info.size = insns_info_index;
3036
3037 return COMPILE_OK;
3038}
3039
3040static int
3041label_get_position(LABEL *lobj)
3042{
3043 return lobj->position;
3044}
3045
3046static int
3047label_get_sp(LABEL *lobj)
3048{
3049 return lobj->sp;
3050}
3051
3052static int
3053iseq_set_exception_table(rb_iseq_t *iseq)
3054{
3055 const VALUE *tptr, *ptr;
3056 unsigned int tlen, i;
3057 struct iseq_catch_table_entry *entry;
3058
3059 ISEQ_BODY(iseq)->catch_table = NULL;
3060
3061 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
3062 if (NIL_P(catch_table_ary)) return COMPILE_OK;
3063 tlen = (int)RARRAY_LEN(catch_table_ary);
3064 tptr = RARRAY_CONST_PTR(catch_table_ary);
3065
3066 if (tlen > 0) {
3067 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
3068 table->size = tlen;
3069
3070 for (i = 0; i < table->size; i++) {
3071 int pos;
3072 ptr = RARRAY_CONST_PTR(tptr[i]);
3073 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
3074 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
3075 pos = label_get_position((LABEL *)(ptr[1] & ~1));
3076 RUBY_ASSERT(pos >= 0);
3077 entry->start = (unsigned int)pos;
3078 pos = label_get_position((LABEL *)(ptr[2] & ~1));
3079 RUBY_ASSERT(pos >= 0);
3080 entry->end = (unsigned int)pos;
3081 entry->iseq = (rb_iseq_t *)ptr[3];
3082 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
3083
3084 /* stack depth */
3085 if (ptr[4]) {
3086 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
3087 entry->cont = label_get_position(lobj);
3088 entry->sp = label_get_sp(lobj);
3089
3090 /* TODO: Dirty Hack! Fix me */
3091 if (entry->type == CATCH_TYPE_RESCUE ||
3092 entry->type == CATCH_TYPE_BREAK ||
3093 entry->type == CATCH_TYPE_NEXT) {
3094 RUBY_ASSERT(entry->sp > 0);
3095 entry->sp--;
3096 }
3097 }
3098 else {
3099 entry->cont = 0;
3100 }
3101 }
3102 ISEQ_BODY(iseq)->catch_table = table;
3103 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
3104 }
3105
3106 RB_GC_GUARD(catch_table_ary);
3107
3108 return COMPILE_OK;
3109}
3110
3111/*
3112 * set optional argument table
3113 * def foo(a, b=expr1, c=expr2)
3114 * =>
3115 * b:
3116 * expr1
3117 * c:
3118 * expr2
3119 */
3120static int
3121iseq_set_optargs_table(rb_iseq_t *iseq)
3122{
3123 int i;
3124 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3125
3126 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3127 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3128 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3129 }
3130 }
3131 return COMPILE_OK;
3132}
3133
3134static LINK_ELEMENT *
3135get_destination_insn(INSN *iobj)
3136{
3137 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3138 LINK_ELEMENT *list;
3139 rb_event_flag_t events = 0;
3140
3141 list = lobj->link.next;
3142 while (list) {
3143 switch (list->type) {
3144 case ISEQ_ELEMENT_INSN:
3145 case ISEQ_ELEMENT_ADJUST:
3146 goto found;
3147 case ISEQ_ELEMENT_LABEL:
3148 /* ignore */
3149 break;
3150 case ISEQ_ELEMENT_TRACE:
3151 {
3152 TRACE *trace = (TRACE *)list;
3153 events |= trace->event;
3154 }
3155 break;
3156 default: break;
3157 }
3158 list = list->next;
3159 }
3160 found:
3161 if (list && IS_INSN(list)) {
3162 INSN *iobj = (INSN *)list;
3163 iobj->insn_info.events |= events;
3164 }
3165 return list;
3166}
3167
3168static LINK_ELEMENT *
3169get_next_insn(INSN *iobj)
3170{
3171 LINK_ELEMENT *list = iobj->link.next;
3172
3173 while (list) {
3174 if (IS_INSN(list) || IS_ADJUST(list)) {
3175 return list;
3176 }
3177 list = list->next;
3178 }
3179 return 0;
3180}
3181
3182static LINK_ELEMENT *
3183get_prev_insn(INSN *iobj)
3184{
3185 LINK_ELEMENT *list = iobj->link.prev;
3186
3187 while (list) {
3188 if (IS_INSN(list) || IS_ADJUST(list)) {
3189 return list;
3190 }
3191 list = list->prev;
3192 }
3193 return 0;
3194}
3195
3196static void
3197unref_destination(INSN *iobj, int pos)
3198{
3199 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3200 --lobj->refcnt;
3201 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3202}
3203
3204static bool
3205replace_destination(INSN *dobj, INSN *nobj)
3206{
3207 VALUE n = OPERAND_AT(nobj, 0);
3208 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3209 LABEL *nl = (LABEL *)n;
3210 if (dl == nl) return false;
3211 --dl->refcnt;
3212 ++nl->refcnt;
3213 OPERAND_AT(dobj, 0) = n;
3214 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3215 return true;
3216}
3217
3218static LABEL*
3219find_destination(INSN *i)
3220{
3221 int pos, len = insn_len(i->insn_id);
3222 for (pos = 0; pos < len; ++pos) {
3223 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3224 return (LABEL *)OPERAND_AT(i, pos);
3225 }
3226 }
3227 return 0;
3228}
3229
3230static int
3231remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3232{
3233 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3234 LABEL *pending = 0;
3235 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3236
3237 if (!i) return 0;
3238 unref_counts = ALLOCA_N(int, nlabels);
3239 MEMZERO(unref_counts, int, nlabels);
3240
3241 end = i;
3242 scan = i;
3243 do {
3244 LABEL *lab;
3245 if (IS_INSN(scan)) {
3246 if (IS_INSN_ID(scan, leave)) {
3247 if (pending) break;
3248 end = scan;
3249 break;
3250 }
3251 else if ((lab = find_destination((INSN *)scan)) != 0) {
3252 unref_counts[lab->label_no]++;
3253 if (lab == pending && lab->refcnt <= unref_counts[lab->label_no]) {
3254 pending = 0;
3255 }
3256 }
3257 }
3258 else if (IS_LABEL(scan)) {
3259 lab = (LABEL *)scan;
3260 if (lab->unremovable) {
3261 if (pending) break;
3262 return 0;
3263 }
3264 if (lab->refcnt > unref_counts[lab->label_no]) {
3265 if (pending) break;
3266 pending = lab;
3267 pending_end = (scan == first) ? 0 : end;
3268 }
3269 continue;
3270 }
3271 else if (IS_ADJUST(scan)) {
3272 if (pending) break;
3273 return 0;
3274 }
3275 if (!pending) end = scan;
3276 } while ((scan = scan->next) != 0);
3277
3278 if (pending) {
3279 if (!pending_end) return 0;
3280 end = pending_end;
3281 }
3282 i = first;
3283 do {
3284 if (IS_INSN(i)) {
3285 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3286 VALUE insn = INSN_OF(i);
3287 int pos, len = insn_len(insn);
3288 for (pos = 0; pos < len; ++pos) {
3289 switch (insn_op_types(insn)[pos]) {
3290 case TS_OFFSET:
3291 unref_destination((INSN *)i, pos);
3292 break;
3293 case TS_CALLDATA:
3294 --(body->ci_size);
3295 break;
3296 }
3297 }
3298 }
3299 ELEM_REMOVE(i);
3300 } while ((i != end) && (i = i->next) != 0);
3301 return 1;
3302}
3303
3304static int
3305iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3306{
3307 switch (OPERAND_AT(iobj, 0)) {
3308 case INT2FIX(0): /* empty array */
3309 ELEM_REMOVE(&iobj->link);
3310 return TRUE;
3311 case INT2FIX(1): /* single element array */
3312 ELEM_REMOVE(&iobj->link);
3313 return FALSE;
3314 default:
3315 iobj->insn_id = BIN(adjuststack);
3316 return TRUE;
3317 }
3318}
3319
3320static int
3321is_frozen_putstring(INSN *insn, VALUE *op)
3322{
3323 if (IS_INSN_ID(insn, dupstring) || IS_INSN_ID(insn, dupchilledstring)) {
3324 *op = OPERAND_AT(insn, 0);
3325 return 1;
3326 }
3327 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3328 *op = OPERAND_AT(insn, 0);
3329 return RB_TYPE_P(*op, T_STRING);
3330 }
3331 return 0;
3332}
3333
3334static int
3335insn_has_label_before(LINK_ELEMENT *elem)
3336{
3337 LINK_ELEMENT *prev = elem->prev;
3338 while (prev) {
3339 if (prev->type == ISEQ_ELEMENT_LABEL) {
3340 LABEL *label = (LABEL *)prev;
3341 if (label->refcnt > 0) {
3342 return 1;
3343 }
3344 }
3345 else if (prev->type == ISEQ_ELEMENT_INSN) {
3346 break;
3347 }
3348 prev = prev->prev;
3349 }
3350 return 0;
3351}
3352
3353static int
3354optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3355{
3356 /*
3357 * putobject obj
3358 * dup
3359 * checktype T_XXX
3360 * branchif l1
3361 * l2:
3362 * ...
3363 * l1:
3364 *
3365 * => obj is a T_XXX
3366 *
3367 * putobject obj (T_XXX)
3368 * jump L1
3369 * L1:
3370 *
3371 * => obj is not a T_XXX
3372 *
3373 * putobject obj (T_XXX)
3374 * jump L2
3375 * L2:
3376 */
3377 int line, node_id;
3378 INSN *niobj, *ciobj, *dup = 0;
3379 LABEL *dest = 0;
3380 VALUE type;
3381
3382 switch (INSN_OF(iobj)) {
3383 case BIN(dupstring):
3384 case BIN(dupchilledstring):
3386 break;
3387 case BIN(putnil):
3388 type = INT2FIX(T_NIL);
3389 break;
3390 case BIN(putobject):
3391 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3392 break;
3393 default: return FALSE;
3394 }
3395
3396 ciobj = (INSN *)get_next_insn(iobj);
3397 if (IS_INSN_ID(ciobj, jump)) {
3398 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3399 }
3400 if (IS_INSN_ID(ciobj, dup)) {
3401 ciobj = (INSN *)get_next_insn(dup = ciobj);
3402 }
3403 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3404 niobj = (INSN *)get_next_insn(ciobj);
3405 if (!niobj) {
3406 /* TODO: putobject true/false */
3407 return FALSE;
3408 }
3409 switch (INSN_OF(niobj)) {
3410 case BIN(branchif):
3411 if (OPERAND_AT(ciobj, 0) == type) {
3412 dest = (LABEL *)OPERAND_AT(niobj, 0);
3413 }
3414 break;
3415 case BIN(branchunless):
3416 if (OPERAND_AT(ciobj, 0) != type) {
3417 dest = (LABEL *)OPERAND_AT(niobj, 0);
3418 }
3419 break;
3420 default:
3421 return FALSE;
3422 }
3423 line = ciobj->insn_info.line_no;
3424 node_id = ciobj->insn_info.node_id;
3425 if (!dest) {
3426 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3427 dest = (LABEL *)niobj->link.next; /* reuse label */
3428 }
3429 else {
3430 dest = NEW_LABEL(line);
3431 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3432 }
3433 }
3434 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3435 LABEL_REF(dest);
3436 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3437 return TRUE;
3438}
3439
3440static const struct rb_callinfo *
3441ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3442{
3443 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3444 vm_ci_flag(ci) | add,
3445 vm_ci_argc(ci),
3446 vm_ci_kwarg(ci));
3447 RB_OBJ_WRITTEN(iseq, ci, nci);
3448 return nci;
3449}
3450
3451static const struct rb_callinfo *
3452ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3453{
3454 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3455 vm_ci_flag(ci),
3456 argc,
3457 vm_ci_kwarg(ci));
3458 RB_OBJ_WRITTEN(iseq, ci, nci);
3459 return nci;
3460}
3461
3462#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3463
3464static VALUE
3465iseq_reg_compile(rb_iseq_t *iseq, VALUE str, int options, const char *sourcefile, int sourceline)
3466{
3467 VALUE errinfo = rb_errinfo();
3468 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3469 if (NIL_P(re)) {
3470 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3471 rb_set_errinfo(errinfo);
3472 COMPILE_ERROR(iseq, sourceline, "%" PRIsVALUE, message);
3473 }
3474 else {
3475 RB_OBJ_SET_SHAREABLE(re);
3476 }
3477 return re;
3478}
3479
3480static int
3481iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3482{
3483 INSN *const iobj = (INSN *)list;
3484
3485 again:
3486 optimize_checktype(iseq, iobj);
3487
3488 if (IS_INSN_ID(iobj, jump)) {
3489 INSN *niobj, *diobj, *piobj;
3490 diobj = (INSN *)get_destination_insn(iobj);
3491 niobj = (INSN *)get_next_insn(iobj);
3492
3493 if (diobj == niobj) {
3494 /*
3495 * jump LABEL
3496 * LABEL:
3497 * =>
3498 * LABEL:
3499 */
3500 unref_destination(iobj, 0);
3501 ELEM_REMOVE(&iobj->link);
3502 return COMPILE_OK;
3503 }
3504 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3505 IS_INSN_ID(diobj, jump) &&
3506 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3507 diobj->insn_info.events == 0) {
3508 /*
3509 * useless jump elimination:
3510 * jump LABEL1
3511 * ...
3512 * LABEL1:
3513 * jump LABEL2
3514 *
3515 * => in this case, first jump instruction should jump to
3516 * LABEL2 directly
3517 */
3518 if (replace_destination(iobj, diobj)) {
3519 remove_unreachable_chunk(iseq, iobj->link.next);
3520 goto again;
3521 }
3522 }
3523 else if (IS_INSN_ID(diobj, leave)) {
3524 /*
3525 * jump LABEL
3526 * ...
3527 * LABEL:
3528 * leave
3529 * =>
3530 * leave
3531 * ...
3532 * LABEL:
3533 * leave
3534 */
3535 /* replace */
3536 unref_destination(iobj, 0);
3537 iobj->insn_id = BIN(leave);
3538 iobj->operand_size = 0;
3539 iobj->insn_info = diobj->insn_info;
3540 goto again;
3541 }
3542 else if (IS_INSN(iobj->link.prev) &&
3543 (piobj = (INSN *)iobj->link.prev) &&
3544 (IS_INSN_ID(piobj, branchif) ||
3545 IS_INSN_ID(piobj, branchunless))) {
3546 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3547 if (niobj == pdiobj) {
3548 int refcnt = IS_LABEL(piobj->link.next) ?
3549 ((LABEL *)piobj->link.next)->refcnt : 0;
3550 /*
3551 * useless jump elimination (if/unless destination):
3552 * if L1
3553 * jump L2
3554 * L1:
3555 * ...
3556 * L2:
3557 *
3558 * ==>
3559 * unless L2
3560 * L1:
3561 * ...
3562 * L2:
3563 */
3564 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3565 ? BIN(branchunless) : BIN(branchif);
3566 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3567 ELEM_REMOVE(&iobj->link);
3568 }
3569 else {
3570 /* TODO: replace other branch destinations too */
3571 }
3572 return COMPILE_OK;
3573 }
3574 else if (diobj == pdiobj) {
3575 /*
3576 * useless jump elimination (if/unless before jump):
3577 * L1:
3578 * ...
3579 * if L1
3580 * jump L1
3581 *
3582 * ==>
3583 * L1:
3584 * ...
3585 * pop
3586 * jump L1
3587 */
3588 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3589 ELEM_REPLACE(&piobj->link, &popiobj->link);
3590 }
3591 }
3592 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3593 goto again;
3594 }
3595 }
3596
3597 /*
3598 * dupstring "beg"
3599 * dupstring "end"
3600 * newrange excl
3601 *
3602 * ==>
3603 *
3604 * putobject "beg".."end"
3605 */
3606 if (IS_INSN_ID(iobj, newrange)) {
3607 INSN *const range = iobj;
3608 INSN *beg, *end;
3609 VALUE str_beg, str_end;
3610
3611 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3612 is_frozen_putstring(end, &str_end) &&
3613 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3614 is_frozen_putstring(beg, &str_beg) &&
3615 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3616 int excl = FIX2INT(OPERAND_AT(range, 0));
3617 VALUE lit_range = RB_OBJ_SET_SHAREABLE(rb_range_new(str_beg, str_end, excl));
3618
3619 ELEM_REMOVE(&beg->link);
3620 ELEM_REMOVE(&end->link);
3621 range->insn_id = BIN(putobject);
3622 OPERAND_AT(range, 0) = lit_range;
3623 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3624 }
3625 }
3626
3627 if (IS_INSN_ID(iobj, leave)) {
3628 remove_unreachable_chunk(iseq, iobj->link.next);
3629 }
3630
3631 /*
3632 * ...
3633 * duparray [...]
3634 * concatarray | concattoarray
3635 * =>
3636 * ...
3637 * putobject [...]
3638 * concatarray | concattoarray
3639 */
3640 if (IS_INSN_ID(iobj, duparray)) {
3641 LINK_ELEMENT *next = iobj->link.next;
3642 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3643 iobj->insn_id = BIN(putobject);
3644 }
3645 }
3646
3647 /*
3648 * duparray [...]
3649 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3650 * =>
3651 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3652 */
3653 if (IS_INSN_ID(iobj, duparray)) {
3654 LINK_ELEMENT *next = iobj->link.next;
3655 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3656 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3657 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3658
3659 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3660 VALUE ary = iobj->operands[0];
3662
3663 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3664 ELEM_REMOVE(next);
3665 }
3666 }
3667 }
3668
3669 /*
3670 * duphash {...}
3671 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3672 * =>
3673 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3674 */
3675 if (IS_INSN_ID(iobj, duphash)) {
3676 LINK_ELEMENT *next = iobj->link.next;
3677 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3678 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3679 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3680
3681 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3682 VALUE hash = iobj->operands[0];
3683 rb_obj_reveal(hash, rb_cHash);
3684 RB_OBJ_SET_SHAREABLE(hash);
3685
3686 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3687 ELEM_REMOVE(next);
3688 }
3689 }
3690 }
3691
3692 /*
3693 * newarray 0
3694 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3695 * =>
3696 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3697 */
3698 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3699 LINK_ELEMENT *next = iobj->link.next;
3700 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3701 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3702 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3703
3704 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3705 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3706 ELEM_REMOVE(next);
3707 }
3708 }
3709 }
3710
3711 /*
3712 * newhash 0
3713 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3714 * =>
3715 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3716 */
3717 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3718 LINK_ELEMENT *next = iobj->link.next;
3719 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3720 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3721 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3722
3723 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3724 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3725 ELEM_REMOVE(next);
3726 }
3727 }
3728 }
3729
3730 if (IS_INSN_ID(iobj, branchif) ||
3731 IS_INSN_ID(iobj, branchnil) ||
3732 IS_INSN_ID(iobj, branchunless)) {
3733 /*
3734 * if L1
3735 * ...
3736 * L1:
3737 * jump L2
3738 * =>
3739 * if L2
3740 */
3741 INSN *nobj = (INSN *)get_destination_insn(iobj);
3742
3743 /* This jump-jump optimization may ignore line events on the jump
3744 * instruction being skipped. For example, the Line 2 TracePoint
3745 * event would otherwise never fire in the following code:
3746 *
3747 * 1: raise if 1 == 2
3748 * 2: while true
3749 * 3: break
3750 * 4: end
3751 *
3752 * Do not skip a jump that carries a line event. This applies even
3753 * when coverage is disabled because TracePoint consumes the same
3754 * event. [Bug #15980]
3755 */
3756 int stop_optimization =
3757 nobj->link.type == ISEQ_ELEMENT_INSN &&
3758 (nobj->insn_info.events & (RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3759 if (!stop_optimization) {
3760 INSN *pobj = (INSN *)iobj->link.prev;
3761 int prev_dup = 0;
3762 if (pobj) {
3763 if (!IS_INSN(&pobj->link))
3764 pobj = 0;
3765 else if (IS_INSN_ID(pobj, dup))
3766 prev_dup = 1;
3767 }
3768
3769 for (;;) {
3770 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3771 if (!replace_destination(iobj, nobj)) break;
3772 }
3773 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3774 !!(nobj = (INSN *)nobj->link.next) &&
3775 IS_INSN(&nobj->link) &&
3776 /* basic blocks, with no labels in the middle */
3777 nobj->insn_id == iobj->insn_id) {
3778 /*
3779 * dup
3780 * if L1
3781 * ...
3782 * L1:
3783 * dup
3784 * if L2
3785 * =>
3786 * dup
3787 * if L2
3788 * ...
3789 * L1:
3790 * dup
3791 * if L2
3792 */
3793 if (!replace_destination(iobj, nobj)) break;
3794 }
3795 else if (pobj) {
3796 /*
3797 * putnil
3798 * if L1
3799 * =>
3800 * # nothing
3801 *
3802 * putobject true
3803 * if L1
3804 * =>
3805 * jump L1
3806 *
3807 * dupstring ".."
3808 * if L1
3809 * =>
3810 * jump L1
3811 *
3812 * dupstring ".."
3813 * dup
3814 * if L1
3815 * =>
3816 * dupstring ".."
3817 * jump L1
3818 *
3819 */
3820 int cond;
3821 if (prev_dup && IS_INSN(pobj->link.prev)) {
3822 pobj = (INSN *)pobj->link.prev;
3823 }
3824 if (IS_INSN_ID(pobj, putobject)) {
3825 cond = (IS_INSN_ID(iobj, branchif) ?
3826 OPERAND_AT(pobj, 0) != Qfalse :
3827 IS_INSN_ID(iobj, branchunless) ?
3828 OPERAND_AT(pobj, 0) == Qfalse :
3829 FALSE);
3830 }
3831 else if (IS_INSN_ID(pobj, dupstring) ||
3832 IS_INSN_ID(pobj, duparray) ||
3833 IS_INSN_ID(pobj, newarray)) {
3834 cond = IS_INSN_ID(iobj, branchif);
3835 }
3836 else if (IS_INSN_ID(pobj, putnil)) {
3837 cond = !IS_INSN_ID(iobj, branchif);
3838 }
3839 else break;
3840 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3841 ELEM_REMOVE(iobj->link.prev);
3842 }
3843 else if (!iseq_pop_newarray(iseq, pobj)) {
3844 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3845 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3846 }
3847 if (cond) {
3848 if (prev_dup) {
3849 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3850 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3851 }
3852 iobj->insn_id = BIN(jump);
3853 goto again;
3854 }
3855 else {
3856 unref_destination(iobj, 0);
3857 ELEM_REMOVE(&iobj->link);
3858 }
3859 break;
3860 }
3861 else break;
3862 {
3863 LINK_ELEMENT *dest = get_destination_insn(nobj);
3864 if (!dest || !IS_INSN(dest)) break;
3865 nobj = (INSN *)dest;
3866 }
3867 }
3868 }
3869 }
3870
3871 if (IS_INSN_ID(iobj, pop)) {
3872 /*
3873 * putself / putnil / putobject obj / dupstring "..."
3874 * pop
3875 * =>
3876 * # do nothing
3877 */
3878 LINK_ELEMENT *prev = iobj->link.prev;
3879 if (IS_INSN(prev)) {
3880 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3881 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3882 previ == BIN(putself) || previ == BIN(dupstring) ||
3883 previ == BIN(dupchilledstring) ||
3884 previ == BIN(dup) ||
3885 previ == BIN(getlocal) ||
3886 previ == BIN(getblockparam) ||
3887 previ == BIN(getblockparamproxy) ||
3888 previ == BIN(getinstancevariable) ||
3889 previ == BIN(duparray)) {
3890 /* just push operand or static value and pop soon, no
3891 * side effects */
3892 ELEM_REMOVE(prev);
3893 ELEM_REMOVE(&iobj->link);
3894 }
3895 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3896 ELEM_REMOVE(&iobj->link);
3897 }
3898 else if (previ == BIN(concatarray)) {
3899 INSN *piobj = (INSN *)prev;
3900 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3901 INSN_OF(piobj) = BIN(pop);
3902 }
3903 else if (previ == BIN(concatstrings)) {
3904 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3905 ELEM_REMOVE(prev);
3906 }
3907 else {
3908 ELEM_REMOVE(&iobj->link);
3909 INSN_OF(prev) = BIN(adjuststack);
3910 }
3911 }
3912 }
3913 }
3914
3915 if (IS_INSN_ID(iobj, newarray) ||
3916 IS_INSN_ID(iobj, duparray) ||
3917 IS_INSN_ID(iobj, concatarray) ||
3918 IS_INSN_ID(iobj, splatarray) ||
3919 0) {
3920 /*
3921 * newarray N
3922 * splatarray
3923 * =>
3924 * newarray N
3925 * newarray always puts an array
3926 */
3927 LINK_ELEMENT *next = iobj->link.next;
3928 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3929 /* remove splatarray following always-array insn */
3930 ELEM_REMOVE(next);
3931 }
3932 }
3933
3934 if (IS_INSN_ID(iobj, newarray)) {
3935 LINK_ELEMENT *next = iobj->link.next;
3936 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3937 OPERAND_AT(next, 1) == INT2FIX(0)) {
3938 VALUE op1, op2;
3939 op1 = OPERAND_AT(iobj, 0);
3940 op2 = OPERAND_AT(next, 0);
3941 ELEM_REMOVE(next);
3942
3943 if (op1 == op2) {
3944 /*
3945 * newarray 2
3946 * expandarray 2, 0
3947 * =>
3948 * swap
3949 */
3950 if (op1 == INT2FIX(2)) {
3951 INSN_OF(iobj) = BIN(swap);
3952 iobj->operand_size = 0;
3953 }
3954 /*
3955 * newarray X
3956 * expandarray X, 0
3957 * =>
3958 * opt_reverse X
3959 */
3960 else {
3961 INSN_OF(iobj) = BIN(opt_reverse);
3962 }
3963 }
3964 else {
3965 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3966 INSN_OF(iobj) = BIN(opt_reverse);
3967 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3968
3969 if (op1 > op2) {
3970 /* X > Y
3971 * newarray X
3972 * expandarray Y, 0
3973 * =>
3974 * pop * (Y-X)
3975 * opt_reverse Y
3976 */
3977 for (; diff > 0; diff--) {
3978 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3979 }
3980 }
3981 else { /* (op1 < op2) */
3982 /* X < Y
3983 * newarray X
3984 * expandarray Y, 0
3985 * =>
3986 * putnil * (Y-X)
3987 * opt_reverse Y
3988 */
3989 for (; diff < 0; diff++) {
3990 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3991 }
3992 }
3993 }
3994 }
3995 }
3996
3997 if (IS_INSN_ID(iobj, duparray)) {
3998 LINK_ELEMENT *next = iobj->link.next;
3999 /*
4000 * duparray obj
4001 * expandarray X, 0
4002 * =>
4003 * putobject obj
4004 * expandarray X, 0
4005 */
4006 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
4007 INSN_OF(iobj) = BIN(putobject);
4008 }
4009 }
4010
4011 if (IS_INSN_ID(iobj, anytostring)) {
4012 LINK_ELEMENT *next = iobj->link.next;
4013 /*
4014 * anytostring
4015 * concatstrings 1
4016 * =>
4017 * anytostring
4018 */
4019 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
4020 OPERAND_AT(next, 0) == INT2FIX(1)) {
4021 ELEM_REMOVE(next);
4022 }
4023 }
4024
4025 if (IS_INSN_ID(iobj, dupstring) || IS_INSN_ID(iobj, dupchilledstring) ||
4026 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
4027 /*
4028 * dupstring ""
4029 * concatstrings N
4030 * =>
4031 * concatstrings N-1
4032 */
4033 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
4034 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
4035 INSN *next = (INSN *)iobj->link.next;
4036 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
4037 ELEM_REMOVE(&next->link);
4038 }
4039 ELEM_REMOVE(&iobj->link);
4040 }
4041 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
4042 INSN *next = (INSN *)iobj->link.next;
4043 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
4044 VALUE src = OPERAND_AT(iobj, 0);
4045 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
4046 VALUE path = rb_iseq_path(iseq);
4047 int line = iobj->insn_info.line_no;
4048 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
4049 /* The folded operand is a Regexp, so the instruction must be
4050 * putobject: dupstring/dupchilledstring would resurrect the
4051 * Regexp as a String at run time (e.g. for a /o regexp whose
4052 * interpolation folds to a constant, such as /#{"a"}/o). */
4053 iobj->insn_id = BIN(putobject);
4054 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
4055 ELEM_REMOVE(iobj->link.next);
4056 }
4057 }
4058 }
4059
4060 if (IS_INSN_ID(iobj, concatstrings)) {
4061 /*
4062 * concatstrings N
4063 * concatstrings M
4064 * =>
4065 * concatstrings N+M-1
4066 */
4067 LINK_ELEMENT *next = iobj->link.next;
4068 INSN *jump = 0;
4069 if (IS_INSN(next) && IS_INSN_ID(next, jump))
4070 next = get_destination_insn(jump = (INSN *)next);
4071 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
4072 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
4073 OPERAND_AT(iobj, 0) = INT2FIX(n);
4074 if (jump) {
4075 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
4076 if (!--label->refcnt) {
4077 ELEM_REMOVE(&label->link);
4078 }
4079 else {
4080 label = NEW_LABEL(0);
4081 OPERAND_AT(jump, 0) = (VALUE)label;
4082 }
4083 label->refcnt++;
4084 ELEM_INSERT_NEXT(next, &label->link);
4085 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
4086 }
4087 else {
4088 ELEM_REMOVE(next);
4089 }
4090 }
4091 }
4092
4093 if (do_tailcallopt &&
4094 (IS_INSN_ID(iobj, send) ||
4095 IS_INSN_ID(iobj, invokesuper))) {
4096 /*
4097 * send ...
4098 * leave
4099 * =>
4100 * send ..., ... | VM_CALL_TAILCALL, ...
4101 * leave # unreachable
4102 */
4103 INSN *piobj = NULL;
4104 if (iobj->link.next) {
4105 LINK_ELEMENT *next = iobj->link.next;
4106 do {
4107 if (!IS_INSN(next)) {
4108 next = next->next;
4109 continue;
4110 }
4111 switch (INSN_OF(next)) {
4112 case BIN(nop):
4113 next = next->next;
4114 break;
4115 case BIN(jump):
4116 /* if cond
4117 * return tailcall
4118 * end
4119 */
4120 next = get_destination_insn((INSN *)next);
4121 break;
4122 case BIN(leave):
4123 piobj = iobj;
4124 /* fall through */
4125 default:
4126 next = NULL;
4127 break;
4128 }
4129 } while (next);
4130 }
4131
4132 if (piobj) {
4133 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
4134 if (IS_INSN_ID(piobj, send) ||
4135 IS_INSN_ID(piobj, invokesuper)) {
4136 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
4137 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4138 OPERAND_AT(piobj, 0) = (VALUE)ci;
4139 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4140 }
4141 }
4142 else {
4143 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4144 OPERAND_AT(piobj, 0) = (VALUE)ci;
4145 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4146 }
4147 }
4148 }
4149
4150 if (IS_INSN_ID(iobj, dup)) {
4151 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4152 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4153
4154 /*
4155 * dup
4156 * setlocal x, y
4157 * setlocal x, y
4158 * =>
4159 * dup
4160 * setlocal x, y
4161 */
4162 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4163 set2 = set1->next;
4164 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4165 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4166 ELEM_REMOVE(set1);
4167 ELEM_REMOVE(&iobj->link);
4168 }
4169 }
4170
4171 /*
4172 * dup
4173 * setlocal x, y
4174 * dup
4175 * setlocal x, y
4176 * =>
4177 * dup
4178 * setlocal x, y
4179 */
4180 else if (IS_NEXT_INSN_ID(set1, dup) &&
4181 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4182 set2 = set1->next->next;
4183 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4184 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4185 ELEM_REMOVE(set1->next);
4186 ELEM_REMOVE(set2);
4187 }
4188 }
4189 }
4190 }
4191
4192 /*
4193 * getlocal x, y
4194 * dup
4195 * setlocal x, y
4196 * =>
4197 * dup
4198 */
4199 if (IS_INSN_ID(iobj, getlocal)) {
4200 LINK_ELEMENT *niobj = &iobj->link;
4201 if (IS_NEXT_INSN_ID(niobj, dup)) {
4202 niobj = niobj->next;
4203 }
4204 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4205 LINK_ELEMENT *set1 = niobj->next;
4206 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4207 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4208 ELEM_REMOVE(set1);
4209 ELEM_REMOVE(niobj);
4210 }
4211 }
4212 }
4213
4214 /*
4215 * opt_invokebuiltin_delegate
4216 * trace
4217 * leave
4218 * =>
4219 * opt_invokebuiltin_delegate_leave
4220 * trace
4221 * leave
4222 */
4223 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4224 if (IS_TRACE(iobj->link.next)) {
4225 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4226 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4227 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4228 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4229 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4230 }
4231 }
4232 }
4233 }
4234
4235 /*
4236 * getblockparam
4237 * branchif / branchunless
4238 * =>
4239 * getblockparamproxy
4240 * branchif / branchunless
4241 */
4242 if (IS_INSN_ID(iobj, getblockparam)) {
4243 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4244 iobj->insn_id = BIN(getblockparamproxy);
4245 }
4246 }
4247
4248 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4249 LINK_ELEMENT *niobj = &iobj->link;
4250 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4251 niobj = niobj->next;
4252 LINK_ELEMENT *siobj;
4253 unsigned int set_flags = 0, unset_flags = 0;
4254
4255 /*
4256 * Eliminate hash allocation for f(*a, kw: 1)
4257 *
4258 * splatarray false
4259 * duphash
4260 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4261 * =>
4262 * splatarray false
4263 * putobject
4264 * send ARGS_SPLAT|KW_SPLAT
4265 */
4266 if (IS_NEXT_INSN_ID(niobj, send)) {
4267 siobj = niobj->next;
4268 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4269 unset_flags = VM_CALL_ARGS_BLOCKARG;
4270 }
4271 /*
4272 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4273 *
4274 * splatarray false
4275 * duphash
4276 * getlocal / getinstancevariable / getblockparamproxy
4277 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4278 * =>
4279 * splatarray false
4280 * putobject
4281 * getlocal / getinstancevariable / getblockparamproxy
4282 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4283 */
4284 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4285 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4286 siobj = niobj->next->next;
4287 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4288 }
4289
4290 if (set_flags) {
4291 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4292 unsigned int flags = vm_ci_flag(ci);
4293 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4294 ((INSN*)niobj)->insn_id = BIN(putobject);
4295 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4296
4297 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4298 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4299 RB_OBJ_WRITTEN(iseq, ci, nci);
4300 OPERAND_AT(siobj, 0) = (VALUE)nci;
4301 }
4302 }
4303 }
4304 }
4305
4306 /*
4307 * putself / (or any other independent instruction)
4308 * putnil / (or any other independent instruction)
4309 * swap
4310 * =>
4311 * putnil / (or any other independent instruction)
4312 * putself / (or any other independent instruction)
4313 */
4314 if (IS_NEXT_NEXT_INSN_ID(&iobj->link, swap)) {
4315 LINK_ELEMENT *first = &iobj->link;
4316 LINK_ELEMENT *second = first->next;
4317 LINK_ELEMENT *swap = second->next;
4318 if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) {
4319 ELEM_REMOVE(swap);
4320 ELEM_SWAP(first, second);
4321 }
4322 }
4323
4324 return COMPILE_OK;
4325}
4326
4327static int
4328insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4329{
4330 if (insn_id == BIN(opt_neq)) {
4331 VALUE original_ci = iobj->operands[0];
4332 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4333 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4334 }
4335 else {
4336 iobj->insn_id = insn_id;
4337 iobj->operand_size = insn_len(insn_id) - 1;
4338 }
4339 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4340
4341 return COMPILE_OK;
4342}
4343
4344static int
4345iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4346{
4347 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4348 IS_INSN(iobj->link.next)) {
4349 /*
4350 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4351 */
4352 INSN *niobj = (INSN *)iobj->link.next;
4353 if (IS_INSN_ID(niobj, send)) {
4354 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4355 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4356 VALUE method = INT2FIX(0);
4357 switch (vm_ci_mid(ci)) {
4358 case idMax:
4359 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4360 break;
4361 case idMin:
4362 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4363 break;
4364 case idHash:
4365 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4366 break;
4367 }
4368
4369 if (method != INT2FIX(0)) {
4370 VALUE num = iobj->operands[0];
4371 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4372 ELEM_REMOVE(&niobj->link);
4373 return COMPILE_OK;
4374 }
4375 }
4376 }
4377 else if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4378 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4379 IS_NEXT_INSN_ID(&niobj->link, send)) {
4380 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4381 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4382 VALUE num = iobj->operands[0];
4383 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4384 ELEM_REMOVE(&iobj->link);
4385 ELEM_REMOVE(niobj->link.next);
4386 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4387 return COMPILE_OK;
4388 }
4389 }
4390 // newarray n, dupchilledstring "E", getlocal b, send :pack with {buffer: b}
4391 // -> dupchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
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, getlocal) &&
4395 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4396 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4397 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4398 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4399 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4400 VALUE num = iobj->operands[0];
4401 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4402 // Remove the "send" insn.
4403 ELEM_REMOVE((niobj->link.next)->next);
4404 // Remove the modified insn from its original "newarray" position...
4405 ELEM_REMOVE(&iobj->link);
4406 // and insert it after the buffer insn.
4407 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4408 return COMPILE_OK;
4409 }
4410 }
4411
4412 // Break the "else if" chain since some prior checks abort after sub-ifs.
4413 // We already found "newarray". To match `[...].include?(arg)` we look for
4414 // the instruction(s) representing the argument followed by a "send".
4415 if ((IS_INSN_ID(niobj, dupstring) || IS_INSN_ID(niobj, dupchilledstring) ||
4416 IS_INSN_ID(niobj, putobject) ||
4417 IS_INSN_ID(niobj, putself) ||
4418 IS_INSN_ID(niobj, getlocal) ||
4419 IS_INSN_ID(niobj, getinstancevariable)) &&
4420 IS_NEXT_INSN_ID(&niobj->link, send)) {
4421
4422 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4423 const struct rb_callinfo *ci;
4424 // Allow any number (0 or more) of simple method calls on the argument
4425 // (as in `[...].include?(arg.method1.method2)`.
4426 do {
4427 sendobj = sendobj->next;
4428 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4429 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4430
4431 // If this send is for .include? with one arg we can do our opt.
4432 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4433 VALUE num = iobj->operands[0];
4434 INSN *sendins = (INSN *)sendobj;
4435 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4436 // Remove the original "newarray" insn.
4437 ELEM_REMOVE(&iobj->link);
4438 return COMPILE_OK;
4439 }
4440 }
4441 }
4442
4443 /*
4444 * duparray [...]
4445 * some insn for the arg...
4446 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4447 * =>
4448 * arg insn...
4449 * opt_duparray_send [...], :include?, 1
4450 */
4451 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4452 INSN *niobj = (INSN *)iobj->link.next;
4453 if ((IS_INSN_ID(niobj, getlocal) ||
4454 IS_INSN_ID(niobj, getinstancevariable) ||
4455 IS_INSN_ID(niobj, putself) ||
4456 IS_INSN_ID(niobj, putobject) ||
4457 IS_INSN_ID(niobj, putnil)) &&
4458 IS_NEXT_INSN_ID(&niobj->link, send)) {
4459
4460 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4461 const struct rb_callinfo *ci;
4462 // Allow any number (0 or more) of simple method calls on the argument
4463 // (as in `[...].include?(arg.method1.method2)`.
4464 do {
4465 sendobj = sendobj->next;
4466 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4467 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4468
4469 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4470 // Move the array arg from duparray to opt_duparray_send.
4471 VALUE ary = iobj->operands[0];
4473
4474 INSN *sendins = (INSN *)sendobj;
4475 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4476
4477 // Remove the duparray insn.
4478 ELEM_REMOVE(&iobj->link);
4479 return COMPILE_OK;
4480 }
4481 }
4482 }
4483
4484
4485 if (IS_INSN_ID(iobj, send)) {
4486 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4487 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4488
4489#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4490 if (vm_ci_simple(ci)) {
4491 switch (vm_ci_argc(ci)) {
4492 case 0:
4493 switch (vm_ci_mid(ci)) {
4494 case idLength: SP_INSN(length); return COMPILE_OK;
4495 case idSize: SP_INSN(size); return COMPILE_OK;
4496 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4497 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4498 case idSucc: SP_INSN(succ); return COMPILE_OK;
4499 case idNot: SP_INSN(not); return COMPILE_OK;
4500 }
4501 break;
4502 case 1:
4503 switch (vm_ci_mid(ci)) {
4504 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4505 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4506 case idMULT: SP_INSN(mult); return COMPILE_OK;
4507 case idDIV: SP_INSN(div); return COMPILE_OK;
4508 case idMOD: SP_INSN(mod); return COMPILE_OK;
4509 case idEq: SP_INSN(eq); return COMPILE_OK;
4510 case idNeq: SP_INSN(neq); return COMPILE_OK;
4511 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4512 case idLT: SP_INSN(lt); return COMPILE_OK;
4513 case idLE: SP_INSN(le); return COMPILE_OK;
4514 case idGT: SP_INSN(gt); return COMPILE_OK;
4515 case idGE: SP_INSN(ge); return COMPILE_OK;
4516 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4517 case idAREF: SP_INSN(aref); return COMPILE_OK;
4518 case idAnd: SP_INSN(and); return COMPILE_OK;
4519 case idOr: SP_INSN(or); return COMPILE_OK;
4520 }
4521 break;
4522 case 2:
4523 switch (vm_ci_mid(ci)) {
4524 case idASET: SP_INSN(aset); return COMPILE_OK;
4525 }
4526 break;
4527 }
4528 }
4529
4530 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4531 iobj->insn_id = BIN(opt_send_without_block);
4532 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4533 }
4534 }
4535#undef SP_INSN
4536
4537 return COMPILE_OK;
4538}
4539
4540static inline int
4541tailcallable_p(rb_iseq_t *iseq)
4542{
4543 switch (ISEQ_BODY(iseq)->type) {
4544 case ISEQ_TYPE_TOP:
4545 case ISEQ_TYPE_EVAL:
4546 case ISEQ_TYPE_MAIN:
4547 /* not tail callable because cfp will be over popped */
4548 case ISEQ_TYPE_RESCUE:
4549 case ISEQ_TYPE_ENSURE:
4550 /* rescue block can't tail call because of errinfo */
4551 return FALSE;
4552 default:
4553 return TRUE;
4554 }
4555}
4556
4557static int
4558iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4559{
4560 LINK_ELEMENT *list;
4561 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4562 const int do_tailcallopt = tailcallable_p(iseq) &&
4563 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4564 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4565 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4566 const int do_without_ints = ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_WITHOUT_INTERRUPTS;
4567 int rescue_level = 0;
4568 int tailcallopt = do_tailcallopt;
4569
4570 list = FIRST_ELEMENT(anchor);
4571
4572 int do_block_optimization = 0;
4573 LABEL * block_loop_label = NULL;
4574
4575 // If we're optimizing a block
4576 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4577 do_block_optimization = 1;
4578
4579 // If the block starts with a nop and a label,
4580 // record the label so we can detect if it's a jump target
4581 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4582 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4583 block_loop_label = (LABEL *)le->next;
4584 }
4585 }
4586
4587 while (list) {
4588 if (IS_INSN(list)) {
4589 if (do_peepholeopt) {
4590 iseq_peephole_optimize(iseq, list, tailcallopt);
4591 }
4592 if (do_si) {
4593 iseq_specialized_instruction(iseq, (INSN *)list);
4594 }
4595 if (do_ou) {
4596 insn_operands_unification((INSN *)list);
4597 }
4598
4599 if (do_without_ints) {
4600 INSN *item = (INSN *)list;
4601 if (IS_INSN_ID(item, jump)) {
4602 item->insn_id = BIN(jump_without_ints);
4603 }
4604 else if (IS_INSN_ID(item, branchif)) {
4605 item->insn_id = BIN(branchif_without_ints);
4606 }
4607 else if (IS_INSN_ID(item, branchunless)) {
4608 item->insn_id = BIN(branchunless_without_ints);
4609 }
4610 else if (IS_INSN_ID(item, branchnil)) {
4611 item->insn_id = BIN(branchnil_without_ints);
4612 }
4613 }
4614
4615 if (do_block_optimization) {
4616 INSN * item = (INSN *)list;
4617 // Give up if there is a throw
4618 if (IS_INSN_ID(item, throw)) {
4619 do_block_optimization = 0;
4620 }
4621 else {
4622 // If the instruction has a jump target, check if the
4623 // jump target is the block loop label
4624 const char *types = insn_op_types(item->insn_id);
4625 for (int j = 0; types[j]; j++) {
4626 if (types[j] == TS_OFFSET) {
4627 // If the jump target is equal to the block loop
4628 // label, then we can't do the optimization because
4629 // the leading `nop` instruction fires the block
4630 // entry tracepoint
4631 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4632 if (target == block_loop_label) {
4633 do_block_optimization = 0;
4634 }
4635 }
4636 }
4637 }
4638 }
4639 }
4640 if (IS_LABEL(list)) {
4641 switch (((LABEL *)list)->rescued) {
4642 case LABEL_RESCUE_BEG:
4643 rescue_level++;
4644 tailcallopt = FALSE;
4645 break;
4646 case LABEL_RESCUE_END:
4647 if (!--rescue_level) tailcallopt = do_tailcallopt;
4648 break;
4649 }
4650 }
4651 list = list->next;
4652 }
4653
4654 if (do_block_optimization) {
4655 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4656 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4657 ELEM_REMOVE(le);
4658 }
4659 }
4660 return COMPILE_OK;
4661}
4662
4663#if OPT_INSTRUCTIONS_UNIFICATION
4664static INSN *
4665new_unified_insn(rb_iseq_t *iseq,
4666 int insn_id, int size, LINK_ELEMENT *seq_list)
4667{
4668 INSN *iobj = 0;
4669 LINK_ELEMENT *list = seq_list;
4670 int i, argc = 0;
4671 VALUE *operands = 0, *ptr = 0;
4672
4673
4674 /* count argc */
4675 for (i = 0; i < size; i++) {
4676 iobj = (INSN *)list;
4677 argc += iobj->operand_size;
4678 list = list->next;
4679 }
4680
4681 if (argc > 0) {
4682 ptr = operands = compile_data_alloc2_type(iseq, VALUE, argc);
4683 }
4684
4685 /* copy operands */
4686 list = seq_list;
4687 for (i = 0; i < size; i++) {
4688 iobj = (INSN *)list;
4689 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4690 ptr += iobj->operand_size;
4691 list = list->next;
4692 }
4693
4694 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4695}
4696#endif
4697
4698/*
4699 * This scheme can get more performance if do this optimize with
4700 * label address resolving.
4701 * It's future work (if compile time was bottle neck).
4702 */
4703static int
4704iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4705{
4706#if OPT_INSTRUCTIONS_UNIFICATION
4707 LINK_ELEMENT *list;
4708 INSN *iobj, *niobj;
4709 int id, k;
4710 intptr_t j;
4711
4712 list = FIRST_ELEMENT(anchor);
4713 while (list) {
4714 if (IS_INSN(list)) {
4715 iobj = (INSN *)list;
4716 id = iobj->insn_id;
4717 if (unified_insns_data[id] != 0) {
4718 const int *const *entry = unified_insns_data[id];
4719 for (j = 1; j < (intptr_t)entry[0]; j++) {
4720 const int *unified = entry[j];
4721 LINK_ELEMENT *li = list->next;
4722 for (k = 2; k < unified[1]; k++) {
4723 if (!IS_INSN(li) ||
4724 ((INSN *)li)->insn_id != unified[k]) {
4725 goto miss;
4726 }
4727 li = li->next;
4728 }
4729 /* matched */
4730 niobj =
4731 new_unified_insn(iseq, unified[0], unified[1] - 1,
4732 list);
4733
4734 /* insert to list */
4735 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4736 niobj->link.next = li;
4737 if (li) {
4738 li->prev = (LINK_ELEMENT *)niobj;
4739 }
4740
4741 list->prev->next = (LINK_ELEMENT *)niobj;
4742 list = (LINK_ELEMENT *)niobj;
4743 break;
4744 miss:;
4745 }
4746 }
4747 }
4748 list = list->next;
4749 }
4750#endif
4751 return COMPILE_OK;
4752}
4753
4754static int
4755all_string_result_p(const NODE *node)
4756{
4757 if (!node) return FALSE;
4758 switch (nd_type(node)) {
4759 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4760 return TRUE;
4761 case NODE_IF: case NODE_UNLESS:
4762 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4763 if (all_string_result_p(RNODE_IF(node)->nd_body))
4764 return all_string_result_p(RNODE_IF(node)->nd_else);
4765 return FALSE;
4766 case NODE_AND: case NODE_OR:
4767 if (!RNODE_AND(node)->nd_2nd)
4768 return all_string_result_p(RNODE_AND(node)->nd_1st);
4769 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4770 return FALSE;
4771 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4772 default:
4773 return FALSE;
4774 }
4775}
4776
4778 rb_iseq_t *const iseq;
4779 LINK_ANCHOR *const ret;
4780 VALUE lit;
4781 const NODE *lit_node;
4782 int cnt;
4783 int dregx;
4784};
4785
4786static int
4787append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4788{
4789 VALUE s = rb_str_new_mutable_parser_string(str);
4790 if (args->dregx) {
4791 VALUE error = rb_reg_check_preprocess(s);
4792 if (!NIL_P(error)) {
4793 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4794 return COMPILE_NG;
4795 }
4796 }
4797 if (NIL_P(args->lit)) {
4798 args->lit = s;
4799 args->lit_node = node;
4800 }
4801 else {
4802 rb_str_buf_append(args->lit, s);
4803 }
4804 return COMPILE_OK;
4805}
4806
4807static void
4808flush_dstr_fragment(struct dstr_ctxt *args)
4809{
4810 if (!NIL_P(args->lit)) {
4811 rb_iseq_t *iseq = args->iseq;
4812 VALUE lit = args->lit;
4813 args->lit = Qnil;
4814 lit = rb_fstring(lit);
4815 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4816 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4817 args->cnt++;
4818 }
4819}
4820
4821static int
4822compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4823{
4824 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4825 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4826
4827 if (str) {
4828 CHECK(append_dstr_fragment(args, node, str));
4829 }
4830
4831 while (list) {
4832 const NODE *const head = list->nd_head;
4833 if (nd_type_p(head, NODE_STR)) {
4834 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4835 }
4836 else if (nd_type_p(head, NODE_DSTR)) {
4837 CHECK(compile_dstr_fragments_0(args, head));
4838 }
4839 else {
4840 flush_dstr_fragment(args);
4841 rb_iseq_t *iseq = args->iseq;
4842 CHECK(COMPILE(args->ret, "each string", head));
4843 args->cnt++;
4844 }
4845 list = (struct RNode_LIST *)list->nd_next;
4846 }
4847 return COMPILE_OK;
4848}
4849
4850static int
4851compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4852{
4853 struct dstr_ctxt args = {
4854 .iseq = iseq, .ret = ret,
4855 .lit = Qnil, .lit_node = NULL,
4856 .cnt = 0, .dregx = dregx,
4857 };
4858 CHECK(compile_dstr_fragments_0(&args, node));
4859 flush_dstr_fragment(&args);
4860
4861 *cntp = args.cnt;
4862
4863 return COMPILE_OK;
4864}
4865
4866static int
4867compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4868{
4869 while (node && nd_type_p(node, NODE_BLOCK)) {
4870 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4871 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4872 node = RNODE_BLOCK(node)->nd_next;
4873 }
4874 if (node) {
4875 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4876 }
4877 return COMPILE_OK;
4878}
4879
4880static int
4881compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4882{
4883 int cnt;
4884 if (!RNODE_DSTR(node)->nd_next) {
4885 VALUE lit = rb_node_dstr_string_val(node);
4886 ADD_INSN1(ret, node, dupstring, lit);
4887 RB_OBJ_SET_SHAREABLE(lit);
4888 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4889 }
4890 else {
4891 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4892 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4893 }
4894 return COMPILE_OK;
4895}
4896
4897static int
4898compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4899{
4900 int cnt;
4901 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4902
4903 if (!RNODE_DREGX(node)->nd_next) {
4904 if (!popped) {
4905 VALUE src = rb_node_dregx_string_val(node);
4906 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4907 ADD_INSN1(ret, node, putobject, match);
4908 RB_OBJ_WRITTEN(iseq, Qundef, match);
4909 }
4910 return COMPILE_OK;
4911 }
4912
4913 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4914 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4915
4916 if (popped) {
4917 ADD_INSN(ret, node, pop);
4918 }
4919
4920 return COMPILE_OK;
4921}
4922
4923static int
4924compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4925 LABEL *then_label, LABEL *else_label)
4926{
4927 const int line = nd_line(node);
4928 LABEL *lend = NEW_LABEL(line);
4929 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4930 + VM_SVAR_FLIPFLOP_START;
4931 VALUE key = INT2FIX(cnt);
4932
4933 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4934 ADD_INSNL(ret, node, branchif, lend);
4935
4936 /* *flip == 0 */
4937 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4938 ADD_INSNL(ret, node, branchunless, else_label);
4939 ADD_INSN1(ret, node, putobject, Qtrue);
4940 ADD_INSN1(ret, node, setspecial, key);
4941 if (!again) {
4942 ADD_INSNL(ret, node, jump, then_label);
4943 }
4944
4945 /* *flip == 1 */
4946 ADD_LABEL(ret, lend);
4947 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4948 ADD_INSNL(ret, node, branchunless, then_label);
4949 ADD_INSN1(ret, node, putobject, Qfalse);
4950 ADD_INSN1(ret, node, setspecial, key);
4951 ADD_INSNL(ret, node, jump, then_label);
4952
4953 return COMPILE_OK;
4954}
4955
4956static int
4957compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4958 LABEL *then_label, LABEL *else_label);
4959
4960#define COMPILE_SINGLE 2
4961static int
4962compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4963 LABEL *then_label, LABEL *else_label)
4964{
4965 DECL_ANCHOR(seq);
4966 INIT_ANCHOR(seq);
4967 LABEL *label = NEW_LABEL(nd_line(cond));
4968 if (!then_label) then_label = label;
4969 else if (!else_label) else_label = label;
4970
4971 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4972
4973 if (LIST_INSN_SIZE_ONE(seq)) {
4974 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4975 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4976 return COMPILE_OK;
4977 }
4978 if (!label->refcnt) {
4979 return COMPILE_SINGLE;
4980 }
4981 ADD_LABEL(seq, label);
4982 ADD_SEQ(ret, seq);
4983 return COMPILE_OK;
4984}
4985
4986static int
4987compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4988 LABEL *then_label, LABEL *else_label)
4989{
4990 int ok;
4991 DECL_ANCHOR(ignore);
4992
4993 again:
4994 switch (nd_type(cond)) {
4995 case NODE_AND:
4996 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4997 cond = RNODE_AND(cond)->nd_2nd;
4998 if (ok == COMPILE_SINGLE) {
4999 ADD_INSNL(ret, cond, jump, else_label);
5000 INIT_ANCHOR(ignore);
5001 ret = ignore;
5002 then_label = NEW_LABEL(nd_line(cond));
5003 }
5004 goto again;
5005 case NODE_OR:
5006 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
5007 cond = RNODE_OR(cond)->nd_2nd;
5008 if (ok == COMPILE_SINGLE) {
5009 ADD_INSNL(ret, cond, jump, then_label);
5010 INIT_ANCHOR(ignore);
5011 ret = ignore;
5012 else_label = NEW_LABEL(nd_line(cond));
5013 }
5014 goto again;
5015 case NODE_SYM:
5016 case NODE_LINE:
5017 case NODE_FILE:
5018 case NODE_ENCODING:
5019 case NODE_INTEGER: /* NODE_INTEGER is always true */
5020 case NODE_FLOAT: /* NODE_FLOAT is always true */
5021 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
5022 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
5023 case NODE_TRUE:
5024 case NODE_STR:
5025 case NODE_REGX:
5026 case NODE_ZLIST:
5027 case NODE_LAMBDA:
5028 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5029 ADD_INSNL(ret, cond, jump, then_label);
5030 return COMPILE_OK;
5031 case NODE_FALSE:
5032 case NODE_NIL:
5033 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
5034 ADD_INSNL(ret, cond, jump, else_label);
5035 return COMPILE_OK;
5036 case NODE_LIST:
5037 case NODE_ARGSCAT:
5038 case NODE_DREGX:
5039 case NODE_DSTR:
5040 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
5041 ADD_INSNL(ret, cond, jump, then_label);
5042 return COMPILE_OK;
5043 case NODE_FLIP2:
5044 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
5045 return COMPILE_OK;
5046 case NODE_FLIP3:
5047 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
5048 return COMPILE_OK;
5049 case NODE_DEFINED:
5050 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
5051 break;
5052 default:
5053 {
5054 DECL_ANCHOR(cond_seq);
5055 INIT_ANCHOR(cond_seq);
5056
5057 CHECK(COMPILE(cond_seq, "branch condition", cond));
5058
5059 if (LIST_INSN_SIZE_ONE(cond_seq)) {
5060 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
5061 if (insn->insn_id == BIN(putobject)) {
5062 if (RTEST(insn->operands[0])) {
5063 ADD_INSNL(ret, cond, jump, then_label);
5064 // maybe unreachable
5065 return COMPILE_OK;
5066 }
5067 else {
5068 ADD_INSNL(ret, cond, jump, else_label);
5069 return COMPILE_OK;
5070 }
5071 }
5072 }
5073 ADD_SEQ(ret, cond_seq);
5074 }
5075 break;
5076 }
5077
5078 ADD_INSNL(ret, cond, branchunless, else_label);
5079 ADD_INSNL(ret, cond, jump, then_label);
5080 return COMPILE_OK;
5081}
5082
5083#define HASH_BRACE 1
5084
5085static int
5086keyword_node_p(const NODE *const node)
5087{
5088 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
5089}
5090
5091static VALUE
5092get_symbol_value(rb_iseq_t *iseq, const NODE *node)
5093{
5094 switch (nd_type(node)) {
5095 case NODE_SYM:
5096 return rb_node_sym_string_val(node);
5097 default:
5098 UNKNOWN_NODE("get_symbol_value", node, Qnil);
5099 }
5100}
5101
5102static VALUE
5103node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
5104{
5105 NODE *node = node_hash->nd_head;
5106 VALUE hash = rb_hash_new();
5107 VALUE ary = rb_ary_new();
5108
5109 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5110 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
5111 VALUE idx = rb_hash_aref(hash, key);
5112 if (!NIL_P(idx)) {
5113 rb_ary_store(ary, FIX2INT(idx), Qfalse);
5114 (*count_ptr)--;
5115 }
5116 rb_hash_aset(hash, key, INT2FIX(i));
5117 rb_ary_store(ary, i, Qtrue);
5118 (*count_ptr)++;
5119 }
5120
5121 return ary;
5122}
5123
5124static int
5125compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5126 const NODE *const root_node,
5127 struct rb_callinfo_kwarg **const kw_arg_ptr,
5128 unsigned int *flag)
5129{
5130 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
5131 RUBY_ASSERT(kw_arg_ptr != NULL);
5132 RUBY_ASSERT(flag != NULL);
5133
5134 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5135 const NODE *node = RNODE_HASH(root_node)->nd_head;
5136 int seen_nodes = 0;
5137
5138 while (node) {
5139 const NODE *key_node = RNODE_LIST(node)->nd_head;
5140 seen_nodes++;
5141
5142 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
5143 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5144 /* can be keywords */
5145 }
5146 else {
5147 if (flag) {
5148 *flag |= VM_CALL_KW_SPLAT;
5149 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5150 /* A new hash will be created for the keyword arguments
5151 * in this case, so mark the method as passing mutable
5152 * keyword splat.
5153 */
5154 *flag |= VM_CALL_KW_SPLAT_MUT;
5155 }
5156 }
5157 return FALSE;
5158 }
5159 node = RNODE_LIST(node)->nd_next; /* skip value node */
5160 node = RNODE_LIST(node)->nd_next;
5161 }
5162
5163 /* may be keywords */
5164 node = RNODE_HASH(root_node)->nd_head;
5165 {
5166 int len = 0;
5167 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
5168
5169 if (len > VM_CALL_KW_LEN_MAX) {
5170 COMPILE_ERROR(ERROR_ARGS_AT(root_node) "too many keyword arguments (%d, maximum is %d)",
5171 len, (int)VM_CALL_KW_LEN_MAX);
5172 }
5173
5174 struct rb_callinfo_kwarg *kw_arg =
5175 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
5176 VALUE *keywords = kw_arg->keywords;
5177 int i = 0;
5178 int j = 0;
5179 kw_arg->references = 0;
5180 kw_arg->keyword_len = len;
5181
5182 *kw_arg_ptr = kw_arg;
5183
5184 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5185 const NODE *key_node = RNODE_LIST(node)->nd_head;
5186 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5187 int popped = TRUE;
5188 if (rb_ary_entry(key_index, i)) {
5189 keywords[j] = get_symbol_value(iseq, key_node);
5190 j++;
5191 popped = FALSE;
5192 }
5193 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
5194 }
5195 RUBY_ASSERT(j == len);
5196 return TRUE;
5197 }
5198 }
5199 return FALSE;
5200}
5201
5202static int
5203compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
5204{
5205 int len = 0;
5206
5207 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
5208 if (CPDEBUG > 0) {
5209 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
5210 }
5211
5212 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
5213 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5214 }
5215 else {
5216 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5217 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
5218 }
5219 }
5220
5221 return len;
5222}
5223
5224static inline bool
5225frozen_string_literal_p(const rb_iseq_t *iseq)
5226{
5227 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5228}
5229
5230static inline bool
5231static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
5232{
5233 switch (nd_type(node)) {
5234 case NODE_SYM:
5235 case NODE_REGX:
5236 case NODE_LINE:
5237 case NODE_ENCODING:
5238 case NODE_INTEGER:
5239 case NODE_FLOAT:
5240 case NODE_RATIONAL:
5241 case NODE_IMAGINARY:
5242 case NODE_NIL:
5243 case NODE_TRUE:
5244 case NODE_FALSE:
5245 return TRUE;
5246 case NODE_STR:
5247 case NODE_FILE:
5248 return hash_key || frozen_string_literal_p(iseq);
5249 default:
5250 return FALSE;
5251 }
5252}
5253
5254static inline VALUE
5255static_literal_value(const NODE *node, rb_iseq_t *iseq)
5256{
5257 switch (nd_type(node)) {
5258 case NODE_INTEGER:
5259 {
5260 VALUE lit = rb_node_integer_literal_val(node);
5261 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5262 return lit;
5263 }
5264 case NODE_FLOAT:
5265 {
5266 VALUE lit = rb_node_float_literal_val(node);
5267 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
5268 return lit;
5269 }
5270 case NODE_RATIONAL:
5271 return rb_ractor_make_shareable(rb_node_rational_literal_val(node));
5272 case NODE_IMAGINARY:
5273 return rb_ractor_make_shareable(rb_node_imaginary_literal_val(node));
5274 case NODE_NIL:
5275 return Qnil;
5276 case NODE_TRUE:
5277 return Qtrue;
5278 case NODE_FALSE:
5279 return Qfalse;
5280 case NODE_SYM:
5281 return rb_node_sym_string_val(node);
5282 case NODE_REGX:
5283 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5284 case NODE_LINE:
5285 return rb_node_line_lineno_val(node);
5286 case NODE_ENCODING:
5287 return rb_node_encoding_val(node);
5288 case NODE_FILE:
5289 case NODE_STR:
5290 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5291 VALUE lit = get_string_value(node);
5292 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5293 RB_OBJ_SET_SHAREABLE(str);
5294 return str;
5295 }
5296 else {
5297 return get_string_value(node);
5298 }
5299 default:
5300 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5301 }
5302}
5303
5304static int
5305compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5306{
5307 const NODE *line_node = node;
5308
5309 if (nd_type_p(node, NODE_ZLIST)) {
5310 if (!popped) {
5311 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5312 }
5313 return 0;
5314 }
5315
5316 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5317
5318 if (popped) {
5319 for (; node; node = RNODE_LIST(node)->nd_next) {
5320 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5321 }
5322 return 1;
5323 }
5324
5325 /* Compilation of an array literal.
5326 * The following code is essentially the same as:
5327 *
5328 * for (int count = 0; node; count++; node->nd_next) {
5329 * compile(node->nd_head);
5330 * }
5331 * ADD_INSN(newarray, count);
5332 *
5333 * However, there are three points.
5334 *
5335 * - The code above causes stack overflow for a big string literal.
5336 * The following limits the stack length up to max_stack_len.
5337 *
5338 * [x1,x2,...,x10000] =>
5339 * push x1 ; push x2 ; ...; push x256; newarray 256;
5340 * push x257; push x258; ...; push x512; pushtoarray 256;
5341 * push x513; push x514; ...; push x768; pushtoarray 256;
5342 * ...
5343 *
5344 * - Long subarray can be optimized by pre-allocating a hidden array.
5345 *
5346 * [1,2,3,...,100] =>
5347 * duparray [1,2,3,...,100]
5348 *
5349 * [x, 1,2,3,...,100, z] =>
5350 * push x; newarray 1;
5351 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5352 * push z; pushtoarray 1;
5353 *
5354 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5355 * to only push it onto the array if it is not empty
5356 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5357 *
5358 * [1,2,3,**kw] =>
5359 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5360 */
5361
5362 const int max_stack_len = 0x100;
5363 const int min_tmp_ary_len = 0x40;
5364 int stack_len = 0;
5365
5366 /* Either create a new array, or push to the existing array */
5367#define FLUSH_CHUNK \
5368 if (stack_len) { \
5369 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5370 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5371 first_chunk = FALSE; \
5372 stack_len = 0; \
5373 }
5374
5375 while (node) {
5376 int count = 1;
5377
5378 /* pre-allocation check (this branch can be omittable) */
5379 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5380 /* count the elements that are optimizable */
5381 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5382 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5383 count++;
5384
5385 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5386 /* The literal contains only optimizable elements, or the subarray is long enough */
5387 VALUE ary = rb_ary_hidden_new(count);
5388
5389 /* Create a hidden array */
5390 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5391 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5392 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5393
5394 /* Emit optimized code */
5395 FLUSH_CHUNK;
5396 if (first_chunk) {
5397 ADD_INSN1(ret, line_node, duparray, ary);
5398 first_chunk = FALSE;
5399 }
5400 else {
5401 ADD_INSN1(ret, line_node, putobject, ary);
5402 ADD_INSN(ret, line_node, concattoarray);
5403 }
5404 RB_OBJ_SET_SHAREABLE(ary);
5405 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5406 }
5407 }
5408
5409 /* Base case: Compile "count" elements */
5410 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5411 if (CPDEBUG > 0) {
5412 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5413 }
5414
5415 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5416 /* Create array or push existing non-keyword elements onto array */
5417 if (stack_len == 0 && first_chunk) {
5418 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5419 }
5420 else {
5421 FLUSH_CHUNK;
5422 }
5423 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5424 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5425 return 1;
5426 }
5427 else {
5428 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5429 stack_len++;
5430 }
5431
5432 /* If there are many pushed elements, flush them to avoid stack overflow */
5433 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5434 }
5435 }
5436
5437 FLUSH_CHUNK;
5438#undef FLUSH_CHUNK
5439 return 1;
5440}
5441
5442static inline int
5443static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5444{
5445 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);
5446}
5447
5448static int
5449compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5450{
5451 const NODE *line_node = node;
5452
5453 node = RNODE_HASH(node)->nd_head;
5454
5455 if (!node || nd_type_p(node, NODE_ZLIST)) {
5456 if (!popped) {
5457 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5458 }
5459 return 0;
5460 }
5461
5462 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5463
5464 if (popped) {
5465 for (; node; node = RNODE_LIST(node)->nd_next) {
5466 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5467 }
5468 return 1;
5469 }
5470
5471 /* Compilation of a hash literal (or keyword arguments).
5472 * This is very similar to compile_array, but there are some differences:
5473 *
5474 * - It contains key-value pairs. So we need to take every two elements.
5475 * We can assume that the length is always even.
5476 *
5477 * - Merging is done by a method call (id_core_hash_merge_bang_ptr).
5478 * Sometimes we need to insert the receiver, so "anchor" is needed.
5479 * In addition, a method call is much slower than concatarray.
5480 * So it pays only when the subsequence is really long.
5481 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5482 *
5483 * - We need to handle keyword splat: **kw.
5484 * For **kw, the key part (node->nd_head) is NULL, and the value part
5485 * (node->nd_next->nd_head) is "kw".
5486 * The code is a bit difficult to avoid hash allocation for **{}.
5487 */
5488
5489 const int max_stack_len = 0x100;
5490 const int min_tmp_hash_len = 0x800;
5491 int stack_len = 0;
5492 int first_chunk = 1;
5493 DECL_ANCHOR(anchor);
5494 INIT_ANCHOR(anchor);
5495
5496 /* Convert pushed elements to a hash, and merge if needed */
5497#define FLUSH_CHUNK() \
5498 if (stack_len) { \
5499 if (first_chunk) { \
5500 APPEND_LIST(ret, anchor); \
5501 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5502 } \
5503 else { \
5504 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5505 ADD_INSN(ret, line_node, swap); \
5506 APPEND_LIST(ret, anchor); \
5507 ADD_SEND(ret, line_node, id_core_hash_merge_bang_ptr, INT2FIX(stack_len + 1)); \
5508 } \
5509 INIT_ANCHOR(anchor); \
5510 first_chunk = stack_len = 0; \
5511 }
5512
5513 while (node) {
5514 int count = 1;
5515
5516 /* pre-allocation check (this branch can be omittable) */
5517 if (static_literal_node_pair_p(node, iseq)) {
5518 /* count the elements that are optimizable */
5519 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5520 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5521 count++;
5522
5523 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5524 /* The literal contains only optimizable elements, or the subsequence is long enough */
5525 VALUE ary = rb_ary_hidden_new(count);
5526
5527 /* Create a hidden hash */
5528 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5529 VALUE elem[2];
5530 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5531 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5532 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5533 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5534 rb_ary_cat(ary, elem, 2);
5535 }
5536 VALUE hash = rb_hash_alloc_fixed_size(Qfalse, RARRAY_LEN(ary) / 2);
5537 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5538 RB_GC_GUARD(ary);
5539 hash = RB_OBJ_SET_FROZEN_SHAREABLE(hash);
5540
5541 /* Emit optimized code */
5542 FLUSH_CHUNK();
5543 if (first_chunk) {
5544 ADD_INSN1(ret, line_node, duphash, hash);
5545 first_chunk = 0;
5546 }
5547 else {
5548 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5549 ADD_INSN(ret, line_node, swap);
5550
5551 ADD_INSN1(ret, line_node, putobject, hash);
5552
5553 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5554 }
5555 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5556 }
5557 }
5558
5559 /* Base case: Compile "count" elements */
5560 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5561
5562 if (CPDEBUG > 0) {
5563 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5564 }
5565
5566 if (RNODE_LIST(node)->nd_head) {
5567 /* Normal key-value pair */
5568 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5569 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5570 stack_len += 2;
5571
5572 /* If there are many pushed elements, flush them to avoid stack overflow */
5573 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5574 }
5575 else {
5576 /* kwsplat case: foo(..., **kw, ...) */
5577 FLUSH_CHUNK();
5578
5579 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5580 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5581 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5582 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5583 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5584
5585 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5586 if (empty_kw) {
5587 if (only_kw && method_call_keywords) {
5588 /* **{} appears at the only keyword argument in method call,
5589 * so it won't be modified.
5590 * kw is a special NODE_LIT that contains a special empty hash,
5591 * so this emits: putobject {}.
5592 * This is only done for method calls and not for literal hashes,
5593 * because literal hashes should always result in a new hash.
5594 */
5595 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5596 }
5597 else if (first_kw) {
5598 /* **{} appears as the first keyword argument, so it may be modified.
5599 * We need to create a fresh hash object.
5600 */
5601 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5602 }
5603 /* Any empty keyword splats that are not the first can be ignored.
5604 * since merging an empty hash into the existing hash is the same
5605 * as not merging it. */
5606 }
5607 else {
5608 if (only_kw && method_call_keywords) {
5609 /* **kw is only keyword argument in method call.
5610 * Use directly. This will be not be flagged as mutable.
5611 * This is only done for method calls and not for literal hashes,
5612 * because literal hashes should always result in a new hash.
5613 */
5614 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5615 }
5616 else {
5617 /* There is more than one keyword argument, or this is not a method
5618 * call. In that case, we need to add an empty hash (if first keyword),
5619 * or merge the hash to the accumulated hash (if not the first keyword).
5620 */
5621 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5622 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5623 else ADD_INSN(ret, line_node, swap);
5624
5625 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5626
5627 ADD_SEND(ret, line_node, id_core_hash_merge_bang_kwd, INT2FIX(2));
5628 }
5629 }
5630
5631 first_chunk = 0;
5632 }
5633 }
5634 }
5635
5636 FLUSH_CHUNK();
5637#undef FLUSH_CHUNK
5638 return 1;
5639}
5640
5641static VALUE
5642rb_node_case_when_optimizable_literal(const NODE *const node)
5643{
5644 switch (nd_type(node)) {
5645 case NODE_INTEGER:
5646 return rb_node_integer_literal_val(node);
5647 case NODE_FLOAT: {
5648 VALUE v = rb_node_float_literal_val(node);
5649 double ival;
5650
5651 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5652 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5653 }
5654 return v;
5655 }
5656 case NODE_RATIONAL:
5657 case NODE_IMAGINARY:
5658 return Qundef;
5659 case NODE_NIL:
5660 return Qnil;
5661 case NODE_TRUE:
5662 return Qtrue;
5663 case NODE_FALSE:
5664 return Qfalse;
5665 case NODE_SYM:
5666 return rb_node_sym_string_val(node);
5667 case NODE_LINE:
5668 return rb_node_line_lineno_val(node);
5669 case NODE_STR:
5670 return rb_node_str_string_val(node);
5671 case NODE_FILE:
5672 return rb_node_file_path_val(node);
5673 }
5674 return Qundef;
5675}
5676
5677static int
5678when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5679 LABEL *l1, int only_special_literals, VALUE literals)
5680{
5681 while (vals) {
5682 const NODE *val = RNODE_LIST(vals)->nd_head;
5683 VALUE lit = rb_node_case_when_optimizable_literal(val);
5684
5685 if (UNDEF_P(lit)) {
5686 only_special_literals = 0;
5687 }
5688 else {
5689 cdhash_aset_if_missing(literals, lit, (VALUE)(l1));
5690 }
5691
5692 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5693 debugp_param("nd_lit", get_string_value(val));
5694 lit = get_string_value(val);
5695 ADD_INSN1(cond_seq, val, putobject, lit);
5696 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5697 }
5698 else {
5699 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5700 }
5701
5702 // Emit pattern === target
5703 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5704 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5705 ADD_INSNL(cond_seq, val, branchif, l1);
5706 vals = RNODE_LIST(vals)->nd_next;
5707 }
5708 return only_special_literals;
5709}
5710
5711static int
5712when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5713 LABEL *l1, int only_special_literals, VALUE literals)
5714{
5715 const NODE *line_node = vals;
5716
5717 switch (nd_type(vals)) {
5718 case NODE_LIST:
5719 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5720 return COMPILE_NG;
5721 break;
5722 case NODE_SPLAT:
5723 ADD_INSN (cond_seq, line_node, dup);
5724 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5725 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5726 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5727 ADD_INSNL(cond_seq, line_node, branchif, l1);
5728 break;
5729 case NODE_ARGSCAT:
5730 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5731 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5732 break;
5733 case NODE_ARGSPUSH:
5734 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5735 ADD_INSN (cond_seq, line_node, dup);
5736 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5737 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5738 ADD_INSNL(cond_seq, line_node, branchif, l1);
5739 break;
5740 default:
5741 ADD_INSN (cond_seq, line_node, dup);
5742 CHECK(COMPILE(cond_seq, "when val", vals));
5743 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5744 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5745 ADD_INSNL(cond_seq, line_node, branchif, l1);
5746 break;
5747 }
5748 return COMPILE_OK;
5749}
5750
5751/* Multiple Assignment Handling
5752 *
5753 * In order to handle evaluation of multiple assignment such that the left hand side
5754 * is evaluated before the right hand side, we need to process the left hand side
5755 * and see if there are any attributes that need to be assigned, or constants set
5756 * on explicit objects. If so, we add instructions to evaluate the receiver of
5757 * any assigned attributes or constants before we process the right hand side.
5758 *
5759 * For a multiple assignment such as:
5760 *
5761 * l1.m1, l2[0] = r3, r4
5762 *
5763 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5764 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5765 * On the VM stack, this looks like:
5766 *
5767 * self # putself
5768 * l1 # send
5769 * l1, self # putself
5770 * l1, l2 # send
5771 * l1, l2, 0 # putobject 0
5772 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5773 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5774 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5775 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5776 * l1, l2, 0, [r3, r4], r4, m1= # send
5777 * l1, l2, 0, [r3, r4], r4 # pop
5778 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5779 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5780 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5781 * l1, l2, 0, [r3, r4], r4, []= # send
5782 * l1, l2, 0, [r3, r4], r4 # pop
5783 * l1, l2, 0, [r3, r4] # pop
5784 * [r3, r4], l2, 0, [r3, r4] # setn 3
5785 * [r3, r4], l2, 0 # pop
5786 * [r3, r4], l2 # pop
5787 * [r3, r4] # pop
5788 *
5789 * This is made more complex when you have to handle splats, post args,
5790 * and arbitrary levels of nesting. You need to keep track of the total
5791 * number of attributes to set, and for each attribute, how many entries
5792 * are on the stack before the final attribute, in order to correctly
5793 * calculate the topn value to use to get the receiver of the attribute
5794 * setter method.
5795 *
5796 * A brief description of the VM stack for simple multiple assignment
5797 * with no splat (rhs_array will not be present if the return value of
5798 * the multiple assignment is not needed):
5799 *
5800 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5801 *
5802 * For multiple assignment with splats, while processing the part before
5803 * the splat (splat+post here is an array of the splat and the post arguments):
5804 *
5805 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5806 *
5807 * When processing the splat and post arguments:
5808 *
5809 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5810 *
5811 * When processing nested multiple assignment, existing values on the stack
5812 * are kept. So for:
5813 *
5814 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5815 *
5816 * The stack layout would be the following before processing the nested
5817 * multiple assignment:
5818 *
5819 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5820 *
5821 * In order to handle this correctly, we need to keep track of the nesting
5822 * level for each attribute assignment, as well as the attribute number
5823 * (left hand side attributes are processed left to right) and number of
5824 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5825 * this information.
5826 *
5827 * We also need to track information for the entire multiple assignment, such
5828 * as the total number of arguments, and the current nesting level, to
5829 * handle both nested multiple assignment as well as cases where the
5830 * rhs is not needed. We also need to keep track of all attribute
5831 * assignments in this, which we do using a linked listed. struct masgn_state
5832 * tracks this information.
5833 */
5834
5836 INSN *before_insn;
5837 struct masgn_lhs_node *next;
5838 const NODE *line_node;
5839 int argn;
5840 int num_args;
5841 int lhs_pos;
5842};
5843
5845 struct masgn_lhs_node *first_memo;
5846 struct masgn_lhs_node *last_memo;
5847 int lhs_level;
5848 int num_args;
5849 bool nested;
5850};
5851
5852static int
5853add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5854{
5855 if (!state) {
5856 rb_bug("no masgn_state");
5857 }
5858
5859 struct masgn_lhs_node *memo;
5860 memo = malloc(sizeof(struct masgn_lhs_node));
5861 if (!memo) {
5862 return COMPILE_NG;
5863 }
5864
5865 memo->before_insn = before_insn;
5866 memo->line_node = line_node;
5867 memo->argn = state->num_args + 1;
5868 memo->num_args = argc;
5869 state->num_args += argc;
5870 memo->lhs_pos = lhs_pos;
5871 memo->next = NULL;
5872 if (!state->first_memo) {
5873 state->first_memo = memo;
5874 }
5875 else {
5876 state->last_memo->next = memo;
5877 }
5878 state->last_memo = memo;
5879
5880 return COMPILE_OK;
5881}
5882
5883static 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);
5884
5885static int
5886compile_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)
5887{
5888 switch (nd_type(node)) {
5889 case NODE_ATTRASGN: {
5890 INSN *iobj;
5891 const NODE *line_node = node;
5892
5893 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5894
5895 bool safenav_call = false;
5896 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5897 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5898 ASSUME(iobj);
5899 ELEM_REMOVE(insn_element);
5900 if (!IS_INSN_ID(iobj, send)) {
5901 safenav_call = true;
5902 iobj = (INSN *)get_prev_insn(iobj);
5903 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5904 }
5905 (pre->last = iobj->link.prev)->next = 0;
5906
5907 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5908 int argc = vm_ci_argc(ci) + 1;
5909 ci = ci_argc_set(iseq, ci, argc);
5910 OPERAND_AT(iobj, 0) = (VALUE)ci;
5911 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5912
5913 if (argc == 1) {
5914 ADD_INSN(lhs, line_node, swap);
5915 }
5916 else {
5917 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5918 }
5919
5920 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5921 return COMPILE_NG;
5922 }
5923
5924 iobj->link.prev = lhs->last;
5925 lhs->last->next = &iobj->link;
5926 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5927 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5928 int argc = vm_ci_argc(ci);
5929 bool dupsplat = false;
5930 ci = ci_argc_set(iseq, ci, argc - 1);
5931 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5932 /* Given h[*a], _ = ary
5933 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5934 * `a` must be dupped, because it will be appended with ary[0]
5935 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5936 */
5937 dupsplat = true;
5938 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5939 }
5940 OPERAND_AT(iobj, 0) = (VALUE)ci;
5941 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5942
5943 /* Given: h[*a], h[*b, 1] = ary
5944 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5945 * so this uses splatarray true on a to dup it before using pushtoarray
5946 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5947 * so you can use pushtoarray directly
5948 */
5949 int line_no = nd_line(line_node);
5950 int node_id = nd_node_id(line_node);
5951
5952 if (dupsplat) {
5953 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5954 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5955 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5956 }
5957 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5958 }
5959 if (!safenav_call) {
5960 ADD_INSN(lhs, line_node, pop);
5961 if (argc != 1) {
5962 ADD_INSN(lhs, line_node, pop);
5963 }
5964 }
5965 for (int i=0; i < argc; i++) {
5966 ADD_INSN(post, line_node, pop);
5967 }
5968 break;
5969 }
5970 case NODE_MASGN: {
5971 DECL_ANCHOR(nest_rhs);
5972 INIT_ANCHOR(nest_rhs);
5973 DECL_ANCHOR(nest_lhs);
5974 INIT_ANCHOR(nest_lhs);
5975
5976 int prev_level = state->lhs_level;
5977 bool prev_nested = state->nested;
5978 state->nested = 1;
5979 state->lhs_level = lhs_pos - 1;
5980 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5981 state->lhs_level = prev_level;
5982 state->nested = prev_nested;
5983
5984 ADD_SEQ(lhs, nest_rhs);
5985 ADD_SEQ(lhs, nest_lhs);
5986 break;
5987 }
5988 case NODE_CDECL:
5989 if (!RNODE_CDECL(node)->nd_vid) {
5990 /* Special handling only needed for expr::C, not for C */
5991 INSN *iobj;
5992
5993 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5994
5995 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5996 iobj = (INSN *)insn_element; /* setconstant insn */
5997 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5998 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5999 ELEM_REMOVE(insn_element);
6000 pre->last = iobj->link.prev;
6001 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
6002
6003 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
6004 return COMPILE_NG;
6005 }
6006
6007 ADD_INSN(post, node, pop);
6008 break;
6009 }
6010 /* Fallthrough */
6011 default: {
6012 DECL_ANCHOR(anchor);
6013 INIT_ANCHOR(anchor);
6014 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
6015 ELEM_REMOVE(FIRST_ELEMENT(anchor));
6016 ADD_SEQ(lhs, anchor);
6017 }
6018 }
6019
6020 return COMPILE_OK;
6021}
6022
6023static int
6024compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
6025{
6026 if (lhsn) {
6027 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
6028 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
6029 }
6030 return COMPILE_OK;
6031}
6032
6033static int
6034compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6035 const NODE *rhsn, const NODE *orig_lhsn)
6036{
6037 VALUE mem[64];
6038 const int memsize = numberof(mem);
6039 int memindex = 0;
6040 int llen = 0, rlen = 0;
6041 int i;
6042 const NODE *lhsn = orig_lhsn;
6043
6044#define MEMORY(v) { \
6045 int i; \
6046 if (memindex == memsize) return 0; \
6047 for (i=0; i<memindex; i++) { \
6048 if (mem[i] == (v)) return 0; \
6049 } \
6050 mem[memindex++] = (v); \
6051}
6052
6053 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
6054 return 0;
6055 }
6056
6057 while (lhsn) {
6058 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
6059 switch (nd_type(ln)) {
6060 case NODE_LASGN:
6061 case NODE_DASGN:
6062 case NODE_IASGN:
6063 case NODE_CVASGN:
6064 MEMORY(get_nd_vid(ln));
6065 break;
6066 default:
6067 return 0;
6068 }
6069 lhsn = RNODE_LIST(lhsn)->nd_next;
6070 llen++;
6071 }
6072
6073 while (rhsn) {
6074 if (llen <= rlen) {
6075 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
6076 }
6077 else {
6078 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
6079 }
6080 rhsn = RNODE_LIST(rhsn)->nd_next;
6081 rlen++;
6082 }
6083
6084 if (llen > rlen) {
6085 for (i=0; i<llen-rlen; i++) {
6086 ADD_INSN(ret, orig_lhsn, putnil);
6087 }
6088 }
6089
6090 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
6091 return 1;
6092}
6093
6094static int
6095compile_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)
6096{
6097 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
6098 const NODE *splatn = RNODE_MASGN(node)->nd_args;
6099 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
6100 const NODE *lhsn_count = lhsn;
6101 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
6102
6103 int llen = 0;
6104 int lpos = 0;
6105
6106 while (lhsn_count) {
6107 llen++;
6108 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
6109 }
6110 while (lhsn) {
6111 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
6112 lpos++;
6113 lhsn = RNODE_LIST(lhsn)->nd_next;
6114 }
6115
6116 if (lhs_splat) {
6117 if (nd_type_p(splatn, NODE_POSTARG)) {
6118 /*a, b, *r, p1, p2 */
6119 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
6120 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
6121 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
6122 int ppos = 0;
6123 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
6124
6125 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
6126
6127 if (NODE_NAMED_REST_P(restn)) {
6128 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6129 }
6130 while (postn) {
6131 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6132 ppos++;
6133 postn = RNODE_LIST(postn)->nd_next;
6134 }
6135 }
6136 else {
6137 /* a, b, *r */
6138 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6139 }
6140 }
6141
6142 if (!state->nested) {
6143 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
6144 }
6145
6146 if (!popped) {
6147 ADD_INSN(rhs, node, dup);
6148 }
6149 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
6150 return COMPILE_OK;
6151}
6152
6153static int
6154compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6155{
6156 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6157 struct masgn_state state;
6158 state.lhs_level = popped ? 0 : 1;
6159 state.nested = 0;
6160 state.num_args = 0;
6161 state.first_memo = NULL;
6162 state.last_memo = NULL;
6163
6164 DECL_ANCHOR(pre);
6165 INIT_ANCHOR(pre);
6166 DECL_ANCHOR(rhs);
6167 INIT_ANCHOR(rhs);
6168 DECL_ANCHOR(lhs);
6169 INIT_ANCHOR(lhs);
6170 DECL_ANCHOR(post);
6171 INIT_ANCHOR(post);
6172 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6173
6174 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
6175 while (memo) {
6176 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6177 for (int i = 0; i < memo->num_args; i++) {
6178 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6179 }
6180 tmp_memo = memo->next;
6181 free(memo);
6182 memo = tmp_memo;
6183 }
6184 CHECK(ok);
6185
6186 ADD_SEQ(ret, pre);
6187 ADD_SEQ(ret, rhs);
6188 ADD_SEQ(ret, lhs);
6189 if (!popped && state.num_args >= 1) {
6190 /* make sure rhs array is returned before popping */
6191 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
6192 }
6193 ADD_SEQ(ret, post);
6194 }
6195 return COMPILE_OK;
6196}
6197
6198static VALUE
6199collect_const_segments(rb_iseq_t *iseq, const NODE *node)
6200{
6201 VALUE arr = rb_ary_new();
6202 for (;;) {
6203 switch (nd_type(node)) {
6204 case NODE_CONST:
6205 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
6206 RB_OBJ_SET_SHAREABLE(arr);
6207 return arr;
6208 case NODE_COLON3:
6209 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
6210 rb_ary_unshift(arr, ID2SYM(idNULL));
6211 RB_OBJ_SET_SHAREABLE(arr);
6212 return arr;
6213 case NODE_COLON2:
6214 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
6215 node = RNODE_COLON2(node)->nd_head;
6216 break;
6217 default:
6218 return Qfalse;
6219 }
6220 }
6221}
6222
6223static int
6224compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
6225 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
6226{
6227 switch (nd_type(node)) {
6228 case NODE_CONST:
6229 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6230 ADD_INSN1(body, node, putobject, Qtrue);
6231 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
6232 break;
6233 case NODE_COLON3:
6234 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6235 ADD_INSN(body, node, pop);
6236 ADD_INSN1(body, node, putobject, rb_cObject);
6237 ADD_INSN1(body, node, putobject, Qtrue);
6238 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
6239 break;
6240 case NODE_COLON2:
6241 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6242 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6243 ADD_INSN1(body, node, putobject, Qfalse);
6244 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
6245 break;
6246 default:
6247 CHECK(COMPILE(pref, "const colon2 prefix", node));
6248 break;
6249 }
6250 return COMPILE_OK;
6251}
6252
6253static int
6254cpath_const_p(const NODE *node)
6255{
6256 switch (nd_type(node)) {
6257 case NODE_CONST:
6258 case NODE_COLON3:
6259 return TRUE;
6260 case NODE_COLON2:
6261 if (RNODE_COLON2(node)->nd_head) {
6262 return cpath_const_p(RNODE_COLON2(node)->nd_head);
6263 }
6264 return TRUE;
6265 default:
6266 return FALSE;
6267 }
6268}
6269
6270static int
6271compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6272{
6273 if (nd_type_p(cpath, NODE_COLON3)) {
6274 /* toplevel class ::Foo */
6275 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6276 return VM_DEFINECLASS_FLAG_SCOPED;
6277 }
6278 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6279 /* Bar::Foo or expr::Foo */
6280 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6281 int flags = VM_DEFINECLASS_FLAG_SCOPED;
6282 if (!cpath_const_p(RNODE_COLON2(cpath)->nd_head)) {
6283 flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
6284 }
6285 return flags;
6286 }
6287 else {
6288 /* class at cbase Foo */
6289 ADD_INSN1(ret, cpath, putspecialobject,
6290 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6291 return 0;
6292 }
6293}
6294
6295static inline int
6296private_recv_p(const NODE *node)
6297{
6298 NODE *recv = get_nd_recv(node);
6299 if (recv && nd_type_p(recv, NODE_SELF)) {
6300 return RNODE_SELF(recv)->nd_state != 0;
6301 }
6302 return 0;
6303}
6304
6305static void
6306defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6307 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6308
6309static int
6310compile_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);
6311
6312static void
6313defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6314 const NODE *const node, LABEL **lfinish, VALUE needstr,
6315 bool keep_result)
6316{
6317 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6318 enum node_type type;
6319 const int line = nd_line(node);
6320 const NODE *line_node = node;
6321
6322 switch (type = nd_type(node)) {
6323
6324 /* easy literals */
6325 case NODE_NIL:
6326 expr_type = DEFINED_NIL;
6327 break;
6328 case NODE_SELF:
6329 expr_type = DEFINED_SELF;
6330 break;
6331 case NODE_TRUE:
6332 expr_type = DEFINED_TRUE;
6333 break;
6334 case NODE_FALSE:
6335 expr_type = DEFINED_FALSE;
6336 break;
6337
6338 case NODE_HASH:
6339 case NODE_LIST:{
6340 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6341
6342 if (vals) {
6343 do {
6344 if (RNODE_LIST(vals)->nd_head) {
6345 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6346
6347 if (!lfinish[1]) {
6348 lfinish[1] = NEW_LABEL(line);
6349 }
6350 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6351 }
6352 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6353 }
6354 }
6355 /* fall through */
6356 case NODE_STR:
6357 case NODE_SYM:
6358 case NODE_REGX:
6359 case NODE_LINE:
6360 case NODE_FILE:
6361 case NODE_ENCODING:
6362 case NODE_INTEGER:
6363 case NODE_FLOAT:
6364 case NODE_RATIONAL:
6365 case NODE_IMAGINARY:
6366 case NODE_ZLIST:
6367 case NODE_AND:
6368 case NODE_OR:
6369 default:
6370 expr_type = DEFINED_EXPR;
6371 break;
6372
6373 case NODE_SPLAT:
6374 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6375 if (!lfinish[1]) {
6376 lfinish[1] = NEW_LABEL(line);
6377 }
6378 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6379 expr_type = DEFINED_EXPR;
6380 break;
6381
6382 /* variables */
6383 case NODE_LVAR:
6384 case NODE_DVAR:
6385 expr_type = DEFINED_LVAR;
6386 break;
6387
6388#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6389 case NODE_IVAR:
6390 ADD_INSN3(ret, line_node, definedivar,
6391 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6392 return;
6393
6394 case NODE_GVAR:
6395 ADD_INSN(ret, line_node, putnil);
6396 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6397 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6398 return;
6399
6400 case NODE_CVAR:
6401 ADD_INSN(ret, line_node, putnil);
6402 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6403 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6404 return;
6405
6406 case NODE_CONST:
6407 ADD_INSN(ret, line_node, putnil);
6408 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6409 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6410 return;
6411 case NODE_COLON2:
6412 if (!lfinish[1]) {
6413 lfinish[1] = NEW_LABEL(line);
6414 }
6415 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6416 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6417 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6418
6419 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6420 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6421 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6422 }
6423 else {
6424 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6425 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6426 }
6427 return;
6428 case NODE_COLON3:
6429 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6430 ADD_INSN3(ret, line_node, defined,
6431 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6432 return;
6433
6434 /* method dispatch */
6435 case NODE_CALL:
6436 case NODE_OPCALL:
6437 case NODE_VCALL:
6438 case NODE_FCALL:
6439 case NODE_ATTRASGN:{
6440 const int explicit_receiver =
6441 (type == NODE_CALL || type == NODE_OPCALL ||
6442 (type == NODE_ATTRASGN && !private_recv_p(node)));
6443
6444 if (get_nd_args(node) || explicit_receiver) {
6445 if (!lfinish[1]) {
6446 lfinish[1] = NEW_LABEL(line);
6447 }
6448 if (!lfinish[2]) {
6449 lfinish[2] = NEW_LABEL(line);
6450 }
6451 }
6452 if (get_nd_args(node)) {
6453 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6454 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6455 }
6456 if (explicit_receiver) {
6457 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6458 switch (nd_type(get_nd_recv(node))) {
6459 case NODE_CALL:
6460 case NODE_OPCALL:
6461 case NODE_VCALL:
6462 case NODE_FCALL:
6463 case NODE_ATTRASGN:
6464 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6465 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6466 break;
6467 default:
6468 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6469 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6470 break;
6471 }
6472 if (keep_result) {
6473 ADD_INSN(ret, line_node, dup);
6474 }
6475 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6476 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6477 }
6478 else {
6479 ADD_INSN(ret, line_node, putself);
6480 if (keep_result) {
6481 ADD_INSN(ret, line_node, dup);
6482 }
6483 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6484 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6485 }
6486 return;
6487 }
6488
6489 case NODE_YIELD:
6490 ADD_INSN(ret, line_node, putnil);
6491 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6492 PUSH_VAL(DEFINED_YIELD));
6493 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6494 return;
6495
6496 case NODE_BACK_REF:
6497 case NODE_NTH_REF:
6498 ADD_INSN(ret, line_node, putnil);
6499 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6500 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6501 PUSH_VAL(DEFINED_GVAR));
6502 return;
6503
6504 case NODE_SUPER:
6505 case NODE_ZSUPER:
6506 ADD_INSN(ret, line_node, putnil);
6507 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6508 PUSH_VAL(DEFINED_ZSUPER));
6509 return;
6510
6511#undef PUSH_VAL
6512 case NODE_OP_ASGN1:
6513 case NODE_OP_ASGN2:
6514 case NODE_OP_ASGN_OR:
6515 case NODE_OP_ASGN_AND:
6516 case NODE_MASGN:
6517 case NODE_LASGN:
6518 case NODE_DASGN:
6519 case NODE_GASGN:
6520 case NODE_IASGN:
6521 case NODE_CDECL:
6522 case NODE_CVASGN:
6523 case NODE_OP_CDECL:
6524 expr_type = DEFINED_ASGN;
6525 break;
6526 }
6527
6528 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6529
6530 if (needstr != Qfalse) {
6531 VALUE str = rb_iseq_defined_string(expr_type);
6532 ADD_INSN1(ret, line_node, putobject, str);
6533 }
6534 else {
6535 ADD_INSN1(ret, line_node, putobject, Qtrue);
6536 }
6537}
6538
6539static void
6540build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6541{
6542 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6543 iseq_set_exception_local_table(iseq);
6544}
6545
6546static void
6547defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6548 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6549{
6550 LINK_ELEMENT *lcur = ret->last;
6551 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6552 if (lfinish[1]) {
6553 int line = nd_line(node);
6554 LABEL *lstart = NEW_LABEL(line);
6555 LABEL *lend = NEW_LABEL(line);
6556 const rb_iseq_t *rescue;
6558 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6559 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6560 rb_str_concat(rb_str_new2("defined guard in "),
6561 ISEQ_BODY(iseq)->location.label),
6562 ISEQ_TYPE_RESCUE, 0);
6563 lstart->rescued = LABEL_RESCUE_BEG;
6564 lend->rescued = LABEL_RESCUE_END;
6565 APPEND_LABEL(ret, lcur, lstart);
6566 ADD_LABEL(ret, lend);
6567 if (!ignore) {
6568 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6569 }
6570 }
6571}
6572
6573static int
6574compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6575{
6576 const int line = nd_line(node);
6577 const NODE *line_node = node;
6578 if (!RNODE_DEFINED(node)->nd_head) {
6579 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6580 ADD_INSN1(ret, line_node, putobject, str);
6581 }
6582 else {
6583 LABEL *lfinish[3];
6584 LINK_ELEMENT *last = ret->last;
6585 lfinish[0] = NEW_LABEL(line);
6586 lfinish[1] = 0;
6587 lfinish[2] = 0;
6588 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6589 if (lfinish[1]) {
6590 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6591 ADD_INSN(ret, line_node, swap);
6592 if (lfinish[2]) {
6593 ADD_LABEL(ret, lfinish[2]);
6594 }
6595 ADD_INSN(ret, line_node, pop);
6596 ADD_LABEL(ret, lfinish[1]);
6597 }
6598 ADD_LABEL(ret, lfinish[0]);
6599 }
6600 return COMPILE_OK;
6601}
6602
6603static VALUE
6604make_name_for_block(const rb_iseq_t *orig_iseq)
6605{
6606 int level = 1;
6607 const rb_iseq_t *iseq = orig_iseq;
6608
6609 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6610 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6611 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6612 level++;
6613 }
6614 iseq = ISEQ_BODY(iseq)->parent_iseq;
6615 }
6616 }
6617
6618 if (level == 1) {
6619 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6620 }
6621 else {
6622 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6623 }
6624}
6625
6626static void
6627push_ensure_entry(rb_iseq_t *iseq,
6629 struct ensure_range *er, const void *const node)
6630{
6631 enl->ensure_node = node;
6632 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6633 enl->erange = er;
6634 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6635}
6636
6637static void
6638add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6639 LABEL *lstart, LABEL *lend)
6640{
6641 struct ensure_range *ne =
6642 compile_data_alloc_type(iseq, struct ensure_range);
6643
6644 while (erange->next != 0) {
6645 erange = erange->next;
6646 }
6647 ne->next = 0;
6648 ne->begin = lend;
6649 ne->end = erange->end;
6650 erange->end = lstart;
6651
6652 erange->next = ne;
6653}
6654
6655static bool
6656can_add_ensure_iseq(const rb_iseq_t *iseq)
6657{
6659 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6660 while (e) {
6661 if (e->ensure_node) return false;
6662 e = e->prev;
6663 }
6664 }
6665 return true;
6666}
6667
6668static void
6669add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6670{
6671 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6672
6674 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6675 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6676 DECL_ANCHOR(ensure);
6677
6678 INIT_ANCHOR(ensure);
6679 while (enlp) {
6680 if (enlp->erange != NULL) {
6681 DECL_ANCHOR(ensure_part);
6682 LABEL *lstart = NEW_LABEL(0);
6683 LABEL *lend = NEW_LABEL(0);
6684 INIT_ANCHOR(ensure_part);
6685
6686 add_ensure_range(iseq, enlp->erange, lstart, lend);
6687
6688 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6689 ADD_LABEL(ensure_part, lstart);
6690 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6691 ADD_LABEL(ensure_part, lend);
6692 ADD_SEQ(ensure, ensure_part);
6693 }
6694 else {
6695 if (!is_return) {
6696 break;
6697 }
6698 }
6699 enlp = enlp->prev;
6700 }
6701 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6702 ADD_SEQ(ret, ensure);
6703}
6704
6705#if RUBY_DEBUG
6706static int
6707check_keyword(const NODE *node)
6708{
6709 /* This check is essentially a code clone of compile_keyword_arg. */
6710
6711 if (nd_type_p(node, NODE_LIST)) {
6712 while (RNODE_LIST(node)->nd_next) {
6713 node = RNODE_LIST(node)->nd_next;
6714 }
6715 node = RNODE_LIST(node)->nd_head;
6716 }
6717
6718 return keyword_node_p(node);
6719}
6720#endif
6721
6722static bool
6723keyword_node_single_splat_p(NODE *kwnode)
6724{
6725 RUBY_ASSERT(keyword_node_p(kwnode));
6726
6727 NODE *node = RNODE_HASH(kwnode)->nd_head;
6728 return RNODE_LIST(node)->nd_head == NULL &&
6729 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6730}
6731
6732static void
6733compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6734 NODE *kwnode, unsigned int *flag_ptr)
6735{
6736 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6737 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6738 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6739 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6740 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6741}
6742
6743#define SPLATARRAY_FALSE 0
6744#define SPLATARRAY_TRUE 1
6745#define DUP_SINGLE_KW_SPLAT 2
6746
6747static int
6748setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6749 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6750{
6751 if (!argn) return 0;
6752
6753 NODE *kwnode = NULL;
6754
6755 switch (nd_type(argn)) {
6756 case NODE_LIST: {
6757 // f(x, y, z)
6758 int len = compile_args(iseq, args, argn, &kwnode);
6759 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6760
6761 if (kwnode) {
6762 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6763 len -= 1;
6764 }
6765 else {
6766 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6767 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6768 }
6769 else {
6770 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6771 }
6772 }
6773 }
6774
6775 return len;
6776 }
6777 case NODE_SPLAT: {
6778 // f(*a)
6779 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6780 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6781 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6782 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6783 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6784 return 1;
6785 }
6786 case NODE_ARGSCAT: {
6787 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6788 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6789 bool args_pushed = false;
6790
6791 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6792 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6793 if (kwnode) rest_len--;
6794 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6795 args_pushed = true;
6796 }
6797 else {
6798 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6799 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6800 }
6801
6802 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6803 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6804 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6805 argc += 1;
6806 }
6807 else if (!args_pushed) {
6808 ADD_INSN(args, argn, concattoarray);
6809 }
6810
6811 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6812 if (kwnode) {
6813 // kwsplat
6814 *flag_ptr |= VM_CALL_KW_SPLAT;
6815 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6816 argc += 1;
6817 }
6818
6819 return argc;
6820 }
6821 case NODE_ARGSPUSH: {
6822 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6823 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6824
6825 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6826 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6827 if (kwnode) rest_len--;
6828 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6829 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6830 }
6831 else {
6832 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6833 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6834 }
6835 else {
6836 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6837 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6838 }
6839 }
6840
6841 if (kwnode) {
6842 // f(*a, k:1)
6843 *flag_ptr |= VM_CALL_KW_SPLAT;
6844 if (!keyword_node_single_splat_p(kwnode)) {
6845 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6846 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6847 }
6848 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6849 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6850 }
6851 else {
6852 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6853 }
6854 argc += 1;
6855 }
6856
6857 return argc;
6858 }
6859 default: {
6860 UNKNOWN_NODE("setup_arg", argn, Qnil);
6861 }
6862 }
6863}
6864
6865static void
6866setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6867{
6868 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6869 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6870 }
6871}
6872
6873static bool
6874setup_args_dup_rest_p(const NODE *argn)
6875{
6876 switch(nd_type(argn)) {
6877 case NODE_LVAR:
6878 case NODE_DVAR:
6879 case NODE_GVAR:
6880 case NODE_IVAR:
6881 case NODE_CVAR:
6882 case NODE_CONST:
6883 case NODE_COLON3:
6884 case NODE_INTEGER:
6885 case NODE_FLOAT:
6886 case NODE_RATIONAL:
6887 case NODE_IMAGINARY:
6888 case NODE_STR:
6889 case NODE_SYM:
6890 case NODE_REGX:
6891 case NODE_SELF:
6892 case NODE_NIL:
6893 case NODE_TRUE:
6894 case NODE_FALSE:
6895 case NODE_LAMBDA:
6896 case NODE_NTH_REF:
6897 case NODE_BACK_REF:
6898 return false;
6899 case NODE_COLON2:
6900 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6901 case NODE_LIST:
6902 while (argn) {
6903 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6904 return true;
6905 }
6906 argn = RNODE_LIST(argn)->nd_next;
6907 }
6908 return false;
6909 default:
6910 return true;
6911 }
6912}
6913
6914static VALUE
6915setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6916 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6917{
6918 VALUE ret;
6919 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6920
6921 if (argn) {
6922 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6923 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6924
6925 if (check_arg) {
6926 switch(nd_type(check_arg)) {
6927 case(NODE_SPLAT):
6928 // avoid caller side array allocation for f(*arg)
6929 dup_rest = SPLATARRAY_FALSE;
6930 break;
6931 case(NODE_ARGSCAT):
6932 // avoid caller side array allocation for f(1, *arg)
6933 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6934 break;
6935 case(NODE_ARGSPUSH):
6936 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6937 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6938 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6939 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6940 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6941 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6942
6943 if (dup_rest == SPLATARRAY_FALSE) {
6944 // require allocation for keyword key/value/splat that may modify splatted argument
6945 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6946 while (node) {
6947 NODE *key_node = RNODE_LIST(node)->nd_head;
6948 if (key_node && setup_args_dup_rest_p(key_node)) {
6949 dup_rest = SPLATARRAY_TRUE;
6950 break;
6951 }
6952
6953 node = RNODE_LIST(node)->nd_next;
6954 NODE *value_node = RNODE_LIST(node)->nd_head;
6955 if (setup_args_dup_rest_p(value_node)) {
6956 dup_rest = SPLATARRAY_TRUE;
6957 break;
6958 }
6959
6960 node = RNODE_LIST(node)->nd_next;
6961 }
6962 }
6963 break;
6964 default:
6965 break;
6966 }
6967 }
6968
6969 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6970 // for block pass that may modify splatted argument, dup rest and kwrest if given
6971 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6972 }
6973 }
6974 initial_dup_rest = dup_rest;
6975
6976 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6977 DECL_ANCHOR(arg_block);
6978 INIT_ANCHOR(arg_block);
6979
6980 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6981 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6982
6983 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6984 const NODE * arg_node =
6985 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6986
6987 int argc = 0;
6988
6989 // Only compile leading args:
6990 // foo(x, y, ...)
6991 // ^^^^
6992 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6993 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6994 }
6995
6996 *flag |= VM_CALL_FORWARDING;
6997
6998 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6999 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7000 return INT2FIX(argc);
7001 }
7002 else {
7003 *flag |= VM_CALL_ARGS_BLOCKARG;
7004
7005 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
7006 }
7007
7008 if (LIST_INSN_SIZE_ONE(arg_block)) {
7009 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
7010 if (IS_INSN(elem)) {
7011 INSN *iobj = (INSN *)elem;
7012 if (iobj->insn_id == BIN(getblockparam)) {
7013 iobj->insn_id = BIN(getblockparamproxy);
7014 }
7015 }
7016 }
7017 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
7018 ADD_SEQ(args, arg_block);
7019 }
7020 else {
7021 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
7022 }
7023 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
7024 return ret;
7025}
7026
7027static void
7028build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
7029{
7030 const NODE *body = ptr;
7031 int line = nd_line(body);
7032 VALUE argc = INT2FIX(0);
7033 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
7034
7035 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7036 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
7037 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
7038 iseq_set_local_table(iseq, 0, 0);
7039}
7040
7041static void
7042compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
7043{
7044 const NODE *vars;
7045 LINK_ELEMENT *last;
7046 int line = nd_line(node);
7047 const NODE *line_node = node;
7048 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
7049
7050#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
7051 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
7052#else
7053 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
7054#endif
7055 ADD_INSN(ret, line_node, dup);
7056 ADD_INSNL(ret, line_node, branchunless, fail_label);
7057
7058 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7059 INSN *cap;
7060 if (RNODE_BLOCK(vars)->nd_next) {
7061 ADD_INSN(ret, line_node, dup);
7062 }
7063 last = ret->last;
7064 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7065 last = last->next; /* putobject :var */
7066 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
7067 NULL, INT2FIX(0), NULL);
7068 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
7069#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
7070 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
7071 /* only one name */
7072 DECL_ANCHOR(nom);
7073
7074 INIT_ANCHOR(nom);
7075 ADD_INSNL(nom, line_node, jump, end_label);
7076 ADD_LABEL(nom, fail_label);
7077# if 0 /* $~ must be MatchData or nil */
7078 ADD_INSN(nom, line_node, pop);
7079 ADD_INSN(nom, line_node, putnil);
7080# endif
7081 ADD_LABEL(nom, end_label);
7082 (nom->last->next = cap->link.next)->prev = nom->last;
7083 (cap->link.next = nom->anchor.next)->prev = &cap->link;
7084 return;
7085 }
7086#endif
7087 }
7088 ADD_INSNL(ret, line_node, jump, end_label);
7089 ADD_LABEL(ret, fail_label);
7090 ADD_INSN(ret, line_node, pop);
7091 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
7092 last = ret->last;
7093 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
7094 last = last->next; /* putobject :var */
7095 ((INSN*)last)->insn_id = BIN(putnil);
7096 ((INSN*)last)->operand_size = 0;
7097 }
7098 ADD_LABEL(ret, end_label);
7099}
7100
7101static int
7102optimizable_range_item_p(const NODE *n)
7103{
7104 if (!n) return FALSE;
7105 switch (nd_type(n)) {
7106 case NODE_LINE:
7107 return TRUE;
7108 case NODE_INTEGER:
7109 return TRUE;
7110 case NODE_NIL:
7111 return TRUE;
7112 default:
7113 return FALSE;
7114 }
7115}
7116
7117static VALUE
7118optimized_range_item(const NODE *n)
7119{
7120 switch (nd_type(n)) {
7121 case NODE_LINE:
7122 return rb_node_line_lineno_val(n);
7123 case NODE_INTEGER:
7124 return rb_node_integer_literal_val(n);
7125 case NODE_FLOAT:
7126 return rb_node_float_literal_val(n);
7127 case NODE_RATIONAL:
7128 return rb_node_rational_literal_val(n);
7129 case NODE_IMAGINARY:
7130 return rb_node_imaginary_literal_val(n);
7131 case NODE_NIL:
7132 return Qnil;
7133 default:
7134 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
7135 }
7136}
7137
7138static int
7139compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7140{
7141 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
7142 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
7143
7144 const int line = nd_line(node);
7145 const NODE *line_node = node;
7146 DECL_ANCHOR(cond_seq);
7147 LABEL *then_label, *else_label, *end_label;
7148 VALUE branches = Qfalse;
7149
7150 INIT_ANCHOR(cond_seq);
7151 then_label = NEW_LABEL(line);
7152 else_label = NEW_LABEL(line);
7153 end_label = 0;
7154
7155 NODE *cond = RNODE_IF(node)->nd_cond;
7156 if (nd_type(cond) == NODE_BLOCK) {
7157 cond = RNODE_BLOCK(cond)->nd_head;
7158 }
7159
7160 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7161 ADD_SEQ(ret, cond_seq);
7162
7163 if (then_label->refcnt && else_label->refcnt) {
7164 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
7165 }
7166
7167 if (then_label->refcnt) {
7168 ADD_LABEL(ret, then_label);
7169
7170 DECL_ANCHOR(then_seq);
7171 INIT_ANCHOR(then_seq);
7172 CHECK(COMPILE_(then_seq, "then", node_body, popped));
7173
7174 if (else_label->refcnt) {
7175 const NODE *const coverage_node = node_body ? node_body : node;
7176 add_trace_branch_coverage(
7177 iseq,
7178 ret,
7179 nd_code_loc(coverage_node),
7180 nd_node_id(coverage_node),
7181 0,
7182 type == NODE_IF ? "then" : "else",
7183 branches);
7184 end_label = NEW_LABEL(line);
7185 ADD_INSNL(then_seq, line_node, jump, end_label);
7186 if (!popped) {
7187 ADD_INSN(then_seq, line_node, pop);
7188 }
7189 }
7190 ADD_SEQ(ret, then_seq);
7191 }
7192
7193 if (else_label->refcnt) {
7194 ADD_LABEL(ret, else_label);
7195
7196 DECL_ANCHOR(else_seq);
7197 INIT_ANCHOR(else_seq);
7198 CHECK(COMPILE_(else_seq, "else", node_else, popped));
7199
7200 if (then_label->refcnt) {
7201 const NODE *const coverage_node = node_else ? node_else : node;
7202 add_trace_branch_coverage(
7203 iseq,
7204 ret,
7205 nd_code_loc(coverage_node),
7206 nd_node_id(coverage_node),
7207 1,
7208 type == NODE_IF ? "else" : "then",
7209 branches);
7210 }
7211 ADD_SEQ(ret, else_seq);
7212 }
7213
7214 if (end_label) {
7215 ADD_LABEL(ret, end_label);
7216 }
7217
7218 return COMPILE_OK;
7219}
7220
7221static int
7222compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7223{
7224 const NODE *vals;
7225 const NODE *node = orig_node;
7226 LABEL *endlabel, *elselabel;
7227 DECL_ANCHOR(head);
7228 DECL_ANCHOR(body_seq);
7229 DECL_ANCHOR(cond_seq);
7230 int only_special_literals = 1;
7231 VALUE literals = cdhash_new(0);
7232 int line;
7233 enum node_type type;
7234 const NODE *line_node;
7235 VALUE branches = Qfalse;
7236 int branch_id = 0;
7237
7238 INIT_ANCHOR(head);
7239 INIT_ANCHOR(body_seq);
7240 INIT_ANCHOR(cond_seq);
7241
7242 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
7243
7244 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
7245
7246 node = RNODE_CASE(node)->nd_body;
7247 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7248 type = nd_type(node);
7249 line = nd_line(node);
7250 line_node = node;
7251
7252 endlabel = NEW_LABEL(line);
7253 elselabel = NEW_LABEL(line);
7254
7255 ADD_SEQ(ret, head); /* case VAL */
7256
7257 while (type == NODE_WHEN) {
7258 LABEL *l1;
7259
7260 l1 = NEW_LABEL(line);
7261 ADD_LABEL(body_seq, l1);
7262 ADD_INSN(body_seq, line_node, pop);
7263
7264 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7265 add_trace_branch_coverage(
7266 iseq,
7267 body_seq,
7268 nd_code_loc(coverage_node),
7269 nd_node_id(coverage_node),
7270 branch_id++,
7271 "when",
7272 branches);
7273
7274 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7275 ADD_INSNL(body_seq, line_node, jump, endlabel);
7276
7277 vals = RNODE_WHEN(node)->nd_head;
7278 if (vals) {
7279 switch (nd_type(vals)) {
7280 case NODE_LIST:
7281 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7282 if (only_special_literals < 0) return COMPILE_NG;
7283 break;
7284 case NODE_SPLAT:
7285 case NODE_ARGSCAT:
7286 case NODE_ARGSPUSH:
7287 only_special_literals = 0;
7288 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7289 break;
7290 default:
7291 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7292 }
7293 }
7294 else {
7295 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7296 }
7297
7298 node = RNODE_WHEN(node)->nd_next;
7299 if (!node) {
7300 break;
7301 }
7302 type = nd_type(node);
7303 line = nd_line(node);
7304 line_node = node;
7305 }
7306 /* else */
7307 if (node) {
7308 ADD_LABEL(cond_seq, elselabel);
7309 ADD_INSN(cond_seq, line_node, pop);
7310 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7311 CHECK(COMPILE_(cond_seq, "else", node, popped));
7312 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7313 }
7314 else {
7315 debugs("== else (implicit)\n");
7316 ADD_LABEL(cond_seq, elselabel);
7317 ADD_INSN(cond_seq, orig_node, pop);
7318 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7319 if (!popped) {
7320 ADD_INSN(cond_seq, orig_node, putnil);
7321 }
7322 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7323 }
7324
7325 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7326 ADD_INSN(ret, orig_node, dup);
7327 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7328 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7329 LABEL_REF(elselabel);
7330 }
7331
7332 ADD_SEQ(ret, cond_seq);
7333 ADD_SEQ(ret, body_seq);
7334 ADD_LABEL(ret, endlabel);
7335 return COMPILE_OK;
7336}
7337
7338static int
7339compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7340{
7341 const NODE *vals;
7342 const NODE *val;
7343 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7344 LABEL *endlabel;
7345 DECL_ANCHOR(body_seq);
7346 VALUE branches = Qfalse;
7347 int branch_id = 0;
7348
7349 branches = decl_branch_base(iseq, nd_node_id(orig_node), nd_code_loc(orig_node), "case");
7350
7351 INIT_ANCHOR(body_seq);
7352 endlabel = NEW_LABEL(nd_line(node));
7353
7354 while (node && nd_type_p(node, NODE_WHEN)) {
7355 const int line = nd_line(node);
7356 LABEL *l1 = NEW_LABEL(line);
7357 ADD_LABEL(body_seq, l1);
7358
7359 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7360 add_trace_branch_coverage(
7361 iseq,
7362 body_seq,
7363 nd_code_loc(coverage_node),
7364 nd_node_id(coverage_node),
7365 branch_id++,
7366 "when",
7367 branches);
7368
7369 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7370 ADD_INSNL(body_seq, node, jump, endlabel);
7371
7372 vals = RNODE_WHEN(node)->nd_head;
7373 if (!vals) {
7374 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7375 }
7376 switch (nd_type(vals)) {
7377 case NODE_LIST:
7378 while (vals) {
7379 LABEL *lnext;
7380 val = RNODE_LIST(vals)->nd_head;
7381 lnext = NEW_LABEL(nd_line(val));
7382 debug_compile("== when2\n", (void)0);
7383 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7384 ADD_LABEL(ret, lnext);
7385 vals = RNODE_LIST(vals)->nd_next;
7386 }
7387 break;
7388 case NODE_SPLAT:
7389 case NODE_ARGSCAT:
7390 case NODE_ARGSPUSH:
7391 ADD_INSN(ret, vals, putnil);
7392 CHECK(COMPILE(ret, "when2/cond splat", vals));
7393 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7394 ADD_INSNL(ret, vals, branchif, l1);
7395 break;
7396 default:
7397 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7398 }
7399 node = RNODE_WHEN(node)->nd_next;
7400 }
7401 /* else */
7402 const NODE *const coverage_node = node ? node : orig_node;
7403 add_trace_branch_coverage(
7404 iseq,
7405 ret,
7406 nd_code_loc(coverage_node),
7407 nd_node_id(coverage_node),
7408 branch_id,
7409 "else",
7410 branches);
7411 CHECK(COMPILE_(ret, "else", node, popped));
7412 ADD_INSNL(ret, orig_node, jump, endlabel);
7413
7414 ADD_SEQ(ret, body_seq);
7415 ADD_LABEL(ret, endlabel);
7416 return COMPILE_OK;
7417}
7418
7419static 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);
7420
7421static 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);
7422static 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);
7423static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7424static 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);
7425static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7426
7427#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7428#define CASE3_BI_OFFSET_ERROR_STRING 1
7429#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7430#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7431#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7432
7433static int
7434iseq_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)
7435{
7436 const int line = nd_line(node);
7437 const NODE *line_node = node;
7438
7439 switch (nd_type(node)) {
7440 case NODE_ARYPTN: {
7441 /*
7442 * if pattern.use_rest_num?
7443 * rest_num = 0
7444 * end
7445 * if pattern.has_constant_node?
7446 * unless pattern.constant === obj
7447 * goto match_failed
7448 * end
7449 * end
7450 * unless obj.respond_to?(:deconstruct)
7451 * goto match_failed
7452 * end
7453 * d = obj.deconstruct
7454 * unless Array === d
7455 * goto type_error
7456 * end
7457 * min_argc = pattern.pre_args_num + pattern.post_args_num
7458 * if pattern.has_rest_arg?
7459 * unless d.length >= min_argc
7460 * goto match_failed
7461 * end
7462 * else
7463 * unless d.length == min_argc
7464 * goto match_failed
7465 * end
7466 * end
7467 * pattern.pre_args_num.each do |i|
7468 * unless pattern.pre_args[i].match?(d[i])
7469 * goto match_failed
7470 * end
7471 * end
7472 * if pattern.use_rest_num?
7473 * rest_num = d.length - min_argc
7474 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7475 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7476 * goto match_failed
7477 * end
7478 * end
7479 * end
7480 * pattern.post_args_num.each do |i|
7481 * j = pattern.pre_args_num + i
7482 * j += rest_num
7483 * unless pattern.post_args[i].match?(d[j])
7484 * goto match_failed
7485 * end
7486 * end
7487 * goto matched
7488 * type_error:
7489 * FrozenCore.raise TypeError
7490 * match_failed:
7491 * goto unmatched
7492 */
7493 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7494 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7495 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7496
7497 const int min_argc = pre_args_num + post_args_num;
7498 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7499 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7500
7501 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7502 int i;
7503 match_failed = NEW_LABEL(line);
7504 type_error = NEW_LABEL(line);
7505 deconstruct = NEW_LABEL(line);
7506 deconstructed = NEW_LABEL(line);
7507
7508 if (use_rest_num) {
7509 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7510 ADD_INSN(ret, line_node, swap);
7511 if (base_index) {
7512 base_index++;
7513 }
7514 }
7515
7516 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7517
7518 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7519
7520 ADD_INSN(ret, line_node, dup);
7521 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7522 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7523 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7524 if (in_single_pattern) {
7525 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7526 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7527 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7528 INT2FIX(min_argc), base_index + 1 /* (1) */));
7529 }
7530 ADD_INSNL(ret, line_node, branchunless, match_failed);
7531
7532 for (i = 0; i < pre_args_num; i++) {
7533 ADD_INSN(ret, line_node, dup);
7534 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7535 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7536 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));
7537 args = RNODE_LIST(args)->nd_next;
7538 }
7539
7540 if (RNODE_ARYPTN(node)->rest_arg) {
7541 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7542 ADD_INSN(ret, line_node, dup);
7543 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7544 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7545 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7546 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7547 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7548 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7549 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7550
7551 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));
7552 }
7553 else {
7554 if (post_args_num > 0) {
7555 ADD_INSN(ret, line_node, dup);
7556 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7557 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7558 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7559 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7560 ADD_INSN(ret, line_node, pop);
7561 }
7562 }
7563 }
7564
7565 args = RNODE_ARYPTN(node)->post_args;
7566 for (i = 0; i < post_args_num; i++) {
7567 ADD_INSN(ret, line_node, dup);
7568
7569 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7570 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7571 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7572
7573 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7574 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));
7575 args = RNODE_LIST(args)->nd_next;
7576 }
7577
7578 ADD_INSN(ret, line_node, pop);
7579 if (use_rest_num) {
7580 ADD_INSN(ret, line_node, pop);
7581 }
7582 ADD_INSNL(ret, line_node, jump, matched);
7583 ADD_INSN(ret, line_node, putnil);
7584 if (use_rest_num) {
7585 ADD_INSN(ret, line_node, putnil);
7586 }
7587
7588 ADD_LABEL(ret, type_error);
7589 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7590 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7591 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7592 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7593 ADD_INSN(ret, line_node, pop);
7594
7595 ADD_LABEL(ret, match_failed);
7596 ADD_INSN(ret, line_node, pop);
7597 if (use_rest_num) {
7598 ADD_INSN(ret, line_node, pop);
7599 }
7600 ADD_INSNL(ret, line_node, jump, unmatched);
7601
7602 break;
7603 }
7604 case NODE_FNDPTN: {
7605 /*
7606 * if pattern.has_constant_node?
7607 * unless pattern.constant === obj
7608 * goto match_failed
7609 * end
7610 * end
7611 * unless obj.respond_to?(:deconstruct)
7612 * goto match_failed
7613 * end
7614 * d = obj.deconstruct
7615 * unless Array === d
7616 * goto type_error
7617 * end
7618 * unless d.length >= pattern.args_num
7619 * goto match_failed
7620 * end
7621 *
7622 * begin
7623 * len = d.length
7624 * limit = d.length - pattern.args_num
7625 * i = 0
7626 * while i <= limit
7627 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7628 * if pattern.has_pre_rest_arg_id
7629 * unless pattern.pre_rest_arg.match?(d[0, i])
7630 * goto find_failed
7631 * end
7632 * end
7633 * if pattern.has_post_rest_arg_id
7634 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7635 * goto find_failed
7636 * end
7637 * end
7638 * goto find_succeeded
7639 * end
7640 * i+=1
7641 * end
7642 * find_failed:
7643 * goto match_failed
7644 * find_succeeded:
7645 * end
7646 *
7647 * goto matched
7648 * type_error:
7649 * FrozenCore.raise TypeError
7650 * match_failed:
7651 * goto unmatched
7652 */
7653 const NODE *args = RNODE_FNDPTN(node)->args;
7654 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7655
7656 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7657 match_failed = NEW_LABEL(line);
7658 type_error = NEW_LABEL(line);
7659 deconstruct = NEW_LABEL(line);
7660 deconstructed = NEW_LABEL(line);
7661
7662 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7663
7664 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7665
7666 ADD_INSN(ret, line_node, dup);
7667 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7668 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7669 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7670 if (in_single_pattern) {
7671 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) */));
7672 }
7673 ADD_INSNL(ret, line_node, branchunless, match_failed);
7674
7675 {
7676 LABEL *while_begin = NEW_LABEL(nd_line(node));
7677 LABEL *next_loop = NEW_LABEL(nd_line(node));
7678 LABEL *find_succeeded = NEW_LABEL(line);
7679 LABEL *find_failed = NEW_LABEL(nd_line(node));
7680 int j;
7681
7682 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7683 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7684
7685 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7686 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7687 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7688
7689 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7690
7691 ADD_LABEL(ret, while_begin);
7692
7693 ADD_INSN(ret, line_node, dup);
7694 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7695 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7696 ADD_INSNL(ret, line_node, branchunless, find_failed);
7697
7698 for (j = 0; j < args_num; j++) {
7699 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7700 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7701 if (j != 0) {
7702 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7703 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7704 }
7705 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7706
7707 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));
7708 args = RNODE_LIST(args)->nd_next;
7709 }
7710
7711 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7712 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7713 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7714 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7715 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7716 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));
7717 }
7718 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7719 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7720 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7721 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7722 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7723 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7724 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7725 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));
7726 }
7727 ADD_INSNL(ret, line_node, jump, find_succeeded);
7728
7729 ADD_LABEL(ret, next_loop);
7730 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7731 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7732 ADD_INSNL(ret, line_node, jump, while_begin);
7733
7734 ADD_LABEL(ret, find_failed);
7735 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7736 if (in_single_pattern) {
7737 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7738 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7739 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7740 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7741 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7742
7743 ADD_INSN1(ret, line_node, putobject, Qfalse);
7744 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7745
7746 ADD_INSN(ret, line_node, pop);
7747 ADD_INSN(ret, line_node, pop);
7748 }
7749 ADD_INSNL(ret, line_node, jump, match_failed);
7750 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7751
7752 ADD_LABEL(ret, find_succeeded);
7753 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7754 }
7755
7756 ADD_INSN(ret, line_node, pop);
7757 ADD_INSNL(ret, line_node, jump, matched);
7758 ADD_INSN(ret, line_node, putnil);
7759
7760 ADD_LABEL(ret, type_error);
7761 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7762 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7763 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7764 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7765 ADD_INSN(ret, line_node, pop);
7766
7767 ADD_LABEL(ret, match_failed);
7768 ADD_INSN(ret, line_node, pop);
7769 ADD_INSNL(ret, line_node, jump, unmatched);
7770
7771 break;
7772 }
7773 case NODE_HSHPTN: {
7774 /*
7775 * keys = nil
7776 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7777 * keys = pattern.kw_args_node.keys
7778 * end
7779 * if pattern.has_constant_node?
7780 * unless pattern.constant === obj
7781 * goto match_failed
7782 * end
7783 * end
7784 * unless obj.respond_to?(:deconstruct_keys)
7785 * goto match_failed
7786 * end
7787 * d = obj.deconstruct_keys(keys)
7788 * unless Hash === d
7789 * goto type_error
7790 * end
7791 * if pattern.has_kw_rest_arg_node?
7792 * d = d.dup
7793 * end
7794 * if pattern.has_kw_args_node?
7795 * pattern.kw_args_node.each |k,|
7796 * unless d.key?(k)
7797 * goto match_failed
7798 * end
7799 * end
7800 * pattern.kw_args_node.each |k, pat|
7801 * if pattern.has_kw_rest_arg_node?
7802 * unless pat.match?(d.delete(k))
7803 * goto match_failed
7804 * end
7805 * else
7806 * unless pat.match?(d[k])
7807 * goto match_failed
7808 * end
7809 * end
7810 * end
7811 * else
7812 * unless d.empty?
7813 * goto match_failed
7814 * end
7815 * end
7816 * if pattern.has_kw_rest_arg_node?
7817 * if pattern.no_rest_keyword?
7818 * unless d.empty?
7819 * goto match_failed
7820 * end
7821 * else
7822 * unless pattern.kw_rest_arg_node.match?(d)
7823 * goto match_failed
7824 * end
7825 * end
7826 * end
7827 * goto matched
7828 * type_error:
7829 * FrozenCore.raise TypeError
7830 * match_failed:
7831 * goto unmatched
7832 */
7833 LABEL *match_failed, *type_error;
7834 VALUE keys = Qnil;
7835
7836 match_failed = NEW_LABEL(line);
7837 type_error = NEW_LABEL(line);
7838
7839 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7840 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7841 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7842 while (kw_args) {
7843 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7844 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7845 }
7846 }
7847
7848 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7849
7850 ADD_INSN(ret, line_node, dup);
7851 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7852 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7853 if (in_single_pattern) {
7854 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7855 }
7856 ADD_INSNL(ret, line_node, branchunless, match_failed);
7857
7858 if (NIL_P(keys)) {
7859 ADD_INSN(ret, line_node, putnil);
7860 }
7861 else {
7862 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7863 ADD_INSN1(ret, line_node, duparray, keys);
7864 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7865 }
7866 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7867
7868 ADD_INSN(ret, line_node, dup);
7869 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7870 ADD_INSNL(ret, line_node, branchunless, type_error);
7871
7872 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7873 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7874 }
7875
7876 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7877 int i;
7878 int keys_num;
7879 const NODE *args;
7880 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7881 if (args) {
7882 DECL_ANCHOR(match_values);
7883 INIT_ANCHOR(match_values);
7884 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7885 for (i = 0; i < keys_num; i++) {
7886 NODE *key_node = RNODE_LIST(args)->nd_head;
7887 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7888 VALUE key = get_symbol_value(iseq, key_node);
7889
7890 ADD_INSN(ret, line_node, dup);
7891 ADD_INSN1(ret, line_node, putobject, key);
7892 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7893 if (in_single_pattern) {
7894 LABEL *match_succeeded;
7895 match_succeeded = NEW_LABEL(line);
7896
7897 ADD_INSN(ret, line_node, dup);
7898 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7899
7900 VALUE str = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key));
7901 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str)); // (4)
7902 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7903 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7904 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7905 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7906 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7907 ADD_INSN1(ret, line_node, putobject, key); // (7)
7908 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7909
7910 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7911
7912 ADD_LABEL(ret, match_succeeded);
7913 }
7914 ADD_INSNL(ret, line_node, branchunless, match_failed);
7915
7916 ADD_INSN(match_values, line_node, dup);
7917 ADD_INSN1(match_values, line_node, putobject, key);
7918 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7919 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7920 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7921 }
7922 ADD_SEQ(ret, match_values);
7923 }
7924 }
7925 else {
7926 ADD_INSN(ret, line_node, dup);
7927 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7928 if (in_single_pattern) {
7929 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7930 }
7931 ADD_INSNL(ret, line_node, branchunless, match_failed);
7932 }
7933
7934 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7935 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7936 ADD_INSN(ret, line_node, dup);
7937 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7938 if (in_single_pattern) {
7939 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7940 }
7941 ADD_INSNL(ret, line_node, branchunless, match_failed);
7942 }
7943 else {
7944 ADD_INSN(ret, line_node, dup); // (11)
7945 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));
7946 }
7947 }
7948
7949 ADD_INSN(ret, line_node, pop);
7950 ADD_INSNL(ret, line_node, jump, matched);
7951 ADD_INSN(ret, line_node, putnil);
7952
7953 ADD_LABEL(ret, type_error);
7954 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7955 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7956 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7957 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7958 ADD_INSN(ret, line_node, pop);
7959
7960 ADD_LABEL(ret, match_failed);
7961 ADD_INSN(ret, line_node, pop);
7962 ADD_INSNL(ret, line_node, jump, unmatched);
7963 break;
7964 }
7965 case NODE_SYM:
7966 case NODE_REGX:
7967 case NODE_LINE:
7968 case NODE_INTEGER:
7969 case NODE_FLOAT:
7970 case NODE_RATIONAL:
7971 case NODE_IMAGINARY:
7972 case NODE_FILE:
7973 case NODE_ENCODING:
7974 case NODE_STR:
7975 case NODE_XSTR:
7976 case NODE_DSTR:
7977 case NODE_DSYM:
7978 case NODE_DREGX:
7979 case NODE_LIST:
7980 case NODE_ZLIST:
7981 case NODE_LAMBDA:
7982 case NODE_DOT2:
7983 case NODE_DOT3:
7984 case NODE_CONST:
7985 case NODE_LVAR:
7986 case NODE_DVAR:
7987 case NODE_IVAR:
7988 case NODE_CVAR:
7989 case NODE_GVAR:
7990 case NODE_TRUE:
7991 case NODE_FALSE:
7992 case NODE_SELF:
7993 case NODE_NIL:
7994 case NODE_COLON2:
7995 case NODE_COLON3:
7996 case NODE_BEGIN:
7997 case NODE_BLOCK:
7998 case NODE_ONCE:
7999 CHECK(COMPILE(ret, "case in literal", node)); // (1)
8000 if (in_single_pattern) {
8001 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8002 }
8003 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
8004 if (in_single_pattern) {
8005 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
8006 }
8007 ADD_INSNL(ret, line_node, branchif, matched);
8008 ADD_INSNL(ret, line_node, jump, unmatched);
8009 break;
8010 case NODE_LASGN: {
8011 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8012 ID id = RNODE_LASGN(node)->nd_vid;
8013 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8014
8015 if (in_alt_pattern) {
8016 const char *name = rb_id2name(id);
8017 if (name && strlen(name) > 0 && name[0] != '_') {
8018 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8019 rb_id2str(id));
8020 return COMPILE_NG;
8021 }
8022 }
8023
8024 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8025 ADD_INSNL(ret, line_node, jump, matched);
8026 break;
8027 }
8028 case NODE_DASGN: {
8029 int idx, lv, ls;
8030 ID id = RNODE_DASGN(node)->nd_vid;
8031
8032 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
8033
8034 if (in_alt_pattern) {
8035 const char *name = rb_id2name(id);
8036 if (name && strlen(name) > 0 && name[0] != '_') {
8037 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
8038 rb_id2str(id));
8039 return COMPILE_NG;
8040 }
8041 }
8042
8043 if (idx < 0) {
8044 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
8045 rb_id2str(id));
8046 return COMPILE_NG;
8047 }
8048 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
8049 ADD_INSNL(ret, line_node, jump, matched);
8050 break;
8051 }
8052 case NODE_IF:
8053 case NODE_UNLESS: {
8054 LABEL *match_failed;
8055 match_failed = unmatched;
8056 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8057 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
8058 if (in_single_pattern) {
8059 LABEL *match_succeeded;
8060 match_succeeded = NEW_LABEL(line);
8061
8062 ADD_INSN(ret, line_node, dup);
8063 if (nd_type_p(node, NODE_IF)) {
8064 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8065 }
8066 else {
8067 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
8068 }
8069
8070 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
8071 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8072 ADD_INSN1(ret, line_node, putobject, Qfalse);
8073 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8074
8075 ADD_INSN(ret, line_node, pop);
8076 ADD_INSN(ret, line_node, pop);
8077
8078 ADD_LABEL(ret, match_succeeded);
8079 }
8080 if (nd_type_p(node, NODE_IF)) {
8081 ADD_INSNL(ret, line_node, branchunless, match_failed);
8082 }
8083 else {
8084 ADD_INSNL(ret, line_node, branchif, match_failed);
8085 }
8086 ADD_INSNL(ret, line_node, jump, matched);
8087 break;
8088 }
8089 case NODE_HASH: {
8090 NODE *n;
8091 LABEL *match_failed;
8092 match_failed = NEW_LABEL(line);
8093
8094 n = RNODE_HASH(node)->nd_head;
8095 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
8096 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8097 return COMPILE_NG;
8098 }
8099
8100 ADD_INSN(ret, line_node, dup); // (1)
8101 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));
8102 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));
8103 ADD_INSN(ret, line_node, putnil);
8104
8105 ADD_LABEL(ret, match_failed);
8106 ADD_INSN(ret, line_node, pop);
8107 ADD_INSNL(ret, line_node, jump, unmatched);
8108 break;
8109 }
8110 case NODE_OR: {
8111 LABEL *match_succeeded, *fin;
8112 match_succeeded = NEW_LABEL(line);
8113 fin = NEW_LABEL(line);
8114
8115 ADD_INSN(ret, line_node, dup); // (1)
8116 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));
8117 ADD_LABEL(ret, match_succeeded);
8118 ADD_INSN(ret, line_node, pop);
8119 ADD_INSNL(ret, line_node, jump, matched);
8120 ADD_INSN(ret, line_node, putnil);
8121 ADD_LABEL(ret, fin);
8122 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
8123 break;
8124 }
8125 default:
8126 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
8127 }
8128 return COMPILE_OK;
8129}
8130
8131static int
8132iseq_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)
8133{
8134 LABEL *fin = NEW_LABEL(nd_line(node));
8135 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
8136 ADD_LABEL(ret, fin);
8137 return COMPILE_OK;
8138}
8139
8140static int
8141iseq_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)
8142{
8143 const NODE *line_node = node;
8144
8145 if (RNODE_ARYPTN(node)->nd_pconst) {
8146 ADD_INSN(ret, line_node, dup); // (1)
8147 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
8148 if (in_single_pattern) {
8149 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
8150 }
8151 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
8152 if (in_single_pattern) {
8153 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
8154 }
8155 ADD_INSNL(ret, line_node, branchunless, match_failed);
8156 }
8157 return COMPILE_OK;
8158}
8159
8160
8161static int
8162iseq_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)
8163{
8164 const NODE *line_node = node;
8165
8166 // NOTE: this optimization allows us to re-use the #deconstruct value
8167 // (or its absence).
8168 if (use_deconstructed_cache) {
8169 // If value is nil then we haven't tried to deconstruct
8170 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8171 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8172
8173 // If false then the value is not deconstructable
8174 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8175 ADD_INSNL(ret, line_node, branchunless, match_failed);
8176
8177 // Drop value, add deconstructed to the stack and jump
8178 ADD_INSN(ret, line_node, pop); // (1)
8179 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
8180 ADD_INSNL(ret, line_node, jump, deconstructed);
8181 }
8182 else {
8183 ADD_INSNL(ret, line_node, jump, deconstruct);
8184 }
8185
8186 ADD_LABEL(ret, deconstruct);
8187 ADD_INSN(ret, line_node, dup);
8188 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
8189 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
8190
8191 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
8192 if (use_deconstructed_cache) {
8193 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
8194 }
8195
8196 if (in_single_pattern) {
8197 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
8198 }
8199
8200 ADD_INSNL(ret, line_node, branchunless, match_failed);
8201
8202 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
8203
8204 // Cache the result (if it's cacheable - currently, only top-level array patterns)
8205 if (use_deconstructed_cache) {
8206 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8207 }
8208
8209 ADD_INSN(ret, line_node, dup);
8210 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
8211 ADD_INSNL(ret, line_node, branchunless, type_error);
8212
8213 ADD_LABEL(ret, deconstructed);
8214
8215 return COMPILE_OK;
8216}
8217
8218static int
8219iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
8220{
8221 /*
8222 * if match_succeeded?
8223 * goto match_succeeded
8224 * end
8225 * error_string = FrozenCore.sprintf(errmsg, matchee)
8226 * key_error_p = false
8227 * match_succeeded:
8228 */
8229 const int line = nd_line(node);
8230 const NODE *line_node = node;
8231 LABEL *match_succeeded = NEW_LABEL(line);
8232
8233 ADD_INSN(ret, line_node, dup);
8234 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8235
8236 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8237 ADD_INSN1(ret, line_node, putobject, errmsg);
8238 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8239 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
8240 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8241
8242 ADD_INSN1(ret, line_node, putobject, Qfalse);
8243 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8244
8245 ADD_INSN(ret, line_node, pop);
8246 ADD_INSN(ret, line_node, pop);
8247 ADD_LABEL(ret, match_succeeded);
8248
8249 return COMPILE_OK;
8250}
8251
8252static int
8253iseq_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)
8254{
8255 /*
8256 * if match_succeeded?
8257 * goto match_succeeded
8258 * end
8259 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
8260 * key_error_p = false
8261 * match_succeeded:
8262 */
8263 const int line = nd_line(node);
8264 const NODE *line_node = node;
8265 LABEL *match_succeeded = NEW_LABEL(line);
8266
8267 ADD_INSN(ret, line_node, dup);
8268 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8269
8270 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8271 ADD_INSN1(ret, line_node, putobject, errmsg);
8272 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8273 ADD_INSN(ret, line_node, dup);
8274 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8275 ADD_INSN1(ret, line_node, putobject, pattern_length);
8276 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8277 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8278
8279 ADD_INSN1(ret, line_node, putobject, Qfalse);
8280 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8281
8282 ADD_INSN(ret, line_node, pop);
8283 ADD_INSN(ret, line_node, pop);
8284 ADD_LABEL(ret, match_succeeded);
8285
8286 return COMPILE_OK;
8287}
8288
8289static int
8290iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8291{
8292 /*
8293 * if match_succeeded?
8294 * goto match_succeeded
8295 * end
8296 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8297 * key_error_p = false
8298 * match_succeeded:
8299 */
8300 const int line = nd_line(node);
8301 const NODE *line_node = node;
8302 LABEL *match_succeeded = NEW_LABEL(line);
8303
8304 ADD_INSN(ret, line_node, dup);
8305 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8306
8307 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8308 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8309 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8310 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8311 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8312 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8313
8314 ADD_INSN1(ret, line_node, putobject, Qfalse);
8315 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8316
8317 ADD_INSN(ret, line_node, pop);
8318 ADD_INSN(ret, line_node, pop);
8319
8320 ADD_LABEL(ret, match_succeeded);
8321 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8322 ADD_INSN(ret, line_node, pop);
8323 ADD_INSN(ret, line_node, pop);
8324
8325 return COMPILE_OK;
8326}
8327
8328static int
8329compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8330{
8331 const NODE *pattern;
8332 const NODE *node = orig_node;
8333 LABEL *endlabel, *elselabel;
8334 DECL_ANCHOR(head);
8335 DECL_ANCHOR(body_seq);
8336 DECL_ANCHOR(cond_seq);
8337 int line;
8338 enum node_type type;
8339 const NODE *line_node;
8340 VALUE branches = 0;
8341 int branch_id = 0;
8342 bool single_pattern;
8343
8344 INIT_ANCHOR(head);
8345 INIT_ANCHOR(body_seq);
8346 INIT_ANCHOR(cond_seq);
8347
8348 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "case");
8349
8350 node = RNODE_CASE3(node)->nd_body;
8351 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8352 type = nd_type(node);
8353 line = nd_line(node);
8354 line_node = node;
8355 single_pattern = !RNODE_IN(node)->nd_next;
8356
8357 endlabel = NEW_LABEL(line);
8358 elselabel = NEW_LABEL(line);
8359
8360 if (single_pattern) {
8361 /* allocate stack for ... */
8362 ADD_INSN(head, line_node, putnil); /* key_error_key */
8363 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8364 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8365 ADD_INSN(head, line_node, putnil); /* error_string */
8366 }
8367 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8368
8369 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8370
8371 ADD_SEQ(ret, head); /* case VAL */
8372
8373 while (type == NODE_IN) {
8374 LABEL *l1;
8375
8376 if (branch_id) {
8377 ADD_INSN(body_seq, line_node, putnil);
8378 }
8379 l1 = NEW_LABEL(line);
8380 ADD_LABEL(body_seq, l1);
8381 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8382
8383 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8384 add_trace_branch_coverage(
8385 iseq,
8386 body_seq,
8387 nd_code_loc(coverage_node),
8388 nd_node_id(coverage_node),
8389 branch_id++,
8390 "in",
8391 branches);
8392
8393 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8394 ADD_INSNL(body_seq, line_node, jump, endlabel);
8395
8396 pattern = RNODE_IN(node)->nd_head;
8397 if (pattern) {
8398 int pat_line = nd_line(pattern);
8399 LABEL *next_pat = NEW_LABEL(pat_line);
8400 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8401 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8402 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8403 ADD_LABEL(cond_seq, next_pat);
8404 LABEL_UNREMOVABLE(next_pat);
8405 }
8406 else {
8407 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8408 return COMPILE_NG;
8409 }
8410
8411 node = RNODE_IN(node)->nd_next;
8412 if (!node) {
8413 break;
8414 }
8415 type = nd_type(node);
8416 line = nd_line(node);
8417 line_node = node;
8418 }
8419 /* else */
8420 if (node) {
8421 ADD_LABEL(cond_seq, elselabel);
8422 ADD_INSN(cond_seq, line_node, pop);
8423 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8424 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8425 CHECK(COMPILE_(cond_seq, "else", node, popped));
8426 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8427 ADD_INSN(cond_seq, line_node, putnil);
8428 if (popped) {
8429 ADD_INSN(cond_seq, line_node, putnil);
8430 }
8431 }
8432 else {
8433 debugs("== else (implicit)\n");
8434 ADD_LABEL(cond_seq, elselabel);
8435 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8436 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8437
8438 if (single_pattern) {
8439 /*
8440 * if key_error_p
8441 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8442 * else
8443 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8444 * end
8445 */
8446 LABEL *key_error, *fin;
8447 struct rb_callinfo_kwarg *kw_arg;
8448
8449 key_error = NEW_LABEL(line);
8450 fin = NEW_LABEL(line);
8451
8452 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8453 kw_arg->references = 0;
8454 kw_arg->keyword_len = 2;
8455 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8456 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8457
8458 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8459 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8460 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8461 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8462 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8463 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8464 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8465 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8466 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8467 ADD_INSNL(cond_seq, orig_node, jump, fin);
8468
8469 ADD_LABEL(cond_seq, key_error);
8470 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8471 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8472 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8473 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8474 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8475 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8476 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8477 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8478 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8479 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8480
8481 ADD_LABEL(cond_seq, fin);
8482 }
8483 else {
8484 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8485 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8486 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8487 }
8488 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8489 if (!popped) {
8490 ADD_INSN(cond_seq, orig_node, putnil);
8491 }
8492 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8493 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8494 if (popped) {
8495 ADD_INSN(cond_seq, line_node, putnil);
8496 }
8497 }
8498
8499 ADD_SEQ(ret, cond_seq);
8500 ADD_SEQ(ret, body_seq);
8501 ADD_LABEL(ret, endlabel);
8502 return COMPILE_OK;
8503}
8504
8505#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8506#undef CASE3_BI_OFFSET_ERROR_STRING
8507#undef CASE3_BI_OFFSET_KEY_ERROR_P
8508#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8509#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8510
8511static int
8512compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8513{
8514 const int line = (int)nd_line(node);
8515 const NODE *line_node = node;
8516
8517 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8518 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8519 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8520 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8521 VALUE branches = Qfalse;
8522
8524
8525 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8526 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8527 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8528 LABEL *end_label = NEW_LABEL(line);
8529 LABEL *adjust_label = NEW_LABEL(line);
8530
8531 LABEL *next_catch_label = NEW_LABEL(line);
8532 LABEL *tmp_label = NULL;
8533
8534 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8535 push_ensure_entry(iseq, &enl, NULL, NULL);
8536
8537 if (RNODE_WHILE(node)->nd_state == 1) {
8538 ADD_INSNL(ret, line_node, jump, next_label);
8539 }
8540 else {
8541 tmp_label = NEW_LABEL(line);
8542 ADD_INSNL(ret, line_node, jump, tmp_label);
8543 }
8544 ADD_LABEL(ret, adjust_label);
8545 ADD_INSN(ret, line_node, putnil);
8546 ADD_LABEL(ret, next_catch_label);
8547 ADD_INSN(ret, line_node, pop);
8548 ADD_INSNL(ret, line_node, jump, next_label);
8549 if (tmp_label) ADD_LABEL(ret, tmp_label);
8550
8551 ADD_LABEL(ret, redo_label);
8552 branches = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8553
8554 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8555 add_trace_branch_coverage(
8556 iseq,
8557 ret,
8558 nd_code_loc(coverage_node),
8559 nd_node_id(coverage_node),
8560 0,
8561 "body",
8562 branches);
8563
8564 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8565 ADD_LABEL(ret, next_label); /* next */
8566
8567 if (type == NODE_WHILE) {
8568 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8569 redo_label, end_label));
8570 }
8571 else {
8572 /* until */
8573 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8574 end_label, redo_label));
8575 }
8576
8577 ADD_LABEL(ret, end_label);
8578 ADD_ADJUST_RESTORE(ret, adjust_label);
8579
8580 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8581 /* ADD_INSN(ret, line_node, putundef); */
8582 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8583 return COMPILE_NG;
8584 }
8585 else {
8586 ADD_INSN(ret, line_node, putnil);
8587 }
8588
8589 ADD_LABEL(ret, break_label); /* break */
8590
8591 if (popped) {
8592 ADD_INSN(ret, line_node, pop);
8593 }
8594
8595 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8596 break_label);
8597 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8598 next_catch_label);
8599 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8600 ISEQ_COMPILE_DATA(iseq)->redo_label);
8601
8602 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8603 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8604 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8605 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8606 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8607 return COMPILE_OK;
8608}
8609
8610static int
8611compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8612{
8613 const int line = nd_line(node);
8614 const NODE *line_node = node;
8615 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8616 LABEL *retry_label = NEW_LABEL(line);
8617 LABEL *retry_end_l = NEW_LABEL(line);
8618 const rb_iseq_t *child_iseq;
8619
8620 ADD_LABEL(ret, retry_label);
8621 if (nd_type_p(node, NODE_FOR)) {
8622 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8623
8624 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8625 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8626 ISEQ_TYPE_BLOCK, line);
8627 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8628 }
8629 else {
8630 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8631 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8632 ISEQ_TYPE_BLOCK, line);
8633 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8634 }
8635
8636 {
8637 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8638 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8639 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8640 //
8641 // Normally, "send" instruction is at the last.
8642 // However, qcall under branch coverage measurement adds some instructions after the "send".
8643 //
8644 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8645 INSN *iobj;
8646 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8647 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8648 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8649 iobj = (INSN*) get_prev_insn(iobj);
8650 }
8651 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8652
8653 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8654 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8655 if (&iobj->link == LAST_ELEMENT(ret)) {
8656 ret->last = (LINK_ELEMENT*) retry_end_l;
8657 }
8658 }
8659
8660 if (popped) {
8661 ADD_INSN(ret, line_node, pop);
8662 }
8663
8664 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8665
8666 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8667 return COMPILE_OK;
8668}
8669
8670static int
8671compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8672{
8673 /* massign to var in "for"
8674 * (args.length == 1 && Array.try_convert(args[0])) || args
8675 */
8676 const NODE *line_node = node;
8677 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8678 LABEL *not_single = NEW_LABEL(nd_line(var));
8679 LABEL *not_ary = NEW_LABEL(nd_line(var));
8680 CHECK(COMPILE(ret, "for var", var));
8681 ADD_INSN(ret, line_node, dup);
8682 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8683 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8684 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8685 ADD_INSNL(ret, line_node, branchunless, not_single);
8686 ADD_INSN(ret, line_node, dup);
8687 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8688 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8689 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8690 ADD_INSN(ret, line_node, swap);
8691 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8692 ADD_INSN(ret, line_node, dup);
8693 ADD_INSNL(ret, line_node, branchunless, not_ary);
8694 ADD_INSN(ret, line_node, swap);
8695 ADD_LABEL(ret, not_ary);
8696 ADD_INSN(ret, line_node, pop);
8697 ADD_LABEL(ret, not_single);
8698 return COMPILE_OK;
8699}
8700
8701static int
8702compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8703{
8704 const NODE *line_node = node;
8705 unsigned long throw_flag = 0;
8706
8707 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8708 /* while/until */
8709 LABEL *splabel = NEW_LABEL(0);
8710 ADD_LABEL(ret, splabel);
8711 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8712 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8713 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8714 add_ensure_iseq(ret, iseq, 0);
8715 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8716 ADD_ADJUST_RESTORE(ret, splabel);
8717
8718 if (!popped) {
8719 ADD_INSN(ret, line_node, putnil);
8720 }
8721 }
8722 else {
8723 const rb_iseq_t *ip = iseq;
8724
8725 while (ip) {
8726 if (!ISEQ_COMPILE_DATA(ip)) {
8727 ip = 0;
8728 break;
8729 }
8730
8731 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8732 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8733 }
8734 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8735 throw_flag = 0;
8736 }
8737 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8738 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8739 return COMPILE_NG;
8740 }
8741 else {
8742 ip = ISEQ_BODY(ip)->parent_iseq;
8743 continue;
8744 }
8745
8746 /* escape from block */
8747 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8748 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8749 if (popped) {
8750 ADD_INSN(ret, line_node, pop);
8751 }
8752 return COMPILE_OK;
8753 }
8754 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8755 return COMPILE_NG;
8756 }
8757 return COMPILE_OK;
8758}
8759
8760static int
8761compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8762{
8763 const NODE *line_node = node;
8764 unsigned long throw_flag = 0;
8765
8766 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8767 LABEL *splabel = NEW_LABEL(0);
8768 debugs("next in while loop\n");
8769 ADD_LABEL(ret, splabel);
8770 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8771 add_ensure_iseq(ret, iseq, 0);
8772 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8773 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8774 ADD_ADJUST_RESTORE(ret, splabel);
8775 if (!popped) {
8776 ADD_INSN(ret, line_node, putnil);
8777 }
8778 }
8779 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8780 LABEL *splabel = NEW_LABEL(0);
8781 debugs("next in block\n");
8782 ADD_LABEL(ret, splabel);
8783 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8784 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8785 add_ensure_iseq(ret, iseq, 0);
8786 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8787 ADD_ADJUST_RESTORE(ret, splabel);
8788
8789 if (!popped) {
8790 ADD_INSN(ret, line_node, putnil);
8791 }
8792 }
8793 else {
8794 const rb_iseq_t *ip = iseq;
8795
8796 while (ip) {
8797 if (!ISEQ_COMPILE_DATA(ip)) {
8798 ip = 0;
8799 break;
8800 }
8801
8802 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8803 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8804 /* while loop */
8805 break;
8806 }
8807 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8808 break;
8809 }
8810 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8811 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8812 return COMPILE_NG;
8813 }
8814
8815 ip = ISEQ_BODY(ip)->parent_iseq;
8816 }
8817 if (ip != 0) {
8818 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8819 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8820
8821 if (popped) {
8822 ADD_INSN(ret, line_node, pop);
8823 }
8824 }
8825 else {
8826 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8827 return COMPILE_NG;
8828 }
8829 }
8830 return COMPILE_OK;
8831}
8832
8833static int
8834compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8835{
8836 const NODE *line_node = node;
8837
8838 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8839 LABEL *splabel = NEW_LABEL(0);
8840 debugs("redo in while");
8841 ADD_LABEL(ret, splabel);
8842 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8843 add_ensure_iseq(ret, iseq, 0);
8844 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8845 ADD_ADJUST_RESTORE(ret, splabel);
8846 if (!popped) {
8847 ADD_INSN(ret, line_node, putnil);
8848 }
8849 }
8850 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8851 LABEL *splabel = NEW_LABEL(0);
8852
8853 debugs("redo in block");
8854 ADD_LABEL(ret, splabel);
8855 add_ensure_iseq(ret, iseq, 0);
8856 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8857 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8858 ADD_ADJUST_RESTORE(ret, splabel);
8859
8860 if (!popped) {
8861 ADD_INSN(ret, line_node, putnil);
8862 }
8863 }
8864 else {
8865 const rb_iseq_t *ip = iseq;
8866
8867 while (ip) {
8868 if (!ISEQ_COMPILE_DATA(ip)) {
8869 ip = 0;
8870 break;
8871 }
8872
8873 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8874 break;
8875 }
8876 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8877 break;
8878 }
8879 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8880 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8881 return COMPILE_NG;
8882 }
8883
8884 ip = ISEQ_BODY(ip)->parent_iseq;
8885 }
8886 if (ip != 0) {
8887 ADD_INSN(ret, line_node, putnil);
8888 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8889
8890 if (popped) {
8891 ADD_INSN(ret, line_node, pop);
8892 }
8893 }
8894 else {
8895 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8896 return COMPILE_NG;
8897 }
8898 }
8899 return COMPILE_OK;
8900}
8901
8902static int
8903compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8904{
8905 const NODE *line_node = node;
8906
8907 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8908 ADD_INSN(ret, line_node, putnil);
8909 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8910
8911 if (popped) {
8912 ADD_INSN(ret, line_node, pop);
8913 }
8914 }
8915 else {
8916 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8917 return COMPILE_NG;
8918 }
8919 return COMPILE_OK;
8920}
8921
8922static int
8923compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8924{
8925 const int line = nd_line(node);
8926 const NODE *line_node = node;
8927 LABEL *lstart = NEW_LABEL(line);
8928 LABEL *lend = NEW_LABEL(line);
8929 LABEL *lcont = NEW_LABEL(line);
8930 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8931 rb_str_concat(rb_str_new2("rescue in "),
8932 ISEQ_BODY(iseq)->location.label),
8933 ISEQ_TYPE_RESCUE, line);
8934
8935 lstart->rescued = LABEL_RESCUE_BEG;
8936 lend->rescued = LABEL_RESCUE_END;
8937 ADD_LABEL(ret, lstart);
8938
8939 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8940 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8941 {
8942 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8943 }
8944 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8945
8946 ADD_LABEL(ret, lend);
8947 if (RNODE_RESCUE(node)->nd_else) {
8948 ADD_INSN(ret, line_node, pop);
8949 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8950 }
8951 ADD_INSN(ret, line_node, nop);
8952 ADD_LABEL(ret, lcont);
8953
8954 if (popped) {
8955 ADD_INSN(ret, line_node, pop);
8956 }
8957
8958 /* register catch entry */
8959 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8960 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8961 return COMPILE_OK;
8962}
8963
8964static int
8965compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8966{
8967 const int line = nd_line(node);
8968 const NODE *line_node = node;
8969 const NODE *resq = node;
8970 const NODE *narg;
8971 LABEL *label_miss, *label_hit;
8972
8973 while (resq) {
8974 label_miss = NEW_LABEL(line);
8975 label_hit = NEW_LABEL(line);
8976
8977 narg = RNODE_RESBODY(resq)->nd_args;
8978 if (narg) {
8979 switch (nd_type(narg)) {
8980 case NODE_LIST:
8981 while (narg) {
8982 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8983 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8984 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8985 ADD_INSNL(ret, line_node, branchif, label_hit);
8986 narg = RNODE_LIST(narg)->nd_next;
8987 }
8988 break;
8989 case NODE_SPLAT:
8990 case NODE_ARGSCAT:
8991 case NODE_ARGSPUSH:
8992 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8993 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8994 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8995 ADD_INSNL(ret, line_node, branchif, label_hit);
8996 break;
8997 default:
8998 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8999 }
9000 }
9001 else {
9002 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
9003 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
9004 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
9005 ADD_INSNL(ret, line_node, branchif, label_hit);
9006 }
9007 ADD_INSNL(ret, line_node, jump, label_miss);
9008 ADD_LABEL(ret, label_hit);
9009 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
9010
9011 if (RNODE_RESBODY(resq)->nd_exc_var) {
9012 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
9013 }
9014
9015 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) {
9016 // empty body
9017 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
9018 }
9019 else {
9020 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
9021 }
9022
9023 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
9024 ADD_INSN(ret, line_node, nop);
9025 }
9026 ADD_INSN(ret, line_node, leave);
9027 ADD_LABEL(ret, label_miss);
9028 resq = RNODE_RESBODY(resq)->nd_next;
9029 }
9030 return COMPILE_OK;
9031}
9032
9033static int
9034compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9035{
9036 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
9037 const NODE *line_node = node;
9038 DECL_ANCHOR(ensr);
9039 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
9040 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
9041 ISEQ_TYPE_ENSURE, line);
9042 LABEL *lstart = NEW_LABEL(line);
9043 LABEL *lend = NEW_LABEL(line);
9044 LABEL *lcont = NEW_LABEL(line);
9045 LINK_ELEMENT *last;
9046 int last_leave = 0;
9047 struct ensure_range er;
9049 struct ensure_range *erange;
9050
9051 INIT_ANCHOR(ensr);
9052 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
9053 last = ensr->last;
9054 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
9055
9056 er.begin = lstart;
9057 er.end = lend;
9058 er.next = 0;
9059 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
9060
9061 ADD_LABEL(ret, lstart);
9062 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
9063 ADD_LABEL(ret, lend);
9064 ADD_SEQ(ret, ensr);
9065 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
9066 ADD_LABEL(ret, lcont);
9067 if (last_leave) ADD_INSN(ret, line_node, pop);
9068
9069 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
9070 if (lstart->link.next != &lend->link) {
9071 while (erange) {
9072 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
9073 ensure, lcont);
9074 erange = erange->next;
9075 }
9076 }
9077
9078 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
9079 return COMPILE_OK;
9080}
9081
9082static int
9083compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9084{
9085 const NODE *line_node = node;
9086
9087 if (iseq) {
9088 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
9089 const rb_iseq_t *is = iseq;
9090 enum rb_iseq_type t = type;
9091 const NODE *retval = RNODE_RETURN(node)->nd_stts;
9092 LABEL *splabel = 0;
9093
9094 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
9095 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
9096 t = ISEQ_BODY(is)->type;
9097 }
9098 switch (t) {
9099 case ISEQ_TYPE_TOP:
9100 case ISEQ_TYPE_MAIN:
9101 if (retval) {
9102 rb_warn("argument of top-level return is ignored");
9103 }
9104 if (is == iseq) {
9105 /* plain top-level, leave directly */
9106 type = ISEQ_TYPE_METHOD;
9107 }
9108 break;
9109 default:
9110 break;
9111 }
9112
9113 if (type == ISEQ_TYPE_METHOD) {
9114 splabel = NEW_LABEL(0);
9115 ADD_LABEL(ret, splabel);
9116 ADD_ADJUST(ret, line_node, 0);
9117 }
9118
9119 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
9120
9121 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
9122 add_ensure_iseq(ret, iseq, 1);
9123 ADD_TRACE(ret, RUBY_EVENT_RETURN);
9124 ADD_INSN(ret, line_node, leave);
9125 ADD_ADJUST_RESTORE(ret, splabel);
9126
9127 if (!popped) {
9128 ADD_INSN(ret, line_node, putnil);
9129 }
9130 }
9131 else {
9132 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
9133 if (popped) {
9134 ADD_INSN(ret, line_node, pop);
9135 }
9136 }
9137 }
9138 return COMPILE_OK;
9139}
9140
9141static bool
9142drop_unreachable_return(LINK_ANCHOR *ret)
9143{
9144 LINK_ELEMENT *i = ret->last, *last;
9145 if (!i) return false;
9146 if (IS_TRACE(i)) i = i->prev;
9147 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
9148 last = i = i->prev;
9149 if (IS_ADJUST(i)) i = i->prev;
9150 if (!IS_INSN(i)) return false;
9151 switch (INSN_OF(i)) {
9152 case BIN(leave):
9153 case BIN(jump):
9154 break;
9155 default:
9156 return false;
9157 }
9158 (ret->last = last->prev)->next = NULL;
9159 return true;
9160}
9161
9162static int
9163compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9164{
9165 CHECK(COMPILE_(ret, "nd_body", node, popped));
9166
9167 if (!popped && !all_string_result_p(node)) {
9168 const NODE *line_node = node;
9169 const unsigned int flag = VM_CALL_FCALL;
9170
9171 // Note, this dup could be removed if we are willing to change anytostring. It pops
9172 // two VALUEs off the stack when it could work by replacing the top most VALUE.
9173 ADD_INSN(ret, line_node, dup);
9174 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9175 ADD_INSN(ret, line_node, anytostring);
9176 }
9177 return COMPILE_OK;
9178}
9179
9180static void
9181compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
9182{
9183 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9184
9185 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
9186 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9187}
9188
9189static LABEL *
9190qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
9191{
9192 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9193 VALUE br = 0;
9194
9195 br = decl_branch_base(iseq, nd_node_id(node), nd_code_loc(node), "&.");
9196 *branches = br;
9197 ADD_INSN(recv, line_node, dup);
9198 ADD_INSNL(recv, line_node, branchnil, else_label);
9199 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
9200 return else_label;
9201}
9202
9203static void
9204qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
9205{
9206 LABEL *end_label;
9207 if (!else_label) return;
9208 end_label = NEW_LABEL(nd_line(line_node));
9209 ADD_INSNL(ret, line_node, jump, end_label);
9210 ADD_LABEL(ret, else_label);
9211 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
9212 ADD_LABEL(ret, end_label);
9213}
9214
9215static int
9216compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
9217{
9218 /* optimization shortcut
9219 * "literal".freeze -> opt_str_freeze("literal")
9220 */
9221 if (get_nd_recv(node) &&
9222 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9223 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9224 get_nd_args(node) == NULL &&
9225 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9226 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9227 VALUE str = get_string_value(get_nd_recv(node));
9228 if (get_node_call_nd_mid(node) == idUMinus) {
9229 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9230 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9231 }
9232 else {
9233 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9234 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9235 }
9236 RB_OBJ_WRITTEN(iseq, Qundef, str);
9237 if (popped) {
9238 ADD_INSN(ret, line_node, pop);
9239 }
9240 return TRUE;
9241 }
9242 return FALSE;
9243}
9244
9245static int
9246iseq_has_builtin_function_table(const rb_iseq_t *iseq)
9247{
9248 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9249}
9250
9251static const struct rb_builtin_function *
9252iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
9253{
9254 int i;
9255 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9256 for (i=0; table[i].index != -1; i++) {
9257 if (strcmp(table[i].name, name) == 0) {
9258 return &table[i];
9259 }
9260 }
9261 return NULL;
9262}
9263
9264static const char *
9265iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9266{
9267 const char *name = rb_id2name(mid);
9268 static const char prefix[] = "__builtin_";
9269 const size_t prefix_len = sizeof(prefix) - 1;
9270
9271 switch (type) {
9272 case NODE_CALL:
9273 if (recv) {
9274 switch (nd_type(recv)) {
9275 case NODE_VCALL:
9276 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9277 return name;
9278 }
9279 break;
9280 case NODE_CONST:
9281 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9282 return name;
9283 }
9284 break;
9285 default: break;
9286 }
9287 }
9288 break;
9289 case NODE_VCALL:
9290 case NODE_FCALL:
9291 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9292 return &name[prefix_len];
9293 }
9294 break;
9295 default: break;
9296 }
9297 return NULL;
9298}
9299
9300static int
9301delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9302{
9303
9304 if (argc == 0) {
9305 *pstart_index = 0;
9306 return TRUE;
9307 }
9308 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9309 unsigned int start=0;
9310
9311 // local_table: [p1, p2, p3, l1, l2, l3]
9312 // arguments: [p3, l1, l2] -> 2
9313 for (start = 0;
9314 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9315 start++) {
9316 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9317
9318 for (unsigned int i=start; i-start<argc; i++) {
9319 if (IS_INSN(elem) &&
9320 INSN_OF(elem) == BIN(getlocal)) {
9321 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9322 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9323
9324 if (local_level == 0) {
9325 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9326 if (0) { // for debug
9327 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9328 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9329 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9330 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9331 }
9332 if (i == index) {
9333 elem = elem->next;
9334 continue; /* for */
9335 }
9336 else {
9337 goto next;
9338 }
9339 }
9340 else {
9341 goto fail; // level != 0 is unsupported
9342 }
9343 }
9344 else {
9345 goto fail; // insn is not a getlocal
9346 }
9347 }
9348 goto success;
9349 next:;
9350 }
9351 fail:
9352 return FALSE;
9353 success:
9354 *pstart_index = start;
9355 return TRUE;
9356 }
9357 else {
9358 return FALSE;
9359 }
9360}
9361
9362static int
9363compile_builtin_attr_symbol(rb_iseq_t *iseq, VALUE symbol)
9364{
9365 VALUE string = rb_sym2str(symbol);
9366 if (rb_streql_lit(string, "leaf")) {
9367 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9368 }
9369 else if (rb_streql_lit(string, "inline_block")) {
9370 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9371 }
9372 else if (rb_streql_lit(string, "use_block")) {
9373 iseq_set_use_block(iseq);
9374 }
9375 else if (rb_streql_lit(string, "c_trace")) {
9376 // Let the iseq act like a C method in backtraces
9377 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9378 }
9379 else if (rb_streql_lit(string, "without_interrupts")) {
9380 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_WITHOUT_INTERRUPTS;
9381 }
9382 else {
9383 return COMPILE_NG;
9384 }
9385 return COMPILE_OK;
9386}
9387
9388// Compile Primitive.attr! :leaf, ...
9389static int
9390compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9391{
9392 VALUE symbol;
9393 if (!node) goto no_arg;
9394 while (node) {
9395 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9396 const NODE *next = RNODE_LIST(node)->nd_next;
9397
9398 node = RNODE_LIST(node)->nd_head;
9399 if (!node) goto no_arg;
9400 switch (nd_type(node)) {
9401 case NODE_SYM:
9402 symbol = rb_node_sym_string_val(node);
9403 break;
9404 default:
9405 goto bad_arg;
9406 }
9407
9408 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9409 if (compile_builtin_attr_symbol(iseq, symbol) != COMPILE_OK) goto unknown_arg;
9410 node = next;
9411 }
9412 return COMPILE_OK;
9413 no_arg:
9414 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9415 return COMPILE_NG;
9416 non_symbol_arg:
9417 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9418 return COMPILE_NG;
9419 unknown_arg:
9420 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %" PRIsVALUE, symbol);
9421 return COMPILE_NG;
9422 bad_arg:
9423 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9424}
9425
9426static int
9427compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9428{
9429 VALUE name;
9430
9431 if (!node) goto no_arg;
9432 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9433 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9434 node = RNODE_LIST(node)->nd_head;
9435 if (!node) goto no_arg;
9436 switch (nd_type(node)) {
9437 case NODE_SYM:
9438 name = rb_node_sym_string_val(node);
9439 break;
9440 default:
9441 goto bad_arg;
9442 }
9443 if (!SYMBOL_P(name)) goto non_symbol_arg;
9444 if (!popped) {
9445 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9446 }
9447 return COMPILE_OK;
9448 no_arg:
9449 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9450 return COMPILE_NG;
9451 too_many_arg:
9452 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9453 return COMPILE_NG;
9454 non_symbol_arg:
9455 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9456 rb_builtin_class_name(name));
9457 return COMPILE_NG;
9458 bad_arg:
9459 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9460}
9461
9462static NODE *
9463mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9464{
9465 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9466 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9467 return RNODE_IF(node)->nd_body;
9468 }
9469 else {
9470 rb_bug("mandatory_node: can't find mandatory node");
9471 }
9472}
9473
9474static int
9475compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9476{
9477 // arguments
9478 struct rb_args_info args = {
9479 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9480 };
9481 rb_node_args_t args_node;
9482 rb_node_init(RNODE(&args_node), NODE_ARGS);
9483 args_node.nd_ainfo = args;
9484
9485 // local table without non-mandatory parameters
9486 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9487 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9488
9489 VALUE idtmp = 0;
9490 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9491 tbl->size = table_size;
9492
9493 int i;
9494
9495 // lead parameters
9496 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9497 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9498 }
9499 // local variables
9500 for (; i<table_size; i++) {
9501 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9502 }
9503
9504 rb_node_scope_t scope_node;
9505 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9506 scope_node.nd_tbl = tbl;
9507 scope_node.nd_body = mandatory_node(iseq, node);
9508 scope_node.nd_parent = NULL;
9509 scope_node.nd_args = &args_node;
9510
9511 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9512
9513 const rb_iseq_t *mandatory_only_iseq =
9514 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9515 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9516 nd_line(line_node), NULL, 0,
9517 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9518 ISEQ_SCRIPT_LINES(iseq));
9519 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9520
9521 ALLOCV_END(idtmp);
9522 return COMPILE_OK;
9523}
9524
9525static int
9526compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9527 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9528{
9529 NODE *args_node = get_nd_args(node);
9530
9531 if (parent_block != NULL) {
9532 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9533 return COMPILE_NG;
9534 }
9535 else {
9536# define BUILTIN_INLINE_PREFIX "_bi"
9537 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9538 bool cconst = false;
9539 retry:;
9540 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9541
9542 if (bf == NULL) {
9543 if (strcmp("cstmt!", builtin_func) == 0 ||
9544 strcmp("cexpr!", builtin_func) == 0) {
9545 // ok
9546 }
9547 else if (strcmp("cconst!", builtin_func) == 0) {
9548 cconst = true;
9549 }
9550 else if (strcmp("cinit!", builtin_func) == 0) {
9551 // ignore
9552 return COMPILE_OK;
9553 }
9554 else if (strcmp("attr!", builtin_func) == 0) {
9555 return compile_builtin_attr(iseq, args_node);
9556 }
9557 else if (strcmp("arg!", builtin_func) == 0) {
9558 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9559 }
9560 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9561 if (popped) {
9562 rb_bug("mandatory_only? should be in if condition");
9563 }
9564 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9565 rb_bug("mandatory_only? should be put on top");
9566 }
9567
9568 ADD_INSN1(ret, line_node, putobject, Qfalse);
9569 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9570 }
9571 else if (1) {
9572 rb_bug("can't find builtin function:%s", builtin_func);
9573 }
9574 else {
9575 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9576 return COMPILE_NG;
9577 }
9578
9579 int inline_index = nd_line(node);
9580 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9581 builtin_func = inline_func;
9582 args_node = NULL;
9583 goto retry;
9584 }
9585
9586 if (cconst) {
9587 typedef VALUE(*builtin_func0)(void *, VALUE);
9588 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9589 ADD_INSN1(ret, line_node, putobject, const_val);
9590 return COMPILE_OK;
9591 }
9592
9593 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9594
9595 unsigned int flag = 0;
9596 struct rb_callinfo_kwarg *keywords = NULL;
9597 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9598
9599 if (FIX2INT(argc) != bf->argc) {
9600 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9601 builtin_func, bf->argc, FIX2INT(argc));
9602 return COMPILE_NG;
9603 }
9604
9605 unsigned int start_index;
9606 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9607 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9608 }
9609 else {
9610 ADD_SEQ(ret, args);
9611 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9612 }
9613
9614 if (popped) ADD_INSN(ret, line_node, pop);
9615 return COMPILE_OK;
9616 }
9617}
9618
9619static int
9620compile_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)
9621{
9622 /* call: obj.method(...)
9623 * fcall: func(...)
9624 * vcall: func
9625 */
9626 DECL_ANCHOR(recv);
9627 DECL_ANCHOR(args);
9628 ID mid = get_node_call_nd_mid(node);
9629 VALUE argc;
9630 unsigned int flag = 0;
9631 struct rb_callinfo_kwarg *keywords = NULL;
9632 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9633 LABEL *else_label = NULL;
9634 VALUE branches = Qfalse;
9635
9636 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9637
9638 INIT_ANCHOR(recv);
9639 INIT_ANCHOR(args);
9640
9641#if OPT_SUPPORT_JOKE
9642 if (nd_type_p(node, NODE_VCALL)) {
9643 ID id_bitblt;
9644 ID id_answer;
9645
9646 CONST_ID(id_bitblt, "bitblt");
9647 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9648
9649 if (mid == id_bitblt) {
9650 ADD_INSN(ret, line_node, bitblt);
9651 return COMPILE_OK;
9652 }
9653 else if (mid == id_answer) {
9654 ADD_INSN(ret, line_node, answer);
9655 return COMPILE_OK;
9656 }
9657 }
9658 /* only joke */
9659 {
9660 ID goto_id;
9661 ID label_id;
9662
9663 CONST_ID(goto_id, "__goto__");
9664 CONST_ID(label_id, "__label__");
9665
9666 if (nd_type_p(node, NODE_FCALL) &&
9667 (mid == goto_id || mid == label_id)) {
9668 LABEL *label;
9669 st_data_t data;
9670 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9671 VALUE label_name;
9672
9673 if (!labels_table) {
9674 labels_table = st_init_numtable();
9675 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9676 }
9677 {
9678 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9679 return COMPILE_NG;
9680 }
9681
9682 if (mid == goto_id) {
9683 ADD_INSNL(ret, line_node, jump, label);
9684 }
9685 else {
9686 ADD_LABEL(ret, label);
9687 }
9688 return COMPILE_OK;
9689 }
9690 }
9691#endif
9692
9693 const char *builtin_func;
9694 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9695 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9696 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9697 }
9698
9699 /* receiver */
9700 if (!assume_receiver) {
9701 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9702 int idx, level;
9703
9704 if ((mid == idCall || mid == idAREF || mid == idYield || mid == idEqq) &&
9705 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9706 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9707 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9708 }
9709 else if (private_recv_p(node)) {
9710 ADD_INSN(recv, node, putself);
9711 flag |= VM_CALL_FCALL;
9712 }
9713 else {
9714 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9715 }
9716
9717 if (type == NODE_QCALL) {
9718 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9719 }
9720 }
9721 else if (type == NODE_FCALL || type == NODE_VCALL) {
9722 ADD_CALL_RECEIVER(recv, line_node);
9723 }
9724 }
9725
9726 /* args */
9727 if (type != NODE_VCALL) {
9728 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9729 CHECK(!NIL_P(argc));
9730 }
9731 else {
9732 argc = INT2FIX(0);
9733 }
9734
9735 ADD_SEQ(ret, recv);
9736
9737 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9738 mid == rb_intern("new") &&
9739 parent_block == NULL &&
9740 !(flag & VM_CALL_ARGS_BLOCKARG);
9741
9742 if (inline_new) {
9743 ADD_INSN(ret, node, putnil);
9744 ADD_INSN(ret, node, swap);
9745 }
9746
9747 ADD_SEQ(ret, args);
9748
9749 debugp_param("call args argc", argc);
9750 debugp_param("call method", ID2SYM(mid));
9751
9752 switch ((int)type) {
9753 case NODE_VCALL:
9754 flag |= VM_CALL_VCALL;
9755 /* VCALL is funcall, so fall through */
9756 case NODE_FCALL:
9757 flag |= VM_CALL_FCALL;
9758 }
9759
9760 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9761 ADD_INSN(ret, line_node, splatkw);
9762 }
9763
9764 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9765 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9766
9767 if (inline_new) {
9768 // Jump unless the receiver uses the "basic" implementation of "new"
9769 VALUE ci;
9770 if (flag & VM_CALL_FORWARDING) {
9771 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9772 }
9773 else {
9774 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9775 }
9776 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9777 LABEL_REF(not_basic_new);
9778
9779 // optimized path
9780 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9781 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9782
9783 ADD_LABEL(ret, not_basic_new);
9784 // Fall back to normal send
9785 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9786 ADD_INSN(ret, line_node, swap);
9787
9788 ADD_LABEL(ret, not_basic_new_finish);
9789 ADD_INSN(ret, line_node, pop);
9790 }
9791 else {
9792 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9793 }
9794
9795 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9796 if (popped) {
9797 ADD_INSN(ret, line_node, pop);
9798 }
9799 return COMPILE_OK;
9800}
9801
9802static int
9803compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9804{
9805 const int line = nd_line(node);
9806 VALUE argc;
9807 unsigned int flag = 0;
9808 int asgnflag = 0;
9809 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9810
9811 /*
9812 * a[x] (op)= y
9813 *
9814 * nil # nil
9815 * eval a # nil a
9816 * eval x # nil a x
9817 * dupn 2 # nil a x a x
9818 * send :[] # nil a x a[x]
9819 * eval y # nil a x a[x] y
9820 * send op # nil a x ret
9821 * setn 3 # ret a x ret
9822 * send []= # ret ?
9823 * pop # ret
9824 */
9825
9826 /*
9827 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9828 * NODE_OP_ASGN nd_recv
9829 * nd_args->nd_head
9830 * nd_args->nd_body
9831 * nd_mid
9832 */
9833
9834 if (!popped) {
9835 ADD_INSN(ret, node, putnil);
9836 }
9837 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9838 CHECK(asgnflag != -1);
9839 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9840 case NODE_ZLIST:
9841 argc = INT2FIX(0);
9842 break;
9843 default:
9844 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9845 CHECK(!NIL_P(argc));
9846 }
9847 int dup_argn = FIX2INT(argc) + 1;
9848 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9849 flag |= asgnflag;
9850 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9851
9852 if (id == idOROP || id == idANDOP) {
9853 /* a[x] ||= y or a[x] &&= y
9854
9855 unless/if a[x]
9856 a[x]= y
9857 else
9858 nil
9859 end
9860 */
9861 LABEL *label = NEW_LABEL(line);
9862 LABEL *lfin = NEW_LABEL(line);
9863
9864 ADD_INSN(ret, node, dup);
9865 if (id == idOROP) {
9866 ADD_INSNL(ret, node, branchif, label);
9867 }
9868 else { /* idANDOP */
9869 ADD_INSNL(ret, node, branchunless, label);
9870 }
9871 ADD_INSN(ret, node, pop);
9872
9873 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9874 if (!popped) {
9875 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9876 }
9877 if (flag & VM_CALL_ARGS_SPLAT) {
9878 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9879 ADD_INSN(ret, node, swap);
9880 ADD_INSN1(ret, node, splatarray, Qtrue);
9881 ADD_INSN(ret, node, swap);
9882 flag |= VM_CALL_ARGS_SPLAT_MUT;
9883 }
9884 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9885 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9886 }
9887 else {
9888 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9889 }
9890 ADD_INSN(ret, node, pop);
9891 ADD_INSNL(ret, node, jump, lfin);
9892 ADD_LABEL(ret, label);
9893 if (!popped) {
9894 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9895 }
9896 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9897 ADD_LABEL(ret, lfin);
9898 }
9899 else {
9900 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9901 ADD_SEND(ret, node, id, INT2FIX(1));
9902 if (!popped) {
9903 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9904 }
9905 if (flag & VM_CALL_ARGS_SPLAT) {
9906 if (flag & VM_CALL_KW_SPLAT) {
9907 ADD_INSN1(ret, node, topn, INT2FIX(2));
9908 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9909 ADD_INSN1(ret, node, splatarray, Qtrue);
9910 flag |= VM_CALL_ARGS_SPLAT_MUT;
9911 }
9912 ADD_INSN(ret, node, swap);
9913 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9914 ADD_INSN1(ret, node, setn, INT2FIX(2));
9915 ADD_INSN(ret, node, pop);
9916 }
9917 else {
9918 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9919 ADD_INSN(ret, node, swap);
9920 ADD_INSN1(ret, node, splatarray, Qtrue);
9921 ADD_INSN(ret, node, swap);
9922 flag |= VM_CALL_ARGS_SPLAT_MUT;
9923 }
9924 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9925 }
9926 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9927 }
9928 else {
9929 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9930 }
9931 ADD_INSN(ret, node, pop);
9932 }
9933 return COMPILE_OK;
9934}
9935
9936static int
9937compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9938{
9939 const int line = nd_line(node);
9940 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9941 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9942 int asgnflag;
9943 LABEL *lfin = NEW_LABEL(line);
9944 LABEL *lcfin = NEW_LABEL(line);
9945 LABEL *lskip = 0;
9946 /*
9947 class C; attr_accessor :c; end
9948 r = C.new
9949 r.a &&= v # asgn2
9950
9951 eval r # r
9952 dup # r r
9953 eval r.a # r o
9954
9955 # or
9956 dup # r o o
9957 if lcfin # r o
9958 pop # r
9959 eval v # r v
9960 swap # v r
9961 topn 1 # v r v
9962 send a= # v ?
9963 jump lfin # v ?
9964
9965 lcfin: # r o
9966 swap # o r
9967
9968 lfin: # o ?
9969 pop # o
9970
9971 # or (popped)
9972 if lcfin # r
9973 eval v # r v
9974 send a= # ?
9975 jump lfin # ?
9976
9977 lcfin: # r
9978
9979 lfin: # ?
9980 pop #
9981
9982 # and
9983 dup # r o o
9984 unless lcfin
9985 pop # r
9986 eval v # r v
9987 swap # v r
9988 topn 1 # v r v
9989 send a= # v ?
9990 jump lfin # v ?
9991
9992 # others
9993 eval v # r o v
9994 send ?? # r w
9995 send a= # w
9996
9997 */
9998
9999 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
10000 CHECK(asgnflag != -1);
10001 if (RNODE_OP_ASGN2(node)->nd_aid) {
10002 lskip = NEW_LABEL(line);
10003 ADD_INSN(ret, node, dup);
10004 ADD_INSNL(ret, node, branchnil, lskip);
10005 }
10006 ADD_INSN(ret, node, dup);
10007 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
10008
10009 if (atype == idOROP || atype == idANDOP) {
10010 if (!popped) {
10011 ADD_INSN(ret, node, dup);
10012 }
10013 if (atype == idOROP) {
10014 ADD_INSNL(ret, node, branchif, lcfin);
10015 }
10016 else { /* idANDOP */
10017 ADD_INSNL(ret, node, branchunless, lcfin);
10018 }
10019 if (!popped) {
10020 ADD_INSN(ret, node, pop);
10021 }
10022 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10023 if (!popped) {
10024 ADD_INSN(ret, node, swap);
10025 ADD_INSN1(ret, node, topn, INT2FIX(1));
10026 }
10027 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10028 ADD_INSNL(ret, node, jump, lfin);
10029
10030 ADD_LABEL(ret, lcfin);
10031 if (!popped) {
10032 ADD_INSN(ret, node, swap);
10033 }
10034
10035 ADD_LABEL(ret, lfin);
10036 }
10037 else {
10038 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
10039 ADD_SEND(ret, node, atype, INT2FIX(1));
10040 if (!popped) {
10041 ADD_INSN(ret, node, swap);
10042 ADD_INSN1(ret, node, topn, INT2FIX(1));
10043 }
10044 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
10045 }
10046 if (lskip && popped) {
10047 ADD_LABEL(ret, lskip);
10048 }
10049 ADD_INSN(ret, node, pop);
10050 if (lskip && !popped) {
10051 ADD_LABEL(ret, lskip);
10052 }
10053 return COMPILE_OK;
10054}
10055
10056static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
10057
10058static int
10059compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10060{
10061 const int line = nd_line(node);
10062 LABEL *lfin = 0;
10063 LABEL *lassign = 0;
10064 ID mid;
10065
10066 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
10067 case NODE_COLON3:
10068 ADD_INSN1(ret, node, putobject, rb_cObject);
10069 break;
10070 case NODE_COLON2:
10071 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
10072 break;
10073 default:
10074 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
10075 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
10076 return COMPILE_NG;
10077 }
10078 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
10079 /* cref */
10080 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
10081 lassign = NEW_LABEL(line);
10082 ADD_INSN(ret, node, dup); /* cref cref */
10083 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
10084 ID2SYM(mid), Qtrue); /* cref bool */
10085 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
10086 }
10087 ADD_INSN(ret, node, dup); /* cref cref */
10088 ADD_INSN1(ret, node, putobject, Qtrue);
10089 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
10090
10091 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
10092 lfin = NEW_LABEL(line);
10093 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
10094 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
10095 ADD_INSNL(ret, node, branchif, lfin);
10096 else /* idANDOP */
10097 ADD_INSNL(ret, node, branchunless, lfin);
10098 /* cref [obj] */
10099 if (!popped) ADD_INSN(ret, node, pop); /* cref */
10100 if (lassign) ADD_LABEL(ret, lassign);
10101 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10102 /* cref value */
10103 if (popped)
10104 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
10105 else {
10106 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
10107 ADD_INSN(ret, node, swap); /* cref value value cref */
10108 }
10109 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
10110 ADD_LABEL(ret, lfin); /* cref [value] */
10111 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
10112 ADD_INSN(ret, node, pop); /* [value] */
10113 }
10114 else {
10115 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
10116 /* cref obj value */
10117 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
10118 /* cref value */
10119 ADD_INSN(ret, node, swap); /* value cref */
10120 if (!popped) {
10121 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
10122 ADD_INSN(ret, node, swap); /* value value cref */
10123 }
10124 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
10125 }
10126 return COMPILE_OK;
10127}
10128
10129static int
10130compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10131{
10132 const int line = nd_line(node);
10133 LABEL *lfin = NEW_LABEL(line);
10134 LABEL *lassign;
10135
10136 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
10137 LABEL *lfinish[2];
10138 lfinish[0] = lfin;
10139 lfinish[1] = 0;
10140 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
10141 lassign = lfinish[1];
10142 if (!lassign) {
10143 lassign = NEW_LABEL(line);
10144 }
10145 ADD_INSNL(ret, node, branchunless, lassign);
10146 }
10147 else {
10148 lassign = NEW_LABEL(line);
10149 }
10150
10151 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10152
10153 if (!popped) {
10154 ADD_INSN(ret, node, dup);
10155 }
10156
10157 if (type == NODE_OP_ASGN_AND) {
10158 ADD_INSNL(ret, node, branchunless, lfin);
10159 }
10160 else {
10161 ADD_INSNL(ret, node, branchif, lfin);
10162 }
10163
10164 if (!popped) {
10165 ADD_INSN(ret, node, pop);
10166 }
10167
10168 ADD_LABEL(ret, lassign);
10169 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10170 ADD_LABEL(ret, lfin);
10171 return COMPILE_OK;
10172}
10173
10174static int
10175compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10176{
10177 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10178 DECL_ANCHOR(args);
10179 int argc;
10180 unsigned int flag = 0;
10181 struct rb_callinfo_kwarg *keywords = NULL;
10182 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10183 int use_block = 1;
10184
10185 INIT_ANCHOR(args);
10186 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10187
10188 if (type == NODE_SUPER) {
10189 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10190 CHECK(!NIL_P(vargc));
10191 argc = FIX2INT(vargc);
10192 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10193 ADD_INSN(args, node, splatkw);
10194 }
10195
10196 if (flag & VM_CALL_ARGS_BLOCKARG) {
10197 use_block = 0;
10198 }
10199 }
10200 else {
10201 /* NODE_ZSUPER */
10202 int i;
10203 const rb_iseq_t *liseq = body->local_iseq;
10204 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
10205 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
10206 int lvar_level = get_lvar_level(iseq);
10207
10208 argc = local_body->param.lead_num;
10209
10210 /* normal arguments */
10211 for (i = 0; i < local_body->param.lead_num; i++) {
10212 int idx = local_body->local_table_size - i;
10213 ADD_GETLOCAL(args, node, idx, lvar_level);
10214 }
10215
10216 /* forward ... */
10217 if (local_body->param.flags.forwardable) {
10218 flag |= VM_CALL_FORWARDING;
10219 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10220 ADD_GETLOCAL(args, node, idx, lvar_level);
10221 }
10222
10223 if (local_body->param.flags.has_opt) {
10224 /* optional arguments */
10225 int j;
10226 for (j = 0; j < local_body->param.opt_num; j++) {
10227 int idx = local_body->local_table_size - (i + j);
10228 ADD_GETLOCAL(args, node, idx, lvar_level);
10229 }
10230 i += j;
10231 argc = i;
10232 }
10233 if (local_body->param.flags.has_rest) {
10234 /* rest argument */
10235 int idx = local_body->local_table_size - local_body->param.rest_start;
10236 ADD_GETLOCAL(args, node, idx, lvar_level);
10237 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10238
10239 argc = local_body->param.rest_start + 1;
10240 flag |= VM_CALL_ARGS_SPLAT;
10241 }
10242 if (local_body->param.flags.has_post) {
10243 /* post arguments */
10244 int post_len = local_body->param.post_num;
10245 int post_start = local_body->param.post_start;
10246
10247 if (local_body->param.flags.has_rest) {
10248 int j;
10249 for (j=0; j<post_len; j++) {
10250 int idx = local_body->local_table_size - (post_start + j);
10251 ADD_GETLOCAL(args, node, idx, lvar_level);
10252 }
10253 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
10254 flag |= VM_CALL_ARGS_SPLAT_MUT;
10255 /* argc is settled at above */
10256 }
10257 else {
10258 int j;
10259 for (j=0; j<post_len; j++) {
10260 int idx = local_body->local_table_size - (post_start + j);
10261 ADD_GETLOCAL(args, node, idx, lvar_level);
10262 }
10263 argc = post_len + post_start;
10264 }
10265 }
10266
10267 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10268 int local_size = local_body->local_table_size;
10269 argc++;
10270
10271 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10272
10273 if (local_body->param.flags.has_kwrest) {
10274 int idx = local_body->local_table_size - local_kwd->rest_start;
10275 ADD_GETLOCAL(args, node, idx, lvar_level);
10276 RUBY_ASSERT(local_kwd->num > 0);
10277 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10278 }
10279 else {
10280 ADD_INSN1(args, node, newhash, INT2FIX(0));
10281 }
10282 for (i = 0; i < local_kwd->num; ++i) {
10283 ID id = local_kwd->table[i];
10284 int idx = local_size - get_local_var_idx(liseq, id);
10285 ADD_INSN1(args, node, putobject, ID2SYM(id));
10286 ADD_GETLOCAL(args, node, idx, lvar_level);
10287 }
10288 ADD_SEND(args, node, id_core_hash_merge_bang_ptr, INT2FIX(i * 2 + 1));
10289 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10290 }
10291 else 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 argc++;
10295 flag |= VM_CALL_KW_SPLAT;
10296 }
10297 }
10298
10299 if (use_block && parent_block == NULL) {
10300 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10301 }
10302
10303 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10304 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10305 ADD_INSN(ret, node, putself);
10306 ADD_SEQ(ret, args);
10307
10308 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10309
10310 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10311 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10312 }
10313 else {
10314 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10315 }
10316
10317 if (popped) {
10318 ADD_INSN(ret, node, pop);
10319 }
10320 return COMPILE_OK;
10321}
10322
10323static int
10324compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10325{
10326 DECL_ANCHOR(args);
10327 VALUE argc;
10328 unsigned int flag = 0;
10329 struct rb_callinfo_kwarg *keywords = NULL;
10330
10331 INIT_ANCHOR(args);
10332
10333 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10334 case ISEQ_TYPE_TOP:
10335 case ISEQ_TYPE_MAIN:
10336 case ISEQ_TYPE_CLASS:
10337 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10338 return COMPILE_NG;
10339 default: /* valid */;
10340 }
10341
10342 if (RNODE_YIELD(node)->nd_head) {
10343 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10344 CHECK(!NIL_P(argc));
10345 }
10346 else {
10347 argc = INT2FIX(0);
10348 }
10349
10350 ADD_SEQ(ret, args);
10351 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10352 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10353
10354 if (popped) {
10355 ADD_INSN(ret, node, pop);
10356 }
10357
10358 int level = 0;
10359 const rb_iseq_t *tmp_iseq = iseq;
10360 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10361 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10362 }
10363 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10364
10365 return COMPILE_OK;
10366}
10367
10368static int
10369compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10370{
10371 DECL_ANCHOR(recv);
10372 DECL_ANCHOR(val);
10373
10374 INIT_ANCHOR(recv);
10375 INIT_ANCHOR(val);
10376 switch ((int)type) {
10377 case NODE_MATCH:
10378 {
10379 VALUE re = rb_node_regx_string_val(node);
10380 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10381 ADD_INSN1(recv, node, putobject, re);
10382 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10383 INT2FIX(0));
10384 }
10385 break;
10386 case NODE_MATCH2:
10387 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10388 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10389 break;
10390 case NODE_MATCH3:
10391 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10392 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10393 break;
10394 }
10395
10396 ADD_SEQ(ret, recv);
10397 ADD_SEQ(ret, val);
10398 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10399
10400 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10401 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10402 }
10403
10404 if (popped) {
10405 ADD_INSN(ret, node, pop);
10406 }
10407 return COMPILE_OK;
10408}
10409
10410static int
10411compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10412{
10413 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10414 /* constant */
10415 VALUE segments;
10416 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10417 (segments = collect_const_segments(iseq, node))) {
10418 ISEQ_BODY(iseq)->ic_size++;
10419 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10420 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10421 }
10422 else {
10423 /* constant */
10424 DECL_ANCHOR(pref);
10425 DECL_ANCHOR(body);
10426
10427 INIT_ANCHOR(pref);
10428 INIT_ANCHOR(body);
10429 CHECK(compile_const_prefix(iseq, node, pref, body));
10430 if (LIST_INSN_SIZE_ZERO(pref)) {
10431 ADD_INSN(ret, node, putnil);
10432 ADD_SEQ(ret, body);
10433 }
10434 else {
10435 ADD_SEQ(ret, pref);
10436 ADD_SEQ(ret, body);
10437 }
10438 }
10439 }
10440 else {
10441 /* function call */
10442 ADD_CALL_RECEIVER(ret, node);
10443 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10444 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10445 }
10446 if (popped) {
10447 ADD_INSN(ret, node, pop);
10448 }
10449 return COMPILE_OK;
10450}
10451
10452static int
10453compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10454{
10455 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10456
10457 /* add cache insn */
10458 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10459 ISEQ_BODY(iseq)->ic_size++;
10460 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10461 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10462 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10463 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10464 }
10465 else {
10466 ADD_INSN1(ret, node, putobject, rb_cObject);
10467 ADD_INSN1(ret, node, putobject, Qtrue);
10468 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10469 }
10470
10471 if (popped) {
10472 ADD_INSN(ret, node, pop);
10473 }
10474 return COMPILE_OK;
10475}
10476
10477static int
10478compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10479{
10480 VALUE flag = INT2FIX(excl);
10481 const NODE *b = RNODE_DOT2(node)->nd_beg;
10482 const NODE *e = RNODE_DOT2(node)->nd_end;
10483
10484 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10485 if (!popped) {
10486 VALUE bv = optimized_range_item(b);
10487 VALUE ev = optimized_range_item(e);
10488 VALUE val = rb_range_new(bv, ev, excl);
10490 ADD_INSN1(ret, node, putobject, val);
10491 RB_OBJ_WRITTEN(iseq, Qundef, val);
10492 }
10493 }
10494 else {
10495 CHECK(COMPILE_(ret, "min", b, popped));
10496 CHECK(COMPILE_(ret, "max", e, popped));
10497 if (!popped) {
10498 ADD_INSN1(ret, node, newrange, flag);
10499 }
10500 }
10501 return COMPILE_OK;
10502}
10503
10504static int
10505compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10506{
10507 if (!popped) {
10508 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10509 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10510 }
10511 else {
10512 const rb_iseq_t *ip = iseq;
10513 int level = 0;
10514 while (ip) {
10515 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10516 break;
10517 }
10518 ip = ISEQ_BODY(ip)->parent_iseq;
10519 level++;
10520 }
10521 if (ip) {
10522 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10523 }
10524 else {
10525 ADD_INSN(ret, node, putnil);
10526 }
10527 }
10528 }
10529 return COMPILE_OK;
10530}
10531
10532static int
10533compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10534{
10535 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10536 LABEL *end_label = NEW_LABEL(nd_line(node));
10537 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10538
10539 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10540 /* required argument. do nothing */
10541 COMPILE_ERROR(ERROR_ARGS "unreachable");
10542 return COMPILE_NG;
10543 }
10544 else if (nd_type_p(default_value, NODE_SYM) ||
10545 nd_type_p(default_value, NODE_REGX) ||
10546 nd_type_p(default_value, NODE_LINE) ||
10547 nd_type_p(default_value, NODE_INTEGER) ||
10548 nd_type_p(default_value, NODE_FLOAT) ||
10549 nd_type_p(default_value, NODE_RATIONAL) ||
10550 nd_type_p(default_value, NODE_IMAGINARY) ||
10551 nd_type_p(default_value, NODE_NIL) ||
10552 nd_type_p(default_value, NODE_TRUE) ||
10553 nd_type_p(default_value, NODE_FALSE)) {
10554 COMPILE_ERROR(ERROR_ARGS "unreachable");
10555 return COMPILE_NG;
10556 }
10557 else {
10558 /* if keywordcheck(_kw_bits, nth_keyword)
10559 * kw = default_value
10560 * end
10561 */
10562 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10563 int keyword_idx = body->param.keyword->num;
10564
10565 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10566 ADD_INSNL(ret, node, branchif, end_label);
10567 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10568 ADD_LABEL(ret, end_label);
10569 }
10570 return COMPILE_OK;
10571}
10572
10573static int
10574compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10575{
10576 DECL_ANCHOR(recv);
10577 DECL_ANCHOR(args);
10578 unsigned int flag = 0;
10579 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10580 VALUE argc;
10581 LABEL *else_label = NULL;
10582 VALUE branches = Qfalse;
10583
10584 INIT_ANCHOR(recv);
10585 INIT_ANCHOR(args);
10586 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10587 CHECK(!NIL_P(argc));
10588
10589 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10590 CHECK(asgnflag != -1);
10591 flag |= (unsigned int)asgnflag;
10592
10593 debugp_param("argc", argc);
10594 debugp_param("nd_mid", ID2SYM(mid));
10595
10596 if (!rb_is_attrset_id(mid)) {
10597 /* safe nav attr */
10598 mid = rb_id_attrset(mid);
10599 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10600 }
10601 if (!popped) {
10602 ADD_INSN(ret, node, putnil);
10603 ADD_SEQ(ret, recv);
10604 ADD_SEQ(ret, args);
10605
10606 if (flag & VM_CALL_ARGS_SPLAT) {
10607 ADD_INSN(ret, node, dup);
10608 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10609 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10610 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10611 ADD_INSN (ret, node, pop);
10612 }
10613 else {
10614 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10615 }
10616 }
10617 else {
10618 ADD_SEQ(ret, recv);
10619 ADD_SEQ(ret, args);
10620 }
10621 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10622 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10623 ADD_INSN(ret, node, pop);
10624 return COMPILE_OK;
10625}
10626
10627static int
10628compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10629{
10630 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10631 ADD_SEQ(ret, sub);
10632
10633 if (copy) {
10634 /*
10635 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10636 * NEW_LIST(value, loc), loc);
10637 */
10638 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10639 }
10640 else {
10641 /*
10642 * NEW_CALL(fcore, rb_intern("make_shareable"),
10643 * NEW_LIST(value, loc), loc);
10644 */
10645 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10646 }
10647
10648 return COMPILE_OK;
10649}
10650
10651static VALUE
10652node_const_decl_val(const NODE *node)
10653{
10654 VALUE path;
10655 switch (nd_type(node)) {
10656 case NODE_CDECL:
10657 if (RNODE_CDECL(node)->nd_vid) {
10658 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10659 goto end;
10660 }
10661 else {
10662 node = RNODE_CDECL(node)->nd_else;
10663 }
10664 break;
10665 case NODE_COLON2:
10666 break;
10667 case NODE_COLON3:
10668 // ::Const
10669 path = rb_str_new_cstr("::");
10670 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10671 goto end;
10672 default:
10673 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10675 }
10676
10677 path = rb_ary_new();
10678 if (node) {
10679 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10680 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10681 }
10682 if (node && nd_type_p(node, NODE_CONST)) {
10683 // Const::Name
10684 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10685 }
10686 else if (node && nd_type_p(node, NODE_COLON3)) {
10687 // ::Const::Name
10688 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10689 rb_ary_push(path, rb_str_new(0, 0));
10690 }
10691 else {
10692 // expression::Name
10693 rb_ary_push(path, rb_str_new_cstr("..."));
10694 }
10695 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10696 }
10697 end:
10698 path = rb_fstring(path);
10699 return path;
10700}
10701
10702static VALUE
10703const_decl_path(NODE *dest)
10704{
10705 VALUE path = Qnil;
10706 if (!nd_type_p(dest, NODE_CALL)) {
10707 path = node_const_decl_val(dest);
10708 }
10709 return path;
10710}
10711
10712static int
10713compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10714{
10715 /*
10716 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10717 */
10718 VALUE path = const_decl_path(dest);
10719 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10720 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10721 ADD_INSN1(ret, value, putobject, path);
10722 RB_OBJ_WRITTEN(iseq, Qundef, path);
10723 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10724
10725 return COMPILE_OK;
10726}
10727
10728#ifndef SHAREABLE_BARE_EXPRESSION
10729#define SHAREABLE_BARE_EXPRESSION 1
10730#endif
10731
10732static int
10733compile_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)
10734{
10735# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10736 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10737 VALUE lit = Qnil;
10738 DECL_ANCHOR(anchor);
10739
10740 enum node_type type = node ? nd_type(node) : NODE_NIL;
10741 switch (type) {
10742 case NODE_TRUE:
10743 *value_p = Qtrue;
10744 goto compile;
10745 case NODE_FALSE:
10746 *value_p = Qfalse;
10747 goto compile;
10748 case NODE_NIL:
10749 *value_p = Qnil;
10750 goto compile;
10751 case NODE_SYM:
10752 *value_p = rb_node_sym_string_val(node);
10753 goto compile;
10754 case NODE_REGX:
10755 *value_p = rb_node_regx_string_val(node);
10756 goto compile;
10757 case NODE_LINE:
10758 *value_p = rb_node_line_lineno_val(node);
10759 goto compile;
10760 case NODE_INTEGER:
10761 *value_p = rb_node_integer_literal_val(node);
10762 goto compile;
10763 case NODE_FLOAT:
10764 *value_p = rb_node_float_literal_val(node);
10765 goto compile;
10766 case NODE_RATIONAL:
10767 *value_p = rb_node_rational_literal_val(node);
10768 goto compile;
10769 case NODE_IMAGINARY:
10770 *value_p = rb_node_imaginary_literal_val(node);
10771 goto compile;
10772 case NODE_ENCODING:
10773 *value_p = rb_node_encoding_val(node);
10774
10775 compile:
10776 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10777 *shareable_literal_p = 1;
10778 return COMPILE_OK;
10779
10780 case NODE_DSTR:
10781 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10782 if (shareable == rb_parser_shareable_literal) {
10783 /*
10784 * NEW_CALL(node, idUMinus, 0, loc);
10785 *
10786 * -"#{var}"
10787 */
10788 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10789 }
10790 *value_p = Qundef;
10791 *shareable_literal_p = 1;
10792 return COMPILE_OK;
10793
10794 case NODE_STR:{
10795 VALUE lit = rb_node_str_string_val(node);
10796 ADD_INSN1(ret, node, putobject, lit);
10797 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10798 *value_p = lit;
10799 *shareable_literal_p = 1;
10800
10801 return COMPILE_OK;
10802 }
10803
10804 case NODE_FILE:{
10805 VALUE lit = rb_node_file_path_val(node);
10806 ADD_INSN1(ret, node, putobject, lit);
10807 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10808 *value_p = lit;
10809 *shareable_literal_p = 1;
10810
10811 return COMPILE_OK;
10812 }
10813
10814 case NODE_ZLIST:{
10815 VALUE lit = rb_ary_new();
10816 OBJ_FREEZE(lit);
10817 ADD_INSN1(ret, node, putobject, lit);
10818 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10819 *value_p = lit;
10820 *shareable_literal_p = 1;
10821
10822 return COMPILE_OK;
10823 }
10824
10825 case NODE_LIST:{
10826 INIT_ANCHOR(anchor);
10827 lit = rb_ary_new();
10828 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10829 VALUE val;
10830 int shareable_literal_p2;
10831 NODE *elt = RNODE_LIST(n)->nd_head;
10832 if (elt) {
10833 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10834 if (shareable_literal_p2) {
10835 /* noop */
10836 }
10837 else if (RTEST(lit)) {
10838 rb_ary_clear(lit);
10839 lit = Qfalse;
10840 }
10841 }
10842 if (RTEST(lit)) {
10843 if (!UNDEF_P(val)) {
10844 rb_ary_push(lit, val);
10845 }
10846 else {
10847 rb_ary_clear(lit);
10848 lit = Qnil; /* make shareable at runtime */
10849 }
10850 }
10851 }
10852 break;
10853 }
10854 case NODE_HASH:{
10855 if (!RNODE_HASH(node)->nd_brace) {
10856 *value_p = Qundef;
10857 *shareable_literal_p = 0;
10858 return COMPILE_OK;
10859 }
10860 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10861 if (!RNODE_LIST(n)->nd_head) {
10862 // If the hash node have a keyword splat, fall back to the default case.
10863 goto compile_shareable;
10864 }
10865 }
10866
10867 INIT_ANCHOR(anchor);
10868 lit = rb_hash_new();
10869 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10870 VALUE key_val = 0;
10871 VALUE value_val = 0;
10872 int shareable_literal_p2;
10873 NODE *key = RNODE_LIST(n)->nd_head;
10874 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10875 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10876 if (shareable_literal_p2) {
10877 /* noop */
10878 }
10879 else if (RTEST(lit)) {
10880 rb_hash_clear(lit);
10881 lit = Qfalse;
10882 }
10883 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10884 if (shareable_literal_p2) {
10885 /* noop */
10886 }
10887 else if (RTEST(lit)) {
10888 rb_hash_clear(lit);
10889 lit = Qfalse;
10890 }
10891 if (RTEST(lit)) {
10892 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10893 rb_hash_aset(lit, key_val, value_val);
10894 }
10895 else {
10896 rb_hash_clear(lit);
10897 lit = Qnil; /* make shareable at runtime */
10898 }
10899 }
10900 }
10901 break;
10902 }
10903
10904 default:
10905
10906 compile_shareable:
10907 if (shareable == rb_parser_shareable_literal &&
10908 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10909 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10910 *value_p = Qundef;
10911 *shareable_literal_p = 1;
10912 return COMPILE_OK;
10913 }
10914 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10915 *value_p = Qundef;
10916 *shareable_literal_p = 0;
10917 return COMPILE_OK;
10918 }
10919
10920 /* Array or Hash that does not have keyword splat */
10921 if (!lit) {
10922 if (nd_type(node) == NODE_LIST) {
10923 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10924 }
10925 else if (nd_type(node) == NODE_HASH) {
10926 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10929 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10930 }
10931 *value_p = Qundef;
10932 *shareable_literal_p = 0;
10933 ADD_SEQ(ret, anchor);
10934 return COMPILE_OK;
10935 }
10936 if (NIL_P(lit)) {
10937 // if shareable_literal, all elements should have been ensured
10938 // as shareable
10939 if (nd_type(node) == NODE_LIST) {
10940 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10941 }
10942 else if (nd_type(node) == NODE_HASH) {
10943 long len = RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10946 ADD_INSN1(anchor, node, newhash, LONG2FIX(len));
10947 }
10948 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10949 *value_p = Qundef;
10950 *shareable_literal_p = 1;
10951 }
10952 else {
10954 ADD_INSN1(ret, node, putobject, val);
10955 RB_OBJ_WRITTEN(iseq, Qundef, val);
10956 *value_p = val;
10957 *shareable_literal_p = 1;
10958 }
10959
10960 return COMPILE_OK;
10961}
10962
10963static int
10964compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10965{
10966 int literal_p = 0;
10967 VALUE val;
10968 DECL_ANCHOR(anchor);
10969 INIT_ANCHOR(anchor);
10970
10971 switch (shareable) {
10972 case rb_parser_shareable_none:
10973 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10974 return COMPILE_OK;
10975
10976 case rb_parser_shareable_literal:
10977 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10978 ADD_SEQ(ret, anchor);
10979 return COMPILE_OK;
10980
10981 case rb_parser_shareable_copy:
10982 case rb_parser_shareable_everything:
10983 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10984 if (!literal_p) {
10985 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10986 }
10987 else {
10988 ADD_SEQ(ret, anchor);
10989 }
10990 return COMPILE_OK;
10991 default:
10992 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10993 }
10994}
10995
10996static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
11004static int
11005iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
11006{
11007 if (node == 0) {
11008 if (!popped) {
11009 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
11010 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
11011 debugs("node: NODE_NIL(implicit)\n");
11012 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
11013 }
11014 return COMPILE_OK;
11015 }
11016 return iseq_compile_each0(iseq, ret, node, popped);
11017}
11018
11019static int
11020iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
11021{
11022 const int line = (int)nd_line(node);
11023 const enum node_type type = nd_type(node);
11024 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11025
11026 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
11027 /* ignore */
11028 }
11029 else {
11030 if (nd_fl_newline(node)) {
11031 int event = RUBY_EVENT_LINE;
11032 ISEQ_COMPILE_DATA(iseq)->last_line = line;
11033 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
11034 event |= RUBY_EVENT_COVERAGE_LINE;
11035 }
11036 ADD_TRACE(ret, event);
11037 }
11038 }
11039
11040 debug_node_start(node);
11041#undef BEFORE_RETURN
11042#define BEFORE_RETURN debug_node_end()
11043
11044 switch (type) {
11045 case NODE_BLOCK:
11046 CHECK(compile_block(iseq, ret, node, popped));
11047 break;
11048 case NODE_IF:
11049 case NODE_UNLESS:
11050 CHECK(compile_if(iseq, ret, node, popped, type));
11051 break;
11052 case NODE_CASE:
11053 CHECK(compile_case(iseq, ret, node, popped));
11054 break;
11055 case NODE_CASE2:
11056 CHECK(compile_case2(iseq, ret, node, popped));
11057 break;
11058 case NODE_CASE3:
11059 CHECK(compile_case3(iseq, ret, node, popped));
11060 break;
11061 case NODE_WHILE:
11062 case NODE_UNTIL:
11063 CHECK(compile_loop(iseq, ret, node, popped, type));
11064 break;
11065 case NODE_FOR:
11066 case NODE_ITER:
11067 CHECK(compile_iter(iseq, ret, node, popped));
11068 break;
11069 case NODE_FOR_MASGN:
11070 CHECK(compile_for_masgn(iseq, ret, node, popped));
11071 break;
11072 case NODE_BREAK:
11073 CHECK(compile_break(iseq, ret, node, popped));
11074 break;
11075 case NODE_NEXT:
11076 CHECK(compile_next(iseq, ret, node, popped));
11077 break;
11078 case NODE_REDO:
11079 CHECK(compile_redo(iseq, ret, node, popped));
11080 break;
11081 case NODE_RETRY:
11082 CHECK(compile_retry(iseq, ret, node, popped));
11083 break;
11084 case NODE_BEGIN:{
11085 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
11086 break;
11087 }
11088 case NODE_RESCUE:
11089 CHECK(compile_rescue(iseq, ret, node, popped));
11090 break;
11091 case NODE_RESBODY:
11092 CHECK(compile_resbody(iseq, ret, node, popped));
11093 break;
11094 case NODE_ENSURE:
11095 CHECK(compile_ensure(iseq, ret, node, popped));
11096 break;
11097
11098 case NODE_AND:
11099 case NODE_OR:{
11100 LABEL *end_label = NEW_LABEL(line);
11101 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
11102 if (!popped) {
11103 ADD_INSN(ret, node, dup);
11104 }
11105 if (type == NODE_AND) {
11106 ADD_INSNL(ret, node, branchunless, end_label);
11107 }
11108 else {
11109 ADD_INSNL(ret, node, branchif, end_label);
11110 }
11111 if (!popped) {
11112 ADD_INSN(ret, node, pop);
11113 }
11114 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
11115 ADD_LABEL(ret, end_label);
11116 break;
11117 }
11118
11119 case NODE_MASGN:{
11120 compile_massign(iseq, ret, node, popped);
11121 break;
11122 }
11123
11124 case NODE_LASGN:{
11125 ID id = RNODE_LASGN(node)->nd_vid;
11126 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
11127
11128 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
11129 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
11130
11131 if (!popped) {
11132 ADD_INSN(ret, node, dup);
11133 }
11134 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
11135 break;
11136 }
11137 case NODE_DASGN: {
11138 int idx, lv, ls;
11139 ID id = RNODE_DASGN(node)->nd_vid;
11140 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
11141 debugi("dassn id", rb_id2str(id) ? id : '*');
11142
11143 if (!popped) {
11144 ADD_INSN(ret, node, dup);
11145 }
11146
11147 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
11148
11149 if (idx < 0) {
11150 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
11151 rb_id2str(id));
11152 goto ng;
11153 }
11154 ADD_SETLOCAL(ret, node, ls - idx, lv);
11155 break;
11156 }
11157 case NODE_GASGN:{
11158 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
11159
11160 if (!popped) {
11161 ADD_INSN(ret, node, dup);
11162 }
11163 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
11164 break;
11165 }
11166 case NODE_IASGN:{
11167 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
11168 if (!popped) {
11169 ADD_INSN(ret, node, dup);
11170 }
11171 ADD_INSN2(ret, node, setinstancevariable,
11172 ID2SYM(RNODE_IASGN(node)->nd_vid),
11173 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11174 break;
11175 }
11176 case NODE_CDECL:{
11177 if (RNODE_CDECL(node)->nd_vid) {
11178 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11179
11180 if (!popped) {
11181 ADD_INSN(ret, node, dup);
11182 }
11183
11184 ADD_INSN1(ret, node, putspecialobject,
11185 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11186 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
11187 }
11188 else {
11189 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11190 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11191 ADD_INSN(ret, node, swap);
11192
11193 if (!popped) {
11194 ADD_INSN1(ret, node, topn, INT2FIX(1));
11195 ADD_INSN(ret, node, swap);
11196 }
11197
11198 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11199 }
11200 break;
11201 }
11202 case NODE_CVASGN:{
11203 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
11204 if (!popped) {
11205 ADD_INSN(ret, node, dup);
11206 }
11207 ADD_INSN2(ret, node, setclassvariable,
11208 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11209 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11210 break;
11211 }
11212 case NODE_OP_ASGN1:
11213 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11214 break;
11215 case NODE_OP_ASGN2:
11216 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11217 break;
11218 case NODE_OP_CDECL:
11219 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11220 break;
11221 case NODE_OP_ASGN_AND:
11222 case NODE_OP_ASGN_OR:
11223 CHECK(compile_op_log(iseq, ret, node, popped, type));
11224 break;
11225 case NODE_CALL: /* obj.foo */
11226 case NODE_OPCALL: /* foo[] */
11227 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11228 break;
11229 }
11230 case NODE_QCALL: /* obj&.foo */
11231 case NODE_FCALL: /* foo() */
11232 case NODE_VCALL: /* foo (variable or call) */
11233 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
11234 goto ng;
11235 }
11236 break;
11237 case NODE_SUPER:
11238 case NODE_ZSUPER:
11239 CHECK(compile_super(iseq, ret, node, popped, type));
11240 break;
11241 case NODE_LIST:{
11242 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11243 break;
11244 }
11245 case NODE_ZLIST:{
11246 if (!popped) {
11247 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11248 }
11249 break;
11250 }
11251 case NODE_HASH:
11252 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11253 break;
11254 case NODE_RETURN:
11255 CHECK(compile_return(iseq, ret, node, popped));
11256 break;
11257 case NODE_YIELD:
11258 CHECK(compile_yield(iseq, ret, node, popped));
11259 break;
11260 case NODE_LVAR:{
11261 if (!popped) {
11262 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11263 }
11264 break;
11265 }
11266 case NODE_DVAR:{
11267 int lv, idx, ls;
11268 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11269 if (!popped) {
11270 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11271 if (idx < 0) {
11272 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11273 rb_id2str(RNODE_DVAR(node)->nd_vid));
11274 goto ng;
11275 }
11276 ADD_GETLOCAL(ret, node, ls - idx, lv);
11277 }
11278 break;
11279 }
11280 case NODE_GVAR:{
11281 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11282 if (popped) {
11283 ADD_INSN(ret, node, pop);
11284 }
11285 break;
11286 }
11287 case NODE_IVAR:{
11288 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11289 if (!popped) {
11290 ADD_INSN2(ret, node, getinstancevariable,
11291 ID2SYM(RNODE_IVAR(node)->nd_vid),
11292 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11293 }
11294 break;
11295 }
11296 case NODE_CONST:{
11297 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11298
11299 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11300 body->ic_size++;
11301 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11302 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11303 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11304 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11305 }
11306 else {
11307 ADD_INSN(ret, node, putnil);
11308 ADD_INSN1(ret, node, putobject, Qtrue);
11309 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11310 }
11311
11312 if (popped) {
11313 ADD_INSN(ret, node, pop);
11314 }
11315 break;
11316 }
11317 case NODE_CVAR:{
11318 if (!popped) {
11319 ADD_INSN2(ret, node, getclassvariable,
11320 ID2SYM(RNODE_CVAR(node)->nd_vid),
11321 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11322 }
11323 break;
11324 }
11325 case NODE_NTH_REF:{
11326 if (!popped) {
11327 if (!RNODE_NTH_REF(node)->nd_nth) {
11328 ADD_INSN(ret, node, putnil);
11329 break;
11330 }
11331 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11332 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11333 }
11334 break;
11335 }
11336 case NODE_BACK_REF:{
11337 if (!popped) {
11338 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11339 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11340 }
11341 break;
11342 }
11343 case NODE_MATCH:
11344 case NODE_MATCH2:
11345 case NODE_MATCH3:
11346 CHECK(compile_match(iseq, ret, node, popped, type));
11347 break;
11348 case NODE_SYM:{
11349 if (!popped) {
11350 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11351 }
11352 break;
11353 }
11354 case NODE_LINE:{
11355 if (!popped) {
11356 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11357 }
11358 break;
11359 }
11360 case NODE_ENCODING:{
11361 if (!popped) {
11362 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11363 }
11364 break;
11365 }
11366 case NODE_INTEGER:{
11367 VALUE lit = rb_node_integer_literal_val(node);
11368 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11369 debugp_param("integer", lit);
11370 if (!popped) {
11371 ADD_INSN1(ret, node, putobject, lit);
11372 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11373 }
11374 break;
11375 }
11376 case NODE_FLOAT:{
11377 VALUE lit = rb_node_float_literal_val(node);
11378 if (!SPECIAL_CONST_P(lit)) RB_OBJ_SET_SHAREABLE(lit);
11379 debugp_param("float", lit);
11380 if (!popped) {
11381 ADD_INSN1(ret, node, putobject, lit);
11382 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11383 }
11384 break;
11385 }
11386 case NODE_RATIONAL:{
11387 VALUE lit = rb_node_rational_literal_val(node);
11389 debugp_param("rational", lit);
11390 if (!popped) {
11391 ADD_INSN1(ret, node, putobject, lit);
11392 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11393 }
11394 break;
11395 }
11396 case NODE_IMAGINARY:{
11397 VALUE lit = rb_node_imaginary_literal_val(node);
11399 debugp_param("imaginary", lit);
11400 if (!popped) {
11401 ADD_INSN1(ret, node, putobject, lit);
11402 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11403 }
11404 break;
11405 }
11406 case NODE_FILE:
11407 case NODE_STR:{
11408 debugp_param("nd_lit", get_string_value(node));
11409 if (!popped) {
11410 VALUE lit = get_string_value(node);
11411 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11412 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11413 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11414 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11415 RB_OBJ_SET_SHAREABLE(lit);
11416 }
11417 switch (option->frozen_string_literal) {
11418 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11419 ADD_INSN1(ret, node, dupchilledstring, lit);
11420 break;
11421 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11422 ADD_INSN1(ret, node, dupstring, lit);
11423 break;
11424 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11425 ADD_INSN1(ret, node, putobject, lit);
11426 break;
11427 default:
11428 rb_bug("invalid frozen_string_literal");
11429 }
11430 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11431 }
11432 break;
11433 }
11434 case NODE_DSTR:{
11435 compile_dstr(iseq, ret, node);
11436
11437 if (popped) {
11438 ADD_INSN(ret, node, pop);
11439 }
11440 break;
11441 }
11442 case NODE_XSTR:{
11443 ADD_CALL_RECEIVER(ret, node);
11444 VALUE str = rb_node_str_string_val(node);
11445 ADD_INSN1(ret, node, putobject, str);
11446 RB_OBJ_WRITTEN(iseq, Qundef, str);
11447 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11448
11449 if (popped) {
11450 ADD_INSN(ret, node, pop);
11451 }
11452 break;
11453 }
11454 case NODE_DXSTR:{
11455 ADD_CALL_RECEIVER(ret, node);
11456 compile_dstr(iseq, ret, node);
11457 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11458
11459 if (popped) {
11460 ADD_INSN(ret, node, pop);
11461 }
11462 break;
11463 }
11464 case NODE_EVSTR:
11465 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11466 break;
11467 case NODE_REGX:{
11468 if (!popped) {
11469 VALUE lit = rb_node_regx_string_val(node);
11470 RB_OBJ_SET_SHAREABLE(lit);
11471 ADD_INSN1(ret, node, putobject, lit);
11472 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11473 }
11474 break;
11475 }
11476 case NODE_DREGX:
11477 compile_dregx(iseq, ret, node, popped);
11478 break;
11479 case NODE_ONCE:{
11480 int ic_index = body->ise_size++;
11481 const rb_iseq_t *block_iseq;
11482 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11483
11484 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11485 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11486
11487 if (popped) {
11488 ADD_INSN(ret, node, pop);
11489 }
11490 break;
11491 }
11492 case NODE_ARGSCAT:{
11493 if (popped) {
11494 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11495 ADD_INSN1(ret, node, splatarray, Qfalse);
11496 ADD_INSN(ret, node, pop);
11497 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11498 ADD_INSN1(ret, node, splatarray, Qfalse);
11499 ADD_INSN(ret, node, pop);
11500 }
11501 else {
11502 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11503 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11504 if (nd_type_p(body_node, NODE_LIST)) {
11505 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11506 }
11507 else {
11508 CHECK(COMPILE(ret, "argscat body", body_node));
11509 ADD_INSN(ret, node, concattoarray);
11510 }
11511 }
11512 break;
11513 }
11514 case NODE_ARGSPUSH:{
11515 if (popped) {
11516 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11517 ADD_INSN1(ret, node, splatarray, Qfalse);
11518 ADD_INSN(ret, node, pop);
11519 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11520 }
11521 else {
11522 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11523 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11524 if (keyword_node_p(body_node)) {
11525 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11526 ADD_INSN(ret, node, pushtoarraykwsplat);
11527 }
11528 else if (static_literal_node_p(body_node, iseq, false)) {
11529 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11530 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11531 }
11532 else {
11533 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11534 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11535 }
11536 }
11537 break;
11538 }
11539 case NODE_SPLAT:{
11540 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11541 ADD_INSN1(ret, node, splatarray, Qtrue);
11542
11543 if (popped) {
11544 ADD_INSN(ret, node, pop);
11545 }
11546 break;
11547 }
11548 case NODE_DEFN:{
11549 ID mid = RNODE_DEFN(node)->nd_mid;
11550 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11551 rb_id2str(mid),
11552 ISEQ_TYPE_METHOD, line);
11553
11554 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11555 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11556 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11557
11558 if (!popped) {
11559 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11560 }
11561
11562 break;
11563 }
11564 case NODE_DEFS:{
11565 ID mid = RNODE_DEFS(node)->nd_mid;
11566 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11567 rb_id2str(mid),
11568 ISEQ_TYPE_METHOD, line);
11569
11570 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11571 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11572 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11573 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11574
11575 if (!popped) {
11576 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11577 }
11578 break;
11579 }
11580 case NODE_ALIAS:{
11581 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11582 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11583 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11584 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11585 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11586
11587 if (popped) {
11588 ADD_INSN(ret, node, pop);
11589 }
11590 break;
11591 }
11592 case NODE_VALIAS:{
11593 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11594 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11595 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11596 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11597
11598 if (popped) {
11599 ADD_INSN(ret, node, pop);
11600 }
11601 break;
11602 }
11603 case NODE_UNDEF:{
11604 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11605
11606 for (long i = 0; i < ary->len; i++) {
11607 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11608 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11609 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11610 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11611
11612 if (i < ary->len - 1) {
11613 ADD_INSN(ret, node, pop);
11614 }
11615 }
11616
11617 if (popped) {
11618 ADD_INSN(ret, node, pop);
11619 }
11620 break;
11621 }
11622 case NODE_CLASS:{
11623 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11624 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11625 ISEQ_TYPE_CLASS, line);
11626 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11627 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11628 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11629
11630 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11631 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11632 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11633
11634 if (popped) {
11635 ADD_INSN(ret, node, pop);
11636 }
11637 break;
11638 }
11639 case NODE_MODULE:{
11640 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11641 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11642 ISEQ_TYPE_CLASS, line);
11643 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11644 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11645
11646 ADD_INSN (ret, node, putnil); /* dummy */
11647 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11648 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11649
11650 if (popped) {
11651 ADD_INSN(ret, node, pop);
11652 }
11653 break;
11654 }
11655 case NODE_SCLASS:{
11656 ID singletonclass;
11657 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11658 ISEQ_TYPE_CLASS, line);
11659
11660 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11661 ADD_INSN (ret, node, putnil);
11662 CONST_ID(singletonclass, "singletonclass");
11663
11664 /* `class << self` in a class body and `class << Foo` (constant
11665 receiver) are stable. All other forms are potentially dynamic. */
11666 int sclass_flags = VM_DEFINECLASS_TYPE_SINGLETON_CLASS;
11667 const NODE *recv = RNODE_SCLASS(node)->nd_recv;
11668 if (!(nd_type_p(recv, NODE_SELF) &&
11669 ISEQ_BODY(iseq)->type == ISEQ_TYPE_CLASS) &&
11670 !cpath_const_p(recv)) {
11671 sclass_flags |= VM_DEFINECLASS_FLAG_DYNAMIC_CREF;
11672 }
11673
11674 ADD_INSN3(ret, node, defineclass,
11675 ID2SYM(singletonclass), singleton_class,
11676 INT2FIX(sclass_flags));
11677 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11678
11679 if (popped) {
11680 ADD_INSN(ret, node, pop);
11681 }
11682 break;
11683 }
11684 case NODE_COLON2:
11685 CHECK(compile_colon2(iseq, ret, node, popped));
11686 break;
11687 case NODE_COLON3:
11688 CHECK(compile_colon3(iseq, ret, node, popped));
11689 break;
11690 case NODE_DOT2:
11691 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11692 break;
11693 case NODE_DOT3:
11694 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11695 break;
11696 case NODE_FLIP2:
11697 case NODE_FLIP3:{
11698 LABEL *lend = NEW_LABEL(line);
11699 LABEL *ltrue = NEW_LABEL(line);
11700 LABEL *lfalse = NEW_LABEL(line);
11701 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11702 ltrue, lfalse));
11703 ADD_LABEL(ret, ltrue);
11704 ADD_INSN1(ret, node, putobject, Qtrue);
11705 ADD_INSNL(ret, node, jump, lend);
11706 ADD_LABEL(ret, lfalse);
11707 ADD_INSN1(ret, node, putobject, Qfalse);
11708 ADD_LABEL(ret, lend);
11709 break;
11710 }
11711 case NODE_SELF:{
11712 if (!popped) {
11713 ADD_INSN(ret, node, putself);
11714 }
11715 break;
11716 }
11717 case NODE_NIL:{
11718 if (!popped) {
11719 ADD_INSN(ret, node, putnil);
11720 }
11721 break;
11722 }
11723 case NODE_TRUE:{
11724 if (!popped) {
11725 ADD_INSN1(ret, node, putobject, Qtrue);
11726 }
11727 break;
11728 }
11729 case NODE_FALSE:{
11730 if (!popped) {
11731 ADD_INSN1(ret, node, putobject, Qfalse);
11732 }
11733 break;
11734 }
11735 case NODE_ERRINFO:
11736 CHECK(compile_errinfo(iseq, ret, node, popped));
11737 break;
11738 case NODE_DEFINED:
11739 if (!popped) {
11740 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11741 }
11742 break;
11743 case NODE_POSTEXE:{
11744 /* compiled to:
11745 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11746 */
11747 int is_index = body->ise_size++;
11749 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11750 const rb_iseq_t *once_iseq =
11751 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11752
11753 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11754 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11755
11756 if (popped) {
11757 ADD_INSN(ret, node, pop);
11758 }
11759 break;
11760 }
11761 case NODE_KW_ARG:
11762 CHECK(compile_kw_arg(iseq, ret, node, popped));
11763 break;
11764 case NODE_DSYM:{
11765 compile_dstr(iseq, ret, node);
11766 if (!popped) {
11767 ADD_INSN(ret, node, intern);
11768 }
11769 else {
11770 ADD_INSN(ret, node, pop);
11771 }
11772 break;
11773 }
11774 case NODE_ATTRASGN:
11775 CHECK(compile_attrasgn(iseq, ret, node, popped));
11776 break;
11777 case NODE_LAMBDA:{
11778 /* compile same as lambda{...} */
11779 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11780 VALUE argc = INT2FIX(0);
11781
11782 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11783 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11784 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11785
11786 if (popped) {
11787 ADD_INSN(ret, node, pop);
11788 }
11789 break;
11790 }
11791 default:
11792 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11793 ng:
11794 debug_node_end();
11795 return COMPILE_NG;
11796 }
11797
11798 debug_node_end();
11799 return COMPILE_OK;
11800}
11801
11802/***************************/
11803/* instruction information */
11804/***************************/
11805
11806static int
11807insn_data_length(INSN *iobj)
11808{
11809 return insn_len(iobj->insn_id);
11810}
11811
11812static int
11813calc_sp_depth(int depth, INSN *insn)
11814{
11815 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11816}
11817
11818static VALUE
11819opobj_inspect(VALUE obj)
11820{
11821 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11822 switch (BUILTIN_TYPE(obj)) {
11823 case T_STRING:
11824 obj = rb_str_resurrect(obj);
11825 break;
11826 case T_ARRAY:
11827 obj = rb_ary_resurrect(obj);
11828 break;
11829 default:
11830 break;
11831 }
11832 }
11833 return rb_inspect(obj);
11834}
11835
11836
11837
11838static VALUE
11839insn_data_to_s_detail(INSN *iobj)
11840{
11841 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11842
11843 if (iobj->operands) {
11844 const char *types = insn_op_types(iobj->insn_id);
11845 int j;
11846
11847 for (j = 0; types[j]; j++) {
11848 char type = types[j];
11849
11850 switch (type) {
11851 case TS_OFFSET: /* label(destination position) */
11852 {
11853 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11854 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11855 break;
11856 }
11857 break;
11858 case TS_ISEQ: /* iseq */
11859 {
11860 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11861 VALUE val = Qnil;
11862 if (0 && iseq) { /* TODO: invalidate now */
11863 val = (VALUE)iseq;
11864 }
11865 rb_str_concat(str, opobj_inspect(val));
11866 }
11867 break;
11868 case TS_LINDEX:
11869 case TS_NUM: /* ulong */
11870 case TS_VALUE: /* VALUE */
11871 {
11872 VALUE v = OPERAND_AT(iobj, j);
11873 if (!CLASS_OF(v))
11874 rb_str_cat2(str, "<hidden>");
11875 else {
11876 rb_str_concat(str, opobj_inspect(v));
11877 }
11878 break;
11879 }
11880 case TS_ID: /* ID */
11881 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11882 break;
11883 case TS_IC: /* inline cache */
11884 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11885 break;
11886 case TS_IVC: /* inline ivar cache */
11887 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11888 break;
11889 case TS_ICVARC: /* inline cvar cache */
11890 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11891 break;
11892 case TS_ISE: /* inline storage entry */
11893 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11894 break;
11895 case TS_CALLDATA: /* we store these as call infos at compile time */
11896 {
11897 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11898 rb_str_cat2(str, "<calldata:");
11899 if (vm_ci_mid(ci)) rb_str_append(str, rb_id2str(vm_ci_mid(ci)));
11900 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11901 break;
11902 }
11903 case TS_CDHASH: /* case/when condition cache */
11904 rb_str_cat2(str, "<ch>");
11905 break;
11906 case TS_FUNCPTR:
11907 {
11908 void *func = (void *)OPERAND_AT(iobj, j);
11909#ifdef HAVE_DLADDR
11910 Dl_info info;
11911 if (dladdr(func, &info) && info.dli_sname) {
11912 rb_str_cat2(str, info.dli_sname);
11913 break;
11914 }
11915#endif
11916 rb_str_catf(str, "<%p>", func);
11917 }
11918 break;
11919 case TS_BUILTIN:
11920 rb_str_cat2(str, "<TS_BUILTIN>");
11921 break;
11922 default:{
11923 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11924 }
11925 }
11926 if (types[j + 1]) {
11927 rb_str_cat2(str, ", ");
11928 }
11929 }
11930 }
11931 return str;
11932}
11933
11934static void
11935dump_disasm_list(const LINK_ELEMENT *link)
11936{
11937 dump_disasm_list_with_cursor(link, NULL, NULL);
11938}
11939
11940static void
11941dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11942{
11943 int pos = 0;
11944 INSN *iobj;
11945 LABEL *lobj;
11946 VALUE str;
11947
11948 printf("-- raw disasm--------\n");
11949
11950 while (link) {
11951 if (curr) printf(curr == link ? "*" : " ");
11952 switch (link->type) {
11953 case ISEQ_ELEMENT_INSN:
11954 {
11955 iobj = (INSN *)link;
11956 str = insn_data_to_s_detail(iobj);
11957 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11958 pos += insn_data_length(iobj);
11959 break;
11960 }
11961 case ISEQ_ELEMENT_LABEL:
11962 {
11963 lobj = (LABEL *)link;
11964 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11965 dest == lobj ? " <---" : "");
11966 break;
11967 }
11968 case ISEQ_ELEMENT_TRACE:
11969 {
11970 TRACE *trace = (TRACE *)link;
11971 printf(" trace: %0x\n", trace->event);
11972 break;
11973 }
11974 case ISEQ_ELEMENT_ADJUST:
11975 {
11976 ADJUST *adjust = (ADJUST *)link;
11977 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11978 break;
11979 }
11980 default:
11981 /* ignore */
11982 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11983 }
11984 link = link->next;
11985 }
11986 printf("---------------------\n");
11987 fflush(stdout);
11988}
11989
11990int
11991rb_insn_len(VALUE insn)
11992{
11993 return insn_len(insn);
11994}
11995
11996const char *
11997rb_insns_name(int i)
11998{
11999 return insn_name(i);
12000}
12001
12002VALUE
12003rb_insns_name_array(void)
12004{
12005 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
12006 int i;
12007 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
12008 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
12009 }
12010 return rb_ary_freeze(ary);
12011}
12012
12013static LABEL *
12014register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
12015{
12016 LABEL *label = 0;
12017 st_data_t tmp;
12018 obj = rb_to_symbol_type(obj);
12019
12020 if (st_lookup(labels_table, obj, &tmp) == 0) {
12021 label = NEW_LABEL(0);
12022 st_insert(labels_table, obj, (st_data_t)label);
12023 }
12024 else {
12025 label = (LABEL *)tmp;
12026 }
12027 LABEL_REF(label);
12028 return label;
12029}
12030
12031static VALUE
12032get_exception_sym2type(VALUE sym)
12033{
12034 static VALUE symRescue, symEnsure, symRetry;
12035 static VALUE symBreak, symRedo, symNext;
12036
12037 if (symRescue == 0) {
12038 symRescue = ID2SYM(rb_intern_const("rescue"));
12039 symEnsure = ID2SYM(rb_intern_const("ensure"));
12040 symRetry = ID2SYM(rb_intern_const("retry"));
12041 symBreak = ID2SYM(rb_intern_const("break"));
12042 symRedo = ID2SYM(rb_intern_const("redo"));
12043 symNext = ID2SYM(rb_intern_const("next"));
12044 }
12045
12046 if (sym == symRescue) return CATCH_TYPE_RESCUE;
12047 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
12048 if (sym == symRetry) return CATCH_TYPE_RETRY;
12049 if (sym == symBreak) return CATCH_TYPE_BREAK;
12050 if (sym == symRedo) return CATCH_TYPE_REDO;
12051 if (sym == symNext) return CATCH_TYPE_NEXT;
12052 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
12053 return 0;
12054}
12055
12056static int
12057iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
12058 VALUE exception)
12059{
12060 int i;
12061
12062 for (i=0; i<RARRAY_LEN(exception); i++) {
12063 const rb_iseq_t *eiseq;
12064 VALUE v, type;
12065 LABEL *lstart, *lend, *lcont;
12066 unsigned int sp;
12067
12068 v = rb_to_array_type(RARRAY_AREF(exception, i));
12069 if (RARRAY_LEN(v) != 6) {
12070 rb_raise(rb_eSyntaxError, "wrong exception entry");
12071 }
12072 type = get_exception_sym2type(RARRAY_AREF(v, 0));
12073 if (NIL_P(RARRAY_AREF(v, 1))) {
12074 eiseq = NULL;
12075 }
12076 else {
12077 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
12078 }
12079
12080 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
12081 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
12082 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
12083 sp = NUM2UINT(RARRAY_AREF(v, 5));
12084
12085 /* TODO: Dirty Hack! Fix me */
12086 if (type == CATCH_TYPE_RESCUE ||
12087 type == CATCH_TYPE_BREAK ||
12088 type == CATCH_TYPE_NEXT) {
12089 ++sp;
12090 }
12091
12092 lcont->sp = sp;
12093
12094 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
12095
12096 RB_GC_GUARD(v);
12097 }
12098 return COMPILE_OK;
12099}
12100
12101static struct st_table *
12102insn_make_insn_table(void)
12103{
12104 struct st_table *table;
12105 int i;
12106 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
12107
12108 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
12109 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
12110 }
12111
12112 return table;
12113}
12114
12115static const rb_iseq_t *
12116iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
12117{
12118 VALUE iseqw;
12119 const rb_iseq_t *loaded_iseq;
12120
12121 if (RB_TYPE_P(op, T_ARRAY)) {
12122 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
12123 }
12124 else if (CLASS_OF(op) == rb_cISeq) {
12125 iseqw = op;
12126 }
12127 else {
12128 rb_raise(rb_eSyntaxError, "ISEQ is required");
12129 }
12130
12131 loaded_iseq = rb_iseqw_to_iseq(iseqw);
12132 return loaded_iseq;
12133}
12134
12135static VALUE
12136iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
12137{
12138 ID mid = 0;
12139 int orig_argc = 0;
12140 unsigned int flag = 0;
12141 struct rb_callinfo_kwarg *kw_arg = 0;
12142
12143 if (!NIL_P(op)) {
12144 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
12145 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
12146 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
12147 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
12148
12149 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
12150 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
12151 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
12152
12153 if (!NIL_P(vkw_arg)) {
12154 int i;
12155 int len = RARRAY_LENINT(vkw_arg);
12156 size_t n = rb_callinfo_kwarg_bytes(len);
12157
12158 kw_arg = xmalloc(n);
12159 kw_arg->references = 0;
12160 kw_arg->keyword_len = len;
12161 for (i = 0; i < len; i++) {
12162 VALUE kw = RARRAY_AREF(vkw_arg, i);
12163 SYM2ID(kw); /* make immortal */
12164 kw_arg->keywords[i] = kw;
12165 }
12166 }
12167 }
12168
12169 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12170 RB_OBJ_WRITTEN(iseq, Qundef, ci);
12171 return (VALUE)ci;
12172}
12173
12174static rb_event_flag_t
12175event_name_to_flag(VALUE sym)
12176{
12177#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12178 CHECK_EVENT(RUBY_EVENT_LINE);
12179 CHECK_EVENT(RUBY_EVENT_CLASS);
12180 CHECK_EVENT(RUBY_EVENT_END);
12181 CHECK_EVENT(RUBY_EVENT_CALL);
12182 CHECK_EVENT(RUBY_EVENT_RETURN);
12183 CHECK_EVENT(RUBY_EVENT_B_CALL);
12184 CHECK_EVENT(RUBY_EVENT_B_RETURN);
12185 CHECK_EVENT(RUBY_EVENT_RESCUE);
12186#undef CHECK_EVENT
12187 return RUBY_EVENT_NONE;
12188}
12189
12190static int
12191iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
12192 VALUE body, VALUE node_ids, VALUE labels_wrapper)
12193{
12194 /* TODO: body should be frozen */
12195 long i, len = RARRAY_LEN(body);
12196 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
12197 int j;
12198 int line_no = 0, node_id = -1, insn_idx = 0;
12199 int ret = COMPILE_OK;
12200
12201 /*
12202 * index -> LABEL *label
12203 */
12204 static struct st_table *insn_table;
12205
12206 if (insn_table == 0) {
12207 insn_table = insn_make_insn_table();
12208 }
12209
12210 for (i=0; i<len; i++) {
12211 VALUE obj = RARRAY_AREF(body, i);
12212
12213 if (SYMBOL_P(obj)) {
12214 rb_event_flag_t event;
12215 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
12216 ADD_TRACE(anchor, event);
12217 }
12218 else {
12219 LABEL *label = register_label(iseq, labels_table, obj);
12220 ADD_LABEL(anchor, label);
12221 }
12222 }
12223 else if (FIXNUM_P(obj)) {
12224 line_no = NUM2INT(obj);
12225 }
12226 else if (RB_TYPE_P(obj, T_ARRAY)) {
12227 VALUE *argv = 0;
12228 int argc = RARRAY_LENINT(obj) - 1;
12229 st_data_t insn_id;
12230 VALUE insn;
12231
12232 if (node_ids) {
12233 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
12234 }
12235
12236 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
12237 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12238 /* TODO: exception */
12239 COMPILE_ERROR(iseq, line_no,
12240 "unknown instruction: %+"PRIsVALUE, insn);
12241 ret = COMPILE_NG;
12242 break;
12243 }
12244
12245 if (argc != insn_len((VALUE)insn_id)-1) {
12246 COMPILE_ERROR(iseq, line_no,
12247 "operand size mismatch");
12248 ret = COMPILE_NG;
12249 break;
12250 }
12251
12252 if (argc > 0) {
12253 argv = compile_data_calloc2_type(iseq, VALUE, argc);
12254
12255 // add element before operand setup to make GC root
12256 ADD_ELEM(anchor,
12257 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12258 (enum ruby_vminsn_type)insn_id, argc, argv));
12259
12260 for (j=0; j<argc; j++) {
12261 VALUE op = rb_ary_entry(obj, j+1);
12262 switch (insn_op_type((VALUE)insn_id, j)) {
12263 case TS_OFFSET: {
12264 LABEL *label = register_label(iseq, labels_table, op);
12265 argv[j] = (VALUE)label;
12266 break;
12267 }
12268 case TS_LINDEX:
12269 case TS_NUM:
12270 (void)NUM2INT(op);
12271 argv[j] = op;
12272 break;
12273 case TS_VALUE:
12274 argv[j] = op;
12275 RB_OBJ_WRITTEN(iseq, Qundef, op);
12276 break;
12277 case TS_ISEQ:
12278 {
12279 if (op != Qnil) {
12280 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12281 argv[j] = v;
12282 RB_OBJ_WRITTEN(iseq, Qundef, v);
12283 }
12284 else {
12285 argv[j] = 0;
12286 }
12287 }
12288 break;
12289 case TS_ISE:
12290 argv[j] = op;
12291 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12292 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12293 }
12294 break;
12295 case TS_IC:
12296 {
12297 VALUE segments = rb_ary_new();
12298 op = rb_to_array_type(op);
12299
12300 for (int i = 0; i < RARRAY_LEN(op); i++) {
12301 VALUE sym = RARRAY_AREF(op, i);
12302 sym = rb_to_symbol_type(sym);
12303 rb_ary_push(segments, sym);
12304 }
12305
12306 RB_GC_GUARD(op);
12307 argv[j] = segments;
12308 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12309 ISEQ_BODY(iseq)->ic_size++;
12310 }
12311 break;
12312 case TS_IVC: /* inline ivar cache */
12313 argv[j] = op;
12314 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12315 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12316 }
12317 break;
12318 case TS_ICVARC: /* inline cvar cache */
12319 argv[j] = op;
12320 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12321 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12322 }
12323 break;
12324 case TS_CALLDATA:
12325 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12326 break;
12327 case TS_ID:
12328 argv[j] = rb_to_symbol_type(op);
12329 break;
12330 case TS_CDHASH:
12331 {
12332 int i;
12333 VALUE map = cdhash_new(RARRAY_LEN(op) / 2);
12334
12335 op = rb_to_array_type(op);
12336 for (i=0; i<RARRAY_LEN(op); i+=2) {
12337 VALUE key = RARRAY_AREF(op, i);
12338 VALUE sym = RARRAY_AREF(op, i+1);
12339 LABEL *label =
12340 register_label(iseq, labels_table, sym);
12341 cdhash_aset(map, key, (VALUE)label);
12342 }
12343 RB_GC_GUARD(op);
12344 RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
12345 argv[j] = map;
12346 RB_OBJ_WRITTEN(iseq, Qundef, map);
12347 }
12348 break;
12349 case TS_FUNCPTR:
12350 {
12351#if SIZEOF_VALUE <= SIZEOF_LONG
12352 long funcptr = NUM2LONG(op);
12353#else
12354 LONG_LONG funcptr = NUM2LL(op);
12355#endif
12356 argv[j] = (VALUE)funcptr;
12357 }
12358 break;
12359 default:
12360 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12361 }
12362 }
12363 }
12364 else {
12365 ADD_ELEM(anchor,
12366 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12367 (enum ruby_vminsn_type)insn_id, argc, NULL));
12368 }
12369 }
12370 else {
12371 rb_raise(rb_eTypeError, "unexpected object for instruction");
12372 }
12373 }
12374 RTYPEDDATA_DATA(labels_wrapper) = 0;
12375 RB_GC_GUARD(labels_wrapper);
12376 validate_labels(iseq, labels_table);
12377 if (!ret) return ret;
12378 return iseq_setup(iseq, anchor);
12379}
12380
12381#define CHECK_ARRAY(v) rb_to_array_type(v)
12382#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12383
12384static int
12385int_param(int *dst, VALUE param, VALUE sym)
12386{
12387 VALUE val = rb_hash_aref(param, sym);
12388 if (FIXNUM_P(val)) {
12389 *dst = FIX2INT(val);
12390 return TRUE;
12391 }
12392 else if (!NIL_P(val)) {
12393 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12394 sym, val);
12395 }
12396 return FALSE;
12397}
12398
12399static const struct rb_iseq_param_keyword *
12400iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12401{
12402 int i, j;
12403 int len = RARRAY_LENINT(keywords);
12404 int default_len;
12405 VALUE key, sym, default_val;
12406 VALUE *dvs;
12407 ID *ids;
12408 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12409
12410 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12411
12412 keyword->num = len;
12413#define SYM(s) ID2SYM(rb_intern_const(#s))
12414 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12415 i = keyword->bits_start - keyword->num;
12416 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12417#undef SYM
12418
12419 /* required args */
12420 for (i = 0; i < len; i++) {
12421 VALUE val = RARRAY_AREF(keywords, i);
12422
12423 if (!SYMBOL_P(val)) {
12424 goto default_values;
12425 }
12426 ids[i] = SYM2ID(val);
12427 keyword->required_num++;
12428 }
12429
12430 default_values: /* note: we intentionally preserve `i' from previous loop */
12431 default_len = len - i;
12432 if (default_len == 0) {
12433 keyword->table = ids;
12434 return keyword;
12435 }
12436 else if (default_len < 0) {
12438 }
12439
12440 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12441
12442 for (j = 0; i < len; i++, j++) {
12443 key = RARRAY_AREF(keywords, i);
12444 CHECK_ARRAY(key);
12445
12446 switch (RARRAY_LEN(key)) {
12447 case 1:
12448 sym = RARRAY_AREF(key, 0);
12449 default_val = Qundef;
12450 break;
12451 case 2:
12452 sym = RARRAY_AREF(key, 0);
12453 default_val = RARRAY_AREF(key, 1);
12454 break;
12455 default:
12456 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12457 }
12458 ids[i] = SYM2ID(sym);
12459 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12460 }
12461
12462 keyword->table = ids;
12463 keyword->default_values = dvs;
12464
12465 return keyword;
12466}
12467
12468static void
12469iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12470{
12471 rb_gc_mark_and_move(obj);
12472}
12473
12474void
12475rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12476{
12477 INSN *iobj = 0;
12478 size_t size = sizeof(INSN);
12479 size_t align = ALIGNMENT_SIZE_OF(INSN);
12480 unsigned int pos = 0;
12481
12482 while (storage) {
12483 size_t padding = calc_padding((void *)&storage->buff[pos], align);
12484 size_t offset = pos + size + padding;
12485 if (offset > storage->size || offset > storage->pos) {
12486 pos = 0;
12487 storage = storage->next;
12488 }
12489 else {
12490 pos += (int)padding;
12491
12492 iobj = (INSN *)&storage->buff[pos];
12493
12494 if (iobj->operands) {
12495 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12496 }
12497 pos += (int)size;
12498 }
12499 }
12500}
12501
12502static const rb_data_type_t labels_wrapper_type = {
12503 .wrap_struct_name = "compiler/labels_wrapper",
12504 .function = {
12505 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12506 .dfree = (RUBY_DATA_FUNC)st_free_table,
12507 },
12508 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED,
12509};
12510
12511void
12512rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12513 VALUE exception, VALUE body)
12514{
12515#define SYM(s) ID2SYM(rb_intern_const(#s))
12516 int i, len;
12517 unsigned int arg_size, local_size, stack_max;
12518 ID *tbl;
12519 struct st_table *labels_table = st_init_numtable();
12520 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12521 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12522 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12523 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12524 DECL_ANCHOR(anchor);
12525 INIT_ANCHOR(anchor);
12526
12527 len = RARRAY_LENINT(locals);
12528 ISEQ_BODY(iseq)->local_table_size = len;
12529 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12530
12531 for (i = 0; i < len; i++) {
12532 VALUE lv = RARRAY_AREF(locals, i);
12533
12534 if (sym_arg_rest == lv) {
12535 tbl[i] = 0;
12536 }
12537 else {
12538 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12539 }
12540 }
12541
12542#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12543 if (INT_PARAM(lead_num)) {
12544 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12545 }
12546 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12547 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12548 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12549 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12550#undef INT_PARAM
12551 {
12552#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12553 int x;
12554 INT_PARAM(arg_size);
12555 INT_PARAM(local_size);
12556 INT_PARAM(stack_max);
12557#undef INT_PARAM
12558 }
12559
12560 VALUE source_hash = rb_hash_aref(misc, ID2SYM(rb_intern("source_hash")));
12561 if (!NIL_P(source_hash)) {
12562 ISEQ_BODY(iseq)->source_hash = NUM2ULL(source_hash);
12563 }
12564
12565 VALUE node_ids = Qfalse;
12566#ifdef USE_ISEQ_NODE_ID
12567 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12568 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12569 rb_raise(rb_eTypeError, "node_ids is not an array");
12570 }
12571#endif
12572
12573 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12574 len = RARRAY_LENINT(arg_opt_labels);
12575 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12576
12577 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12578 VALUE *opt_table = ALLOC_N(VALUE, len);
12579
12580 for (i = 0; i < len; i++) {
12581 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12582 LABEL *label = register_label(iseq, labels_table, ent);
12583 opt_table[i] = (VALUE)label;
12584 }
12585
12586 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12587 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12588 }
12589 }
12590 else if (!NIL_P(arg_opt_labels)) {
12591 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12592 arg_opt_labels);
12593 }
12594
12595 if (RB_TYPE_P(keywords, T_ARRAY)) {
12596 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12597 }
12598 else if (!NIL_P(keywords)) {
12599 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12600 keywords);
12601 }
12602
12603 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12604 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12605 }
12606
12607 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12608 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12609 }
12610
12611 if (int_param(&i, params, SYM(kwrest))) {
12612 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12613 if (keyword == NULL) {
12614 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12615 }
12616 keyword->rest_start = i;
12617 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12618 }
12619#undef SYM
12620 iseq_calc_param_size(iseq);
12621
12622 /* exception */
12623 iseq_build_from_ary_exception(iseq, labels_table, exception);
12624
12625 /* body */
12626 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12627
12628 ISEQ_BODY(iseq)->param.size = arg_size;
12629 ISEQ_BODY(iseq)->local_table_size = local_size;
12630 ISEQ_BODY(iseq)->stack_max = stack_max;
12631}
12632
12633/* for parser */
12634
12635int
12636rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12637{
12638 if (iseq) {
12639 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12640 while (body->type == ISEQ_TYPE_BLOCK ||
12641 body->type == ISEQ_TYPE_RESCUE ||
12642 body->type == ISEQ_TYPE_ENSURE ||
12643 body->type == ISEQ_TYPE_EVAL ||
12644 body->type == ISEQ_TYPE_MAIN
12645 ) {
12646 unsigned int i;
12647
12648 for (i = 0; i < body->local_table_size; i++) {
12649 if (body->local_table[i] == id) {
12650 return 1;
12651 }
12652 }
12653 iseq = body->parent_iseq;
12654 body = ISEQ_BODY(iseq);
12655 }
12656 }
12657 return 0;
12658}
12659
12660int
12661rb_local_defined(ID id, const rb_iseq_t *iseq)
12662{
12663 if (iseq) {
12664 unsigned int i;
12665 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12666
12667 for (i=0; i<body->local_table_size; i++) {
12668 if (body->local_table[i] == id) {
12669 return 1;
12670 }
12671 }
12672 }
12673 return 0;
12674}
12675
12676/* ISeq binary format */
12677
12678#ifndef IBF_ISEQ_DEBUG
12679#define IBF_ISEQ_DEBUG 0
12680#endif
12681
12682#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12683#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12684#endif
12685
12686typedef uint32_t ibf_offset_t;
12687#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12688
12689#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12690#ifdef RUBY_DEVEL
12691#define IBF_DEVEL_VERSION 8
12692#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12693#else
12694#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12695#endif
12696
12697static const char IBF_ENDIAN_MARK =
12698#ifdef WORDS_BIGENDIAN
12699 'b'
12700#else
12701 'l'
12702#endif
12703 ;
12704
12706 char magic[4]; /* YARB */
12707 uint32_t major_version;
12708 uint32_t minor_version;
12709 uint32_t size;
12710 uint32_t extra_size;
12711
12712 uint32_t iseq_list_size;
12713 uint32_t global_object_list_size;
12714 ibf_offset_t iseq_list_offset;
12715 ibf_offset_t global_object_list_offset;
12716 uint8_t endian;
12717 uint8_t wordsize; /* assume no 2048-bit CPU */
12718};
12719
12721 VALUE str;
12722 st_table *obj_table; /* obj -> obj number */
12723};
12724
12725struct ibf_dump {
12726 st_table *iseq_table; /* iseq -> iseq number */
12727 struct ibf_dump_buffer global_buffer;
12728 struct ibf_dump_buffer *current_buffer;
12729};
12730
12732 const char *buff;
12733 ibf_offset_t size;
12734
12735 VALUE obj_list; /* [obj0, ...] */
12736 unsigned int obj_list_size;
12737 ibf_offset_t obj_list_offset;
12738};
12739
12740struct ibf_load {
12741 const struct ibf_header *header;
12742 VALUE iseq_list; /* [iseq0, ...] */
12743 struct ibf_load_buffer global_buffer;
12744 VALUE loader_obj;
12745 rb_iseq_t *iseq;
12746 VALUE str;
12747 struct ibf_load_buffer *current_buffer;
12748};
12749
12751 long size;
12752 VALUE buffer[1];
12753};
12754
12755static void
12756pinned_list_mark(void *ptr)
12757{
12758 long i;
12759 struct pinned_list *list = (struct pinned_list *)ptr;
12760 for (i = 0; i < list->size; i++) {
12761 if (list->buffer[i]) {
12762 rb_gc_mark(list->buffer[i]);
12763 }
12764 }
12765}
12766
12767static const rb_data_type_t pinned_list_type = {
12768 "pinned_list",
12769 {
12770 pinned_list_mark,
12772 NULL, // No external memory to report,
12773 },
12774 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
12775};
12776
12777static VALUE
12778pinned_list_fetch(VALUE list, long offset)
12779{
12780 struct pinned_list * ptr;
12781
12782 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12783
12784 if (offset < 0 || offset >= ptr->size) {
12785 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12786 }
12787
12788 return ptr->buffer[offset];
12789}
12790
12791static void
12792pinned_list_store(VALUE list, long offset, VALUE object)
12793{
12794 struct pinned_list * ptr;
12795
12796 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12797
12798 if (offset < 0 || offset >= ptr->size) {
12799 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12800 }
12801
12802 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12803}
12804
12805static VALUE
12806pinned_list_new(long size)
12807{
12808 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12809 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12810 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12811 ptr->size = size;
12812 return obj_list;
12813}
12814
12815static ibf_offset_t
12816ibf_dump_pos(struct ibf_dump *dump)
12817{
12818 long pos = RSTRING_LEN(dump->current_buffer->str);
12819#if SIZEOF_LONG > SIZEOF_INT
12820 if (pos >= UINT_MAX) {
12821 rb_raise(rb_eRuntimeError, "dump size exceeds");
12822 }
12823#endif
12824 return (unsigned int)pos;
12825}
12826
12827static void
12828ibf_dump_align(struct ibf_dump *dump, size_t align)
12829{
12830 ibf_offset_t pos = ibf_dump_pos(dump);
12831 if (pos % align) {
12832 static const char padding[sizeof(VALUE)];
12833 size_t size = align - ((size_t)pos % align);
12834#if SIZEOF_LONG > SIZEOF_INT
12835 if (pos + size >= UINT_MAX) {
12836 rb_raise(rb_eRuntimeError, "dump size exceeds");
12837 }
12838#endif
12839 for (; size > sizeof(padding); size -= sizeof(padding)) {
12840 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12841 }
12842 rb_str_cat(dump->current_buffer->str, padding, size);
12843 }
12844}
12845
12846static ibf_offset_t
12847ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12848{
12849 ibf_offset_t pos = ibf_dump_pos(dump);
12850#if SIZEOF_LONG > SIZEOF_INT
12851 /* ensure the resulting dump does not exceed UINT_MAX */
12852 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12853 rb_raise(rb_eRuntimeError, "dump size exceeds");
12854 }
12855#endif
12856 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12857 return pos;
12858}
12859
12860static ibf_offset_t
12861ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12862{
12863 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12864}
12865
12866static void
12867ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12868{
12869 VALUE str = dump->current_buffer->str;
12870 char *ptr = RSTRING_PTR(str);
12871 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12872 rb_bug("ibf_dump_overwrite: overflow");
12873 memcpy(ptr + offset, buff, size);
12874}
12875
12876static const void *
12877ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12878{
12879 ibf_offset_t beg = *offset;
12880 *offset += size;
12881 return load->current_buffer->buff + beg;
12882}
12883
12884static void *
12885ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12886{
12887 void *buff = ruby_xmalloc2(x, y);
12888 size_t size = x * y;
12889 memcpy(buff, load->current_buffer->buff + offset, size);
12890 return buff;
12891}
12892
12893#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12894
12895#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12896#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12897#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12898#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12899#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12900
12901static int
12902ibf_table_lookup(struct st_table *table, st_data_t key)
12903{
12904 st_data_t val;
12905
12906 if (st_lookup(table, key, &val)) {
12907 return (int)val;
12908 }
12909 else {
12910 return -1;
12911 }
12912}
12913
12914static int
12915ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12916{
12917 int index = ibf_table_lookup(table, key);
12918
12919 if (index < 0) { /* not found */
12920 index = (int)table->num_entries;
12921 st_insert(table, key, (st_data_t)index);
12922 }
12923
12924 return index;
12925}
12926
12927/* dump/load generic */
12928
12929static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12930
12931static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12932static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12933
12934static st_table *
12935ibf_dump_object_table_new(void)
12936{
12937 st_table *obj_table = st_init_numtable(); /* need free */
12938 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12939
12940 return obj_table;
12941}
12942
12943static VALUE
12944ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12945{
12946 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12947}
12948
12949static VALUE
12950ibf_dump_id(struct ibf_dump *dump, ID id)
12951{
12952 if (id == 0 || rb_id2name(id) == NULL) {
12953 return 0;
12954 }
12955 return ibf_dump_object(dump, rb_id2sym(id));
12956}
12957
12958static ID
12959ibf_load_id(const struct ibf_load *load, const ID id_index)
12960{
12961 if (id_index == 0) {
12962 return 0;
12963 }
12964 VALUE sym = ibf_load_object(load, id_index);
12965 if (rb_integer_type_p(sym)) {
12966 /* Load hidden local variables as indexes */
12967 return NUM2ULONG(sym);
12968 }
12969 return rb_sym2id(sym);
12970}
12971
12972/* dump/load: code */
12973
12974static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12975
12976static int
12977ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12978{
12979 if (iseq == NULL) {
12980 return -1;
12981 }
12982 else {
12983 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12984 }
12985}
12986
12987static unsigned char
12988ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12989{
12990 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12991 return (unsigned char)load->current_buffer->buff[(*offset)++];
12992}
12993
12994/*
12995 * Small uint serialization
12996 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12997 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12998 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12999 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13000 * ...
13001 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13002 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
13003 */
13004static void
13005ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
13006{
13007 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13008 ibf_dump_write(dump, &x, sizeof(VALUE));
13009 return;
13010 }
13011
13012 enum { max_byte_length = sizeof(VALUE) + 1 };
13013
13014 unsigned char bytes[max_byte_length];
13015 ibf_offset_t n;
13016
13017 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
13018 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13019 }
13020
13021 x <<= 1;
13022 x |= 1;
13023 x <<= n;
13024 bytes[max_byte_length - 1 - n] = (unsigned char)x;
13025 n++;
13026
13027 ibf_dump_write(dump, bytes + max_byte_length - n, n);
13028}
13029
13030static VALUE
13031ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
13032{
13033 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
13034 union { char s[sizeof(VALUE)]; VALUE v; } x;
13035
13036 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
13037 *offset += sizeof(VALUE);
13038
13039 return x.v;
13040 }
13041
13042 enum { max_byte_length = sizeof(VALUE) + 1 };
13043
13044 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
13045 const unsigned char c = buffer[*offset];
13046
13047 ibf_offset_t n =
13048 c & 1 ? 1 :
13049 c == 0 ? 9 : ntz_int32(c) + 1;
13050 VALUE x = (VALUE)c >> n;
13051
13052 if (*offset + n > load->current_buffer->size) {
13053 rb_raise(rb_eRuntimeError, "invalid byte sequence");
13054 }
13055
13056 ibf_offset_t i;
13057 for (i = 1; i < n; i++) {
13058 x <<= 8;
13059 x |= (VALUE)buffer[*offset + i];
13060 }
13061
13062 *offset += n;
13063 return x;
13064}
13065
13066static void
13067ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
13068{
13069 // short: index
13070 // short: name.length
13071 // bytes: name
13072 // // omit argc (only verify with name)
13073 ibf_dump_write_small_value(dump, (VALUE)bf->index);
13074
13075 size_t len = strlen(bf->name);
13076 ibf_dump_write_small_value(dump, (VALUE)len);
13077 ibf_dump_write(dump, bf->name, len);
13078}
13079
13080static const struct rb_builtin_function *
13081ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
13082{
13083 int i = (int)ibf_load_small_value(load, offset);
13084 int len = (int)ibf_load_small_value(load, offset);
13085 const char *name = (char *)ibf_load_ptr(load, offset, len);
13086
13087 if (0) {
13088 fprintf(stderr, "%.*s!!\n", len, name);
13089 }
13090
13091 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
13092 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
13093 if (strncmp(table[i].name, name, len) != 0) {
13094 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %.*s but %s)",
13095 i, len, name, table[i].name);
13096 }
13097 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
13098
13099 return &table[i];
13100}
13101
13102static ibf_offset_t
13103ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
13104{
13105 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13106 const int iseq_size = body->iseq_size;
13107 int code_index;
13108 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
13109
13110 ibf_offset_t offset = ibf_dump_pos(dump);
13111
13112 for (code_index=0; code_index<iseq_size;) {
13113 const VALUE insn = orig_code[code_index++];
13114 const char *types = insn_op_types(insn);
13115 int op_index;
13116
13117 /* opcode */
13118 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
13119 ibf_dump_write_small_value(dump, insn);
13120
13121 /* operands */
13122 for (op_index=0; types[op_index]; op_index++, code_index++) {
13123 VALUE op = orig_code[code_index];
13124 VALUE wv;
13125
13126 switch (types[op_index]) {
13127 case TS_CDHASH:
13128 case TS_VALUE:
13129 wv = ibf_dump_object(dump, op);
13130 break;
13131 case TS_ISEQ:
13132 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
13133 break;
13134 case TS_IC:
13135 {
13136 IC ic = (IC)op;
13137 VALUE arr = idlist_to_array(ic->segments);
13138 wv = ibf_dump_object(dump, arr);
13139 }
13140 break;
13141 case TS_ISE:
13142 case TS_IVC:
13143 case TS_ICVARC:
13144 {
13146 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
13147 }
13148 break;
13149 case TS_CALLDATA:
13150 {
13151 goto skip_wv;
13152 }
13153 case TS_ID:
13154 wv = ibf_dump_id(dump, (ID)op);
13155 break;
13156 case TS_FUNCPTR:
13157 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13158 goto skip_wv;
13159 case TS_BUILTIN:
13160 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
13161 goto skip_wv;
13162 default:
13163 wv = op;
13164 break;
13165 }
13166 ibf_dump_write_small_value(dump, wv);
13167 skip_wv:;
13168 }
13169 RUBY_ASSERT(insn_len(insn) == op_index+1);
13170 }
13171
13172 return offset;
13173}
13174
13175static VALUE *
13176ibf_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)
13177{
13178 VALUE iseqv = (VALUE)iseq;
13179 unsigned int code_index;
13180 ibf_offset_t reading_pos = bytecode_offset;
13181 VALUE *code = ZALLOC_N(VALUE, iseq_size);
13182
13183 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
13184 struct rb_call_data *cd_entries = load_body->call_data;
13185 int ic_index = 0;
13186
13187 load_body->iseq_encoded = code;
13188 load_body->iseq_size = iseq_size;
13189
13190 iseq_bits_t * mark_offset_bits;
13191 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13192 load_body->mark_bits.single = 0;
13193 mark_offset_bits = &load_body->mark_bits.single;
13194 }
13195 else {
13196 load_body->mark_bits.list = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13197 mark_offset_bits = load_body->mark_bits.list;
13198 }
13199 bool needs_bitmap = false;
13200
13201 for (code_index=0; code_index<iseq_size;) {
13202 /* opcode */
13203 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13204 const char *types = insn_op_types(insn);
13205 int op_index;
13206
13207 code_index++;
13208
13209 /* operands */
13210 for (op_index=0; types[op_index]; op_index++, code_index++) {
13211 const char operand_type = types[op_index];
13212 switch (operand_type) {
13213 case TS_VALUE:
13214 {
13215 VALUE op = ibf_load_small_value(load, &reading_pos);
13216 VALUE v = ibf_load_object(load, op);
13217 code[code_index] = v;
13218 if (!SPECIAL_CONST_P(v)) {
13219 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13220 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13221 needs_bitmap = true;
13222 }
13223 break;
13224 }
13225 case TS_CDHASH:
13226 {
13227 VALUE op = ibf_load_small_value(load, &reading_pos);
13228 VALUE v = ibf_load_object(load, op);
13229
13230 // Overwrite the existing hash in the object list. This
13231 // is to keep the object alive during load time.
13232 // [Bug #17984] [ruby-core:104259]
13233 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
13234
13235 code[code_index] = v;
13236 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13237 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13238 needs_bitmap = true;
13239 break;
13240 }
13241 case TS_ISEQ:
13242 {
13243 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
13244 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
13245 code[code_index] = v;
13246 if (!SPECIAL_CONST_P(v)) {
13247 RB_OBJ_WRITTEN(iseqv, Qundef, v);
13248 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13249 needs_bitmap = true;
13250 }
13251 break;
13252 }
13253 case TS_IC:
13254 {
13255 VALUE op = ibf_load_small_value(load, &reading_pos);
13256 VALUE arr = ibf_load_object(load, op);
13257
13258 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13259 ic->segments = array_to_idlist(arr);
13260
13261 code[code_index] = (VALUE)ic;
13262 }
13263 break;
13264 case TS_ISE:
13265 case TS_ICVARC:
13266 case TS_IVC:
13267 {
13268 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13269
13270 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13271 code[code_index] = (VALUE)ic;
13272
13273 if (operand_type == TS_IVC) {
13274 IVC cache = (IVC)ic;
13275
13276 if (insn == BIN(setinstancevariable)) {
13277 ID iv_name = (ID)code[code_index - 1];
13278 cache->iv_set_name = iv_name;
13279 cache->value = IVAR_CACHE_INIT;
13280 }
13281 else {
13282 cache->iv_set_name = 0;
13283 cache->value = rb_getivar_cache_pack(ROOT_SHAPE_ID, ATTR_INDEX_NOT_SET);
13284 }
13285 }
13286
13287 }
13288 break;
13289 case TS_CALLDATA:
13290 {
13291 code[code_index] = (VALUE)cd_entries++;
13292 }
13293 break;
13294 case TS_ID:
13295 {
13296 VALUE op = ibf_load_small_value(load, &reading_pos);
13297 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13298 }
13299 break;
13300 case TS_FUNCPTR:
13301 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13302 break;
13303 case TS_BUILTIN:
13304 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13305 break;
13306 default:
13307 code[code_index] = ibf_load_small_value(load, &reading_pos);
13308 continue;
13309 }
13310 }
13311 if (insn_len(insn) != op_index+1) {
13312 rb_raise(rb_eRuntimeError, "operand size mismatch");
13313 }
13314 }
13315
13316 if (!needs_bitmap) {
13317 SIZED_FREE_N(load_body->mark_bits.list, ISEQ_MBITS_BUFLEN(iseq_size));
13318 load_body->mark_bits.list = NULL;
13319 }
13320
13321 RUBY_ASSERT(code_index == iseq_size);
13322 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13323 return code;
13324}
13325
13326static ibf_offset_t
13327ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13328{
13329 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13330
13331 if (opt_num > 0) {
13332 IBF_W_ALIGN(VALUE);
13333 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13334 }
13335 else {
13336 return ibf_dump_pos(dump);
13337 }
13338}
13339
13340static VALUE *
13341ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13342{
13343 if (opt_num > 0) {
13344 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13345 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13346 return table;
13347 }
13348 else {
13349 return NULL;
13350 }
13351}
13352
13353static ibf_offset_t
13354ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13355{
13356 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13357
13358 if (kw) {
13359 struct rb_iseq_param_keyword dump_kw = *kw;
13360 int dv_num = kw->num - kw->required_num;
13361 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13362 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13363 int i;
13364
13365 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13366 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13367
13368 dump_kw.table = IBF_W(ids, ID, kw->num);
13369 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13370 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13371 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13372 }
13373 else {
13374 return 0;
13375 }
13376}
13377
13378static const struct rb_iseq_param_keyword *
13379ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13380{
13381 if (param_keyword_offset) {
13382 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13383 int dv_num = kw->num - kw->required_num;
13384 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13385
13386 int i;
13387 for (i=0; i<dv_num; i++) {
13388 dvs[i] = ibf_load_object(load, dvs[i]);
13389 }
13390
13391 // Will be set once the local table is loaded.
13392 kw->table = NULL;
13393
13394 kw->default_values = dvs;
13395 return kw;
13396 }
13397 else {
13398 return NULL;
13399 }
13400}
13401
13402static ibf_offset_t
13403ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13404{
13405 ibf_offset_t offset = ibf_dump_pos(dump);
13406 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13407
13408 unsigned int i;
13409 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13410 ibf_dump_write_small_value(dump, entries[i].line_no);
13411#ifdef USE_ISEQ_NODE_ID
13412 ibf_dump_write_small_value(dump, entries[i].node_id);
13413#endif
13414 ibf_dump_write_small_value(dump, entries[i].events);
13415 }
13416
13417 return offset;
13418}
13419
13420static struct iseq_insn_info_entry *
13421ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13422{
13423 ibf_offset_t reading_pos = body_offset;
13424 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13425
13426 unsigned int i;
13427 for (i = 0; i < size; i++) {
13428 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13429#ifdef USE_ISEQ_NODE_ID
13430 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13431#endif
13432 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13433 }
13434
13435 return entries;
13436}
13437
13438static ibf_offset_t
13439ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13440{
13441 ibf_offset_t offset = ibf_dump_pos(dump);
13442
13443 unsigned int last = 0;
13444 unsigned int i;
13445 for (i = 0; i < size; i++) {
13446 ibf_dump_write_small_value(dump, positions[i] - last);
13447 last = positions[i];
13448 }
13449
13450 return offset;
13451}
13452
13453static unsigned int *
13454ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13455{
13456 ibf_offset_t reading_pos = positions_offset;
13457 unsigned int *positions = ALLOC_N(unsigned int, size);
13458
13459 unsigned int last = 0;
13460 unsigned int i;
13461 for (i = 0; i < size; i++) {
13462 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13463 last = positions[i];
13464 }
13465
13466 return positions;
13467}
13468
13469static ibf_offset_t
13470ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13471{
13472 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13473 const int size = body->local_table_size;
13474 ID *table = ALLOCA_N(ID, size);
13475 int i;
13476
13477 for (i=0; i<size; i++) {
13478 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13479 if (v == 0) {
13480 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13481 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13482 }
13483 table[i] = v;
13484 }
13485
13486 IBF_W_ALIGN(ID);
13487 return ibf_dump_write(dump, table, sizeof(ID) * size);
13488}
13489
13490static const ID *
13491ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13492{
13493 if (size > 0) {
13494 ID *table = IBF_R(local_table_offset, ID, size);
13495 int i;
13496
13497 for (i=0; i<size; i++) {
13498 table[i] = ibf_load_id(load, table[i]);
13499 }
13500
13501 if (size == 1 && table[0] == idERROR_INFO) {
13502 ruby_xfree_sized(table, sizeof(ID) * size);
13503 return rb_iseq_shared_exc_local_tbl;
13504 }
13505 else {
13506 return table;
13507 }
13508 }
13509 else {
13510 return NULL;
13511 }
13512}
13513
13514static ibf_offset_t
13515ibf_dump_lvar_states(struct ibf_dump *dump, const rb_iseq_t *iseq)
13516{
13517 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13518 const int size = ISEQ_LVAR_STATES_BUFLEN(body->local_table_size);
13519 IBF_W_ALIGN(uint8_t);
13520 if (iseq_has_lvar_states_p(body)) {
13521 return ibf_dump_write(dump, iseq_lvar_states(body), sizeof(uint8_t) * size);
13522 }
13523 else {
13524 return ibf_dump_write(dump, NULL, 0);
13525 }
13526}
13527
13528static void
13529ibf_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)
13530{
13531 if (local_table == rb_iseq_shared_exc_local_tbl ||
13532 size <= 0) {
13533 load_body->lvar_states.list = NULL;
13534 }
13535 else if (ISEQ_LVAR_STATES_EMBED_P((unsigned int)size)) {
13536 ibf_offset_t pos = lvar_states_offset;
13537 const int len = sizeof(uint8_t) * ISEQ_LVAR_STATES_BUFLEN(size);
13538 memcpy(load_body->lvar_states.single, ibf_load_ptr(load, &pos, len), len);
13539 }
13540 else {
13541 load_body->lvar_states.list = IBF_R(lvar_states_offset, uint8_t, ISEQ_LVAR_STATES_BUFLEN(size));
13542 }
13543}
13544
13545static ibf_offset_t
13546ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13547{
13548 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13549
13550 if (table) {
13551 int *iseq_indices = ALLOCA_N(int, table->size);
13552 unsigned int i;
13553
13554 for (i=0; i<table->size; i++) {
13555 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13556 }
13557
13558 const ibf_offset_t offset = ibf_dump_pos(dump);
13559
13560 for (i=0; i<table->size; i++) {
13561 ibf_dump_write_small_value(dump, iseq_indices[i]);
13562 ibf_dump_write_small_value(dump, table->entries[i].type);
13563 ibf_dump_write_small_value(dump, table->entries[i].start);
13564 ibf_dump_write_small_value(dump, table->entries[i].end);
13565 ibf_dump_write_small_value(dump, table->entries[i].cont);
13566 ibf_dump_write_small_value(dump, table->entries[i].sp);
13567 }
13568 return offset;
13569 }
13570 else {
13571 return ibf_dump_pos(dump);
13572 }
13573}
13574
13575static void
13576ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13577{
13578 if (size) {
13579 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13580 table->size = size;
13581 ISEQ_BODY(parent_iseq)->catch_table = table;
13582
13583 ibf_offset_t reading_pos = catch_table_offset;
13584
13585 unsigned int i;
13586 for (i=0; i<table->size; i++) {
13587 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13588 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13589 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13590 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13591 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13592 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13593
13594 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13595 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13596 }
13597 }
13598 else {
13599 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13600 }
13601}
13602
13603static ibf_offset_t
13604ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13605{
13606 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13607 const unsigned int ci_size = body->ci_size;
13608 const struct rb_call_data *cds = body->call_data;
13609
13610 ibf_offset_t offset = ibf_dump_pos(dump);
13611
13612 unsigned int i;
13613
13614 for (i = 0; i < ci_size; i++) {
13615 const struct rb_callinfo *ci = cds[i].ci;
13616 if (ci != NULL) {
13617 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13618 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13619 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13620
13621 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13622 if (kwarg) {
13623 int len = kwarg->keyword_len;
13624 ibf_dump_write_small_value(dump, len);
13625 for (int j=0; j<len; j++) {
13626 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13627 ibf_dump_write_small_value(dump, keyword);
13628 }
13629 }
13630 else {
13631 ibf_dump_write_small_value(dump, 0);
13632 }
13633 }
13634 else {
13635 // TODO: truncate NULL ci from call_data.
13636 ibf_dump_write_small_value(dump, (VALUE)-1);
13637 }
13638 }
13639
13640 return offset;
13641}
13642
13644 ID id;
13645 VALUE name;
13646 VALUE val;
13647};
13648
13650 size_t num;
13651 struct outer_variable_pair pairs[1];
13652};
13653
13654static enum rb_id_table_iterator_result
13655store_outer_variable(ID id, VALUE val, void *dump)
13656{
13657 struct outer_variable_list *ovlist = dump;
13658 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13659 pair->id = id;
13660 pair->name = rb_id2str(id);
13661 pair->val = val;
13662 return ID_TABLE_CONTINUE;
13663}
13664
13665static int
13666outer_variable_cmp(const void *a, const void *b, void *arg)
13667{
13668 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13669 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13670
13671 if (!ap->name) {
13672 return -1;
13673 }
13674 else if (!bp->name) {
13675 return 1;
13676 }
13677
13678 return rb_str_cmp(ap->name, bp->name);
13679}
13680
13681static ibf_offset_t
13682ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13683{
13684 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13685
13686 ibf_offset_t offset = ibf_dump_pos(dump);
13687
13688 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13689 ibf_dump_write_small_value(dump, (VALUE)size);
13690 if (size > 0) {
13691 VALUE buff;
13692 size_t buffsize =
13693 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13694 offsetof(struct outer_variable_list, pairs),
13695 rb_eArgError);
13696 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13697 ovlist->num = 0;
13698 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13699 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13700 for (size_t i = 0; i < size; ++i) {
13701 ID id = ovlist->pairs[i].id;
13702 ID val = ovlist->pairs[i].val;
13703 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13704 ibf_dump_write_small_value(dump, val);
13705 }
13706 }
13707
13708 return offset;
13709}
13710
13711/* note that we dump out rb_call_info but load back rb_call_data */
13712static void
13713ibf_load_ci_entries(const struct ibf_load *load,
13714 ibf_offset_t ci_entries_offset,
13715 unsigned int ci_size,
13716 struct rb_call_data **cd_ptr)
13717{
13718 if (!ci_size) {
13719 *cd_ptr = NULL;
13720 return;
13721 }
13722
13723 ibf_offset_t reading_pos = ci_entries_offset;
13724
13725 unsigned int i;
13726
13727 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13728 *cd_ptr = cds;
13729
13730 for (i = 0; i < ci_size; i++) {
13731 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13732 if (mid_index != (VALUE)-1) {
13733 ID mid = ibf_load_id(load, mid_index);
13734 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13735 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13736
13737 struct rb_callinfo_kwarg *kwarg = NULL;
13738 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13739 if (kwlen > 0) {
13740 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13741 kwarg->references = 0;
13742 kwarg->keyword_len = kwlen;
13743 for (int j=0; j<kwlen; j++) {
13744 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13745 kwarg->keywords[j] = ibf_load_object(load, keyword);
13746 }
13747 }
13748
13749 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13750 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13751 cds[i].cc = vm_cc_empty();
13752 }
13753 else {
13754 // NULL ci
13755 cds[i].ci = NULL;
13756 cds[i].cc = NULL;
13757 }
13758 }
13759}
13760
13761static struct rb_id_table *
13762ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13763{
13764 ibf_offset_t reading_pos = outer_variables_offset;
13765
13766 struct rb_id_table *tbl = NULL;
13767
13768 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13769
13770 if (table_size > 0) {
13771 tbl = rb_id_table_create(table_size);
13772 }
13773
13774 for (size_t i = 0; i < table_size; i++) {
13775 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13776 VALUE value = ibf_load_small_value(load, &reading_pos);
13777 if (!key) key = rb_make_temporary_id(i);
13778 rb_id_table_insert(tbl, key, value);
13779 }
13780
13781 return tbl;
13782}
13783
13784static ibf_offset_t
13785ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13786{
13787 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13788
13789 unsigned int *positions;
13790
13791 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13792
13793 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13794 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13795
13796#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13797 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13798
13799 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13800 struct ibf_dump_buffer buffer;
13801 buffer.str = rb_str_new(0, 0);
13802 buffer.obj_table = ibf_dump_object_table_new();
13803 dump->current_buffer = &buffer;
13804#endif
13805
13806 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13807 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13808 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13809 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13810 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13811
13812 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13813 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13814 SIZED_FREE_N(positions, ISEQ_BODY(iseq)->insns_info.size);
13815
13816 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13817 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13818 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13819 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13820 /* a NULL parent (persisted root) and references outside a Proc#refined subtree dump come out absent (-1) */
13821 const int parent_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->parent_iseq);
13822 const int local_iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)ISEQ_BODY(iseq)->local_iseq);
13823 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13824 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13825 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13826
13827#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13828 ibf_offset_t local_obj_list_offset;
13829 unsigned int local_obj_list_size;
13830
13831 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13832#endif
13833
13834 ibf_offset_t body_offset = ibf_dump_pos(dump);
13835
13836 /* dump the constant body */
13837 unsigned int param_flags =
13838 (body->param.flags.has_lead << 0) |
13839 (body->param.flags.has_opt << 1) |
13840 (body->param.flags.has_rest << 2) |
13841 (body->param.flags.has_post << 3) |
13842 (body->param.flags.has_kw << 4) |
13843 (body->param.flags.has_kwrest << 5) |
13844 (body->param.flags.has_block << 6) |
13845 (body->param.flags.ambiguous_param0 << 7) |
13846 (body->param.flags.accepts_no_kwarg << 8) |
13847 (body->param.flags.ruby2_keywords << 9) |
13848 (body->param.flags.anon_rest << 10) |
13849 (body->param.flags.anon_kwrest << 11) |
13850 (body->param.flags.use_block << 12) |
13851 (body->param.flags.forwardable << 13) |
13852 (body->param.flags.accepts_no_block << 14);
13853
13854#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13855# define IBF_BODY_OFFSET(x) (x)
13856#else
13857# define IBF_BODY_OFFSET(x) (body_offset - (x))
13858#endif
13859
13860 ibf_dump_write_small_value(dump, body->type);
13861 ibf_dump_write_small_value(dump, body->iseq_size);
13862 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13863 ibf_dump_write_small_value(dump, bytecode_size);
13864 ibf_dump_write_small_value(dump, param_flags);
13865 ibf_dump_write_small_value(dump, body->param.size);
13866 ibf_dump_write_small_value(dump, body->param.lead_num);
13867 ibf_dump_write_small_value(dump, body->param.opt_num);
13868 ibf_dump_write_small_value(dump, body->param.rest_start);
13869 ibf_dump_write_small_value(dump, body->param.post_start);
13870 ibf_dump_write_small_value(dump, body->param.post_num);
13871 ibf_dump_write_small_value(dump, body->param.block_start);
13872 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13873 ibf_dump_write_small_value(dump, param_keyword_offset);
13874 ibf_dump_write_small_value(dump, location_pathobj_index);
13875 ibf_dump_write_small_value(dump, location_label_index);
13876 ibf_dump_write_small_value(dump, body->location.first_lineno);
13877 ibf_dump_write_small_value(dump, body->location.node_id);
13878 /* Dump the source hash (0 if unavailable) in two 32-bit halves, because
13879 * VALUE may be 32 bits wide. */
13880 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)(body->source_hash >> 32));
13881 ibf_dump_write_small_value(dump, (VALUE)(uint32_t)body->source_hash);
13882 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13883 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13884 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13885 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13886 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13887 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13888 ibf_dump_write_small_value(dump, body->insns_info.size);
13889 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13890 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13891 ibf_dump_write_small_value(dump, catch_table_size);
13892 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13893 ibf_dump_write_small_value(dump, parent_iseq_index);
13894 ibf_dump_write_small_value(dump, local_iseq_index);
13895 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13896 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13897 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13898 ibf_dump_write_small_value(dump, ISEQ_FLIP_CNT(iseq));
13899 ibf_dump_write_small_value(dump, body->local_table_size);
13900 ibf_dump_write_small_value(dump, body->ivc_size);
13901 ibf_dump_write_small_value(dump, body->icvarc_size);
13902 ibf_dump_write_small_value(dump, body->ise_size);
13903 ibf_dump_write_small_value(dump, body->ic_size);
13904 ibf_dump_write_small_value(dump, body->ci_size);
13905 ibf_dump_write_small_value(dump, body->stack_max);
13906 ibf_dump_write_small_value(dump, body->builtin_attrs);
13907 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13908
13909#undef IBF_BODY_OFFSET
13910
13911#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13912 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13913
13914 dump->current_buffer = saved_buffer;
13915 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13916
13917 ibf_offset_t offset = ibf_dump_pos(dump);
13918 ibf_dump_write_small_value(dump, iseq_start);
13919 ibf_dump_write_small_value(dump, iseq_length_bytes);
13920 ibf_dump_write_small_value(dump, body_offset);
13921
13922 ibf_dump_write_small_value(dump, local_obj_list_offset);
13923 ibf_dump_write_small_value(dump, local_obj_list_size);
13924
13925 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13926
13927 return offset;
13928#else
13929 return body_offset;
13930#endif
13931}
13932
13933static VALUE
13934ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13935{
13936 VALUE str = ibf_load_object(load, str_index);
13937 if (str != Qnil) {
13938 str = rb_fstring(str);
13939 }
13940 return str;
13941}
13942
13943static void
13944ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13945{
13946 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13947
13948 ibf_offset_t reading_pos = offset;
13949
13950#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13951 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13952 load->current_buffer = &load->global_buffer;
13953
13954 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13955 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13956 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13957
13958 struct ibf_load_buffer buffer;
13959 buffer.buff = load->global_buffer.buff + iseq_start;
13960 buffer.size = iseq_length_bytes;
13961 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13962 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13963 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13964
13965 load->current_buffer = &buffer;
13966 reading_pos = body_offset;
13967#endif
13968
13969#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13970# define IBF_BODY_OFFSET(x) (x)
13971#else
13972# define IBF_BODY_OFFSET(x) (offset - (x))
13973#endif
13974
13975 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13976 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13977 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13978 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13979 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13980 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13981 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13982 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13983 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13984 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13985 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13986 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13987 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13988 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13989 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13990 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13991 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13992 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13993 const uint64_t source_hash_hi = (uint64_t)ibf_load_small_value(load, &reading_pos);
13994 const uint64_t source_hash_lo = (uint64_t)ibf_load_small_value(load, &reading_pos);
13995 const uint64_t source_hash = (source_hash_hi << 32) | (uint32_t)source_hash_lo;
13996 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13997 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13998 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13999 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
14000 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14001 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14002 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14003 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14004 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14005 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14006 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14007 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14008 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14009 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
14010 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14011 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
14012 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
14013 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14014
14015 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14016 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14017 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14018 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14019
14020 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
14021 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
14022 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
14023 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
14024
14025 // setup fname and dummy frame
14026 VALUE path = ibf_load_object(load, location_pathobj_index);
14027 {
14028 VALUE realpath = Qnil;
14029
14030 if (RB_TYPE_P(path, T_STRING)) {
14031 realpath = path = rb_fstring(path);
14032 }
14033 else if (RB_TYPE_P(path, T_ARRAY)) {
14034 VALUE pathobj = path;
14035 if (RARRAY_LEN(pathobj) != 2) {
14036 rb_raise(rb_eRuntimeError, "path object size mismatch");
14037 }
14038 path = rb_fstring(RARRAY_AREF(pathobj, 0));
14039 realpath = RARRAY_AREF(pathobj, 1);
14040 if (!NIL_P(realpath)) {
14041 if (!RB_TYPE_P(realpath, T_STRING)) {
14042 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
14043 "(%x), path=%+"PRIsVALUE,
14044 realpath, TYPE(realpath), path);
14045 }
14046 realpath = rb_fstring(realpath);
14047 }
14048 }
14049 else {
14050 rb_raise(rb_eRuntimeError, "unexpected path object");
14051 }
14052 rb_iseq_pathobj_set(iseq, path, realpath);
14053 }
14054
14055 // push dummy frame
14056 rb_execution_context_t *ec = GET_EC();
14057 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
14058
14059#undef IBF_BODY_OFFSET
14060
14061 load_body->type = type;
14062 load_body->stack_max = stack_max;
14063 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
14064 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
14065 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
14066 load_body->param.flags.has_post = (param_flags >> 3) & 1;
14067 load_body->param.flags.has_kw = FALSE;
14068 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
14069 load_body->param.flags.has_block = (param_flags >> 6) & 1;
14070 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
14071 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
14072 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
14073 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
14074 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
14075 load_body->param.flags.use_block = (param_flags >> 12) & 1;
14076 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
14077 load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
14078 load_body->param.size = param_size;
14079 load_body->param.lead_num = param_lead_num;
14080 load_body->param.opt_num = param_opt_num;
14081 load_body->param.rest_start = param_rest_start;
14082 load_body->param.post_start = param_post_start;
14083 load_body->param.post_num = param_post_num;
14084 load_body->param.block_start = param_block_start;
14085 load_body->local_table_size = local_table_size;
14086 load_body->ci_size = ci_size;
14087 load_body->insns_info.size = insns_info_size;
14088
14089 // variable is NULL from ZALLOC; only allocate if flip_count is non-zero.
14090 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
14091 if (variable_flip_count) {
14092 struct rb_iseq_variable *v = rb_iseq_variable_ensure(iseq);
14093 v->flip_count = variable_flip_count;
14094 }
14095
14096 load_body->location.first_lineno = location_first_lineno;
14097 load_body->location.node_id = location_node_id;
14098 load_body->source_hash = source_hash;
14099 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
14100 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
14101 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
14102 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
14103 load_body->builtin_attrs = builtin_attrs;
14104 load_body->prism = prism;
14105
14106 load_body->ivc_size = ivc_size;
14107 load_body->icvarc_size = icvarc_size;
14108 load_body->ise_size = ise_size;
14109 load_body->ic_size = ic_size;
14110
14111 if (ISEQ_IS_SIZE(load_body)) {
14112 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
14113 }
14114 else {
14115 load_body->is_entries = NULL;
14116 }
14117 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
14118 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
14119 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
14120 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
14121 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
14122 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
14123 load_body->insns_info.positions_or_succ_index_table.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
14124 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
14125 ibf_load_lvar_states(load, load_body, lvar_states_offset, local_table_size, load_body->local_table);
14126 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
14127
14128 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
14129 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
14130 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
14131
14132 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
14133 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
14134 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
14135
14136 // This must be done after the local table is loaded.
14137 if (load_body->param.keyword != NULL) {
14138 RUBY_ASSERT(load_body->local_table);
14139 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
14140 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
14141 }
14142
14143 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
14144#if VM_INSN_INFO_TABLE_IMPL == 2
14145 rb_iseq_insns_info_encode_positions(iseq);
14146#endif
14147
14148 rb_iseq_translate_threaded_code(iseq);
14149
14150#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14151 load->current_buffer = &load->global_buffer;
14152#endif
14153
14154 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
14155
14156#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
14157 load->current_buffer = saved_buffer;
14158#endif
14159 verify_call_cache(iseq);
14160
14161 RB_GC_GUARD(dummy_frame);
14162 rb_vm_pop_frame_no_int(ec);
14163}
14164
14166{
14167 struct ibf_dump *dump;
14168 VALUE offset_list;
14169};
14170
14171static int
14172ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14173{
14174 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
14175 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
14176
14177 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14178 rb_ary_push(args->offset_list, UINT2NUM(offset));
14179
14180 return ST_CONTINUE;
14181}
14182
14183static void
14184ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
14185{
14186 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
14187
14188 struct ibf_dump_iseq_list_arg args;
14189 args.dump = dump;
14190 args.offset_list = offset_list;
14191
14192 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14193
14194 st_index_t i;
14195 st_index_t size = dump->iseq_table->num_entries;
14196 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
14197
14198 for (i = 0; i < size; i++) {
14199 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
14200 }
14201
14202 ibf_dump_align(dump, sizeof(ibf_offset_t));
14203 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
14204 header->iseq_list_size = (unsigned int)size;
14205}
14206
14207/*
14208 * Binary format
14209 * - ibf_object_header
14210 * - ibf_object_xxx (xxx is type)
14211 */
14212
14214 unsigned int type: 5;
14215 unsigned int special_const: 1;
14216 unsigned int frozen: 1;
14217 unsigned int internal: 1;
14218};
14219
14220enum ibf_object_class_index {
14221 IBF_OBJECT_CLASS_OBJECT,
14222 IBF_OBJECT_CLASS_ARRAY,
14223 IBF_OBJECT_CLASS_STANDARD_ERROR,
14224 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14225 IBF_OBJECT_CLASS_TYPE_ERROR,
14226 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14227};
14228
14230 long srcstr;
14231 char option;
14232};
14233
14235 long len;
14236 long keyval[FLEX_ARY_LEN];
14237};
14238
14240 long class_index;
14241 long len;
14242 long beg;
14243 long end;
14244 int excl;
14245};
14246
14248 ssize_t slen;
14249 BDIGIT digits[FLEX_ARY_LEN];
14250};
14251
14252enum ibf_object_data_type {
14253 IBF_OBJECT_DATA_ENCODING,
14254};
14255
14257 long a, b;
14258};
14259
14261 long str;
14262};
14263
14264#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
14265 ((((offset) - 1) / (align) + 1) * (align))
14266/* No cast, since it's UB to create an unaligned pointer.
14267 * Leave as void* for use with memcpy in those cases.
14268 * We align the offset, but the buffer pointer is only VALUE aligned,
14269 * so the returned pointer may be unaligned for `type` .*/
14270#define IBF_OBJBODY(type, offset) \
14271 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14272
14273static const void *
14274ibf_load_check_offset(const struct ibf_load *load, size_t offset)
14275{
14276 if (offset >= load->current_buffer->size) {
14277 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
14278 }
14279 return load->current_buffer->buff + offset;
14280}
14281
14282NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
14283
14284static void
14285ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
14286{
14287 char buff[0x100];
14288 rb_raw_obj_info(buff, sizeof(buff), obj);
14289 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
14290}
14291
14292NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
14293
14294static VALUE
14295ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14296{
14297 rb_raise(rb_eArgError, "unsupported");
14299}
14300
14301static void
14302ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
14303{
14304 enum ibf_object_class_index cindex;
14305 if (obj == rb_cObject) {
14306 cindex = IBF_OBJECT_CLASS_OBJECT;
14307 }
14308 else if (obj == rb_cArray) {
14309 cindex = IBF_OBJECT_CLASS_ARRAY;
14310 }
14311 else if (obj == rb_eStandardError) {
14312 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14313 }
14314 else if (obj == rb_eNoMatchingPatternError) {
14315 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14316 }
14317 else if (obj == rb_eTypeError) {
14318 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14319 }
14320 else if (obj == rb_eNoMatchingPatternKeyError) {
14321 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14322 }
14323 else {
14324 rb_obj_info_dump(obj);
14325 rb_p(obj);
14326 rb_bug("unsupported class");
14327 }
14328 ibf_dump_write_small_value(dump, (VALUE)cindex);
14329}
14330
14331static VALUE
14332ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14333{
14334 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14335
14336 switch (cindex) {
14337 case IBF_OBJECT_CLASS_OBJECT:
14338 return rb_cObject;
14339 case IBF_OBJECT_CLASS_ARRAY:
14340 return rb_cArray;
14341 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14342 return rb_eStandardError;
14343 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14345 case IBF_OBJECT_CLASS_TYPE_ERROR:
14346 return rb_eTypeError;
14347 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14349 }
14350
14351 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14352}
14353
14354
14355static void
14356ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14357{
14358 double dbl = RFLOAT_VALUE(obj);
14359 (void)IBF_W(&dbl, double, 1);
14360}
14361
14362static VALUE
14363ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14364{
14365 double d;
14366 /* Avoid unaligned VFP load on ARMv7; IBF payload may be unaligned (C99 6.3.2.3 p7). */
14367 memcpy(&d, IBF_OBJBODY(double, offset), sizeof(d));
14368 VALUE f = DBL2NUM(d);
14369 if (!FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14370 return f;
14371}
14372
14373static void
14374ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14375{
14376 long encindex = (long)rb_enc_get_index(obj);
14377 long len = RSTRING_LEN(obj);
14378 const char *ptr = RSTRING_PTR(obj);
14379
14380 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14381 rb_encoding *enc = rb_enc_from_index((int)encindex);
14382 const char *enc_name = rb_enc_name(enc);
14383 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14384 }
14385
14386 ibf_dump_write_small_value(dump, encindex);
14387 ibf_dump_write_small_value(dump, len);
14388 IBF_WP(ptr, char, len);
14389}
14390
14391static VALUE
14392ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14393{
14394 ibf_offset_t reading_pos = offset;
14395
14396 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14397 const long len = (long)ibf_load_small_value(load, &reading_pos);
14398 const char *ptr = load->current_buffer->buff + reading_pos;
14399
14400 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14401 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14402 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14403 }
14404
14405 VALUE str;
14406 if (header->frozen && !header->internal) {
14407 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14408 }
14409 else {
14410 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14411
14412 if (header->internal) rb_obj_hide(str);
14413 if (header->frozen) str = rb_fstring(str);
14414 }
14415 return str;
14416}
14417
14418static void
14419ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14420{
14421 VALUE srcstr = RREGEXP_SRC(obj);
14422 struct ibf_object_regexp regexp;
14423 regexp.option = (char)rb_reg_options(obj);
14424 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14425
14426 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14427 ibf_dump_write_small_value(dump, regexp.srcstr);
14428}
14429
14430static VALUE
14431ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14432{
14433 struct ibf_object_regexp regexp;
14434 regexp.option = ibf_load_byte(load, &offset);
14435 regexp.srcstr = ibf_load_small_value(load, &offset);
14436
14437 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14438 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14439
14440 if (header->internal) rb_obj_hide(reg);
14441 if (header->frozen) RB_OBJ_SET_SHAREABLE(rb_obj_freeze(reg));
14442
14443 return reg;
14444}
14445
14446static void
14447ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14448{
14449 long i, len = RARRAY_LEN(obj);
14450 ibf_dump_write_small_value(dump, len);
14451 for (i=0; i<len; i++) {
14452 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14453 ibf_dump_write_small_value(dump, index);
14454 }
14455}
14456
14457static VALUE
14458ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14459{
14460 ibf_offset_t reading_pos = offset;
14461
14462 const long len = (long)ibf_load_small_value(load, &reading_pos);
14463
14464 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14465 int i;
14466
14467 for (i=0; i<len; i++) {
14468 const VALUE index = ibf_load_small_value(load, &reading_pos);
14469 rb_ary_push(ary, ibf_load_object(load, index));
14470 }
14471
14472 if (header->frozen) {
14473 rb_ary_freeze(ary);
14474 rb_ractor_make_shareable(ary); // TODO: check elements
14475 }
14476
14477 return ary;
14478}
14479
14480static int
14481ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14482{
14483 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14484
14485 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14486 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14487
14488 ibf_dump_write_small_value(dump, key_index);
14489 ibf_dump_write_small_value(dump, val_index);
14490 return ST_CONTINUE;
14491}
14492
14493static void
14494ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14495{
14496 long len = RHASH_SIZE(obj);
14497 ibf_dump_write_small_value(dump, (VALUE)len);
14498
14499 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14500}
14501
14502static VALUE
14503ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14504{
14505 long len = (long)ibf_load_small_value(load, &offset);
14506 VALUE obj = header->frozen ? rb_hash_alloc_fixed_size(rb_cHash, len) : rb_hash_new_capa(len);
14507 int i;
14508
14509 for (i = 0; i < len; i++) {
14510 VALUE key_index = ibf_load_small_value(load, &offset);
14511 VALUE val_index = ibf_load_small_value(load, &offset);
14512
14513 VALUE key = ibf_load_object(load, key_index);
14514 VALUE val = ibf_load_object(load, val_index);
14515 rb_hash_aset(obj, key, val);
14516 }
14517
14518 if (header->internal) rb_obj_hide(obj);
14519 if (header->frozen) {
14520 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14521 }
14522
14523 return obj;
14524}
14525
14526static int
14527ibf_dump_cdhash_i(st_data_t key, st_data_t val, st_data_t ptr)
14528{
14529 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14530
14531 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14532
14533 ibf_dump_write_small_value(dump, key_index);
14534 ibf_dump_write_small_value(dump, val);
14535 return ST_CONTINUE;
14536}
14537
14538static void
14539ibf_dump_object_imemo(struct ibf_dump *dump, VALUE obj)
14540{
14541 switch (imemo_type(obj)) {
14542 case imemo_cdhash: {
14543 st_table *tbl = rb_imemo_cdhash_tbl(obj);
14544
14545 long len = tbl->num_entries;
14546 ibf_dump_write_small_value(dump, (VALUE)len);
14547 if (len > 0) st_foreach(tbl, ibf_dump_cdhash_i, (VALUE)dump);
14548 break;
14549 }
14550 default:
14551 ibf_dump_object_unsupported(dump, obj);
14552 break;
14553 }
14554}
14555
14556static VALUE
14557ibf_load_object_imemo(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14558{
14559 long len = (long)ibf_load_small_value(load, &offset);
14560 VALUE obj = cdhash_new(len);
14561
14562 int i;
14563 for (i = 0; i < len; i++) {
14564 VALUE key_index = ibf_load_small_value(load, &offset);
14565 VALUE val = ibf_load_small_value(load, &offset);
14566
14567 VALUE key = ibf_load_object(load, key_index);
14568 cdhash_aset(obj, key, val);
14569 }
14570
14571 return obj;
14572}
14573
14574static void
14575ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14576{
14577 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14578 struct ibf_object_struct_range range;
14579 VALUE beg, end;
14580 IBF_ZERO(range);
14581 range.len = 3;
14582 range.class_index = 0;
14583
14584 rb_range_values(obj, &beg, &end, &range.excl);
14585 range.beg = (long)ibf_dump_object(dump, beg);
14586 range.end = (long)ibf_dump_object(dump, end);
14587
14588 IBF_W_ALIGN(struct ibf_object_struct_range);
14589 IBF_WV(range);
14590 }
14591 else {
14592 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14593 rb_class_name(CLASS_OF(obj)));
14594 }
14595}
14596
14597static VALUE
14598ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14599{
14600 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14601 VALUE beg = ibf_load_object(load, range->beg);
14602 VALUE end = ibf_load_object(load, range->end);
14603 VALUE obj = rb_range_new(beg, end, range->excl);
14604 if (header->internal) rb_obj_hide(obj);
14605 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14606 return obj;
14607}
14608
14609static void
14610ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14611{
14612 ssize_t len = BIGNUM_LEN(obj);
14613 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14614 BDIGIT *d = BIGNUM_DIGITS(obj);
14615
14616 (void)IBF_W(&slen, ssize_t, 1);
14617 IBF_WP(d, BDIGIT, len);
14618}
14619
14620static VALUE
14621ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14622{
14623 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14624 int sign = bignum->slen > 0;
14625 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14626 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14629 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14630 big_unpack_flags |
14631 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14632 if (header->internal) rb_obj_hide(obj);
14633 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14634 return obj;
14635}
14636
14637static void
14638ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14639{
14640 if (rb_data_is_encoding(obj)) {
14641 rb_encoding *enc = rb_to_encoding(obj);
14642 const char *name = rb_enc_name(enc);
14643 long len = strlen(name) + 1;
14644 long data[2];
14645 data[0] = IBF_OBJECT_DATA_ENCODING;
14646 data[1] = len;
14647 (void)IBF_W(data, long, 2);
14648 IBF_WP(name, char, len);
14649 }
14650 else {
14651 ibf_dump_object_unsupported(dump, obj);
14652 }
14653}
14654
14655static VALUE
14656ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14657{
14658 const long *body = IBF_OBJBODY(long, offset);
14659 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14660 /* const long len = body[1]; */
14661 const char *data = (const char *)&body[2];
14662
14663 switch (type) {
14664 case IBF_OBJECT_DATA_ENCODING:
14665 {
14666 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14667 return encobj;
14668 }
14669 }
14670
14671 return ibf_load_object_unsupported(load, header, offset);
14672}
14673
14674static void
14675ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14676{
14677 long data[2];
14678 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14679 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14680
14681 (void)IBF_W(data, long, 2);
14682}
14683
14684static VALUE
14685ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14686{
14687 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14688 VALUE a = ibf_load_object(load, nums->a);
14689 VALUE b = ibf_load_object(load, nums->b);
14690 VALUE obj = header->type == T_COMPLEX ?
14691 rb_complex_new(a, b) : rb_rational_new(a, b);
14692
14693 if (header->internal) rb_obj_hide(obj);
14694 if (header->frozen) rb_ractor_make_shareable(rb_obj_freeze(obj));
14695 return obj;
14696}
14697
14698static void
14699ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14700{
14701 ibf_dump_object_string(dump, rb_sym2str(obj));
14702}
14703
14704static VALUE
14705ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14706{
14707 ibf_offset_t reading_pos = offset;
14708
14709 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14710 const long len = (long)ibf_load_small_value(load, &reading_pos);
14711 const char *ptr = load->current_buffer->buff + reading_pos;
14712
14713 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14714 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14715 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14716 }
14717
14718 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14719 return ID2SYM(id);
14720}
14721
14722typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14723static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14724 ibf_dump_object_unsupported, /* T_NONE */
14725 ibf_dump_object_unsupported, /* T_OBJECT */
14726 ibf_dump_object_class, /* T_CLASS */
14727 ibf_dump_object_unsupported, /* T_MODULE */
14728 ibf_dump_object_float, /* T_FLOAT */
14729 ibf_dump_object_string, /* T_STRING */
14730 ibf_dump_object_regexp, /* T_REGEXP */
14731 ibf_dump_object_array, /* T_ARRAY */
14732 ibf_dump_object_hash, /* T_HASH */
14733 ibf_dump_object_struct, /* T_STRUCT */
14734 ibf_dump_object_bignum, /* T_BIGNUM */
14735 ibf_dump_object_unsupported, /* T_FILE */
14736 ibf_dump_object_data, /* T_DATA */
14737 ibf_dump_object_unsupported, /* T_MATCH */
14738 ibf_dump_object_complex_rational, /* T_COMPLEX */
14739 ibf_dump_object_complex_rational, /* T_RATIONAL */
14740 ibf_dump_object_unsupported, /* 0x10 */
14741 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14742 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14743 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14744 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14745 ibf_dump_object_unsupported, /* T_FIXNUM */
14746 ibf_dump_object_unsupported, /* T_UNDEF */
14747 ibf_dump_object_unsupported, /* 0x17 */
14748 ibf_dump_object_unsupported, /* 0x18 */
14749 ibf_dump_object_unsupported, /* 0x19 */
14750 ibf_dump_object_imemo, /* T_IMEMO 0x1a */
14751 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14752 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14753 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14754 ibf_dump_object_unsupported, /* 0x1e */
14755 ibf_dump_object_unsupported, /* 0x1f */
14756};
14757
14758static void
14759ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14760{
14761 unsigned char byte =
14762 (header.type << 0) |
14763 (header.special_const << 5) |
14764 (header.frozen << 6) |
14765 (header.internal << 7);
14766
14767 IBF_WV(byte);
14768}
14769
14770static struct ibf_object_header
14771ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14772{
14773 unsigned char byte = ibf_load_byte(load, offset);
14774
14775 struct ibf_object_header header;
14776 header.type = (byte >> 0) & 0x1f;
14777 header.special_const = (byte >> 5) & 0x01;
14778 header.frozen = (byte >> 6) & 0x01;
14779 header.internal = (byte >> 7) & 0x01;
14780
14781 return header;
14782}
14783
14784static ibf_offset_t
14785ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14786{
14787 struct ibf_object_header obj_header;
14788 ibf_offset_t current_offset;
14789 IBF_ZERO(obj_header);
14790 obj_header.type = TYPE(obj);
14791
14792 IBF_W_ALIGN(ibf_offset_t);
14793 current_offset = ibf_dump_pos(dump);
14794
14795 if (SPECIAL_CONST_P(obj) &&
14796 ! (SYMBOL_P(obj) ||
14797 RB_FLOAT_TYPE_P(obj))) {
14798 obj_header.special_const = TRUE;
14799 obj_header.frozen = TRUE;
14800 obj_header.internal = TRUE;
14801 ibf_dump_object_object_header(dump, obj_header);
14802 ibf_dump_write_small_value(dump, obj);
14803 }
14804 else {
14805 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14806 obj_header.special_const = FALSE;
14807 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14808 ibf_dump_object_object_header(dump, obj_header);
14809 (*dump_object_functions[obj_header.type])(dump, obj);
14810 }
14811
14812 return current_offset;
14813}
14814
14815typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14816static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14817 ibf_load_object_unsupported, /* T_NONE */
14818 ibf_load_object_unsupported, /* T_OBJECT */
14819 ibf_load_object_class, /* T_CLASS */
14820 ibf_load_object_unsupported, /* T_MODULE */
14821 ibf_load_object_float, /* T_FLOAT */
14822 ibf_load_object_string, /* T_STRING */
14823 ibf_load_object_regexp, /* T_REGEXP */
14824 ibf_load_object_array, /* T_ARRAY */
14825 ibf_load_object_hash, /* T_HASH */
14826 ibf_load_object_struct, /* T_STRUCT */
14827 ibf_load_object_bignum, /* T_BIGNUM */
14828 ibf_load_object_unsupported, /* T_FILE */
14829 ibf_load_object_data, /* T_DATA */
14830 ibf_load_object_unsupported, /* T_MATCH */
14831 ibf_load_object_complex_rational, /* T_COMPLEX */
14832 ibf_load_object_complex_rational, /* T_RATIONAL */
14833 ibf_load_object_unsupported, /* 0x10 */
14834 ibf_load_object_unsupported, /* T_NIL */
14835 ibf_load_object_unsupported, /* T_TRUE */
14836 ibf_load_object_unsupported, /* T_FALSE */
14837 ibf_load_object_symbol,
14838 ibf_load_object_unsupported, /* T_FIXNUM */
14839 ibf_load_object_unsupported, /* T_UNDEF */
14840 ibf_load_object_unsupported, /* 0x17 */
14841 ibf_load_object_unsupported, /* 0x18 */
14842 ibf_load_object_unsupported, /* 0x19 */
14843 ibf_load_object_imemo, /* T_IMEMO 0x1a */
14844 ibf_load_object_unsupported, /* T_NODE 0x1b */
14845 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14846 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14847 ibf_load_object_unsupported, /* 0x1e */
14848 ibf_load_object_unsupported, /* 0x1f */
14849};
14850
14851static VALUE
14852ibf_load_object(const struct ibf_load *load, VALUE object_index)
14853{
14854 if (object_index == 0) {
14855 return Qnil;
14856 }
14857 else {
14858 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14859 if (!obj) {
14860 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14861 ibf_offset_t offset = offsets[object_index];
14862 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14863
14864#if IBF_ISEQ_DEBUG
14865 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14866 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14867 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14868 header.type, header.special_const, header.frozen, header.internal);
14869#endif
14870 if (offset >= load->current_buffer->size) {
14871 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14872 }
14873
14874 if (header.special_const) {
14875 ibf_offset_t reading_pos = offset;
14876
14877 obj = ibf_load_small_value(load, &reading_pos);
14878 }
14879 else {
14880 obj = (*load_object_functions[header.type])(load, &header, offset);
14881 }
14882
14883 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14884 }
14885#if IBF_ISEQ_DEBUG
14886 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14887 object_index, obj);
14888#endif
14889 return obj;
14890 }
14891}
14892
14894{
14895 struct ibf_dump *dump;
14896 VALUE offset_list;
14897};
14898
14899static int
14900ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14901{
14902 VALUE obj = (VALUE)key;
14903 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14904
14905 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14906 rb_ary_push(args->offset_list, UINT2NUM(offset));
14907
14908 return ST_CONTINUE;
14909}
14910
14911static void
14912ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14913{
14914 st_table *obj_table = dump->current_buffer->obj_table;
14915 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14916
14917 struct ibf_dump_object_list_arg args;
14918 args.dump = dump;
14919 args.offset_list = offset_list;
14920
14921 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14922
14923 IBF_W_ALIGN(ibf_offset_t);
14924 *obj_list_offset = ibf_dump_pos(dump);
14925
14926 st_index_t size = obj_table->num_entries;
14927 st_index_t i;
14928
14929 for (i=0; i<size; i++) {
14930 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14931 IBF_WV(offset);
14932 }
14933
14934 *obj_list_size = (unsigned int)size;
14935}
14936
14937static void
14938ibf_dump_mark(void *ptr)
14939{
14940 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14941 rb_gc_mark(dump->global_buffer.str);
14942
14943 rb_mark_set(dump->global_buffer.obj_table);
14944 rb_mark_set(dump->iseq_table);
14945}
14946
14947static void
14948ibf_dump_free(void *ptr)
14949{
14950 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14951 if (dump->global_buffer.obj_table) {
14952 st_free_table(dump->global_buffer.obj_table);
14953 dump->global_buffer.obj_table = 0;
14954 }
14955 if (dump->iseq_table) {
14956 st_free_table(dump->iseq_table);
14957 dump->iseq_table = 0;
14958 }
14959}
14960
14961static size_t
14962ibf_dump_memsize(const void *ptr)
14963{
14964 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14965 size_t size = 0;
14966 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14967 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14968 return size;
14969}
14970
14971static const rb_data_type_t ibf_dump_type = {
14972 "ibf_dump",
14973 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14974 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_EMBEDDABLE
14975};
14976
14977static void
14978ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14979{
14980 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14981 dump->iseq_table = NULL;
14982
14983 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14984 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14985 dump->iseq_table = st_init_numtable(); /* need free */
14986
14987 dump->current_buffer = &dump->global_buffer;
14988}
14989
14990static VALUE
14991iseq_ibf_dump_0(struct ibf_dump *dump, const rb_iseq_t *iseq, VALUE opt)
14992{
14993 struct ibf_header header = {{0}};
14994
14995 ibf_dump_write(dump, &header, sizeof(header));
14996 ibf_dump_iseq(dump, iseq);
14997
14998 header.magic[0] = 'Y'; /* YARB */
14999 header.magic[1] = 'A';
15000 header.magic[2] = 'R';
15001 header.magic[3] = 'B';
15002 header.major_version = IBF_MAJOR_VERSION;
15003 header.minor_version = IBF_MINOR_VERSION;
15004 header.endian = IBF_ENDIAN_MARK;
15005 header.wordsize = (uint8_t)SIZEOF_VALUE;
15006 ibf_dump_iseq_list(dump, &header);
15007 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
15008 header.size = ibf_dump_pos(dump);
15009
15010 if (RTEST(opt)) {
15011 VALUE opt_str = opt;
15012 const char *ptr = StringValuePtr(opt_str);
15013 header.extra_size = RSTRING_LENINT(opt_str);
15014 ibf_dump_write(dump, ptr, header.extra_size);
15015 }
15016 else {
15017 header.extra_size = 0;
15018 }
15019
15020 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
15021
15022 return dump->global_buffer.str;
15023}
15024
15025VALUE
15026rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
15027{
15028 struct ibf_dump *dump;
15029 VALUE dump_obj;
15030 VALUE str;
15031
15032 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
15033 ISEQ_BODY(iseq)->local_iseq != iseq) {
15034 rb_raise(rb_eRuntimeError, "should be top of iseq");
15035 }
15036 if (RTEST(ISEQ_COVERAGE(iseq))) {
15037 rb_raise(rb_eRuntimeError, "should not compile with coverage");
15038 }
15039
15040 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15041 ibf_dump_setup(dump, dump_obj);
15042
15043 str = iseq_ibf_dump_0(dump, iseq, opt);
15044 RB_GC_GUARD(dump_obj);
15045 return str;
15046}
15047
15048static const ibf_offset_t *
15049ibf_iseq_list(const struct ibf_load *load)
15050{
15051 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
15052}
15053
15054void
15055rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
15056{
15057 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
15058 rb_iseq_t *prev_src_iseq = load->iseq;
15059 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
15060 load->iseq = iseq;
15061#if IBF_ISEQ_DEBUG
15062 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
15063 iseq->aux.loader.index, offset,
15064 load->header->size);
15065#endif
15066 ibf_load_iseq_each(load, iseq, offset);
15067 ISEQ_COMPILE_DATA_CLEAR(iseq);
15068 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15069 rb_iseq_init_trace(iseq);
15070 load->iseq = prev_src_iseq;
15071}
15072
15073#if USE_LAZY_LOAD
15074const rb_iseq_t *
15075rb_iseq_complete(const rb_iseq_t *iseq)
15076{
15077 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
15078 return iseq;
15079}
15080#endif
15081
15082static rb_iseq_t *
15083ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
15084{
15085 int iseq_index = (int)(VALUE)index_iseq;
15086
15087#if IBF_ISEQ_DEBUG
15088 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
15089 (void *)index_iseq, (void *)load->iseq_list);
15090#endif
15091 if (iseq_index == -1) {
15092 return NULL;
15093 }
15094 else {
15095 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
15096
15097#if IBF_ISEQ_DEBUG
15098 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
15099#endif
15100 if (iseqv) {
15101 return (rb_iseq_t *)iseqv;
15102 }
15103 else {
15104 rb_iseq_t *iseq = iseq_imemo_alloc();
15105#if IBF_ISEQ_DEBUG
15106 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
15107#endif
15108 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
15109 RB_OBJ_WRITE((VALUE)iseq, &iseq->aux.loader.obj, load->loader_obj);
15110 iseq->aux.loader.index = iseq_index;
15111#if IBF_ISEQ_DEBUG
15112 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
15113 (void *)iseq, (void *)load->loader_obj, iseq_index);
15114#endif
15115 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
15116
15117 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
15118#if IBF_ISEQ_DEBUG
15119 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
15120#endif
15121 rb_ibf_load_iseq_complete(iseq);
15122 }
15123
15124#if IBF_ISEQ_DEBUG
15125 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
15126 (void *)iseq, (void *)load->iseq);
15127#endif
15128 return iseq;
15129 }
15130 }
15131}
15132
15133static void
15134ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
15135{
15136 struct ibf_header *header = (struct ibf_header *)bytes;
15137 load->loader_obj = loader_obj;
15138 load->global_buffer.buff = bytes;
15139 load->header = header;
15140 load->global_buffer.size = header->size;
15141 load->global_buffer.obj_list_offset = header->global_object_list_offset;
15142 load->global_buffer.obj_list_size = header->global_object_list_size;
15143 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
15144 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
15145 load->iseq = NULL;
15146
15147 load->current_buffer = &load->global_buffer;
15148
15149 if (size < header->size) {
15150 rb_raise(rb_eRuntimeError, "broken binary format");
15151 }
15152 if (strncmp(header->magic, "YARB", 4) != 0) {
15153 rb_raise(rb_eRuntimeError, "unknown binary format");
15154 }
15155 if (header->major_version != IBF_MAJOR_VERSION ||
15156 header->minor_version != IBF_MINOR_VERSION) {
15157 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
15158 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
15159 }
15160 if (header->endian != IBF_ENDIAN_MARK) {
15161 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
15162 }
15163 if (header->wordsize != SIZEOF_VALUE) {
15164 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
15165 }
15166 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15167 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
15168 header->iseq_list_offset);
15169 }
15170 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
15171 rb_raise(rb_eArgError, "unaligned object list offset: %u",
15172 load->global_buffer.obj_list_offset);
15173 }
15174}
15175
15176static void
15177ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
15178{
15179 StringValue(str);
15180
15181 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
15182 rb_raise(rb_eRuntimeError, "broken binary format");
15183 }
15184
15185 if (USE_LAZY_LOAD) {
15186 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
15187 }
15188
15189 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
15190 RB_OBJ_WRITE(loader_obj, &load->str, str);
15191}
15192
15193static void
15194ibf_loader_mark(void *ptr)
15195{
15196 struct ibf_load *load = (struct ibf_load *)ptr;
15197 rb_gc_mark(load->str);
15198 rb_gc_mark(load->iseq_list);
15199 rb_gc_mark(load->global_buffer.obj_list);
15200}
15201
15202static void
15203ibf_loader_free(void *ptr)
15204{
15205 struct ibf_load *load = (struct ibf_load *)ptr;
15206 SIZED_FREE(load);
15207}
15208
15209static size_t
15210ibf_loader_memsize(const void *ptr)
15211{
15212 return sizeof(struct ibf_load);
15213}
15214
15215static const rb_data_type_t ibf_load_type = {
15216 "ibf_loader",
15217 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
15218 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_THREAD_SAFE_FREE
15219};
15220
15221const rb_iseq_t *
15222rb_iseq_ibf_load(VALUE str)
15223{
15224 struct ibf_load *load;
15225 rb_iseq_t *iseq;
15226 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15227
15228 ibf_load_setup(load, loader_obj, str);
15229 iseq = ibf_load_iseq(load, 0);
15230
15231 RB_GC_GUARD(loader_obj);
15232 return iseq;
15233}
15234
15235const rb_iseq_t *
15236rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
15237{
15238 struct ibf_load *load;
15239 rb_iseq_t *iseq;
15240 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15241
15242 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15243 iseq = ibf_load_iseq(load, 0);
15244
15245 RB_GC_GUARD(loader_obj);
15246 return iseq;
15247}
15248
15249/* collect the iseq table into an array indexed by iseq-list index */
15250static int
15251ibf_dump_iseq_table_collect_i(st_data_t key, st_data_t val, st_data_t arg)
15252{
15253 const rb_iseq_t **srcs = (const rb_iseq_t **)arg;
15254 srcs[(int)val] = (const rb_iseq_t *)key;
15255 return ST_CONTINUE;
15256}
15257
15258/* pc2branchindex (branch coverage) is per-iseq, so pair each copy with its
15259 * source by list index */
15260static void
15261iseq_subtree_copy_pc2branchindex(const struct ibf_dump *dump, const struct ibf_load *load)
15262{
15263 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15264 VALUE srcs_buf;
15265 const rb_iseq_t **srcs = ALLOCV_N(const rb_iseq_t *, srcs_buf, iseq_count);
15266 st_foreach(dump->iseq_table, ibf_dump_iseq_table_collect_i, (st_data_t)srcs);
15267
15268 for (unsigned int i = 0; i < iseq_count; i++) {
15269 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15270 VALUE pc2branchindex = ISEQ_PC2BRANCHINDEX(srcs[i]);
15271 if (pc2branchindex != Qnil) {
15272 ISEQ_PC2BRANCHINDEX_SET(copy, pc2branchindex);
15273 }
15274 }
15275
15276 ALLOCV_END(srcs_buf);
15277}
15278
15279/* Deep-copy an iseq subtree with independent inline caches for Proc#refined */
15280const rb_iseq_t *
15281rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
15282{
15283 struct ibf_dump *dump;
15284 VALUE dump_obj;
15285 VALUE str;
15286
15287 /* --- dump the subtree --- */
15288 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
15289 ibf_dump_setup(dump, dump_obj);
15290
15291 str = iseq_ibf_dump_0(dump, src_root, Qnil);
15292
15293 /* --- load it back --- */
15294 struct ibf_load *load;
15295 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15296 ibf_load_setup(load, loader_obj, str);
15297
15298 /* What the loader could not reconstruct is the same for every iseq in
15299 * the subtree: the only absent parent is the top's, every absent
15300 * local_iseq is the source's local root (runtime walks compare it
15301 * against the original frames, so a copy must not stand in), and
15302 * pathobj/script_lines/coverage are per-file values. */
15303 const struct rb_iseq_constant_body *sb = ISEQ_BODY(src_root);
15304 unsigned int iseq_count = (unsigned int)dump->iseq_table->num_entries;
15305 const rb_iseq_t *result = NULL;
15306 for (unsigned int i = 0; i < iseq_count; i++) {
15307 rb_iseq_t *copy = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)i);
15308 /* force completion even under USE_LAZY_LOAD */
15309 if (FL_TEST((VALUE)copy, ISEQ_NOT_LOADED_YET)) {
15310 rb_ibf_load_iseq_complete(copy);
15311 }
15312
15313 FL_SET((VALUE)copy, ISEQ_REFINED_COPY);
15314
15315 struct rb_iseq_constant_body *cb = ISEQ_BODY(copy);
15316 if (!cb->local_iseq) RB_OBJ_WRITE(copy, &cb->local_iseq, sb->local_iseq);
15317 RB_OBJ_WRITE(copy, &cb->location.pathobj, sb->location.pathobj);
15318 VALUE sl = ISEQ_SCRIPT_LINES(src_root);
15319 VALUE cov = ISEQ_COVERAGE(src_root);
15320 if (!NIL_P(sl) || !NIL_P(cov)) {
15321 struct rb_iseq_variable *v = rb_iseq_variable_ensure(copy);
15322 RB_OBJ_WRITE(copy, &v->script_lines, sl);
15323 RB_OBJ_WRITE(copy, &v->coverage, cov);
15324 }
15325
15326 if (i == 0) {
15327 RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
15328 result = copy;
15329 }
15330
15331 /* Shared across Ractors through the Proc#refined memo; the duplicated
15332 * subtree is self-contained, so mark each copy shareable. */
15333 RB_OBJ_SET_SHAREABLE((VALUE)copy);
15334 }
15335
15336 if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
15337 iseq_subtree_copy_pc2branchindex(dump, load);
15338 }
15339
15340 RB_GC_GUARD(dump_obj);
15341 RB_GC_GUARD(loader_obj);
15342 return result;
15343}
15344
15345VALUE
15346rb_iseq_ibf_load_extra_data(VALUE str)
15347{
15348 struct ibf_load *load;
15349 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
15350 VALUE extra_str;
15351
15352 ibf_load_setup(load, loader_obj, str);
15353 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15354 RB_GC_GUARD(loader_obj);
15355 return extra_str;
15356}
15357
15358#include "prism_compile.c"
#define RBIMPL_ASSERT_OR_ASSUME(...)
This is either RUBY_ASSERT or RBIMPL_ASSUME, depending on RUBY_DEBUG.
Definition assert.h:311
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define RUBY_ATOMIC_PTR_LOAD(var)
Identical to RUBY_ATOMIC_LOAD, except it expects its arguments are void*.
Definition atomic.h:338
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:133
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:125
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define NUM2ULL
Old name of RB_NUM2ULL.
Definition long_long.h:35
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:127
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:129
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:487
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1441
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1444
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:689
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:468
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1445
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1433
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1448
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:103
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:94
VALUE rb_cHash
Hash class.
Definition hash.c:122
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:668
VALUE rb_cRange
Range class.
Definition range.c:35
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:905
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1308
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:468
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:456
#define RB_POSFIXABLE(_)
Checks if the passed value is in range of fixnum, assuming it is a positive number.
Definition fixnum.h:43
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:33
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_resurrect(VALUE ary)
I guess there is no use case of this function in extension libraries, but this is a routine identical...
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:550
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:568
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:532
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1234
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1258
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1882
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:77
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:2006
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4476
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3897
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1782
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4260
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4246
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3665
VALUE rb_str_resurrect(VALUE str)
Like rb_str_dup(), but always create an instance of rb_cString regardless of the given object's class...
Definition string.c:2040
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3863
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4314
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:4134
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3375
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:515
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:1129
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:1091
int len
Length of the buffer.
Definition io.h:8
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
Definition ractor.h:235
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1912
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:385
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:166
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:56
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:69
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:102
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:438
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:106
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:773
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:604
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9083
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:31
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:368
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:285
Definition vm_core.h:288
Definition iseq.h:339
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:245
Definition st.h:79
Definition vm_core.h:297
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145