Ruby 3.5.0dev (2025-08-09 revision 2a6345e957c01f4495323723c7a3d7ac0d4ac339)
compile.c (2a6345e957c01f4495323723c7a3d7ac0d4ac339)
1/**********************************************************************
2
3 compile.c - ruby node tree -> VM instruction sequence
4
5 $Author$
6 created at: 04/01/01 03:42:15 JST
7
8 Copyright (C) 2004-2007 Koichi Sasada
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13#include <math.h>
14
15#ifdef HAVE_DLADDR
16# include <dlfcn.h>
17#endif
18
19#include "encindex.h"
20#include "id_table.h"
21#include "internal.h"
22#include "internal/array.h"
23#include "internal/compile.h"
24#include "internal/complex.h"
25#include "internal/encoding.h"
26#include "internal/error.h"
27#include "internal/gc.h"
28#include "internal/hash.h"
29#include "internal/io.h"
30#include "internal/numeric.h"
31#include "internal/object.h"
32#include "internal/rational.h"
33#include "internal/re.h"
34#include "internal/ruby_parser.h"
35#include "internal/symbol.h"
36#include "internal/thread.h"
37#include "internal/variable.h"
38#include "iseq.h"
39#include "ruby/ractor.h"
40#include "ruby/re.h"
41#include "ruby/util.h"
42#include "vm_core.h"
43#include "vm_callinfo.h"
44#include "vm_debug.h"
45#include "yjit.h"
46
47#include "builtin.h"
48#include "insns.inc"
49#include "insns_info.inc"
50
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
52
53typedef struct iseq_link_element {
54 enum {
55 ISEQ_ELEMENT_ANCHOR,
56 ISEQ_ELEMENT_LABEL,
57 ISEQ_ELEMENT_INSN,
58 ISEQ_ELEMENT_ADJUST,
59 ISEQ_ELEMENT_TRACE,
60 } type;
61 struct iseq_link_element *next;
62 struct iseq_link_element *prev;
64
65typedef struct iseq_link_anchor {
66 LINK_ELEMENT anchor;
67 LINK_ELEMENT *last;
69
70typedef enum {
71 LABEL_RESCUE_NONE,
72 LABEL_RESCUE_BEG,
73 LABEL_RESCUE_END,
74 LABEL_RESCUE_TYPE_MAX
75} LABEL_RESCUE_TYPE;
76
77typedef struct iseq_label_data {
78 LINK_ELEMENT link;
79 int label_no;
80 int position;
81 int sc_state;
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
87} LABEL;
88
89typedef struct iseq_insn_data {
90 LINK_ELEMENT link;
91 enum ruby_vminsn_type insn_id;
92 int operand_size;
93 int sc_state;
94 VALUE *operands;
95 struct {
96 int line_no;
97 int node_id;
98 rb_event_flag_t events;
99 } insn_info;
100} INSN;
101
102typedef struct iseq_adjust_data {
103 LINK_ELEMENT link;
104 LABEL *label;
105 int line_no;
106} ADJUST;
107
108typedef struct iseq_trace_data {
109 LINK_ELEMENT link;
110 rb_event_flag_t event;
111 long data;
112} TRACE;
113
115 LABEL *begin;
116 LABEL *end;
117 struct ensure_range *next;
118};
119
121 const void *ensure_node;
123 struct ensure_range *erange;
124};
125
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
127
141#ifndef CPDEBUG
142#define CPDEBUG 0
143#endif
144
145#if CPDEBUG >= 0
146#define compile_debug CPDEBUG
147#else
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
149#endif
150
151#if CPDEBUG
152
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
155
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
159
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
163
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
167
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
171
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
175
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
179 gl_node_level++)
180
181#define debug_node_end() gl_node_level --
182
183#else
184
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
192#endif
193
194#if CPDEBUG > 1 || CPDEBUG < 0
195#undef printf
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
199#else
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
202#endif
203
204#define LVAR_ERRINFO (1)
205
206/* create new label */
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
209
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
212
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
215
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
218
219/* add instructions */
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
222
223/* add an instruction */
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226
227/* add an instruction with the given line number and node id */
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230
231/* insert an instruction before next */
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234
235/* insert an instruction after prev */
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238
239/* add an instruction with some operands (1, 2, 3, 5) */
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243
244/* insert an instruction with some operands (1, 2, 3, 5) before next */
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248
249/* insert an instruction with some operands (1, 2, 3, 5) after prev */
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
253
254#define LABEL_REF(label) ((label)->refcnt++)
255
256/* add an instruction with label operand (alias of ADD_INSN1) */
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
258
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
262
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266
267/* Specific Insn factory */
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
270
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
273
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
276
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
279
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
282
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
285
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
288
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
293
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
296
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299
300/* add label */
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
303
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
306
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
309
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
312
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
320 LABEL_REF(le); \
321 LABEL_REF(lc); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
325} while (0)
326
327/* compile node */
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
331
332/* compile node, this node's value will be popped */
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
336
337/* compile node, which is popped when 'popped' is true */
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
341
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
346
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
349
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
352
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360
361/* error */
362#if CPDEBUG > 0
364#endif
365RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
366static void
367append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
368{
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
371 VALUE err = err_info == Qtrue ? Qfalse : err_info;
372 va_list args;
373
374 va_start(args, fmt);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
376 va_end(args);
377 if (NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 rb_set_errinfo(err);
380 }
381 else if (!err_info) {
382 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
383 }
384 if (compile_debug) {
385 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
386 rb_exc_fatal(err);
387 }
388}
389
390#if 0
391static void
392compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
393{
394 va_list args;
395 va_start(args, fmt);
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
397 va_end(args);
398 abort();
399}
400#endif
401
402#define COMPILE_ERROR append_compile_error
403
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
406
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
408do { \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
415 return errval; \
416 } \
417} while (0)
418
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
420do { \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
423 return errval; \
424} while (0)
425
426#define UNKNOWN_NODE(prefix, node, errval) \
427do { \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
431 return errval; \
432} while (0)
433
434#define COMPILE_OK 1
435#define COMPILE_NG 0
436
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
439#define BEFORE_RETURN
440
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL) /* re-initialize */
445
446static inline VALUE
447freeze_hide_obj(VALUE obj)
448{
449 OBJ_FREEZE(obj);
450 RBASIC_CLEAR_CLASS(obj);
451 return obj;
452}
453
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
457#endif
458
459/* for debug */
460#if CPDEBUG < 0
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#else
464#define ISEQ_ARG
465#define ISEQ_ARG_DECLARE
466#endif
467
468#if CPDEBUG
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470#endif
471
472static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
473static void dump_disasm_list(const LINK_ELEMENT *elem);
474
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(int depth, INSN *iobj);
477
478static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq, long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
482
483
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489
490static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
493
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497
498static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
499static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
500
501/*
502 * To make Array to LinkedList, use link_anchor
503 */
504
505static void
506verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
507{
508#if CPDEBUG
509 int flag = 0;
510 LINK_ELEMENT *list, *plist;
511
512 if (!compile_debug) return;
513
514 list = anchor->anchor.next;
515 plist = &anchor->anchor;
516 while (list) {
517 if (plist != list->prev) {
518 flag += 1;
519 }
520 plist = list;
521 list = list->next;
522 }
523
524 if (anchor->last != plist && anchor->last != 0) {
525 flag |= 0x70000;
526 }
527
528 if (flag != 0) {
529 rb_bug("list verify error: %08x (%s)", flag, info);
530 }
531#endif
532}
533#if CPDEBUG < 0
534#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
535#endif
536
537static void
538verify_call_cache(rb_iseq_t *iseq)
539{
540#if CPDEBUG
541 VALUE *original = rb_iseq_original_iseq(iseq);
542 size_t i = 0;
543 while (i < ISEQ_BODY(iseq)->iseq_size) {
544 VALUE insn = original[i];
545 const char *types = insn_op_types(insn);
546
547 for (int j=0; types[j]; j++) {
548 if (types[j] == TS_CALLDATA) {
549 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
550 const struct rb_callinfo *ci = cd->ci;
551 const struct rb_callcache *cc = cd->cc;
552 if (cc != vm_cc_empty()) {
553 vm_ci_dump(ci);
554 rb_bug("call cache is not initialized by vm_cc_empty()");
555 }
556 }
557 }
558 i += insn_len(insn);
559 }
560
561 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
562 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
563 const struct rb_callinfo *ci = cd->ci;
564 const struct rb_callcache *cc = cd->cc;
565 if (cc != NULL && cc != vm_cc_empty()) {
566 vm_ci_dump(ci);
567 rb_bug("call cache is not initialized by vm_cc_empty()");
568 }
569 }
570#endif
571}
572
573/*
574 * elem1, elem2 => elem1, elem2, elem
575 */
576static void
577ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
578{
579 elem->prev = anchor->last;
580 anchor->last->next = elem;
581 anchor->last = elem;
582 verify_list("add", anchor);
583}
584
585/*
586 * elem1, before, elem2 => elem1, before, elem, elem2
587 */
588static void
589APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
590{
591 elem->prev = before;
592 elem->next = before->next;
593 elem->next->prev = elem;
594 before->next = elem;
595 if (before == anchor->last) anchor->last = elem;
596 verify_list("add", anchor);
597}
598#if CPDEBUG < 0
599#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
600#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
601#endif
602
603static int
604branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
605{
606 if (!ISEQ_COVERAGE(iseq)) return 0;
607 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
608 if (first_line <= 0) return 0;
609 return 1;
610}
611
612#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
613
614static VALUE
615setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
616{
617 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
618 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
619 VALUE branch = rb_ary_hidden_new(6);
620
621 rb_hash_aset(structure, key, branch);
622 rb_ary_push(branch, ID2SYM(rb_intern(type)));
623 rb_ary_push(branch, INT2FIX(first_lineno));
624 rb_ary_push(branch, INT2FIX(first_column));
625 rb_ary_push(branch, INT2FIX(last_lineno));
626 rb_ary_push(branch, INT2FIX(last_column));
627 return branch;
628}
629
630static VALUE
631decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
632{
633 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
634
635 /*
636 * if !structure[node]
637 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
638 * else
639 * branches = structure[node][5]
640 * end
641 */
642
643 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
644 VALUE branch_base = rb_hash_aref(structure, key);
645 VALUE branches;
646
647 if (NIL_P(branch_base)) {
648 branch_base = setup_branch(loc, type, structure, key);
649 branches = rb_hash_new();
650 rb_obj_hide(branches);
651 rb_ary_push(branch_base, branches);
652 }
653 else {
654 branches = RARRAY_AREF(branch_base, 5);
655 }
656
657 return branches;
658}
659
660static NODE
661generate_dummy_line_node(int lineno, int node_id)
662{
663 NODE dummy = { 0 };
664 nd_set_line(&dummy, lineno);
665 nd_set_node_id(&dummy, node_id);
666 return dummy;
667}
668
669static void
670add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
671{
672 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
673
674 /*
675 * if !branches[branch_id]
676 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
677 * else
678 * counter_idx= branches[branch_id][5]
679 * end
680 */
681
682 VALUE key = INT2FIX(branch_id);
683 VALUE branch = rb_hash_aref(branches, key);
684 long counter_idx;
685
686 if (NIL_P(branch)) {
687 branch = setup_branch(loc, type, branches, key);
688 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
689 counter_idx = RARRAY_LEN(counters);
690 rb_ary_push(branch, LONG2FIX(counter_idx));
691 rb_ary_push(counters, INT2FIX(0));
692 }
693 else {
694 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
695 }
696
697 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
698 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
699}
700
701#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
702
703static int
704validate_label(st_data_t name, st_data_t label, st_data_t arg)
705{
706 rb_iseq_t *iseq = (rb_iseq_t *)arg;
707 LABEL *lobj = (LABEL *)label;
708 if (!lobj->link.next) {
709 do {
710 COMPILE_ERROR(iseq, lobj->position,
711 "%"PRIsVALUE": undefined label",
712 rb_sym2str((VALUE)name));
713 } while (0);
714 }
715 return ST_CONTINUE;
716}
717
718static void
719validate_labels(rb_iseq_t *iseq, st_table *labels_table)
720{
721 st_foreach(labels_table, validate_label, (st_data_t)iseq);
722 st_free_table(labels_table);
723}
724
725static NODE *
726get_nd_recv(const NODE *node)
727{
728 switch (nd_type(node)) {
729 case NODE_CALL:
730 return RNODE_CALL(node)->nd_recv;
731 case NODE_OPCALL:
732 return RNODE_OPCALL(node)->nd_recv;
733 case NODE_FCALL:
734 return 0;
735 case NODE_QCALL:
736 return RNODE_QCALL(node)->nd_recv;
737 case NODE_VCALL:
738 return 0;
739 case NODE_ATTRASGN:
740 return RNODE_ATTRASGN(node)->nd_recv;
741 case NODE_OP_ASGN1:
742 return RNODE_OP_ASGN1(node)->nd_recv;
743 case NODE_OP_ASGN2:
744 return RNODE_OP_ASGN2(node)->nd_recv;
745 default:
746 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
747 }
748}
749
750static ID
751get_node_call_nd_mid(const NODE *node)
752{
753 switch (nd_type(node)) {
754 case NODE_CALL:
755 return RNODE_CALL(node)->nd_mid;
756 case NODE_OPCALL:
757 return RNODE_OPCALL(node)->nd_mid;
758 case NODE_FCALL:
759 return RNODE_FCALL(node)->nd_mid;
760 case NODE_QCALL:
761 return RNODE_QCALL(node)->nd_mid;
762 case NODE_VCALL:
763 return RNODE_VCALL(node)->nd_mid;
764 case NODE_ATTRASGN:
765 return RNODE_ATTRASGN(node)->nd_mid;
766 default:
767 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
768 }
769}
770
771static NODE *
772get_nd_args(const NODE *node)
773{
774 switch (nd_type(node)) {
775 case NODE_CALL:
776 return RNODE_CALL(node)->nd_args;
777 case NODE_OPCALL:
778 return RNODE_OPCALL(node)->nd_args;
779 case NODE_FCALL:
780 return RNODE_FCALL(node)->nd_args;
781 case NODE_QCALL:
782 return RNODE_QCALL(node)->nd_args;
783 case NODE_VCALL:
784 return 0;
785 case NODE_ATTRASGN:
786 return RNODE_ATTRASGN(node)->nd_args;
787 default:
788 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
789 }
790}
791
792static ID
793get_node_colon_nd_mid(const NODE *node)
794{
795 switch (nd_type(node)) {
796 case NODE_COLON2:
797 return RNODE_COLON2(node)->nd_mid;
798 case NODE_COLON3:
799 return RNODE_COLON3(node)->nd_mid;
800 default:
801 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
802 }
803}
804
805static ID
806get_nd_vid(const NODE *node)
807{
808 switch (nd_type(node)) {
809 case NODE_LASGN:
810 return RNODE_LASGN(node)->nd_vid;
811 case NODE_DASGN:
812 return RNODE_DASGN(node)->nd_vid;
813 case NODE_IASGN:
814 return RNODE_IASGN(node)->nd_vid;
815 case NODE_CVASGN:
816 return RNODE_CVASGN(node)->nd_vid;
817 default:
818 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
819 }
820}
821
822static NODE *
823get_nd_value(const NODE *node)
824{
825 switch (nd_type(node)) {
826 case NODE_LASGN:
827 return RNODE_LASGN(node)->nd_value;
828 case NODE_DASGN:
829 return RNODE_DASGN(node)->nd_value;
830 default:
831 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
832 }
833}
834
835static VALUE
836get_string_value(const NODE *node)
837{
838 switch (nd_type(node)) {
839 case NODE_STR:
840 return rb_node_str_string_val(node);
841 case NODE_FILE:
842 return rb_node_file_path_val(node);
843 default:
844 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
845 }
846}
847
848VALUE
849rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
850{
851 DECL_ANCHOR(ret);
852 INIT_ANCHOR(ret);
853
854 (*ifunc->func)(iseq, ret, ifunc->data);
855
856 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
857
858 CHECK(iseq_setup_insn(iseq, ret));
859 return iseq_setup(iseq, ret);
860}
861
862static bool drop_unreachable_return(LINK_ANCHOR *ret);
863
864VALUE
865rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
866{
867 DECL_ANCHOR(ret);
868 INIT_ANCHOR(ret);
869
870 if (node == 0) {
871 NO_CHECK(COMPILE(ret, "nil", node));
872 iseq_set_local_table(iseq, 0, 0);
873 }
874 /* assume node is T_NODE */
875 else if (nd_type_p(node, NODE_SCOPE)) {
876 /* iseq type of top, method, class, block */
877 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
879
880 switch (ISEQ_BODY(iseq)->type) {
881 case ISEQ_TYPE_BLOCK:
882 {
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
885
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
888
889 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
893 ADD_LABEL(ret, end);
894 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896
897 /* wide range catch handler must put at last */
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 break;
901 }
902 case ISEQ_TYPE_CLASS:
903 {
904 ADD_TRACE(ret, RUBY_EVENT_CLASS);
905 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
906 ADD_TRACE(ret, RUBY_EVENT_END);
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 break;
909 }
910 case ISEQ_TYPE_METHOD:
911 {
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
913 ADD_TRACE(ret, RUBY_EVENT_CALL);
914 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
916 ADD_TRACE(ret, RUBY_EVENT_RETURN);
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
918 break;
919 }
920 default: {
921 CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
922 break;
923 }
924 }
925 }
926 else {
927 const char *m;
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->type) {
931 case INVALID_ISEQ_TYPE(METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret, "rescue", node));
941 break;
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret, "ensure", node));
945 break;
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret, "ensure", node));
948 break;
949 default:
950 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
951 return COMPILE_NG;
952 invalid_iseq_type:
953 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
954 return COMPILE_NG;
955 }
956 }
957
958 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
962 }
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
965 }
966
967#if OPT_SUPPORT_JOKE
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
972 }
973#endif
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
976}
977
978static int
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
980{
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void * const *table = rb_vm_get_insns_address_table();
983 unsigned int i;
984 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
985
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (VALUE)table[insn];
990 i += len;
991 }
992 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
993#endif
994
995#if USE_YJIT
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
998#endif
999
1000 return COMPILE_OK;
1001}
1002
1003VALUE *
1004rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
1005{
1006 VALUE *original_code;
1007
1008 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
1011
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1013 {
1014 unsigned int i;
1015
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
1017 const void *addr = (const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1019
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1022 }
1023 }
1024#endif
1025 return original_code;
1026}
1027
1028/*********************************************/
1029/* definition of data structure for compiler */
1030/*********************************************/
1031
1032/*
1033 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1034 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1035 * generate SPARCV8PLUS code with unaligned memory access instructions.
1036 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1037 */
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1040#endif
1041
1042/*
1043 * Some OpenBSD platforms (including sparc64) require strict alignment.
1044 */
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1049 #endif
1050#endif
1051
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1055 #else
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1057 #endif
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1061#else
1062 #define PADDING_SIZE_MAX 0
1063#endif /* STRICT_ALIGNMENT */
1064
1065#ifdef STRICT_ALIGNMENT
1066/* calculate padding size for aligned memory access */
1067static size_t
1068calc_padding(void *ptr, size_t size)
1069{
1070 size_t mis;
1071 size_t padding = 0;
1072
1073 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1074 if (mis > 0) {
1075 padding = ALIGNMENT_SIZE - mis;
1076 }
1077/*
1078 * On 32-bit sparc or equivalents, when a single VALUE is requested
1079 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1080 */
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
1083 padding = 0;
1084 }
1085#endif
1086
1087 return padding;
1088}
1089#endif /* STRICT_ALIGNMENT */
1090
1091static void *
1092compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
1093{
1094 void *ptr = 0;
1095 struct iseq_compile_data_storage *storage = *arena;
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
1098#else
1099 const size_t padding = 0; /* expected to be optimized by compiler */
1100#endif /* STRICT_ALIGNMENT */
1101
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1105
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1108 alloc_size *= 2;
1109 }
1110 storage->next = (void *)ALLOC_N(char, alloc_size +
1111 offsetof(struct iseq_compile_data_storage, buff));
1112 storage = *arena = storage->next;
1113 storage->next = 0;
1114 storage->pos = 0;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((void *)&storage->buff[storage->pos], size);
1118#endif /* STRICT_ALIGNMENT */
1119 }
1120
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1123#endif /* STRICT_ALIGNMENT */
1124
1125 ptr = (void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1127 return ptr;
1128}
1129
1130static void *
1131compile_data_alloc(rb_iseq_t *iseq, size_t size)
1132{
1133 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1134 return compile_data_alloc_with_arena(arena, size);
1135}
1136
1137static inline void *
1138compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1139{
1140 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1141 return compile_data_alloc(iseq, size);
1142}
1143
1144static inline void *
1145compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1146{
1147 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1148 void *p = compile_data_alloc(iseq, size);
1149 memset(p, 0, size);
1150 return p;
1151}
1152
1153static INSN *
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1155{
1156 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1157 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1158}
1159
1160static LABEL *
1161compile_data_alloc_label(rb_iseq_t *iseq)
1162{
1163 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1164}
1165
1166static ADJUST *
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1168{
1169 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1170}
1171
1172static TRACE *
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1174{
1175 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1176}
1177
1178/*
1179 * elem1, elemX => elem1, elem2, elemX
1180 */
1181static void
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1183{
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1187 if (elem2->next) {
1188 elem2->next->prev = elem2;
1189 }
1190}
1191
1192/*
1193 * elem1, elemX => elemX, elem2, elem1
1194 */
1195static void
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1197{
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1201 if (elem2->prev) {
1202 elem2->prev->next = elem2;
1203 }
1204}
1205
1206/*
1207 * elemX, elem1, elemY => elemX, elem2, elemY
1208 */
1209static void
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1211{
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1214 if (elem1->prev) {
1215 elem1->prev->next = elem2;
1216 }
1217 if (elem1->next) {
1218 elem1->next->prev = elem2;
1219 }
1220}
1221
1222static void
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1224{
1225 elem->prev->next = elem->next;
1226 if (elem->next) {
1227 elem->next->prev = elem->prev;
1228 }
1229}
1230
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1233{
1234 return anchor->anchor.next;
1235}
1236
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *const anchor)
1239{
1240 return anchor->last;
1241}
1242
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245{
1246 while (elem) {
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1250 return elem;
1251 default:
1252 elem = elem->next;
1253 }
1254 }
1255 return NULL;
1256}
1257
1258static int
1259LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1260{
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1264 return TRUE;
1265 }
1266 else {
1267 return FALSE;
1268 }
1269}
1270
1271static int
1272LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1273{
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1275 return TRUE;
1276 }
1277 else {
1278 return FALSE;
1279 }
1280}
1281
1282/*
1283 * anc1: e1, e2, e3
1284 * anc2: e4, e5
1285 *#=>
1286 * anc1: e1, e2, e3, e4, e5
1287 * anc2: e4, e5 (broken)
1288 */
1289static void
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1291{
1292 if (anc2->anchor.next) {
1293 /* LINK_ANCHOR must not loop */
1294 RUBY_ASSERT(anc2->last != &anc2->anchor);
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1298 }
1299 else {
1300 RUBY_ASSERT(anc2->last == &anc2->anchor);
1301 }
1302 verify_list("append", anc1);
1303}
1304#if CPDEBUG < 0
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1306#endif
1307
1308#if CPDEBUG && 0
1309static void
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1311{
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1313 printf("----\n");
1314 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1315 (void *)anchor->anchor.next, (void *)anchor->last);
1316 while (list) {
1317 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1318 (void *)list->prev, (int)list->type);
1319 list = list->next;
1320 }
1321 printf("----\n");
1322
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list("debug list", anchor);
1325}
1326#if CPDEBUG < 0
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#endif
1329#else
1330#define debug_list(anc, cur) ((void)0)
1331#endif
1332
1333static TRACE *
1334new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1335{
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1337
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1341 trace->data = data;
1342
1343 return trace;
1344}
1345
1346static LABEL *
1347new_label_body(rb_iseq_t *iseq, long line)
1348{
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1350
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1353
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1356 labelobj->sp = -1;
1357 labelobj->refcnt = 0;
1358 labelobj->set = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1362 return labelobj;
1363}
1364
1365static ADJUST *
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1367{
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1374 return adjust;
1375}
1376
1377static void
1378iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1379{
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (int j = 0; types[j]; j++) {
1382 char type = types[j];
1383 switch (type) {
1384 case TS_CDHASH:
1385 case TS_ISEQ:
1386 case TS_VALUE:
1387 case TS_IC: // constant path array
1388 case TS_CALLDATA: // ci is stored.
1389 func(&OPERAND_AT(insn, j), data);
1390 break;
1391 default:
1392 break;
1393 }
1394 }
1395}
1396
1397static void
1398iseq_insn_each_object_write_barrier(VALUE * obj, VALUE iseq)
1399{
1400 RB_OBJ_WRITTEN(iseq, Qundef, *obj);
1401}
1402
1403static INSN *
1404new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
1405{
1406 INSN *iobj = compile_data_alloc_insn(iseq);
1407
1408 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1409
1410 iobj->link.type = ISEQ_ELEMENT_INSN;
1411 iobj->link.next = 0;
1412 iobj->insn_id = insn_id;
1413 iobj->insn_info.line_no = line_no;
1414 iobj->insn_info.node_id = node_id;
1415 iobj->insn_info.events = 0;
1416 iobj->operands = argv;
1417 iobj->operand_size = argc;
1418 iobj->sc_state = 0;
1419
1420 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1421
1422 return iobj;
1423}
1424
1425static INSN *
1426new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
1427{
1428 VALUE *operands = 0;
1429 va_list argv;
1430 if (argc > 0) {
1431 int i;
1432 va_start(argv, argc);
1433 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1434 for (i = 0; i < argc; i++) {
1435 VALUE v = va_arg(argv, VALUE);
1436 operands[i] = v;
1437 }
1438 va_end(argv);
1439 }
1440 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1441}
1442
1443static INSN *
1444insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj, enum ruby_vminsn_type insn_id, int argc, ...)
1445{
1446 VALUE *operands = 0;
1447 va_list argv;
1448 if (argc > 0) {
1449 int i;
1450 va_start(argv, argc);
1451 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1452 for (i = 0; i < argc; i++) {
1453 VALUE v = va_arg(argv, VALUE);
1454 operands[i] = v;
1455 }
1456 va_end(argv);
1457 }
1458
1459 iobj->insn_id = insn_id;
1460 iobj->operand_size = argc;
1461 iobj->operands = operands;
1462 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1463
1464 return iobj;
1465}
1466
1467static const struct rb_callinfo *
1468new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1469{
1470 VM_ASSERT(argc >= 0);
1471
1472 if (kw_arg) {
1473 flag |= VM_CALL_KWARG;
1474 argc += kw_arg->keyword_len;
1475 }
1476
1477 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1478 && !has_blockiseq) {
1479 flag |= VM_CALL_ARGS_SIMPLE;
1480 }
1481
1482 ISEQ_BODY(iseq)->ci_size++;
1483 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1484 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1485 return ci;
1486}
1487
1488static INSN *
1489new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1490{
1491 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1492 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1493 operands[0] = ci;
1494 operands[1] = (VALUE)blockiseq;
1495 if (blockiseq) {
1496 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1497 }
1498
1499 INSN *insn;
1500
1501 if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1502 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1503 }
1504 else {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1506 }
1507
1508 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1509 RB_GC_GUARD(ci);
1510 return insn;
1511}
1512
1513static rb_iseq_t *
1514new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1515 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1516{
1517 rb_iseq_t *ret_iseq;
1518 VALUE ast_value = rb_ruby_ast_new(node);
1519
1520 debugs("[new_child_iseq]> ---------------------------------------\n");
1521 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1522 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1523 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1524 line_no, parent,
1525 isolated_depth ? isolated_depth + 1 : 0,
1526 type, ISEQ_COMPILE_DATA(iseq)->option,
1527 ISEQ_BODY(iseq)->variable.script_lines);
1528 debugs("[new_child_iseq]< ---------------------------------------\n");
1529 return ret_iseq;
1530}
1531
1532static rb_iseq_t *
1533new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1534 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1535{
1536 rb_iseq_t *ret_iseq;
1537
1538 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1539 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1540 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1541 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1542 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1543 return ret_iseq;
1544}
1545
1546static void
1547set_catch_except_p(rb_iseq_t *iseq)
1548{
1549 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1550 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1551 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1552 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1553 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1554 }
1555 }
1556}
1557
1558/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1559 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1560 if catch table exists. But we want to optimize while loop, which always has catch
1561 table entries for break/next/redo.
1562
1563 So this function sets true for limited ISeqs with break/next/redo catch table entries
1564 whose child ISeq would really raise an exception. */
1565static void
1566update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
1567{
1568 unsigned int pos;
1569 size_t i;
1570 int insn;
1571 const struct iseq_catch_table *ct = body->catch_table;
1572
1573 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1574 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1575 pos = 0;
1576 while (pos < body->iseq_size) {
1577 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1578 if (insn == BIN(throw)) {
1579 set_catch_except_p(iseq);
1580 break;
1581 }
1582 pos += insn_len(insn);
1583 }
1584
1585 if (ct == NULL)
1586 return;
1587
1588 for (i = 0; i < ct->size; i++) {
1589 const struct iseq_catch_table_entry *entry =
1590 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1591 if (entry->type != CATCH_TYPE_BREAK
1592 && entry->type != CATCH_TYPE_NEXT
1593 && entry->type != CATCH_TYPE_REDO) {
1594 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1595 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
1596 break;
1597 }
1598 }
1599}
1600
1601static void
1602iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1603{
1604 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1605 if (NIL_P(catch_table_ary)) return;
1606 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1607 const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
1608 for (i = 0; i < tlen; i++) {
1609 const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
1610 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1611 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1612 LINK_ELEMENT *e;
1613
1614 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1615
1616 if (ct != CATCH_TYPE_BREAK
1617 && ct != CATCH_TYPE_NEXT
1618 && ct != CATCH_TYPE_REDO) {
1619
1620 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1621 if (e == cont) {
1622 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1623 ELEM_INSERT_NEXT(end, &nop->link);
1624 break;
1625 }
1626 }
1627 }
1628 }
1629
1630 RB_GC_GUARD(catch_table_ary);
1631}
1632
1633static int
1634iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1635{
1636 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1637 return COMPILE_NG;
1638
1639 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1640
1641 if (compile_debug > 5)
1642 dump_disasm_list(FIRST_ELEMENT(anchor));
1643
1644 debugs("[compile step 3.1 (iseq_optimize)]\n");
1645 iseq_optimize(iseq, anchor);
1646
1647 if (compile_debug > 5)
1648 dump_disasm_list(FIRST_ELEMENT(anchor));
1649
1650 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1651 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1652 iseq_insns_unification(iseq, anchor);
1653 if (compile_debug > 5)
1654 dump_disasm_list(FIRST_ELEMENT(anchor));
1655 }
1656
1657 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1658 iseq_insert_nop_between_end_and_cont(iseq);
1659 if (compile_debug > 5)
1660 dump_disasm_list(FIRST_ELEMENT(anchor));
1661
1662 return COMPILE_OK;
1663}
1664
1665static int
1666iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1667{
1668 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1669 return COMPILE_NG;
1670
1671 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1672 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1673 if (compile_debug > 5)
1674 dump_disasm_list(FIRST_ELEMENT(anchor));
1675
1676 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1677 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1678
1679 debugs("[compile step 4.3 (set_optargs_table)] \n");
1680 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1681
1682 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1683 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1684
1685 debugs("[compile step 6 (update_catch_except_flags)] \n");
1686 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1687 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1688
1689 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1690 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
1691 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1692 xfree(ISEQ_BODY(iseq)->catch_table);
1693 ISEQ_BODY(iseq)->catch_table = NULL;
1694 }
1695
1696#if VM_INSN_INFO_TABLE_IMPL == 2
1697 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1698 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1699 rb_iseq_insns_info_encode_positions(iseq);
1700 }
1701#endif
1702
1703 if (compile_debug > 1) {
1704 VALUE str = rb_iseq_disasm(iseq);
1705 printf("%s\n", StringValueCStr(str));
1706 }
1707 verify_call_cache(iseq);
1708 debugs("[compile step: finish]\n");
1709
1710 return COMPILE_OK;
1711}
1712
1713static int
1714iseq_set_exception_local_table(rb_iseq_t *iseq)
1715{
1716 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1717 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1718 return COMPILE_OK;
1719}
1720
1721static int
1722get_lvar_level(const rb_iseq_t *iseq)
1723{
1724 int lev = 0;
1725 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1726 lev++;
1727 iseq = ISEQ_BODY(iseq)->parent_iseq;
1728 }
1729 return lev;
1730}
1731
1732static int
1733get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1734{
1735 unsigned int i;
1736
1737 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1738 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1739 return (int)i;
1740 }
1741 }
1742 return -1;
1743}
1744
1745static int
1746get_local_var_idx(const rb_iseq_t *iseq, ID id)
1747{
1748 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1749
1750 if (idx < 0) {
1751 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1752 "get_local_var_idx: %d", idx);
1753 }
1754
1755 return idx;
1756}
1757
1758static int
1759get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1760{
1761 int lv = 0, idx = -1;
1762 const rb_iseq_t *const topmost_iseq = iseq;
1763
1764 while (iseq) {
1765 idx = get_dyna_var_idx_at_raw(iseq, id);
1766 if (idx >= 0) {
1767 break;
1768 }
1769 iseq = ISEQ_BODY(iseq)->parent_iseq;
1770 lv++;
1771 }
1772
1773 if (idx < 0) {
1774 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1775 "get_dyna_var_idx: -1");
1776 }
1777
1778 *level = lv;
1779 *ls = ISEQ_BODY(iseq)->local_table_size;
1780 return idx;
1781}
1782
1783static int
1784iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1785{
1786 const struct rb_iseq_constant_body *body;
1787 while (level > 0) {
1788 iseq = ISEQ_BODY(iseq)->parent_iseq;
1789 level--;
1790 }
1791 body = ISEQ_BODY(iseq);
1792 if (body->local_iseq == iseq && /* local variables */
1793 body->param.flags.has_block &&
1794 body->local_table_size - body->param.block_start == idx) {
1795 return TRUE;
1796 }
1797 else {
1798 return FALSE;
1799 }
1800}
1801
1802static int
1803iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1804{
1805 int level, ls;
1806 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1807 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1808 *pidx = ls - idx;
1809 *plevel = level;
1810 return TRUE;
1811 }
1812 else {
1813 return FALSE;
1814 }
1815}
1816
1817static void
1818access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1819{
1820 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1821
1822 if (isolated_depth && level >= isolated_depth) {
1823 if (id == rb_intern("yield")) {
1824 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1825 }
1826 else {
1827 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
1828 }
1829 }
1830
1831 for (int i=0; i<level; i++) {
1832 VALUE val;
1833 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1834
1835 if (!ovs) {
1836 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1837 }
1838
1839 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1840 if (write && !val) {
1841 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1842 }
1843 }
1844 else {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1846 }
1847
1848 iseq = ISEQ_BODY(iseq)->parent_iseq;
1849 }
1850}
1851
1852static ID
1853iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1854{
1855 for (int i=0; i<level; i++) {
1856 iseq = ISEQ_BODY(iseq)->parent_iseq;
1857 }
1858
1859 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1860 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1861 return id;
1862}
1863
1864static void
1865iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1866{
1867 if (iseq_local_block_param_p(iseq, idx, level)) {
1868 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1869 }
1870 else {
1871 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1872 }
1873 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1874}
1875
1876static void
1877iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1878{
1879 if (iseq_local_block_param_p(iseq, idx, level)) {
1880 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1881 }
1882 else {
1883 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1884 }
1885 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1886}
1887
1888
1889
1890static void
1891iseq_calc_param_size(rb_iseq_t *iseq)
1892{
1893 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1894 if (body->param.flags.has_opt ||
1895 body->param.flags.has_post ||
1896 body->param.flags.has_rest ||
1897 body->param.flags.has_block ||
1898 body->param.flags.has_kw ||
1899 body->param.flags.has_kwrest) {
1900
1901 if (body->param.flags.has_block) {
1902 body->param.size = body->param.block_start + 1;
1903 }
1904 else if (body->param.flags.has_kwrest) {
1905 body->param.size = body->param.keyword->rest_start + 1;
1906 }
1907 else if (body->param.flags.has_kw) {
1908 body->param.size = body->param.keyword->bits_start + 1;
1909 }
1910 else if (body->param.flags.has_post) {
1911 body->param.size = body->param.post_start + body->param.post_num;
1912 }
1913 else if (body->param.flags.has_rest) {
1914 body->param.size = body->param.rest_start + 1;
1915 }
1916 else if (body->param.flags.has_opt) {
1917 body->param.size = body->param.lead_num + body->param.opt_num;
1918 }
1919 else {
1921 }
1922 }
1923 else {
1924 body->param.size = body->param.lead_num;
1925 }
1926}
1927
1928static int
1929iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1930 const struct rb_args_info *args, int arg_size)
1931{
1932 const rb_node_kw_arg_t *node = args->kw_args;
1933 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1934 struct rb_iseq_param_keyword *keyword;
1935 const VALUE default_values = rb_ary_hidden_new(1);
1936 const VALUE complex_mark = rb_str_tmp_new(0);
1937 int kw = 0, rkw = 0, di = 0, i;
1938
1939 body->param.flags.has_kw = TRUE;
1940 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1941
1942 while (node) {
1943 kw++;
1944 node = node->nd_next;
1945 }
1946 arg_size += kw;
1947 keyword->bits_start = arg_size++;
1948
1949 node = args->kw_args;
1950 while (node) {
1951 const NODE *val_node = get_nd_value(node->nd_body);
1952 VALUE dv;
1953
1954 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1955 ++rkw;
1956 }
1957 else {
1958 switch (nd_type(val_node)) {
1959 case NODE_SYM:
1960 dv = rb_node_sym_string_val(val_node);
1961 break;
1962 case NODE_REGX:
1963 dv = rb_node_regx_string_val(val_node);
1964 break;
1965 case NODE_LINE:
1966 dv = rb_node_line_lineno_val(val_node);
1967 break;
1968 case NODE_INTEGER:
1969 dv = rb_node_integer_literal_val(val_node);
1970 break;
1971 case NODE_FLOAT:
1972 dv = rb_node_float_literal_val(val_node);
1973 break;
1974 case NODE_RATIONAL:
1975 dv = rb_node_rational_literal_val(val_node);
1976 break;
1977 case NODE_IMAGINARY:
1978 dv = rb_node_imaginary_literal_val(val_node);
1979 break;
1980 case NODE_ENCODING:
1981 dv = rb_node_encoding_val(val_node);
1982 break;
1983 case NODE_NIL:
1984 dv = Qnil;
1985 break;
1986 case NODE_TRUE:
1987 dv = Qtrue;
1988 break;
1989 case NODE_FALSE:
1990 dv = Qfalse;
1991 break;
1992 default:
1993 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
1994 dv = complex_mark;
1995 }
1996
1997 keyword->num = ++di;
1998 rb_ary_push(default_values, dv);
1999 }
2000
2001 node = node->nd_next;
2002 }
2003
2004 keyword->num = kw;
2005
2006 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2007 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2008 keyword->rest_start = arg_size++;
2009 body->param.flags.has_kwrest = TRUE;
2010
2011 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2012 }
2013 keyword->required_num = rkw;
2014 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2015
2016 if (RARRAY_LEN(default_values)) {
2017 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
2018
2019 for (i = 0; i < RARRAY_LEN(default_values); i++) {
2020 VALUE dv = RARRAY_AREF(default_values, i);
2021 if (dv == complex_mark) dv = Qundef;
2022 RB_OBJ_WRITE(iseq, &dvs[i], dv);
2023 }
2024
2025 keyword->default_values = dvs;
2026 }
2027 return arg_size;
2028}
2029
2030static void
2031iseq_set_use_block(rb_iseq_t *iseq)
2032{
2033 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2034 if (!body->param.flags.use_block) {
2035 body->param.flags.use_block = 1;
2036
2037 rb_vm_t *vm = GET_VM();
2038
2039 if (!rb_warning_category_enabled_p(RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK)) {
2040 st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
2041 set_insert(vm->unused_block_warning_table, key);
2042 }
2043 }
2044}
2045
2046static int
2047iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
2048{
2049 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
2050
2051 if (node_args) {
2052 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2053 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2054 ID rest_id = 0;
2055 int last_comma = 0;
2056 ID block_id = 0;
2057 int arg_size;
2058
2059 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2060
2061 body->param.flags.ruby2_keywords = args->ruby2_keywords;
2062 body->param.lead_num = arg_size = (int)args->pre_args_num;
2063 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2064 debugs(" - argc: %d\n", body->param.lead_num);
2065
2066 rest_id = args->rest_arg;
2067 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2068 last_comma = 1;
2069 rest_id = 0;
2070 }
2071 block_id = args->block_arg;
2072
2073 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2074
2075 if (optimized_forward) {
2076 rest_id = 0;
2077 block_id = 0;
2078 }
2079
2080 if (args->opt_args) {
2081 const rb_node_opt_arg_t *node = args->opt_args;
2082 LABEL *label;
2083 VALUE labels = rb_ary_hidden_new(1);
2084 VALUE *opt_table;
2085 int i = 0, j;
2086
2087 while (node) {
2088 label = NEW_LABEL(nd_line(RNODE(node)));
2089 rb_ary_push(labels, (VALUE)label | 1);
2090 ADD_LABEL(optargs, label);
2091 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
2092 node = node->nd_next;
2093 i += 1;
2094 }
2095
2096 /* last label */
2097 label = NEW_LABEL(nd_line(node_args));
2098 rb_ary_push(labels, (VALUE)label | 1);
2099 ADD_LABEL(optargs, label);
2100
2101 opt_table = ALLOC_N(VALUE, i+1);
2102
2103 MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
2104 for (j = 0; j < i+1; j++) {
2105 opt_table[j] &= ~1;
2106 }
2107 rb_ary_clear(labels);
2108
2109 body->param.flags.has_opt = TRUE;
2110 body->param.opt_num = i;
2111 body->param.opt_table = opt_table;
2112 arg_size += i;
2113 }
2114
2115 if (rest_id) {
2116 body->param.rest_start = arg_size++;
2117 body->param.flags.has_rest = TRUE;
2118 if (rest_id == '*') body->param.flags.anon_rest = TRUE;
2119 RUBY_ASSERT(body->param.rest_start != -1);
2120 }
2121
2122 if (args->first_post_arg) {
2123 body->param.post_start = arg_size;
2124 body->param.post_num = args->post_args_num;
2125 body->param.flags.has_post = TRUE;
2126 arg_size += args->post_args_num;
2127
2128 if (body->param.flags.has_rest) { /* TODO: why that? */
2129 body->param.post_start = body->param.rest_start + 1;
2130 }
2131 }
2132
2133 if (args->kw_args) {
2134 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2135 }
2136 else if (args->kw_rest_arg && !optimized_forward) {
2137 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2138 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
2139 keyword->rest_start = arg_size++;
2140 body->param.keyword = keyword;
2141 body->param.flags.has_kwrest = TRUE;
2142
2143 static ID anon_kwrest = 0;
2144 if (!anon_kwrest) anon_kwrest = rb_intern("**");
2145 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2146 }
2147 else if (args->no_kwarg) {
2148 body->param.flags.accepts_no_kwarg = TRUE;
2149 }
2150
2151 if (block_id) {
2152 body->param.block_start = arg_size++;
2153 body->param.flags.has_block = TRUE;
2154 iseq_set_use_block(iseq);
2155 }
2156
2157 // Only optimize specifically methods like this: `foo(...)`
2158 if (optimized_forward) {
2159 body->param.flags.use_block = 1;
2160 body->param.flags.forwardable = TRUE;
2161 arg_size = 1;
2162 }
2163
2164 iseq_calc_param_size(iseq);
2165 body->param.size = arg_size;
2166
2167 if (args->pre_init) { /* m_init */
2168 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
2169 }
2170 if (args->post_init) { /* p_init */
2171 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
2172 }
2173
2174 if (body->type == ISEQ_TYPE_BLOCK) {
2175 if (body->param.flags.has_opt == FALSE &&
2176 body->param.flags.has_post == FALSE &&
2177 body->param.flags.has_rest == FALSE &&
2178 body->param.flags.has_kw == FALSE &&
2179 body->param.flags.has_kwrest == FALSE) {
2180
2181 if (body->param.lead_num == 1 && last_comma == 0) {
2182 /* {|a|} */
2183 body->param.flags.ambiguous_param0 = TRUE;
2184 }
2185 }
2186 }
2187 }
2188
2189 return COMPILE_OK;
2190}
2191
2192static int
2193iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
2194{
2195 unsigned int size = tbl ? tbl->size : 0;
2196 unsigned int offset = 0;
2197
2198 if (node_args) {
2199 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2200
2201 // If we have a function that only has `...` as the parameter,
2202 // then its local table should only be `...`
2203 // FIXME: I think this should be fixed in the AST rather than special case here.
2204 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2205 CHECK(size >= 3);
2206 size -= 3;
2207 offset += 3;
2208 }
2209 }
2210
2211 if (size > 0) {
2212 ID *ids = ALLOC_N(ID, size);
2213 MEMCPY(ids, tbl->ids + offset, ID, size);
2214 ISEQ_BODY(iseq)->local_table = ids;
2215 }
2216 ISEQ_BODY(iseq)->local_table_size = size;
2217
2218 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2219 return COMPILE_OK;
2220}
2221
2222int
2223rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
2224{
2225 int tval, tlit;
2226
2227 if (val == lit) {
2228 return 0;
2229 }
2230 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2231 return val != lit;
2232 }
2233 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2234 return -1;
2235 }
2236 else if (tlit != tval) {
2237 return -1;
2238 }
2239 else if (tlit == T_SYMBOL) {
2240 return val != lit;
2241 }
2242 else if (tlit == T_STRING) {
2243 return rb_str_hash_cmp(lit, val);
2244 }
2245 else if (tlit == T_BIGNUM) {
2246 long x = FIX2LONG(rb_big_cmp(lit, val));
2247
2248 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2249 * There is no need to call rb_fix2int here. */
2250 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2251 return (int)x;
2252 }
2253 else if (tlit == T_FLOAT) {
2254 return rb_float_cmp(lit, val);
2255 }
2256 else if (tlit == T_RATIONAL) {
2257 const struct RRational *rat1 = RRATIONAL(val);
2258 const struct RRational *rat2 = RRATIONAL(lit);
2259 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2260 }
2261 else if (tlit == T_COMPLEX) {
2262 const struct RComplex *comp1 = RCOMPLEX(val);
2263 const struct RComplex *comp2 = RCOMPLEX(lit);
2264 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2265 }
2266 else if (tlit == T_REGEXP) {
2267 return rb_reg_equal(val, lit) ? 0 : -1;
2268 }
2269 else {
2271 }
2272}
2273
2274st_index_t
2275rb_iseq_cdhash_hash(VALUE a)
2276{
2277 switch (OBJ_BUILTIN_TYPE(a)) {
2278 case -1:
2279 case T_SYMBOL:
2280 return (st_index_t)a;
2281 case T_STRING:
2282 return rb_str_hash(a);
2283 case T_BIGNUM:
2284 return FIX2LONG(rb_big_hash(a));
2285 case T_FLOAT:
2286 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2287 case T_RATIONAL:
2288 return rb_rational_hash(a);
2289 case T_COMPLEX:
2290 return rb_complex_hash(a);
2291 case T_REGEXP:
2292 return NUM2LONG(rb_reg_hash(a));
2293 default:
2295 }
2296}
2297
2298static const struct st_hash_type cdhash_type = {
2299 rb_iseq_cdhash_cmp,
2300 rb_iseq_cdhash_hash,
2301};
2302
2304 VALUE hash;
2305 int pos;
2306 int len;
2307};
2308
2309static int
2310cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2311{
2312 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2313 LABEL *lobj = (LABEL *)(val & ~1);
2314 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2315 return ST_CONTINUE;
2316}
2317
2318
2319static inline VALUE
2320get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2321{
2322 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2323}
2324
2325static inline VALUE
2326get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2327{
2328 VALUE val;
2329 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2330 if (tbl) {
2331 if (rb_id_table_lookup(tbl,id,&val)) {
2332 return val;
2333 }
2334 }
2335 else {
2336 tbl = rb_id_table_create(1);
2337 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2338 }
2339 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2340 rb_id_table_insert(tbl,id,val);
2341 return val;
2342}
2343
2344#define BADINSN_DUMP(anchor, list, dest) \
2345 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2346
2347#define BADINSN_ERROR \
2348 (xfree(generated_iseq), \
2349 xfree(insns_info), \
2350 BADINSN_DUMP(anchor, list, NULL), \
2351 COMPILE_ERROR)
2352
2353static int
2354fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2355{
2356 int stack_max = 0, sp = 0, line = 0;
2357 LINK_ELEMENT *list;
2358
2359 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2360 if (IS_LABEL(list)) {
2361 LABEL *lobj = (LABEL *)list;
2362 lobj->set = TRUE;
2363 }
2364 }
2365
2366 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2367 switch (list->type) {
2368 case ISEQ_ELEMENT_INSN:
2369 {
2370 int j, len, insn;
2371 const char *types;
2372 VALUE *operands;
2373 INSN *iobj = (INSN *)list;
2374
2375 /* update sp */
2376 sp = calc_sp_depth(sp, iobj);
2377 if (sp < 0) {
2378 BADINSN_DUMP(anchor, list, NULL);
2379 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2380 "argument stack underflow (%d)", sp);
2381 return -1;
2382 }
2383 if (sp > stack_max) {
2384 stack_max = sp;
2385 }
2386
2387 line = iobj->insn_info.line_no;
2388 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2389 operands = iobj->operands;
2390 insn = iobj->insn_id;
2391 types = insn_op_types(insn);
2392 len = insn_len(insn);
2393
2394 /* operand check */
2395 if (iobj->operand_size != len - 1) {
2396 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2397 BADINSN_DUMP(anchor, list, NULL);
2398 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2399 "operand size miss! (%d for %d)",
2400 iobj->operand_size, len - 1);
2401 return -1;
2402 }
2403
2404 for (j = 0; types[j]; j++) {
2405 if (types[j] == TS_OFFSET) {
2406 /* label(destination position) */
2407 LABEL *lobj = (LABEL *)operands[j];
2408 if (!lobj->set) {
2409 BADINSN_DUMP(anchor, list, NULL);
2410 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2411 "unknown label: "LABEL_FORMAT, lobj->label_no);
2412 return -1;
2413 }
2414 if (lobj->sp == -1) {
2415 lobj->sp = sp;
2416 }
2417 else if (lobj->sp != sp) {
2418 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2419 RSTRING_PTR(rb_iseq_path(iseq)), line,
2420 lobj->label_no, lobj->sp, sp);
2421 }
2422 }
2423 }
2424 break;
2425 }
2426 case ISEQ_ELEMENT_LABEL:
2427 {
2428 LABEL *lobj = (LABEL *)list;
2429 if (lobj->sp == -1) {
2430 lobj->sp = sp;
2431 }
2432 else {
2433 if (lobj->sp != sp) {
2434 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2435 RSTRING_PTR(rb_iseq_path(iseq)), line,
2436 lobj->label_no, lobj->sp, sp);
2437 }
2438 sp = lobj->sp;
2439 }
2440 break;
2441 }
2442 case ISEQ_ELEMENT_TRACE:
2443 {
2444 /* ignore */
2445 break;
2446 }
2447 case ISEQ_ELEMENT_ADJUST:
2448 {
2449 ADJUST *adjust = (ADJUST *)list;
2450 int orig_sp = sp;
2451
2452 sp = adjust->label ? adjust->label->sp : 0;
2453 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2454 BADINSN_DUMP(anchor, list, NULL);
2455 COMPILE_ERROR(iseq, adjust->line_no,
2456 "iseq_set_sequence: adjust bug %d < %d",
2457 orig_sp, sp);
2458 return -1;
2459 }
2460 break;
2461 }
2462 default:
2463 BADINSN_DUMP(anchor, list, NULL);
2464 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2465 return -1;
2466 }
2467 }
2468 return stack_max;
2469}
2470
2471static int
2472add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2473 int insns_info_index, int code_index, const INSN *iobj)
2474{
2475 if (insns_info_index == 0 ||
2476 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2477#ifdef USE_ISEQ_NODE_ID
2478 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2479#endif
2480 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2481 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2482#ifdef USE_ISEQ_NODE_ID
2483 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2484#endif
2485 insns_info[insns_info_index].events = iobj->insn_info.events;
2486 positions[insns_info_index] = code_index;
2487 return TRUE;
2488 }
2489 return FALSE;
2490}
2491
2492static int
2493add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2494 int insns_info_index, int code_index, const ADJUST *adjust)
2495{
2496 insns_info[insns_info_index].line_no = adjust->line_no;
2497 insns_info[insns_info_index].node_id = -1;
2498 insns_info[insns_info_index].events = 0;
2499 positions[insns_info_index] = code_index;
2500 return TRUE;
2501}
2502
2503static ID *
2504array_to_idlist(VALUE arr)
2505{
2507 long size = RARRAY_LEN(arr);
2508 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2509 for (long i = 0; i < size; i++) {
2510 VALUE sym = RARRAY_AREF(arr, i);
2511 ids[i] = SYM2ID(sym);
2512 }
2513 ids[size] = 0;
2514 return ids;
2515}
2516
2517static VALUE
2518idlist_to_array(const ID *ids)
2519{
2520 VALUE arr = rb_ary_new();
2521 while (*ids) {
2522 rb_ary_push(arr, ID2SYM(*ids++));
2523 }
2524 return arr;
2525}
2526
2530static int
2531iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2532{
2533 struct iseq_insn_info_entry *insns_info;
2534 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2535 unsigned int *positions;
2536 LINK_ELEMENT *list;
2537 VALUE *generated_iseq;
2538 rb_event_flag_t events = 0;
2539 long data = 0;
2540
2541 int insn_num, code_index, insns_info_index, sp = 0;
2542 int stack_max = fix_sp_depth(iseq, anchor);
2543
2544 if (stack_max < 0) return COMPILE_NG;
2545
2546 /* fix label position */
2547 insn_num = code_index = 0;
2548 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2549 switch (list->type) {
2550 case ISEQ_ELEMENT_INSN:
2551 {
2552 INSN *iobj = (INSN *)list;
2553 /* update sp */
2554 sp = calc_sp_depth(sp, iobj);
2555 insn_num++;
2556 events = iobj->insn_info.events |= events;
2557 if (ISEQ_COVERAGE(iseq)) {
2558 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2559 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2560 int line = iobj->insn_info.line_no - 1;
2561 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2562 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2563 }
2564 }
2565 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2566 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2567 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2568 }
2569 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2570 }
2571 }
2572 code_index += insn_data_length(iobj);
2573 events = 0;
2574 data = 0;
2575 break;
2576 }
2577 case ISEQ_ELEMENT_LABEL:
2578 {
2579 LABEL *lobj = (LABEL *)list;
2580 lobj->position = code_index;
2581 if (lobj->sp != sp) {
2582 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2583 RSTRING_PTR(rb_iseq_path(iseq)),
2584 lobj->label_no, lobj->sp, sp);
2585 }
2586 sp = lobj->sp;
2587 break;
2588 }
2589 case ISEQ_ELEMENT_TRACE:
2590 {
2591 TRACE *trace = (TRACE *)list;
2592 events |= trace->event;
2593 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2594 break;
2595 }
2596 case ISEQ_ELEMENT_ADJUST:
2597 {
2598 ADJUST *adjust = (ADJUST *)list;
2599 if (adjust->line_no != -1) {
2600 int orig_sp = sp;
2601 sp = adjust->label ? adjust->label->sp : 0;
2602 if (orig_sp - sp > 0) {
2603 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2604 code_index++; /* insn */
2605 insn_num++;
2606 }
2607 }
2608 break;
2609 }
2610 default: break;
2611 }
2612 }
2613
2614 /* make instruction sequence */
2615 generated_iseq = ALLOC_N(VALUE, code_index);
2616 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2617 positions = ALLOC_N(unsigned int, insn_num);
2618 if (ISEQ_IS_SIZE(body)) {
2619 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2620 }
2621 else {
2622 body->is_entries = NULL;
2623 }
2624
2625 if (body->ci_size) {
2626 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2627 }
2628 else {
2629 body->call_data = NULL;
2630 }
2631 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2632
2633 // Calculate the bitmask buffer size.
2634 // Round the generated_iseq size up to the nearest multiple
2635 // of the number of bits in an unsigned long.
2636
2637 // Allocate enough room for the bitmask list
2638 iseq_bits_t * mark_offset_bits;
2639 int code_size = code_index;
2640
2641 bool needs_bitmap = false;
2642
2643 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2644 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2645 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = true;
2646 }
2647 else {
2648 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2649 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2650 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit = false;
2651 }
2652
2653 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (void *)generated_iseq;
2654 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2655
2656 list = FIRST_ELEMENT(anchor);
2657 insns_info_index = code_index = sp = 0;
2658
2659 while (list) {
2660 switch (list->type) {
2661 case ISEQ_ELEMENT_INSN:
2662 {
2663 int j, len, insn;
2664 const char *types;
2665 VALUE *operands;
2666 INSN *iobj = (INSN *)list;
2667
2668 /* update sp */
2669 sp = calc_sp_depth(sp, iobj);
2670 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2671 operands = iobj->operands;
2672 insn = iobj->insn_id;
2673 generated_iseq[code_index] = insn;
2674 types = insn_op_types(insn);
2675 len = insn_len(insn);
2676
2677 for (j = 0; types[j]; j++) {
2678 char type = types[j];
2679
2680 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2681 switch (type) {
2682 case TS_OFFSET:
2683 {
2684 /* label(destination position) */
2685 LABEL *lobj = (LABEL *)operands[j];
2686 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2687 break;
2688 }
2689 case TS_CDHASH:
2690 {
2691 VALUE map = operands[j];
2692 struct cdhash_set_label_struct data;
2693 data.hash = map;
2694 data.pos = code_index;
2695 data.len = len;
2696 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2697
2698 rb_hash_rehash(map);
2699 freeze_hide_obj(map);
2700 generated_iseq[code_index + 1 + j] = map;
2701 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2702 RB_OBJ_WRITTEN(iseq, Qundef, map);
2703 needs_bitmap = true;
2704 break;
2705 }
2706 case TS_LINDEX:
2707 case TS_NUM: /* ulong */
2708 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2709 break;
2710 case TS_ISEQ: /* iseq */
2711 case TS_VALUE: /* VALUE */
2712 {
2713 VALUE v = operands[j];
2714 generated_iseq[code_index + 1 + j] = v;
2715 /* to mark ruby object */
2716 if (!SPECIAL_CONST_P(v)) {
2717 RB_OBJ_WRITTEN(iseq, Qundef, v);
2718 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2719 needs_bitmap = true;
2720 }
2721 break;
2722 }
2723 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2724 case TS_IC: /* inline cache: constants */
2725 {
2726 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2727 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2728 if (UNLIKELY(ic_index >= body->ic_size)) {
2729 BADINSN_DUMP(anchor, &iobj->link, 0);
2730 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2731 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2732 ic_index, ISEQ_IS_SIZE(body));
2733 }
2734
2735 ic->segments = array_to_idlist(operands[j]);
2736
2737 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2738 }
2739 break;
2740 case TS_IVC: /* inline ivar cache */
2741 {
2742 unsigned int ic_index = FIX2UINT(operands[j]);
2743
2744 IVC cache = ((IVC)&body->is_entries[ic_index]);
2745
2746 if (insn == BIN(setinstancevariable)) {
2747 cache->iv_set_name = SYM2ID(operands[j - 1]);
2748 }
2749 else {
2750 cache->iv_set_name = 0;
2751 }
2752
2753 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2754 }
2755 case TS_ISE: /* inline storage entry: `once` insn */
2756 case TS_ICVARC: /* inline cvar cache */
2757 {
2758 unsigned int ic_index = FIX2UINT(operands[j]);
2759 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2760 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2761 BADINSN_DUMP(anchor, &iobj->link, 0);
2762 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2763 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2764 ic_index, ISEQ_IS_SIZE(body));
2765 }
2766 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2767
2768 break;
2769 }
2770 case TS_CALLDATA:
2771 {
2772 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2773 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2774 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2775 cd->ci = source_ci;
2776 cd->cc = vm_cc_empty();
2777 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2778 break;
2779 }
2780 case TS_ID: /* ID */
2781 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2782 break;
2783 case TS_FUNCPTR:
2784 generated_iseq[code_index + 1 + j] = operands[j];
2785 break;
2786 case TS_BUILTIN:
2787 generated_iseq[code_index + 1 + j] = operands[j];
2788 break;
2789 default:
2790 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2791 "unknown operand type: %c", type);
2792 return COMPILE_NG;
2793 }
2794 }
2795 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2796 code_index += len;
2797 break;
2798 }
2799 case ISEQ_ELEMENT_LABEL:
2800 {
2801 LABEL *lobj = (LABEL *)list;
2802 if (lobj->sp != sp) {
2803 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2804 RSTRING_PTR(rb_iseq_path(iseq)),
2805 lobj->label_no, lobj->sp, sp);
2806 }
2807 sp = lobj->sp;
2808 break;
2809 }
2810 case ISEQ_ELEMENT_ADJUST:
2811 {
2812 ADJUST *adjust = (ADJUST *)list;
2813 int orig_sp = sp;
2814
2815 if (adjust->label) {
2816 sp = adjust->label->sp;
2817 }
2818 else {
2819 sp = 0;
2820 }
2821
2822 if (adjust->line_no != -1) {
2823 const int diff = orig_sp - sp;
2824 if (diff > 0) {
2825 if (insns_info_index == 0) {
2826 COMPILE_ERROR(iseq, adjust->line_no,
2827 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2828 }
2829 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2830 }
2831 if (diff > 1) {
2832 generated_iseq[code_index++] = BIN(adjuststack);
2833 generated_iseq[code_index++] = orig_sp - sp;
2834 }
2835 else if (diff == 1) {
2836 generated_iseq[code_index++] = BIN(pop);
2837 }
2838 else if (diff < 0) {
2839 int label_no = adjust->label ? adjust->label->label_no : -1;
2840 xfree(generated_iseq);
2841 xfree(insns_info);
2842 xfree(positions);
2843 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2844 xfree(mark_offset_bits);
2845 }
2846 debug_list(anchor, list);
2847 COMPILE_ERROR(iseq, adjust->line_no,
2848 "iseq_set_sequence: adjust bug to %d %d < %d",
2849 label_no, orig_sp, sp);
2850 return COMPILE_NG;
2851 }
2852 }
2853 break;
2854 }
2855 default:
2856 /* ignore */
2857 break;
2858 }
2859 list = list->next;
2860 }
2861
2862 body->iseq_encoded = (void *)generated_iseq;
2863 body->iseq_size = code_index;
2864 body->stack_max = stack_max;
2865
2866 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2867 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2868 }
2869 else {
2870 if (needs_bitmap) {
2871 body->mark_bits.list = mark_offset_bits;
2872 }
2873 else {
2874 body->mark_bits.list = NULL;
2875 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2876 ruby_xfree(mark_offset_bits);
2877 }
2878 }
2879
2880 /* get rid of memory leak when REALLOC failed */
2881 body->insns_info.body = insns_info;
2882 body->insns_info.positions = positions;
2883
2884 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2885 body->insns_info.body = insns_info;
2886 REALLOC_N(positions, unsigned int, insns_info_index);
2887 body->insns_info.positions = positions;
2888 body->insns_info.size = insns_info_index;
2889
2890 return COMPILE_OK;
2891}
2892
2893static int
2894label_get_position(LABEL *lobj)
2895{
2896 return lobj->position;
2897}
2898
2899static int
2900label_get_sp(LABEL *lobj)
2901{
2902 return lobj->sp;
2903}
2904
2905static int
2906iseq_set_exception_table(rb_iseq_t *iseq)
2907{
2908 const VALUE *tptr, *ptr;
2909 unsigned int tlen, i;
2910 struct iseq_catch_table_entry *entry;
2911
2912 ISEQ_BODY(iseq)->catch_table = NULL;
2913
2914 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2915 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2916 tlen = (int)RARRAY_LEN(catch_table_ary);
2917 tptr = RARRAY_CONST_PTR(catch_table_ary);
2918
2919 if (tlen > 0) {
2920 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2921 table->size = tlen;
2922
2923 for (i = 0; i < table->size; i++) {
2924 int pos;
2925 ptr = RARRAY_CONST_PTR(tptr[i]);
2926 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2927 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2928 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2929 RUBY_ASSERT(pos >= 0);
2930 entry->start = (unsigned int)pos;
2931 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2932 RUBY_ASSERT(pos >= 0);
2933 entry->end = (unsigned int)pos;
2934 entry->iseq = (rb_iseq_t *)ptr[3];
2935 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2936
2937 /* stack depth */
2938 if (ptr[4]) {
2939 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2940 entry->cont = label_get_position(lobj);
2941 entry->sp = label_get_sp(lobj);
2942
2943 /* TODO: Dirty Hack! Fix me */
2944 if (entry->type == CATCH_TYPE_RESCUE ||
2945 entry->type == CATCH_TYPE_BREAK ||
2946 entry->type == CATCH_TYPE_NEXT) {
2947 RUBY_ASSERT(entry->sp > 0);
2948 entry->sp--;
2949 }
2950 }
2951 else {
2952 entry->cont = 0;
2953 }
2954 }
2955 ISEQ_BODY(iseq)->catch_table = table;
2956 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2957 }
2958
2959 RB_GC_GUARD(catch_table_ary);
2960
2961 return COMPILE_OK;
2962}
2963
2964/*
2965 * set optional argument table
2966 * def foo(a, b=expr1, c=expr2)
2967 * =>
2968 * b:
2969 * expr1
2970 * c:
2971 * expr2
2972 */
2973static int
2974iseq_set_optargs_table(rb_iseq_t *iseq)
2975{
2976 int i;
2977 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2978
2979 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2980 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2981 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2982 }
2983 }
2984 return COMPILE_OK;
2985}
2986
2987static LINK_ELEMENT *
2988get_destination_insn(INSN *iobj)
2989{
2990 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2991 LINK_ELEMENT *list;
2992 rb_event_flag_t events = 0;
2993
2994 list = lobj->link.next;
2995 while (list) {
2996 switch (list->type) {
2997 case ISEQ_ELEMENT_INSN:
2998 case ISEQ_ELEMENT_ADJUST:
2999 goto found;
3000 case ISEQ_ELEMENT_LABEL:
3001 /* ignore */
3002 break;
3003 case ISEQ_ELEMENT_TRACE:
3004 {
3005 TRACE *trace = (TRACE *)list;
3006 events |= trace->event;
3007 }
3008 break;
3009 default: break;
3010 }
3011 list = list->next;
3012 }
3013 found:
3014 if (list && IS_INSN(list)) {
3015 INSN *iobj = (INSN *)list;
3016 iobj->insn_info.events |= events;
3017 }
3018 return list;
3019}
3020
3021static LINK_ELEMENT *
3022get_next_insn(INSN *iobj)
3023{
3024 LINK_ELEMENT *list = iobj->link.next;
3025
3026 while (list) {
3027 if (IS_INSN(list) || IS_ADJUST(list)) {
3028 return list;
3029 }
3030 list = list->next;
3031 }
3032 return 0;
3033}
3034
3035static LINK_ELEMENT *
3036get_prev_insn(INSN *iobj)
3037{
3038 LINK_ELEMENT *list = iobj->link.prev;
3039
3040 while (list) {
3041 if (IS_INSN(list) || IS_ADJUST(list)) {
3042 return list;
3043 }
3044 list = list->prev;
3045 }
3046 return 0;
3047}
3048
3049static void
3050unref_destination(INSN *iobj, int pos)
3051{
3052 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3053 --lobj->refcnt;
3054 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3055}
3056
3057static bool
3058replace_destination(INSN *dobj, INSN *nobj)
3059{
3060 VALUE n = OPERAND_AT(nobj, 0);
3061 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3062 LABEL *nl = (LABEL *)n;
3063 if (dl == nl) return false;
3064 --dl->refcnt;
3065 ++nl->refcnt;
3066 OPERAND_AT(dobj, 0) = n;
3067 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3068 return true;
3069}
3070
3071static LABEL*
3072find_destination(INSN *i)
3073{
3074 int pos, len = insn_len(i->insn_id);
3075 for (pos = 0; pos < len; ++pos) {
3076 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3077 return (LABEL *)OPERAND_AT(i, pos);
3078 }
3079 }
3080 return 0;
3081}
3082
3083static int
3084remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3085{
3086 LINK_ELEMENT *first = i, *end;
3087 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3088
3089 if (!i) return 0;
3090 unref_counts = ALLOCA_N(int, nlabels);
3091 MEMZERO(unref_counts, int, nlabels);
3092 end = i;
3093 do {
3094 LABEL *lab;
3095 if (IS_INSN(i)) {
3096 if (IS_INSN_ID(i, leave)) {
3097 end = i;
3098 break;
3099 }
3100 else if ((lab = find_destination((INSN *)i)) != 0) {
3101 unref_counts[lab->label_no]++;
3102 }
3103 }
3104 else if (IS_LABEL(i)) {
3105 lab = (LABEL *)i;
3106 if (lab->unremovable) return 0;
3107 if (lab->refcnt > unref_counts[lab->label_no]) {
3108 if (i == first) return 0;
3109 break;
3110 }
3111 continue;
3112 }
3113 else if (IS_TRACE(i)) {
3114 /* do nothing */
3115 }
3116 else if (IS_ADJUST(i)) {
3117 return 0;
3118 }
3119 end = i;
3120 } while ((i = i->next) != 0);
3121 i = first;
3122 do {
3123 if (IS_INSN(i)) {
3124 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
3125 VALUE insn = INSN_OF(i);
3126 int pos, len = insn_len(insn);
3127 for (pos = 0; pos < len; ++pos) {
3128 switch (insn_op_types(insn)[pos]) {
3129 case TS_OFFSET:
3130 unref_destination((INSN *)i, pos);
3131 break;
3132 case TS_CALLDATA:
3133 --(body->ci_size);
3134 break;
3135 }
3136 }
3137 }
3138 ELEM_REMOVE(i);
3139 } while ((i != end) && (i = i->next) != 0);
3140 return 1;
3141}
3142
3143static int
3144iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3145{
3146 switch (OPERAND_AT(iobj, 0)) {
3147 case INT2FIX(0): /* empty array */
3148 ELEM_REMOVE(&iobj->link);
3149 return TRUE;
3150 case INT2FIX(1): /* single element array */
3151 ELEM_REMOVE(&iobj->link);
3152 return FALSE;
3153 default:
3154 iobj->insn_id = BIN(adjuststack);
3155 return TRUE;
3156 }
3157}
3158
3159static int
3160is_frozen_putstring(INSN *insn, VALUE *op)
3161{
3162 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3163 *op = OPERAND_AT(insn, 0);
3164 return 1;
3165 }
3166 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
3167 *op = OPERAND_AT(insn, 0);
3168 return RB_TYPE_P(*op, T_STRING);
3169 }
3170 return 0;
3171}
3172
3173static int
3174optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3175{
3176 /*
3177 * putobject obj
3178 * dup
3179 * checktype T_XXX
3180 * branchif l1
3181 * l2:
3182 * ...
3183 * l1:
3184 *
3185 * => obj is a T_XXX
3186 *
3187 * putobject obj (T_XXX)
3188 * jump L1
3189 * L1:
3190 *
3191 * => obj is not a T_XXX
3192 *
3193 * putobject obj (T_XXX)
3194 * jump L2
3195 * L2:
3196 */
3197 int line, node_id;
3198 INSN *niobj, *ciobj, *dup = 0;
3199 LABEL *dest = 0;
3200 VALUE type;
3201
3202 switch (INSN_OF(iobj)) {
3203 case BIN(putstring):
3204 case BIN(putchilledstring):
3206 break;
3207 case BIN(putnil):
3208 type = INT2FIX(T_NIL);
3209 break;
3210 case BIN(putobject):
3211 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
3212 break;
3213 default: return FALSE;
3214 }
3215
3216 ciobj = (INSN *)get_next_insn(iobj);
3217 if (IS_INSN_ID(ciobj, jump)) {
3218 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3219 }
3220 if (IS_INSN_ID(ciobj, dup)) {
3221 ciobj = (INSN *)get_next_insn(dup = ciobj);
3222 }
3223 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
3224 niobj = (INSN *)get_next_insn(ciobj);
3225 if (!niobj) {
3226 /* TODO: putobject true/false */
3227 return FALSE;
3228 }
3229 switch (INSN_OF(niobj)) {
3230 case BIN(branchif):
3231 if (OPERAND_AT(ciobj, 0) == type) {
3232 dest = (LABEL *)OPERAND_AT(niobj, 0);
3233 }
3234 break;
3235 case BIN(branchunless):
3236 if (OPERAND_AT(ciobj, 0) != type) {
3237 dest = (LABEL *)OPERAND_AT(niobj, 0);
3238 }
3239 break;
3240 default:
3241 return FALSE;
3242 }
3243 line = ciobj->insn_info.line_no;
3244 node_id = ciobj->insn_info.node_id;
3245 if (!dest) {
3246 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3247 dest = (LABEL *)niobj->link.next; /* reuse label */
3248 }
3249 else {
3250 dest = NEW_LABEL(line);
3251 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3252 }
3253 }
3254 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3255 LABEL_REF(dest);
3256 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3257 return TRUE;
3258}
3259
3260static const struct rb_callinfo *
3261ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3262{
3263 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3264 vm_ci_flag(ci) | add,
3265 vm_ci_argc(ci),
3266 vm_ci_kwarg(ci));
3267 RB_OBJ_WRITTEN(iseq, ci, nci);
3268 return nci;
3269}
3270
3271static const struct rb_callinfo *
3272ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3273{
3274 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3275 vm_ci_flag(ci),
3276 argc,
3277 vm_ci_kwarg(ci));
3278 RB_OBJ_WRITTEN(iseq, ci, nci);
3279 return nci;
3280}
3281
3282#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3283
3284static int
3285iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3286{
3287 INSN *const iobj = (INSN *)list;
3288
3289 again:
3290 optimize_checktype(iseq, iobj);
3291
3292 if (IS_INSN_ID(iobj, jump)) {
3293 INSN *niobj, *diobj, *piobj;
3294 diobj = (INSN *)get_destination_insn(iobj);
3295 niobj = (INSN *)get_next_insn(iobj);
3296
3297 if (diobj == niobj) {
3298 /*
3299 * jump LABEL
3300 * LABEL:
3301 * =>
3302 * LABEL:
3303 */
3304 unref_destination(iobj, 0);
3305 ELEM_REMOVE(&iobj->link);
3306 return COMPILE_OK;
3307 }
3308 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3309 IS_INSN_ID(diobj, jump) &&
3310 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3311 diobj->insn_info.events == 0) {
3312 /*
3313 * useless jump elimination:
3314 * jump LABEL1
3315 * ...
3316 * LABEL1:
3317 * jump LABEL2
3318 *
3319 * => in this case, first jump instruction should jump to
3320 * LABEL2 directly
3321 */
3322 if (replace_destination(iobj, diobj)) {
3323 remove_unreachable_chunk(iseq, iobj->link.next);
3324 goto again;
3325 }
3326 }
3327 else if (IS_INSN_ID(diobj, leave)) {
3328 /*
3329 * jump LABEL
3330 * ...
3331 * LABEL:
3332 * leave
3333 * =>
3334 * leave
3335 * ...
3336 * LABEL:
3337 * leave
3338 */
3339 /* replace */
3340 unref_destination(iobj, 0);
3341 iobj->insn_id = BIN(leave);
3342 iobj->operand_size = 0;
3343 iobj->insn_info = diobj->insn_info;
3344 goto again;
3345 }
3346 else if (IS_INSN(iobj->link.prev) &&
3347 (piobj = (INSN *)iobj->link.prev) &&
3348 (IS_INSN_ID(piobj, branchif) ||
3349 IS_INSN_ID(piobj, branchunless))) {
3350 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3351 if (niobj == pdiobj) {
3352 int refcnt = IS_LABEL(piobj->link.next) ?
3353 ((LABEL *)piobj->link.next)->refcnt : 0;
3354 /*
3355 * useless jump elimination (if/unless destination):
3356 * if L1
3357 * jump L2
3358 * L1:
3359 * ...
3360 * L2:
3361 *
3362 * ==>
3363 * unless L2
3364 * L1:
3365 * ...
3366 * L2:
3367 */
3368 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3369 ? BIN(branchunless) : BIN(branchif);
3370 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3371 ELEM_REMOVE(&iobj->link);
3372 }
3373 else {
3374 /* TODO: replace other branch destinations too */
3375 }
3376 return COMPILE_OK;
3377 }
3378 else if (diobj == pdiobj) {
3379 /*
3380 * useless jump elimination (if/unless before jump):
3381 * L1:
3382 * ...
3383 * if L1
3384 * jump L1
3385 *
3386 * ==>
3387 * L1:
3388 * ...
3389 * pop
3390 * jump L1
3391 */
3392 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3393 ELEM_REPLACE(&piobj->link, &popiobj->link);
3394 }
3395 }
3396 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3397 goto again;
3398 }
3399 }
3400
3401 /*
3402 * putstring "beg"
3403 * putstring "end"
3404 * newrange excl
3405 *
3406 * ==>
3407 *
3408 * putobject "beg".."end"
3409 */
3410 if (IS_INSN_ID(iobj, newrange)) {
3411 INSN *const range = iobj;
3412 INSN *beg, *end;
3413 VALUE str_beg, str_end;
3414
3415 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3416 is_frozen_putstring(end, &str_end) &&
3417 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3418 is_frozen_putstring(beg, &str_beg)) {
3419 int excl = FIX2INT(OPERAND_AT(range, 0));
3420 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3421
3422 ELEM_REMOVE(&beg->link);
3423 ELEM_REMOVE(&end->link);
3424 range->insn_id = BIN(putobject);
3425 OPERAND_AT(range, 0) = lit_range;
3426 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3427 }
3428 }
3429
3430 if (IS_INSN_ID(iobj, leave)) {
3431 remove_unreachable_chunk(iseq, iobj->link.next);
3432 }
3433
3434 /*
3435 * ...
3436 * duparray [...]
3437 * concatarray | concattoarray
3438 * =>
3439 * ...
3440 * putobject [...]
3441 * concatarray | concattoarray
3442 */
3443 if (IS_INSN_ID(iobj, duparray)) {
3444 LINK_ELEMENT *next = iobj->link.next;
3445 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3446 iobj->insn_id = BIN(putobject);
3447 }
3448 }
3449
3450 /*
3451 * duparray [...]
3452 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3453 * =>
3454 * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3455 */
3456 if (IS_INSN_ID(iobj, duparray)) {
3457 LINK_ELEMENT *next = iobj->link.next;
3458 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3459 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3460 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3461
3462 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3463 VALUE ary = iobj->operands[0];
3465
3466 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (VALUE)ci);
3467 ELEM_REMOVE(next);
3468 }
3469 }
3470 }
3471
3472 /*
3473 * duphash {...}
3474 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3475 * =>
3476 * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3477 */
3478 if (IS_INSN_ID(iobj, duphash)) {
3479 LINK_ELEMENT *next = iobj->link.next;
3480 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3481 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3482 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3483
3484 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3485 VALUE hash = iobj->operands[0];
3486 rb_obj_reveal(hash, rb_cHash);
3487
3488 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (VALUE)ci);
3489 ELEM_REMOVE(next);
3490 }
3491 }
3492 }
3493
3494 /*
3495 * newarray 0
3496 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3497 * =>
3498 * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3499 */
3500 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
3501 LINK_ELEMENT *next = iobj->link.next;
3502 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3503 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3504 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3505
3506 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3507 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (VALUE)ci);
3508 ELEM_REMOVE(next);
3509 }
3510 }
3511 }
3512
3513 /*
3514 * newhash 0
3515 * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
3516 * =>
3517 * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
3518 */
3519 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
3520 LINK_ELEMENT *next = iobj->link.next;
3521 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3522 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
3523 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3524
3525 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3526 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (VALUE)ci);
3527 ELEM_REMOVE(next);
3528 }
3529 }
3530 }
3531
3532 if (IS_INSN_ID(iobj, branchif) ||
3533 IS_INSN_ID(iobj, branchnil) ||
3534 IS_INSN_ID(iobj, branchunless)) {
3535 /*
3536 * if L1
3537 * ...
3538 * L1:
3539 * jump L2
3540 * =>
3541 * if L2
3542 */
3543 INSN *nobj = (INSN *)get_destination_insn(iobj);
3544
3545 /* This is super nasty hack!!!
3546 *
3547 * This jump-jump optimization may ignore event flags of the jump
3548 * instruction being skipped. Actually, Line 2 TracePoint event
3549 * is never fired in the following code:
3550 *
3551 * 1: raise if 1 == 2
3552 * 2: while true
3553 * 3: break
3554 * 4: end
3555 *
3556 * This is critical for coverage measurement. [Bug #15980]
3557 *
3558 * This is a stopgap measure: stop the jump-jump optimization if
3559 * coverage measurement is enabled and if the skipped instruction
3560 * has any event flag.
3561 *
3562 * Note that, still, TracePoint Line event does not occur on Line 2.
3563 * This should be fixed in future.
3564 */
3565 int stop_optimization =
3566 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3567 nobj->link.type == ISEQ_ELEMENT_INSN &&
3568 nobj->insn_info.events;
3569 if (!stop_optimization) {
3570 INSN *pobj = (INSN *)iobj->link.prev;
3571 int prev_dup = 0;
3572 if (pobj) {
3573 if (!IS_INSN(&pobj->link))
3574 pobj = 0;
3575 else if (IS_INSN_ID(pobj, dup))
3576 prev_dup = 1;
3577 }
3578
3579 for (;;) {
3580 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3581 if (!replace_destination(iobj, nobj)) break;
3582 }
3583 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3584 !!(nobj = (INSN *)nobj->link.next) &&
3585 /* basic blocks, with no labels in the middle */
3586 nobj->insn_id == iobj->insn_id) {
3587 /*
3588 * dup
3589 * if L1
3590 * ...
3591 * L1:
3592 * dup
3593 * if L2
3594 * =>
3595 * dup
3596 * if L2
3597 * ...
3598 * L1:
3599 * dup
3600 * if L2
3601 */
3602 if (!replace_destination(iobj, nobj)) break;
3603 }
3604 else if (pobj) {
3605 /*
3606 * putnil
3607 * if L1
3608 * =>
3609 * # nothing
3610 *
3611 * putobject true
3612 * if L1
3613 * =>
3614 * jump L1
3615 *
3616 * putstring ".."
3617 * if L1
3618 * =>
3619 * jump L1
3620 *
3621 * putstring ".."
3622 * dup
3623 * if L1
3624 * =>
3625 * putstring ".."
3626 * jump L1
3627 *
3628 */
3629 int cond;
3630 if (prev_dup && IS_INSN(pobj->link.prev)) {
3631 pobj = (INSN *)pobj->link.prev;
3632 }
3633 if (IS_INSN_ID(pobj, putobject)) {
3634 cond = (IS_INSN_ID(iobj, branchif) ?
3635 OPERAND_AT(pobj, 0) != Qfalse :
3636 IS_INSN_ID(iobj, branchunless) ?
3637 OPERAND_AT(pobj, 0) == Qfalse :
3638 FALSE);
3639 }
3640 else if (IS_INSN_ID(pobj, putstring) ||
3641 IS_INSN_ID(pobj, duparray) ||
3642 IS_INSN_ID(pobj, newarray)) {
3643 cond = IS_INSN_ID(iobj, branchif);
3644 }
3645 else if (IS_INSN_ID(pobj, putnil)) {
3646 cond = !IS_INSN_ID(iobj, branchif);
3647 }
3648 else break;
3649 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3650 ELEM_REMOVE(iobj->link.prev);
3651 }
3652 else if (!iseq_pop_newarray(iseq, pobj)) {
3653 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3654 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3655 }
3656 if (cond) {
3657 if (prev_dup) {
3658 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3659 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3660 }
3661 iobj->insn_id = BIN(jump);
3662 goto again;
3663 }
3664 else {
3665 unref_destination(iobj, 0);
3666 ELEM_REMOVE(&iobj->link);
3667 }
3668 break;
3669 }
3670 else break;
3671 nobj = (INSN *)get_destination_insn(nobj);
3672 }
3673 }
3674 }
3675
3676 if (IS_INSN_ID(iobj, pop)) {
3677 /*
3678 * putself / putnil / putobject obj / putstring "..."
3679 * pop
3680 * =>
3681 * # do nothing
3682 */
3683 LINK_ELEMENT *prev = iobj->link.prev;
3684 if (IS_INSN(prev)) {
3685 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3686 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3687 previ == BIN(putself) || previ == BIN(putstring) ||
3688 previ == BIN(putchilledstring) ||
3689 previ == BIN(dup) ||
3690 previ == BIN(getlocal) ||
3691 previ == BIN(getblockparam) ||
3692 previ == BIN(getblockparamproxy) ||
3693 previ == BIN(getinstancevariable) ||
3694 previ == BIN(duparray)) {
3695 /* just push operand or static value and pop soon, no
3696 * side effects */
3697 ELEM_REMOVE(prev);
3698 ELEM_REMOVE(&iobj->link);
3699 }
3700 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3701 ELEM_REMOVE(&iobj->link);
3702 }
3703 else if (previ == BIN(concatarray)) {
3704 INSN *piobj = (INSN *)prev;
3705 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
3706 INSN_OF(piobj) = BIN(pop);
3707 }
3708 else if (previ == BIN(concatstrings)) {
3709 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3710 ELEM_REMOVE(prev);
3711 }
3712 else {
3713 ELEM_REMOVE(&iobj->link);
3714 INSN_OF(prev) = BIN(adjuststack);
3715 }
3716 }
3717 }
3718 }
3719
3720 if (IS_INSN_ID(iobj, newarray) ||
3721 IS_INSN_ID(iobj, duparray) ||
3722 IS_INSN_ID(iobj, concatarray) ||
3723 IS_INSN_ID(iobj, splatarray) ||
3724 0) {
3725 /*
3726 * newarray N
3727 * splatarray
3728 * =>
3729 * newarray N
3730 * newarray always puts an array
3731 */
3732 LINK_ELEMENT *next = iobj->link.next;
3733 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3734 /* remove splatarray following always-array insn */
3735 ELEM_REMOVE(next);
3736 }
3737 }
3738
3739 if (IS_INSN_ID(iobj, newarray)) {
3740 LINK_ELEMENT *next = iobj->link.next;
3741 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3742 OPERAND_AT(next, 1) == INT2FIX(0)) {
3743 VALUE op1, op2;
3744 op1 = OPERAND_AT(iobj, 0);
3745 op2 = OPERAND_AT(next, 0);
3746 ELEM_REMOVE(next);
3747
3748 if (op1 == op2) {
3749 /*
3750 * newarray 2
3751 * expandarray 2, 0
3752 * =>
3753 * swap
3754 */
3755 if (op1 == INT2FIX(2)) {
3756 INSN_OF(iobj) = BIN(swap);
3757 iobj->operand_size = 0;
3758 }
3759 /*
3760 * newarray X
3761 * expandarray X, 0
3762 * =>
3763 * opt_reverse X
3764 */
3765 else {
3766 INSN_OF(iobj) = BIN(opt_reverse);
3767 }
3768 }
3769 else {
3770 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3771 INSN_OF(iobj) = BIN(opt_reverse);
3772 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3773
3774 if (op1 > op2) {
3775 /* X > Y
3776 * newarray X
3777 * expandarray Y, 0
3778 * =>
3779 * pop * (Y-X)
3780 * opt_reverse Y
3781 */
3782 for (; diff > 0; diff--) {
3783 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3784 }
3785 }
3786 else { /* (op1 < op2) */
3787 /* X < Y
3788 * newarray X
3789 * expandarray Y, 0
3790 * =>
3791 * putnil * (Y-X)
3792 * opt_reverse Y
3793 */
3794 for (; diff < 0; diff++) {
3795 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3796 }
3797 }
3798 }
3799 }
3800 }
3801
3802 if (IS_INSN_ID(iobj, duparray)) {
3803 LINK_ELEMENT *next = iobj->link.next;
3804 /*
3805 * duparray obj
3806 * expandarray X, 0
3807 * =>
3808 * putobject obj
3809 * expandarray X, 0
3810 */
3811 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3812 INSN_OF(iobj) = BIN(putobject);
3813 }
3814 }
3815
3816 if (IS_INSN_ID(iobj, anytostring)) {
3817 LINK_ELEMENT *next = iobj->link.next;
3818 /*
3819 * anytostring
3820 * concatstrings 1
3821 * =>
3822 * anytostring
3823 */
3824 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3825 OPERAND_AT(next, 0) == INT2FIX(1)) {
3826 ELEM_REMOVE(next);
3827 }
3828 }
3829
3830 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3831 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3832 /*
3833 * putstring ""
3834 * concatstrings N
3835 * =>
3836 * concatstrings N-1
3837 */
3838 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3839 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3840 INSN *next = (INSN *)iobj->link.next;
3841 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3842 ELEM_REMOVE(&next->link);
3843 }
3844 ELEM_REMOVE(&iobj->link);
3845 }
3846 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3847 INSN *next = (INSN *)iobj->link.next;
3848 if (OPERAND_AT(next, 1) == INT2FIX(1)) {
3849 VALUE src = OPERAND_AT(iobj, 0);
3850 int opt = (int)FIX2LONG(OPERAND_AT(next, 0));
3851 VALUE path = rb_iseq_path(iseq);
3852 int line = iobj->insn_info.line_no;
3853 VALUE errinfo = rb_errinfo();
3854 VALUE re = rb_reg_compile(src, opt, RSTRING_PTR(path), line);
3855 if (NIL_P(re)) {
3856 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3857 rb_set_errinfo(errinfo);
3858 COMPILE_ERROR(iseq, line, "%" PRIsVALUE, message);
3859 }
3860 RB_OBJ_WRITE(iseq, &OPERAND_AT(iobj, 0), re);
3861 ELEM_REMOVE(iobj->link.next);
3862 }
3863 }
3864 }
3865
3866 if (IS_INSN_ID(iobj, concatstrings)) {
3867 /*
3868 * concatstrings N
3869 * concatstrings M
3870 * =>
3871 * concatstrings N+M-1
3872 */
3873 LINK_ELEMENT *next = iobj->link.next;
3874 INSN *jump = 0;
3875 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3876 next = get_destination_insn(jump = (INSN *)next);
3877 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3878 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3879 OPERAND_AT(iobj, 0) = INT2FIX(n);
3880 if (jump) {
3881 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3882 if (!--label->refcnt) {
3883 ELEM_REMOVE(&label->link);
3884 }
3885 else {
3886 label = NEW_LABEL(0);
3887 OPERAND_AT(jump, 0) = (VALUE)label;
3888 }
3889 label->refcnt++;
3890 ELEM_INSERT_NEXT(next, &label->link);
3891 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3892 }
3893 else {
3894 ELEM_REMOVE(next);
3895 }
3896 }
3897 }
3898
3899 if (do_tailcallopt &&
3900 (IS_INSN_ID(iobj, send) ||
3901 IS_INSN_ID(iobj, opt_aref_with) ||
3902 IS_INSN_ID(iobj, opt_aset_with) ||
3903 IS_INSN_ID(iobj, invokesuper))) {
3904 /*
3905 * send ...
3906 * leave
3907 * =>
3908 * send ..., ... | VM_CALL_TAILCALL, ...
3909 * leave # unreachable
3910 */
3911 INSN *piobj = NULL;
3912 if (iobj->link.next) {
3913 LINK_ELEMENT *next = iobj->link.next;
3914 do {
3915 if (!IS_INSN(next)) {
3916 next = next->next;
3917 continue;
3918 }
3919 switch (INSN_OF(next)) {
3920 case BIN(nop):
3921 next = next->next;
3922 break;
3923 case BIN(jump):
3924 /* if cond
3925 * return tailcall
3926 * end
3927 */
3928 next = get_destination_insn((INSN *)next);
3929 break;
3930 case BIN(leave):
3931 piobj = iobj;
3932 /* fall through */
3933 default:
3934 next = NULL;
3935 break;
3936 }
3937 } while (next);
3938 }
3939
3940 if (piobj) {
3941 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3942 if (IS_INSN_ID(piobj, send) ||
3943 IS_INSN_ID(piobj, invokesuper)) {
3944 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3945 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3946 OPERAND_AT(piobj, 0) = (VALUE)ci;
3947 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3948 }
3949 }
3950 else {
3951 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3952 OPERAND_AT(piobj, 0) = (VALUE)ci;
3953 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3954 }
3955 }
3956 }
3957
3958 if (IS_INSN_ID(iobj, dup)) {
3959 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3960 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3961
3962 /*
3963 * dup
3964 * setlocal x, y
3965 * setlocal x, y
3966 * =>
3967 * dup
3968 * setlocal x, y
3969 */
3970 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3971 set2 = set1->next;
3972 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3973 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3974 ELEM_REMOVE(set1);
3975 ELEM_REMOVE(&iobj->link);
3976 }
3977 }
3978
3979 /*
3980 * dup
3981 * setlocal x, y
3982 * dup
3983 * setlocal x, y
3984 * =>
3985 * dup
3986 * setlocal x, y
3987 */
3988 else if (IS_NEXT_INSN_ID(set1, dup) &&
3989 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3990 set2 = set1->next->next;
3991 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3992 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3993 ELEM_REMOVE(set1->next);
3994 ELEM_REMOVE(set2);
3995 }
3996 }
3997 }
3998 }
3999
4000 /*
4001 * getlocal x, y
4002 * dup
4003 * setlocal x, y
4004 * =>
4005 * dup
4006 */
4007 if (IS_INSN_ID(iobj, getlocal)) {
4008 LINK_ELEMENT *niobj = &iobj->link;
4009 if (IS_NEXT_INSN_ID(niobj, dup)) {
4010 niobj = niobj->next;
4011 }
4012 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4013 LINK_ELEMENT *set1 = niobj->next;
4014 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4015 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4016 ELEM_REMOVE(set1);
4017 ELEM_REMOVE(niobj);
4018 }
4019 }
4020 }
4021
4022 /*
4023 * opt_invokebuiltin_delegate
4024 * trace
4025 * leave
4026 * =>
4027 * opt_invokebuiltin_delegate_leave
4028 * trace
4029 * leave
4030 */
4031 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4032 if (IS_TRACE(iobj->link.next)) {
4033 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4034 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4035 const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
4036 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4037 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4038 }
4039 }
4040 }
4041 }
4042
4043 /*
4044 * getblockparam
4045 * branchif / branchunless
4046 * =>
4047 * getblockparamproxy
4048 * branchif / branchunless
4049 */
4050 if (IS_INSN_ID(iobj, getblockparam)) {
4051 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4052 iobj->insn_id = BIN(getblockparamproxy);
4053 }
4054 }
4055
4056 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
4057 LINK_ELEMENT *niobj = &iobj->link;
4058 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4059 niobj = niobj->next;
4060 LINK_ELEMENT *siobj;
4061 unsigned int set_flags = 0, unset_flags = 0;
4062
4063 /*
4064 * Eliminate hash allocation for f(*a, kw: 1)
4065 *
4066 * splatarray false
4067 * duphash
4068 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
4069 * =>
4070 * splatarray false
4071 * putobject
4072 * send ARGS_SPLAT|KW_SPLAT
4073 */
4074 if (IS_NEXT_INSN_ID(niobj, send)) {
4075 siobj = niobj->next;
4076 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4077 unset_flags = VM_CALL_ARGS_BLOCKARG;
4078 }
4079 /*
4080 * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4081 *
4082 * splatarray false
4083 * duphash
4084 * getlocal / getinstancevariable / getblockparamproxy
4085 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4086 * =>
4087 * splatarray false
4088 * putobject
4089 * getlocal / getinstancevariable / getblockparamproxy
4090 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4091 */
4092 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4093 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4094 siobj = niobj->next->next;
4095 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4096 }
4097
4098 if (set_flags) {
4099 const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
4100 unsigned int flags = vm_ci_flag(ci);
4101 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4102 ((INSN*)niobj)->insn_id = BIN(putobject);
4103 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4104
4105 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4106 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4107 RB_OBJ_WRITTEN(iseq, ci, nci);
4108 OPERAND_AT(siobj, 0) = (VALUE)nci;
4109 }
4110 }
4111 }
4112 }
4113
4114 return COMPILE_OK;
4115}
4116
4117static int
4118insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
4119{
4120 if (insn_id == BIN(opt_neq)) {
4121 VALUE original_ci = iobj->operands[0];
4122 VALUE new_ci = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4123 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4124 }
4125 else {
4126 iobj->insn_id = insn_id;
4127 iobj->operand_size = insn_len(insn_id) - 1;
4128 }
4129 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
4130
4131 return COMPILE_OK;
4132}
4133
4134static int
4135iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4136{
4137 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4138 IS_INSN(iobj->link.next)) {
4139 /*
4140 * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
4141 */
4142 INSN *niobj = (INSN *)iobj->link.next;
4143 if (IS_INSN_ID(niobj, send)) {
4144 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
4145 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4146 VALUE method = INT2FIX(0);
4147 switch (vm_ci_mid(ci)) {
4148 case idMax:
4149 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4150 break;
4151 case idMin:
4152 method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4153 break;
4154 case idHash:
4155 method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4156 break;
4157 }
4158
4159 if (method != INT2FIX(0)) {
4160 VALUE num = iobj->operands[0];
4161 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4162 ELEM_REMOVE(&niobj->link);
4163 return COMPILE_OK;
4164 }
4165 }
4166 }
4167 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4168 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4169 IS_NEXT_INSN_ID(&niobj->link, send)) {
4170 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
4171 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4172 VALUE num = iobj->operands[0];
4173 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4174 ELEM_REMOVE(&iobj->link);
4175 ELEM_REMOVE(niobj->link.next);
4176 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4177 return COMPILE_OK;
4178 }
4179 }
4180 // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
4181 // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
4182 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4183 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
4184 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4185 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4186 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
4187 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
4188 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4189 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
4190 VALUE num = iobj->operands[0];
4191 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2), INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4192 // Remove the "send" insn.
4193 ELEM_REMOVE((niobj->link.next)->next);
4194 // Remove the modified insn from its original "newarray" position...
4195 ELEM_REMOVE(&iobj->link);
4196 // and insert it after the buffer insn.
4197 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4198 return COMPILE_OK;
4199 }
4200 }
4201
4202 // Break the "else if" chain since some prior checks abort after sub-ifs.
4203 // We already found "newarray". To match `[...].include?(arg)` we look for
4204 // the instruction(s) representing the argument followed by a "send".
4205 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4206 IS_INSN_ID(niobj, putobject) ||
4207 IS_INSN_ID(niobj, putself) ||
4208 IS_INSN_ID(niobj, getlocal) ||
4209 IS_INSN_ID(niobj, getinstancevariable)) &&
4210 IS_NEXT_INSN_ID(&niobj->link, send)) {
4211
4212 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4213 const struct rb_callinfo *ci;
4214 // Allow any number (0 or more) of simple method calls on the argument
4215 // (as in `[...].include?(arg.method1.method2)`.
4216 do {
4217 sendobj = sendobj->next;
4218 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4219 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4220
4221 // If this send is for .include? with one arg we can do our opt.
4222 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4223 VALUE num = iobj->operands[0];
4224 INSN *sendins = (INSN *)sendobj;
4225 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1), INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4226 // Remove the original "newarray" insn.
4227 ELEM_REMOVE(&iobj->link);
4228 return COMPILE_OK;
4229 }
4230 }
4231 }
4232
4233 /*
4234 * duparray [...]
4235 * some insn for the arg...
4236 * send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
4237 * =>
4238 * arg insn...
4239 * opt_duparray_send [...], :include?, 1
4240 */
4241 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4242 INSN *niobj = (INSN *)iobj->link.next;
4243 if ((IS_INSN_ID(niobj, getlocal) ||
4244 IS_INSN_ID(niobj, getinstancevariable) ||
4245 IS_INSN_ID(niobj, putself)) &&
4246 IS_NEXT_INSN_ID(&niobj->link, send)) {
4247
4248 LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
4249 const struct rb_callinfo *ci;
4250 // Allow any number (0 or more) of simple method calls on the argument
4251 // (as in `[...].include?(arg.method1.method2)`.
4252 do {
4253 sendobj = sendobj->next;
4254 ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4255 } while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4256
4257 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4258 // Move the array arg from duparray to opt_duparray_send.
4259 VALUE ary = iobj->operands[0];
4261
4262 INSN *sendins = (INSN *)sendobj;
4263 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary, rb_id2sym(idIncludeP), INT2FIX(1));
4264
4265 // Remove the duparray insn.
4266 ELEM_REMOVE(&iobj->link);
4267 return COMPILE_OK;
4268 }
4269 }
4270 }
4271
4272
4273 if (IS_INSN_ID(iobj, send)) {
4274 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4275 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4276
4277#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4278 if (vm_ci_simple(ci)) {
4279 switch (vm_ci_argc(ci)) {
4280 case 0:
4281 switch (vm_ci_mid(ci)) {
4282 case idLength: SP_INSN(length); return COMPILE_OK;
4283 case idSize: SP_INSN(size); return COMPILE_OK;
4284 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
4285 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
4286 case idSucc: SP_INSN(succ); return COMPILE_OK;
4287 case idNot: SP_INSN(not); return COMPILE_OK;
4288 }
4289 break;
4290 case 1:
4291 switch (vm_ci_mid(ci)) {
4292 case idPLUS: SP_INSN(plus); return COMPILE_OK;
4293 case idMINUS: SP_INSN(minus); return COMPILE_OK;
4294 case idMULT: SP_INSN(mult); return COMPILE_OK;
4295 case idDIV: SP_INSN(div); return COMPILE_OK;
4296 case idMOD: SP_INSN(mod); return COMPILE_OK;
4297 case idEq: SP_INSN(eq); return COMPILE_OK;
4298 case idNeq: SP_INSN(neq); return COMPILE_OK;
4299 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
4300 case idLT: SP_INSN(lt); return COMPILE_OK;
4301 case idLE: SP_INSN(le); return COMPILE_OK;
4302 case idGT: SP_INSN(gt); return COMPILE_OK;
4303 case idGE: SP_INSN(ge); return COMPILE_OK;
4304 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
4305 case idAREF: SP_INSN(aref); return COMPILE_OK;
4306 case idAnd: SP_INSN(and); return COMPILE_OK;
4307 case idOr: SP_INSN(or); return COMPILE_OK;
4308 }
4309 break;
4310 case 2:
4311 switch (vm_ci_mid(ci)) {
4312 case idASET: SP_INSN(aset); return COMPILE_OK;
4313 }
4314 break;
4315 }
4316 }
4317
4318 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4319 iobj->insn_id = BIN(opt_send_without_block);
4320 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4321 }
4322 }
4323#undef SP_INSN
4324
4325 return COMPILE_OK;
4326}
4327
4328static inline int
4329tailcallable_p(rb_iseq_t *iseq)
4330{
4331 switch (ISEQ_BODY(iseq)->type) {
4332 case ISEQ_TYPE_TOP:
4333 case ISEQ_TYPE_EVAL:
4334 case ISEQ_TYPE_MAIN:
4335 /* not tail callable because cfp will be over popped */
4336 case ISEQ_TYPE_RESCUE:
4337 case ISEQ_TYPE_ENSURE:
4338 /* rescue block can't tail call because of errinfo */
4339 return FALSE;
4340 default:
4341 return TRUE;
4342 }
4343}
4344
4345static int
4346iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4347{
4348 LINK_ELEMENT *list;
4349 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4350 const int do_tailcallopt = tailcallable_p(iseq) &&
4351 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4352 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4353 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4354 int rescue_level = 0;
4355 int tailcallopt = do_tailcallopt;
4356
4357 list = FIRST_ELEMENT(anchor);
4358
4359 int do_block_optimization = 0;
4360 LABEL * block_loop_label = NULL;
4361
4362 // If we're optimizing a block
4363 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
4364 do_block_optimization = 1;
4365
4366 // If the block starts with a nop and a label,
4367 // record the label so we can detect if it's a jump target
4368 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4369 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4370 block_loop_label = (LABEL *)le->next;
4371 }
4372 }
4373
4374 while (list) {
4375 if (IS_INSN(list)) {
4376 if (do_peepholeopt) {
4377 iseq_peephole_optimize(iseq, list, tailcallopt);
4378 }
4379 if (do_si) {
4380 iseq_specialized_instruction(iseq, (INSN *)list);
4381 }
4382 if (do_ou) {
4383 insn_operands_unification((INSN *)list);
4384 }
4385
4386 if (do_block_optimization) {
4387 INSN * item = (INSN *)list;
4388 // Give up if there is a throw
4389 if (IS_INSN_ID(item, throw)) {
4390 do_block_optimization = 0;
4391 }
4392 else {
4393 // If the instruction has a jump target, check if the
4394 // jump target is the block loop label
4395 const char *types = insn_op_types(item->insn_id);
4396 for (int j = 0; types[j]; j++) {
4397 if (types[j] == TS_OFFSET) {
4398 // If the jump target is equal to the block loop
4399 // label, then we can't do the optimization because
4400 // the leading `nop` instruction fires the block
4401 // entry tracepoint
4402 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4403 if (target == block_loop_label) {
4404 do_block_optimization = 0;
4405 }
4406 }
4407 }
4408 }
4409 }
4410 }
4411 if (IS_LABEL(list)) {
4412 switch (((LABEL *)list)->rescued) {
4413 case LABEL_RESCUE_BEG:
4414 rescue_level++;
4415 tailcallopt = FALSE;
4416 break;
4417 case LABEL_RESCUE_END:
4418 if (!--rescue_level) tailcallopt = do_tailcallopt;
4419 break;
4420 }
4421 }
4422 list = list->next;
4423 }
4424
4425 if (do_block_optimization) {
4426 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4427 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4428 ELEM_REMOVE(le);
4429 }
4430 }
4431 return COMPILE_OK;
4432}
4433
4434#if OPT_INSTRUCTIONS_UNIFICATION
4435static INSN *
4436new_unified_insn(rb_iseq_t *iseq,
4437 int insn_id, int size, LINK_ELEMENT *seq_list)
4438{
4439 INSN *iobj = 0;
4440 LINK_ELEMENT *list = seq_list;
4441 int i, argc = 0;
4442 VALUE *operands = 0, *ptr = 0;
4443
4444
4445 /* count argc */
4446 for (i = 0; i < size; i++) {
4447 iobj = (INSN *)list;
4448 argc += iobj->operand_size;
4449 list = list->next;
4450 }
4451
4452 if (argc > 0) {
4453 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
4454 }
4455
4456 /* copy operands */
4457 list = seq_list;
4458 for (i = 0; i < size; i++) {
4459 iobj = (INSN *)list;
4460 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
4461 ptr += iobj->operand_size;
4462 list = list->next;
4463 }
4464
4465 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4466}
4467#endif
4468
4469/*
4470 * This scheme can get more performance if do this optimize with
4471 * label address resolving.
4472 * It's future work (if compile time was bottle neck).
4473 */
4474static int
4475iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4476{
4477#if OPT_INSTRUCTIONS_UNIFICATION
4478 LINK_ELEMENT *list;
4479 INSN *iobj, *niobj;
4480 int id, k;
4481 intptr_t j;
4482
4483 list = FIRST_ELEMENT(anchor);
4484 while (list) {
4485 if (IS_INSN(list)) {
4486 iobj = (INSN *)list;
4487 id = iobj->insn_id;
4488 if (unified_insns_data[id] != 0) {
4489 const int *const *entry = unified_insns_data[id];
4490 for (j = 1; j < (intptr_t)entry[0]; j++) {
4491 const int *unified = entry[j];
4492 LINK_ELEMENT *li = list->next;
4493 for (k = 2; k < unified[1]; k++) {
4494 if (!IS_INSN(li) ||
4495 ((INSN *)li)->insn_id != unified[k]) {
4496 goto miss;
4497 }
4498 li = li->next;
4499 }
4500 /* matched */
4501 niobj =
4502 new_unified_insn(iseq, unified[0], unified[1] - 1,
4503 list);
4504
4505 /* insert to list */
4506 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4507 niobj->link.next = li;
4508 if (li) {
4509 li->prev = (LINK_ELEMENT *)niobj;
4510 }
4511
4512 list->prev->next = (LINK_ELEMENT *)niobj;
4513 list = (LINK_ELEMENT *)niobj;
4514 break;
4515 miss:;
4516 }
4517 }
4518 }
4519 list = list->next;
4520 }
4521#endif
4522 return COMPILE_OK;
4523}
4524
4525static int
4526all_string_result_p(const NODE *node)
4527{
4528 if (!node) return FALSE;
4529 switch (nd_type(node)) {
4530 case NODE_STR: case NODE_DSTR: case NODE_FILE:
4531 return TRUE;
4532 case NODE_IF: case NODE_UNLESS:
4533 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
4534 if (all_string_result_p(RNODE_IF(node)->nd_body))
4535 return all_string_result_p(RNODE_IF(node)->nd_else);
4536 return FALSE;
4537 case NODE_AND: case NODE_OR:
4538 if (!RNODE_AND(node)->nd_2nd)
4539 return all_string_result_p(RNODE_AND(node)->nd_1st);
4540 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4541 return FALSE;
4542 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4543 default:
4544 return FALSE;
4545 }
4546}
4547
4549 rb_iseq_t *const iseq;
4550 LINK_ANCHOR *const ret;
4551 VALUE lit;
4552 const NODE *lit_node;
4553 int cnt;
4554 int dregx;
4555};
4556
4557static int
4558append_dstr_fragment(struct dstr_ctxt *args, const NODE *const node, rb_parser_string_t *str)
4559{
4560 VALUE s = rb_str_new_mutable_parser_string(str);
4561 if (args->dregx) {
4562 VALUE error = rb_reg_check_preprocess(s);
4563 if (!NIL_P(error)) {
4564 COMPILE_ERROR(args->iseq, nd_line(node), "%" PRIsVALUE, error);
4565 return COMPILE_NG;
4566 }
4567 }
4568 if (NIL_P(args->lit)) {
4569 args->lit = s;
4570 args->lit_node = node;
4571 }
4572 else {
4573 rb_str_buf_append(args->lit, s);
4574 }
4575 return COMPILE_OK;
4576}
4577
4578static void
4579flush_dstr_fragment(struct dstr_ctxt *args)
4580{
4581 if (!NIL_P(args->lit)) {
4582 rb_iseq_t *iseq = args->iseq;
4583 VALUE lit = args->lit;
4584 args->lit = Qnil;
4585 lit = rb_fstring(lit);
4586 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4587 RB_OBJ_WRITTEN(args->iseq, Qundef, lit);
4588 args->cnt++;
4589 }
4590}
4591
4592static int
4593compile_dstr_fragments_0(struct dstr_ctxt *args, const NODE *const node)
4594{
4595 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4596 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4597
4598 if (str) {
4599 CHECK(append_dstr_fragment(args, node, str));
4600 }
4601
4602 while (list) {
4603 const NODE *const head = list->nd_head;
4604 if (nd_type_p(head, NODE_STR)) {
4605 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->string));
4606 }
4607 else if (nd_type_p(head, NODE_DSTR)) {
4608 CHECK(compile_dstr_fragments_0(args, head));
4609 }
4610 else {
4611 flush_dstr_fragment(args);
4612 rb_iseq_t *iseq = args->iseq;
4613 CHECK(COMPILE(args->ret, "each string", head));
4614 args->cnt++;
4615 }
4616 list = (struct RNode_LIST *)list->nd_next;
4617 }
4618 return COMPILE_OK;
4619}
4620
4621static int
4622compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp, int dregx)
4623{
4624 struct dstr_ctxt args = {
4625 .iseq = iseq, .ret = ret,
4626 .lit = Qnil, .lit_node = NULL,
4627 .cnt = 0, .dregx = dregx,
4628 };
4629 CHECK(compile_dstr_fragments_0(&args, node));
4630 flush_dstr_fragment(&args);
4631
4632 *cntp = args.cnt;
4633
4634 return COMPILE_OK;
4635}
4636
4637static int
4638compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4639{
4640 while (node && nd_type_p(node, NODE_BLOCK)) {
4641 CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
4642 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4643 node = RNODE_BLOCK(node)->nd_next;
4644 }
4645 if (node) {
4646 CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4647 }
4648 return COMPILE_OK;
4649}
4650
4651static int
4652compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4653{
4654 int cnt;
4655 if (!RNODE_DSTR(node)->nd_next) {
4656 VALUE lit = rb_node_dstr_string_val(node);
4657 ADD_INSN1(ret, node, putstring, lit);
4658 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4659 }
4660 else {
4661 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4662 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4663 }
4664 return COMPILE_OK;
4665}
4666
4667static int
4668compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4669{
4670 int cnt;
4671 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4672
4673 if (!RNODE_DREGX(node)->nd_next) {
4674 if (!popped) {
4675 VALUE src = rb_node_dregx_string_val(node);
4676 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4677 ADD_INSN1(ret, node, putobject, match);
4678 RB_OBJ_WRITTEN(iseq, Qundef, match);
4679 }
4680 return COMPILE_OK;
4681 }
4682
4683 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4684 ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
4685
4686 if (popped) {
4687 ADD_INSN(ret, node, pop);
4688 }
4689
4690 return COMPILE_OK;
4691}
4692
4693static int
4694compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4695 LABEL *then_label, LABEL *else_label)
4696{
4697 const int line = nd_line(node);
4698 LABEL *lend = NEW_LABEL(line);
4699 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4700 + VM_SVAR_FLIPFLOP_START;
4701 VALUE key = INT2FIX(cnt);
4702
4703 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4704 ADD_INSNL(ret, node, branchif, lend);
4705
4706 /* *flip == 0 */
4707 CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
4708 ADD_INSNL(ret, node, branchunless, else_label);
4709 ADD_INSN1(ret, node, putobject, Qtrue);
4710 ADD_INSN1(ret, node, setspecial, key);
4711 if (!again) {
4712 ADD_INSNL(ret, node, jump, then_label);
4713 }
4714
4715 /* *flip == 1 */
4716 ADD_LABEL(ret, lend);
4717 CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
4718 ADD_INSNL(ret, node, branchunless, then_label);
4719 ADD_INSN1(ret, node, putobject, Qfalse);
4720 ADD_INSN1(ret, node, setspecial, key);
4721 ADD_INSNL(ret, node, jump, then_label);
4722
4723 return COMPILE_OK;
4724}
4725
4726static int
4727compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4728 LABEL *then_label, LABEL *else_label);
4729
4730#define COMPILE_SINGLE 2
4731static int
4732compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4733 LABEL *then_label, LABEL *else_label)
4734{
4735 DECL_ANCHOR(seq);
4736 INIT_ANCHOR(seq);
4737 LABEL *label = NEW_LABEL(nd_line(cond));
4738 if (!then_label) then_label = label;
4739 else if (!else_label) else_label = label;
4740
4741 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4742
4743 if (LIST_INSN_SIZE_ONE(seq)) {
4744 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4745 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4746 return COMPILE_OK;
4747 }
4748 if (!label->refcnt) {
4749 return COMPILE_SINGLE;
4750 }
4751 ADD_LABEL(seq, label);
4752 ADD_SEQ(ret, seq);
4753 return COMPILE_OK;
4754}
4755
4756static int
4757compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
4758 LABEL *then_label, LABEL *else_label)
4759{
4760 int ok;
4761 DECL_ANCHOR(ignore);
4762
4763 again:
4764 switch (nd_type(cond)) {
4765 case NODE_AND:
4766 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4767 cond = RNODE_AND(cond)->nd_2nd;
4768 if (ok == COMPILE_SINGLE) {
4769 INIT_ANCHOR(ignore);
4770 ret = ignore;
4771 then_label = NEW_LABEL(nd_line(cond));
4772 }
4773 goto again;
4774 case NODE_OR:
4775 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4776 cond = RNODE_OR(cond)->nd_2nd;
4777 if (ok == COMPILE_SINGLE) {
4778 INIT_ANCHOR(ignore);
4779 ret = ignore;
4780 else_label = NEW_LABEL(nd_line(cond));
4781 }
4782 goto again;
4783 case NODE_SYM:
4784 case NODE_LINE:
4785 case NODE_FILE:
4786 case NODE_ENCODING:
4787 case NODE_INTEGER: /* NODE_INTEGER is always true */
4788 case NODE_FLOAT: /* NODE_FLOAT is always true */
4789 case NODE_RATIONAL: /* NODE_RATIONAL is always true */
4790 case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
4791 case NODE_TRUE:
4792 case NODE_STR:
4793 case NODE_REGX:
4794 case NODE_ZLIST:
4795 case NODE_LAMBDA:
4796 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4797 ADD_INSNL(ret, cond, jump, then_label);
4798 return COMPILE_OK;
4799 case NODE_FALSE:
4800 case NODE_NIL:
4801 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4802 ADD_INSNL(ret, cond, jump, else_label);
4803 return COMPILE_OK;
4804 case NODE_LIST:
4805 case NODE_ARGSCAT:
4806 case NODE_DREGX:
4807 case NODE_DSTR:
4808 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4809 ADD_INSNL(ret, cond, jump, then_label);
4810 return COMPILE_OK;
4811 case NODE_FLIP2:
4812 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4813 return COMPILE_OK;
4814 case NODE_FLIP3:
4815 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4816 return COMPILE_OK;
4817 case NODE_DEFINED:
4818 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
4819 break;
4820 default:
4821 {
4822 DECL_ANCHOR(cond_seq);
4823 INIT_ANCHOR(cond_seq);
4824
4825 CHECK(COMPILE(cond_seq, "branch condition", cond));
4826
4827 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4828 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4829 if (insn->insn_id == BIN(putobject)) {
4830 if (RTEST(insn->operands[0])) {
4831 ADD_INSNL(ret, cond, jump, then_label);
4832 // maybe unreachable
4833 return COMPILE_OK;
4834 }
4835 else {
4836 ADD_INSNL(ret, cond, jump, else_label);
4837 return COMPILE_OK;
4838 }
4839 }
4840 }
4841 ADD_SEQ(ret, cond_seq);
4842 }
4843 break;
4844 }
4845
4846 ADD_INSNL(ret, cond, branchunless, else_label);
4847 ADD_INSNL(ret, cond, jump, then_label);
4848 return COMPILE_OK;
4849}
4850
4851#define HASH_BRACE 1
4852
4853static int
4854keyword_node_p(const NODE *const node)
4855{
4856 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4857}
4858
4859static VALUE
4860get_symbol_value(rb_iseq_t *iseq, const NODE *node)
4861{
4862 switch (nd_type(node)) {
4863 case NODE_SYM:
4864 return rb_node_sym_string_val(node);
4865 default:
4866 UNKNOWN_NODE("get_symbol_value", node, Qnil);
4867 }
4868}
4869
4870static VALUE
4871node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
4872{
4873 NODE *node = node_hash->nd_head;
4874 VALUE hash = rb_hash_new();
4875 VALUE ary = rb_ary_new();
4876
4877 for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4878 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4879 VALUE idx = rb_hash_aref(hash, key);
4880 if (!NIL_P(idx)) {
4881 rb_ary_store(ary, FIX2INT(idx), Qfalse);
4882 (*count_ptr)--;
4883 }
4884 rb_hash_aset(hash, key, INT2FIX(i));
4885 rb_ary_store(ary, i, Qtrue);
4886 (*count_ptr)++;
4887 }
4888
4889 return ary;
4890}
4891
4892static int
4893compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4894 const NODE *const root_node,
4895 struct rb_callinfo_kwarg **const kw_arg_ptr,
4896 unsigned int *flag)
4897{
4898 RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
4899 RUBY_ASSERT(kw_arg_ptr != NULL);
4900 RUBY_ASSERT(flag != NULL);
4901
4902 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4903 const NODE *node = RNODE_HASH(root_node)->nd_head;
4904 int seen_nodes = 0;
4905
4906 while (node) {
4907 const NODE *key_node = RNODE_LIST(node)->nd_head;
4908 seen_nodes++;
4909
4910 RUBY_ASSERT(nd_type_p(node, NODE_LIST));
4911 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4912 /* can be keywords */
4913 }
4914 else {
4915 if (flag) {
4916 *flag |= VM_CALL_KW_SPLAT;
4917 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4918 /* A new hash will be created for the keyword arguments
4919 * in this case, so mark the method as passing mutable
4920 * keyword splat.
4921 */
4922 *flag |= VM_CALL_KW_SPLAT_MUT;
4923 }
4924 }
4925 return FALSE;
4926 }
4927 node = RNODE_LIST(node)->nd_next; /* skip value node */
4928 node = RNODE_LIST(node)->nd_next;
4929 }
4930
4931 /* may be keywords */
4932 node = RNODE_HASH(root_node)->nd_head;
4933 {
4934 int len = 0;
4935 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
4936 struct rb_callinfo_kwarg *kw_arg =
4937 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4938 VALUE *keywords = kw_arg->keywords;
4939 int i = 0;
4940 int j = 0;
4941 kw_arg->references = 0;
4942 kw_arg->keyword_len = len;
4943
4944 *kw_arg_ptr = kw_arg;
4945
4946 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4947 const NODE *key_node = RNODE_LIST(node)->nd_head;
4948 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4949 int popped = TRUE;
4950 if (rb_ary_entry(key_index, i)) {
4951 keywords[j] = get_symbol_value(iseq, key_node);
4952 j++;
4953 popped = FALSE;
4954 }
4955 NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
4956 }
4957 RUBY_ASSERT(j == len);
4958 return TRUE;
4959 }
4960 }
4961 return FALSE;
4962}
4963
4964static int
4965compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
4966{
4967 int len = 0;
4968
4969 for (; node; len++, node = RNODE_LIST(node)->nd_next) {
4970 if (CPDEBUG > 0) {
4971 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4972 }
4973
4974 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
4975 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4976 }
4977 else {
4978 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4979 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
4980 }
4981 }
4982
4983 return len;
4984}
4985
4986static inline bool
4987frozen_string_literal_p(const rb_iseq_t *iseq)
4988{
4989 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4990}
4991
4992static inline bool
4993static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
4994{
4995 switch (nd_type(node)) {
4996 case NODE_SYM:
4997 case NODE_REGX:
4998 case NODE_LINE:
4999 case NODE_ENCODING:
5000 case NODE_INTEGER:
5001 case NODE_FLOAT:
5002 case NODE_RATIONAL:
5003 case NODE_IMAGINARY:
5004 case NODE_NIL:
5005 case NODE_TRUE:
5006 case NODE_FALSE:
5007 return TRUE;
5008 case NODE_STR:
5009 case NODE_FILE:
5010 return hash_key || frozen_string_literal_p(iseq);
5011 default:
5012 return FALSE;
5013 }
5014}
5015
5016static inline VALUE
5017static_literal_value(const NODE *node, rb_iseq_t *iseq)
5018{
5019 switch (nd_type(node)) {
5020 case NODE_INTEGER:
5021 return rb_node_integer_literal_val(node);
5022 case NODE_FLOAT:
5023 return rb_node_float_literal_val(node);
5024 case NODE_RATIONAL:
5025 return rb_node_rational_literal_val(node);
5026 case NODE_IMAGINARY:
5027 return rb_node_imaginary_literal_val(node);
5028 case NODE_NIL:
5029 return Qnil;
5030 case NODE_TRUE:
5031 return Qtrue;
5032 case NODE_FALSE:
5033 return Qfalse;
5034 case NODE_SYM:
5035 return rb_node_sym_string_val(node);
5036 case NODE_REGX:
5037 return rb_node_regx_string_val(node);
5038 case NODE_LINE:
5039 return rb_node_line_lineno_val(node);
5040 case NODE_ENCODING:
5041 return rb_node_encoding_val(node);
5042 case NODE_FILE:
5043 case NODE_STR:
5044 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
5045 VALUE lit = get_string_value(node);
5046 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (int)nd_line(node));
5047 }
5048 else {
5049 return get_string_value(node);
5050 }
5051 default:
5052 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
5053 }
5054}
5055
5056static int
5057compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
5058{
5059 const NODE *line_node = node;
5060
5061 if (nd_type_p(node, NODE_ZLIST)) {
5062 if (!popped) {
5063 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5064 }
5065 return 0;
5066 }
5067
5068 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5069
5070 if (popped) {
5071 for (; node; node = RNODE_LIST(node)->nd_next) {
5072 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
5073 }
5074 return 1;
5075 }
5076
5077 /* Compilation of an array literal.
5078 * The following code is essentially the same as:
5079 *
5080 * for (int count = 0; node; count++; node->nd_next) {
5081 * compile(node->nd_head);
5082 * }
5083 * ADD_INSN(newarray, count);
5084 *
5085 * However, there are three points.
5086 *
5087 * - The code above causes stack overflow for a big string literal.
5088 * The following limits the stack length up to max_stack_len.
5089 *
5090 * [x1,x2,...,x10000] =>
5091 * push x1 ; push x2 ; ...; push x256; newarray 256;
5092 * push x257; push x258; ...; push x512; pushtoarray 256;
5093 * push x513; push x514; ...; push x768; pushtoarray 256;
5094 * ...
5095 *
5096 * - Long subarray can be optimized by pre-allocating a hidden array.
5097 *
5098 * [1,2,3,...,100] =>
5099 * duparray [1,2,3,...,100]
5100 *
5101 * [x, 1,2,3,...,100, z] =>
5102 * push x; newarray 1;
5103 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
5104 * push z; pushtoarray 1;
5105 *
5106 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
5107 * to only push it onto the array if it is not empty
5108 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
5109 *
5110 * [1,2,3,**kw] =>
5111 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
5112 */
5113
5114 const int max_stack_len = 0x100;
5115 const int min_tmp_ary_len = 0x40;
5116 int stack_len = 0;
5117
5118 /* Either create a new array, or push to the existing array */
5119#define FLUSH_CHUNK \
5120 if (stack_len) { \
5121 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5122 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5123 first_chunk = FALSE; \
5124 stack_len = 0; \
5125 }
5126
5127 while (node) {
5128 int count = 1;
5129
5130 /* pre-allocation check (this branch can be omittable) */
5131 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
5132 /* count the elements that are optimizable */
5133 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5134 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5135 count++;
5136
5137 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5138 /* The literal contains only optimizable elements, or the subarray is long enough */
5139 VALUE ary = rb_ary_hidden_new(count);
5140
5141 /* Create a hidden array */
5142 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5143 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5144 OBJ_FREEZE(ary);
5145
5146 /* Emit optimized code */
5147 FLUSH_CHUNK;
5148 if (first_chunk) {
5149 ADD_INSN1(ret, line_node, duparray, ary);
5150 first_chunk = FALSE;
5151 }
5152 else {
5153 ADD_INSN1(ret, line_node, putobject, ary);
5154 ADD_INSN(ret, line_node, concattoarray);
5155 }
5156 RB_OBJ_WRITTEN(iseq, Qundef, ary);
5157 }
5158 }
5159
5160 /* Base case: Compile "count" elements */
5161 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5162 if (CPDEBUG > 0) {
5163 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
5164 }
5165
5166 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5167 /* Create array or push existing non-keyword elements onto array */
5168 if (stack_len == 0 && first_chunk) {
5169 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
5170 }
5171 else {
5172 FLUSH_CHUNK;
5173 }
5174 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5175 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5176 return 1;
5177 }
5178 else {
5179 NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
5180 stack_len++;
5181 }
5182
5183 /* If there are many pushed elements, flush them to avoid stack overflow */
5184 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5185 }
5186 }
5187
5188 FLUSH_CHUNK;
5189#undef FLUSH_CHUNK
5190 return 1;
5191}
5192
5193static inline int
5194static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
5195{
5196 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);
5197}
5198
5199static int
5200compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
5201{
5202 const NODE *line_node = node;
5203
5204 node = RNODE_HASH(node)->nd_head;
5205
5206 if (!node || nd_type_p(node, NODE_ZLIST)) {
5207 if (!popped) {
5208 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5209 }
5210 return 0;
5211 }
5212
5213 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5214
5215 if (popped) {
5216 for (; node; node = RNODE_LIST(node)->nd_next) {
5217 NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
5218 }
5219 return 1;
5220 }
5221
5222 /* Compilation of a hash literal (or keyword arguments).
5223 * This is very similar to compile_array, but there are some differences:
5224 *
5225 * - It contains key-value pairs. So we need to take every two elements.
5226 * We can assume that the length is always even.
5227 *
5228 * - Merging is done by a method call (id_core_hash_merge_ptr).
5229 * Sometimes we need to insert the receiver, so "anchor" is needed.
5230 * In addition, a method call is much slower than concatarray.
5231 * So it pays only when the subsequence is really long.
5232 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
5233 *
5234 * - We need to handle keyword splat: **kw.
5235 * For **kw, the key part (node->nd_head) is NULL, and the value part
5236 * (node->nd_next->nd_head) is "kw".
5237 * The code is a bit difficult to avoid hash allocation for **{}.
5238 */
5239
5240 const int max_stack_len = 0x100;
5241 const int min_tmp_hash_len = 0x800;
5242 int stack_len = 0;
5243 int first_chunk = 1;
5244 DECL_ANCHOR(anchor);
5245 INIT_ANCHOR(anchor);
5246
5247 /* Convert pushed elements to a hash, and merge if needed */
5248#define FLUSH_CHUNK() \
5249 if (stack_len) { \
5250 if (first_chunk) { \
5251 APPEND_LIST(ret, anchor); \
5252 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5253 } \
5254 else { \
5255 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5256 ADD_INSN(ret, line_node, swap); \
5257 APPEND_LIST(ret, anchor); \
5258 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5259 } \
5260 INIT_ANCHOR(anchor); \
5261 first_chunk = stack_len = 0; \
5262 }
5263
5264 while (node) {
5265 int count = 1;
5266
5267 /* pre-allocation check (this branch can be omittable) */
5268 if (static_literal_node_pair_p(node, iseq)) {
5269 /* count the elements that are optimizable */
5270 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5271 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5272 count++;
5273
5274 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5275 /* The literal contains only optimizable elements, or the subsequence is long enough */
5276 VALUE ary = rb_ary_hidden_new(count);
5277
5278 /* Create a hidden hash */
5279 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5280 VALUE elem[2];
5281 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5282 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5283 rb_ary_cat(ary, elem, 2);
5284 }
5285 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
5286 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
5287 hash = rb_obj_hide(hash);
5288 OBJ_FREEZE(hash);
5289
5290 /* Emit optimized code */
5291 FLUSH_CHUNK();
5292 if (first_chunk) {
5293 ADD_INSN1(ret, line_node, duphash, hash);
5294 first_chunk = 0;
5295 }
5296 else {
5297 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5298 ADD_INSN(ret, line_node, swap);
5299
5300 ADD_INSN1(ret, line_node, putobject, hash);
5301
5302 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5303 }
5304 RB_OBJ_WRITTEN(iseq, Qundef, hash);
5305 }
5306 }
5307
5308 /* Base case: Compile "count" elements */
5309 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5310
5311 if (CPDEBUG > 0) {
5312 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
5313 }
5314
5315 if (RNODE_LIST(node)->nd_head) {
5316 /* Normal key-value pair */
5317 NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
5318 NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5319 stack_len += 2;
5320
5321 /* If there are many pushed elements, flush them to avoid stack overflow */
5322 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5323 }
5324 else {
5325 /* kwsplat case: foo(..., **kw, ...) */
5326 FLUSH_CHUNK();
5327
5328 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5329 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
5330 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
5331 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
5332 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
5333
5334 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
5335 if (empty_kw) {
5336 if (only_kw && method_call_keywords) {
5337 /* **{} appears at the only keyword argument in method call,
5338 * so it won't be modified.
5339 * kw is a special NODE_LIT that contains a special empty hash,
5340 * so this emits: putobject {}.
5341 * This is only done for method calls and not for literal hashes,
5342 * because literal hashes should always result in a new hash.
5343 */
5344 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5345 }
5346 else if (first_kw) {
5347 /* **{} appears as the first keyword argument, so it may be modified.
5348 * We need to create a fresh hash object.
5349 */
5350 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5351 }
5352 /* Any empty keyword splats that are not the first can be ignored.
5353 * since merging an empty hash into the existing hash is the same
5354 * as not merging it. */
5355 }
5356 else {
5357 if (only_kw && method_call_keywords) {
5358 /* **kw is only keyword argument in method call.
5359 * Use directly. This will be not be flagged as mutable.
5360 * This is only done for method calls and not for literal hashes,
5361 * because literal hashes should always result in a new hash.
5362 */
5363 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5364 }
5365 else {
5366 /* There is more than one keyword argument, or this is not a method
5367 * call. In that case, we need to add an empty hash (if first keyword),
5368 * or merge the hash to the accumulated hash (if not the first keyword).
5369 */
5370 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5371 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
5372 else ADD_INSN(ret, line_node, swap);
5373
5374 NO_CHECK(COMPILE(ret, "keyword splat", kw));
5375
5376 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
5377 }
5378 }
5379
5380 first_chunk = 0;
5381 }
5382 }
5383 }
5384
5385 FLUSH_CHUNK();
5386#undef FLUSH_CHUNK
5387 return 1;
5388}
5389
5390VALUE
5391rb_node_case_when_optimizable_literal(const NODE *const node)
5392{
5393 switch (nd_type(node)) {
5394 case NODE_INTEGER:
5395 return rb_node_integer_literal_val(node);
5396 case NODE_FLOAT: {
5397 VALUE v = rb_node_float_literal_val(node);
5398 double ival;
5399
5400 if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
5401 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
5402 }
5403 return v;
5404 }
5405 case NODE_RATIONAL:
5406 case NODE_IMAGINARY:
5407 return Qundef;
5408 case NODE_NIL:
5409 return Qnil;
5410 case NODE_TRUE:
5411 return Qtrue;
5412 case NODE_FALSE:
5413 return Qfalse;
5414 case NODE_SYM:
5415 return rb_node_sym_string_val(node);
5416 case NODE_LINE:
5417 return rb_node_line_lineno_val(node);
5418 case NODE_STR:
5419 return rb_node_str_string_val(node);
5420 case NODE_FILE:
5421 return rb_node_file_path_val(node);
5422 }
5423 return Qundef;
5424}
5425
5426static int
5427when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5428 LABEL *l1, int only_special_literals, VALUE literals)
5429{
5430 while (vals) {
5431 const NODE *val = RNODE_LIST(vals)->nd_head;
5432 VALUE lit = rb_node_case_when_optimizable_literal(val);
5433
5434 if (UNDEF_P(lit)) {
5435 only_special_literals = 0;
5436 }
5437 else if (NIL_P(rb_hash_lookup(literals, lit))) {
5438 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
5439 }
5440
5441 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5442 debugp_param("nd_lit", get_string_value(val));
5443 lit = get_string_value(val);
5444 ADD_INSN1(cond_seq, val, putobject, lit);
5445 RB_OBJ_WRITTEN(iseq, Qundef, lit);
5446 }
5447 else {
5448 if (!COMPILE(cond_seq, "when cond", val)) return -1;
5449 }
5450
5451 // Emit pattern === target
5452 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
5453 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
5454 ADD_INSNL(cond_seq, val, branchif, l1);
5455 vals = RNODE_LIST(vals)->nd_next;
5456 }
5457 return only_special_literals;
5458}
5459
5460static int
5461when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
5462 LABEL *l1, int only_special_literals, VALUE literals)
5463{
5464 const NODE *line_node = vals;
5465
5466 switch (nd_type(vals)) {
5467 case NODE_LIST:
5468 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5469 return COMPILE_NG;
5470 break;
5471 case NODE_SPLAT:
5472 ADD_INSN (cond_seq, line_node, dup);
5473 CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
5474 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5475 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5476 ADD_INSNL(cond_seq, line_node, branchif, l1);
5477 break;
5478 case NODE_ARGSCAT:
5479 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5480 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5481 break;
5482 case NODE_ARGSPUSH:
5483 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5484 ADD_INSN (cond_seq, line_node, dup);
5485 CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5486 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5487 ADD_INSNL(cond_seq, line_node, branchif, l1);
5488 break;
5489 default:
5490 ADD_INSN (cond_seq, line_node, dup);
5491 CHECK(COMPILE(cond_seq, "when val", vals));
5492 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
5493 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5494 ADD_INSNL(cond_seq, line_node, branchif, l1);
5495 break;
5496 }
5497 return COMPILE_OK;
5498}
5499
5500/* Multiple Assignment Handling
5501 *
5502 * In order to handle evaluation of multiple assignment such that the left hand side
5503 * is evaluated before the right hand side, we need to process the left hand side
5504 * and see if there are any attributes that need to be assigned, or constants set
5505 * on explicit objects. If so, we add instructions to evaluate the receiver of
5506 * any assigned attributes or constants before we process the right hand side.
5507 *
5508 * For a multiple assignment such as:
5509 *
5510 * l1.m1, l2[0] = r3, r4
5511 *
5512 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5513 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5514 * On the VM stack, this looks like:
5515 *
5516 * self # putself
5517 * l1 # send
5518 * l1, self # putself
5519 * l1, l2 # send
5520 * l1, l2, 0 # putobject 0
5521 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5522 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5523 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5524 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5525 * l1, l2, 0, [r3, r4], r4, m1= # send
5526 * l1, l2, 0, [r3, r4], r4 # pop
5527 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5528 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5529 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5530 * l1, l2, 0, [r3, r4], r4, []= # send
5531 * l1, l2, 0, [r3, r4], r4 # pop
5532 * l1, l2, 0, [r3, r4] # pop
5533 * [r3, r4], l2, 0, [r3, r4] # setn 3
5534 * [r3, r4], l2, 0 # pop
5535 * [r3, r4], l2 # pop
5536 * [r3, r4] # pop
5537 *
5538 * This is made more complex when you have to handle splats, post args,
5539 * and arbitrary levels of nesting. You need to keep track of the total
5540 * number of attributes to set, and for each attribute, how many entries
5541 * are on the stack before the final attribute, in order to correctly
5542 * calculate the topn value to use to get the receiver of the attribute
5543 * setter method.
5544 *
5545 * A brief description of the VM stack for simple multiple assignment
5546 * with no splat (rhs_array will not be present if the return value of
5547 * the multiple assignment is not needed):
5548 *
5549 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5550 *
5551 * For multiple assignment with splats, while processing the part before
5552 * the splat (splat+post here is an array of the splat and the post arguments):
5553 *
5554 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5555 *
5556 * When processing the splat and post arguments:
5557 *
5558 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5559 *
5560 * When processing nested multiple assignment, existing values on the stack
5561 * are kept. So for:
5562 *
5563 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5564 *
5565 * The stack layout would be the following before processing the nested
5566 * multiple assignment:
5567 *
5568 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5569 *
5570 * In order to handle this correctly, we need to keep track of the nesting
5571 * level for each attribute assignment, as well as the attribute number
5572 * (left hand side attributes are processed left to right) and number of
5573 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5574 * this information.
5575 *
5576 * We also need to track information for the entire multiple assignment, such
5577 * as the total number of arguments, and the current nesting level, to
5578 * handle both nested multiple assignment as well as cases where the
5579 * rhs is not needed. We also need to keep track of all attribute
5580 * assignments in this, which we do using a linked listed. struct masgn_state
5581 * tracks this information.
5582 */
5583
5585 INSN *before_insn;
5586 struct masgn_lhs_node *next;
5587 const NODE *line_node;
5588 int argn;
5589 int num_args;
5590 int lhs_pos;
5591};
5592
5594 struct masgn_lhs_node *first_memo;
5595 struct masgn_lhs_node *last_memo;
5596 int lhs_level;
5597 int num_args;
5598 bool nested;
5599};
5600
5601static int
5602add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5603{
5604 if (!state) {
5605 rb_bug("no masgn_state");
5606 }
5607
5608 struct masgn_lhs_node *memo;
5609 memo = malloc(sizeof(struct masgn_lhs_node));
5610 if (!memo) {
5611 return COMPILE_NG;
5612 }
5613
5614 memo->before_insn = before_insn;
5615 memo->line_node = line_node;
5616 memo->argn = state->num_args + 1;
5617 memo->num_args = argc;
5618 state->num_args += argc;
5619 memo->lhs_pos = lhs_pos;
5620 memo->next = NULL;
5621 if (!state->first_memo) {
5622 state->first_memo = memo;
5623 }
5624 else {
5625 state->last_memo->next = memo;
5626 }
5627 state->last_memo = memo;
5628
5629 return COMPILE_OK;
5630}
5631
5632static 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);
5633
5634static int
5635compile_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)
5636{
5637 switch (nd_type(node)) {
5638 case NODE_ATTRASGN: {
5639 INSN *iobj;
5640 const NODE *line_node = node;
5641
5642 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5643
5644 bool safenav_call = false;
5645 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5646 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5647 ASSUME(iobj);
5648 ELEM_REMOVE(insn_element);
5649 if (!IS_INSN_ID(iobj, send)) {
5650 safenav_call = true;
5651 iobj = (INSN *)get_prev_insn(iobj);
5652 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5653 }
5654 (pre->last = iobj->link.prev)->next = 0;
5655
5656 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5657 int argc = vm_ci_argc(ci) + 1;
5658 ci = ci_argc_set(iseq, ci, argc);
5659 OPERAND_AT(iobj, 0) = (VALUE)ci;
5660 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5661
5662 if (argc == 1) {
5663 ADD_INSN(lhs, line_node, swap);
5664 }
5665 else {
5666 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5667 }
5668
5669 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5670 return COMPILE_NG;
5671 }
5672
5673 iobj->link.prev = lhs->last;
5674 lhs->last->next = &iobj->link;
5675 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5676 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5677 int argc = vm_ci_argc(ci);
5678 bool dupsplat = false;
5679 ci = ci_argc_set(iseq, ci, argc - 1);
5680 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5681 /* Given h[*a], _ = ary
5682 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5683 * `a` must be dupped, because it will be appended with ary[0]
5684 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5685 */
5686 dupsplat = true;
5687 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5688 }
5689 OPERAND_AT(iobj, 0) = (VALUE)ci;
5690 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5691
5692 /* Given: h[*a], h[*b, 1] = ary
5693 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5694 * so this uses splatarray true on a to dup it before using pushtoarray
5695 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5696 * so you can use pushtoarray directly
5697 */
5698 int line_no = nd_line(line_node);
5699 int node_id = nd_node_id(line_node);
5700
5701 if (dupsplat) {
5702 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5703 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
5704 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5705 }
5706 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
5707 }
5708 if (!safenav_call) {
5709 ADD_INSN(lhs, line_node, pop);
5710 if (argc != 1) {
5711 ADD_INSN(lhs, line_node, pop);
5712 }
5713 }
5714 for (int i=0; i < argc; i++) {
5715 ADD_INSN(post, line_node, pop);
5716 }
5717 break;
5718 }
5719 case NODE_MASGN: {
5720 DECL_ANCHOR(nest_rhs);
5721 INIT_ANCHOR(nest_rhs);
5722 DECL_ANCHOR(nest_lhs);
5723 INIT_ANCHOR(nest_lhs);
5724
5725 int prev_level = state->lhs_level;
5726 bool prev_nested = state->nested;
5727 state->nested = 1;
5728 state->lhs_level = lhs_pos - 1;
5729 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5730 state->lhs_level = prev_level;
5731 state->nested = prev_nested;
5732
5733 ADD_SEQ(lhs, nest_rhs);
5734 ADD_SEQ(lhs, nest_lhs);
5735 break;
5736 }
5737 case NODE_CDECL:
5738 if (!RNODE_CDECL(node)->nd_vid) {
5739 /* Special handling only needed for expr::C, not for C */
5740 INSN *iobj;
5741
5742 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5743
5744 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5745 iobj = (INSN *)insn_element; /* setconstant insn */
5746 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5747 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5748 ELEM_REMOVE(insn_element);
5749 pre->last = iobj->link.prev;
5750 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5751
5752 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5753 return COMPILE_NG;
5754 }
5755
5756 ADD_INSN(post, node, pop);
5757 break;
5758 }
5759 /* Fallthrough */
5760 default: {
5761 DECL_ANCHOR(anchor);
5762 INIT_ANCHOR(anchor);
5763 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5764 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5765 ADD_SEQ(lhs, anchor);
5766 }
5767 }
5768
5769 return COMPILE_OK;
5770}
5771
5772static int
5773compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5774{
5775 if (lhsn) {
5776 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5777 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5778 }
5779 return COMPILE_OK;
5780}
5781
5782static int
5783compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5784 const NODE *rhsn, const NODE *orig_lhsn)
5785{
5786 VALUE mem[64];
5787 const int memsize = numberof(mem);
5788 int memindex = 0;
5789 int llen = 0, rlen = 0;
5790 int i;
5791 const NODE *lhsn = orig_lhsn;
5792
5793#define MEMORY(v) { \
5794 int i; \
5795 if (memindex == memsize) return 0; \
5796 for (i=0; i<memindex; i++) { \
5797 if (mem[i] == (v)) return 0; \
5798 } \
5799 mem[memindex++] = (v); \
5800}
5801
5802 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5803 return 0;
5804 }
5805
5806 while (lhsn) {
5807 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5808 switch (nd_type(ln)) {
5809 case NODE_LASGN:
5810 case NODE_DASGN:
5811 case NODE_IASGN:
5812 case NODE_CVASGN:
5813 MEMORY(get_nd_vid(ln));
5814 break;
5815 default:
5816 return 0;
5817 }
5818 lhsn = RNODE_LIST(lhsn)->nd_next;
5819 llen++;
5820 }
5821
5822 while (rhsn) {
5823 if (llen <= rlen) {
5824 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5825 }
5826 else {
5827 NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
5828 }
5829 rhsn = RNODE_LIST(rhsn)->nd_next;
5830 rlen++;
5831 }
5832
5833 if (llen > rlen) {
5834 for (i=0; i<llen-rlen; i++) {
5835 ADD_INSN(ret, orig_lhsn, putnil);
5836 }
5837 }
5838
5839 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5840 return 1;
5841}
5842
5843static int
5844compile_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)
5845{
5846 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5847 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5848 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5849 const NODE *lhsn_count = lhsn;
5850 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5851
5852 int llen = 0;
5853 int lpos = 0;
5854
5855 while (lhsn_count) {
5856 llen++;
5857 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5858 }
5859 while (lhsn) {
5860 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5861 lpos++;
5862 lhsn = RNODE_LIST(lhsn)->nd_next;
5863 }
5864
5865 if (lhs_splat) {
5866 if (nd_type_p(splatn, NODE_POSTARG)) {
5867 /*a, b, *r, p1, p2 */
5868 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5869 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5870 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5871 int ppos = 0;
5872 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5873
5874 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5875
5876 if (NODE_NAMED_REST_P(restn)) {
5877 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5878 }
5879 while (postn) {
5880 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5881 ppos++;
5882 postn = RNODE_LIST(postn)->nd_next;
5883 }
5884 }
5885 else {
5886 /* a, b, *r */
5887 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5888 }
5889 }
5890
5891 if (!state->nested) {
5892 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5893 }
5894
5895 if (!popped) {
5896 ADD_INSN(rhs, node, dup);
5897 }
5898 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5899 return COMPILE_OK;
5900}
5901
5902static int
5903compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5904{
5905 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5906 struct masgn_state state;
5907 state.lhs_level = popped ? 0 : 1;
5908 state.nested = 0;
5909 state.num_args = 0;
5910 state.first_memo = NULL;
5911 state.last_memo = NULL;
5912
5913 DECL_ANCHOR(pre);
5914 INIT_ANCHOR(pre);
5915 DECL_ANCHOR(rhs);
5916 INIT_ANCHOR(rhs);
5917 DECL_ANCHOR(lhs);
5918 INIT_ANCHOR(lhs);
5919 DECL_ANCHOR(post);
5920 INIT_ANCHOR(post);
5921 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5922
5923 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5924 while (memo) {
5925 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5926 for (int i = 0; i < memo->num_args; i++) {
5927 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5928 }
5929 tmp_memo = memo->next;
5930 free(memo);
5931 memo = tmp_memo;
5932 }
5933 CHECK(ok);
5934
5935 ADD_SEQ(ret, pre);
5936 ADD_SEQ(ret, rhs);
5937 ADD_SEQ(ret, lhs);
5938 if (!popped && state.num_args >= 1) {
5939 /* make sure rhs array is returned before popping */
5940 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5941 }
5942 ADD_SEQ(ret, post);
5943 }
5944 return COMPILE_OK;
5945}
5946
5947static VALUE
5948collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5949{
5950 VALUE arr = rb_ary_new();
5951 for (;;) {
5952 switch (nd_type(node)) {
5953 case NODE_CONST:
5954 rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
5955 return arr;
5956 case NODE_COLON3:
5957 rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
5958 rb_ary_unshift(arr, ID2SYM(idNULL));
5959 return arr;
5960 case NODE_COLON2:
5961 rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
5962 node = RNODE_COLON2(node)->nd_head;
5963 break;
5964 default:
5965 return Qfalse;
5966 }
5967 }
5968}
5969
5970static int
5971compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5972 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5973{
5974 switch (nd_type(node)) {
5975 case NODE_CONST:
5976 debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5977 ADD_INSN1(body, node, putobject, Qtrue);
5978 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
5979 break;
5980 case NODE_COLON3:
5981 debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5982 ADD_INSN(body, node, pop);
5983 ADD_INSN1(body, node, putobject, rb_cObject);
5984 ADD_INSN1(body, node, putobject, Qtrue);
5985 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
5986 break;
5987 case NODE_COLON2:
5988 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5989 debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5990 ADD_INSN1(body, node, putobject, Qfalse);
5991 ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
5992 break;
5993 default:
5994 CHECK(COMPILE(pref, "const colon2 prefix", node));
5995 break;
5996 }
5997 return COMPILE_OK;
5998}
5999
6000static int
6001compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
6002{
6003 if (nd_type_p(cpath, NODE_COLON3)) {
6004 /* toplevel class ::Foo */
6005 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6006 return VM_DEFINECLASS_FLAG_SCOPED;
6007 }
6008 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6009 /* Bar::Foo */
6010 NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6011 return VM_DEFINECLASS_FLAG_SCOPED;
6012 }
6013 else {
6014 /* class at cbase Foo */
6015 ADD_INSN1(ret, cpath, putspecialobject,
6016 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6017 return 0;
6018 }
6019}
6020
6021static inline int
6022private_recv_p(const NODE *node)
6023{
6024 NODE *recv = get_nd_recv(node);
6025 if (recv && nd_type_p(recv, NODE_SELF)) {
6026 return RNODE_SELF(recv)->nd_state != 0;
6027 }
6028 return 0;
6029}
6030
6031static void
6032defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6033 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
6034
6035static int
6036compile_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);
6037
6038static void
6039defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6040 const NODE *const node, LABEL **lfinish, VALUE needstr,
6041 bool keep_result)
6042{
6043 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6044 enum node_type type;
6045 const int line = nd_line(node);
6046 const NODE *line_node = node;
6047
6048 switch (type = nd_type(node)) {
6049
6050 /* easy literals */
6051 case NODE_NIL:
6052 expr_type = DEFINED_NIL;
6053 break;
6054 case NODE_SELF:
6055 expr_type = DEFINED_SELF;
6056 break;
6057 case NODE_TRUE:
6058 expr_type = DEFINED_TRUE;
6059 break;
6060 case NODE_FALSE:
6061 expr_type = DEFINED_FALSE;
6062 break;
6063
6064 case NODE_HASH:
6065 case NODE_LIST:{
6066 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6067
6068 if (vals) {
6069 do {
6070 if (RNODE_LIST(vals)->nd_head) {
6071 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
6072
6073 if (!lfinish[1]) {
6074 lfinish[1] = NEW_LABEL(line);
6075 }
6076 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6077 }
6078 } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6079 }
6080 }
6081 /* fall through */
6082 case NODE_STR:
6083 case NODE_SYM:
6084 case NODE_REGX:
6085 case NODE_LINE:
6086 case NODE_FILE:
6087 case NODE_ENCODING:
6088 case NODE_INTEGER:
6089 case NODE_FLOAT:
6090 case NODE_RATIONAL:
6091 case NODE_IMAGINARY:
6092 case NODE_ZLIST:
6093 case NODE_AND:
6094 case NODE_OR:
6095 default:
6096 expr_type = DEFINED_EXPR;
6097 break;
6098
6099 case NODE_SPLAT:
6100 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
6101 if (!lfinish[1]) {
6102 lfinish[1] = NEW_LABEL(line);
6103 }
6104 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6105 expr_type = DEFINED_EXPR;
6106 break;
6107
6108 /* variables */
6109 case NODE_LVAR:
6110 case NODE_DVAR:
6111 expr_type = DEFINED_LVAR;
6112 break;
6113
6114#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6115 case NODE_IVAR:
6116 ADD_INSN3(ret, line_node, definedivar,
6117 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6118 return;
6119
6120 case NODE_GVAR:
6121 ADD_INSN(ret, line_node, putnil);
6122 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
6123 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6124 return;
6125
6126 case NODE_CVAR:
6127 ADD_INSN(ret, line_node, putnil);
6128 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
6129 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6130 return;
6131
6132 case NODE_CONST:
6133 ADD_INSN(ret, line_node, putnil);
6134 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
6135 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6136 return;
6137 case NODE_COLON2:
6138 if (!lfinish[1]) {
6139 lfinish[1] = NEW_LABEL(line);
6140 }
6141 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
6142 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6143 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6144
6145 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
6146 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
6147 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6148 }
6149 else {
6150 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6151 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6152 }
6153 return;
6154 case NODE_COLON3:
6155 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6156 ADD_INSN3(ret, line_node, defined,
6157 INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6158 return;
6159
6160 /* method dispatch */
6161 case NODE_CALL:
6162 case NODE_OPCALL:
6163 case NODE_VCALL:
6164 case NODE_FCALL:
6165 case NODE_ATTRASGN:{
6166 const int explicit_receiver =
6167 (type == NODE_CALL || type == NODE_OPCALL ||
6168 (type == NODE_ATTRASGN && !private_recv_p(node)));
6169
6170 if (get_nd_args(node) || explicit_receiver) {
6171 if (!lfinish[1]) {
6172 lfinish[1] = NEW_LABEL(line);
6173 }
6174 if (!lfinish[2]) {
6175 lfinish[2] = NEW_LABEL(line);
6176 }
6177 }
6178 if (get_nd_args(node)) {
6179 defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
6180 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6181 }
6182 if (explicit_receiver) {
6183 defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
6184 switch (nd_type(get_nd_recv(node))) {
6185 case NODE_CALL:
6186 case NODE_OPCALL:
6187 case NODE_VCALL:
6188 case NODE_FCALL:
6189 case NODE_ATTRASGN:
6190 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6191 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
6192 break;
6193 default:
6194 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6195 NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
6196 break;
6197 }
6198 if (keep_result) {
6199 ADD_INSN(ret, line_node, dup);
6200 }
6201 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
6202 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6203 }
6204 else {
6205 ADD_INSN(ret, line_node, putself);
6206 if (keep_result) {
6207 ADD_INSN(ret, line_node, dup);
6208 }
6209 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
6210 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6211 }
6212 return;
6213 }
6214
6215 case NODE_YIELD:
6216 ADD_INSN(ret, line_node, putnil);
6217 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
6218 PUSH_VAL(DEFINED_YIELD));
6219 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6220 return;
6221
6222 case NODE_BACK_REF:
6223 case NODE_NTH_REF:
6224 ADD_INSN(ret, line_node, putnil);
6225 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
6226 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
6227 PUSH_VAL(DEFINED_GVAR));
6228 return;
6229
6230 case NODE_SUPER:
6231 case NODE_ZSUPER:
6232 ADD_INSN(ret, line_node, putnil);
6233 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
6234 PUSH_VAL(DEFINED_ZSUPER));
6235 return;
6236
6237#undef PUSH_VAL
6238 case NODE_OP_ASGN1:
6239 case NODE_OP_ASGN2:
6240 case NODE_OP_ASGN_OR:
6241 case NODE_OP_ASGN_AND:
6242 case NODE_MASGN:
6243 case NODE_LASGN:
6244 case NODE_DASGN:
6245 case NODE_GASGN:
6246 case NODE_IASGN:
6247 case NODE_CDECL:
6248 case NODE_CVASGN:
6249 case NODE_OP_CDECL:
6250 expr_type = DEFINED_ASGN;
6251 break;
6252 }
6253
6254 RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
6255
6256 if (needstr != Qfalse) {
6257 VALUE str = rb_iseq_defined_string(expr_type);
6258 ADD_INSN1(ret, line_node, putobject, str);
6259 }
6260 else {
6261 ADD_INSN1(ret, line_node, putobject, Qtrue);
6262 }
6263}
6264
6265static void
6266build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
6267{
6268 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6269 iseq_set_exception_local_table(iseq);
6270}
6271
6272static void
6273defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
6274 const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
6275{
6276 LINK_ELEMENT *lcur = ret->last;
6277 defined_expr0(iseq, ret, node, lfinish, needstr, false);
6278 if (lfinish[1]) {
6279 int line = nd_line(node);
6280 LABEL *lstart = NEW_LABEL(line);
6281 LABEL *lend = NEW_LABEL(line);
6282 const rb_iseq_t *rescue;
6284 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6285 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6286 rb_str_concat(rb_str_new2("defined guard in "),
6287 ISEQ_BODY(iseq)->location.label),
6288 ISEQ_TYPE_RESCUE, 0);
6289 lstart->rescued = LABEL_RESCUE_BEG;
6290 lend->rescued = LABEL_RESCUE_END;
6291 APPEND_LABEL(ret, lcur, lstart);
6292 ADD_LABEL(ret, lend);
6293 if (!ignore) {
6294 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6295 }
6296 }
6297}
6298
6299static int
6300compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
6301{
6302 const int line = nd_line(node);
6303 const NODE *line_node = node;
6304 if (!RNODE_DEFINED(node)->nd_head) {
6305 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6306 ADD_INSN1(ret, line_node, putobject, str);
6307 }
6308 else {
6309 LABEL *lfinish[3];
6310 LINK_ELEMENT *last = ret->last;
6311 lfinish[0] = NEW_LABEL(line);
6312 lfinish[1] = 0;
6313 lfinish[2] = 0;
6314 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6315 if (lfinish[1]) {
6316 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6317 ADD_INSN(ret, line_node, swap);
6318 if (lfinish[2]) {
6319 ADD_LABEL(ret, lfinish[2]);
6320 }
6321 ADD_INSN(ret, line_node, pop);
6322 ADD_LABEL(ret, lfinish[1]);
6323 }
6324 ADD_LABEL(ret, lfinish[0]);
6325 }
6326 return COMPILE_OK;
6327}
6328
6329static VALUE
6330make_name_for_block(const rb_iseq_t *orig_iseq)
6331{
6332 int level = 1;
6333 const rb_iseq_t *iseq = orig_iseq;
6334
6335 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6336 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6337 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
6338 level++;
6339 }
6340 iseq = ISEQ_BODY(iseq)->parent_iseq;
6341 }
6342 }
6343
6344 if (level == 1) {
6345 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6346 }
6347 else {
6348 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6349 }
6350}
6351
6352static void
6353push_ensure_entry(rb_iseq_t *iseq,
6355 struct ensure_range *er, const void *const node)
6356{
6357 enl->ensure_node = node;
6358 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
6359 enl->erange = er;
6360 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6361}
6362
6363static void
6364add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
6365 LABEL *lstart, LABEL *lend)
6366{
6367 struct ensure_range *ne =
6368 compile_data_alloc(iseq, sizeof(struct ensure_range));
6369
6370 while (erange->next != 0) {
6371 erange = erange->next;
6372 }
6373 ne->next = 0;
6374 ne->begin = lend;
6375 ne->end = erange->end;
6376 erange->end = lstart;
6377
6378 erange->next = ne;
6379}
6380
6381static bool
6382can_add_ensure_iseq(const rb_iseq_t *iseq)
6383{
6385 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6386 while (e) {
6387 if (e->ensure_node) return false;
6388 e = e->prev;
6389 }
6390 }
6391 return true;
6392}
6393
6394static void
6395add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
6396{
6397 RUBY_ASSERT(can_add_ensure_iseq(iseq));
6398
6400 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6401 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
6402 DECL_ANCHOR(ensure);
6403
6404 INIT_ANCHOR(ensure);
6405 while (enlp) {
6406 if (enlp->erange != NULL) {
6407 DECL_ANCHOR(ensure_part);
6408 LABEL *lstart = NEW_LABEL(0);
6409 LABEL *lend = NEW_LABEL(0);
6410 INIT_ANCHOR(ensure_part);
6411
6412 add_ensure_range(iseq, enlp->erange, lstart, lend);
6413
6414 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6415 ADD_LABEL(ensure_part, lstart);
6416 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
6417 ADD_LABEL(ensure_part, lend);
6418 ADD_SEQ(ensure, ensure_part);
6419 }
6420 else {
6421 if (!is_return) {
6422 break;
6423 }
6424 }
6425 enlp = enlp->prev;
6426 }
6427 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6428 ADD_SEQ(ret, ensure);
6429}
6430
6431#if RUBY_DEBUG
6432static int
6433check_keyword(const NODE *node)
6434{
6435 /* This check is essentially a code clone of compile_keyword_arg. */
6436
6437 if (nd_type_p(node, NODE_LIST)) {
6438 while (RNODE_LIST(node)->nd_next) {
6439 node = RNODE_LIST(node)->nd_next;
6440 }
6441 node = RNODE_LIST(node)->nd_head;
6442 }
6443
6444 return keyword_node_p(node);
6445}
6446#endif
6447
6448static bool
6449keyword_node_single_splat_p(NODE *kwnode)
6450{
6451 RUBY_ASSERT(keyword_node_p(kwnode));
6452
6453 NODE *node = RNODE_HASH(kwnode)->nd_head;
6454 return RNODE_LIST(node)->nd_head == NULL &&
6455 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6456}
6457
6458static void
6459compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6460 NODE *kwnode, unsigned int *flag_ptr)
6461{
6462 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6463 ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6464 ADD_INSN1(args, argn, newhash, INT2FIX(0));
6465 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6466 ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
6467}
6468
6469#define SPLATARRAY_FALSE 0
6470#define SPLATARRAY_TRUE 1
6471#define DUP_SINGLE_KW_SPLAT 2
6472
6473static int
6474setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6475 unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
6476{
6477 if (!argn) return 0;
6478
6479 NODE *kwnode = NULL;
6480
6481 switch (nd_type(argn)) {
6482 case NODE_LIST: {
6483 // f(x, y, z)
6484 int len = compile_args(iseq, args, argn, &kwnode);
6485 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6486
6487 if (kwnode) {
6488 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6489 len -= 1;
6490 }
6491 else {
6492 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6493 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6494 }
6495 else {
6496 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6497 }
6498 }
6499 }
6500
6501 return len;
6502 }
6503 case NODE_SPLAT: {
6504 // f(*a)
6505 NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
6506 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6507 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6508 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6509 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6510 return 1;
6511 }
6512 case NODE_ARGSCAT: {
6513 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6514 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6515 bool args_pushed = false;
6516
6517 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6518 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6519 if (kwnode) rest_len--;
6520 ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
6521 args_pushed = true;
6522 }
6523 else {
6524 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6525 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6526 }
6527
6528 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6529 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6530 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6531 argc += 1;
6532 }
6533 else if (!args_pushed) {
6534 ADD_INSN(args, argn, concattoarray);
6535 }
6536
6537 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6538 if (kwnode) {
6539 // kwsplat
6540 *flag_ptr |= VM_CALL_KW_SPLAT;
6541 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6542 argc += 1;
6543 }
6544
6545 return argc;
6546 }
6547 case NODE_ARGSPUSH: {
6548 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6549 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6550
6551 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6552 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6553 if (kwnode) rest_len--;
6554 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
6555 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6556 }
6557 else {
6558 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6559 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6560 }
6561 else {
6562 NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6563 ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
6564 }
6565 }
6566
6567 if (kwnode) {
6568 // f(*a, k:1)
6569 *flag_ptr |= VM_CALL_KW_SPLAT;
6570 if (!keyword_node_single_splat_p(kwnode)) {
6571 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6572 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6573 }
6574 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6575 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6576 }
6577 else {
6578 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6579 }
6580 argc += 1;
6581 }
6582
6583 return argc;
6584 }
6585 default: {
6586 UNKNOWN_NODE("setup_arg", argn, Qnil);
6587 }
6588 }
6589}
6590
6591static void
6592setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
6593{
6594 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6595 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6596 }
6597}
6598
6599static bool
6600setup_args_dup_rest_p(const NODE *argn)
6601{
6602 switch(nd_type(argn)) {
6603 case NODE_LVAR:
6604 case NODE_DVAR:
6605 case NODE_GVAR:
6606 case NODE_IVAR:
6607 case NODE_CVAR:
6608 case NODE_CONST:
6609 case NODE_COLON3:
6610 case NODE_INTEGER:
6611 case NODE_FLOAT:
6612 case NODE_RATIONAL:
6613 case NODE_IMAGINARY:
6614 case NODE_STR:
6615 case NODE_SYM:
6616 case NODE_REGX:
6617 case NODE_SELF:
6618 case NODE_NIL:
6619 case NODE_TRUE:
6620 case NODE_FALSE:
6621 case NODE_LAMBDA:
6622 case NODE_NTH_REF:
6623 case NODE_BACK_REF:
6624 return false;
6625 case NODE_COLON2:
6626 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6627 case NODE_LIST:
6628 while (argn) {
6629 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6630 return true;
6631 }
6632 argn = RNODE_LIST(argn)->nd_next;
6633 }
6634 return false;
6635 default:
6636 return true;
6637 }
6638}
6639
6640static VALUE
6641setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
6642 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
6643{
6644 VALUE ret;
6645 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6646
6647 if (argn) {
6648 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6649 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6650
6651 if (check_arg) {
6652 switch(nd_type(check_arg)) {
6653 case(NODE_SPLAT):
6654 // avoid caller side array allocation for f(*arg)
6655 dup_rest = SPLATARRAY_FALSE;
6656 break;
6657 case(NODE_ARGSCAT):
6658 // avoid caller side array allocation for f(1, *arg)
6659 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6660 break;
6661 case(NODE_ARGSPUSH):
6662 // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
6663 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6664 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6665 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6666 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6667 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6668
6669 if (dup_rest == SPLATARRAY_FALSE) {
6670 // require allocation for keyword key/value/splat that may modify splatted argument
6671 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6672 while (node) {
6673 NODE *key_node = RNODE_LIST(node)->nd_head;
6674 if (key_node && setup_args_dup_rest_p(key_node)) {
6675 dup_rest = SPLATARRAY_TRUE;
6676 break;
6677 }
6678
6679 node = RNODE_LIST(node)->nd_next;
6680 NODE *value_node = RNODE_LIST(node)->nd_head;
6681 if (setup_args_dup_rest_p(value_node)) {
6682 dup_rest = SPLATARRAY_TRUE;
6683 break;
6684 }
6685
6686 node = RNODE_LIST(node)->nd_next;
6687 }
6688 }
6689 break;
6690 default:
6691 break;
6692 }
6693 }
6694
6695 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6696 // for block pass that may modify splatted argument, dup rest and kwrest if given
6697 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6698 }
6699 }
6700 initial_dup_rest = dup_rest;
6701
6702 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6703 DECL_ANCHOR(arg_block);
6704 INIT_ANCHOR(arg_block);
6705
6706 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6707 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
6708
6709 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6710 const NODE * arg_node =
6711 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6712
6713 int argc = 0;
6714
6715 // Only compile leading args:
6716 // foo(x, y, ...)
6717 // ^^^^
6718 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6719 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6720 }
6721
6722 *flag |= VM_CALL_FORWARDING;
6723
6724 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6725 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6726 return INT2FIX(argc);
6727 }
6728 else {
6729 *flag |= VM_CALL_ARGS_BLOCKARG;
6730
6731 NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
6732 }
6733
6734 if (LIST_INSN_SIZE_ONE(arg_block)) {
6735 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6736 if (IS_INSN(elem)) {
6737 INSN *iobj = (INSN *)elem;
6738 if (iobj->insn_id == BIN(getblockparam)) {
6739 iobj->insn_id = BIN(getblockparamproxy);
6740 }
6741 }
6742 }
6743 ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6744 ADD_SEQ(args, arg_block);
6745 }
6746 else {
6747 ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6748 }
6749 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6750 return ret;
6751}
6752
6753static void
6754build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
6755{
6756 const NODE *body = ptr;
6757 int line = nd_line(body);
6758 VALUE argc = INT2FIX(0);
6759 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6760
6761 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6762 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6763 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
6764 iseq_set_local_table(iseq, 0, 0);
6765}
6766
6767static void
6768compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
6769{
6770 const NODE *vars;
6771 LINK_ELEMENT *last;
6772 int line = nd_line(node);
6773 const NODE *line_node = node;
6774 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6775
6776#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6777 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
6778#else
6779 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
6780#endif
6781 ADD_INSN(ret, line_node, dup);
6782 ADD_INSNL(ret, line_node, branchunless, fail_label);
6783
6784 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6785 INSN *cap;
6786 if (RNODE_BLOCK(vars)->nd_next) {
6787 ADD_INSN(ret, line_node, dup);
6788 }
6789 last = ret->last;
6790 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6791 last = last->next; /* putobject :var */
6792 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
6793 NULL, INT2FIX(0), NULL);
6794 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6795#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6796 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6797 /* only one name */
6798 DECL_ANCHOR(nom);
6799
6800 INIT_ANCHOR(nom);
6801 ADD_INSNL(nom, line_node, jump, end_label);
6802 ADD_LABEL(nom, fail_label);
6803# if 0 /* $~ must be MatchData or nil */
6804 ADD_INSN(nom, line_node, pop);
6805 ADD_INSN(nom, line_node, putnil);
6806# endif
6807 ADD_LABEL(nom, end_label);
6808 (nom->last->next = cap->link.next)->prev = nom->last;
6809 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6810 return;
6811 }
6812#endif
6813 }
6814 ADD_INSNL(ret, line_node, jump, end_label);
6815 ADD_LABEL(ret, fail_label);
6816 ADD_INSN(ret, line_node, pop);
6817 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6818 last = ret->last;
6819 NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
6820 last = last->next; /* putobject :var */
6821 ((INSN*)last)->insn_id = BIN(putnil);
6822 ((INSN*)last)->operand_size = 0;
6823 }
6824 ADD_LABEL(ret, end_label);
6825}
6826
6827static int
6828optimizable_range_item_p(const NODE *n)
6829{
6830 if (!n) return FALSE;
6831 switch (nd_type(n)) {
6832 case NODE_LINE:
6833 return TRUE;
6834 case NODE_INTEGER:
6835 return TRUE;
6836 case NODE_NIL:
6837 return TRUE;
6838 default:
6839 return FALSE;
6840 }
6841}
6842
6843static VALUE
6844optimized_range_item(const NODE *n)
6845{
6846 switch (nd_type(n)) {
6847 case NODE_LINE:
6848 return rb_node_line_lineno_val(n);
6849 case NODE_INTEGER:
6850 return rb_node_integer_literal_val(n);
6851 case NODE_FLOAT:
6852 return rb_node_float_literal_val(n);
6853 case NODE_RATIONAL:
6854 return rb_node_rational_literal_val(n);
6855 case NODE_IMAGINARY:
6856 return rb_node_imaginary_literal_val(n);
6857 case NODE_NIL:
6858 return Qnil;
6859 default:
6860 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
6861 }
6862}
6863
6864static int
6865compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6866{
6867 const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6868 const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6869
6870 const int line = nd_line(node);
6871 const NODE *line_node = node;
6872 DECL_ANCHOR(cond_seq);
6873 LABEL *then_label, *else_label, *end_label;
6874 VALUE branches = Qfalse;
6875
6876 INIT_ANCHOR(cond_seq);
6877 then_label = NEW_LABEL(line);
6878 else_label = NEW_LABEL(line);
6879 end_label = 0;
6880
6881 NODE *cond = RNODE_IF(node)->nd_cond;
6882 if (nd_type(cond) == NODE_BLOCK) {
6883 cond = RNODE_BLOCK(cond)->nd_head;
6884 }
6885
6886 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6887 ADD_SEQ(ret, cond_seq);
6888
6889 if (then_label->refcnt && else_label->refcnt) {
6890 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
6891 }
6892
6893 if (then_label->refcnt) {
6894 ADD_LABEL(ret, then_label);
6895
6896 DECL_ANCHOR(then_seq);
6897 INIT_ANCHOR(then_seq);
6898 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6899
6900 if (else_label->refcnt) {
6901 const NODE *const coverage_node = node_body ? node_body : node;
6902 add_trace_branch_coverage(
6903 iseq,
6904 ret,
6905 nd_code_loc(coverage_node),
6906 nd_node_id(coverage_node),
6907 0,
6908 type == NODE_IF ? "then" : "else",
6909 branches);
6910 end_label = NEW_LABEL(line);
6911 ADD_INSNL(then_seq, line_node, jump, end_label);
6912 if (!popped) {
6913 ADD_INSN(then_seq, line_node, pop);
6914 }
6915 }
6916 ADD_SEQ(ret, then_seq);
6917 }
6918
6919 if (else_label->refcnt) {
6920 ADD_LABEL(ret, else_label);
6921
6922 DECL_ANCHOR(else_seq);
6923 INIT_ANCHOR(else_seq);
6924 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6925
6926 if (then_label->refcnt) {
6927 const NODE *const coverage_node = node_else ? node_else : node;
6928 add_trace_branch_coverage(
6929 iseq,
6930 ret,
6931 nd_code_loc(coverage_node),
6932 nd_node_id(coverage_node),
6933 1,
6934 type == NODE_IF ? "else" : "then",
6935 branches);
6936 }
6937 ADD_SEQ(ret, else_seq);
6938 }
6939
6940 if (end_label) {
6941 ADD_LABEL(ret, end_label);
6942 }
6943
6944 return COMPILE_OK;
6945}
6946
6947static int
6948compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6949{
6950 const NODE *vals;
6951 const NODE *node = orig_node;
6952 LABEL *endlabel, *elselabel;
6953 DECL_ANCHOR(head);
6954 DECL_ANCHOR(body_seq);
6955 DECL_ANCHOR(cond_seq);
6956 int only_special_literals = 1;
6957 VALUE literals = rb_hash_new();
6958 int line;
6959 enum node_type type;
6960 const NODE *line_node;
6961 VALUE branches = Qfalse;
6962 int branch_id = 0;
6963
6964 INIT_ANCHOR(head);
6965 INIT_ANCHOR(body_seq);
6966 INIT_ANCHOR(cond_seq);
6967
6968 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6969
6970 CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
6971
6972 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
6973
6974 node = RNODE_CASE(node)->nd_body;
6975 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6976 type = nd_type(node);
6977 line = nd_line(node);
6978 line_node = node;
6979
6980 endlabel = NEW_LABEL(line);
6981 elselabel = NEW_LABEL(line);
6982
6983 ADD_SEQ(ret, head); /* case VAL */
6984
6985 while (type == NODE_WHEN) {
6986 LABEL *l1;
6987
6988 l1 = NEW_LABEL(line);
6989 ADD_LABEL(body_seq, l1);
6990 ADD_INSN(body_seq, line_node, pop);
6991
6992 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6993 add_trace_branch_coverage(
6994 iseq,
6995 body_seq,
6996 nd_code_loc(coverage_node),
6997 nd_node_id(coverage_node),
6998 branch_id++,
6999 "when",
7000 branches);
7001
7002 CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
7003 ADD_INSNL(body_seq, line_node, jump, endlabel);
7004
7005 vals = RNODE_WHEN(node)->nd_head;
7006 if (vals) {
7007 switch (nd_type(vals)) {
7008 case NODE_LIST:
7009 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7010 if (only_special_literals < 0) return COMPILE_NG;
7011 break;
7012 case NODE_SPLAT:
7013 case NODE_ARGSCAT:
7014 case NODE_ARGSPUSH:
7015 only_special_literals = 0;
7016 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7017 break;
7018 default:
7019 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
7020 }
7021 }
7022 else {
7023 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
7024 }
7025
7026 node = RNODE_WHEN(node)->nd_next;
7027 if (!node) {
7028 break;
7029 }
7030 type = nd_type(node);
7031 line = nd_line(node);
7032 line_node = node;
7033 }
7034 /* else */
7035 if (node) {
7036 ADD_LABEL(cond_seq, elselabel);
7037 ADD_INSN(cond_seq, line_node, pop);
7038 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
7039 CHECK(COMPILE_(cond_seq, "else", node, popped));
7040 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7041 }
7042 else {
7043 debugs("== else (implicit)\n");
7044 ADD_LABEL(cond_seq, elselabel);
7045 ADD_INSN(cond_seq, orig_node, pop);
7046 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
7047 if (!popped) {
7048 ADD_INSN(cond_seq, orig_node, putnil);
7049 }
7050 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7051 }
7052
7053 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7054 ADD_INSN(ret, orig_node, dup);
7055 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7056 RB_OBJ_WRITTEN(iseq, Qundef, literals);
7057 LABEL_REF(elselabel);
7058 }
7059
7060 ADD_SEQ(ret, cond_seq);
7061 ADD_SEQ(ret, body_seq);
7062 ADD_LABEL(ret, endlabel);
7063 return COMPILE_OK;
7064}
7065
7066static int
7067compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7068{
7069 const NODE *vals;
7070 const NODE *val;
7071 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7072 LABEL *endlabel;
7073 DECL_ANCHOR(body_seq);
7074 VALUE branches = Qfalse;
7075 int branch_id = 0;
7076
7077 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
7078
7079 INIT_ANCHOR(body_seq);
7080 endlabel = NEW_LABEL(nd_line(node));
7081
7082 while (node && nd_type_p(node, NODE_WHEN)) {
7083 const int line = nd_line(node);
7084 LABEL *l1 = NEW_LABEL(line);
7085 ADD_LABEL(body_seq, l1);
7086
7087 const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7088 add_trace_branch_coverage(
7089 iseq,
7090 body_seq,
7091 nd_code_loc(coverage_node),
7092 nd_node_id(coverage_node),
7093 branch_id++,
7094 "when",
7095 branches);
7096
7097 CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
7098 ADD_INSNL(body_seq, node, jump, endlabel);
7099
7100 vals = RNODE_WHEN(node)->nd_head;
7101 if (!vals) {
7102 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7103 }
7104 switch (nd_type(vals)) {
7105 case NODE_LIST:
7106 while (vals) {
7107 LABEL *lnext;
7108 val = RNODE_LIST(vals)->nd_head;
7109 lnext = NEW_LABEL(nd_line(val));
7110 debug_compile("== when2\n", (void)0);
7111 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7112 ADD_LABEL(ret, lnext);
7113 vals = RNODE_LIST(vals)->nd_next;
7114 }
7115 break;
7116 case NODE_SPLAT:
7117 case NODE_ARGSCAT:
7118 case NODE_ARGSPUSH:
7119 ADD_INSN(ret, vals, putnil);
7120 CHECK(COMPILE(ret, "when2/cond splat", vals));
7121 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7122 ADD_INSNL(ret, vals, branchif, l1);
7123 break;
7124 default:
7125 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
7126 }
7127 node = RNODE_WHEN(node)->nd_next;
7128 }
7129 /* else */
7130 const NODE *const coverage_node = node ? node : orig_node;
7131 add_trace_branch_coverage(
7132 iseq,
7133 ret,
7134 nd_code_loc(coverage_node),
7135 nd_node_id(coverage_node),
7136 branch_id,
7137 "else",
7138 branches);
7139 CHECK(COMPILE_(ret, "else", node, popped));
7140 ADD_INSNL(ret, orig_node, jump, endlabel);
7141
7142 ADD_SEQ(ret, body_seq);
7143 ADD_LABEL(ret, endlabel);
7144 return COMPILE_OK;
7145}
7146
7147static 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);
7148
7149static 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);
7150static 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);
7151static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
7152static 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);
7153static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
7154
7155#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7156#define CASE3_BI_OFFSET_ERROR_STRING 1
7157#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7158#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7159#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7160
7161static int
7162iseq_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)
7163{
7164 const int line = nd_line(node);
7165 const NODE *line_node = node;
7166
7167 switch (nd_type(node)) {
7168 case NODE_ARYPTN: {
7169 /*
7170 * if pattern.use_rest_num?
7171 * rest_num = 0
7172 * end
7173 * if pattern.has_constant_node?
7174 * unless pattern.constant === obj
7175 * goto match_failed
7176 * end
7177 * end
7178 * unless obj.respond_to?(:deconstruct)
7179 * goto match_failed
7180 * end
7181 * d = obj.deconstruct
7182 * unless Array === d
7183 * goto type_error
7184 * end
7185 * min_argc = pattern.pre_args_num + pattern.post_args_num
7186 * if pattern.has_rest_arg?
7187 * unless d.length >= min_argc
7188 * goto match_failed
7189 * end
7190 * else
7191 * unless d.length == min_argc
7192 * goto match_failed
7193 * end
7194 * end
7195 * pattern.pre_args_num.each do |i|
7196 * unless pattern.pre_args[i].match?(d[i])
7197 * goto match_failed
7198 * end
7199 * end
7200 * if pattern.use_rest_num?
7201 * rest_num = d.length - min_argc
7202 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
7203 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
7204 * goto match_failed
7205 * end
7206 * end
7207 * end
7208 * pattern.post_args_num.each do |i|
7209 * j = pattern.pre_args_num + i
7210 * j += rest_num
7211 * unless pattern.post_args[i].match?(d[j])
7212 * goto match_failed
7213 * end
7214 * end
7215 * goto matched
7216 * type_error:
7217 * FrozenCore.raise TypeError
7218 * match_failed:
7219 * goto unmatched
7220 */
7221 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7222 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7223 const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7224
7225 const int min_argc = pre_args_num + post_args_num;
7226 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7227 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7228
7229 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7230 int i;
7231 match_failed = NEW_LABEL(line);
7232 type_error = NEW_LABEL(line);
7233 deconstruct = NEW_LABEL(line);
7234 deconstructed = NEW_LABEL(line);
7235
7236 if (use_rest_num) {
7237 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
7238 ADD_INSN(ret, line_node, swap);
7239 if (base_index) {
7240 base_index++;
7241 }
7242 }
7243
7244 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7245
7246 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7247
7248 ADD_INSN(ret, line_node, dup);
7249 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7250 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7251 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
7252 if (in_single_pattern) {
7253 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7254 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
7255 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
7256 INT2FIX(min_argc), base_index + 1 /* (1) */));
7257 }
7258 ADD_INSNL(ret, line_node, branchunless, match_failed);
7259
7260 for (i = 0; i < pre_args_num; i++) {
7261 ADD_INSN(ret, line_node, dup);
7262 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
7263 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
7264 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));
7265 args = RNODE_LIST(args)->nd_next;
7266 }
7267
7268 if (RNODE_ARYPTN(node)->rest_arg) {
7269 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7270 ADD_INSN(ret, line_node, dup);
7271 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
7272 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7273 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7274 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7275 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7276 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
7277 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
7278
7279 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));
7280 }
7281 else {
7282 if (post_args_num > 0) {
7283 ADD_INSN(ret, line_node, dup);
7284 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7285 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
7286 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
7287 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7288 ADD_INSN(ret, line_node, pop);
7289 }
7290 }
7291 }
7292
7293 args = RNODE_ARYPTN(node)->post_args;
7294 for (i = 0; i < post_args_num; i++) {
7295 ADD_INSN(ret, line_node, dup);
7296
7297 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
7298 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7299 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7300
7301 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
7302 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));
7303 args = RNODE_LIST(args)->nd_next;
7304 }
7305
7306 ADD_INSN(ret, line_node, pop);
7307 if (use_rest_num) {
7308 ADD_INSN(ret, line_node, pop);
7309 }
7310 ADD_INSNL(ret, line_node, jump, matched);
7311 ADD_INSN(ret, line_node, putnil);
7312 if (use_rest_num) {
7313 ADD_INSN(ret, line_node, putnil);
7314 }
7315
7316 ADD_LABEL(ret, type_error);
7317 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7318 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7319 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7320 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7321 ADD_INSN(ret, line_node, pop);
7322
7323 ADD_LABEL(ret, match_failed);
7324 ADD_INSN(ret, line_node, pop);
7325 if (use_rest_num) {
7326 ADD_INSN(ret, line_node, pop);
7327 }
7328 ADD_INSNL(ret, line_node, jump, unmatched);
7329
7330 break;
7331 }
7332 case NODE_FNDPTN: {
7333 /*
7334 * if pattern.has_constant_node?
7335 * unless pattern.constant === obj
7336 * goto match_failed
7337 * end
7338 * end
7339 * unless obj.respond_to?(:deconstruct)
7340 * goto match_failed
7341 * end
7342 * d = obj.deconstruct
7343 * unless Array === d
7344 * goto type_error
7345 * end
7346 * unless d.length >= pattern.args_num
7347 * goto match_failed
7348 * end
7349 *
7350 * begin
7351 * len = d.length
7352 * limit = d.length - pattern.args_num
7353 * i = 0
7354 * while i <= limit
7355 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
7356 * if pattern.has_pre_rest_arg_id
7357 * unless pattern.pre_rest_arg.match?(d[0, i])
7358 * goto find_failed
7359 * end
7360 * end
7361 * if pattern.has_post_rest_arg_id
7362 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
7363 * goto find_failed
7364 * end
7365 * end
7366 * goto find_succeeded
7367 * end
7368 * i+=1
7369 * end
7370 * find_failed:
7371 * goto match_failed
7372 * find_succeeded:
7373 * end
7374 *
7375 * goto matched
7376 * type_error:
7377 * FrozenCore.raise TypeError
7378 * match_failed:
7379 * goto unmatched
7380 */
7381 const NODE *args = RNODE_FNDPTN(node)->args;
7382 const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7383
7384 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7385 match_failed = NEW_LABEL(line);
7386 type_error = NEW_LABEL(line);
7387 deconstruct = NEW_LABEL(line);
7388 deconstructed = NEW_LABEL(line);
7389
7390 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7391
7392 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7393
7394 ADD_INSN(ret, line_node, dup);
7395 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7396 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7397 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
7398 if (in_single_pattern) {
7399 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) */));
7400 }
7401 ADD_INSNL(ret, line_node, branchunless, match_failed);
7402
7403 {
7404 LABEL *while_begin = NEW_LABEL(nd_line(node));
7405 LABEL *next_loop = NEW_LABEL(nd_line(node));
7406 LABEL *find_succeeded = NEW_LABEL(line);
7407 LABEL *find_failed = NEW_LABEL(nd_line(node));
7408 int j;
7409
7410 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
7411 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
7412
7413 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
7414 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7415 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
7416
7417 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
7418
7419 ADD_LABEL(ret, while_begin);
7420
7421 ADD_INSN(ret, line_node, dup);
7422 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7423 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
7424 ADD_INSNL(ret, line_node, branchunless, find_failed);
7425
7426 for (j = 0; j < args_num; j++) {
7427 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7428 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7429 if (j != 0) {
7430 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
7431 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7432 }
7433 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
7434
7435 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));
7436 args = RNODE_LIST(args)->nd_next;
7437 }
7438
7439 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7440 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7441 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7442 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7443 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
7444 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));
7445 }
7446 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7447 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7448 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
7449 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
7450 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7451 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7452 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
7453 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));
7454 }
7455 ADD_INSNL(ret, line_node, jump, find_succeeded);
7456
7457 ADD_LABEL(ret, next_loop);
7458 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7459 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
7460 ADD_INSNL(ret, line_node, jump, while_begin);
7461
7462 ADD_LABEL(ret, find_failed);
7463 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7464 if (in_single_pattern) {
7465 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7466 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
7467 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
7468 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
7469 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
7470
7471 ADD_INSN1(ret, line_node, putobject, Qfalse);
7472 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
7473
7474 ADD_INSN(ret, line_node, pop);
7475 ADD_INSN(ret, line_node, pop);
7476 }
7477 ADD_INSNL(ret, line_node, jump, match_failed);
7478 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
7479
7480 ADD_LABEL(ret, find_succeeded);
7481 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
7482 }
7483
7484 ADD_INSN(ret, line_node, pop);
7485 ADD_INSNL(ret, line_node, jump, matched);
7486 ADD_INSN(ret, line_node, putnil);
7487
7488 ADD_LABEL(ret, type_error);
7489 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7490 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7491 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
7492 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7493 ADD_INSN(ret, line_node, pop);
7494
7495 ADD_LABEL(ret, match_failed);
7496 ADD_INSN(ret, line_node, pop);
7497 ADD_INSNL(ret, line_node, jump, unmatched);
7498
7499 break;
7500 }
7501 case NODE_HSHPTN: {
7502 /*
7503 * keys = nil
7504 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7505 * keys = pattern.kw_args_node.keys
7506 * end
7507 * if pattern.has_constant_node?
7508 * unless pattern.constant === obj
7509 * goto match_failed
7510 * end
7511 * end
7512 * unless obj.respond_to?(:deconstruct_keys)
7513 * goto match_failed
7514 * end
7515 * d = obj.deconstruct_keys(keys)
7516 * unless Hash === d
7517 * goto type_error
7518 * end
7519 * if pattern.has_kw_rest_arg_node?
7520 * d = d.dup
7521 * end
7522 * if pattern.has_kw_args_node?
7523 * pattern.kw_args_node.each |k,|
7524 * unless d.key?(k)
7525 * goto match_failed
7526 * end
7527 * end
7528 * pattern.kw_args_node.each |k, pat|
7529 * if pattern.has_kw_rest_arg_node?
7530 * unless pat.match?(d.delete(k))
7531 * goto match_failed
7532 * end
7533 * else
7534 * unless pat.match?(d[k])
7535 * goto match_failed
7536 * end
7537 * end
7538 * end
7539 * else
7540 * unless d.empty?
7541 * goto match_failed
7542 * end
7543 * end
7544 * if pattern.has_kw_rest_arg_node?
7545 * if pattern.no_rest_keyword?
7546 * unless d.empty?
7547 * goto match_failed
7548 * end
7549 * else
7550 * unless pattern.kw_rest_arg_node.match?(d)
7551 * goto match_failed
7552 * end
7553 * end
7554 * end
7555 * goto matched
7556 * type_error:
7557 * FrozenCore.raise TypeError
7558 * match_failed:
7559 * goto unmatched
7560 */
7561 LABEL *match_failed, *type_error;
7562 VALUE keys = Qnil;
7563
7564 match_failed = NEW_LABEL(line);
7565 type_error = NEW_LABEL(line);
7566
7567 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7568 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7569 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7570 while (kw_args) {
7571 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7572 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7573 }
7574 }
7575
7576 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7577
7578 ADD_INSN(ret, line_node, dup);
7579 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
7580 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
7581 if (in_single_pattern) {
7582 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
7583 }
7584 ADD_INSNL(ret, line_node, branchunless, match_failed);
7585
7586 if (NIL_P(keys)) {
7587 ADD_INSN(ret, line_node, putnil);
7588 }
7589 else {
7590 ADD_INSN1(ret, line_node, duparray, keys);
7591 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
7592 }
7593 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7594
7595 ADD_INSN(ret, line_node, dup);
7596 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
7597 ADD_INSNL(ret, line_node, branchunless, type_error);
7598
7599 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7600 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
7601 }
7602
7603 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7604 int i;
7605 int keys_num;
7606 const NODE *args;
7607 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7608 if (args) {
7609 DECL_ANCHOR(match_values);
7610 INIT_ANCHOR(match_values);
7611 keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7612 for (i = 0; i < keys_num; i++) {
7613 NODE *key_node = RNODE_LIST(args)->nd_head;
7614 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7615 VALUE key = get_symbol_value(iseq, key_node);
7616
7617 ADD_INSN(ret, line_node, dup);
7618 ADD_INSN1(ret, line_node, putobject, key);
7619 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
7620 if (in_single_pattern) {
7621 LABEL *match_succeeded;
7622 match_succeeded = NEW_LABEL(line);
7623
7624 ADD_INSN(ret, line_node, dup);
7625 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7626
7627 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
7628 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
7629 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
7630 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
7631 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
7632 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
7633 ADD_INSN1(ret, line_node, putobject, key); // (7)
7634 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
7635
7636 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
7637
7638 ADD_LABEL(ret, match_succeeded);
7639 }
7640 ADD_INSNL(ret, line_node, branchunless, match_failed);
7641
7642 ADD_INSN(match_values, line_node, dup);
7643 ADD_INSN1(match_values, line_node, putobject, key);
7644 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
7645 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
7646 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7647 }
7648 ADD_SEQ(ret, match_values);
7649 }
7650 }
7651 else {
7652 ADD_INSN(ret, line_node, dup);
7653 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
7654 if (in_single_pattern) {
7655 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
7656 }
7657 ADD_INSNL(ret, line_node, branchunless, match_failed);
7658 }
7659
7660 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7661 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7662 ADD_INSN(ret, line_node, dup);
7663 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
7664 if (in_single_pattern) {
7665 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
7666 }
7667 ADD_INSNL(ret, line_node, branchunless, match_failed);
7668 }
7669 else {
7670 ADD_INSN(ret, line_node, dup); // (11)
7671 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));
7672 }
7673 }
7674
7675 ADD_INSN(ret, line_node, pop);
7676 ADD_INSNL(ret, line_node, jump, matched);
7677 ADD_INSN(ret, line_node, putnil);
7678
7679 ADD_LABEL(ret, type_error);
7680 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7681 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
7682 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
7683 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
7684 ADD_INSN(ret, line_node, pop);
7685
7686 ADD_LABEL(ret, match_failed);
7687 ADD_INSN(ret, line_node, pop);
7688 ADD_INSNL(ret, line_node, jump, unmatched);
7689 break;
7690 }
7691 case NODE_SYM:
7692 case NODE_REGX:
7693 case NODE_LINE:
7694 case NODE_INTEGER:
7695 case NODE_FLOAT:
7696 case NODE_RATIONAL:
7697 case NODE_IMAGINARY:
7698 case NODE_FILE:
7699 case NODE_ENCODING:
7700 case NODE_STR:
7701 case NODE_XSTR:
7702 case NODE_DSTR:
7703 case NODE_DSYM:
7704 case NODE_DREGX:
7705 case NODE_LIST:
7706 case NODE_ZLIST:
7707 case NODE_LAMBDA:
7708 case NODE_DOT2:
7709 case NODE_DOT3:
7710 case NODE_CONST:
7711 case NODE_LVAR:
7712 case NODE_DVAR:
7713 case NODE_IVAR:
7714 case NODE_CVAR:
7715 case NODE_GVAR:
7716 case NODE_TRUE:
7717 case NODE_FALSE:
7718 case NODE_SELF:
7719 case NODE_NIL:
7720 case NODE_COLON2:
7721 case NODE_COLON3:
7722 case NODE_BEGIN:
7723 case NODE_BLOCK:
7724 case NODE_ONCE:
7725 CHECK(COMPILE(ret, "case in literal", node)); // (1)
7726 if (in_single_pattern) {
7727 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7728 }
7729 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
7730 if (in_single_pattern) {
7731 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
7732 }
7733 ADD_INSNL(ret, line_node, branchif, matched);
7734 ADD_INSNL(ret, line_node, jump, unmatched);
7735 break;
7736 case NODE_LASGN: {
7737 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
7738 ID id = RNODE_LASGN(node)->nd_vid;
7739 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7740
7741 if (in_alt_pattern) {
7742 const char *name = rb_id2name(id);
7743 if (name && strlen(name) > 0 && name[0] != '_') {
7744 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7745 rb_id2str(id));
7746 return COMPILE_NG;
7747 }
7748 }
7749
7750 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7751 ADD_INSNL(ret, line_node, jump, matched);
7752 break;
7753 }
7754 case NODE_DASGN: {
7755 int idx, lv, ls;
7756 ID id = RNODE_DASGN(node)->nd_vid;
7757
7758 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7759
7760 if (in_alt_pattern) {
7761 const char *name = rb_id2name(id);
7762 if (name && strlen(name) > 0 && name[0] != '_') {
7763 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
7764 rb_id2str(id));
7765 return COMPILE_NG;
7766 }
7767 }
7768
7769 if (idx < 0) {
7770 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
7771 rb_id2str(id));
7772 return COMPILE_NG;
7773 }
7774 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7775 ADD_INSNL(ret, line_node, jump, matched);
7776 break;
7777 }
7778 case NODE_IF:
7779 case NODE_UNLESS: {
7780 LABEL *match_failed;
7781 match_failed = unmatched;
7782 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7783 CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
7784 if (in_single_pattern) {
7785 LABEL *match_succeeded;
7786 match_succeeded = NEW_LABEL(line);
7787
7788 ADD_INSN(ret, line_node, dup);
7789 if (nd_type_p(node, NODE_IF)) {
7790 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7791 }
7792 else {
7793 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7794 }
7795
7796 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
7797 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7798 ADD_INSN1(ret, line_node, putobject, Qfalse);
7799 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7800
7801 ADD_INSN(ret, line_node, pop);
7802 ADD_INSN(ret, line_node, pop);
7803
7804 ADD_LABEL(ret, match_succeeded);
7805 }
7806 if (nd_type_p(node, NODE_IF)) {
7807 ADD_INSNL(ret, line_node, branchunless, match_failed);
7808 }
7809 else {
7810 ADD_INSNL(ret, line_node, branchif, match_failed);
7811 }
7812 ADD_INSNL(ret, line_node, jump, matched);
7813 break;
7814 }
7815 case NODE_HASH: {
7816 NODE *n;
7817 LABEL *match_failed;
7818 match_failed = NEW_LABEL(line);
7819
7820 n = RNODE_HASH(node)->nd_head;
7821 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7822 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7823 return COMPILE_NG;
7824 }
7825
7826 ADD_INSN(ret, line_node, dup); // (1)
7827 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));
7828 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));
7829 ADD_INSN(ret, line_node, putnil);
7830
7831 ADD_LABEL(ret, match_failed);
7832 ADD_INSN(ret, line_node, pop);
7833 ADD_INSNL(ret, line_node, jump, unmatched);
7834 break;
7835 }
7836 case NODE_OR: {
7837 LABEL *match_succeeded, *fin;
7838 match_succeeded = NEW_LABEL(line);
7839 fin = NEW_LABEL(line);
7840
7841 ADD_INSN(ret, line_node, dup); // (1)
7842 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));
7843 ADD_LABEL(ret, match_succeeded);
7844 ADD_INSN(ret, line_node, pop);
7845 ADD_INSNL(ret, line_node, jump, matched);
7846 ADD_INSN(ret, line_node, putnil);
7847 ADD_LABEL(ret, fin);
7848 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7849 break;
7850 }
7851 default:
7852 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7853 }
7854 return COMPILE_OK;
7855}
7856
7857static int
7858iseq_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)
7859{
7860 LABEL *fin = NEW_LABEL(nd_line(node));
7861 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7862 ADD_LABEL(ret, fin);
7863 return COMPILE_OK;
7864}
7865
7866static int
7867iseq_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)
7868{
7869 const NODE *line_node = node;
7870
7871 if (RNODE_ARYPTN(node)->nd_pconst) {
7872 ADD_INSN(ret, line_node, dup); // (1)
7873 CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
7874 if (in_single_pattern) {
7875 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7876 }
7877 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7878 if (in_single_pattern) {
7879 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7880 }
7881 ADD_INSNL(ret, line_node, branchunless, match_failed);
7882 }
7883 return COMPILE_OK;
7884}
7885
7886
7887static int
7888iseq_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)
7889{
7890 const NODE *line_node = node;
7891
7892 // NOTE: this optimization allows us to re-use the #deconstruct value
7893 // (or its absence).
7894 if (use_deconstructed_cache) {
7895 // If value is nil then we haven't tried to deconstruct
7896 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7897 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7898
7899 // If false then the value is not deconstructable
7900 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7901 ADD_INSNL(ret, line_node, branchunless, match_failed);
7902
7903 // Drop value, add deconstructed to the stack and jump
7904 ADD_INSN(ret, line_node, pop); // (1)
7905 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7906 ADD_INSNL(ret, line_node, jump, deconstructed);
7907 }
7908 else {
7909 ADD_INSNL(ret, line_node, jump, deconstruct);
7910 }
7911
7912 ADD_LABEL(ret, deconstruct);
7913 ADD_INSN(ret, line_node, dup);
7914 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7915 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7916
7917 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7918 if (use_deconstructed_cache) {
7919 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7920 }
7921
7922 if (in_single_pattern) {
7923 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7924 }
7925
7926 ADD_INSNL(ret, line_node, branchunless, match_failed);
7927
7928 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7929
7930 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7931 if (use_deconstructed_cache) {
7932 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7933 }
7934
7935 ADD_INSN(ret, line_node, dup);
7936 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7937 ADD_INSNL(ret, line_node, branchunless, type_error);
7938
7939 ADD_LABEL(ret, deconstructed);
7940
7941 return COMPILE_OK;
7942}
7943
7944static int
7945iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7946{
7947 /*
7948 * if match_succeeded?
7949 * goto match_succeeded
7950 * end
7951 * error_string = FrozenCore.sprintf(errmsg, matchee)
7952 * key_error_p = false
7953 * match_succeeded:
7954 */
7955 const int line = nd_line(node);
7956 const NODE *line_node = node;
7957 LABEL *match_succeeded = NEW_LABEL(line);
7958
7959 ADD_INSN(ret, line_node, dup);
7960 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7961
7962 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7963 ADD_INSN1(ret, line_node, putobject, errmsg);
7964 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7965 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7966 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7967
7968 ADD_INSN1(ret, line_node, putobject, Qfalse);
7969 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7970
7971 ADD_INSN(ret, line_node, pop);
7972 ADD_INSN(ret, line_node, pop);
7973 ADD_LABEL(ret, match_succeeded);
7974
7975 return COMPILE_OK;
7976}
7977
7978static int
7979iseq_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)
7980{
7981 /*
7982 * if match_succeeded?
7983 * goto match_succeeded
7984 * end
7985 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7986 * key_error_p = false
7987 * match_succeeded:
7988 */
7989 const int line = nd_line(node);
7990 const NODE *line_node = node;
7991 LABEL *match_succeeded = NEW_LABEL(line);
7992
7993 ADD_INSN(ret, line_node, dup);
7994 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7995
7996 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7997 ADD_INSN1(ret, line_node, putobject, errmsg);
7998 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7999 ADD_INSN(ret, line_node, dup);
8000 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
8001 ADD_INSN1(ret, line_node, putobject, pattern_length);
8002 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
8003 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8004
8005 ADD_INSN1(ret, line_node, putobject, Qfalse);
8006 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
8007
8008 ADD_INSN(ret, line_node, pop);
8009 ADD_INSN(ret, line_node, pop);
8010 ADD_LABEL(ret, match_succeeded);
8011
8012 return COMPILE_OK;
8013}
8014
8015static int
8016iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
8017{
8018 /*
8019 * if match_succeeded?
8020 * goto match_succeeded
8021 * end
8022 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
8023 * key_error_p = false
8024 * match_succeeded:
8025 */
8026 const int line = nd_line(node);
8027 const NODE *line_node = node;
8028 LABEL *match_succeeded = NEW_LABEL(line);
8029
8030 ADD_INSN(ret, line_node, dup);
8031 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8032
8033 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8034 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
8035 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
8036 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
8037 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
8038 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
8039
8040 ADD_INSN1(ret, line_node, putobject, Qfalse);
8041 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
8042
8043 ADD_INSN(ret, line_node, pop);
8044 ADD_INSN(ret, line_node, pop);
8045
8046 ADD_LABEL(ret, match_succeeded);
8047 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
8048 ADD_INSN(ret, line_node, pop);
8049 ADD_INSN(ret, line_node, pop);
8050
8051 return COMPILE_OK;
8052}
8053
8054static int
8055compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
8056{
8057 const NODE *pattern;
8058 const NODE *node = orig_node;
8059 LABEL *endlabel, *elselabel;
8060 DECL_ANCHOR(head);
8061 DECL_ANCHOR(body_seq);
8062 DECL_ANCHOR(cond_seq);
8063 int line;
8064 enum node_type type;
8065 const NODE *line_node;
8066 VALUE branches = 0;
8067 int branch_id = 0;
8068 bool single_pattern;
8069
8070 INIT_ANCHOR(head);
8071 INIT_ANCHOR(body_seq);
8072 INIT_ANCHOR(cond_seq);
8073
8074 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
8075
8076 node = RNODE_CASE3(node)->nd_body;
8077 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
8078 type = nd_type(node);
8079 line = nd_line(node);
8080 line_node = node;
8081 single_pattern = !RNODE_IN(node)->nd_next;
8082
8083 endlabel = NEW_LABEL(line);
8084 elselabel = NEW_LABEL(line);
8085
8086 if (single_pattern) {
8087 /* allocate stack for ... */
8088 ADD_INSN(head, line_node, putnil); /* key_error_key */
8089 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
8090 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
8091 ADD_INSN(head, line_node, putnil); /* error_string */
8092 }
8093 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
8094
8095 CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
8096
8097 ADD_SEQ(ret, head); /* case VAL */
8098
8099 while (type == NODE_IN) {
8100 LABEL *l1;
8101
8102 if (branch_id) {
8103 ADD_INSN(body_seq, line_node, putnil);
8104 }
8105 l1 = NEW_LABEL(line);
8106 ADD_LABEL(body_seq, l1);
8107 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
8108
8109 const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8110 add_trace_branch_coverage(
8111 iseq,
8112 body_seq,
8113 nd_code_loc(coverage_node),
8114 nd_node_id(coverage_node),
8115 branch_id++,
8116 "in",
8117 branches);
8118
8119 CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
8120 ADD_INSNL(body_seq, line_node, jump, endlabel);
8121
8122 pattern = RNODE_IN(node)->nd_head;
8123 if (pattern) {
8124 int pat_line = nd_line(pattern);
8125 LABEL *next_pat = NEW_LABEL(pat_line);
8126 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
8127 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
8128 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
8129 ADD_LABEL(cond_seq, next_pat);
8130 LABEL_UNREMOVABLE(next_pat);
8131 }
8132 else {
8133 COMPILE_ERROR(ERROR_ARGS "unexpected node");
8134 return COMPILE_NG;
8135 }
8136
8137 node = RNODE_IN(node)->nd_next;
8138 if (!node) {
8139 break;
8140 }
8141 type = nd_type(node);
8142 line = nd_line(node);
8143 line_node = node;
8144 }
8145 /* else */
8146 if (node) {
8147 ADD_LABEL(cond_seq, elselabel);
8148 ADD_INSN(cond_seq, line_node, pop);
8149 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
8150 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
8151 CHECK(COMPILE_(cond_seq, "else", node, popped));
8152 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8153 ADD_INSN(cond_seq, line_node, putnil);
8154 if (popped) {
8155 ADD_INSN(cond_seq, line_node, putnil);
8156 }
8157 }
8158 else {
8159 debugs("== else (implicit)\n");
8160 ADD_LABEL(cond_seq, elselabel);
8161 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
8162 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8163
8164 if (single_pattern) {
8165 /*
8166 * if key_error_p
8167 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
8168 * else
8169 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
8170 * end
8171 */
8172 LABEL *key_error, *fin;
8173 struct rb_callinfo_kwarg *kw_arg;
8174
8175 key_error = NEW_LABEL(line);
8176 fin = NEW_LABEL(line);
8177
8178 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
8179 kw_arg->references = 0;
8180 kw_arg->keyword_len = 2;
8181 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
8182 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
8183
8184 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8185 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8186 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8187 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8188 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8189 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8190 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8191 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8192 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8193 ADD_INSNL(cond_seq, orig_node, jump, fin);
8194
8195 ADD_LABEL(cond_seq, key_error);
8196 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
8197 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8198 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
8199 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
8200 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8201 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
8202 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8203 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8204 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
8205 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
8206
8207 ADD_LABEL(cond_seq, fin);
8208 }
8209 else {
8210 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
8211 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
8212 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
8213 }
8214 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
8215 if (!popped) {
8216 ADD_INSN(cond_seq, orig_node, putnil);
8217 }
8218 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8219 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
8220 if (popped) {
8221 ADD_INSN(cond_seq, line_node, putnil);
8222 }
8223 }
8224
8225 ADD_SEQ(ret, cond_seq);
8226 ADD_SEQ(ret, body_seq);
8227 ADD_LABEL(ret, endlabel);
8228 return COMPILE_OK;
8229}
8230
8231#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8232#undef CASE3_BI_OFFSET_ERROR_STRING
8233#undef CASE3_BI_OFFSET_KEY_ERROR_P
8234#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8235#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8236
8237static int
8238compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8239{
8240 const int line = (int)nd_line(node);
8241 const NODE *line_node = node;
8242
8243 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8244 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8245 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8246 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8247 VALUE branches = Qfalse;
8248
8250
8251 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
8252 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
8253 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
8254 LABEL *end_label = NEW_LABEL(line);
8255 LABEL *adjust_label = NEW_LABEL(line);
8256
8257 LABEL *next_catch_label = NEW_LABEL(line);
8258 LABEL *tmp_label = NULL;
8259
8260 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8261 push_ensure_entry(iseq, &enl, NULL, NULL);
8262
8263 if (RNODE_WHILE(node)->nd_state == 1) {
8264 ADD_INSNL(ret, line_node, jump, next_label);
8265 }
8266 else {
8267 tmp_label = NEW_LABEL(line);
8268 ADD_INSNL(ret, line_node, jump, tmp_label);
8269 }
8270 ADD_LABEL(ret, adjust_label);
8271 ADD_INSN(ret, line_node, putnil);
8272 ADD_LABEL(ret, next_catch_label);
8273 ADD_INSN(ret, line_node, pop);
8274 ADD_INSNL(ret, line_node, jump, next_label);
8275 if (tmp_label) ADD_LABEL(ret, tmp_label);
8276
8277 ADD_LABEL(ret, redo_label);
8278 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
8279
8280 const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8281 add_trace_branch_coverage(
8282 iseq,
8283 ret,
8284 nd_code_loc(coverage_node),
8285 nd_node_id(coverage_node),
8286 0,
8287 "body",
8288 branches);
8289
8290 CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
8291 ADD_LABEL(ret, next_label); /* next */
8292
8293 if (type == NODE_WHILE) {
8294 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8295 redo_label, end_label));
8296 }
8297 else {
8298 /* until */
8299 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8300 end_label, redo_label));
8301 }
8302
8303 ADD_LABEL(ret, end_label);
8304 ADD_ADJUST_RESTORE(ret, adjust_label);
8305
8306 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8307 /* ADD_INSN(ret, line_node, putundef); */
8308 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
8309 return COMPILE_NG;
8310 }
8311 else {
8312 ADD_INSN(ret, line_node, putnil);
8313 }
8314
8315 ADD_LABEL(ret, break_label); /* break */
8316
8317 if (popped) {
8318 ADD_INSN(ret, line_node, pop);
8319 }
8320
8321 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8322 break_label);
8323 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8324 next_catch_label);
8325 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8326 ISEQ_COMPILE_DATA(iseq)->redo_label);
8327
8328 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8329 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8330 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8331 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8332 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8333 return COMPILE_OK;
8334}
8335
8336static int
8337compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8338{
8339 const int line = nd_line(node);
8340 const NODE *line_node = node;
8341 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8342 LABEL *retry_label = NEW_LABEL(line);
8343 LABEL *retry_end_l = NEW_LABEL(line);
8344 const rb_iseq_t *child_iseq;
8345
8346 ADD_LABEL(ret, retry_label);
8347 if (nd_type_p(node, NODE_FOR)) {
8348 CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
8349
8350 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8351 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8352 ISEQ_TYPE_BLOCK, line);
8353 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
8354 }
8355 else {
8356 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8357 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8358 ISEQ_TYPE_BLOCK, line);
8359 CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
8360 }
8361
8362 {
8363 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
8364 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
8365 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
8366 //
8367 // Normally, "send" instruction is at the last.
8368 // However, qcall under branch coverage measurement adds some instructions after the "send".
8369 //
8370 // Note that "invokesuper", "invokesuperforward" appears instead of "send".
8371 INSN *iobj;
8372 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8373 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8374 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8375 iobj = (INSN*) get_prev_insn(iobj);
8376 }
8377 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8378
8379 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
8380 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
8381 if (&iobj->link == LAST_ELEMENT(ret)) {
8382 ret->last = (LINK_ELEMENT*) retry_end_l;
8383 }
8384 }
8385
8386 if (popped) {
8387 ADD_INSN(ret, line_node, pop);
8388 }
8389
8390 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8391
8392 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8393 return COMPILE_OK;
8394}
8395
8396static int
8397compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8398{
8399 /* massign to var in "for"
8400 * (args.length == 1 && Array.try_convert(args[0])) || args
8401 */
8402 const NODE *line_node = node;
8403 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8404 LABEL *not_single = NEW_LABEL(nd_line(var));
8405 LABEL *not_ary = NEW_LABEL(nd_line(var));
8406 CHECK(COMPILE(ret, "for var", var));
8407 ADD_INSN(ret, line_node, dup);
8408 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
8409 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
8410 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
8411 ADD_INSNL(ret, line_node, branchunless, not_single);
8412 ADD_INSN(ret, line_node, dup);
8413 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
8414 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
8415 ADD_INSN1(ret, line_node, putobject, rb_cArray);
8416 ADD_INSN(ret, line_node, swap);
8417 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
8418 ADD_INSN(ret, line_node, dup);
8419 ADD_INSNL(ret, line_node, branchunless, not_ary);
8420 ADD_INSN(ret, line_node, swap);
8421 ADD_LABEL(ret, not_ary);
8422 ADD_INSN(ret, line_node, pop);
8423 ADD_LABEL(ret, not_single);
8424 return COMPILE_OK;
8425}
8426
8427static int
8428compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8429{
8430 const NODE *line_node = node;
8431 unsigned long throw_flag = 0;
8432
8433 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8434 /* while/until */
8435 LABEL *splabel = NEW_LABEL(0);
8436 ADD_LABEL(ret, splabel);
8437 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8438 CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
8439 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8440 add_ensure_iseq(ret, iseq, 0);
8441 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8442 ADD_ADJUST_RESTORE(ret, splabel);
8443
8444 if (!popped) {
8445 ADD_INSN(ret, line_node, putnil);
8446 }
8447 }
8448 else {
8449 const rb_iseq_t *ip = iseq;
8450
8451 while (ip) {
8452 if (!ISEQ_COMPILE_DATA(ip)) {
8453 ip = 0;
8454 break;
8455 }
8456
8457 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8458 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8459 }
8460 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8461 throw_flag = 0;
8462 }
8463 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8464 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
8465 return COMPILE_NG;
8466 }
8467 else {
8468 ip = ISEQ_BODY(ip)->parent_iseq;
8469 continue;
8470 }
8471
8472 /* escape from block */
8473 CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
8474 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
8475 if (popped) {
8476 ADD_INSN(ret, line_node, pop);
8477 }
8478 return COMPILE_OK;
8479 }
8480 COMPILE_ERROR(ERROR_ARGS "Invalid break");
8481 return COMPILE_NG;
8482 }
8483 return COMPILE_OK;
8484}
8485
8486static int
8487compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8488{
8489 const NODE *line_node = node;
8490 unsigned long throw_flag = 0;
8491
8492 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8493 LABEL *splabel = NEW_LABEL(0);
8494 debugs("next in while loop\n");
8495 ADD_LABEL(ret, splabel);
8496 CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8497 add_ensure_iseq(ret, iseq, 0);
8498 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8499 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8500 ADD_ADJUST_RESTORE(ret, splabel);
8501 if (!popped) {
8502 ADD_INSN(ret, line_node, putnil);
8503 }
8504 }
8505 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8506 LABEL *splabel = NEW_LABEL(0);
8507 debugs("next in block\n");
8508 ADD_LABEL(ret, splabel);
8509 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8510 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8511 add_ensure_iseq(ret, iseq, 0);
8512 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8513 ADD_ADJUST_RESTORE(ret, splabel);
8514
8515 if (!popped) {
8516 ADD_INSN(ret, line_node, putnil);
8517 }
8518 }
8519 else {
8520 const rb_iseq_t *ip = iseq;
8521
8522 while (ip) {
8523 if (!ISEQ_COMPILE_DATA(ip)) {
8524 ip = 0;
8525 break;
8526 }
8527
8528 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8529 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8530 /* while loop */
8531 break;
8532 }
8533 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8534 break;
8535 }
8536 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8537 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
8538 return COMPILE_NG;
8539 }
8540
8541 ip = ISEQ_BODY(ip)->parent_iseq;
8542 }
8543 if (ip != 0) {
8544 CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
8545 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
8546
8547 if (popped) {
8548 ADD_INSN(ret, line_node, pop);
8549 }
8550 }
8551 else {
8552 COMPILE_ERROR(ERROR_ARGS "Invalid next");
8553 return COMPILE_NG;
8554 }
8555 }
8556 return COMPILE_OK;
8557}
8558
8559static int
8560compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8561{
8562 const NODE *line_node = node;
8563
8564 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8565 LABEL *splabel = NEW_LABEL(0);
8566 debugs("redo in while");
8567 ADD_LABEL(ret, splabel);
8568 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8569 add_ensure_iseq(ret, iseq, 0);
8570 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8571 ADD_ADJUST_RESTORE(ret, splabel);
8572 if (!popped) {
8573 ADD_INSN(ret, line_node, putnil);
8574 }
8575 }
8576 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8577 LABEL *splabel = NEW_LABEL(0);
8578
8579 debugs("redo in block");
8580 ADD_LABEL(ret, splabel);
8581 add_ensure_iseq(ret, iseq, 0);
8582 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8583 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8584 ADD_ADJUST_RESTORE(ret, splabel);
8585
8586 if (!popped) {
8587 ADD_INSN(ret, line_node, putnil);
8588 }
8589 }
8590 else {
8591 const rb_iseq_t *ip = iseq;
8592
8593 while (ip) {
8594 if (!ISEQ_COMPILE_DATA(ip)) {
8595 ip = 0;
8596 break;
8597 }
8598
8599 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8600 break;
8601 }
8602 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
8603 break;
8604 }
8605 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
8606 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
8607 return COMPILE_NG;
8608 }
8609
8610 ip = ISEQ_BODY(ip)->parent_iseq;
8611 }
8612 if (ip != 0) {
8613 ADD_INSN(ret, line_node, putnil);
8614 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8615
8616 if (popped) {
8617 ADD_INSN(ret, line_node, pop);
8618 }
8619 }
8620 else {
8621 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
8622 return COMPILE_NG;
8623 }
8624 }
8625 return COMPILE_OK;
8626}
8627
8628static int
8629compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8630{
8631 const NODE *line_node = node;
8632
8633 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
8634 ADD_INSN(ret, line_node, putnil);
8635 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
8636
8637 if (popped) {
8638 ADD_INSN(ret, line_node, pop);
8639 }
8640 }
8641 else {
8642 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
8643 return COMPILE_NG;
8644 }
8645 return COMPILE_OK;
8646}
8647
8648static int
8649compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8650{
8651 const int line = nd_line(node);
8652 const NODE *line_node = node;
8653 LABEL *lstart = NEW_LABEL(line);
8654 LABEL *lend = NEW_LABEL(line);
8655 LABEL *lcont = NEW_LABEL(line);
8656 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8657 rb_str_concat(rb_str_new2("rescue in "),
8658 ISEQ_BODY(iseq)->location.label),
8659 ISEQ_TYPE_RESCUE, line);
8660
8661 lstart->rescued = LABEL_RESCUE_BEG;
8662 lend->rescued = LABEL_RESCUE_END;
8663 ADD_LABEL(ret, lstart);
8664
8665 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8666 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
8667 {
8668 CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
8669 }
8670 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8671
8672 ADD_LABEL(ret, lend);
8673 if (RNODE_RESCUE(node)->nd_else) {
8674 ADD_INSN(ret, line_node, pop);
8675 CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
8676 }
8677 ADD_INSN(ret, line_node, nop);
8678 ADD_LABEL(ret, lcont);
8679
8680 if (popped) {
8681 ADD_INSN(ret, line_node, pop);
8682 }
8683
8684 /* register catch entry */
8685 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8686 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8687 return COMPILE_OK;
8688}
8689
8690static int
8691compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8692{
8693 const int line = nd_line(node);
8694 const NODE *line_node = node;
8695 const NODE *resq = node;
8696 const NODE *narg;
8697 LABEL *label_miss, *label_hit;
8698
8699 while (resq) {
8700 label_miss = NEW_LABEL(line);
8701 label_hit = NEW_LABEL(line);
8702
8703 narg = RNODE_RESBODY(resq)->nd_args;
8704 if (narg) {
8705 switch (nd_type(narg)) {
8706 case NODE_LIST:
8707 while (narg) {
8708 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8709 CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
8710 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8711 ADD_INSNL(ret, line_node, branchif, label_hit);
8712 narg = RNODE_LIST(narg)->nd_next;
8713 }
8714 break;
8715 case NODE_SPLAT:
8716 case NODE_ARGSCAT:
8717 case NODE_ARGSPUSH:
8718 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8719 CHECK(COMPILE(ret, "rescue/cond splat", narg));
8720 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8721 ADD_INSNL(ret, line_node, branchif, label_hit);
8722 break;
8723 default:
8724 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
8725 }
8726 }
8727 else {
8728 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8729 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
8730 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8731 ADD_INSNL(ret, line_node, branchif, label_hit);
8732 }
8733 ADD_INSNL(ret, line_node, jump, label_miss);
8734 ADD_LABEL(ret, label_hit);
8735 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
8736
8737 if (RNODE_RESBODY(resq)->nd_exc_var) {
8738 CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8739 }
8740
8741 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) {
8742 // empty body
8743 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8744 }
8745 else {
8746 CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
8747 }
8748
8749 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8750 ADD_INSN(ret, line_node, nop);
8751 }
8752 ADD_INSN(ret, line_node, leave);
8753 ADD_LABEL(ret, label_miss);
8754 resq = RNODE_RESBODY(resq)->nd_next;
8755 }
8756 return COMPILE_OK;
8757}
8758
8759static int
8760compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8761{
8762 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8763 const NODE *line_node = node;
8764 DECL_ANCHOR(ensr);
8765 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8766 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
8767 ISEQ_TYPE_ENSURE, line);
8768 LABEL *lstart = NEW_LABEL(line);
8769 LABEL *lend = NEW_LABEL(line);
8770 LABEL *lcont = NEW_LABEL(line);
8771 LINK_ELEMENT *last;
8772 int last_leave = 0;
8773 struct ensure_range er;
8775 struct ensure_range *erange;
8776
8777 INIT_ANCHOR(ensr);
8778 CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8779 last = ensr->last;
8780 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8781
8782 er.begin = lstart;
8783 er.end = lend;
8784 er.next = 0;
8785 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8786
8787 ADD_LABEL(ret, lstart);
8788 CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8789 ADD_LABEL(ret, lend);
8790 ADD_SEQ(ret, ensr);
8791 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8792 ADD_LABEL(ret, lcont);
8793 if (last_leave) ADD_INSN(ret, line_node, pop);
8794
8795 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8796 if (lstart->link.next != &lend->link) {
8797 while (erange) {
8798 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8799 ensure, lcont);
8800 erange = erange->next;
8801 }
8802 }
8803
8804 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8805 return COMPILE_OK;
8806}
8807
8808static int
8809compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8810{
8811 const NODE *line_node = node;
8812
8813 if (iseq) {
8814 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
8815 const rb_iseq_t *is = iseq;
8816 enum rb_iseq_type t = type;
8817 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8818 LABEL *splabel = 0;
8819
8820 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8821 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
8822 t = ISEQ_BODY(is)->type;
8823 }
8824 switch (t) {
8825 case ISEQ_TYPE_TOP:
8826 case ISEQ_TYPE_MAIN:
8827 if (retval) {
8828 rb_warn("argument of top-level return is ignored");
8829 }
8830 if (is == iseq) {
8831 /* plain top-level, leave directly */
8832 type = ISEQ_TYPE_METHOD;
8833 }
8834 break;
8835 default:
8836 break;
8837 }
8838
8839 if (type == ISEQ_TYPE_METHOD) {
8840 splabel = NEW_LABEL(0);
8841 ADD_LABEL(ret, splabel);
8842 ADD_ADJUST(ret, line_node, 0);
8843 }
8844
8845 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
8846
8847 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8848 add_ensure_iseq(ret, iseq, 1);
8849 ADD_TRACE(ret, RUBY_EVENT_RETURN);
8850 ADD_INSN(ret, line_node, leave);
8851 ADD_ADJUST_RESTORE(ret, splabel);
8852
8853 if (!popped) {
8854 ADD_INSN(ret, line_node, putnil);
8855 }
8856 }
8857 else {
8858 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
8859 if (popped) {
8860 ADD_INSN(ret, line_node, pop);
8861 }
8862 }
8863 }
8864 return COMPILE_OK;
8865}
8866
8867static bool
8868drop_unreachable_return(LINK_ANCHOR *ret)
8869{
8870 LINK_ELEMENT *i = ret->last, *last;
8871 if (!i) return false;
8872 if (IS_TRACE(i)) i = i->prev;
8873 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
8874 last = i = i->prev;
8875 if (IS_ADJUST(i)) i = i->prev;
8876 if (!IS_INSN(i)) return false;
8877 switch (INSN_OF(i)) {
8878 case BIN(leave):
8879 case BIN(jump):
8880 break;
8881 default:
8882 return false;
8883 }
8884 (ret->last = last->prev)->next = NULL;
8885 return true;
8886}
8887
8888static int
8889compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8890{
8891 CHECK(COMPILE_(ret, "nd_body", node, popped));
8892
8893 if (!popped && !all_string_result_p(node)) {
8894 const NODE *line_node = node;
8895 const unsigned int flag = VM_CALL_FCALL;
8896
8897 // Note, this dup could be removed if we are willing to change anytostring. It pops
8898 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8899 ADD_INSN(ret, line_node, dup);
8900 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8901 ADD_INSN(ret, line_node, anytostring);
8902 }
8903 return COMPILE_OK;
8904}
8905
8906static void
8907compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8908{
8909 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8910
8911 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8912 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8913}
8914
8915static LABEL *
8916qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8917{
8918 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8919 VALUE br = 0;
8920
8921 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
8922 *branches = br;
8923 ADD_INSN(recv, line_node, dup);
8924 ADD_INSNL(recv, line_node, branchnil, else_label);
8925 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
8926 return else_label;
8927}
8928
8929static void
8930qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8931{
8932 LABEL *end_label;
8933 if (!else_label) return;
8934 end_label = NEW_LABEL(nd_line(line_node));
8935 ADD_INSNL(ret, line_node, jump, end_label);
8936 ADD_LABEL(ret, else_label);
8937 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
8938 ADD_LABEL(ret, end_label);
8939}
8940
8941static int
8942compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8943{
8944 /* optimization shortcut
8945 * "literal".freeze -> opt_str_freeze("literal")
8946 */
8947 if (get_nd_recv(node) &&
8948 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8949 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8950 get_nd_args(node) == NULL &&
8951 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8952 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8953 VALUE str = get_string_value(get_nd_recv(node));
8954 if (get_node_call_nd_mid(node) == idUMinus) {
8955 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8956 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8957 }
8958 else {
8959 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8960 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8961 }
8962 RB_OBJ_WRITTEN(iseq, Qundef, str);
8963 if (popped) {
8964 ADD_INSN(ret, line_node, pop);
8965 }
8966 return TRUE;
8967 }
8968 /* optimization shortcut
8969 * obj["literal"] -> opt_aref_with(obj, "literal")
8970 */
8971 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8972 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8973 (nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
8974 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8975 !frozen_string_literal_p(iseq) &&
8976 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8977 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8978 CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
8979 ADD_INSN2(ret, line_node, opt_aref_with, str,
8980 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8981 RB_OBJ_WRITTEN(iseq, Qundef, str);
8982 if (popped) {
8983 ADD_INSN(ret, line_node, pop);
8984 }
8985 return TRUE;
8986 }
8987 return FALSE;
8988}
8989
8990static int
8991iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8992{
8993 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8994}
8995
8996static const struct rb_builtin_function *
8997iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8998{
8999 int i;
9000 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9001 for (i=0; table[i].index != -1; i++) {
9002 if (strcmp(table[i].name, name) == 0) {
9003 return &table[i];
9004 }
9005 }
9006 return NULL;
9007}
9008
9009static const char *
9010iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
9011{
9012 const char *name = rb_id2name(mid);
9013 static const char prefix[] = "__builtin_";
9014 const size_t prefix_len = sizeof(prefix) - 1;
9015
9016 switch (type) {
9017 case NODE_CALL:
9018 if (recv) {
9019 switch (nd_type(recv)) {
9020 case NODE_VCALL:
9021 if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
9022 return name;
9023 }
9024 break;
9025 case NODE_CONST:
9026 if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
9027 return name;
9028 }
9029 break;
9030 default: break;
9031 }
9032 }
9033 break;
9034 case NODE_VCALL:
9035 case NODE_FCALL:
9036 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9037 return &name[prefix_len];
9038 }
9039 break;
9040 default: break;
9041 }
9042 return NULL;
9043}
9044
9045static int
9046delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
9047{
9048
9049 if (argc == 0) {
9050 *pstart_index = 0;
9051 return TRUE;
9052 }
9053 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9054 unsigned int start=0;
9055
9056 // local_table: [p1, p2, p3, l1, l2, l3]
9057 // arguments: [p3, l1, l2] -> 2
9058 for (start = 0;
9059 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9060 start++) {
9061 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9062
9063 for (unsigned int i=start; i-start<argc; i++) {
9064 if (IS_INSN(elem) &&
9065 INSN_OF(elem) == BIN(getlocal)) {
9066 int local_index = FIX2INT(OPERAND_AT(elem, 0));
9067 int local_level = FIX2INT(OPERAND_AT(elem, 1));
9068
9069 if (local_level == 0) {
9070 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9071 if (0) { // for debug
9072 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9073 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9074 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9075 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
9076 }
9077 if (i == index) {
9078 elem = elem->next;
9079 continue; /* for */
9080 }
9081 else {
9082 goto next;
9083 }
9084 }
9085 else {
9086 goto fail; // level != 0 is unsupported
9087 }
9088 }
9089 else {
9090 goto fail; // insn is not a getlocal
9091 }
9092 }
9093 goto success;
9094 next:;
9095 }
9096 fail:
9097 return FALSE;
9098 success:
9099 *pstart_index = start;
9100 return TRUE;
9101 }
9102 else {
9103 return FALSE;
9104 }
9105}
9106
9107// Compile Primitive.attr! :leaf, ...
9108static int
9109compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
9110{
9111 VALUE symbol;
9112 VALUE string;
9113 if (!node) goto no_arg;
9114 while (node) {
9115 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9116 const NODE *next = RNODE_LIST(node)->nd_next;
9117
9118 node = RNODE_LIST(node)->nd_head;
9119 if (!node) goto no_arg;
9120 switch (nd_type(node)) {
9121 case NODE_SYM:
9122 symbol = rb_node_sym_string_val(node);
9123 break;
9124 default:
9125 goto bad_arg;
9126 }
9127
9128 if (!SYMBOL_P(symbol)) goto non_symbol_arg;
9129
9130 string = rb_sym2str(symbol);
9131 if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
9132 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9133 }
9134 else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
9135 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9136 }
9137 else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
9138 iseq_set_use_block(iseq);
9139 }
9140 else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
9141 // Let the iseq act like a C method in backtraces
9142 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9143 }
9144 else {
9145 goto unknown_arg;
9146 }
9147 node = next;
9148 }
9149 return COMPILE_OK;
9150 no_arg:
9151 COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
9152 return COMPILE_NG;
9153 non_symbol_arg:
9154 COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9155 return COMPILE_NG;
9156 unknown_arg:
9157 COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
9158 return COMPILE_NG;
9159 bad_arg:
9160 UNKNOWN_NODE("attr!", node, COMPILE_NG);
9161}
9162
9163static int
9164compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
9165{
9166 VALUE name;
9167
9168 if (!node) goto no_arg;
9169 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
9170 if (RNODE_LIST(node)->nd_next) goto too_many_arg;
9171 node = RNODE_LIST(node)->nd_head;
9172 if (!node) goto no_arg;
9173 switch (nd_type(node)) {
9174 case NODE_SYM:
9175 name = rb_node_sym_string_val(node);
9176 break;
9177 default:
9178 goto bad_arg;
9179 }
9180 if (!SYMBOL_P(name)) goto non_symbol_arg;
9181 if (!popped) {
9182 compile_lvar(iseq, ret, line_node, SYM2ID(name));
9183 }
9184 return COMPILE_OK;
9185 no_arg:
9186 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
9187 return COMPILE_NG;
9188 too_many_arg:
9189 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
9190 return COMPILE_NG;
9191 non_symbol_arg:
9192 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
9193 rb_builtin_class_name(name));
9194 return COMPILE_NG;
9195 bad_arg:
9196 UNKNOWN_NODE("arg!", node, COMPILE_NG);
9197}
9198
9199static NODE *
9200mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
9201{
9202 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9203 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9204 return RNODE_IF(node)->nd_body;
9205 }
9206 else {
9207 rb_bug("mandatory_node: can't find mandatory node");
9208 }
9209}
9210
9211static int
9212compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
9213{
9214 // arguments
9215 struct rb_args_info args = {
9216 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9217 };
9218 rb_node_args_t args_node;
9219 rb_node_init(RNODE(&args_node), NODE_ARGS);
9220 args_node.nd_ainfo = args;
9221
9222 // local table without non-mandatory parameters
9223 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9224 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9225
9226 VALUE idtmp = 0;
9227 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
9228 tbl->size = table_size;
9229
9230 int i;
9231
9232 // lead parameters
9233 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9234 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9235 }
9236 // local variables
9237 for (; i<table_size; i++) {
9238 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9239 }
9240
9241 rb_node_scope_t scope_node;
9242 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9243 scope_node.nd_tbl = tbl;
9244 scope_node.nd_body = mandatory_node(iseq, node);
9245 scope_node.nd_args = &args_node;
9246
9247 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9248
9249 const rb_iseq_t *mandatory_only_iseq =
9250 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9251 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9252 nd_line(line_node), NULL, 0,
9253 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9254 ISEQ_BODY(iseq)->variable.script_lines);
9255 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
9256
9257 ALLOCV_END(idtmp);
9258 return COMPILE_OK;
9259}
9260
9261static int
9262compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
9263 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
9264{
9265 NODE *args_node = get_nd_args(node);
9266
9267 if (parent_block != NULL) {
9268 COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
9269 return COMPILE_NG;
9270 }
9271 else {
9272# define BUILTIN_INLINE_PREFIX "_bi"
9273 char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
9274 bool cconst = false;
9275 retry:;
9276 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
9277
9278 if (bf == NULL) {
9279 if (strcmp("cstmt!", builtin_func) == 0 ||
9280 strcmp("cexpr!", builtin_func) == 0) {
9281 // ok
9282 }
9283 else if (strcmp("cconst!", builtin_func) == 0) {
9284 cconst = true;
9285 }
9286 else if (strcmp("cinit!", builtin_func) == 0) {
9287 // ignore
9288 return COMPILE_OK;
9289 }
9290 else if (strcmp("attr!", builtin_func) == 0) {
9291 return compile_builtin_attr(iseq, args_node);
9292 }
9293 else if (strcmp("arg!", builtin_func) == 0) {
9294 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9295 }
9296 else if (strcmp("mandatory_only?", builtin_func) == 0) {
9297 if (popped) {
9298 rb_bug("mandatory_only? should be in if condition");
9299 }
9300 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9301 rb_bug("mandatory_only? should be put on top");
9302 }
9303
9304 ADD_INSN1(ret, line_node, putobject, Qfalse);
9305 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9306 }
9307 else if (1) {
9308 rb_bug("can't find builtin function:%s", builtin_func);
9309 }
9310 else {
9311 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
9312 return COMPILE_NG;
9313 }
9314
9315 int inline_index = nd_line(node);
9316 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
9317 builtin_func = inline_func;
9318 args_node = NULL;
9319 goto retry;
9320 }
9321
9322 if (cconst) {
9323 typedef VALUE(*builtin_func0)(void *, VALUE);
9324 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL, Qnil);
9325 ADD_INSN1(ret, line_node, putobject, const_val);
9326 return COMPILE_OK;
9327 }
9328
9329 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
9330
9331 unsigned int flag = 0;
9332 struct rb_callinfo_kwarg *keywords = NULL;
9333 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9334
9335 if (FIX2INT(argc) != bf->argc) {
9336 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
9337 builtin_func, bf->argc, FIX2INT(argc));
9338 return COMPILE_NG;
9339 }
9340
9341 unsigned int start_index;
9342 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
9343 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
9344 }
9345 else {
9346 ADD_SEQ(ret, args);
9347 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9348 }
9349
9350 if (popped) ADD_INSN(ret, line_node, pop);
9351 return COMPILE_OK;
9352 }
9353}
9354
9355static int
9356compile_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)
9357{
9358 /* call: obj.method(...)
9359 * fcall: func(...)
9360 * vcall: func
9361 */
9362 DECL_ANCHOR(recv);
9363 DECL_ANCHOR(args);
9364 ID mid = get_node_call_nd_mid(node);
9365 VALUE argc;
9366 unsigned int flag = 0;
9367 struct rb_callinfo_kwarg *keywords = NULL;
9368 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9369 LABEL *else_label = NULL;
9370 VALUE branches = Qfalse;
9371
9372 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9373
9374 INIT_ANCHOR(recv);
9375 INIT_ANCHOR(args);
9376
9377#if OPT_SUPPORT_JOKE
9378 if (nd_type_p(node, NODE_VCALL)) {
9379 ID id_bitblt;
9380 ID id_answer;
9381
9382 CONST_ID(id_bitblt, "bitblt");
9383 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
9384
9385 if (mid == id_bitblt) {
9386 ADD_INSN(ret, line_node, bitblt);
9387 return COMPILE_OK;
9388 }
9389 else if (mid == id_answer) {
9390 ADD_INSN(ret, line_node, answer);
9391 return COMPILE_OK;
9392 }
9393 }
9394 /* only joke */
9395 {
9396 ID goto_id;
9397 ID label_id;
9398
9399 CONST_ID(goto_id, "__goto__");
9400 CONST_ID(label_id, "__label__");
9401
9402 if (nd_type_p(node, NODE_FCALL) &&
9403 (mid == goto_id || mid == label_id)) {
9404 LABEL *label;
9405 st_data_t data;
9406 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9407 VALUE label_name;
9408
9409 if (!labels_table) {
9410 labels_table = st_init_numtable();
9411 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9412 }
9413 {
9414 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
9415 return COMPILE_NG;
9416 }
9417
9418 if (mid == goto_id) {
9419 ADD_INSNL(ret, line_node, jump, label);
9420 }
9421 else {
9422 ADD_LABEL(ret, label);
9423 }
9424 return COMPILE_OK;
9425 }
9426 }
9427#endif
9428
9429 const char *builtin_func;
9430 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9431 (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
9432 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9433 }
9434
9435 /* receiver */
9436 if (!assume_receiver) {
9437 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
9438 int idx, level;
9439
9440 if (mid == idCall &&
9441 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9442 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9443 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
9444 }
9445 else if (private_recv_p(node)) {
9446 ADD_INSN(recv, node, putself);
9447 flag |= VM_CALL_FCALL;
9448 }
9449 else {
9450 CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
9451 }
9452
9453 if (type == NODE_QCALL) {
9454 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9455 }
9456 }
9457 else if (type == NODE_FCALL || type == NODE_VCALL) {
9458 ADD_CALL_RECEIVER(recv, line_node);
9459 }
9460 }
9461
9462 /* args */
9463 if (type != NODE_VCALL) {
9464 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9465 CHECK(!NIL_P(argc));
9466 }
9467 else {
9468 argc = INT2FIX(0);
9469 }
9470
9471 ADD_SEQ(ret, recv);
9472
9473 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9474 mid == rb_intern("new") &&
9475 parent_block == NULL &&
9476 !(flag & VM_CALL_ARGS_BLOCKARG);
9477
9478 if (inline_new) {
9479 ADD_INSN(ret, node, putnil);
9480 ADD_INSN(ret, node, swap);
9481 }
9482
9483 ADD_SEQ(ret, args);
9484
9485 debugp_param("call args argc", argc);
9486 debugp_param("call method", ID2SYM(mid));
9487
9488 switch ((int)type) {
9489 case NODE_VCALL:
9490 flag |= VM_CALL_VCALL;
9491 /* VCALL is funcall, so fall through */
9492 case NODE_FCALL:
9493 flag |= VM_CALL_FCALL;
9494 }
9495
9496 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9497 ADD_INSN(ret, line_node, splatkw);
9498 }
9499
9500 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9501 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9502
9503 if (inline_new) {
9504 // Jump unless the receiver uses the "basic" implementation of "new"
9505 VALUE ci;
9506 if (flag & VM_CALL_FORWARDING) {
9507 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc) + 1, flag, keywords, 0);
9508 }
9509 else {
9510 ci = (VALUE)new_callinfo(iseq, mid, NUM2INT(argc), flag, keywords, 0);
9511 }
9512 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9513 LABEL_REF(not_basic_new);
9514
9515 // optimized path
9516 ADD_SEND_R(ret, line_node, rb_intern("initialize"), argc, parent_block, INT2FIX(flag | VM_CALL_FCALL), keywords);
9517 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9518
9519 ADD_LABEL(ret, not_basic_new);
9520 // Fall back to normal send
9521 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9522 ADD_INSN(ret, line_node, swap);
9523
9524 ADD_LABEL(ret, not_basic_new_finish);
9525 ADD_INSN(ret, line_node, pop);
9526 }
9527 else {
9528 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
9529 }
9530
9531 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9532 if (popped) {
9533 ADD_INSN(ret, line_node, pop);
9534 }
9535 return COMPILE_OK;
9536}
9537
9538static int
9539compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9540{
9541 const int line = nd_line(node);
9542 VALUE argc;
9543 unsigned int flag = 0;
9544 int asgnflag = 0;
9545 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9546
9547 /*
9548 * a[x] (op)= y
9549 *
9550 * nil # nil
9551 * eval a # nil a
9552 * eval x # nil a x
9553 * dupn 2 # nil a x a x
9554 * send :[] # nil a x a[x]
9555 * eval y # nil a x a[x] y
9556 * send op # nil a x ret
9557 * setn 3 # ret a x ret
9558 * send []= # ret ?
9559 * pop # ret
9560 */
9561
9562 /*
9563 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9564 * NODE_OP_ASGN nd_recv
9565 * nd_args->nd_head
9566 * nd_args->nd_body
9567 * nd_mid
9568 */
9569
9570 if (!popped) {
9571 ADD_INSN(ret, node, putnil);
9572 }
9573 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9574 CHECK(asgnflag != -1);
9575 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9576 case NODE_ZLIST:
9577 argc = INT2FIX(0);
9578 break;
9579 default:
9580 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9581 CHECK(!NIL_P(argc));
9582 }
9583 int dup_argn = FIX2INT(argc) + 1;
9584 ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
9585 flag |= asgnflag;
9586 ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9587
9588 if (id == idOROP || id == idANDOP) {
9589 /* a[x] ||= y or a[x] &&= y
9590
9591 unless/if a[x]
9592 a[x]= y
9593 else
9594 nil
9595 end
9596 */
9597 LABEL *label = NEW_LABEL(line);
9598 LABEL *lfin = NEW_LABEL(line);
9599
9600 ADD_INSN(ret, node, dup);
9601 if (id == idOROP) {
9602 ADD_INSNL(ret, node, branchif, label);
9603 }
9604 else { /* idANDOP */
9605 ADD_INSNL(ret, node, branchunless, label);
9606 }
9607 ADD_INSN(ret, node, pop);
9608
9609 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9610 if (!popped) {
9611 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9612 }
9613 if (flag & VM_CALL_ARGS_SPLAT) {
9614 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9615 ADD_INSN(ret, node, swap);
9616 ADD_INSN1(ret, node, splatarray, Qtrue);
9617 ADD_INSN(ret, node, swap);
9618 flag |= VM_CALL_ARGS_SPLAT_MUT;
9619 }
9620 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9621 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9622 }
9623 else {
9624 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9625 }
9626 ADD_INSN(ret, node, pop);
9627 ADD_INSNL(ret, node, jump, lfin);
9628 ADD_LABEL(ret, label);
9629 if (!popped) {
9630 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9631 }
9632 ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
9633 ADD_LABEL(ret, lfin);
9634 }
9635 else {
9636 CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9637 ADD_SEND(ret, node, id, INT2FIX(1));
9638 if (!popped) {
9639 ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
9640 }
9641 if (flag & VM_CALL_ARGS_SPLAT) {
9642 if (flag & VM_CALL_KW_SPLAT) {
9643 ADD_INSN1(ret, node, topn, INT2FIX(2));
9644 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9645 ADD_INSN1(ret, node, splatarray, Qtrue);
9646 flag |= VM_CALL_ARGS_SPLAT_MUT;
9647 }
9648 ADD_INSN(ret, node, swap);
9649 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9650 ADD_INSN1(ret, node, setn, INT2FIX(2));
9651 ADD_INSN(ret, node, pop);
9652 }
9653 else {
9654 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9655 ADD_INSN(ret, node, swap);
9656 ADD_INSN1(ret, node, splatarray, Qtrue);
9657 ADD_INSN(ret, node, swap);
9658 flag |= VM_CALL_ARGS_SPLAT_MUT;
9659 }
9660 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
9661 }
9662 ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
9663 }
9664 else {
9665 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
9666 }
9667 ADD_INSN(ret, node, pop);
9668 }
9669 return COMPILE_OK;
9670}
9671
9672static int
9673compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9674{
9675 const int line = nd_line(node);
9676 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9677 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9678 int asgnflag;
9679 LABEL *lfin = NEW_LABEL(line);
9680 LABEL *lcfin = NEW_LABEL(line);
9681 LABEL *lskip = 0;
9682 /*
9683 class C; attr_accessor :c; end
9684 r = C.new
9685 r.a &&= v # asgn2
9686
9687 eval r # r
9688 dup # r r
9689 eval r.a # r o
9690
9691 # or
9692 dup # r o o
9693 if lcfin # r o
9694 pop # r
9695 eval v # r v
9696 swap # v r
9697 topn 1 # v r v
9698 send a= # v ?
9699 jump lfin # v ?
9700
9701 lcfin: # r o
9702 swap # o r
9703
9704 lfin: # o ?
9705 pop # o
9706
9707 # or (popped)
9708 if lcfin # r
9709 eval v # r v
9710 send a= # ?
9711 jump lfin # ?
9712
9713 lcfin: # r
9714
9715 lfin: # ?
9716 pop #
9717
9718 # and
9719 dup # r o o
9720 unless lcfin
9721 pop # r
9722 eval v # r v
9723 swap # v r
9724 topn 1 # v r v
9725 send a= # v ?
9726 jump lfin # v ?
9727
9728 # others
9729 eval v # r o v
9730 send ?? # r w
9731 send a= # w
9732
9733 */
9734
9735 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9736 CHECK(asgnflag != -1);
9737 if (RNODE_OP_ASGN2(node)->nd_aid) {
9738 lskip = NEW_LABEL(line);
9739 ADD_INSN(ret, node, dup);
9740 ADD_INSNL(ret, node, branchnil, lskip);
9741 }
9742 ADD_INSN(ret, node, dup);
9743 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
9744
9745 if (atype == idOROP || atype == idANDOP) {
9746 if (!popped) {
9747 ADD_INSN(ret, node, dup);
9748 }
9749 if (atype == idOROP) {
9750 ADD_INSNL(ret, node, branchif, lcfin);
9751 }
9752 else { /* idANDOP */
9753 ADD_INSNL(ret, node, branchunless, lcfin);
9754 }
9755 if (!popped) {
9756 ADD_INSN(ret, node, pop);
9757 }
9758 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9759 if (!popped) {
9760 ADD_INSN(ret, node, swap);
9761 ADD_INSN1(ret, node, topn, INT2FIX(1));
9762 }
9763 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9764 ADD_INSNL(ret, node, jump, lfin);
9765
9766 ADD_LABEL(ret, lcfin);
9767 if (!popped) {
9768 ADD_INSN(ret, node, swap);
9769 }
9770
9771 ADD_LABEL(ret, lfin);
9772 }
9773 else {
9774 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9775 ADD_SEND(ret, node, atype, INT2FIX(1));
9776 if (!popped) {
9777 ADD_INSN(ret, node, swap);
9778 ADD_INSN1(ret, node, topn, INT2FIX(1));
9779 }
9780 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
9781 }
9782 if (lskip && popped) {
9783 ADD_LABEL(ret, lskip);
9784 }
9785 ADD_INSN(ret, node, pop);
9786 if (lskip && !popped) {
9787 ADD_LABEL(ret, lskip);
9788 }
9789 return COMPILE_OK;
9790}
9791
9792static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
9793
9794static int
9795compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9796{
9797 const int line = nd_line(node);
9798 LABEL *lfin = 0;
9799 LABEL *lassign = 0;
9800 ID mid;
9801
9802 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9803 case NODE_COLON3:
9804 ADD_INSN1(ret, node, putobject, rb_cObject);
9805 break;
9806 case NODE_COLON2:
9807 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9808 break;
9809 default:
9810 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
9811 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9812 return COMPILE_NG;
9813 }
9814 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9815 /* cref */
9816 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9817 lassign = NEW_LABEL(line);
9818 ADD_INSN(ret, node, dup); /* cref cref */
9819 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
9820 ID2SYM(mid), Qtrue); /* cref bool */
9821 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
9822 }
9823 ADD_INSN(ret, node, dup); /* cref cref */
9824 ADD_INSN1(ret, node, putobject, Qtrue);
9825 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
9826
9827 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9828 lfin = NEW_LABEL(line);
9829 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
9830 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9831 ADD_INSNL(ret, node, branchif, lfin);
9832 else /* idANDOP */
9833 ADD_INSNL(ret, node, branchunless, lfin);
9834 /* cref [obj] */
9835 if (!popped) ADD_INSN(ret, node, pop); /* cref */
9836 if (lassign) ADD_LABEL(ret, lassign);
9837 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9838 /* cref value */
9839 if (popped)
9840 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
9841 else {
9842 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
9843 ADD_INSN(ret, node, swap); /* cref value value cref */
9844 }
9845 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
9846 ADD_LABEL(ret, lfin); /* cref [value] */
9847 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
9848 ADD_INSN(ret, node, pop); /* [value] */
9849 }
9850 else {
9851 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9852 /* cref obj value */
9853 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
9854 /* cref value */
9855 ADD_INSN(ret, node, swap); /* value cref */
9856 if (!popped) {
9857 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
9858 ADD_INSN(ret, node, swap); /* value value cref */
9859 }
9860 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
9861 }
9862 return COMPILE_OK;
9863}
9864
9865static int
9866compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9867{
9868 const int line = nd_line(node);
9869 LABEL *lfin = NEW_LABEL(line);
9870 LABEL *lassign;
9871
9872 if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9873 LABEL *lfinish[2];
9874 lfinish[0] = lfin;
9875 lfinish[1] = 0;
9876 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
9877 lassign = lfinish[1];
9878 if (!lassign) {
9879 lassign = NEW_LABEL(line);
9880 }
9881 ADD_INSNL(ret, node, branchunless, lassign);
9882 }
9883 else {
9884 lassign = NEW_LABEL(line);
9885 }
9886
9887 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9888
9889 if (!popped) {
9890 ADD_INSN(ret, node, dup);
9891 }
9892
9893 if (type == NODE_OP_ASGN_AND) {
9894 ADD_INSNL(ret, node, branchunless, lfin);
9895 }
9896 else {
9897 ADD_INSNL(ret, node, branchif, lfin);
9898 }
9899
9900 if (!popped) {
9901 ADD_INSN(ret, node, pop);
9902 }
9903
9904 ADD_LABEL(ret, lassign);
9905 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9906 ADD_LABEL(ret, lfin);
9907 return COMPILE_OK;
9908}
9909
9910static int
9911compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9912{
9913 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9914 DECL_ANCHOR(args);
9915 int argc;
9916 unsigned int flag = 0;
9917 struct rb_callinfo_kwarg *keywords = NULL;
9918 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9919 int use_block = 1;
9920
9921 INIT_ANCHOR(args);
9922 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9923
9924 if (type == NODE_SUPER) {
9925 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9926 CHECK(!NIL_P(vargc));
9927 argc = FIX2INT(vargc);
9928 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9929 ADD_INSN(args, node, splatkw);
9930 }
9931
9932 if (flag & VM_CALL_ARGS_BLOCKARG) {
9933 use_block = 0;
9934 }
9935 }
9936 else {
9937 /* NODE_ZSUPER */
9938 int i;
9939 const rb_iseq_t *liseq = body->local_iseq;
9940 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
9941 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
9942 int lvar_level = get_lvar_level(iseq);
9943
9944 argc = local_body->param.lead_num;
9945
9946 /* normal arguments */
9947 for (i = 0; i < local_body->param.lead_num; i++) {
9948 int idx = local_body->local_table_size - i;
9949 ADD_GETLOCAL(args, node, idx, lvar_level);
9950 }
9951
9952 /* forward ... */
9953 if (local_body->param.flags.forwardable) {
9954 flag |= VM_CALL_FORWARDING;
9955 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9956 ADD_GETLOCAL(args, node, idx, lvar_level);
9957 }
9958
9959 if (local_body->param.flags.has_opt) {
9960 /* optional arguments */
9961 int j;
9962 for (j = 0; j < local_body->param.opt_num; j++) {
9963 int idx = local_body->local_table_size - (i + j);
9964 ADD_GETLOCAL(args, node, idx, lvar_level);
9965 }
9966 i += j;
9967 argc = i;
9968 }
9969 if (local_body->param.flags.has_rest) {
9970 /* rest argument */
9971 int idx = local_body->local_table_size - local_body->param.rest_start;
9972 ADD_GETLOCAL(args, node, idx, lvar_level);
9973 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
9974
9975 argc = local_body->param.rest_start + 1;
9976 flag |= VM_CALL_ARGS_SPLAT;
9977 }
9978 if (local_body->param.flags.has_post) {
9979 /* post arguments */
9980 int post_len = local_body->param.post_num;
9981 int post_start = local_body->param.post_start;
9982
9983 if (local_body->param.flags.has_rest) {
9984 int j;
9985 for (j=0; j<post_len; j++) {
9986 int idx = local_body->local_table_size - (post_start + j);
9987 ADD_GETLOCAL(args, node, idx, lvar_level);
9988 }
9989 ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
9990 flag |= VM_CALL_ARGS_SPLAT_MUT;
9991 /* argc is settled at above */
9992 }
9993 else {
9994 int j;
9995 for (j=0; j<post_len; j++) {
9996 int idx = local_body->local_table_size - (post_start + j);
9997 ADD_GETLOCAL(args, node, idx, lvar_level);
9998 }
9999 argc = post_len + post_start;
10000 }
10001 }
10002
10003 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
10004 int local_size = local_body->local_table_size;
10005 argc++;
10006
10007 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10008
10009 if (local_body->param.flags.has_kwrest) {
10010 int idx = local_body->local_table_size - local_kwd->rest_start;
10011 ADD_GETLOCAL(args, node, idx, lvar_level);
10012 RUBY_ASSERT(local_kwd->num > 0);
10013 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
10014 }
10015 else {
10016 ADD_INSN1(args, node, newhash, INT2FIX(0));
10017 }
10018 for (i = 0; i < local_kwd->num; ++i) {
10019 ID id = local_kwd->table[i];
10020 int idx = local_size - get_local_var_idx(liseq, id);
10021 ADD_INSN1(args, node, putobject, ID2SYM(id));
10022 ADD_GETLOCAL(args, node, idx, lvar_level);
10023 }
10024 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
10025 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10026 }
10027 else if (local_body->param.flags.has_kwrest) {
10028 int idx = local_body->local_table_size - local_kwd->rest_start;
10029 ADD_GETLOCAL(args, node, idx, lvar_level);
10030 argc++;
10031 flag |= VM_CALL_KW_SPLAT;
10032 }
10033 }
10034
10035 if (use_block && parent_block == NULL) {
10036 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10037 }
10038
10039 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10040 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10041 ADD_INSN(ret, node, putself);
10042 ADD_SEQ(ret, args);
10043
10044 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10045
10046 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10047 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10048 }
10049 else {
10050 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10051 }
10052
10053 if (popped) {
10054 ADD_INSN(ret, node, pop);
10055 }
10056 return COMPILE_OK;
10057}
10058
10059static int
10060compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10061{
10062 DECL_ANCHOR(args);
10063 VALUE argc;
10064 unsigned int flag = 0;
10065 struct rb_callinfo_kwarg *keywords = NULL;
10066
10067 INIT_ANCHOR(args);
10068
10069 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
10070 case ISEQ_TYPE_TOP:
10071 case ISEQ_TYPE_MAIN:
10072 case ISEQ_TYPE_CLASS:
10073 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
10074 return COMPILE_NG;
10075 default: /* valid */;
10076 }
10077
10078 if (RNODE_YIELD(node)->nd_head) {
10079 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10080 CHECK(!NIL_P(argc));
10081 }
10082 else {
10083 argc = INT2FIX(0);
10084 }
10085
10086 ADD_SEQ(ret, args);
10087 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
10088 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10089
10090 if (popped) {
10091 ADD_INSN(ret, node, pop);
10092 }
10093
10094 int level = 0;
10095 const rb_iseq_t *tmp_iseq = iseq;
10096 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10097 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10098 }
10099 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
10100
10101 return COMPILE_OK;
10102}
10103
10104static int
10105compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
10106{
10107 DECL_ANCHOR(recv);
10108 DECL_ANCHOR(val);
10109
10110 INIT_ANCHOR(recv);
10111 INIT_ANCHOR(val);
10112 switch ((int)type) {
10113 case NODE_MATCH:
10114 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
10115 ADD_INSN2(val, node, getspecial, INT2FIX(0),
10116 INT2FIX(0));
10117 break;
10118 case NODE_MATCH2:
10119 CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
10120 CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
10121 break;
10122 case NODE_MATCH3:
10123 CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
10124 CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
10125 break;
10126 }
10127
10128 ADD_SEQ(ret, recv);
10129 ADD_SEQ(ret, val);
10130 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
10131
10132 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10133 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10134 }
10135
10136 if (popped) {
10137 ADD_INSN(ret, node, pop);
10138 }
10139 return COMPILE_OK;
10140}
10141
10142static int
10143compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10144{
10145 if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
10146 /* constant */
10147 VALUE segments;
10148 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10149 (segments = collect_const_segments(iseq, node))) {
10150 ISEQ_BODY(iseq)->ic_size++;
10151 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10152 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10153 }
10154 else {
10155 /* constant */
10156 DECL_ANCHOR(pref);
10157 DECL_ANCHOR(body);
10158
10159 INIT_ANCHOR(pref);
10160 INIT_ANCHOR(body);
10161 CHECK(compile_const_prefix(iseq, node, pref, body));
10162 if (LIST_INSN_SIZE_ZERO(pref)) {
10163 ADD_INSN(ret, node, putnil);
10164 ADD_SEQ(ret, body);
10165 }
10166 else {
10167 ADD_SEQ(ret, pref);
10168 ADD_SEQ(ret, body);
10169 }
10170 }
10171 }
10172 else {
10173 /* function call */
10174 ADD_CALL_RECEIVER(ret, node);
10175 CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
10176 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
10177 }
10178 if (popped) {
10179 ADD_INSN(ret, node, pop);
10180 }
10181 return COMPILE_OK;
10182}
10183
10184static int
10185compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10186{
10187 debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10188
10189 /* add cache insn */
10190 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10191 ISEQ_BODY(iseq)->ic_size++;
10192 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
10193 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10194 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10195 }
10196 else {
10197 ADD_INSN1(ret, node, putobject, rb_cObject);
10198 ADD_INSN1(ret, node, putobject, Qtrue);
10199 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
10200 }
10201
10202 if (popped) {
10203 ADD_INSN(ret, node, pop);
10204 }
10205 return COMPILE_OK;
10206}
10207
10208static int
10209compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
10210{
10211 VALUE flag = INT2FIX(excl);
10212 const NODE *b = RNODE_DOT2(node)->nd_beg;
10213 const NODE *e = RNODE_DOT2(node)->nd_end;
10214
10215 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10216 if (!popped) {
10217 VALUE bv = optimized_range_item(b);
10218 VALUE ev = optimized_range_item(e);
10219 VALUE val = rb_range_new(bv, ev, excl);
10220 ADD_INSN1(ret, node, putobject, val);
10221 RB_OBJ_WRITTEN(iseq, Qundef, val);
10222 }
10223 }
10224 else {
10225 CHECK(COMPILE_(ret, "min", b, popped));
10226 CHECK(COMPILE_(ret, "max", e, popped));
10227 if (!popped) {
10228 ADD_INSN1(ret, node, newrange, flag);
10229 }
10230 }
10231 return COMPILE_OK;
10232}
10233
10234static int
10235compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10236{
10237 if (!popped) {
10238 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
10239 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10240 }
10241 else {
10242 const rb_iseq_t *ip = iseq;
10243 int level = 0;
10244 while (ip) {
10245 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
10246 break;
10247 }
10248 ip = ISEQ_BODY(ip)->parent_iseq;
10249 level++;
10250 }
10251 if (ip) {
10252 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10253 }
10254 else {
10255 ADD_INSN(ret, node, putnil);
10256 }
10257 }
10258 }
10259 return COMPILE_OK;
10260}
10261
10262static int
10263compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10264{
10265 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10266 LABEL *end_label = NEW_LABEL(nd_line(node));
10267 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10268
10269 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10270 /* required argument. do nothing */
10271 COMPILE_ERROR(ERROR_ARGS "unreachable");
10272 return COMPILE_NG;
10273 }
10274 else if (nd_type_p(default_value, NODE_SYM) ||
10275 nd_type_p(default_value, NODE_REGX) ||
10276 nd_type_p(default_value, NODE_LINE) ||
10277 nd_type_p(default_value, NODE_INTEGER) ||
10278 nd_type_p(default_value, NODE_FLOAT) ||
10279 nd_type_p(default_value, NODE_RATIONAL) ||
10280 nd_type_p(default_value, NODE_IMAGINARY) ||
10281 nd_type_p(default_value, NODE_NIL) ||
10282 nd_type_p(default_value, NODE_TRUE) ||
10283 nd_type_p(default_value, NODE_FALSE)) {
10284 COMPILE_ERROR(ERROR_ARGS "unreachable");
10285 return COMPILE_NG;
10286 }
10287 else {
10288 /* if keywordcheck(_kw_bits, nth_keyword)
10289 * kw = default_value
10290 * end
10291 */
10292 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10293 int keyword_idx = body->param.keyword->num;
10294
10295 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
10296 ADD_INSNL(ret, node, branchif, end_label);
10297 CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
10298 ADD_LABEL(ret, end_label);
10299 }
10300 return COMPILE_OK;
10301}
10302
10303static int
10304compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10305{
10306 DECL_ANCHOR(recv);
10307 DECL_ANCHOR(args);
10308 unsigned int flag = 0;
10309 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10310 VALUE argc;
10311 LABEL *else_label = NULL;
10312 VALUE branches = Qfalse;
10313
10314 /* optimization shortcut
10315 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
10316 */
10317 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10318 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10319 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10320 (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
10321 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10322 !frozen_string_literal_p(iseq) &&
10323 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10324 {
10325 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10326 CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
10327 CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10328 if (!popped) {
10329 ADD_INSN(ret, node, swap);
10330 ADD_INSN1(ret, node, topn, INT2FIX(1));
10331 }
10332 ADD_INSN2(ret, node, opt_aset_with, str,
10333 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10334 RB_OBJ_WRITTEN(iseq, Qundef, str);
10335 ADD_INSN(ret, node, pop);
10336 return COMPILE_OK;
10337 }
10338
10339 INIT_ANCHOR(recv);
10340 INIT_ANCHOR(args);
10341 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10342 CHECK(!NIL_P(argc));
10343
10344 int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
10345 CHECK(asgnflag != -1);
10346 flag |= (unsigned int)asgnflag;
10347
10348 debugp_param("argc", argc);
10349 debugp_param("nd_mid", ID2SYM(mid));
10350
10351 if (!rb_is_attrset_id(mid)) {
10352 /* safe nav attr */
10353 mid = rb_id_attrset(mid);
10354 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10355 }
10356 if (!popped) {
10357 ADD_INSN(ret, node, putnil);
10358 ADD_SEQ(ret, recv);
10359 ADD_SEQ(ret, args);
10360
10361 if (flag & VM_CALL_ARGS_SPLAT) {
10362 ADD_INSN(ret, node, dup);
10363 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
10364 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
10365 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10366 ADD_INSN (ret, node, pop);
10367 }
10368 else {
10369 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10370 }
10371 }
10372 else {
10373 ADD_SEQ(ret, recv);
10374 ADD_SEQ(ret, args);
10375 }
10376 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
10377 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10378 ADD_INSN(ret, node, pop);
10379 return COMPILE_OK;
10380}
10381
10382static int
10383compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
10384{
10385 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10386 ADD_SEQ(ret, sub);
10387
10388 if (copy) {
10389 /*
10390 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
10391 * NEW_LIST(value, loc), loc);
10392 */
10393 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10394 }
10395 else {
10396 /*
10397 * NEW_CALL(fcore, rb_intern("make_shareable"),
10398 * NEW_LIST(value, loc), loc);
10399 */
10400 ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
10401 }
10402
10403 return COMPILE_OK;
10404}
10405
10406static VALUE
10407node_const_decl_val(const NODE *node)
10408{
10409 VALUE path;
10410 switch (nd_type(node)) {
10411 case NODE_CDECL:
10412 if (RNODE_CDECL(node)->nd_vid) {
10413 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10414 goto end;
10415 }
10416 else {
10417 node = RNODE_CDECL(node)->nd_else;
10418 }
10419 break;
10420 case NODE_COLON2:
10421 break;
10422 case NODE_COLON3:
10423 // ::Const
10424 path = rb_str_new_cstr("::");
10425 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10426 goto end;
10427 default:
10428 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
10430 }
10431
10432 path = rb_ary_new();
10433 if (node) {
10434 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10435 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10436 }
10437 if (node && nd_type_p(node, NODE_CONST)) {
10438 // Const::Name
10439 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10440 }
10441 else if (node && nd_type_p(node, NODE_COLON3)) {
10442 // ::Const::Name
10443 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10444 rb_ary_push(path, rb_str_new(0, 0));
10445 }
10446 else {
10447 // expression::Name
10448 rb_ary_push(path, rb_str_new_cstr("..."));
10449 }
10450 path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
10451 }
10452 end:
10453 path = rb_fstring(path);
10454 return path;
10455}
10456
10457static VALUE
10458const_decl_path(NODE *dest)
10459{
10460 VALUE path = Qnil;
10461 if (!nd_type_p(dest, NODE_CALL)) {
10462 path = node_const_decl_val(dest);
10463 }
10464 return path;
10465}
10466
10467static int
10468compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
10469{
10470 /*
10471 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
10472 */
10473 VALUE path = const_decl_path(dest);
10474 ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10475 CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
10476 ADD_INSN1(ret, value, putobject, path);
10477 RB_OBJ_WRITTEN(iseq, Qundef, path);
10478 ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
10479
10480 return COMPILE_OK;
10481}
10482
10483#ifndef SHAREABLE_BARE_EXPRESSION
10484#define SHAREABLE_BARE_EXPRESSION 1
10485#endif
10486
10487static int
10488compile_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)
10489{
10490# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10491 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10492 VALUE lit = Qnil;
10493 DECL_ANCHOR(anchor);
10494
10495 enum node_type type = node ? nd_type(node) : NODE_NIL;
10496 switch (type) {
10497 case NODE_TRUE:
10498 *value_p = Qtrue;
10499 goto compile;
10500 case NODE_FALSE:
10501 *value_p = Qfalse;
10502 goto compile;
10503 case NODE_NIL:
10504 *value_p = Qnil;
10505 goto compile;
10506 case NODE_SYM:
10507 *value_p = rb_node_sym_string_val(node);
10508 goto compile;
10509 case NODE_REGX:
10510 *value_p = rb_node_regx_string_val(node);
10511 goto compile;
10512 case NODE_LINE:
10513 *value_p = rb_node_line_lineno_val(node);
10514 goto compile;
10515 case NODE_INTEGER:
10516 *value_p = rb_node_integer_literal_val(node);
10517 goto compile;
10518 case NODE_FLOAT:
10519 *value_p = rb_node_float_literal_val(node);
10520 goto compile;
10521 case NODE_RATIONAL:
10522 *value_p = rb_node_rational_literal_val(node);
10523 goto compile;
10524 case NODE_IMAGINARY:
10525 *value_p = rb_node_imaginary_literal_val(node);
10526 goto compile;
10527 case NODE_ENCODING:
10528 *value_p = rb_node_encoding_val(node);
10529
10530 compile:
10531 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10532 *shareable_literal_p = 1;
10533 return COMPILE_OK;
10534
10535 case NODE_DSTR:
10536 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10537 if (shareable == rb_parser_shareable_literal) {
10538 /*
10539 * NEW_CALL(node, idUMinus, 0, loc);
10540 *
10541 * -"#{var}"
10542 */
10543 ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
10544 }
10545 *value_p = Qundef;
10546 *shareable_literal_p = 1;
10547 return COMPILE_OK;
10548
10549 case NODE_STR:{
10550 VALUE lit = rb_node_str_string_val(node);
10551 ADD_INSN1(ret, node, putobject, lit);
10552 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10553 *value_p = lit;
10554 *shareable_literal_p = 1;
10555
10556 return COMPILE_OK;
10557 }
10558
10559 case NODE_FILE:{
10560 VALUE lit = rb_node_file_path_val(node);
10561 ADD_INSN1(ret, node, putobject, lit);
10562 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10563 *value_p = lit;
10564 *shareable_literal_p = 1;
10565
10566 return COMPILE_OK;
10567 }
10568
10569 case NODE_ZLIST:{
10570 VALUE lit = rb_ary_new();
10571 OBJ_FREEZE(lit);
10572 ADD_INSN1(ret, node, putobject, lit);
10573 RB_OBJ_WRITTEN(iseq, Qundef, lit);
10574 *value_p = lit;
10575 *shareable_literal_p = 1;
10576
10577 return COMPILE_OK;
10578 }
10579
10580 case NODE_LIST:{
10581 INIT_ANCHOR(anchor);
10582 lit = rb_ary_new();
10583 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10584 VALUE val;
10585 int shareable_literal_p2;
10586 NODE *elt = RNODE_LIST(n)->nd_head;
10587 if (elt) {
10588 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10589 if (shareable_literal_p2) {
10590 /* noop */
10591 }
10592 else if (RTEST(lit)) {
10593 rb_ary_clear(lit);
10594 lit = Qfalse;
10595 }
10596 }
10597 if (RTEST(lit)) {
10598 if (!UNDEF_P(val)) {
10599 rb_ary_push(lit, val);
10600 }
10601 else {
10602 rb_ary_clear(lit);
10603 lit = Qnil; /* make shareable at runtime */
10604 }
10605 }
10606 }
10607 break;
10608 }
10609 case NODE_HASH:{
10610 if (!RNODE_HASH(node)->nd_brace) {
10611 *value_p = Qundef;
10612 *shareable_literal_p = 0;
10613 return COMPILE_OK;
10614 }
10615 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10616 if (!RNODE_LIST(n)->nd_head) {
10617 // If the hash node have a keyword splat, fall back to the default case.
10618 goto compile_shareable;
10619 }
10620 }
10621
10622 INIT_ANCHOR(anchor);
10623 lit = rb_hash_new();
10624 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10625 VALUE key_val = 0;
10626 VALUE value_val = 0;
10627 int shareable_literal_p2;
10628 NODE *key = RNODE_LIST(n)->nd_head;
10629 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10630 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10631 if (shareable_literal_p2) {
10632 /* noop */
10633 }
10634 else if (RTEST(lit)) {
10635 rb_hash_clear(lit);
10636 lit = Qfalse;
10637 }
10638 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10639 if (shareable_literal_p2) {
10640 /* noop */
10641 }
10642 else if (RTEST(lit)) {
10643 rb_hash_clear(lit);
10644 lit = Qfalse;
10645 }
10646 if (RTEST(lit)) {
10647 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10648 rb_hash_aset(lit, key_val, value_val);
10649 }
10650 else {
10651 rb_hash_clear(lit);
10652 lit = Qnil; /* make shareable at runtime */
10653 }
10654 }
10655 }
10656 break;
10657 }
10658
10659 default:
10660
10661 compile_shareable:
10662 if (shareable == rb_parser_shareable_literal &&
10663 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10664 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10665 *value_p = Qundef;
10666 *shareable_literal_p = 1;
10667 return COMPILE_OK;
10668 }
10669 CHECK(COMPILE(ret, "shareable_literal_constant", node));
10670 *value_p = Qundef;
10671 *shareable_literal_p = 0;
10672 return COMPILE_OK;
10673 }
10674
10675 /* Array or Hash that does not have keyword splat */
10676 if (!lit) {
10677 if (nd_type(node) == NODE_LIST) {
10678 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10679 }
10680 else if (nd_type(node) == NODE_HASH) {
10681 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10682 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10683 }
10684 *value_p = Qundef;
10685 *shareable_literal_p = 0;
10686 ADD_SEQ(ret, anchor);
10687 return COMPILE_OK;
10688 }
10689 if (NIL_P(lit)) {
10690 // if shareable_literal, all elements should have been ensured
10691 // as shareable
10692 if (nd_type(node) == NODE_LIST) {
10693 ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
10694 }
10695 else if (nd_type(node) == NODE_HASH) {
10696 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10697 ADD_INSN1(anchor, node, newhash, INT2FIX(len));
10698 }
10699 CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
10700 *value_p = Qundef;
10701 *shareable_literal_p = 1;
10702 }
10703 else {
10705 ADD_INSN1(ret, node, putobject, val);
10706 RB_OBJ_WRITTEN(iseq, Qundef, val);
10707 *value_p = val;
10708 *shareable_literal_p = 1;
10709 }
10710
10711 return COMPILE_OK;
10712}
10713
10714static int
10715compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
10716{
10717 int literal_p = 0;
10718 VALUE val;
10719 DECL_ANCHOR(anchor);
10720 INIT_ANCHOR(anchor);
10721
10722 switch (shareable) {
10723 case rb_parser_shareable_none:
10724 CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
10725 return COMPILE_OK;
10726
10727 case rb_parser_shareable_literal:
10728 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10729 ADD_SEQ(ret, anchor);
10730 return COMPILE_OK;
10731
10732 case rb_parser_shareable_copy:
10733 case rb_parser_shareable_everything:
10734 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10735 if (!literal_p) {
10736 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10737 }
10738 else {
10739 ADD_SEQ(ret, anchor);
10740 }
10741 return COMPILE_OK;
10742 default:
10743 rb_bug("unexpected rb_parser_shareability: %d", shareable);
10744 }
10745}
10746
10747static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
10755static int
10756iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
10757{
10758 if (node == 0) {
10759 if (!popped) {
10760 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10761 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
10762 debugs("node: NODE_NIL(implicit)\n");
10763 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10764 }
10765 return COMPILE_OK;
10766 }
10767 return iseq_compile_each0(iseq, ret, node, popped);
10768}
10769
10770static int
10771iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
10772{
10773 const int line = (int)nd_line(node);
10774 const enum node_type type = nd_type(node);
10775 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
10776
10777 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10778 /* ignore */
10779 }
10780 else {
10781 if (nd_fl_newline(node)) {
10782 int event = RUBY_EVENT_LINE;
10783 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10784 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10785 event |= RUBY_EVENT_COVERAGE_LINE;
10786 }
10787 ADD_TRACE(ret, event);
10788 }
10789 }
10790
10791 debug_node_start(node);
10792#undef BEFORE_RETURN
10793#define BEFORE_RETURN debug_node_end()
10794
10795 switch (type) {
10796 case NODE_BLOCK:
10797 CHECK(compile_block(iseq, ret, node, popped));
10798 break;
10799 case NODE_IF:
10800 case NODE_UNLESS:
10801 CHECK(compile_if(iseq, ret, node, popped, type));
10802 break;
10803 case NODE_CASE:
10804 CHECK(compile_case(iseq, ret, node, popped));
10805 break;
10806 case NODE_CASE2:
10807 CHECK(compile_case2(iseq, ret, node, popped));
10808 break;
10809 case NODE_CASE3:
10810 CHECK(compile_case3(iseq, ret, node, popped));
10811 break;
10812 case NODE_WHILE:
10813 case NODE_UNTIL:
10814 CHECK(compile_loop(iseq, ret, node, popped, type));
10815 break;
10816 case NODE_FOR:
10817 case NODE_ITER:
10818 CHECK(compile_iter(iseq, ret, node, popped));
10819 break;
10820 case NODE_FOR_MASGN:
10821 CHECK(compile_for_masgn(iseq, ret, node, popped));
10822 break;
10823 case NODE_BREAK:
10824 CHECK(compile_break(iseq, ret, node, popped));
10825 break;
10826 case NODE_NEXT:
10827 CHECK(compile_next(iseq, ret, node, popped));
10828 break;
10829 case NODE_REDO:
10830 CHECK(compile_redo(iseq, ret, node, popped));
10831 break;
10832 case NODE_RETRY:
10833 CHECK(compile_retry(iseq, ret, node, popped));
10834 break;
10835 case NODE_BEGIN:{
10836 CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10837 break;
10838 }
10839 case NODE_RESCUE:
10840 CHECK(compile_rescue(iseq, ret, node, popped));
10841 break;
10842 case NODE_RESBODY:
10843 CHECK(compile_resbody(iseq, ret, node, popped));
10844 break;
10845 case NODE_ENSURE:
10846 CHECK(compile_ensure(iseq, ret, node, popped));
10847 break;
10848
10849 case NODE_AND:
10850 case NODE_OR:{
10851 LABEL *end_label = NEW_LABEL(line);
10852 CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
10853 if (!popped) {
10854 ADD_INSN(ret, node, dup);
10855 }
10856 if (type == NODE_AND) {
10857 ADD_INSNL(ret, node, branchunless, end_label);
10858 }
10859 else {
10860 ADD_INSNL(ret, node, branchif, end_label);
10861 }
10862 if (!popped) {
10863 ADD_INSN(ret, node, pop);
10864 }
10865 CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10866 ADD_LABEL(ret, end_label);
10867 break;
10868 }
10869
10870 case NODE_MASGN:{
10871 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10872 ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
10873 compile_massign(iseq, ret, node, popped);
10874 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10875 break;
10876 }
10877
10878 case NODE_LASGN:{
10879 ID id = RNODE_LASGN(node)->nd_vid;
10880 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
10881
10882 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
10883 CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
10884
10885 if (!popped) {
10886 ADD_INSN(ret, node, dup);
10887 }
10888 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10889 break;
10890 }
10891 case NODE_DASGN: {
10892 int idx, lv, ls;
10893 ID id = RNODE_DASGN(node)->nd_vid;
10894 CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
10895 debugi("dassn id", rb_id2str(id) ? id : '*');
10896
10897 if (!popped) {
10898 ADD_INSN(ret, node, dup);
10899 }
10900
10901 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
10902
10903 if (idx < 0) {
10904 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
10905 rb_id2str(id));
10906 goto ng;
10907 }
10908 ADD_SETLOCAL(ret, node, ls - idx, lv);
10909 break;
10910 }
10911 case NODE_GASGN:{
10912 CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
10913
10914 if (!popped) {
10915 ADD_INSN(ret, node, dup);
10916 }
10917 ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
10918 break;
10919 }
10920 case NODE_IASGN:{
10921 CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
10922 if (!popped) {
10923 ADD_INSN(ret, node, dup);
10924 }
10925 ADD_INSN2(ret, node, setinstancevariable,
10926 ID2SYM(RNODE_IASGN(node)->nd_vid),
10927 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10928 break;
10929 }
10930 case NODE_CDECL:{
10931 if (RNODE_CDECL(node)->nd_vid) {
10932 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10933
10934 if (!popped) {
10935 ADD_INSN(ret, node, dup);
10936 }
10937
10938 ADD_INSN1(ret, node, putspecialobject,
10939 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10940 ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
10941 }
10942 else {
10943 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10944 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10945 ADD_INSN(ret, node, swap);
10946
10947 if (!popped) {
10948 ADD_INSN1(ret, node, topn, INT2FIX(1));
10949 ADD_INSN(ret, node, swap);
10950 }
10951
10952 ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10953 }
10954 break;
10955 }
10956 case NODE_CVASGN:{
10957 CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
10958 if (!popped) {
10959 ADD_INSN(ret, node, dup);
10960 }
10961 ADD_INSN2(ret, node, setclassvariable,
10962 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10963 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10964 break;
10965 }
10966 case NODE_OP_ASGN1:
10967 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10968 break;
10969 case NODE_OP_ASGN2:
10970 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10971 break;
10972 case NODE_OP_CDECL:
10973 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10974 break;
10975 case NODE_OP_ASGN_AND:
10976 case NODE_OP_ASGN_OR:
10977 CHECK(compile_op_log(iseq, ret, node, popped, type));
10978 break;
10979 case NODE_CALL: /* obj.foo */
10980 case NODE_OPCALL: /* foo[] */
10981 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10982 break;
10983 }
10984 case NODE_QCALL: /* obj&.foo */
10985 case NODE_FCALL: /* foo() */
10986 case NODE_VCALL: /* foo (variable or call) */
10987 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
10988 goto ng;
10989 }
10990 break;
10991 case NODE_SUPER:
10992 case NODE_ZSUPER:
10993 CHECK(compile_super(iseq, ret, node, popped, type));
10994 break;
10995 case NODE_LIST:{
10996 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10997 break;
10998 }
10999 case NODE_ZLIST:{
11000 if (!popped) {
11001 ADD_INSN1(ret, node, newarray, INT2FIX(0));
11002 }
11003 break;
11004 }
11005 case NODE_HASH:
11006 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11007 break;
11008 case NODE_RETURN:
11009 CHECK(compile_return(iseq, ret, node, popped));
11010 break;
11011 case NODE_YIELD:
11012 CHECK(compile_yield(iseq, ret, node, popped));
11013 break;
11014 case NODE_LVAR:{
11015 if (!popped) {
11016 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11017 }
11018 break;
11019 }
11020 case NODE_DVAR:{
11021 int lv, idx, ls;
11022 debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
11023 if (!popped) {
11024 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11025 if (idx < 0) {
11026 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
11027 rb_id2str(RNODE_DVAR(node)->nd_vid));
11028 goto ng;
11029 }
11030 ADD_GETLOCAL(ret, node, ls - idx, lv);
11031 }
11032 break;
11033 }
11034 case NODE_GVAR:{
11035 ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
11036 if (popped) {
11037 ADD_INSN(ret, node, pop);
11038 }
11039 break;
11040 }
11041 case NODE_IVAR:{
11042 debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
11043 if (!popped) {
11044 ADD_INSN2(ret, node, getinstancevariable,
11045 ID2SYM(RNODE_IVAR(node)->nd_vid),
11046 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11047 }
11048 break;
11049 }
11050 case NODE_CONST:{
11051 debugi("nd_vid", RNODE_CONST(node)->nd_vid);
11052
11053 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11054 body->ic_size++;
11055 VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
11056 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11057 RB_OBJ_WRITTEN(iseq, Qundef, segments);
11058 }
11059 else {
11060 ADD_INSN(ret, node, putnil);
11061 ADD_INSN1(ret, node, putobject, Qtrue);
11062 ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
11063 }
11064
11065 if (popped) {
11066 ADD_INSN(ret, node, pop);
11067 }
11068 break;
11069 }
11070 case NODE_CVAR:{
11071 if (!popped) {
11072 ADD_INSN2(ret, node, getclassvariable,
11073 ID2SYM(RNODE_CVAR(node)->nd_vid),
11074 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11075 }
11076 break;
11077 }
11078 case NODE_NTH_REF:{
11079 if (!popped) {
11080 if (!RNODE_NTH_REF(node)->nd_nth) {
11081 ADD_INSN(ret, node, putnil);
11082 break;
11083 }
11084 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11085 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11086 }
11087 break;
11088 }
11089 case NODE_BACK_REF:{
11090 if (!popped) {
11091 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
11092 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11093 }
11094 break;
11095 }
11096 case NODE_MATCH:
11097 case NODE_MATCH2:
11098 case NODE_MATCH3:
11099 CHECK(compile_match(iseq, ret, node, popped, type));
11100 break;
11101 case NODE_SYM:{
11102 if (!popped) {
11103 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11104 }
11105 break;
11106 }
11107 case NODE_LINE:{
11108 if (!popped) {
11109 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11110 }
11111 break;
11112 }
11113 case NODE_ENCODING:{
11114 if (!popped) {
11115 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11116 }
11117 break;
11118 }
11119 case NODE_INTEGER:{
11120 VALUE lit = rb_node_integer_literal_val(node);
11121 debugp_param("integer", lit);
11122 if (!popped) {
11123 ADD_INSN1(ret, node, putobject, lit);
11124 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11125 }
11126 break;
11127 }
11128 case NODE_FLOAT:{
11129 VALUE lit = rb_node_float_literal_val(node);
11130 debugp_param("float", lit);
11131 if (!popped) {
11132 ADD_INSN1(ret, node, putobject, lit);
11133 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11134 }
11135 break;
11136 }
11137 case NODE_RATIONAL:{
11138 VALUE lit = rb_node_rational_literal_val(node);
11139 debugp_param("rational", lit);
11140 if (!popped) {
11141 ADD_INSN1(ret, node, putobject, lit);
11142 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11143 }
11144 break;
11145 }
11146 case NODE_IMAGINARY:{
11147 VALUE lit = rb_node_imaginary_literal_val(node);
11148 debugp_param("imaginary", lit);
11149 if (!popped) {
11150 ADD_INSN1(ret, node, putobject, lit);
11151 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11152 }
11153 break;
11154 }
11155 case NODE_FILE:
11156 case NODE_STR:{
11157 debugp_param("nd_lit", get_string_value(node));
11158 if (!popped) {
11159 VALUE lit = get_string_value(node);
11160 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11161 if ((option->debug_frozen_string_literal || RTEST(ruby_debug)) &&
11162 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11163 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11164 }
11165 switch (option->frozen_string_literal) {
11166 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11167 ADD_INSN1(ret, node, putchilledstring, lit);
11168 break;
11169 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11170 ADD_INSN1(ret, node, putstring, lit);
11171 break;
11172 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11173 ADD_INSN1(ret, node, putobject, lit);
11174 break;
11175 default:
11176 rb_bug("invalid frozen_string_literal");
11177 }
11178 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11179 }
11180 break;
11181 }
11182 case NODE_DSTR:{
11183 compile_dstr(iseq, ret, node);
11184
11185 if (popped) {
11186 ADD_INSN(ret, node, pop);
11187 }
11188 break;
11189 }
11190 case NODE_XSTR:{
11191 ADD_CALL_RECEIVER(ret, node);
11192 VALUE str = rb_node_str_string_val(node);
11193 ADD_INSN1(ret, node, putobject, str);
11194 RB_OBJ_WRITTEN(iseq, Qundef, str);
11195 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11196
11197 if (popped) {
11198 ADD_INSN(ret, node, pop);
11199 }
11200 break;
11201 }
11202 case NODE_DXSTR:{
11203 ADD_CALL_RECEIVER(ret, node);
11204 compile_dstr(iseq, ret, node);
11205 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
11206
11207 if (popped) {
11208 ADD_INSN(ret, node, pop);
11209 }
11210 break;
11211 }
11212 case NODE_EVSTR:
11213 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11214 break;
11215 case NODE_REGX:{
11216 if (!popped) {
11217 VALUE lit = rb_node_regx_string_val(node);
11218 ADD_INSN1(ret, node, putobject, lit);
11219 RB_OBJ_WRITTEN(iseq, Qundef, lit);
11220 }
11221 break;
11222 }
11223 case NODE_DREGX:
11224 compile_dregx(iseq, ret, node, popped);
11225 break;
11226 case NODE_ONCE:{
11227 int ic_index = body->ise_size++;
11228 const rb_iseq_t *block_iseq;
11229 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11230
11231 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
11232 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
11233
11234 if (popped) {
11235 ADD_INSN(ret, node, pop);
11236 }
11237 break;
11238 }
11239 case NODE_ARGSCAT:{
11240 if (popped) {
11241 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11242 ADD_INSN1(ret, node, splatarray, Qfalse);
11243 ADD_INSN(ret, node, pop);
11244 CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
11245 ADD_INSN1(ret, node, splatarray, Qfalse);
11246 ADD_INSN(ret, node, pop);
11247 }
11248 else {
11249 CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
11250 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11251 if (nd_type_p(body_node, NODE_LIST)) {
11252 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11253 }
11254 else {
11255 CHECK(COMPILE(ret, "argscat body", body_node));
11256 ADD_INSN(ret, node, concattoarray);
11257 }
11258 }
11259 break;
11260 }
11261 case NODE_ARGSPUSH:{
11262 if (popped) {
11263 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11264 ADD_INSN1(ret, node, splatarray, Qfalse);
11265 ADD_INSN(ret, node, pop);
11266 CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11267 }
11268 else {
11269 CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
11270 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11271 if (keyword_node_p(body_node)) {
11272 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11273 ADD_INSN(ret, node, pushtoarraykwsplat);
11274 }
11275 else if (static_literal_node_p(body_node, iseq, false)) {
11276 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11277 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11278 }
11279 else {
11280 CHECK(COMPILE_(ret, "array element", body_node, FALSE));
11281 ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
11282 }
11283 }
11284 break;
11285 }
11286 case NODE_SPLAT:{
11287 CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
11288 ADD_INSN1(ret, node, splatarray, Qtrue);
11289
11290 if (popped) {
11291 ADD_INSN(ret, node, pop);
11292 }
11293 break;
11294 }
11295 case NODE_DEFN:{
11296 ID mid = RNODE_DEFN(node)->nd_mid;
11297 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11298 rb_id2str(mid),
11299 ISEQ_TYPE_METHOD, line);
11300
11301 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
11302 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
11303 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
11304
11305 if (!popped) {
11306 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11307 }
11308
11309 break;
11310 }
11311 case NODE_DEFS:{
11312 ID mid = RNODE_DEFS(node)->nd_mid;
11313 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11314 rb_id2str(mid),
11315 ISEQ_TYPE_METHOD, line);
11316
11317 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
11318 CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
11319 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
11320 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
11321
11322 if (!popped) {
11323 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
11324 }
11325 break;
11326 }
11327 case NODE_ALIAS:{
11328 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11329 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11330 CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
11331 CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
11332 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
11333
11334 if (popped) {
11335 ADD_INSN(ret, node, pop);
11336 }
11337 break;
11338 }
11339 case NODE_VALIAS:{
11340 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11341 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
11342 ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
11343 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
11344
11345 if (popped) {
11346 ADD_INSN(ret, node, pop);
11347 }
11348 break;
11349 }
11350 case NODE_UNDEF:{
11351 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11352
11353 for (long i = 0; i < ary->len; i++) {
11354 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11355 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11356 CHECK(COMPILE(ret, "undef arg", ary->data[i]));
11357 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
11358
11359 if (i < ary->len - 1) {
11360 ADD_INSN(ret, node, pop);
11361 }
11362 }
11363
11364 if (popped) {
11365 ADD_INSN(ret, node, pop);
11366 }
11367 break;
11368 }
11369 case NODE_CLASS:{
11370 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11371 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11372 ISEQ_TYPE_CLASS, line);
11373 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11374 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11375 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11376
11377 CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
11378 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
11379 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
11380
11381 if (popped) {
11382 ADD_INSN(ret, node, pop);
11383 }
11384 break;
11385 }
11386 case NODE_MODULE:{
11387 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11388 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11389 ISEQ_TYPE_CLASS, line);
11390 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11391 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11392
11393 ADD_INSN (ret, node, putnil); /* dummy */
11394 ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
11395 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
11396
11397 if (popped) {
11398 ADD_INSN(ret, node, pop);
11399 }
11400 break;
11401 }
11402 case NODE_SCLASS:{
11403 ID singletonclass;
11404 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
11405 ISEQ_TYPE_CLASS, line);
11406
11407 CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
11408 ADD_INSN (ret, node, putnil);
11409 CONST_ID(singletonclass, "singletonclass");
11410 ADD_INSN3(ret, node, defineclass,
11411 ID2SYM(singletonclass), singleton_class,
11412 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11413 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
11414
11415 if (popped) {
11416 ADD_INSN(ret, node, pop);
11417 }
11418 break;
11419 }
11420 case NODE_COLON2:
11421 CHECK(compile_colon2(iseq, ret, node, popped));
11422 break;
11423 case NODE_COLON3:
11424 CHECK(compile_colon3(iseq, ret, node, popped));
11425 break;
11426 case NODE_DOT2:
11427 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11428 break;
11429 case NODE_DOT3:
11430 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11431 break;
11432 case NODE_FLIP2:
11433 case NODE_FLIP3:{
11434 LABEL *lend = NEW_LABEL(line);
11435 LABEL *ltrue = NEW_LABEL(line);
11436 LABEL *lfalse = NEW_LABEL(line);
11437 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
11438 ltrue, lfalse));
11439 ADD_LABEL(ret, ltrue);
11440 ADD_INSN1(ret, node, putobject, Qtrue);
11441 ADD_INSNL(ret, node, jump, lend);
11442 ADD_LABEL(ret, lfalse);
11443 ADD_INSN1(ret, node, putobject, Qfalse);
11444 ADD_LABEL(ret, lend);
11445 break;
11446 }
11447 case NODE_SELF:{
11448 if (!popped) {
11449 ADD_INSN(ret, node, putself);
11450 }
11451 break;
11452 }
11453 case NODE_NIL:{
11454 if (!popped) {
11455 ADD_INSN(ret, node, putnil);
11456 }
11457 break;
11458 }
11459 case NODE_TRUE:{
11460 if (!popped) {
11461 ADD_INSN1(ret, node, putobject, Qtrue);
11462 }
11463 break;
11464 }
11465 case NODE_FALSE:{
11466 if (!popped) {
11467 ADD_INSN1(ret, node, putobject, Qfalse);
11468 }
11469 break;
11470 }
11471 case NODE_ERRINFO:
11472 CHECK(compile_errinfo(iseq, ret, node, popped));
11473 break;
11474 case NODE_DEFINED:
11475 if (!popped) {
11476 CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
11477 }
11478 break;
11479 case NODE_POSTEXE:{
11480 /* compiled to:
11481 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
11482 */
11483 int is_index = body->ise_size++;
11485 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11486 const rb_iseq_t *once_iseq =
11487 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11488
11489 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
11490 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
11491
11492 if (popped) {
11493 ADD_INSN(ret, node, pop);
11494 }
11495 break;
11496 }
11497 case NODE_KW_ARG:
11498 CHECK(compile_kw_arg(iseq, ret, node, popped));
11499 break;
11500 case NODE_DSYM:{
11501 compile_dstr(iseq, ret, node);
11502 if (!popped) {
11503 ADD_INSN(ret, node, intern);
11504 }
11505 else {
11506 ADD_INSN(ret, node, pop);
11507 }
11508 break;
11509 }
11510 case NODE_ATTRASGN:
11511 CHECK(compile_attrasgn(iseq, ret, node, popped));
11512 break;
11513 case NODE_LAMBDA:{
11514 /* compile same as lambda{...} */
11515 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11516 VALUE argc = INT2FIX(0);
11517
11518 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11519 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11520 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
11521
11522 if (popped) {
11523 ADD_INSN(ret, node, pop);
11524 }
11525 break;
11526 }
11527 default:
11528 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
11529 ng:
11530 debug_node_end();
11531 return COMPILE_NG;
11532 }
11533
11534 debug_node_end();
11535 return COMPILE_OK;
11536}
11537
11538/***************************/
11539/* instruction information */
11540/***************************/
11541
11542static int
11543insn_data_length(INSN *iobj)
11544{
11545 return insn_len(iobj->insn_id);
11546}
11547
11548static int
11549calc_sp_depth(int depth, INSN *insn)
11550{
11551 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11552}
11553
11554static VALUE
11555opobj_inspect(VALUE obj)
11556{
11557 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
11558 switch (BUILTIN_TYPE(obj)) {
11559 case T_STRING:
11560 obj = rb_str_new_cstr(RSTRING_PTR(obj));
11561 break;
11562 case T_ARRAY:
11563 obj = rb_ary_dup(obj);
11564 break;
11565 default:
11566 break;
11567 }
11568 }
11569 return rb_inspect(obj);
11570}
11571
11572
11573
11574static VALUE
11575insn_data_to_s_detail(INSN *iobj)
11576{
11577 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
11578
11579 if (iobj->operands) {
11580 const char *types = insn_op_types(iobj->insn_id);
11581 int j;
11582
11583 for (j = 0; types[j]; j++) {
11584 char type = types[j];
11585
11586 switch (type) {
11587 case TS_OFFSET: /* label(destination position) */
11588 {
11589 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11590 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11591 break;
11592 }
11593 break;
11594 case TS_ISEQ: /* iseq */
11595 {
11596 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11597 VALUE val = Qnil;
11598 if (0 && iseq) { /* TODO: invalidate now */
11599 val = (VALUE)iseq;
11600 }
11601 rb_str_concat(str, opobj_inspect(val));
11602 }
11603 break;
11604 case TS_LINDEX:
11605 case TS_NUM: /* ulong */
11606 case TS_VALUE: /* VALUE */
11607 {
11608 VALUE v = OPERAND_AT(iobj, j);
11609 if (!CLASS_OF(v))
11610 rb_str_cat2(str, "<hidden>");
11611 else {
11612 rb_str_concat(str, opobj_inspect(v));
11613 }
11614 break;
11615 }
11616 case TS_ID: /* ID */
11617 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11618 break;
11619 case TS_IC: /* inline cache */
11620 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
11621 break;
11622 case TS_IVC: /* inline ivar cache */
11623 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11624 break;
11625 case TS_ICVARC: /* inline cvar cache */
11626 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11627 break;
11628 case TS_ISE: /* inline storage entry */
11629 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
11630 break;
11631 case TS_CALLDATA: /* we store these as call infos at compile time */
11632 {
11633 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
11634 rb_str_cat2(str, "<calldata:");
11635 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11636 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
11637 break;
11638 }
11639 case TS_CDHASH: /* case/when condition cache */
11640 rb_str_cat2(str, "<ch>");
11641 break;
11642 case TS_FUNCPTR:
11643 {
11644 void *func = (void *)OPERAND_AT(iobj, j);
11645#ifdef HAVE_DLADDR
11646 Dl_info info;
11647 if (dladdr(func, &info) && info.dli_sname) {
11648 rb_str_cat2(str, info.dli_sname);
11649 break;
11650 }
11651#endif
11652 rb_str_catf(str, "<%p>", func);
11653 }
11654 break;
11655 case TS_BUILTIN:
11656 rb_str_cat2(str, "<TS_BUILTIN>");
11657 break;
11658 default:{
11659 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
11660 }
11661 }
11662 if (types[j + 1]) {
11663 rb_str_cat2(str, ", ");
11664 }
11665 }
11666 }
11667 return str;
11668}
11669
11670static void
11671dump_disasm_list(const LINK_ELEMENT *link)
11672{
11673 dump_disasm_list_with_cursor(link, NULL, NULL);
11674}
11675
11676static void
11677dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
11678{
11679 int pos = 0;
11680 INSN *iobj;
11681 LABEL *lobj;
11682 VALUE str;
11683
11684 printf("-- raw disasm--------\n");
11685
11686 while (link) {
11687 if (curr) printf(curr == link ? "*" : " ");
11688 switch (link->type) {
11689 case ISEQ_ELEMENT_INSN:
11690 {
11691 iobj = (INSN *)link;
11692 str = insn_data_to_s_detail(iobj);
11693 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
11694 pos += insn_data_length(iobj);
11695 break;
11696 }
11697 case ISEQ_ELEMENT_LABEL:
11698 {
11699 lobj = (LABEL *)link;
11700 printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11701 dest == lobj ? " <---" : "");
11702 break;
11703 }
11704 case ISEQ_ELEMENT_TRACE:
11705 {
11706 TRACE *trace = (TRACE *)link;
11707 printf(" trace: %0x\n", trace->event);
11708 break;
11709 }
11710 case ISEQ_ELEMENT_ADJUST:
11711 {
11712 ADJUST *adjust = (ADJUST *)link;
11713 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11714 break;
11715 }
11716 default:
11717 /* ignore */
11718 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
11719 }
11720 link = link->next;
11721 }
11722 printf("---------------------\n");
11723 fflush(stdout);
11724}
11725
11726int
11727rb_insn_len(VALUE insn)
11728{
11729 return insn_len(insn);
11730}
11731
11732const char *
11733rb_insns_name(int i)
11734{
11735 return insn_name(i);
11736}
11737
11738VALUE
11739rb_insns_name_array(void)
11740{
11741 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11742 int i;
11743 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11744 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11745 }
11746 return rb_ary_freeze(ary);
11747}
11748
11749static LABEL *
11750register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
11751{
11752 LABEL *label = 0;
11753 st_data_t tmp;
11754 obj = rb_to_symbol_type(obj);
11755
11756 if (st_lookup(labels_table, obj, &tmp) == 0) {
11757 label = NEW_LABEL(0);
11758 st_insert(labels_table, obj, (st_data_t)label);
11759 }
11760 else {
11761 label = (LABEL *)tmp;
11762 }
11763 LABEL_REF(label);
11764 return label;
11765}
11766
11767static VALUE
11768get_exception_sym2type(VALUE sym)
11769{
11770 static VALUE symRescue, symEnsure, symRetry;
11771 static VALUE symBreak, symRedo, symNext;
11772
11773 if (symRescue == 0) {
11774 symRescue = ID2SYM(rb_intern_const("rescue"));
11775 symEnsure = ID2SYM(rb_intern_const("ensure"));
11776 symRetry = ID2SYM(rb_intern_const("retry"));
11777 symBreak = ID2SYM(rb_intern_const("break"));
11778 symRedo = ID2SYM(rb_intern_const("redo"));
11779 symNext = ID2SYM(rb_intern_const("next"));
11780 }
11781
11782 if (sym == symRescue) return CATCH_TYPE_RESCUE;
11783 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
11784 if (sym == symRetry) return CATCH_TYPE_RETRY;
11785 if (sym == symBreak) return CATCH_TYPE_BREAK;
11786 if (sym == symRedo) return CATCH_TYPE_REDO;
11787 if (sym == symNext) return CATCH_TYPE_NEXT;
11788 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
11789 return 0;
11790}
11791
11792static int
11793iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
11794 VALUE exception)
11795{
11796 int i;
11797
11798 for (i=0; i<RARRAY_LEN(exception); i++) {
11799 const rb_iseq_t *eiseq;
11800 VALUE v, type;
11801 LABEL *lstart, *lend, *lcont;
11802 unsigned int sp;
11803
11804 v = rb_to_array_type(RARRAY_AREF(exception, i));
11805 if (RARRAY_LEN(v) != 6) {
11806 rb_raise(rb_eSyntaxError, "wrong exception entry");
11807 }
11808 type = get_exception_sym2type(RARRAY_AREF(v, 0));
11809 if (NIL_P(RARRAY_AREF(v, 1))) {
11810 eiseq = NULL;
11811 }
11812 else {
11813 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
11814 }
11815
11816 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
11817 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
11818 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
11819 sp = NUM2UINT(RARRAY_AREF(v, 5));
11820
11821 /* TODO: Dirty Hack! Fix me */
11822 if (type == CATCH_TYPE_RESCUE ||
11823 type == CATCH_TYPE_BREAK ||
11824 type == CATCH_TYPE_NEXT) {
11825 ++sp;
11826 }
11827
11828 lcont->sp = sp;
11829
11830 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
11831
11832 RB_GC_GUARD(v);
11833 }
11834 return COMPILE_OK;
11835}
11836
11837static struct st_table *
11838insn_make_insn_table(void)
11839{
11840 struct st_table *table;
11841 int i;
11842 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11843
11844 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11845 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
11846 }
11847
11848 return table;
11849}
11850
11851static const rb_iseq_t *
11852iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
11853{
11854 VALUE iseqw;
11855 const rb_iseq_t *loaded_iseq;
11856
11857 if (RB_TYPE_P(op, T_ARRAY)) {
11858 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
11859 }
11860 else if (CLASS_OF(op) == rb_cISeq) {
11861 iseqw = op;
11862 }
11863 else {
11864 rb_raise(rb_eSyntaxError, "ISEQ is required");
11865 }
11866
11867 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11868 return loaded_iseq;
11869}
11870
11871static VALUE
11872iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
11873{
11874 ID mid = 0;
11875 int orig_argc = 0;
11876 unsigned int flag = 0;
11877 struct rb_callinfo_kwarg *kw_arg = 0;
11878
11879 if (!NIL_P(op)) {
11880 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
11881 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
11882 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
11883 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
11884
11885 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
11886 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
11887 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
11888
11889 if (!NIL_P(vkw_arg)) {
11890 int i;
11891 int len = RARRAY_LENINT(vkw_arg);
11892 size_t n = rb_callinfo_kwarg_bytes(len);
11893
11894 kw_arg = xmalloc(n);
11895 kw_arg->references = 0;
11896 kw_arg->keyword_len = len;
11897 for (i = 0; i < len; i++) {
11898 VALUE kw = RARRAY_AREF(vkw_arg, i);
11899 SYM2ID(kw); /* make immortal */
11900 kw_arg->keywords[i] = kw;
11901 }
11902 }
11903 }
11904
11905 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11906 RB_OBJ_WRITTEN(iseq, Qundef, ci);
11907 return (VALUE)ci;
11908}
11909
11910static rb_event_flag_t
11911event_name_to_flag(VALUE sym)
11912{
11913#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11914 CHECK_EVENT(RUBY_EVENT_LINE);
11915 CHECK_EVENT(RUBY_EVENT_CLASS);
11916 CHECK_EVENT(RUBY_EVENT_END);
11917 CHECK_EVENT(RUBY_EVENT_CALL);
11918 CHECK_EVENT(RUBY_EVENT_RETURN);
11919 CHECK_EVENT(RUBY_EVENT_B_CALL);
11920 CHECK_EVENT(RUBY_EVENT_B_RETURN);
11921 CHECK_EVENT(RUBY_EVENT_RESCUE);
11922#undef CHECK_EVENT
11923 return RUBY_EVENT_NONE;
11924}
11925
11926static int
11927iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
11928 VALUE body, VALUE node_ids, VALUE labels_wrapper)
11929{
11930 /* TODO: body should be frozen */
11931 long i, len = RARRAY_LEN(body);
11932 struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
11933 int j;
11934 int line_no = 0, node_id = -1, insn_idx = 0;
11935 int ret = COMPILE_OK;
11936
11937 /*
11938 * index -> LABEL *label
11939 */
11940 static struct st_table *insn_table;
11941
11942 if (insn_table == 0) {
11943 insn_table = insn_make_insn_table();
11944 }
11945
11946 for (i=0; i<len; i++) {
11947 VALUE obj = RARRAY_AREF(body, i);
11948
11949 if (SYMBOL_P(obj)) {
11950 rb_event_flag_t event;
11951 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
11952 ADD_TRACE(anchor, event);
11953 }
11954 else {
11955 LABEL *label = register_label(iseq, labels_table, obj);
11956 ADD_LABEL(anchor, label);
11957 }
11958 }
11959 else if (FIXNUM_P(obj)) {
11960 line_no = NUM2INT(obj);
11961 }
11962 else if (RB_TYPE_P(obj, T_ARRAY)) {
11963 VALUE *argv = 0;
11964 int argc = RARRAY_LENINT(obj) - 1;
11965 st_data_t insn_id;
11966 VALUE insn;
11967
11968 if (node_ids) {
11969 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11970 }
11971
11972 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
11973 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11974 /* TODO: exception */
11975 COMPILE_ERROR(iseq, line_no,
11976 "unknown instruction: %+"PRIsVALUE, insn);
11977 ret = COMPILE_NG;
11978 break;
11979 }
11980
11981 if (argc != insn_len((VALUE)insn_id)-1) {
11982 COMPILE_ERROR(iseq, line_no,
11983 "operand size mismatch");
11984 ret = COMPILE_NG;
11985 break;
11986 }
11987
11988 if (argc > 0) {
11989 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
11990
11991 // add element before operand setup to make GC root
11992 ADD_ELEM(anchor,
11993 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11994 (enum ruby_vminsn_type)insn_id, argc, argv));
11995
11996 for (j=0; j<argc; j++) {
11997 VALUE op = rb_ary_entry(obj, j+1);
11998 switch (insn_op_type((VALUE)insn_id, j)) {
11999 case TS_OFFSET: {
12000 LABEL *label = register_label(iseq, labels_table, op);
12001 argv[j] = (VALUE)label;
12002 break;
12003 }
12004 case TS_LINDEX:
12005 case TS_NUM:
12006 (void)NUM2INT(op);
12007 argv[j] = op;
12008 break;
12009 case TS_VALUE:
12010 argv[j] = op;
12011 RB_OBJ_WRITTEN(iseq, Qundef, op);
12012 break;
12013 case TS_ISEQ:
12014 {
12015 if (op != Qnil) {
12016 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
12017 argv[j] = v;
12018 RB_OBJ_WRITTEN(iseq, Qundef, v);
12019 }
12020 else {
12021 argv[j] = 0;
12022 }
12023 }
12024 break;
12025 case TS_ISE:
12026 argv[j] = op;
12027 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12028 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
12029 }
12030 break;
12031 case TS_IC:
12032 {
12033 VALUE segments = rb_ary_new();
12034 op = rb_to_array_type(op);
12035
12036 for (int i = 0; i < RARRAY_LEN(op); i++) {
12037 VALUE sym = RARRAY_AREF(op, i);
12038 sym = rb_to_symbol_type(sym);
12039 rb_ary_push(segments, sym);
12040 }
12041
12042 RB_GC_GUARD(op);
12043 argv[j] = segments;
12044 RB_OBJ_WRITTEN(iseq, Qundef, segments);
12045 ISEQ_BODY(iseq)->ic_size++;
12046 }
12047 break;
12048 case TS_IVC: /* inline ivar cache */
12049 argv[j] = op;
12050 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12051 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
12052 }
12053 break;
12054 case TS_ICVARC: /* inline cvar cache */
12055 argv[j] = op;
12056 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12057 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
12058 }
12059 break;
12060 case TS_CALLDATA:
12061 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12062 break;
12063 case TS_ID:
12064 argv[j] = rb_to_symbol_type(op);
12065 break;
12066 case TS_CDHASH:
12067 {
12068 int i;
12069 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12070
12071 RHASH_TBL_RAW(map)->type = &cdhash_type;
12072 op = rb_to_array_type(op);
12073 for (i=0; i<RARRAY_LEN(op); i+=2) {
12074 VALUE key = RARRAY_AREF(op, i);
12075 VALUE sym = RARRAY_AREF(op, i+1);
12076 LABEL *label =
12077 register_label(iseq, labels_table, sym);
12078 rb_hash_aset(map, key, (VALUE)label | 1);
12079 }
12080 RB_GC_GUARD(op);
12081 argv[j] = map;
12082 RB_OBJ_WRITTEN(iseq, Qundef, map);
12083 }
12084 break;
12085 case TS_FUNCPTR:
12086 {
12087#if SIZEOF_VALUE <= SIZEOF_LONG
12088 long funcptr = NUM2LONG(op);
12089#else
12090 LONG_LONG funcptr = NUM2LL(op);
12091#endif
12092 argv[j] = (VALUE)funcptr;
12093 }
12094 break;
12095 default:
12096 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
12097 }
12098 }
12099 }
12100 else {
12101 ADD_ELEM(anchor,
12102 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12103 (enum ruby_vminsn_type)insn_id, argc, NULL));
12104 }
12105 }
12106 else {
12107 rb_raise(rb_eTypeError, "unexpected object for instruction");
12108 }
12109 }
12110 RTYPEDDATA_DATA(labels_wrapper) = 0;
12111 RB_GC_GUARD(labels_wrapper);
12112 validate_labels(iseq, labels_table);
12113 if (!ret) return ret;
12114 return iseq_setup(iseq, anchor);
12115}
12116
12117#define CHECK_ARRAY(v) rb_to_array_type(v)
12118#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12119
12120static int
12121int_param(int *dst, VALUE param, VALUE sym)
12122{
12123 VALUE val = rb_hash_aref(param, sym);
12124 if (FIXNUM_P(val)) {
12125 *dst = FIX2INT(val);
12126 return TRUE;
12127 }
12128 else if (!NIL_P(val)) {
12129 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
12130 sym, val);
12131 }
12132 return FALSE;
12133}
12134
12135static const struct rb_iseq_param_keyword *
12136iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
12137{
12138 int i, j;
12139 int len = RARRAY_LENINT(keywords);
12140 int default_len;
12141 VALUE key, sym, default_val;
12142 VALUE *dvs;
12143 ID *ids;
12144 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
12145
12146 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12147
12148 keyword->num = len;
12149#define SYM(s) ID2SYM(rb_intern_const(#s))
12150 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12151 i = keyword->bits_start - keyword->num;
12152 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
12153#undef SYM
12154
12155 /* required args */
12156 for (i = 0; i < len; i++) {
12157 VALUE val = RARRAY_AREF(keywords, i);
12158
12159 if (!SYMBOL_P(val)) {
12160 goto default_values;
12161 }
12162 ids[i] = SYM2ID(val);
12163 keyword->required_num++;
12164 }
12165
12166 default_values: /* note: we intentionally preserve `i' from previous loop */
12167 default_len = len - i;
12168 if (default_len == 0) {
12169 keyword->table = ids;
12170 return keyword;
12171 }
12172 else if (default_len < 0) {
12174 }
12175
12176 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
12177
12178 for (j = 0; i < len; i++, j++) {
12179 key = RARRAY_AREF(keywords, i);
12180 CHECK_ARRAY(key);
12181
12182 switch (RARRAY_LEN(key)) {
12183 case 1:
12184 sym = RARRAY_AREF(key, 0);
12185 default_val = Qundef;
12186 break;
12187 case 2:
12188 sym = RARRAY_AREF(key, 0);
12189 default_val = RARRAY_AREF(key, 1);
12190 break;
12191 default:
12192 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
12193 }
12194 ids[i] = SYM2ID(sym);
12195 RB_OBJ_WRITE(iseq, &dvs[j], default_val);
12196 }
12197
12198 keyword->table = ids;
12199 keyword->default_values = dvs;
12200
12201 return keyword;
12202}
12203
12204static void
12205iseq_insn_each_object_mark_and_move(VALUE * obj, VALUE _)
12206{
12207 rb_gc_mark_and_move(obj);
12208}
12209
12210void
12211rb_iseq_mark_and_move_insn_storage(struct iseq_compile_data_storage *storage)
12212{
12213 INSN *iobj = 0;
12214 size_t size = sizeof(INSN);
12215 unsigned int pos = 0;
12216
12217 while (storage) {
12218#ifdef STRICT_ALIGNMENT
12219 size_t padding = calc_padding((void *)&storage->buff[pos], size);
12220#else
12221 const size_t padding = 0; /* expected to be optimized by compiler */
12222#endif /* STRICT_ALIGNMENT */
12223 size_t offset = pos + size + padding;
12224 if (offset > storage->size || offset > storage->pos) {
12225 pos = 0;
12226 storage = storage->next;
12227 }
12228 else {
12229#ifdef STRICT_ALIGNMENT
12230 pos += (int)padding;
12231#endif /* STRICT_ALIGNMENT */
12232
12233 iobj = (INSN *)&storage->buff[pos];
12234
12235 if (iobj->operands) {
12236 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (VALUE)0);
12237 }
12238 pos += (int)size;
12239 }
12240 }
12241}
12242
12243static const rb_data_type_t labels_wrapper_type = {
12244 .wrap_struct_name = "compiler/labels_wrapper",
12245 .function = {
12246 .dmark = (RUBY_DATA_FUNC)rb_mark_set,
12247 .dfree = (RUBY_DATA_FUNC)st_free_table,
12248 },
12249 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12250};
12251
12252void
12253rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
12254 VALUE exception, VALUE body)
12255{
12256#define SYM(s) ID2SYM(rb_intern_const(#s))
12257 int i, len;
12258 unsigned int arg_size, local_size, stack_max;
12259 ID *tbl;
12260 struct st_table *labels_table = st_init_numtable();
12261 VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
12262 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12263 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12264 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
12265 DECL_ANCHOR(anchor);
12266 INIT_ANCHOR(anchor);
12267
12268 len = RARRAY_LENINT(locals);
12269 ISEQ_BODY(iseq)->local_table_size = len;
12270 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12271
12272 for (i = 0; i < len; i++) {
12273 VALUE lv = RARRAY_AREF(locals, i);
12274
12275 if (sym_arg_rest == lv) {
12276 tbl[i] = 0;
12277 }
12278 else {
12279 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
12280 }
12281 }
12282
12283#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12284 if (INT_PARAM(lead_num)) {
12285 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12286 }
12287 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12288 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12289 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12290 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12291#undef INT_PARAM
12292 {
12293#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12294 int x;
12295 INT_PARAM(arg_size);
12296 INT_PARAM(local_size);
12297 INT_PARAM(stack_max);
12298#undef INT_PARAM
12299 }
12300
12301 VALUE node_ids = Qfalse;
12302#ifdef USE_ISEQ_NODE_ID
12303 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
12304 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
12305 rb_raise(rb_eTypeError, "node_ids is not an array");
12306 }
12307#endif
12308
12309 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
12310 len = RARRAY_LENINT(arg_opt_labels);
12311 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
12312
12313 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12314 VALUE *opt_table = ALLOC_N(VALUE, len);
12315
12316 for (i = 0; i < len; i++) {
12317 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
12318 LABEL *label = register_label(iseq, labels_table, ent);
12319 opt_table[i] = (VALUE)label;
12320 }
12321
12322 ISEQ_BODY(iseq)->param.opt_num = len - 1;
12323 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12324 }
12325 }
12326 else if (!NIL_P(arg_opt_labels)) {
12327 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
12328 arg_opt_labels);
12329 }
12330
12331 if (RB_TYPE_P(keywords, T_ARRAY)) {
12332 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12333 }
12334 else if (!NIL_P(keywords)) {
12335 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
12336 keywords);
12337 }
12338
12339 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12340 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12341 }
12342
12343 if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
12344 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12345 }
12346
12347 if (int_param(&i, params, SYM(kwrest))) {
12348 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12349 if (keyword == NULL) {
12350 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
12351 }
12352 keyword->rest_start = i;
12353 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12354 }
12355#undef SYM
12356 iseq_calc_param_size(iseq);
12357
12358 /* exception */
12359 iseq_build_from_ary_exception(iseq, labels_table, exception);
12360
12361 /* body */
12362 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12363
12364 ISEQ_BODY(iseq)->param.size = arg_size;
12365 ISEQ_BODY(iseq)->local_table_size = local_size;
12366 ISEQ_BODY(iseq)->stack_max = stack_max;
12367}
12368
12369/* for parser */
12370
12371int
12372rb_dvar_defined(ID id, const rb_iseq_t *iseq)
12373{
12374 if (iseq) {
12375 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12376 while (body->type == ISEQ_TYPE_BLOCK ||
12377 body->type == ISEQ_TYPE_RESCUE ||
12378 body->type == ISEQ_TYPE_ENSURE ||
12379 body->type == ISEQ_TYPE_EVAL ||
12380 body->type == ISEQ_TYPE_MAIN
12381 ) {
12382 unsigned int i;
12383
12384 for (i = 0; i < body->local_table_size; i++) {
12385 if (body->local_table[i] == id) {
12386 return 1;
12387 }
12388 }
12389 iseq = body->parent_iseq;
12390 body = ISEQ_BODY(iseq);
12391 }
12392 }
12393 return 0;
12394}
12395
12396int
12397rb_local_defined(ID id, const rb_iseq_t *iseq)
12398{
12399 if (iseq) {
12400 unsigned int i;
12401 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
12402
12403 for (i=0; i<body->local_table_size; i++) {
12404 if (body->local_table[i] == id) {
12405 return 1;
12406 }
12407 }
12408 }
12409 return 0;
12410}
12411
12412/* ISeq binary format */
12413
12414#ifndef IBF_ISEQ_DEBUG
12415#define IBF_ISEQ_DEBUG 0
12416#endif
12417
12418#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12419#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12420#endif
12421
12422typedef uint32_t ibf_offset_t;
12423#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12424
12425#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12426#ifdef RUBY_DEVEL
12427#define IBF_DEVEL_VERSION 4
12428#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12429#else
12430#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12431#endif
12432
12433static const char IBF_ENDIAN_MARK =
12434#ifdef WORDS_BIGENDIAN
12435 'b'
12436#else
12437 'l'
12438#endif
12439 ;
12440
12442 char magic[4]; /* YARB */
12443 uint32_t major_version;
12444 uint32_t minor_version;
12445 uint32_t size;
12446 uint32_t extra_size;
12447
12448 uint32_t iseq_list_size;
12449 uint32_t global_object_list_size;
12450 ibf_offset_t iseq_list_offset;
12451 ibf_offset_t global_object_list_offset;
12452 uint8_t endian;
12453 uint8_t wordsize; /* assume no 2048-bit CPU */
12454};
12455
12457 VALUE str;
12458 st_table *obj_table; /* obj -> obj number */
12459};
12460
12461struct ibf_dump {
12462 st_table *iseq_table; /* iseq -> iseq number */
12463 struct ibf_dump_buffer global_buffer;
12464 struct ibf_dump_buffer *current_buffer;
12465};
12466
12468 const char *buff;
12469 ibf_offset_t size;
12470
12471 VALUE obj_list; /* [obj0, ...] */
12472 unsigned int obj_list_size;
12473 ibf_offset_t obj_list_offset;
12474};
12475
12476struct ibf_load {
12477 const struct ibf_header *header;
12478 VALUE iseq_list; /* [iseq0, ...] */
12479 struct ibf_load_buffer global_buffer;
12480 VALUE loader_obj;
12481 rb_iseq_t *iseq;
12482 VALUE str;
12483 struct ibf_load_buffer *current_buffer;
12484};
12485
12487 long size;
12488 VALUE buffer[1];
12489};
12490
12491static void
12492pinned_list_mark(void *ptr)
12493{
12494 long i;
12495 struct pinned_list *list = (struct pinned_list *)ptr;
12496 for (i = 0; i < list->size; i++) {
12497 if (list->buffer[i]) {
12498 rb_gc_mark(list->buffer[i]);
12499 }
12500 }
12501}
12502
12503static const rb_data_type_t pinned_list_type = {
12504 "pinned_list",
12505 {
12506 pinned_list_mark,
12508 NULL, // No external memory to report,
12509 },
12510 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12511};
12512
12513static VALUE
12514pinned_list_fetch(VALUE list, long offset)
12515{
12516 struct pinned_list * ptr;
12517
12518 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12519
12520 if (offset >= ptr->size) {
12521 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12522 }
12523
12524 return ptr->buffer[offset];
12525}
12526
12527static void
12528pinned_list_store(VALUE list, long offset, VALUE object)
12529{
12530 struct pinned_list * ptr;
12531
12532 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
12533
12534 if (offset >= ptr->size) {
12535 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
12536 }
12537
12538 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
12539}
12540
12541static VALUE
12542pinned_list_new(long size)
12543{
12544 size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
12545 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12546 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12547 ptr->size = size;
12548 return obj_list;
12549}
12550
12551static ibf_offset_t
12552ibf_dump_pos(struct ibf_dump *dump)
12553{
12554 long pos = RSTRING_LEN(dump->current_buffer->str);
12555#if SIZEOF_LONG > SIZEOF_INT
12556 if (pos >= UINT_MAX) {
12557 rb_raise(rb_eRuntimeError, "dump size exceeds");
12558 }
12559#endif
12560 return (unsigned int)pos;
12561}
12562
12563static void
12564ibf_dump_align(struct ibf_dump *dump, size_t align)
12565{
12566 ibf_offset_t pos = ibf_dump_pos(dump);
12567 if (pos % align) {
12568 static const char padding[sizeof(VALUE)];
12569 size_t size = align - ((size_t)pos % align);
12570#if SIZEOF_LONG > SIZEOF_INT
12571 if (pos + size >= UINT_MAX) {
12572 rb_raise(rb_eRuntimeError, "dump size exceeds");
12573 }
12574#endif
12575 for (; size > sizeof(padding); size -= sizeof(padding)) {
12576 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
12577 }
12578 rb_str_cat(dump->current_buffer->str, padding, size);
12579 }
12580}
12581
12582static ibf_offset_t
12583ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
12584{
12585 ibf_offset_t pos = ibf_dump_pos(dump);
12586#if SIZEOF_LONG > SIZEOF_INT
12587 /* ensure the resulting dump does not exceed UINT_MAX */
12588 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12589 rb_raise(rb_eRuntimeError, "dump size exceeds");
12590 }
12591#endif
12592 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
12593 return pos;
12594}
12595
12596static ibf_offset_t
12597ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
12598{
12599 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
12600}
12601
12602static void
12603ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
12604{
12605 VALUE str = dump->current_buffer->str;
12606 char *ptr = RSTRING_PTR(str);
12607 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
12608 rb_bug("ibf_dump_overwrite: overflow");
12609 memcpy(ptr + offset, buff, size);
12610}
12611
12612static const void *
12613ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
12614{
12615 ibf_offset_t beg = *offset;
12616 *offset += size;
12617 return load->current_buffer->buff + beg;
12618}
12619
12620static void *
12621ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
12622{
12623 void *buff = ruby_xmalloc2(x, y);
12624 size_t size = x * y;
12625 memcpy(buff, load->current_buffer->buff + offset, size);
12626 return buff;
12627}
12628
12629#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12630
12631#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12632#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12633#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12634#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12635#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12636
12637static int
12638ibf_table_lookup(struct st_table *table, st_data_t key)
12639{
12640 st_data_t val;
12641
12642 if (st_lookup(table, key, &val)) {
12643 return (int)val;
12644 }
12645 else {
12646 return -1;
12647 }
12648}
12649
12650static int
12651ibf_table_find_or_insert(struct st_table *table, st_data_t key)
12652{
12653 int index = ibf_table_lookup(table, key);
12654
12655 if (index < 0) { /* not found */
12656 index = (int)table->num_entries;
12657 st_insert(table, key, (st_data_t)index);
12658 }
12659
12660 return index;
12661}
12662
12663/* dump/load generic */
12664
12665static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
12666
12667static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
12668static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
12669
12670static st_table *
12671ibf_dump_object_table_new(void)
12672{
12673 st_table *obj_table = st_init_numtable(); /* need free */
12674 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
12675
12676 return obj_table;
12677}
12678
12679static VALUE
12680ibf_dump_object(struct ibf_dump *dump, VALUE obj)
12681{
12682 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12683}
12684
12685static VALUE
12686ibf_dump_id(struct ibf_dump *dump, ID id)
12687{
12688 if (id == 0 || rb_id2name(id) == NULL) {
12689 return 0;
12690 }
12691 return ibf_dump_object(dump, rb_id2sym(id));
12692}
12693
12694static ID
12695ibf_load_id(const struct ibf_load *load, const ID id_index)
12696{
12697 if (id_index == 0) {
12698 return 0;
12699 }
12700 VALUE sym = ibf_load_object(load, id_index);
12701 if (rb_integer_type_p(sym)) {
12702 /* Load hidden local variables as indexes */
12703 return NUM2ULONG(sym);
12704 }
12705 return rb_sym2id(sym);
12706}
12707
12708/* dump/load: code */
12709
12710static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
12711
12712static int
12713ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
12714{
12715 if (iseq == NULL) {
12716 return -1;
12717 }
12718 else {
12719 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12720 }
12721}
12722
12723static unsigned char
12724ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
12725{
12726 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
12727 return (unsigned char)load->current_buffer->buff[(*offset)++];
12728}
12729
12730/*
12731 * Small uint serialization
12732 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12733 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12734 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12735 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12736 * ...
12737 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12738 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12739 */
12740static void
12741ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
12742{
12743 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12744 ibf_dump_write(dump, &x, sizeof(VALUE));
12745 return;
12746 }
12747
12748 enum { max_byte_length = sizeof(VALUE) + 1 };
12749
12750 unsigned char bytes[max_byte_length];
12751 ibf_offset_t n;
12752
12753 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12754 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12755 }
12756
12757 x <<= 1;
12758 x |= 1;
12759 x <<= n;
12760 bytes[max_byte_length - 1 - n] = (unsigned char)x;
12761 n++;
12762
12763 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12764}
12765
12766static VALUE
12767ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
12768{
12769 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
12770 union { char s[sizeof(VALUE)]; VALUE v; } x;
12771
12772 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
12773 *offset += sizeof(VALUE);
12774
12775 return x.v;
12776 }
12777
12778 enum { max_byte_length = sizeof(VALUE) + 1 };
12779
12780 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
12781 const unsigned char c = buffer[*offset];
12782
12783 ibf_offset_t n =
12784 c & 1 ? 1 :
12785 c == 0 ? 9 : ntz_int32(c) + 1;
12786 VALUE x = (VALUE)c >> n;
12787
12788 if (*offset + n > load->current_buffer->size) {
12789 rb_raise(rb_eRuntimeError, "invalid byte sequence");
12790 }
12791
12792 ibf_offset_t i;
12793 for (i = 1; i < n; i++) {
12794 x <<= 8;
12795 x |= (VALUE)buffer[*offset + i];
12796 }
12797
12798 *offset += n;
12799 return x;
12800}
12801
12802static void
12803ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
12804{
12805 // short: index
12806 // short: name.length
12807 // bytes: name
12808 // // omit argc (only verify with name)
12809 ibf_dump_write_small_value(dump, (VALUE)bf->index);
12810
12811 size_t len = strlen(bf->name);
12812 ibf_dump_write_small_value(dump, (VALUE)len);
12813 ibf_dump_write(dump, bf->name, len);
12814}
12815
12816static const struct rb_builtin_function *
12817ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
12818{
12819 int i = (int)ibf_load_small_value(load, offset);
12820 int len = (int)ibf_load_small_value(load, offset);
12821 const char *name = (char *)ibf_load_ptr(load, offset, len);
12822
12823 if (0) {
12824 fprintf(stderr, "%.*s!!\n", len, name);
12825 }
12826
12827 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
12828 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
12829 if (strncmp(table[i].name, name, len) != 0) {
12830 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12831 }
12832 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12833
12834 return &table[i];
12835}
12836
12837static ibf_offset_t
12838ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
12839{
12840 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
12841 const int iseq_size = body->iseq_size;
12842 int code_index;
12843 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12844
12845 ibf_offset_t offset = ibf_dump_pos(dump);
12846
12847 for (code_index=0; code_index<iseq_size;) {
12848 const VALUE insn = orig_code[code_index++];
12849 const char *types = insn_op_types(insn);
12850 int op_index;
12851
12852 /* opcode */
12853 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
12854 ibf_dump_write_small_value(dump, insn);
12855
12856 /* operands */
12857 for (op_index=0; types[op_index]; op_index++, code_index++) {
12858 VALUE op = orig_code[code_index];
12859 VALUE wv;
12860
12861 switch (types[op_index]) {
12862 case TS_CDHASH:
12863 case TS_VALUE:
12864 wv = ibf_dump_object(dump, op);
12865 break;
12866 case TS_ISEQ:
12867 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
12868 break;
12869 case TS_IC:
12870 {
12871 IC ic = (IC)op;
12872 VALUE arr = idlist_to_array(ic->segments);
12873 wv = ibf_dump_object(dump, arr);
12874 }
12875 break;
12876 case TS_ISE:
12877 case TS_IVC:
12878 case TS_ICVARC:
12879 {
12881 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12882 }
12883 break;
12884 case TS_CALLDATA:
12885 {
12886 goto skip_wv;
12887 }
12888 case TS_ID:
12889 wv = ibf_dump_id(dump, (ID)op);
12890 break;
12891 case TS_FUNCPTR:
12892 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
12893 goto skip_wv;
12894 case TS_BUILTIN:
12895 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
12896 goto skip_wv;
12897 default:
12898 wv = op;
12899 break;
12900 }
12901 ibf_dump_write_small_value(dump, wv);
12902 skip_wv:;
12903 }
12904 RUBY_ASSERT(insn_len(insn) == op_index+1);
12905 }
12906
12907 return offset;
12908}
12909
12910static VALUE *
12911ibf_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)
12912{
12913 VALUE iseqv = (VALUE)iseq;
12914 unsigned int code_index;
12915 ibf_offset_t reading_pos = bytecode_offset;
12916 VALUE *code = ALLOC_N(VALUE, iseq_size);
12917
12918 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
12919 struct rb_call_data *cd_entries = load_body->call_data;
12920 int ic_index = 0;
12921
12922 iseq_bits_t * mark_offset_bits;
12923
12924 iseq_bits_t tmp[1] = {0};
12925
12926 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12927 mark_offset_bits = tmp;
12928 }
12929 else {
12930 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12931 }
12932 bool needs_bitmap = false;
12933
12934 for (code_index=0; code_index<iseq_size;) {
12935 /* opcode */
12936 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12937 const char *types = insn_op_types(insn);
12938 int op_index;
12939
12940 code_index++;
12941
12942 /* operands */
12943 for (op_index=0; types[op_index]; op_index++, code_index++) {
12944 const char operand_type = types[op_index];
12945 switch (operand_type) {
12946 case TS_VALUE:
12947 {
12948 VALUE op = ibf_load_small_value(load, &reading_pos);
12949 VALUE v = ibf_load_object(load, op);
12950 code[code_index] = v;
12951 if (!SPECIAL_CONST_P(v)) {
12952 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12953 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12954 needs_bitmap = true;
12955 }
12956 break;
12957 }
12958 case TS_CDHASH:
12959 {
12960 VALUE op = ibf_load_small_value(load, &reading_pos);
12961 VALUE v = ibf_load_object(load, op);
12962 v = rb_hash_dup(v); // hash dumped as frozen
12963 RHASH_TBL_RAW(v)->type = &cdhash_type;
12964 rb_hash_rehash(v); // hash function changed
12965 freeze_hide_obj(v);
12966
12967 // Overwrite the existing hash in the object list. This
12968 // is to keep the object alive during load time.
12969 // [Bug #17984] [ruby-core:104259]
12970 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
12971
12972 code[code_index] = v;
12973 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12974 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12975 needs_bitmap = true;
12976 break;
12977 }
12978 case TS_ISEQ:
12979 {
12980 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
12981 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
12982 code[code_index] = v;
12983 if (!SPECIAL_CONST_P(v)) {
12984 RB_OBJ_WRITTEN(iseqv, Qundef, v);
12985 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12986 needs_bitmap = true;
12987 }
12988 break;
12989 }
12990 case TS_IC:
12991 {
12992 VALUE op = ibf_load_small_value(load, &reading_pos);
12993 VALUE arr = ibf_load_object(load, op);
12994
12995 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12996 ic->segments = array_to_idlist(arr);
12997
12998 code[code_index] = (VALUE)ic;
12999 }
13000 break;
13001 case TS_ISE:
13002 case TS_ICVARC:
13003 case TS_IVC:
13004 {
13005 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
13006
13007 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13008 code[code_index] = (VALUE)ic;
13009
13010 if (operand_type == TS_IVC) {
13011 IVC cache = (IVC)ic;
13012
13013 if (insn == BIN(setinstancevariable)) {
13014 ID iv_name = (ID)code[code_index - 1];
13015 cache->iv_set_name = iv_name;
13016 }
13017 else {
13018 cache->iv_set_name = 0;
13019 }
13020
13021 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13022 }
13023
13024 }
13025 break;
13026 case TS_CALLDATA:
13027 {
13028 code[code_index] = (VALUE)cd_entries++;
13029 }
13030 break;
13031 case TS_ID:
13032 {
13033 VALUE op = ibf_load_small_value(load, &reading_pos);
13034 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
13035 }
13036 break;
13037 case TS_FUNCPTR:
13038 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
13039 break;
13040 case TS_BUILTIN:
13041 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
13042 break;
13043 default:
13044 code[code_index] = ibf_load_small_value(load, &reading_pos);
13045 continue;
13046 }
13047 }
13048 if (insn_len(insn) != op_index+1) {
13049 rb_raise(rb_eRuntimeError, "operand size mismatch");
13050 }
13051 }
13052
13053 load_body->iseq_encoded = code;
13054 load_body->iseq_size = code_index;
13055
13056 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13057 load_body->mark_bits.single = mark_offset_bits[0];
13058 }
13059 else {
13060 if (needs_bitmap) {
13061 load_body->mark_bits.list = mark_offset_bits;
13062 }
13063 else {
13064 load_body->mark_bits.list = 0;
13065 ruby_xfree(mark_offset_bits);
13066 }
13067 }
13068
13069 RUBY_ASSERT(code_index == iseq_size);
13070 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13071 return code;
13072}
13073
13074static ibf_offset_t
13075ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13076{
13077 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13078
13079 if (opt_num > 0) {
13080 IBF_W_ALIGN(VALUE);
13081 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
13082 }
13083 else {
13084 return ibf_dump_pos(dump);
13085 }
13086}
13087
13088static VALUE *
13089ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
13090{
13091 if (opt_num > 0) {
13092 VALUE *table = ALLOC_N(VALUE, opt_num+1);
13093 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
13094 return table;
13095 }
13096 else {
13097 return NULL;
13098 }
13099}
13100
13101static ibf_offset_t
13102ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
13103{
13104 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13105
13106 if (kw) {
13107 struct rb_iseq_param_keyword dump_kw = *kw;
13108 int dv_num = kw->num - kw->required_num;
13109 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
13110 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
13111 int i;
13112
13113 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
13114 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
13115
13116 dump_kw.table = IBF_W(ids, ID, kw->num);
13117 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
13118 IBF_W_ALIGN(struct rb_iseq_param_keyword);
13119 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
13120 }
13121 else {
13122 return 0;
13123 }
13124}
13125
13126static const struct rb_iseq_param_keyword *
13127ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13128{
13129 if (param_keyword_offset) {
13130 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
13131 int dv_num = kw->num - kw->required_num;
13132 VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
13133
13134 int i;
13135 for (i=0; i<dv_num; i++) {
13136 dvs[i] = ibf_load_object(load, dvs[i]);
13137 }
13138
13139 // Will be set once the local table is loaded.
13140 kw->table = NULL;
13141
13142 kw->default_values = dvs;
13143 return kw;
13144 }
13145 else {
13146 return NULL;
13147 }
13148}
13149
13150static ibf_offset_t
13151ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
13152{
13153 ibf_offset_t offset = ibf_dump_pos(dump);
13154 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
13155
13156 unsigned int i;
13157 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13158 ibf_dump_write_small_value(dump, entries[i].line_no);
13159#ifdef USE_ISEQ_NODE_ID
13160 ibf_dump_write_small_value(dump, entries[i].node_id);
13161#endif
13162 ibf_dump_write_small_value(dump, entries[i].events);
13163 }
13164
13165 return offset;
13166}
13167
13168static struct iseq_insn_info_entry *
13169ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
13170{
13171 ibf_offset_t reading_pos = body_offset;
13172 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
13173
13174 unsigned int i;
13175 for (i = 0; i < size; i++) {
13176 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13177#ifdef USE_ISEQ_NODE_ID
13178 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13179#endif
13180 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13181 }
13182
13183 return entries;
13184}
13185
13186static ibf_offset_t
13187ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
13188{
13189 ibf_offset_t offset = ibf_dump_pos(dump);
13190
13191 unsigned int last = 0;
13192 unsigned int i;
13193 for (i = 0; i < size; i++) {
13194 ibf_dump_write_small_value(dump, positions[i] - last);
13195 last = positions[i];
13196 }
13197
13198 return offset;
13199}
13200
13201static unsigned int *
13202ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
13203{
13204 ibf_offset_t reading_pos = positions_offset;
13205 unsigned int *positions = ALLOC_N(unsigned int, size);
13206
13207 unsigned int last = 0;
13208 unsigned int i;
13209 for (i = 0; i < size; i++) {
13210 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
13211 last = positions[i];
13212 }
13213
13214 return positions;
13215}
13216
13217static ibf_offset_t
13218ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13219{
13220 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13221 const int size = body->local_table_size;
13222 ID *table = ALLOCA_N(ID, size);
13223 int i;
13224
13225 for (i=0; i<size; i++) {
13226 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13227 if (v == 0) {
13228 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
13229 v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
13230 }
13231 table[i] = v;
13232 }
13233
13234 IBF_W_ALIGN(ID);
13235 return ibf_dump_write(dump, table, sizeof(ID) * size);
13236}
13237
13238static ID *
13239ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
13240{
13241 if (size > 0) {
13242 ID *table = IBF_R(local_table_offset, ID, size);
13243 int i;
13244
13245 for (i=0; i<size; i++) {
13246 table[i] = ibf_load_id(load, table[i]);
13247 }
13248 return table;
13249 }
13250 else {
13251 return NULL;
13252 }
13253}
13254
13255static ibf_offset_t
13256ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
13257{
13258 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
13259
13260 if (table) {
13261 int *iseq_indices = ALLOCA_N(int, table->size);
13262 unsigned int i;
13263
13264 for (i=0; i<table->size; i++) {
13265 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13266 }
13267
13268 const ibf_offset_t offset = ibf_dump_pos(dump);
13269
13270 for (i=0; i<table->size; i++) {
13271 ibf_dump_write_small_value(dump, iseq_indices[i]);
13272 ibf_dump_write_small_value(dump, table->entries[i].type);
13273 ibf_dump_write_small_value(dump, table->entries[i].start);
13274 ibf_dump_write_small_value(dump, table->entries[i].end);
13275 ibf_dump_write_small_value(dump, table->entries[i].cont);
13276 ibf_dump_write_small_value(dump, table->entries[i].sp);
13277 }
13278 return offset;
13279 }
13280 else {
13281 return ibf_dump_pos(dump);
13282 }
13283}
13284
13285static void
13286ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
13287{
13288 if (size) {
13289 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13290 table->size = size;
13291 ISEQ_BODY(parent_iseq)->catch_table = table;
13292
13293 ibf_offset_t reading_pos = catch_table_offset;
13294
13295 unsigned int i;
13296 for (i=0; i<table->size; i++) {
13297 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13298 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13299 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
13300 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
13301 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
13302 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
13303
13304 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
13305 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13306 }
13307 }
13308 else {
13309 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13310 }
13311}
13312
13313static ibf_offset_t
13314ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
13315{
13316 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
13317 const unsigned int ci_size = body->ci_size;
13318 const struct rb_call_data *cds = body->call_data;
13319
13320 ibf_offset_t offset = ibf_dump_pos(dump);
13321
13322 unsigned int i;
13323
13324 for (i = 0; i < ci_size; i++) {
13325 const struct rb_callinfo *ci = cds[i].ci;
13326 if (ci != NULL) {
13327 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13328 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13329 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13330
13331 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
13332 if (kwarg) {
13333 int len = kwarg->keyword_len;
13334 ibf_dump_write_small_value(dump, len);
13335 for (int j=0; j<len; j++) {
13336 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13337 ibf_dump_write_small_value(dump, keyword);
13338 }
13339 }
13340 else {
13341 ibf_dump_write_small_value(dump, 0);
13342 }
13343 }
13344 else {
13345 // TODO: truncate NULL ci from call_data.
13346 ibf_dump_write_small_value(dump, (VALUE)-1);
13347 }
13348 }
13349
13350 return offset;
13351}
13352
13354 ID id;
13355 VALUE name;
13356 VALUE val;
13357};
13358
13360 size_t num;
13361 struct outer_variable_pair pairs[1];
13362};
13363
13364static enum rb_id_table_iterator_result
13365store_outer_variable(ID id, VALUE val, void *dump)
13366{
13367 struct outer_variable_list *ovlist = dump;
13368 struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
13369 pair->id = id;
13370 pair->name = rb_id2str(id);
13371 pair->val = val;
13372 return ID_TABLE_CONTINUE;
13373}
13374
13375static int
13376outer_variable_cmp(const void *a, const void *b, void *arg)
13377{
13378 const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
13379 const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
13380
13381 if (!ap->name) {
13382 return -1;
13383 }
13384 else if (!bp->name) {
13385 return 1;
13386 }
13387
13388 return rb_str_cmp(ap->name, bp->name);
13389}
13390
13391static ibf_offset_t
13392ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
13393{
13394 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13395
13396 ibf_offset_t offset = ibf_dump_pos(dump);
13397
13398 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13399 ibf_dump_write_small_value(dump, (VALUE)size);
13400 if (size > 0) {
13401 VALUE buff;
13402 size_t buffsize =
13403 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
13404 offsetof(struct outer_variable_list, pairs),
13405 rb_eArgError);
13406 struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
13407 ovlist->num = 0;
13408 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13409 ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
13410 for (size_t i = 0; i < size; ++i) {
13411 ID id = ovlist->pairs[i].id;
13412 ID val = ovlist->pairs[i].val;
13413 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
13414 ibf_dump_write_small_value(dump, val);
13415 }
13416 }
13417
13418 return offset;
13419}
13420
13421/* note that we dump out rb_call_info but load back rb_call_data */
13422static void
13423ibf_load_ci_entries(const struct ibf_load *load,
13424 ibf_offset_t ci_entries_offset,
13425 unsigned int ci_size,
13426 struct rb_call_data **cd_ptr)
13427{
13428 if (!ci_size) {
13429 *cd_ptr = NULL;
13430 return;
13431 }
13432
13433 ibf_offset_t reading_pos = ci_entries_offset;
13434
13435 unsigned int i;
13436
13437 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
13438 *cd_ptr = cds;
13439
13440 for (i = 0; i < ci_size; i++) {
13441 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13442 if (mid_index != (VALUE)-1) {
13443 ID mid = ibf_load_id(load, mid_index);
13444 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
13445 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
13446
13447 struct rb_callinfo_kwarg *kwarg = NULL;
13448 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13449 if (kwlen > 0) {
13450 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
13451 kwarg->references = 0;
13452 kwarg->keyword_len = kwlen;
13453 for (int j=0; j<kwlen; j++) {
13454 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13455 kwarg->keywords[j] = ibf_load_object(load, keyword);
13456 }
13457 }
13458
13459 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13460 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
13461 cds[i].cc = vm_cc_empty();
13462 }
13463 else {
13464 // NULL ci
13465 cds[i].ci = NULL;
13466 cds[i].cc = NULL;
13467 }
13468 }
13469}
13470
13471static struct rb_id_table *
13472ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13473{
13474 ibf_offset_t reading_pos = outer_variables_offset;
13475
13476 struct rb_id_table *tbl = NULL;
13477
13478 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13479
13480 if (table_size > 0) {
13481 tbl = rb_id_table_create(table_size);
13482 }
13483
13484 for (size_t i = 0; i < table_size; i++) {
13485 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
13486 VALUE value = ibf_load_small_value(load, &reading_pos);
13487 if (!key) key = rb_make_temporary_id(i);
13488 rb_id_table_insert(tbl, key, value);
13489 }
13490
13491 return tbl;
13492}
13493
13494static ibf_offset_t
13495ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
13496{
13497 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13498
13499 unsigned int *positions;
13500
13501 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
13502
13503 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
13504 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13505 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13506
13507#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13508 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13509
13510 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
13511 struct ibf_dump_buffer buffer;
13512 buffer.str = rb_str_new(0, 0);
13513 buffer.obj_table = ibf_dump_object_table_new();
13514 dump->current_buffer = &buffer;
13515#endif
13516
13517 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13518 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13519 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13520 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13521 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13522
13523 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13524 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13525 ruby_xfree(positions);
13526
13527 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13528 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13529 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13530 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13531 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13532 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13533 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13534 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13535
13536#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13537 ibf_offset_t local_obj_list_offset;
13538 unsigned int local_obj_list_size;
13539
13540 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13541#endif
13542
13543 ibf_offset_t body_offset = ibf_dump_pos(dump);
13544
13545 /* dump the constant body */
13546 unsigned int param_flags =
13547 (body->param.flags.has_lead << 0) |
13548 (body->param.flags.has_opt << 1) |
13549 (body->param.flags.has_rest << 2) |
13550 (body->param.flags.has_post << 3) |
13551 (body->param.flags.has_kw << 4) |
13552 (body->param.flags.has_kwrest << 5) |
13553 (body->param.flags.has_block << 6) |
13554 (body->param.flags.ambiguous_param0 << 7) |
13555 (body->param.flags.accepts_no_kwarg << 8) |
13556 (body->param.flags.ruby2_keywords << 9) |
13557 (body->param.flags.anon_rest << 10) |
13558 (body->param.flags.anon_kwrest << 11) |
13559 (body->param.flags.use_block << 12) |
13560 (body->param.flags.forwardable << 13) ;
13561
13562#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13563# define IBF_BODY_OFFSET(x) (x)
13564#else
13565# define IBF_BODY_OFFSET(x) (body_offset - (x))
13566#endif
13567
13568 ibf_dump_write_small_value(dump, body->type);
13569 ibf_dump_write_small_value(dump, body->iseq_size);
13570 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13571 ibf_dump_write_small_value(dump, bytecode_size);
13572 ibf_dump_write_small_value(dump, param_flags);
13573 ibf_dump_write_small_value(dump, body->param.size);
13574 ibf_dump_write_small_value(dump, body->param.lead_num);
13575 ibf_dump_write_small_value(dump, body->param.opt_num);
13576 ibf_dump_write_small_value(dump, body->param.rest_start);
13577 ibf_dump_write_small_value(dump, body->param.post_start);
13578 ibf_dump_write_small_value(dump, body->param.post_num);
13579 ibf_dump_write_small_value(dump, body->param.block_start);
13580 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13581 ibf_dump_write_small_value(dump, param_keyword_offset);
13582 ibf_dump_write_small_value(dump, location_pathobj_index);
13583 ibf_dump_write_small_value(dump, location_base_label_index);
13584 ibf_dump_write_small_value(dump, location_label_index);
13585 ibf_dump_write_small_value(dump, body->location.first_lineno);
13586 ibf_dump_write_small_value(dump, body->location.node_id);
13587 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13588 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13589 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13590 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13591 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13592 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13593 ibf_dump_write_small_value(dump, body->insns_info.size);
13594 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13595 ibf_dump_write_small_value(dump, catch_table_size);
13596 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13597 ibf_dump_write_small_value(dump, parent_iseq_index);
13598 ibf_dump_write_small_value(dump, local_iseq_index);
13599 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13600 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13601 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13602 ibf_dump_write_small_value(dump, body->variable.flip_count);
13603 ibf_dump_write_small_value(dump, body->local_table_size);
13604 ibf_dump_write_small_value(dump, body->ivc_size);
13605 ibf_dump_write_small_value(dump, body->icvarc_size);
13606 ibf_dump_write_small_value(dump, body->ise_size);
13607 ibf_dump_write_small_value(dump, body->ic_size);
13608 ibf_dump_write_small_value(dump, body->ci_size);
13609 ibf_dump_write_small_value(dump, body->stack_max);
13610 ibf_dump_write_small_value(dump, body->builtin_attrs);
13611 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13612
13613#undef IBF_BODY_OFFSET
13614
13615#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13616 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13617
13618 dump->current_buffer = saved_buffer;
13619 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13620
13621 ibf_offset_t offset = ibf_dump_pos(dump);
13622 ibf_dump_write_small_value(dump, iseq_start);
13623 ibf_dump_write_small_value(dump, iseq_length_bytes);
13624 ibf_dump_write_small_value(dump, body_offset);
13625
13626 ibf_dump_write_small_value(dump, local_obj_list_offset);
13627 ibf_dump_write_small_value(dump, local_obj_list_size);
13628
13629 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
13630
13631 return offset;
13632#else
13633 return body_offset;
13634#endif
13635}
13636
13637static VALUE
13638ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
13639{
13640 VALUE str = ibf_load_object(load, str_index);
13641 if (str != Qnil) {
13642 str = rb_fstring(str);
13643 }
13644 return str;
13645}
13646
13647static void
13648ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13649{
13650 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
13651
13652 ibf_offset_t reading_pos = offset;
13653
13654#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13655 struct ibf_load_buffer *saved_buffer = load->current_buffer;
13656 load->current_buffer = &load->global_buffer;
13657
13658 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13659 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13660 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13661
13662 struct ibf_load_buffer buffer;
13663 buffer.buff = load->global_buffer.buff + iseq_start;
13664 buffer.size = iseq_length_bytes;
13665 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13666 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13667 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13668
13669 load->current_buffer = &buffer;
13670 reading_pos = body_offset;
13671#endif
13672
13673#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13674# define IBF_BODY_OFFSET(x) (x)
13675#else
13676# define IBF_BODY_OFFSET(x) (offset - (x))
13677#endif
13678
13679 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
13680 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13681 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13682 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13683 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
13684 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13685 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13686 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13687 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13688 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13689 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13690 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13691 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13692 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13693 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13694 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13695 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13696 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13697 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13698 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13699 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13700 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13701 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13702 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13703 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13704 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13705 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13706 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13707 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13708 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13709 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13710 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13711 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13712 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13713 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13714 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13715
13716 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13717 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13718 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13719 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13720
13721 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
13722 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
13723 const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
13724 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13725
13726 // setup fname and dummy frame
13727 VALUE path = ibf_load_object(load, location_pathobj_index);
13728 {
13729 VALUE realpath = Qnil;
13730
13731 if (RB_TYPE_P(path, T_STRING)) {
13732 realpath = path = rb_fstring(path);
13733 }
13734 else if (RB_TYPE_P(path, T_ARRAY)) {
13735 VALUE pathobj = path;
13736 if (RARRAY_LEN(pathobj) != 2) {
13737 rb_raise(rb_eRuntimeError, "path object size mismatch");
13738 }
13739 path = rb_fstring(RARRAY_AREF(pathobj, 0));
13740 realpath = RARRAY_AREF(pathobj, 1);
13741 if (!NIL_P(realpath)) {
13742 if (!RB_TYPE_P(realpath, T_STRING)) {
13743 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
13744 "(%x), path=%+"PRIsVALUE,
13745 realpath, TYPE(realpath), path);
13746 }
13747 realpath = rb_fstring(realpath);
13748 }
13749 }
13750 else {
13751 rb_raise(rb_eRuntimeError, "unexpected path object");
13752 }
13753 rb_iseq_pathobj_set(iseq, path, realpath);
13754 }
13755
13756 // push dummy frame
13757 rb_execution_context_t *ec = GET_EC();
13758 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13759
13760#undef IBF_BODY_OFFSET
13761
13762 load_body->type = type;
13763 load_body->stack_max = stack_max;
13764 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13765 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13766 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13767 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13768 load_body->param.flags.has_kw = FALSE;
13769 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13770 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13771 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13772 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13773 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13774 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13775 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13776 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13777 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13778 load_body->param.size = param_size;
13779 load_body->param.lead_num = param_lead_num;
13780 load_body->param.opt_num = param_opt_num;
13781 load_body->param.rest_start = param_rest_start;
13782 load_body->param.post_start = param_post_start;
13783 load_body->param.post_num = param_post_num;
13784 load_body->param.block_start = param_block_start;
13785 load_body->local_table_size = local_table_size;
13786 load_body->ci_size = ci_size;
13787 load_body->insns_info.size = insns_info_size;
13788
13789 ISEQ_COVERAGE_SET(iseq, Qnil);
13790 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13791 load_body->variable.flip_count = variable_flip_count;
13792 load_body->variable.script_lines = Qnil;
13793
13794 load_body->location.first_lineno = location_first_lineno;
13795 load_body->location.node_id = location_node_id;
13796 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13797 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13798 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13799 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13800 load_body->builtin_attrs = builtin_attrs;
13801 load_body->prism = prism;
13802
13803 load_body->ivc_size = ivc_size;
13804 load_body->icvarc_size = icvarc_size;
13805 load_body->ise_size = ise_size;
13806 load_body->ic_size = ic_size;
13807
13808 if (ISEQ_IS_SIZE(load_body)) {
13809 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
13810 }
13811 else {
13812 load_body->is_entries = NULL;
13813 }
13814 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13815 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13816 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13817 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13818 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13819 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13820 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13821 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13822 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13823
13824 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
13825 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
13826 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
13827
13828 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13829 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13830 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13831
13832 // This must be done after the local table is loaded.
13833 if (load_body->param.keyword != NULL) {
13834 RUBY_ASSERT(load_body->local_table);
13835 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *) load_body->param.keyword;
13836 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13837 }
13838
13839 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13840#if VM_INSN_INFO_TABLE_IMPL == 2
13841 rb_iseq_insns_info_encode_positions(iseq);
13842#endif
13843
13844 rb_iseq_translate_threaded_code(iseq);
13845
13846#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13847 load->current_buffer = &load->global_buffer;
13848#endif
13849
13850 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13851 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13852
13853#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13854 load->current_buffer = saved_buffer;
13855#endif
13856 verify_call_cache(iseq);
13857
13858 RB_GC_GUARD(dummy_frame);
13859 rb_vm_pop_frame_no_int(ec);
13860}
13861
13863{
13864 struct ibf_dump *dump;
13865 VALUE offset_list;
13866};
13867
13868static int
13869ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13870{
13871 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
13872 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
13873
13874 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13875 rb_ary_push(args->offset_list, UINT2NUM(offset));
13876
13877 return ST_CONTINUE;
13878}
13879
13880static void
13881ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
13882{
13883 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13884
13885 struct ibf_dump_iseq_list_arg args;
13886 args.dump = dump;
13887 args.offset_list = offset_list;
13888
13889 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13890
13891 st_index_t i;
13892 st_index_t size = dump->iseq_table->num_entries;
13893 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
13894
13895 for (i = 0; i < size; i++) {
13896 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
13897 }
13898
13899 ibf_dump_align(dump, sizeof(ibf_offset_t));
13900 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
13901 header->iseq_list_size = (unsigned int)size;
13902}
13903
13904#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13905
13906/*
13907 * Binary format
13908 * - ibf_object_header
13909 * - ibf_object_xxx (xxx is type)
13910 */
13911
13913 unsigned int type: 5;
13914 unsigned int special_const: 1;
13915 unsigned int frozen: 1;
13916 unsigned int internal: 1;
13917};
13918
13919enum ibf_object_class_index {
13920 IBF_OBJECT_CLASS_OBJECT,
13921 IBF_OBJECT_CLASS_ARRAY,
13922 IBF_OBJECT_CLASS_STANDARD_ERROR,
13923 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13924 IBF_OBJECT_CLASS_TYPE_ERROR,
13925 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13926};
13927
13929 long srcstr;
13930 char option;
13931};
13932
13934 long len;
13935 long keyval[FLEX_ARY_LEN];
13936};
13937
13939 long class_index;
13940 long len;
13941 long beg;
13942 long end;
13943 int excl;
13944};
13945
13947 ssize_t slen;
13948 BDIGIT digits[FLEX_ARY_LEN];
13949};
13950
13951enum ibf_object_data_type {
13952 IBF_OBJECT_DATA_ENCODING,
13953};
13954
13956 long a, b;
13957};
13958
13960 long str;
13961};
13962
13963#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13964 ((((offset) - 1) / (align) + 1) * (align))
13965#define IBF_OBJBODY(type, offset) (const type *)\
13966 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13967
13968static const void *
13969ibf_load_check_offset(const struct ibf_load *load, size_t offset)
13970{
13971 if (offset >= load->current_buffer->size) {
13972 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
13973 }
13974 return load->current_buffer->buff + offset;
13975}
13976
13977NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
13978
13979static void
13980ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
13981{
13982 char buff[0x100];
13983 rb_raw_obj_info(buff, sizeof(buff), obj);
13984 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
13985}
13986
13987NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
13988
13989static VALUE
13990ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
13991{
13992 rb_raise(rb_eArgError, "unsupported");
13994}
13995
13996static void
13997ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
13998{
13999 enum ibf_object_class_index cindex;
14000 if (obj == rb_cObject) {
14001 cindex = IBF_OBJECT_CLASS_OBJECT;
14002 }
14003 else if (obj == rb_cArray) {
14004 cindex = IBF_OBJECT_CLASS_ARRAY;
14005 }
14006 else if (obj == rb_eStandardError) {
14007 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14008 }
14009 else if (obj == rb_eNoMatchingPatternError) {
14010 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14011 }
14012 else if (obj == rb_eTypeError) {
14013 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14014 }
14015 else if (obj == rb_eNoMatchingPatternKeyError) {
14016 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14017 }
14018 else {
14019 rb_obj_info_dump(obj);
14020 rb_p(obj);
14021 rb_bug("unsupported class");
14022 }
14023 ibf_dump_write_small_value(dump, (VALUE)cindex);
14024}
14025
14026static VALUE
14027ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14028{
14029 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14030
14031 switch (cindex) {
14032 case IBF_OBJECT_CLASS_OBJECT:
14033 return rb_cObject;
14034 case IBF_OBJECT_CLASS_ARRAY:
14035 return rb_cArray;
14036 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14037 return rb_eStandardError;
14038 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14040 case IBF_OBJECT_CLASS_TYPE_ERROR:
14041 return rb_eTypeError;
14042 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14044 }
14045
14046 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
14047}
14048
14049
14050static void
14051ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
14052{
14053 double dbl = RFLOAT_VALUE(obj);
14054 (void)IBF_W(&dbl, double, 1);
14055}
14056
14057static VALUE
14058ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14059{
14060 const double *dblp = IBF_OBJBODY(double, offset);
14061 return DBL2NUM(*dblp);
14062}
14063
14064static void
14065ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
14066{
14067 long encindex = (long)rb_enc_get_index(obj);
14068 long len = RSTRING_LEN(obj);
14069 const char *ptr = RSTRING_PTR(obj);
14070
14071 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14072 rb_encoding *enc = rb_enc_from_index((int)encindex);
14073 const char *enc_name = rb_enc_name(enc);
14074 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
14075 }
14076
14077 ibf_dump_write_small_value(dump, encindex);
14078 ibf_dump_write_small_value(dump, len);
14079 IBF_WP(ptr, char, len);
14080}
14081
14082static VALUE
14083ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14084{
14085 ibf_offset_t reading_pos = offset;
14086
14087 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14088 const long len = (long)ibf_load_small_value(load, &reading_pos);
14089 const char *ptr = load->current_buffer->buff + reading_pos;
14090
14091 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14092 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14093 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14094 }
14095
14096 VALUE str;
14097 if (header->frozen && !header->internal) {
14098 str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
14099 }
14100 else {
14101 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
14102
14103 if (header->internal) rb_obj_hide(str);
14104 if (header->frozen) str = rb_fstring(str);
14105 }
14106 return str;
14107}
14108
14109static void
14110ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
14111{
14112 VALUE srcstr = RREGEXP_SRC(obj);
14113 struct ibf_object_regexp regexp;
14114 regexp.option = (char)rb_reg_options(obj);
14115 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14116
14117 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
14118 ibf_dump_write_small_value(dump, regexp.srcstr);
14119}
14120
14121static VALUE
14122ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14123{
14124 struct ibf_object_regexp regexp;
14125 regexp.option = ibf_load_byte(load, &offset);
14126 regexp.srcstr = ibf_load_small_value(load, &offset);
14127
14128 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14129 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
14130
14131 if (header->internal) rb_obj_hide(reg);
14132 if (header->frozen) rb_obj_freeze(reg);
14133
14134 return reg;
14135}
14136
14137static void
14138ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
14139{
14140 long i, len = RARRAY_LEN(obj);
14141 ibf_dump_write_small_value(dump, len);
14142 for (i=0; i<len; i++) {
14143 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
14144 ibf_dump_write_small_value(dump, index);
14145 }
14146}
14147
14148static VALUE
14149ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14150{
14151 ibf_offset_t reading_pos = offset;
14152
14153 const long len = (long)ibf_load_small_value(load, &reading_pos);
14154
14155 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
14156 int i;
14157
14158 for (i=0; i<len; i++) {
14159 const VALUE index = ibf_load_small_value(load, &reading_pos);
14160 rb_ary_push(ary, ibf_load_object(load, index));
14161 }
14162
14163 if (header->frozen) rb_ary_freeze(ary);
14164
14165 return ary;
14166}
14167
14168static int
14169ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14170{
14171 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14172
14173 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
14174 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
14175
14176 ibf_dump_write_small_value(dump, key_index);
14177 ibf_dump_write_small_value(dump, val_index);
14178 return ST_CONTINUE;
14179}
14180
14181static void
14182ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
14183{
14184 long len = RHASH_SIZE(obj);
14185 ibf_dump_write_small_value(dump, (VALUE)len);
14186
14187 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
14188}
14189
14190static VALUE
14191ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14192{
14193 long len = (long)ibf_load_small_value(load, &offset);
14194 VALUE obj = rb_hash_new_with_size(len);
14195 int i;
14196
14197 for (i = 0; i < len; i++) {
14198 VALUE key_index = ibf_load_small_value(load, &offset);
14199 VALUE val_index = ibf_load_small_value(load, &offset);
14200
14201 VALUE key = ibf_load_object(load, key_index);
14202 VALUE val = ibf_load_object(load, val_index);
14203 rb_hash_aset(obj, key, val);
14204 }
14205 rb_hash_rehash(obj);
14206
14207 if (header->internal) rb_obj_hide(obj);
14208 if (header->frozen) rb_obj_freeze(obj);
14209
14210 return obj;
14211}
14212
14213static void
14214ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
14215{
14216 if (rb_obj_is_kind_of(obj, rb_cRange)) {
14217 struct ibf_object_struct_range range;
14218 VALUE beg, end;
14219 IBF_ZERO(range);
14220 range.len = 3;
14221 range.class_index = 0;
14222
14223 rb_range_values(obj, &beg, &end, &range.excl);
14224 range.beg = (long)ibf_dump_object(dump, beg);
14225 range.end = (long)ibf_dump_object(dump, end);
14226
14227 IBF_W_ALIGN(struct ibf_object_struct_range);
14228 IBF_WV(range);
14229 }
14230 else {
14231 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14232 rb_class_name(CLASS_OF(obj)));
14233 }
14234}
14235
14236static VALUE
14237ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14238{
14239 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
14240 VALUE beg = ibf_load_object(load, range->beg);
14241 VALUE end = ibf_load_object(load, range->end);
14242 VALUE obj = rb_range_new(beg, end, range->excl);
14243 if (header->internal) rb_obj_hide(obj);
14244 if (header->frozen) rb_obj_freeze(obj);
14245 return obj;
14246}
14247
14248static void
14249ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
14250{
14251 ssize_t len = BIGNUM_LEN(obj);
14252 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
14253 BDIGIT *d = BIGNUM_DIGITS(obj);
14254
14255 (void)IBF_W(&slen, ssize_t, 1);
14256 IBF_WP(d, BDIGIT, len);
14257}
14258
14259static VALUE
14260ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14261{
14262 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
14263 int sign = bignum->slen > 0;
14264 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14265 const int big_unpack_flags = /* c.f. rb_big_unpack() */
14268 VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
14269 big_unpack_flags |
14270 (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
14271 if (header->internal) rb_obj_hide(obj);
14272 if (header->frozen) rb_obj_freeze(obj);
14273 return obj;
14274}
14275
14276static void
14277ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
14278{
14279 if (rb_data_is_encoding(obj)) {
14280 rb_encoding *enc = rb_to_encoding(obj);
14281 const char *name = rb_enc_name(enc);
14282 long len = strlen(name) + 1;
14283 long data[2];
14284 data[0] = IBF_OBJECT_DATA_ENCODING;
14285 data[1] = len;
14286 (void)IBF_W(data, long, 2);
14287 IBF_WP(name, char, len);
14288 }
14289 else {
14290 ibf_dump_object_unsupported(dump, obj);
14291 }
14292}
14293
14294static VALUE
14295ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14296{
14297 const long *body = IBF_OBJBODY(long, offset);
14298 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
14299 /* const long len = body[1]; */
14300 const char *data = (const char *)&body[2];
14301
14302 switch (type) {
14303 case IBF_OBJECT_DATA_ENCODING:
14304 {
14305 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14306 return encobj;
14307 }
14308 }
14309
14310 return ibf_load_object_unsupported(load, header, offset);
14311}
14312
14313static void
14314ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
14315{
14316 long data[2];
14317 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14318 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14319
14320 (void)IBF_W(data, long, 2);
14321}
14322
14323static VALUE
14324ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14325{
14326 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
14327 VALUE a = ibf_load_object(load, nums->a);
14328 VALUE b = ibf_load_object(load, nums->b);
14329 VALUE obj = header->type == T_COMPLEX ?
14330 rb_complex_new(a, b) : rb_rational_new(a, b);
14331
14332 if (header->internal) rb_obj_hide(obj);
14333 if (header->frozen) rb_obj_freeze(obj);
14334 return obj;
14335}
14336
14337static void
14338ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
14339{
14340 ibf_dump_object_string(dump, rb_sym2str(obj));
14341}
14342
14343static VALUE
14344ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
14345{
14346 ibf_offset_t reading_pos = offset;
14347
14348 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14349 const long len = (long)ibf_load_small_value(load, &reading_pos);
14350 const char *ptr = load->current_buffer->buff + reading_pos;
14351
14352 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14353 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14354 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14355 }
14356
14357 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
14358 return ID2SYM(id);
14359}
14360
14361typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
14362static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
14363 ibf_dump_object_unsupported, /* T_NONE */
14364 ibf_dump_object_unsupported, /* T_OBJECT */
14365 ibf_dump_object_class, /* T_CLASS */
14366 ibf_dump_object_unsupported, /* T_MODULE */
14367 ibf_dump_object_float, /* T_FLOAT */
14368 ibf_dump_object_string, /* T_STRING */
14369 ibf_dump_object_regexp, /* T_REGEXP */
14370 ibf_dump_object_array, /* T_ARRAY */
14371 ibf_dump_object_hash, /* T_HASH */
14372 ibf_dump_object_struct, /* T_STRUCT */
14373 ibf_dump_object_bignum, /* T_BIGNUM */
14374 ibf_dump_object_unsupported, /* T_FILE */
14375 ibf_dump_object_data, /* T_DATA */
14376 ibf_dump_object_unsupported, /* T_MATCH */
14377 ibf_dump_object_complex_rational, /* T_COMPLEX */
14378 ibf_dump_object_complex_rational, /* T_RATIONAL */
14379 ibf_dump_object_unsupported, /* 0x10 */
14380 ibf_dump_object_unsupported, /* 0x11 T_NIL */
14381 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
14382 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
14383 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
14384 ibf_dump_object_unsupported, /* T_FIXNUM */
14385 ibf_dump_object_unsupported, /* T_UNDEF */
14386 ibf_dump_object_unsupported, /* 0x17 */
14387 ibf_dump_object_unsupported, /* 0x18 */
14388 ibf_dump_object_unsupported, /* 0x19 */
14389 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
14390 ibf_dump_object_unsupported, /* T_NODE 0x1b */
14391 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
14392 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
14393 ibf_dump_object_unsupported, /* 0x1e */
14394 ibf_dump_object_unsupported, /* 0x1f */
14395};
14396
14397static void
14398ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
14399{
14400 unsigned char byte =
14401 (header.type << 0) |
14402 (header.special_const << 5) |
14403 (header.frozen << 6) |
14404 (header.internal << 7);
14405
14406 IBF_WV(byte);
14407}
14408
14409static struct ibf_object_header
14410ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
14411{
14412 unsigned char byte = ibf_load_byte(load, offset);
14413
14414 struct ibf_object_header header;
14415 header.type = (byte >> 0) & 0x1f;
14416 header.special_const = (byte >> 5) & 0x01;
14417 header.frozen = (byte >> 6) & 0x01;
14418 header.internal = (byte >> 7) & 0x01;
14419
14420 return header;
14421}
14422
14423static ibf_offset_t
14424ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
14425{
14426 struct ibf_object_header obj_header;
14427 ibf_offset_t current_offset;
14428 IBF_ZERO(obj_header);
14429 obj_header.type = TYPE(obj);
14430
14431 IBF_W_ALIGN(ibf_offset_t);
14432 current_offset = ibf_dump_pos(dump);
14433
14434 if (SPECIAL_CONST_P(obj) &&
14435 ! (SYMBOL_P(obj) ||
14436 RB_FLOAT_TYPE_P(obj))) {
14437 obj_header.special_const = TRUE;
14438 obj_header.frozen = TRUE;
14439 obj_header.internal = TRUE;
14440 ibf_dump_object_object_header(dump, obj_header);
14441 ibf_dump_write_small_value(dump, obj);
14442 }
14443 else {
14444 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14445 obj_header.special_const = FALSE;
14446 obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
14447 ibf_dump_object_object_header(dump, obj_header);
14448 (*dump_object_functions[obj_header.type])(dump, obj);
14449 }
14450
14451 return current_offset;
14452}
14453
14454typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
14455static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
14456 ibf_load_object_unsupported, /* T_NONE */
14457 ibf_load_object_unsupported, /* T_OBJECT */
14458 ibf_load_object_class, /* T_CLASS */
14459 ibf_load_object_unsupported, /* T_MODULE */
14460 ibf_load_object_float, /* T_FLOAT */
14461 ibf_load_object_string, /* T_STRING */
14462 ibf_load_object_regexp, /* T_REGEXP */
14463 ibf_load_object_array, /* T_ARRAY */
14464 ibf_load_object_hash, /* T_HASH */
14465 ibf_load_object_struct, /* T_STRUCT */
14466 ibf_load_object_bignum, /* T_BIGNUM */
14467 ibf_load_object_unsupported, /* T_FILE */
14468 ibf_load_object_data, /* T_DATA */
14469 ibf_load_object_unsupported, /* T_MATCH */
14470 ibf_load_object_complex_rational, /* T_COMPLEX */
14471 ibf_load_object_complex_rational, /* T_RATIONAL */
14472 ibf_load_object_unsupported, /* 0x10 */
14473 ibf_load_object_unsupported, /* T_NIL */
14474 ibf_load_object_unsupported, /* T_TRUE */
14475 ibf_load_object_unsupported, /* T_FALSE */
14476 ibf_load_object_symbol,
14477 ibf_load_object_unsupported, /* T_FIXNUM */
14478 ibf_load_object_unsupported, /* T_UNDEF */
14479 ibf_load_object_unsupported, /* 0x17 */
14480 ibf_load_object_unsupported, /* 0x18 */
14481 ibf_load_object_unsupported, /* 0x19 */
14482 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
14483 ibf_load_object_unsupported, /* T_NODE 0x1b */
14484 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
14485 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
14486 ibf_load_object_unsupported, /* 0x1e */
14487 ibf_load_object_unsupported, /* 0x1f */
14488};
14489
14490static VALUE
14491ibf_load_object(const struct ibf_load *load, VALUE object_index)
14492{
14493 if (object_index == 0) {
14494 return Qnil;
14495 }
14496 else {
14497 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
14498 if (!obj) {
14499 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14500 ibf_offset_t offset = offsets[object_index];
14501 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14502
14503#if IBF_ISEQ_DEBUG
14504 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14505 load->current_buffer->obj_list_offset, (void *)offsets, offset);
14506 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14507 header.type, header.special_const, header.frozen, header.internal);
14508#endif
14509 if (offset >= load->current_buffer->size) {
14510 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
14511 }
14512
14513 if (header.special_const) {
14514 ibf_offset_t reading_pos = offset;
14515
14516 obj = ibf_load_small_value(load, &reading_pos);
14517 }
14518 else {
14519 obj = (*load_object_functions[header.type])(load, &header, offset);
14520 }
14521
14522 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
14523 }
14524#if IBF_ISEQ_DEBUG
14525 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
14526 object_index, obj);
14527#endif
14528 return obj;
14529 }
14530}
14531
14533{
14534 struct ibf_dump *dump;
14535 VALUE offset_list;
14536};
14537
14538static int
14539ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14540{
14541 VALUE obj = (VALUE)key;
14542 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
14543
14544 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14545 rb_ary_push(args->offset_list, UINT2NUM(offset));
14546
14547 return ST_CONTINUE;
14548}
14549
14550static void
14551ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
14552{
14553 st_table *obj_table = dump->current_buffer->obj_table;
14554 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14555
14556 struct ibf_dump_object_list_arg args;
14557 args.dump = dump;
14558 args.offset_list = offset_list;
14559
14560 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14561
14562 IBF_W_ALIGN(ibf_offset_t);
14563 *obj_list_offset = ibf_dump_pos(dump);
14564
14565 st_index_t size = obj_table->num_entries;
14566 st_index_t i;
14567
14568 for (i=0; i<size; i++) {
14569 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
14570 IBF_WV(offset);
14571 }
14572
14573 *obj_list_size = (unsigned int)size;
14574}
14575
14576static void
14577ibf_dump_mark(void *ptr)
14578{
14579 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14580 rb_gc_mark(dump->global_buffer.str);
14581
14582 rb_mark_set(dump->global_buffer.obj_table);
14583 rb_mark_set(dump->iseq_table);
14584}
14585
14586static void
14587ibf_dump_free(void *ptr)
14588{
14589 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14590 if (dump->global_buffer.obj_table) {
14591 st_free_table(dump->global_buffer.obj_table);
14592 dump->global_buffer.obj_table = 0;
14593 }
14594 if (dump->iseq_table) {
14595 st_free_table(dump->iseq_table);
14596 dump->iseq_table = 0;
14597 }
14598}
14599
14600static size_t
14601ibf_dump_memsize(const void *ptr)
14602{
14603 struct ibf_dump *dump = (struct ibf_dump *)ptr;
14604 size_t size = 0;
14605 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14606 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14607 return size;
14608}
14609
14610static const rb_data_type_t ibf_dump_type = {
14611 "ibf_dump",
14612 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14613 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14614};
14615
14616static void
14617ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
14618{
14619 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
14620 dump->iseq_table = NULL;
14621
14622 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
14623 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14624 dump->iseq_table = st_init_numtable(); /* need free */
14625
14626 dump->current_buffer = &dump->global_buffer;
14627}
14628
14629VALUE
14630rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
14631{
14632 struct ibf_dump *dump;
14633 struct ibf_header header = {{0}};
14634 VALUE dump_obj;
14635 VALUE str;
14636
14637 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14638 ISEQ_BODY(iseq)->local_iseq != iseq) {
14639 rb_raise(rb_eRuntimeError, "should be top of iseq");
14640 }
14641 if (RTEST(ISEQ_COVERAGE(iseq))) {
14642 rb_raise(rb_eRuntimeError, "should not compile with coverage");
14643 }
14644
14645 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
14646 ibf_dump_setup(dump, dump_obj);
14647
14648 ibf_dump_write(dump, &header, sizeof(header));
14649 ibf_dump_iseq(dump, iseq);
14650
14651 header.magic[0] = 'Y'; /* YARB */
14652 header.magic[1] = 'A';
14653 header.magic[2] = 'R';
14654 header.magic[3] = 'B';
14655 header.major_version = IBF_MAJOR_VERSION;
14656 header.minor_version = IBF_MINOR_VERSION;
14657 header.endian = IBF_ENDIAN_MARK;
14658 header.wordsize = (uint8_t)SIZEOF_VALUE;
14659 ibf_dump_iseq_list(dump, &header);
14660 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14661 header.size = ibf_dump_pos(dump);
14662
14663 if (RTEST(opt)) {
14664 VALUE opt_str = opt;
14665 const char *ptr = StringValuePtr(opt_str);
14666 header.extra_size = RSTRING_LENINT(opt_str);
14667 ibf_dump_write(dump, ptr, header.extra_size);
14668 }
14669 else {
14670 header.extra_size = 0;
14671 }
14672
14673 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
14674
14675 str = dump->global_buffer.str;
14676 RB_GC_GUARD(dump_obj);
14677 return str;
14678}
14679
14680static const ibf_offset_t *
14681ibf_iseq_list(const struct ibf_load *load)
14682{
14683 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14684}
14685
14686void
14687rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14688{
14689 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
14690 rb_iseq_t *prev_src_iseq = load->iseq;
14691 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14692 load->iseq = iseq;
14693#if IBF_ISEQ_DEBUG
14694 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14695 iseq->aux.loader.index, offset,
14696 load->header->size);
14697#endif
14698 ibf_load_iseq_each(load, iseq, offset);
14699 ISEQ_COMPILE_DATA_CLEAR(iseq);
14700 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14701 rb_iseq_init_trace(iseq);
14702 load->iseq = prev_src_iseq;
14703}
14704
14705#if USE_LAZY_LOAD
14706const rb_iseq_t *
14707rb_iseq_complete(const rb_iseq_t *iseq)
14708{
14709 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14710 return iseq;
14711}
14712#endif
14713
14714static rb_iseq_t *
14715ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
14716{
14717 int iseq_index = (int)(VALUE)index_iseq;
14718
14719#if IBF_ISEQ_DEBUG
14720 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14721 (void *)index_iseq, (void *)load->iseq_list);
14722#endif
14723 if (iseq_index == -1) {
14724 return NULL;
14725 }
14726 else {
14727 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14728
14729#if IBF_ISEQ_DEBUG
14730 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
14731#endif
14732 if (iseqv) {
14733 return (rb_iseq_t *)iseqv;
14734 }
14735 else {
14736 rb_iseq_t *iseq = iseq_imemo_alloc();
14737#if IBF_ISEQ_DEBUG
14738 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
14739#endif
14740 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
14741 iseq->aux.loader.obj = load->loader_obj;
14742 iseq->aux.loader.index = iseq_index;
14743#if IBF_ISEQ_DEBUG
14744 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14745 (void *)iseq, (void *)load->loader_obj, iseq_index);
14746#endif
14747 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
14748
14749 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14750#if IBF_ISEQ_DEBUG
14751 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
14752#endif
14753 rb_ibf_load_iseq_complete(iseq);
14754 }
14755
14756#if IBF_ISEQ_DEBUG
14757 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
14758 (void *)iseq, (void *)load->iseq);
14759#endif
14760 return iseq;
14761 }
14762 }
14763}
14764
14765static void
14766ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
14767{
14768 struct ibf_header *header = (struct ibf_header *)bytes;
14769 load->loader_obj = loader_obj;
14770 load->global_buffer.buff = bytes;
14771 load->header = header;
14772 load->global_buffer.size = header->size;
14773 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14774 load->global_buffer.obj_list_size = header->global_object_list_size;
14775 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14776 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14777 load->iseq = NULL;
14778
14779 load->current_buffer = &load->global_buffer;
14780
14781 if (size < header->size) {
14782 rb_raise(rb_eRuntimeError, "broken binary format");
14783 }
14784 if (strncmp(header->magic, "YARB", 4) != 0) {
14785 rb_raise(rb_eRuntimeError, "unknown binary format");
14786 }
14787 if (header->major_version != IBF_MAJOR_VERSION ||
14788 header->minor_version != IBF_MINOR_VERSION) {
14789 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
14790 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14791 }
14792 if (header->endian != IBF_ENDIAN_MARK) {
14793 rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
14794 }
14795 if (header->wordsize != SIZEOF_VALUE) {
14796 rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
14797 }
14798 if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14799 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
14800 header->iseq_list_offset);
14801 }
14802 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
14803 rb_raise(rb_eArgError, "unaligned object list offset: %u",
14804 load->global_buffer.obj_list_offset);
14805 }
14806}
14807
14808static void
14809ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
14810{
14811 StringValue(str);
14812
14813 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
14814 rb_raise(rb_eRuntimeError, "broken binary format");
14815 }
14816
14817 if (USE_LAZY_LOAD) {
14818 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14819 }
14820
14821 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14822 RB_OBJ_WRITE(loader_obj, &load->str, str);
14823}
14824
14825static void
14826ibf_loader_mark(void *ptr)
14827{
14828 struct ibf_load *load = (struct ibf_load *)ptr;
14829 rb_gc_mark(load->str);
14830 rb_gc_mark(load->iseq_list);
14831 rb_gc_mark(load->global_buffer.obj_list);
14832}
14833
14834static void
14835ibf_loader_free(void *ptr)
14836{
14837 struct ibf_load *load = (struct ibf_load *)ptr;
14838 ruby_xfree(load);
14839}
14840
14841static size_t
14842ibf_loader_memsize(const void *ptr)
14843{
14844 return sizeof(struct ibf_load);
14845}
14846
14847static const rb_data_type_t ibf_load_type = {
14848 "ibf_loader",
14849 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14850 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14851};
14852
14853const rb_iseq_t *
14854rb_iseq_ibf_load(VALUE str)
14855{
14856 struct ibf_load *load;
14857 rb_iseq_t *iseq;
14858 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14859
14860 ibf_load_setup(load, loader_obj, str);
14861 iseq = ibf_load_iseq(load, 0);
14862
14863 RB_GC_GUARD(loader_obj);
14864 return iseq;
14865}
14866
14867const rb_iseq_t *
14868rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
14869{
14870 struct ibf_load *load;
14871 rb_iseq_t *iseq;
14872 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14873
14874 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14875 iseq = ibf_load_iseq(load, 0);
14876
14877 RB_GC_GUARD(loader_obj);
14878 return iseq;
14879}
14880
14881VALUE
14882rb_iseq_ibf_load_extra_data(VALUE str)
14883{
14884 struct ibf_load *load;
14885 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
14886 VALUE extra_str;
14887
14888 ibf_load_setup(load, loader_obj, str);
14889 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14890 RB_GC_GUARD(loader_obj);
14891 return extra_str;
14892}
14893
14894#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define LONG_LONG
Definition long_long.h:38
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
Definition stdalign.h:28
#define RUBY_EVENT_END
Encountered an end of a class clause.
Definition event.h:40
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:43
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:39
#define RUBY_EVENT_NONE
No events.
Definition event.h:37
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:44
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:108
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:41
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define RBIMPL_ATTR_FORMAT(x, y, z)
Wraps (or simulates) __attribute__((format))
Definition format.h:29
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define NUM2ULONG
Old name of RB_NUM2ULONG.
Definition long.h:52
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:403
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:404
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:136
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:401
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:128
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
Definition value_type.h:85
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:132
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define T_REGEXP
Old name of RUBY_T_REGEXP.
Definition value_type.h:77
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:486
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1443
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:695
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1444
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1432
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1447
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
Definition error.h:57
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
Definition object.c:110
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:101
VALUE rb_cHash
Hash class.
Definition hash.c:109
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:655
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:878
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1297
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:615
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition gc.h:603
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
Definition bignum.h:546
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
Definition bignum.h:528
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1091
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1115
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1838
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:68
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1974
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4225
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3757
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1711
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:4121
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:4107
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3525
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
Definition string.c:3723
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
Definition string.c:4177
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:3994
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3238
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:498
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:986
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1005
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:955
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
Definition ractor.c:1426
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
Definition util.h:48
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
Definition memory.h:304
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:163
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
Definition rdata.h:78
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
Definition rdata.h:104
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:69
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
Definition rtypeddata.h:102
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:515
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:450
#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:497
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9067
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c:30
Internal header for Complex.
Definition complex.h:13
Internal header for Rational.
Definition rational.h:16
Definition iseq.h:280
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:287
Definition vm_core.h:290
Definition iseq.h:251
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:203
const char * wrap_struct_name
Name of structs of this kind.
Definition rtypeddata.h:210
struct rb_iseq_constant_body::@154 param
parameter information
Definition st.h:79
Definition vm_core.h:299
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
Definition value.h:69
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
Definition value_type.h:204
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:145